]> Pileus Git - ~andy/fetchmail/blob - lock.c
Fix Debian bug #230615, making PID file format FHS 2.3 compliant.
[~andy/fetchmail] / lock.c
1 /*
2  * lock.c -- cross-platform concurrency locking for fetchmail
3  *
4  * For license terms, see the file COPYING in this directory.
5  */
6 #include "config.h"
7
8 #include <stdio.h>
9 #ifdef HAVE_STRING_H
10 #include <string.h> /* strcat() */
11 #endif
12 #if defined(STDC_HEADERS)
13 #include <stdlib.h>
14 #endif
15 #if defined(HAVE_UNISTD_H)
16 #include <unistd.h>
17 #endif
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <signal.h>
21
22 #include "fetchmail.h"
23 #include "i18n.h"
24
25 static char *lockfile;          /* name of lockfile */
26 static int lock_acquired;       /* have we acquired a lock */
27
28 void lock_setup(void)
29 /* set up the global lockfile name */
30 {
31     /* set up to do lock protocol */
32 #define FETCHMAIL_PIDFILE       "fetchmail.pid"
33     if (getuid() == ROOT_UID) {
34         lockfile = (char *)xmalloc(
35                 sizeof(PID_DIR) + sizeof(FETCHMAIL_PIDFILE) + 1);
36         strcpy(lockfile, PID_DIR);
37         strcat(lockfile, "/");
38         strcat(lockfile, FETCHMAIL_PIDFILE);
39     } else {
40         lockfile = (char *)xmalloc(strlen(fmhome)+sizeof(FETCHMAIL_PIDFILE)+2);
41         strcpy(lockfile, fmhome);
42         strcat(lockfile, "/");
43         if (fmhome == home)
44            strcat(lockfile, ".");
45         strcat(lockfile, FETCHMAIL_PIDFILE);
46     }
47 #undef FETCHMAIL_PIDFILE
48 }
49
50 #ifdef HAVE_ON_EXIT
51 static void unlockit(int n, void *p)
52 #else
53 static void unlockit(void)
54 #endif
55 /* must-do actions for exit (but we can't count on being able to do malloc) */
56 {
57     if (lockfile && lock_acquired)
58         unlink(lockfile);
59 }
60
61 void lock_dispose(void)
62 /* arrange for a lock to be removed on process exit */
63 {
64 #ifdef HAVE_ATEXIT
65     atexit(unlockit);
66 #endif
67 #ifdef HAVE_ON_EXIT
68     on_exit(unlockit, (char *)NULL);
69 #endif
70 }
71
72 int lock_state(void)
73 {
74     int         pid, st;
75     FILE        *lockfp;
76     int         bkgd = FALSE;
77
78     if ((lockfp = fopen(lockfile, "r")) != NULL)
79     {
80         int args = fscanf(lockfp, "%d %d", &pid, &st);
81         bkgd = (args == 2);
82
83         if (ferror(lockfp))
84             fprintf(stderr, GT_("fetchmail: error reading lockfile \"%s\": %s\n"),
85                     lockfile, strerror(errno));
86
87         if (args == 0 || kill(pid, 0) == -1) {
88             fprintf(stderr,GT_("fetchmail: removing stale lockfile\n"));
89             pid = 0;
90             if (unlink(lockfile))
91                 perror(lockfile);
92         }
93         fclose(lockfp); /* not checking should be safe, file mode was "r" */
94     } else {
95         pid = 0;
96         if (errno != ENOENT)
97             fprintf(stderr, GT_("fetchmail: error opening lockfile \"%s\": %s\n"),
98                     lockfile, strerror(errno));
99     }
100
101     return(bkgd ? -pid : pid);
102 }
103
104 void lock_assert(void)
105 /* assert that we already posess a lock */
106 {
107     lock_acquired = TRUE;
108 }
109
110 void lock_or_die(void)
111 /* get a lock on a given host or exit */
112 {
113     int fd;
114     char        tmpbuf[50];
115
116     if (!lock_acquired) {
117         int e = 0;
118
119         if ((fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0666)) != -1) {
120             snprintf(tmpbuf, sizeof(tmpbuf), "%ld\n", (long)getpid());
121             if (write(fd, tmpbuf, strlen(tmpbuf)) < strlen(tmpbuf)) e = 1;
122             if (run.poll_interval)
123             {
124                 snprintf(tmpbuf, sizeof(tmpbuf), "%d\n", run.poll_interval);
125                 if (write(fd, tmpbuf, strlen(tmpbuf)) < strlen(tmpbuf)) e = 1;
126             }
127             if (fsync(fd)) e = 1;
128             if (close(fd)) e = 1;
129         }
130         if (e == 0) {
131             lock_acquired = TRUE;
132         } else {
133             perror(lockfile);
134             fprintf(stderr, GT_("fetchmail: lock creation failed.\n"));
135             exit(PS_EXCLUDE);
136         }
137     }
138 }
139
140 void lock_release(void)
141 /* release a lock on a given host */
142 {
143     unlink(lockfile);
144 }
145 /* lock.c ends here */