]> Pileus Git - ~andy/fetchmail/blob - lock.c
Remove some obsolete constructs...
[~andy/fetchmail] / lock.c
1 /**
2  * \file 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 #include <string.h> /* strcat() */
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <signal.h>
15
16 #include "fetchmail.h"
17 #include "i18n.h"
18 #include "lock.h"
19
20 static char *lockfile;          /** name of lockfile */
21 static int lock_acquired;       /** flag if have we acquired a lock */
22
23 void fm_lock_setup(struct runctl *ctl)
24 /* set up the global lockfile name */
25 {
26     /* set up to do lock protocol */
27     const char *const FETCHMAIL_PIDFILE="fetchmail.pid";
28
29     /* command-line option override */
30     if (ctl->pidfile) {
31         lockfile = xstrdup(ctl->pidfile);
32         return;
33     }
34
35     /* defaults */
36     if (getuid() == ROOT_UID) {
37         lockfile = (char *)xmalloc(strlen(PID_DIR)
38                 + strlen(FETCHMAIL_PIDFILE) + 2); /* 2: "/" and NUL */
39         strcpy(lockfile, PID_DIR);
40         strcat(lockfile, "/");
41         strcat(lockfile, FETCHMAIL_PIDFILE);
42     } else {
43         lockfile = (char *)xmalloc(strlen(fmhome)
44                 + strlen(FETCHMAIL_PIDFILE) + 3); /* 3: "/", "." and NUL */
45         strcpy(lockfile, fmhome);
46         strcat(lockfile, "/");
47         if (fmhome == home)
48            strcat(lockfile, ".");
49         strcat(lockfile, FETCHMAIL_PIDFILE);
50     }
51 }
52
53 static void unlockit(void)
54 /* must-do actions for exit (but we can't count on being able to do malloc) */
55 {
56     if (lockfile && lock_acquired)
57         unlink(lockfile);
58 }
59
60 void fm_lock_dispose(void)
61 /* arrange for a lock to be removed on process exit */
62 {
63 #ifdef HAVE_ATEXIT
64     atexit(unlockit);
65 #endif
66 }
67
68 int fm_lock_state(void)
69 {
70     long        pid;
71     int         st;
72     FILE        *lockfp;
73     int         bkgd = FALSE;
74
75     if ((lockfp = fopen(lockfile, "r")) != NULL)
76     {
77         int args = fscanf(lockfp, "%ld %d", &pid, &st);
78         bkgd = (args == 2);
79
80         if (ferror(lockfp)) {
81             fprintf(stderr, GT_("fetchmail: error reading lockfile \"%s\": %s\n"),
82                     lockfile, strerror(errno));
83             fclose(lockfp); /* not checking should be safe, file mode was "r" */
84             exit(PS_EXCLUDE);
85         }
86         fclose(lockfp); /* not checking should be safe, file mode was "r" */
87
88         if (args == EOF || args == 0 || kill(pid, 0) == -1) {
89             /* ^ could not read PID  || process does not exist */
90             /* => lockfile is stale, unlink it */
91             pid = 0;
92             fprintf(stderr,GT_("fetchmail: removing stale lockfile\n"));
93             if (unlink(lockfile)) {
94                if (errno != ENOENT) {
95                    perror(lockfile);
96                    /* we complain but we don't exit; it might be
97                     * writable for us, but in a directory we cannot
98                     * write to. This means we can write the new PID to
99                     * the file. Truncate to be safe in case the PID is
100                     * recycled by another process later.
101                     * \bug we should use fcntl() style locks or
102                     * something else instead in a future release. */
103                    if (truncate(lockfile, (off_t)0)) {
104                        /* but if we cannot truncate the file either,
105                         * assume that we cannot write to it later,
106                         * complain and quit. */
107                        perror(lockfile);
108                        exit(PS_EXCLUDE);
109                    }
110                }
111             }
112         }
113     } else {
114         pid = 0;
115         if (errno != ENOENT) {
116             fprintf(stderr, GT_("fetchmail: error opening lockfile \"%s\": %s\n"),
117                     lockfile, strerror(errno));
118             exit(PS_EXCLUDE);
119         }
120     }
121
122     return(bkgd ? -pid : pid);
123 }
124
125 void fm_lock_assert(void)
126 /* assert that we already possess a lock */
127 {
128     lock_acquired = TRUE;
129 }
130
131 void fm_lock_or_die(void)
132 /* get a lock on a given host or exit */
133 {
134     int fd;
135     char        tmpbuf[50];
136
137     if (!lock_acquired) {
138         int e = 0;
139
140         if ((fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0666)) != -1) {
141             ssize_t wr;
142
143             snprintf(tmpbuf, sizeof(tmpbuf), "%ld\n", (long)getpid());
144             wr = write(fd, tmpbuf, strlen(tmpbuf));
145             if (wr == -1 || (size_t)wr != strlen(tmpbuf))
146                 e = 1;
147             if (run.poll_interval)
148             {
149                 snprintf(tmpbuf, sizeof(tmpbuf), "%d\n", run.poll_interval);
150                 wr = write(fd, tmpbuf, strlen(tmpbuf));
151                 if (wr == -1 || (size_t)wr != strlen(tmpbuf))
152                     e = 1;
153             }
154             if (fsync(fd)) e = 1;
155             if (close(fd)) e = 1;
156         } else {
157             e = 1;
158         }
159         if (e == 0) {
160             lock_acquired = TRUE;
161         } else {
162             perror(lockfile);
163             fprintf(stderr, GT_("fetchmail: lock creation failed.\n"));
164             exit(PS_EXCLUDE);
165         }
166     }
167 }
168
169 void fm_lock_release(void)
170 /* release a lock on a given host */
171 {
172     unlink(lockfile);
173 }
174 /* lock.c ends here */