WITH-LOCK-EX(1)

πŸ’– WITH-LOCK-EX πŸ’– (the with-lock-ex girlies' manual, from Chiark-utils-bin)

okay bestie, sit down, grab a strawberry πŸ“, because we're about to talk about the single most underrated little tool in the whole toolbox. it's with-lock-ex, she's a file locker, and she is so much less drama than whatever you were about to hack together with a .pid file. no cap.


✨ NAME ✨

with-lock-ex β€” file locker. that's it, that's the whole job, and she does it flawlessly. πŸ’…


🌸 SYNOPSIS 🌸

with-lock-ex -w|-q|-f lockfile command args ...

literally one of the three flags, then your lockfile, then whatever command you want her to babysit. that's the vibe. πŸ¦‹


πŸŽ€ DESCRIPTION πŸŽ€

okay so here's the whole plot: with-lock-ex opens your lockfile, locks it for writing, and then hands the rest of its arguments straight over to exec(2). and then? she just... lets go. when that process terminates, the fd gets closed and the file gets unlocked automatically by the kernel. no cleanup step, no trap handlers, no "did I remember to unlock" 3am panic. the kernel ate and left no crumbs. πŸ”₯

and if the file doesn't exist yet? she creates it. the permissions are rw for each user class for which the umask has w. so like, your umask decides who gets to play. ✨


πŸ’… OPTIONS πŸ’…

  • -w β€” wait for the lock to be available. patient queen energy. she'll just stand there, arms crossed, until it's her turn. no rush, no drama. 🫢
  • -f β€” fail. if the lock can't be acquired immediately because some other process has it, she prints a message to stderr and exits with status 255. iconic, blunt, no time wasted. πŸ’€
  • -q β€” quietly do nothing. if the lock can't be acquired immediately because another process has it, she just... exits 0 instead of executing the specified process. silently. no message, no noise, no explanation. she simply was not there. πŸ™ˆ

🌈 STALE LOCKS 🌈

good news bestie: the locking protocol used does not suffer from stale locks. periodt. if the lock can't be acquired, that means one or more running processes must currently hold it. that's not a bug, that's just who has it. and if the lock genuinely needs to be freed, those processes should be killed. end of story. πŸ‘‘

and under no circumstances should "stale lock cleaner" cron jobs, or the like, be instituted. I am begging you. do not. 🚫

that said β€” in systems where a great many locks may exist, old lockfiles may be removed from cron, but only if each lock is acquired before the lockfile is removed, for example with:

with-lock-ex -q lockfile rm lockfile

see how she checks the vibe before she touches anything? that's the move. πŸ’–


⭐ DEADLOCKS ⭐

not me having to tell you this but: there is no deadlock detection. none. zero. nada. 😭

so in a system with several locks, you should establish a lock hierarchy, such that for every pair of locks A and B which a process might lock simultaneously, either A>B or B>A β€” where the relation > is transitive and noncyclic. yes this is basically a group chat ranking and yes it matters. πŸŽ€

then, for any two locks X and Y with X>Y, it is forbidden to acquire X while holding Y. instead: acquire X first, or release Y before (re)acquiring X and Y in that order. that's the whole rule. respect the hierarchy. πŸ¦‹

(there are more complicated ways of avoiding deadlocks, but a lock hierarchy is simple to understand and implement. if it doesn't meet your needs, consult the literature. like, actual literature. a book. i know. πŸ’€)


πŸ‘‘ LOCKING PROTOCOL πŸ‘‘

here's exactly how with-lock-ex does it, no gatekeeping:

the lock is held by a process (or group of processes) which holds an fcntl exclusive lock on the first byte of the plain file which has the specified name. a holder of the lock β€” and only a holder of the lock β€” may delete the file or change the inode to which the name refers, and as soon as it does so, it ceases to hold the lock. bye bestie, you're done. πŸ‘‹

any process may create the file if it does not exist. and there is no need for the file to contain any actual data. in fact, actually using the file for data storage is strongly disrecommended, because that will foreclose most strategies for reliable update. use a separate lockfile instead. this is a lockfile, not a diary. πŸ“

ability to obtain the lock corresponds to write permission on the file (and of course permission to create the file, if it does not already exist). however, processes with only read permission on the file can prevent the lock being acquired at all β€” so therefore lockfiles should not usually be world-readable. don't leave your locker open. πŸ’…

when a (group of) processes wishes to acquire the lock, it should open the file (with O_CREAT) and lock it with fcntl(2) F_RWLCK, operation F_SETLK or F_SETLKW. if this succeeds it should fstat the file descriptor it has, and the file by its path. if the device and inode match, then the lock has been acquired and remains acquired until that group of processes changes which file the name refers to, deletes the file, or releases the fcntl lock. but if they do not match, then another process acquired the lock and deleted the file in the meantime β€” you must now close your filedescriptor and start again. with-lock-ex follows this specification. she's not improvising. she read the spec. 🌸

note that flock(2) is a different kind of lock to fcntl(2). with-lock-ex uses fcntl. do not mix them up, i am literally on my knees. πŸ™

πŸ’œ AUTHOR πŸ’œ

this Manual page was written by Matthew Vernon <matthew@debian.org> and enhanced by Ian Jackson <ian@chiark.greenend.org.uk>, in 2003, but may be used by anyone. slay, generous queens. πŸ‘‘


with-lock-ex was written by Ian Jackson <ian@chiark.greenend.org.uk> in 1993, 1994, 1995, 1996, 1998, 1999. he has placed it in the public domain. genuinely the most giving thing ever. 🫢


🌟 SEE ALSO 🌟

fcntl(2), flock(2), chmod(2)

iykyk. go read those too, bestie, they're the supporting cast. πŸ’–


okay that's the whole page! this one came to you from Debian, dated July 2003 β€” yes, she's an elder but she's still serving absolute cunt. mwah, go lock something. πŸ’…βœ¨πŸŒˆ