3 * $Id: locking.c,v 1.1 2003/10/09 15:05:34 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.1 2003/10/09 15:05:34 mdw
35 * Revision 1.3 2003/09/24 14:58:08 mdw
36 * Fix options parsing again.
38 * Revision 1.2 2003/09/24 14:14:03 mdw
39 * Fix option handling behaviour.
41 * Revision 1.1 2003/05/11 13:30:04 mdw
46 /*----- Header files ------------------------------------------------------*/
55 #include <sys/types.h>
61 #include <mLib/mdwopt.h>
62 #include <mLib/quis.h>
63 #include <mLib/report.h>
65 /*----- Static variables --------------------------------------------------*/
69 /*----- Main code ---------------------------------------------------------*/
71 static void alrm(int s
) { longjmp(jmp
, 1); }
73 static void usage(FILE *fp
)
76 "Usage: $ [-cfwx] [-p REALPROG] [-t TIMEOUT] FILE PROG ARGS...\n");
79 static void version(FILE *fp
)
81 pquis(fp
, "$ (toys, version " VERSION
"\n");
84 static void help(FILE *fp
)
90 Lock FILE and run PROG, passing ARGS. Options are:\n\
92 -h, --help Show this help message.\n\
93 -v, --version Show version string.\n\
94 -u, --usage Show terse usage summary.\n\
96 -c, --[no-]create Create FILE if it doesn't exist [default: on].\n\
97 -f, --[no-]fail Fail if the file is already locked [default: off].\n\
98 -w, --[no-]wait Wait for the lock to be available [default: off].\n\
99 -x, --[no-]exclusive Get an exclusive (writer) lock [default: on].\n\
100 -p, --program=REALPROG Run REALPROG instead of PROG.\n\
101 -t, --timeout=TIME Wait for TIME for lock to become available.\n\
105 int main(int argc
, char *argv
[])
107 const char *file
= 0;
108 const char *prog
= 0;
110 void (*oalrm
)(int) = 0;
126 unsigned f
= f_create
| f_excl
;
131 static const struct option opts
[] = {
132 { "help", 0, 0, 'h' },
133 { "version", 0, 0, 'v' },
134 { "usage", 0, 0, 'u' },
135 { "wait", OPTF_NEGATE
, 0, 'w' },
136 { "fail", OPTF_NEGATE
, 0, 'f' },
137 { "create", OPTF_NEGATE
, 0, 'c' },
138 { "program", OPTF_ARGREQ
, 0, 'p' },
139 { "timeout", OPTF_ARGREQ
, 0, 't' },
140 { "exclusive", OPTF_NEGATE
, 0, 'x' },
144 int i
= mdwopt(argc
, argv
, "-hvuw+f+c+x+p:t:", opts
,
145 0, 0, OPTF_NEGATION
);
161 case 'w' | OPTF_NEGATED
:
167 case 'f' | OPTF_NEGATED
:
173 case 'c' | OPTF_NEGATED
:
179 case 'x' | OPTF_NEGATED
:
184 t
= strtol(optarg
, &p
, 0);
191 default: die(111, "unknown time unit `%c'", *p
);
193 if (*p
|| t
< 0 || errno
)
194 die(111, "bad time value `%s'", optarg
);
214 if (f
& f_bogus
|| argc
- optind
< 1) {
223 ((f
& f_create ? O_CREAT
: 0) |
224 (f
& f_excl ? O_RDWR
: O_RDONLY
)), 0666)) < 0)
225 die(111, "error opening `%s': %s", file
, strerror(errno
));
226 l
.l_type
= f
& f_excl ? F_WRLCK
: F_RDLCK
;
227 l
.l_whence
= SEEK_SET
;
236 oalrm
= signal(SIGALRM
, alrm
);
239 if (fcntl(fd
, f
& f_wait ? F_SETLKW
: F_SETLK
, &l
) >= 0)
242 signal(SIGALRM
, oalrm
);
251 ((errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
&& errno
!= EACCES
) ||
253 die(111, "error locking `%s': %s", file
, strerror(errno
));
257 if ((kid
= fork()) < 0)
258 die(111, "error from fork: %s", strerror(errno
));
262 die(111, "couldn't exec `%s': %s", prog
, strerror(errno
));
264 if (waitpid(kid
, &st
, 0) < 0)
265 die(EXIT_FAILURE
, "error from wait: %s", strerror(errno
));
267 l
.l_whence
= SEEK_SET
;
270 fcntl(fd
, F_SETLK
, &l
);
273 exit(WEXITSTATUS(st
));
278 /*----- That's all, folks -------------------------------------------------*/