/* $Id: dotlock.c,v 1.6 2006/05/11 19:48:10 dm Exp $ */ /* * * Copyright (C) 2004 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #include "local.h" #include #include #include #include "getopt_long.h" char *progname; char *deleteme; static void clean (int sig) { if (deleteme) unlink (deleteme); _exit (sig != 0); } static void launch_locker (const char *path) { int fds[2]; pid_t pid; char c = 0; if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds)) { perror ("socketpair"); exit (1); } pid = fork (); if (pid == -1) { perror ("fork"); exit (1); } if (!pid) { int dfd, lfd; fd_set fdsr; setsid (); close (fds[0]); signal (SIGINT, SIG_IGN); signal (SIGTERM, SIG_IGN); signal (SIGTSTP, SIG_IGN); if (dotlock (&dfd, &deleteme, path, &lfd)) _exit (1); write (fds[1], &c, 1); shutdown (fds[1], SHUT_WR); FD_ZERO (&fdsr); for (;;) { struct timeval tv; struct stat sb1, sb2; tv.tv_sec = 15; tv.tv_usec = 0; FD_SET (fds[1], &fdsr); if (select (fds[1]+1, &fdsr, NULL, NULL, &tv) == 1 && read (fds[1], &c, 1) < 1) clean (0); if (fstat (lfd, &sb1) || lstat (deleteme, &sb2) || sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) { fprintf (stderr, "%s: lost the lock on %s\n", progname, path); exit (1); } /* utime (path, NULL); */ utime (deleteme, NULL); } } close (fds[1]); if (read (fds[0], &c, 1) < 1) { fprintf (stderr, "cannot lock %s\n", path); exit (1); } } static void usage (void) __attribute__ ((noreturn)); static void usage (void) { fprintf (stderr, "usage: %s [-LPW] mailbox command [arg ...]\n", progname); exit (1); } int main (int argc, char **argv) { struct option o[] = { { "version", no_argument, NULL, 'v' }, { "fcntl", no_argument, NULL, 'P' }, { "noflock", no_argument, NULL, 'L' }, { "nowait", no_argument, NULL, 'W' }, { NULL, 0, NULL, 0 } }; int c; char **av; progname = strrchr (argv[0], '/'); if (progname) progname++; else progname = argv[0]; while ((c = getopt_long (argc, argv, "+LPW", o, NULL)) != -1) switch (c) { case 'L': opt_noflock = 1; break; case 'P': opt_fcntl = 1; break; case 'W': opt_nowait = 1; break; case 'v': version (progname, 1); exit (0); break; default: usage (); break; } argv += optind; argc -= optind; if (argc < 2) usage (); av = xmalloc (sizeof (av[0]) * argc); for (c = 1; c < argc; c++) av[c - 1] = argv[c]; av[argc - 1] = NULL; launch_locker (argv[0]); execvp (av[0], av); perror (av[0]); exit (1); }