Package: chiark-utils-bin Version: 4.2.0 Severity: wishlist Tags: upstream patch
Hi, I wanted a timeout option to with-lock-ex. The attached patch provides this - you can see -t <secs> after -q or -f and with-lock-ex will then wait that long while trying to get the lock before quitting. I have built and tested the attached patch against the current master branch in git. -- System Information: Debian Release: 7.11 APT prefers oldstable-updates APT policy: (500, 'oldstable-updates'), (500, 'oldstable') Architecture: i386 (i686) Kernel: Linux 3.2.0-4-686-pae (SMP w/4 CPU cores) Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages chiark-utils-bin depends on: ii libc6 2.13-38+deb7u11 Versions of packages chiark-utils-bin recommends: ii libc6 2.13-38+deb7u11 ii libgmp10 2:5.0.5+dfsg-2 ii libnettle4 2.4-3+deb7u1 Versions of packages chiark-utils-bin suggests: ii libx11-6 2:1.5.0-1+deb7u4 -- no debconf information
diff --git a/cprogs/with-lock-ex.c b/cprogs/with-lock-ex.c index 2b7b45b..560711f 100644 --- a/cprogs/with-lock-ex.c +++ b/cprogs/with-lock-ex.c @@ -2,7 +2,7 @@ * File locker * * Usage: - * with-lock-ex -<mode> <lockfile> <command> <args>... + * with-lock-ex -<mode> [-t <secs>] <lockfile> <command> <args>... * with-lock-ex -l <lockfile> * * modes are @@ -13,6 +13,11 @@ * or "write <pid>"; lockfile opened for reading; * no command may be specified) * + * if -t is specified, then with-lock-ex will wait for up to <secs> + * seconds to acquire the lock, and then fail or silently do nothing + * (depending on whether -f or -q is specified). You cannot specify + * a timeout for modes l or w + * * with-lock-ex will open and lock the lockfile for writing and * then feed the remainder of its arguments to exec(2); when * that process terminates the fd will be closed and the file @@ -32,6 +37,10 @@ #include <unistd.h> #include <string.h> #include <sys/stat.h> +#include <limits.h> +#include <time.h> +#include <signal.h> +#include <sys/time.h> static const char *cmd; @@ -42,12 +51,22 @@ static void fail(const char *why) { exit(255); } +volatile int alarmed = 0; + +static void alrm_handler(int signum) { + alarmed = 1; +} + int main(int argc, char **argv) { int fd, mode, um; struct stat stab, fstab; - long cloexec; + long cloexec, secs=-1; struct flock fl; const char *p; + char *endptr; + time_t tstart=0, tend=0; + struct sigaction siga, oldsiga; + struct itimerval itv; if (argc >= 3 && !strcmp((p= strrchr(argv[0],'/')) ? ++p : argv[0], "with-lock")) { mode= 'f'; @@ -56,7 +75,7 @@ int main(int argc, char **argv) { && mode != 'l') || (mode != 'l' && argc < 4) || (mode == 'l' && argc != 3)) { - fputs("usage: with-lock-ex -w|-q|-f <lockfile> <command> <args>...\n" + fputs("usage: with-lock-ex -w|-q|-f [-t <secs>] <lockfile> <command> <args>...\n" " with-lock-ex -l <lockfile>\n" " with-lock <lockfile> <command> <args>...\n", stderr); @@ -64,6 +83,39 @@ int main(int argc, char **argv) { } else { argv++; argc--; } + if (0 == strncmp(argv[1],"-t",2)) { + errno = 0; + secs = strtol(argv[2], &endptr, 0); + if ((errno == ERANGE && (secs == LONG_MAX || secs == LONG_MIN)) + || (errno !=0 && secs == 0)) { + fail("parsing timeout value"); + } + if (secs <= 0) { + fputs("timeout value must be greater than zero.\n", + stderr); + exit(255); + } + tstart = time(NULL); if (tstart==(time_t)-1) fail("getting current time"); + if (mode=='l' || mode=='w') { + fputs("-t only allowed with -q or -f.\n", stderr); + exit(255); + } + argv+= 2; argc-= 2; + if (argc < 2) { + fputs("Insufficient arguments following -t\n" + "Usage: with-lock-ex -f|q -t <secs> <lockfile> <command> <args>...\n", + stderr); + exit(255); + } + /*Install SIGALRM handler, and set a timer for secs seconds from now*/ + memset(&siga,0,sizeof(siga)); + siga.sa_handler=alrm_handler; + if (sigaction(SIGALRM,&siga,&oldsiga)) fail("Installing SIGALRM handler"); + memset(&itv,0,sizeof(itv)); + itv.it_value.tv_sec=secs; + if (setitimer(ITIMER_REAL,&itv,NULL)) fail("Setting timer"); + } + cmd= argv[2]; um= umask(0777); if (um==-1) fail("find umask"); if (umask(um)==-1) fail("reset umask"); @@ -82,9 +134,21 @@ int main(int argc, char **argv) { fl.l_len= mode=='l' ? 0 : 1; if (fcntl(fd, mode=='l' ? F_GETLK : - mode=='w' ? F_SETLKW : + mode=='w' || secs > 0 ? F_SETLKW : F_SETLK, &fl) != -1) break; + if (alarmed==1) { + tend = time(NULL); if (tend==(time_t)-1) fail("getting current time"); + if (tend-tstart >= secs) { + if (mode=='q') exit(0); + else { + fprintf(stderr, + "with-lock-ex %s: timer expired while trying to acquire lock\n", + cmd); + exit(255); + } + } else alarmed=0; + } if (mode=='q' && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EBUSY)) exit(0); @@ -102,6 +166,11 @@ int main(int argc, char **argv) { if (ferror(stdout)) fail("print to stdout\n"); exit(0); } + if (secs > 0) { + itv.it_value.tv_sec=0; + if (setitimer(ITIMER_REAL,&itv,NULL)) fail("Clearing timer"); + if (sigaction(SIGALRM,&oldsiga,NULL)) fail("Restoring SIGALRM handler"); + } if (fstat(fd, &fstab)) fail("could not fstat lock fd"); if (stat(argv[1], &stab)) {