#include "config.h"
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#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 "lock.h"
static char *lockfile;
static int lock_acquired;
void fm_lock_setup(struct runctl *ctl)
{
const char *const FETCHMAIL_PIDFILE="fetchmail.pid";
if (ctl->pidfile) {
lockfile = xstrdup(ctl->pidfile);
return;
}
if (getuid() == ROOT_UID) {
lockfile = (char *)xmalloc(strlen(PID_DIR)
+ strlen(FETCHMAIL_PIDFILE) + 2);
strcpy(lockfile, PID_DIR);
strcat(lockfile, "/");
strcat(lockfile, FETCHMAIL_PIDFILE);
} else {
lockfile = (char *)xmalloc(strlen(fmhome)
+ strlen(FETCHMAIL_PIDFILE) + 3);
strcpy(lockfile, fmhome);
strcat(lockfile, "/");
if (fmhome == home)
strcat(lockfile, ".");
strcat(lockfile, FETCHMAIL_PIDFILE);
}
}
static void unlockit(void)
{
if (lockfile && lock_acquired)
unlink(lockfile);
}
void fm_lock_dispose(void)
{
#ifdef HAVE_ATEXIT
atexit(unlockit);
#endif
}
int fm_lock_state(void)
{
int pid, st;
FILE *lockfp;
int bkgd = FALSE;
if ((lockfp = fopen(lockfile, "r")) != NULL)
{
int args = fscanf(lockfp, "%d %d", &pid, &st);
bkgd = (args == 2);
if (ferror(lockfp)) {
fprintf(stderr, GT_("fetchmail: error reading lockfile \"%s\": %s\n"),
lockfile, strerror(errno));
fclose(lockfp);
exit(PS_EXCLUDE);
}
fclose(lockfp);
if (args == EOF || args == 0 || kill(pid, 0) == -1) {
pid = 0;
fprintf(stderr,GT_("fetchmail: removing stale lockfile\n"));
if (unlink(lockfile)) {
if (errno != ENOENT) {
perror(lockfile);
if (truncate(lockfile, (off_t)0)) {
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);
}
}
return(bkgd ? -pid : pid);
}
void fm_lock_assert(void)
{
lock_acquired = TRUE;
}
void fm_lock_or_die(void)
{
int fd;
char tmpbuf[50];
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 fm_lock_release(void)
{
unlink(lockfile);
}