]> Pileus Git - ~andy/fetchmail/blobdiff - lock.c
Attempt merging from 6.3.24.
[~andy/fetchmail] / lock.c
diff --git a/lock.c b/lock.c
index 89bf896a79d5420795bf5b80d53db972c70adcd7..2d656df65289fcf3ae829ac3d5306cb192fd3d03 100644 (file)
--- a/lock.c
+++ b/lock.c
@@ -1,50 +1,53 @@
-/*
- * lock.c -- cross-platform concurrency locking for fetchmail
+/**
+ * \file lock.c cross-platform concurrency locking for fetchmail
  *
  * For license terms, see the file COPYING in this directory.
  */
 #include "config.h"
 
 #include <stdio.h>
-#ifdef HAVE_STRING_H
 #include <string.h> /* strcat() */
-#endif
-#if defined(STDC_HEADERS)
 #include <stdlib.h>
-#endif
-#if defined(HAVE_UNISTD_H)
 #include <unistd.h>
-#endif
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
 
 #include "fetchmail.h"
-#include "i18n.h"
+#include "gettext.h"
+#include "lock.h"
 
-static char *lockfile;         /* name of lockfile */
-static int lock_acquired;      /* have we acquired a lock */
+static char *lockfile;         /** name of lockfile */
+static int lock_acquired;      /** flag if have we acquired a lock */
 
-void lock_setup(void)
+void fm_lock_setup(struct runctl *ctl)
 /* set up the global lockfile name */
 {
     /* set up to do lock protocol */
-#define        FETCHMAIL_PIDFILE       "fetchmail.pid"
+    const char *const FETCHMAIL_PIDFILE="fetchmail.pid";
+
+    /* command-line option override */
+    if (ctl->pidfile) {
+       lockfile = xstrdup(ctl->pidfile);
+       return;
+    }
+
+    /* defaults */
     if (getuid() == ROOT_UID) {
-       lockfile = (char *)xmalloc(
-               sizeof(PID_DIR) + sizeof(FETCHMAIL_PIDFILE) + 1);
+       lockfile = (char *)xmalloc(strlen(PID_DIR)
+               + strlen(FETCHMAIL_PIDFILE) + 2); /* 2: "/" and NUL */
        strcpy(lockfile, PID_DIR);
        strcat(lockfile, "/");
        strcat(lockfile, FETCHMAIL_PIDFILE);
     } else {
-       lockfile = (char *)xmalloc(strlen(fmhome)+sizeof(FETCHMAIL_PIDFILE)+2);
+       lockfile = (char *)xmalloc(strlen(fmhome)
+               + strlen(FETCHMAIL_PIDFILE) + 3); /* 3: "/", "." and NUL */
        strcpy(lockfile, fmhome);
        strcat(lockfile, "/");
-        if (fmhome == home)
-          strcat(lockfile, ".");
+       if (fmhome == home)
+          strcat(lockfile, ".");
        strcat(lockfile, FETCHMAIL_PIDFILE);
     }
-#undef FETCHMAIL_PIDFILE
 }
 
 static void unlockit(void)
@@ -54,53 +57,76 @@ static void unlockit(void)
        unlink(lockfile);
 }
 
-void lock_dispose(void)
+void fm_lock_dispose(void)
 /* arrange for a lock to be removed on process exit */
 {
-#ifdef HAVE_ATEXIT
     atexit(unlockit);
-#endif
 }
 
-int lock_state(void)
+int fm_lock_state(void)
 {
-    int                pid, st;
+    long       pid;
+    int                st;
     FILE       *lockfp;
     int                bkgd = FALSE;
 
     if ((lockfp = fopen(lockfile, "r")) != NULL)
     {
-       int args = fscanf(lockfp, "%d %d", &pid, &st);
+       int args = fscanf(lockfp, "%ld %d", &pid, &st);
        bkgd = (args == 2);
 
-       if (ferror(lockfp))
+       if (ferror(lockfp)) {
            fprintf(stderr, GT_("fetchmail: error reading lockfile \"%s\": %s\n"),
                    lockfile, strerror(errno));
+           fclose(lockfp); /* not checking should be safe, file mode was "r" */
+           exit(PS_EXCLUDE);
+       }
+       fclose(lockfp); /* not checking should be safe, file mode was "r" */
 
-       if (args == 0 || kill(pid, 0) == -1) {
-           fprintf(stderr,GT_("fetchmail: removing stale lockfile\n"));
+       if (args == EOF || args == 0 || kill(pid, 0) == -1) {
+           /* ^ could not read PID  || process does not exist */
+           /* => lockfile is stale, unlink it */
            pid = 0;
-           if (unlink(lockfile))
-               perror(lockfile);
+           fprintf(stderr,GT_("fetchmail: removing stale lockfile\n"));
+           if (unlink(lockfile)) {
+              if (errno != ENOENT) {
+                  perror(lockfile);
+                  /* we complain but we don't exit; it might be
+                   * writable for us, but in a directory we cannot
+                   * write to. This means we can write the new PID to
+                   * the file. Truncate to be safe in case the PID is
+                   * recycled by another process later.
+                   * \bug we should use fcntl() style locks or
+                   * something else instead in a future release. */
+                  if (truncate(lockfile, (off_t)0)) {
+                      /* but if we cannot truncate the file either,
+                       * assume that we cannot write to it later,
+                       * complain and quit. */
+                      perror(lockfile);
+                      exit(PS_EXCLUDE);
+                  }
+              }
+           }
        }
-       fclose(lockfp); /* not checking should be safe, file mode was "r" */
     } else {
        pid = 0;
-       if (errno != ENOENT)
+       if (errno != ENOENT) {
            fprintf(stderr, GT_("fetchmail: error opening lockfile \"%s\": %s\n"),
                    lockfile, strerror(errno));
+           exit(PS_EXCLUDE);
+       }
     }
 
     return(bkgd ? -pid : pid);
 }
 
-void lock_assert(void)
-/* assert that we already posess a lock */
+void fm_lock_assert(void)
+/* assert that we already possess a lock */
 {
     lock_acquired = TRUE;
 }
 
-void lock_or_die(void)
+void fm_lock_or_die(void)
 /* get a lock on a given host or exit */
 {
     int fd;
@@ -110,15 +136,23 @@ void lock_or_die(void)
        int e = 0;
 
        if ((fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0666)) != -1) {
+           ssize_t wr;
+
            snprintf(tmpbuf, sizeof(tmpbuf), "%ld\n", (long)getpid());
-           if (write(fd, tmpbuf, strlen(tmpbuf)) < strlen(tmpbuf)) e = 1;
+           wr = write(fd, tmpbuf, strlen(tmpbuf));
+           if (wr == -1 || (size_t)wr != strlen(tmpbuf))
+               e = 1;
            if (run.poll_interval)
            {
                snprintf(tmpbuf, sizeof(tmpbuf), "%d\n", run.poll_interval);
-               if (write(fd, tmpbuf, strlen(tmpbuf)) < strlen(tmpbuf)) e = 1;
+               wr = write(fd, tmpbuf, strlen(tmpbuf));
+               if (wr == -1 || (size_t)wr != strlen(tmpbuf))
+                   e = 1;
            }
            if (fsync(fd)) e = 1;
            if (close(fd)) e = 1;
+       } else {
+           e = 1;
        }
        if (e == 0) {
            lock_acquired = TRUE;