3 * $Id: locking.c,v 1.2 2003/10/09 15:15:42 mdw Exp $
5 * Lock a file, run a program
7 * (c) 2003 Mark Wooding
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of the Toys utilties collection.
14 * Toys is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * Toys is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with Toys; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /*----- Revision history --------------------------------------------------*
32 * Revision 1.2 2003/10/09 15:15:42 mdw
33 * Missed a paren. Un-`toys'-ify.
35 * Revision 1.1 2003/10/09 15:05:34 mdw
38 * Revision 1.3 2003/09/24 14:58:08 mdw
39 * Fix options parsing again.
41 * Revision 1.2 2003/09/24 14:14:03 mdw
42 * Fix option handling behaviour.
44 * Revision 1.1 2003/05/11 13:30:04 mdw
49 /*----- Header files ------------------------------------------------------*/
58 #include <sys/types.h>
64 #include <mLib/mdwopt.h>
65 #include <mLib/quis.h>
66 #include <mLib/report.h>
68 /*----- Static variables --------------------------------------------------*/
72 /*----- Main code ---------------------------------------------------------*/
74 static void alrm(int s) { longjmp(jmp, 1); }
76 static void usage(FILE *fp)
79 "Usage: $ [-cfwx] [-p REALPROG] [-t TIMEOUT] FILE PROG ARGS...\n");
82 static void version(FILE *fp)
84 pquis(fp, "$ (version " VERSION ")\n");
87 static void help(FILE *fp)
93 Lock FILE and run PROG, passing ARGS. Options are:\n\
95 -h, --help Show this help message.\n\
96 -v, --version Show version string.\n\
97 -u, --usage Show terse usage summary.\n\
99 -c, --[no-]create Create FILE if it doesn't exist [default: on].\n\
100 -f, --[no-]fail Fail if the file is already locked [default: off].\n\
101 -w, --[no-]wait Wait for the lock to be available [default: off].\n\
102 -x, --[no-]exclusive Get an exclusive (writer) lock [default: on].\n\
103 -p, --program=REALPROG Run REALPROG instead of PROG.\n\
104 -t, --timeout=TIME Wait for TIME for lock to become available.\n\
108 int main(int argc, char *argv[])
110 const char *file = 0;
111 const char *prog = 0;
113 void (*oalrm)(int) = 0;
129 unsigned f = f_create | f_excl;
134 static const struct option opts[] = {
135 { "help", 0, 0, 'h' },
136 { "version", 0, 0, 'v' },
137 { "usage", 0, 0, 'u' },
138 { "wait", OPTF_NEGATE, 0, 'w' },
139 { "fail", OPTF_NEGATE, 0, 'f' },
140 { "create", OPTF_NEGATE, 0, 'c' },
141 { "program", OPTF_ARGREQ, 0, 'p' },
142 { "timeout", OPTF_ARGREQ, 0, 't' },
143 { "exclusive", OPTF_NEGATE, 0, 'x' },
147 int i = mdwopt(argc, argv, "-hvuw+f+c+x+p:t:", opts,
148 0, 0, OPTF_NEGATION);
164 case 'w' | OPTF_NEGATED:
170 case 'f' | OPTF_NEGATED:
176 case 'c' | OPTF_NEGATED:
182 case 'x' | OPTF_NEGATED:
187 t = strtol(optarg, &p, 0);
194 default: die(111, "unknown time unit `%c'", *p);
196 if (*p || t < 0 || errno)
197 die(111, "bad time value `%s'", optarg);
217 if (f & f_bogus || argc - optind < 1) {
226 ((f & f_create ? O_CREAT : 0) |
227 (f & f_excl ? O_RDWR : O_RDONLY)), 0666)) < 0)
228 die(111, "error opening `%s': %s", file, strerror(errno));
229 l.l_type = f & f_excl ? F_WRLCK : F_RDLCK;
230 l.l_whence = SEEK_SET;
239 oalrm = signal(SIGALRM, alrm);
242 if (fcntl(fd, f & f_wait ? F_SETLKW : F_SETLK, &l) >= 0)
245 signal(SIGALRM, oalrm);
254 ((errno != EAGAIN && errno != EWOULDBLOCK && errno != EACCES) ||
256 die(111, "error locking `%s': %s", file, strerror(errno));
260 if ((kid = fork()) < 0)
261 die(111, "error from fork: %s", strerror(errno));
265 die(111, "couldn't exec `%s': %s", prog, strerror(errno));
267 if (waitpid(kid, &st, 0) < 0)
268 die(EXIT_FAILURE, "error from wait: %s", strerror(errno));
270 l.l_whence = SEEK_SET;
273 fcntl(fd, F_SETLK, &l);
276 exit(WEXITSTATUS(st));
281 /*----- That's all, folks -------------------------------------------------*/