flock: user-configurable exit code

When locking the file fails with -n or -w option, caller has no way
to distinguish between the exit code 1 of the -c command,
and the exit code 1 of flock(1) caused by the conflicting lock.

Add a new -E <exitcode> (--conflict-exit-code) option to set
the exit code for the case of locking failure to any value.
This commit is contained in:
Jan \"Yenya\" Kasprzak 2012-06-05 16:26:58 +02:00 committed by Karel Zak
parent e26de525e2
commit 827b1ceefd
2 changed files with 32 additions and 13 deletions

View File

@ -71,13 +71,19 @@ cases, for example if the enclosed command group may have forked a background
process which should not be holding the lock.
.TP
\fB\-n\fP, \fB\-\-nb\fP, \fB\-\-nonblock\fP
Fail (with an exit code of 1) rather than wait if the lock cannot be
Fail rather than wait if the lock cannot be
immediately acquired.
See the
.I \-E
option for the exit code used.
.TP
\fB\-w\fP, \fB\-\-wait\fP, \fB\-\-timeout\fP \fIseconds\fP
Fail (with an exit code of 1) if the lock cannot be acquired within
Fail if the lock cannot be acquired within
.IR seconds .
Decimal fractional values are allowed.
See the
.I \-E
option for the exit code used.
.TP
\fB\-o\fP, \fB\-\-close\fP
Close the file descriptor on which the lock is held before executing
@ -86,6 +92,11 @@ This is useful if
.B command
spawns a child process which should not be holding the lock.
.TP
\fB\-E\fP, \fB\-\-conflict\-exit\-code\fP \fInumber\fP
The exit code used when the \fB\-n\fP option is in use, and the
conflicting lock exists, or the \fB\-w\fP option is in use,
and the timeout is reached. The default value is 1.
.TP
\fB\-c\fP, \fB\-\-command\fP \fIcommand\fP
Pass a single
.IR command ,
@ -134,7 +145,9 @@ return values for everything else but an options
.I \-n
or
.I \-w
failures which return 1.
failures which return either the value given by the
.I \-E
option, or 1 by default.
.SH AUTHOR
.UR hpa@zytor.com
H. Peter Anvin

View File

@ -58,6 +58,7 @@ static void __attribute__((__noreturn__)) usage(int ex)
fputs(_( " -u --unlock remove a lock\n"), stderr);
fputs(_( " -n --nonblock fail rather than wait\n"), stderr);
fputs(_( " -w --timeout <secs> wait for a limited amount of time\n"), stderr);
fputs(_( " -E --conflict-exit-code <number> exit code after conflict or timeout\n"), stderr);
fputs(_( " -o --close close file descriptor before running command\n"), stderr);
fputs(_( " -c --command <command> run a single command string through the shell\n"), stderr);
fprintf(stderr, USAGE_SEPARATOR);
@ -141,6 +142,11 @@ int main(int argc, char *argv[])
int opt, ix;
int do_close = 0;
int status;
/*
* The default exit code for lock conflict or timeout
* is specified in man flock.1
*/
int conflict_exit_code = 1;
char **cmd_argv = NULL, *sh_c_argv[4];
const char *filename = NULL;
struct sigaction sa, old_sa;
@ -153,6 +159,7 @@ int main(int argc, char *argv[])
{"nb", no_argument, NULL, 'n'},
{"timeout", required_argument, NULL, 'w'},
{"wait", required_argument, NULL, 'w'},
{"conflict-exit-code", required_argument, NULL, 'E'},
{"close", no_argument, NULL, 'o'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
@ -171,7 +178,7 @@ int main(int argc, char *argv[])
optopt = 0;
while ((opt =
getopt_long(argc, argv, "+sexnouw:hV?", long_options,
getopt_long(argc, argv, "+sexnouw:E:hV?", long_options,
&ix)) != EOF) {
switch (opt) {
case 's':
@ -194,6 +201,10 @@ int main(int argc, char *argv[])
have_timeout = 1;
strtotimeval(optarg, &timeout.it_value);
break;
case 'E':
conflict_exit_code = strtos32_or_err(optarg,
_("invalid exit code"));
break;
case 'V':
printf("flock (%s)\n", PACKAGE_STRING);
exit(EX_OK);
@ -252,18 +263,13 @@ int main(int argc, char *argv[])
while (flock(fd, type | block)) {
switch (errno) {
case EWOULDBLOCK:
/* -n option set and failed to lock. The numeric
* exit value is specified in man flock.1
*/
exit(1);
/* -n option set and failed to lock. */
exit(conflict_exit_code);
case EINTR:
/* Signal received */
if (timeout_expired)
/* -w option set and failed to lock. The
* numeric exit value is specified in man
* flock.1
*/
exit(1);
/* -w option set and failed to lock. */
exit(conflict_exit_code);
/* otherwise try again */
continue;
case EIO: