diff options
Diffstat (limited to 'lock.c')
-rw-r--r-- | lock.c | 130 |
1 files changed, 130 insertions, 0 deletions
@@ -0,0 +1,130 @@ +/* + * lock.c -- cross-platform concurrency locking for fetchmail + * + * For license terms, see the file COPYING in this directory. + */ +#include "config.h" + +#include <stdio.h> +#if defined(STDC_HEADERS) +#include <stdlib.h> +#endif +#if defined(HAVE_UNISTD_H) +#include <unistd.h> +#endif +#include <fcntl.h> + +#include "fetchmail.h" +#include "i18n.h" + +static char *lockfile; /* name of lockfile */ +static int lock_acquired; /* have we acquired a lock */ + +void lock_setup(void) +/* set up the global lockfile name */ +{ + /* set up to do lock protocol */ +#define FETCHMAIL_PIDFILE "fetchmail.pid" + if (!getuid()) { + xalloca(lockfile, char *, + sizeof(PID_DIR) + sizeof(FETCHMAIL_PIDFILE)); + sprintf(lockfile, "%s/%s", PID_DIR, FETCHMAIL_PIDFILE); + } else { + xalloca(lockfile, char *, strlen(fmhome) + sizeof(FETCHMAIL_PIDFILE) + 2); + strcpy(lockfile, fmhome); + 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) +/* 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 pid, st; + FILE *lockfp; + int bkgd = FALSE; + + pid = 0; + if ((lockfp = fopen(lockfile, "r")) != NULL ) + { + bkgd = (fscanf(lockfp, "%d %d", &pid, &st) == 2); + + if (kill(pid, 0) == -1) { + fprintf(stderr,_("fetchmail: removing stale lockfile\n")); + pid = 0; + unlink(lockfile); + } + 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 */ +{ + lock_acquired = TRUE; +} + +void lock_or_die(void) +/* get a lock on a given host or exit */ +{ + int fd; + char tmpbuf[20]; + +#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, _("fetchmail: lock creation failed.\n")); + exit(PS_EXCLUDE); + } + } +} + +void lock_release(void) +/* release a lock on a given host */ +{ + unlink(lockfile); +} + +/* lock.c ends here */ |