summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoeyh <joeyh>2007-09-06 01:28:28 +0000
committerjoeyh <joeyh>2007-09-06 01:28:28 +0000
commit70564cb95575300bd77dd8035f2d010e9030de4c (patch)
tree6554132b24d33391845a09ea842d23269d710a0f
parent2025c9c518e7165da3d08b28bb7d62682d2f3b1f (diff)
downloadmoreutils-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--Makefile10
-rw-r--r--README2
-rw-r--r--debian/changelog7
-rw-r--r--debian/control3
-rw-r--r--debian/copyright2
-rwxr-xr-xdebian/rules2
-rw-r--r--lckdo.c227
-rw-r--r--lckdo.docbook145
8 files changed, 393 insertions, 5 deletions
diff --git a/Makefile b/Makefile
index 8f9db54..a15226e 100644
--- a/Makefile
+++ b/Makefile
@@ -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" $< > $@;
diff --git a/README b/README
index c07e565..702bb0d 100644
--- a/README
+++ b/README
@@ -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
diff --git a/lckdo.c b/lckdo.c
new file mode 100644
index 0000000..39b7f17
--- /dev/null
+++ b/lckdo.c
@@ -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>