X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=lock.c;h=2d656df65289fcf3ae829ac3d5306cb192fd3d03;hb=87bcf29364c4640edb87cc2186b965d1a564d70c;hp=8b3f03f318a6846613dfdde3243b46fd25769fcf;hpb=c8928081a5a9cbfaf16b14d4db57476bda8e1189;p=~andy%2Ffetchmail diff --git a/lock.c b/lock.c index 8b3f03f3..2d656df6 100644 --- a/lock.c +++ b/lock.c @@ -1,134 +1,172 @@ -/* - * 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 -#ifdef HAVE_STRING_H #include /* strcat() */ -#endif -#if defined(STDC_HEADERS) #include -#endif -#if defined(HAVE_UNISTD_H) #include -#endif +#include #include #include #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); - sprintf(lockfile, "%s/%s", PID_DIR, FETCHMAIL_PIDFILE); + 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 } -#ifdef HAVE_ON_EXIT -static void unlockit(int n, void *p) -#else static void unlockit(void) -#endif /* must-do actions for exit (but we can't count on being able to do malloc) */ { if (lockfile && lock_acquired) 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 -#ifdef HAVE_ON_EXIT - on_exit(unlockit, (char *)NULL); -#endif } -int lock_state(void) +int fm_lock_state(void) { - int pid, st; + long pid; + int st; FILE *lockfp; int bkgd = FALSE; - pid = 0; - if ((lockfp = fopen(lockfile, "r")) != NULL ) + if ((lockfp = fopen(lockfile, "r")) != NULL) { - bkgd = (fscanf(lockfp, "%d %d", &pid, &st) == 2); + int args = fscanf(lockfp, "%ld %d", &pid, &st); + bkgd = (args == 2); - if (kill(pid, 0) == -1) { - fprintf(stderr,GT_("fetchmail: removing stale lockfile\n")); + 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 == EOF || args == 0 || kill(pid, 0) == -1) { + /* ^ could not read PID || process does not exist */ + /* => lockfile is stale, unlink it */ pid = 0; - unlink(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); + } + } + } + } + } else { + pid = 0; + if (errno != ENOENT) { + fprintf(stderr, GT_("fetchmail: error opening lockfile \"%s\": %s\n"), + lockfile, strerror(errno)); + exit(PS_EXCLUDE); } - fclose(lockfp); /* not checking should be safe, file mode was "r" */ } 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; - char tmpbuf[20]; + char tmpbuf[50]; -#ifndef O_SYNC -#define O_SYNC 0 /* use it if we have it */ -#endif - if (!lock_acquired) - { - if ((fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_SYNC, 0666)) != -1) - { - sprintf(tmpbuf,"%d", getpid()); - write(fd, tmpbuf, strlen(tmpbuf)); - if (run.poll_interval) - { - sprintf(tmpbuf," %d", run.poll_interval); - write(fd, tmpbuf, strlen(tmpbuf)); - } - close(fd); /* should be safe, fd was opened with O_SYNC */ - lock_acquired = TRUE; - } - else - { - fprintf(stderr, GT_("fetchmail: lock creation failed.\n")); - exit(PS_EXCLUDE); - } + if (!lock_acquired) { + 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()); + 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); + 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; + } else { + perror(lockfile); + fprintf(stderr, GT_("fetchmail: lock creation failed.\n")); + exit(PS_EXCLUDE); + } } } -void lock_release(void) +void fm_lock_release(void) /* release a lock on a given host */ { unlink(lockfile); } - /* lock.c ends here */