Michael Tokarev wrote:
> No, I'm not really a Debian Developer (yet, still, ...).  My packages
> in Debian are sponsored by other people.

Oh, I didn't realize that.  I make heavy use of rbldnsd and lckdo on my
DNS mirrors; I'd be happy to sponsor any package you'd like in the
archive.

> Concering lckdo - it's a very tiny utility.  Yes it's handy sometimes,
> and I was VERY surprized when I tried to find something similar but
> found nothing (newslock, lockexec or something like those - used in
> shell scripts to do locking - works a bit differently, and mostly
> too complex and too unreliable).
> 
> I don't think it deserves its own package due to it's "size".  I wish
> to see something like lckdo as a standard utility somewhere, maybe
> like in coreutils -- but moreutils looks ok too.
> 
> So if you want(ed) to package it together with the rest of small
> assorted utilities, I'm ok with that.

I'd say getting it in coreutils is a long shot, but here's a patch for
moreutils.  Joey?

-- 
Robert Edmonds
[EMAIL PROTECTED]
diff -Nru moreutils-0.22/Makefile moreutils-0.23~lckdo.0/Makefile
--- moreutils-0.22/Makefile	2006-09-07 20:26:46.000000000 -0400
+++ moreutils-0.23~lckdo.0/Makefile	2007-08-15 22:15:23.272263535 -0400
@@ -1,6 +1,6 @@
-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
 
 all: $(BINS) $(MANS)
@@ -34,5 +34,8 @@
 mispipe.1: mispipe.docbook
 	docbook2x-man $<
 
+lckdo.1: lckdo.docbook
+	docbook2x-man $<
+
 %.1: %
 	pod2man --center=" " --release="moreutils" $< > $@;
diff -Nru moreutils-0.22/debian/changelog moreutils-0.23~lckdo.0/debian/changelog
--- moreutils-0.22/debian/changelog	2007-06-25 16:11:32.000000000 -0400
+++ moreutils-0.23~lckdo.0/debian/changelog	2007-08-15 22:20:33.201925422 -0400
@@ -1,3 +1,10 @@
+moreutils (0.23~lckdo.0) unstable; urgency=low
+
+  * Include Michael Tokarev's lckdo program and replace / conflict with the
+    current lckdo package.
+
+ -- Robert S. Edmonds <[EMAIL PROTECTED]>  Wed, 15 Aug 2007 22:19:17 -0400
+
 moreutils (0.22) unstable; urgency=low
 
   * vidir, zrun: Don't put temp files in the current directory. Closes: #429367
diff -Nru moreutils-0.22/debian/control moreutils-0.23~lckdo.0/debian/control
--- moreutils-0.22/debian/control	2006-12-23 21:55:24.000000000 -0500
+++ moreutils-0.23~lckdo.0/debian/control	2007-08-15 22:18:40.919526811 -0400
@@ -10,6 +10,8 @@
 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 @@
   - 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 -Nru moreutils-0.22/debian/copyright moreutils-0.23~lckdo.0/debian/copyright
--- moreutils-0.22/debian/copyright	2006-09-07 20:12:15.000000000 -0400
+++ moreutils-0.23~lckdo.0/debian/copyright	2007-08-15 22:17:07.618209873 -0400
@@ -19,6 +19,8 @@
 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 -Nru moreutils-0.22/lckdo.c moreutils-0.23~lckdo.0/lckdo.c
--- moreutils-0.22/lckdo.c	1969-12-31 19:00:00.000000000 -0500
+++ moreutils-0.23~lckdo.0/lckdo.c	2007-08-15 22:14:31.649321713 -0400
@@ -0,0 +1,224 @@
+/* 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 <[EMAIL PROTECTED]>
+ * 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;
+    fcntl(fd, F_SETFD, 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 -Nru moreutils-0.22/lckdo.docbook moreutils-0.23~lckdo.0/lckdo.docbook
--- moreutils-0.22/lckdo.docbook	1969-12-31 19:00:00.000000000 -0500
+++ moreutils-0.23~lckdo.0/lckdo.docbook	2007-08-15 22:34:45.470493447 -0400
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+
+Written by Michael Tokarev <[EMAIL PROTECTED]>
+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>[EMAIL PROTECTED]</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>

Attachment: signature.asc
Description: Digital signature

Reply via email to