5 * with-lock-ex -<mode> <lockfile> <command> <args>...
6 * with-lock-ex -l <lockfile>
10 * f fail if the lock cannot be acquired
11 * q silently do nothing if the lock cannot be acquired
12 * l show who is waiting (print "none" or "read <pid>"
13 * or "write <pid>"; lockfile opened for reading;
14 * no command may be specified)
16 * with-lock-ex will open and lock the lockfile for writing and
17 * then feed the remainder of its arguments to exec(2); when
18 * that process terminates the fd will be closed and the file
19 * unlocked automatically by the kernel.
21 * If invoked as with-lock, behaves like with-lock-ex -f (for backward
22 * compatibility with an earlier version).
24 * This file written by me, Ian Jackson, in 1993, 1994, 1995, 1996,
27 * Copyright 1993-2016 Ian Jackson in some jurisdictions
28 * Copyright 2017 Ian Jackson in all jurisdictions
32 * Permission is hereby granted, free of charge, to any person obtaining a
33 * copy of this software and associated documentation files (the "Software"),
34 * to deal in the Software without restriction, including without limitation
35 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
36 * and/or sell copies of the Software, and to permit persons to whom the
37 * Software is furnished to do so, subject to the following conditions:
39 * The above copyright notice and this permission notice shall be included in
40 * all copies or substantial portions of the Software.
42 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
45 * SOFTWARE IN THE PUBLIC INTEREST, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR
46 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
47 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
48 * DEALINGS IN THE SOFTWARE.
59 static const char *cmd;
61 static void fail(const char *why) __attribute__((noreturn));
63 static void fail(const char *why) {
64 fprintf(stderr,"with-lock-ex %s: %s: %s\n",cmd,why,strerror(errno));
68 int main(int argc, char **argv) {
70 struct stat stab, fstab;
75 if (argc >= 3 && !strcmp((p= strrchr(argv[0],'/')) ? ++p : argv[0], "with-lock")) {
77 } else if (argc < 3 || argv[1][0] != '-' || argv[1][2] ||
78 ((mode= argv[1][1]) != 'w' && mode != 'q' && mode != 'f'
80 (mode != 'l' && argc < 4) ||
81 (mode == 'l' && argc != 3)) {
82 fputs("usage: with-lock-ex -w|-q|-f <lockfile> <command> <args>...\n"
83 " with-lock-ex -l <lockfile>\n"
84 " with-lock <lockfile> <command> <args>...\n",
91 um= umask(0777); if (um==-1) fail("find umask");
92 if (umask(um)==-1) fail("reset umask");
96 int openmode = mode=='l' ? O_RDONLY : O_RDWR|O_CREAT;
98 fd= open(argv[1],openmode,0666&~(um|((um&0222)<<1)));
99 if (fd<0) fail(argv[1]);
103 fl.l_whence= SEEK_SET;
105 fl.l_len= mode=='l' ? 0 : 1;
107 mode=='l' ? F_GETLK :
108 mode=='w' ? F_SETLKW :
112 (errno == EAGAIN || errno == EWOULDBLOCK || errno == EBUSY))
114 if (errno != EINTR) fail("could not acquire lock");
119 fl.l_type == F_WRLCK ? "write" :
120 fl.l_type == F_RDLCK ? "read" : "unknown",
121 (unsigned long)fl.l_pid);
125 if (ferror(stdout)) fail("print to stdout\n");
129 if (fstat(fd, &fstab)) fail("could not fstat lock fd");
130 if (stat(argv[1], &stab)) {
131 if (errno != ENOENT) fail("could not stat lockfile");
133 if (stab.st_dev == fstab.st_dev &&
134 stab.st_ino == fstab.st_ino) break;
139 cloexec= fcntl(fd, F_GETFD); if (cloexec==-1) fail("fcntl F_GETFD");
141 if (fcntl(fd, F_SETFD, cloexec)==-1) fail("fcntl F_SETFD");
144 fail("unable to execute command");