diff options
author | joeyh <joeyh> | 2007-09-06 01:28:28 +0000 |
---|---|---|
committer | joeyh <joeyh> | 2007-09-06 01:28:28 +0000 |
commit | 70564cb95575300bd77dd8035f2d010e9030de4c (patch) | |
tree | 6554132b24d33391845a09ea842d23269d710a0f | |
parent | 2025c9c518e7165da3d08b28bb7d62682d2f3b1f (diff) | |
download | moreutils-70564cb95575300bd77dd8035f2d010e9030de4c.tar.gz |
* Don't strip binaries for debian package if built with
DEB_BUILD_OPTIONS=nostrip. Closes: #437577
* Include Michael Tokarev's lckdo program and replace / conflict with the
current lckdo package. (Robert Edmonds) Closes: #432906
* lckdo: Don't clear other flags when setting close on exec.
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | debian/changelog | 7 | ||||
-rw-r--r-- | debian/control | 3 | ||||
-rw-r--r-- | debian/copyright | 2 | ||||
-rwxr-xr-x | debian/rules | 2 | ||||
-rw-r--r-- | lckdo.c | 227 | ||||
-rw-r--r-- | lckdo.docbook | 145 |
8 files changed, 393 insertions, 5 deletions
@@ -1,7 +1,8 @@ -BINS=isutf8 ifdata pee sponge mispipe +BINS=isutf8 ifdata pee sponge mispipe lckdo PERLSCRIPTS=vidir vipe ts combine zrun -MANS=sponge.1 vidir.1 vipe.1 isutf8.1 ts.1 combine.1 ifdata.1 pee.1 zrun.1 mispipe.1 +MANS=sponge.1 vidir.1 vipe.1 isutf8.1 ts.1 combine.1 ifdata.1 pee.1 zrun.1 mispipe.1 lckdo.1 CFLAGS=-O2 -g -Wall +INSTALL_BIN=install -s all: $(BINS) $(MANS) @@ -10,7 +11,7 @@ clean: install: mkdir -p $(PREFIX)/usr/bin - install -s $(BINS) $(PREFIX)/usr/bin + $(INSTALL_BIN) $(BINS) $(PREFIX)/usr/bin install $(PERLSCRIPTS) $(PREFIX)/usr/bin mkdir -p $(PREFIX)/usr/share/man/man1 @@ -34,5 +35,8 @@ sponge.1: sponge.docbook mispipe.1: mispipe.docbook docbook2x-man $< +lckdo.1: lckdo.docbook + docbook2x-man $< + %.1: % pod2man --center=" " --release="moreutils" $< > $@; @@ -7,6 +7,8 @@ ifdata get network interface info without parsing ifconfig output isutf8 check if a file or standard input is utf-8 +lckdo + execute a program with a lock held mispipe pipe two commands, returning the exit status of the first pee diff --git a/debian/changelog b/debian/changelog index 52e97b5..a87665b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,13 @@ moreutils (0.23) UNRELEASED; urgency=low * Add pointer to join from combine's man page. Closes: #435516 + * Don't strip binaries for debian package if built with + DEB_BUILD_OPTIONS=nostrip. Closes: #437577 + * Include Michael Tokarev's lckdo program and replace / conflict with the + current lckdo package. (Robert Edmonds) Closes: #432906 + * lckdo: Don't clear other flags when setting close on exec. - -- Joey Hess <joeyh@debian.org> Wed, 01 Aug 2007 13:45:23 -0400 + -- Joey Hess <joeyh@debian.org> Wed, 05 Sep 2007 21:21:29 -0400 moreutils (0.22) unstable; urgency=low diff --git a/debian/control b/debian/control index 7fb0cb9..06b7339 100644 --- a/debian/control +++ b/debian/control @@ -10,6 +10,8 @@ Package: moreutils Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} Suggests: libtime-duration-perl, libtimedate-perl +Conflicts: lckdo +Replaces: lckdo Description: additional unix utilities This is a growing collection of the unix tools that nobody thought to write thirty years ago. @@ -25,3 +27,4 @@ Description: additional unix utilities - zrun: automatically uncompress arguments to command - mispipe: pipe two commands, returning the exit status of the first - isutf8: check if a file or standard input is utf-8 + - lckdo: execute a program with a lock held diff --git a/debian/copyright b/debian/copyright index 22e443e..6b65c16 100644 --- a/debian/copyright +++ b/debian/copyright @@ -19,6 +19,8 @@ zrun is Copyright (c) Chung-chieh Shan, under the terms of the GPL, version mispipe is Copyright (c) Nathanael Nerode, under the terms of the GPL, version 2 or later. (It's also dual-licensed under the MIT/Expat licence.) +lckdo is public domain code released by Michael Tokarev. + Everything else is copyright 2006 by Joey Hess, under the terms of GPL. The full text of the GNU GPL can be found in /usr/share/common-licenses/GPL on Debian systems. diff --git a/debian/rules b/debian/rules index 10f0e79..5964448 100755 --- a/debian/rules +++ b/debian/rules @@ -21,7 +21,7 @@ binary-arch: build dh_testroot dh_clean -k dh_installdirs - $(MAKE) PREFIX=debian/moreutils install + $(MAKE) PREFIX=debian/moreutils INSTALL_BIN=install install dh_installdocs README dh_installchangelogs dh_perl @@ -0,0 +1,227 @@ +/* lckdo.c: run a program with a lock held, + * to prevent multiple processes running in parallel. + * Use just like `nice' or `nohup'. + * Written by Michael Tokarev <mjt@tls.msk.ru> + * Public domain. + */ + +#define _GNU_SOURCE +#define _BSD_SOURCE +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <stdarg.h> +#include <sysexits.h> +#include <sys/file.h> +#include <sys/wait.h> +#include <signal.h> + +/* compile with -DUSE_FLOCK to use flock() instead of fcntl() */ + +#if !defined(USE_FLOCK) && !defined(F_SETLKW) +# define USE_FLOCK +#endif + +#ifndef __GNUC__ +# ifndef __attribute__ +# define __attribute__(x) +# endif +#endif + +static char *progname; +static void +__attribute__((format(printf,3,4))) +__attribute__((noreturn)) +error(int errnum, int exitcode, const char *fmt, ...) { + va_list ap; + fprintf(stderr, "%s: ", progname); + va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); + if (errnum) fprintf(stderr, ": %s\n", strerror(errnum)); + else fputs("\n", stderr); + exit(exitcode); +} + +static const char *lckfile; +static int quiet; + +static void sigalarm(int sig) { + if (quiet) + _exit(EX_TEMPFAIL); + error(0, EX_TEMPFAIL, + "lock file `%s' is already locked (timeout waiting)", lckfile); + sig = sig; +} + +int main(int argc, char **argv) { + int fd; + int c; + int create = O_CREAT; + int dofork = 1; + int waittime = 0; + int shared = 0; + int test = 0; + int fdn = -1; +#ifndef USE_FLOCK + struct flock fl; +#endif + + if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; + else argv[0] = ++progname; + + if (argc == 1) { + printf( +"%s: execute a program with a lock set.\n" +"Usage: %s [options] lockfile program [arguments]\n" +"where options are:\n" +" -w - if the lock is already held by another process,\n" +" wait for it to complete instead of failing immediately\n" +" -W sec - the same as -w but wait not more than sec seconds\n" +" -e - execute the program directly, no fork/wait\n" +" (keeps extra open file descriptor)\n" +" -E nnn - set the fd# to keep open in -e case (implies -e)\n" +" -n - do not create the lock file if it does not exist\n" +" -q - produce no output if lock is already held\n" +" -s - lock in shared (read) mode\n" +" -x - lock in exclusive (write) mode (default)\n" +" -t - test for lock existence" +#ifndef USE_FLOCK + " (just prints pid if any with -q)\n" +#endif +" (implies -n)\n" + , progname, progname); + return 0; + } + + while((c = getopt(argc, argv, "+wW:neE:sxtq")) != EOF) + switch(c) { + case 'w': + if (!waittime) + waittime = -1; + break; + case 'W': + if ((waittime = atoi(optarg)) < 1) + error(0, EX_USAGE, "invalid wait time `%s'", optarg); + break; + case 't': + test = 1; + /* fall */ + case 'n': + create = 0; + break; + case 'E': + if ((fdn = atoi(optarg)) < 0 || fdn == 2) + error(0, EX_USAGE, "invalid fd# `%s'", optarg); + /* fall */ + case 'e': + dofork = 0; + break; + case 's': + shared = 1; + break; + case 'x': + shared = 0; + break; + case 'q': + quiet = 1; + break; + default: + return EX_USAGE; + } + + argc -= optind; argv += optind; + if (!argc || (!test && argc < 2)) + error(0, EX_USAGE, "too few arguments given"); + + lckfile = *argv++; + +#ifdef USE_FLOCK + create |= O_RDONLY; +#else + if (!test) + create |= shared ? O_RDONLY : O_WRONLY; +#endif + fd = open(lckfile, create, 0666); + if (fd < 0) { + if (test && errno == ENOENT) { + if (!quiet) + printf("lockfile `%s' is not locked\n", lckfile); + return 0; + } + error(errno, EX_CANTCREAT, "unable to open `%s'", lckfile); + } + + if (!test && fdn >= 0) { + /* dup it early to comply with stupid POSIX fcntl locking semantics */ + if (dup2(fd, fdn) < 0) + error(errno, EX_OSERR, "dup2(%d,%d) failed", fd, fdn); + close(fd); + fd = fdn; + } + + if (test) + waittime = 0; + else if (waittime > 0) { + alarm(waittime); + signal(SIGALRM, sigalarm); + } +#ifdef USE_FLOCK + c = flock(fd, (shared ? LOCK_SH : LOCK_EX) | (waittime ? 0 : LOCK_NB)); + if (test && c < 0 && + (errno == EWOULDBLOCK || errno == EAGAIN || errno == EACCES)) { + if (!quiet) + printf("lockfile `%s' is locked\n", lckfile); + else + printf("locked\n"); + return EX_TEMPFAIL; + } +#else + memset(&fl, 0, sizeof(fl)); + fl.l_type = shared ? F_RDLCK : F_WRLCK; + c = fcntl(fd, test ? F_GETLK : waittime ? F_SETLKW : F_SETLK, &fl); + if (test && c == 0) { + if (fl.l_type == F_UNLCK) { + if (!quiet) + printf("lockfile `%s' is not locked\n", lckfile); + return 0; + } + if (!quiet) + printf("lockfile `%s' is locked by process %d\n", lckfile, fl.l_pid); + else + printf("%d\n", fl.l_pid); + return EX_TEMPFAIL; + } +#endif + if (waittime > 0) + alarm(0); + if (c < 0) { + if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EACCES) + error(errno, EX_OSERR, "unable to lock `%s'", lckfile); + else if (quiet) + return EX_TEMPFAIL; + else + error(0, EX_TEMPFAIL, "lockfile `%s' is already locked", lckfile); + } + + if (dofork) { + pid_t pid; + int flags = fcntl(fd, F_GETFD, 0); + if (flags < 0) + error(errno, EX_OSERR, "fcntl() failed"); + fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + pid = fork(); + if (pid < 0) + error(errno, EX_OSERR, "unable to fork"); + else if (pid) { + if (wait(&c) < 0) + error(errno, EX_OSERR, "wait() failed"); + if (WIFSIGNALED(c)) + error(0, EX_SOFTWARE, "%s: %s", *argv, strsignal(WTERMSIG(c))); + return WEXITSTATUS(c); + } + } + execvp(*argv, argv); + error(errno, EX_OSERR, "unable to execute %s", *argv); +} diff --git a/lckdo.docbook b/lckdo.docbook new file mode 100644 index 0000000..8a0a4a8 --- /dev/null +++ b/lckdo.docbook @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + +Written by Michael Tokarev <mjt@tls.msk.ru> +Public domain. + +--> + +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.4//EN" +"file:///usr/share/xml/docbook/schema/dtd/4.4/docbookx.dtd" +[]> + +<refentry> + <refentryinfo> + <address> + <email>mjt@tls.msk.ru</email> + </address> + <author> + <firstname>Michael</firstname> + <surname>Tokarev</surname> + </author> + <date>2007-08-15</date> + </refentryinfo> + + <refmeta> + <refentrytitle>lckdo</refentrytitle> + <manvolnum>1</manvolnum> + </refmeta> + + <refnamediv> + <refname>lckdo</refname> + <refpurpose>run a program with a lock held</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>lckdo</command> + <arg>options</arg> + <arg choice="req">lockfile</arg> + <arg choice="req">program</arg> + <arg>arguments</arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>DESCRIPTION</title> + + <para><command>lckdo</command> runs a program with a lock + held, in order to prevent multiple processes from running in + parallel. Use just like <command>nice</command> or + <command>nohup</command>.</para> + + </refsect1> + + <refsect1> + <title>OPTIONS</title> + + <variablelist> + + <varlistentry> + <term><option>-w</option></term> + <listitem> + <para>If the lock is already held by another process, + wait for it to complete instead of failing + immediately.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>-W {sec}</option></term> + <listitem> + <para>The same as -w but wait not more than sec + seconds.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>-e</option></term> + <listitem> + <para>Execute the program directly without forking and + waiting (keeps an extra file descriptor open).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>-E {nnn}</option></term> + <listitem> + <para>Set the file descriptor number to keep open when + exec()ing (implies -e).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>-n</option></term> + <listitem> + <para>Do not create the lock file if it does not + exist.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>-q</option></term> + <listitem> + <para>Produce no output if lock is already held.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>-s</option></term> + <listitem> + <para>Lock in shared (read) mode.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>-x</option></term> + <listitem> + <para>Lock in exclusive (write) mode (default).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>-t</option></term> + <listitem> + <para>Test for lock existence.</para> + </listitem> + </varlistentry> + + </variablelist> + + </refsect1> + + <refsect1> + <title>EXIT STATUS</title> + + <para>If the lock was successfully acquired, the return value is that + of the program invoked by <command>lckdo</command>. If the lock + couldn't be acquired, EX_TEMPFAIL is returned. If there was a problem + opening/creating or locking the lock file, EX_CANTCREAT or EX_OSERR + will be returned.</para> + + </refsect1> + +</refentry> |