Code sync
[external/libdaemon.git] / libdaemon / dpid.c
1 /***
2   This file is part of libdaemon.
3
4   Copyright 2003-2008 Lennart Poettering
5
6   libdaemon is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation, either version 2.1 of the
9   License, or (at your option) any later version.
10
11   libdaemon is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with libdaemon. If not, see
18   <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <signal.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <time.h>
35 #include <sys/select.h>
36 #include <fcntl.h>
37 #include <stddef.h>
38 #include <sys/time.h>
39
40 #include "dpid.h"
41 #include "dlog.h"
42
43 #ifndef ETIME
44 #define ETIME ETIMEDOUT /* For FreeBSD */
45 #endif
46
47 #ifndef PATH_MAX
48 #define PATH_MAX 512
49 #endif
50
51 #define VARRUN LOCALSTATEDIR "/run"
52
53 const char *daemon_pid_file_ident = NULL;
54 daemon_pid_file_proc_t daemon_pid_file_proc = daemon_pid_file_proc_default;
55
56 const char *daemon_pid_file_proc_default(void) {
57 #ifdef HAVE_ASPRINTF
58     static char *fn = NULL;
59     free(fn);
60     asprintf(&fn,  "%s/%s.pid", VARRUN, daemon_pid_file_ident ? daemon_pid_file_ident : "unknown");
61 #else
62     static char fn[PATH_MAX];
63     snprintf(fn, sizeof(fn), "%s/%s.pid", VARRUN, daemon_pid_file_ident ? daemon_pid_file_ident : "unknown");
64 #endif
65
66     return fn;
67 }
68
69 static int lock_file(int fd, int enable) {
70     struct flock f;
71
72     memset(&f, 0, sizeof(f));
73     f.l_type = enable ? F_WRLCK : F_UNLCK;
74     f.l_whence = SEEK_SET;
75     f.l_start = 0;
76     f.l_len = 0;
77
78     if (fcntl(fd, F_SETLKW, &f) < 0) {
79
80         if (enable && errno == EBADF) {
81             f.l_type = F_RDLCK;
82
83             if (fcntl(fd, F_SETLKW, &f) >= 0)
84                 return 0;
85         }
86
87         daemon_log(LOG_WARNING, "fcntl(F_SETLKW) failed: %s", strerror(errno));
88         return -1;
89     }
90
91     return 0;
92 }
93
94 pid_t daemon_pid_file_is_running(void) {
95     const char *fn;
96     static char txt[256];
97     int fd = -1, locked = -1;
98     pid_t ret = (pid_t) -1, pid;
99     ssize_t l;
100     long lpid;
101     char *e = NULL;
102
103     if (!(fn = daemon_pid_file_proc())) {
104         errno = EINVAL;
105         goto finish;
106     }
107
108     if ((fd = open(fn, O_RDWR, 0644)) < 0) {
109         if ((fd = open(fn, O_RDONLY, 0644)) < 0) {
110             if (errno != ENOENT)
111                 daemon_log(LOG_WARNING, "Failed to open PID file: %s", strerror(errno));
112
113             goto finish;
114         }
115     }
116
117     if ((locked = lock_file(fd, 1)) < 0)
118         goto finish;
119
120     if ((l = read(fd, txt, sizeof(txt)-1)) < 0) {
121         int saved_errno = errno;
122         daemon_log(LOG_WARNING, "read(): %s", strerror(errno));
123         unlink(fn);
124         errno = saved_errno;
125         goto finish;
126     }
127
128     txt[l] = 0;
129     txt[strcspn(txt, "\r\n")] = 0;
130
131     errno = 0;
132     lpid = strtol(txt, &e, 10);
133     pid = (pid_t) lpid;
134
135     if (errno != 0 || !e || *e || (long) pid != lpid) {
136         daemon_log(LOG_WARNING, "PID file corrupt, removing. (%s)", fn);
137         unlink(fn);
138         errno = EINVAL;
139         goto finish;
140     }
141
142     if (kill(pid, 0) != 0 && errno != EPERM) {
143         int saved_errno = errno;
144         daemon_log(LOG_WARNING, "Process %lu died: %s; trying to remove PID file. (%s)", (unsigned long) pid, strerror(errno), fn);
145         unlink(fn);
146         errno = saved_errno;
147         goto finish;
148     }
149
150     ret = pid;
151
152 finish:
153
154     if (fd >= 0) {
155         int saved_errno = errno;
156         if (locked >= 0)
157             lock_file(fd, 0);
158         close(fd);
159         errno = saved_errno;
160     }
161
162     return ret;
163 }
164
165 int daemon_pid_file_kill(int s) {
166     pid_t pid;
167
168     if ((pid = daemon_pid_file_is_running()) == (pid_t) -1)
169         return -1;
170
171     if (kill(pid, s) < 0)
172         return -1;
173
174     return 0;
175 }
176
177 int daemon_pid_file_kill_wait(int s, int m) {
178     pid_t pid;
179     time_t t;
180
181     if ((pid = daemon_pid_file_is_running()) < 0)
182         return -1;
183
184     if (kill(pid, s) < 0)
185         return -1;
186
187     t = time(NULL) + m;
188
189     for (;;) {
190         int r;
191         struct timeval tv = { 0, 100000 };
192
193         if (time(NULL) > t) {
194             errno = ETIME;
195             return -1;
196         }
197
198         if ((r = kill(pid, 0)) < 0 && errno != ESRCH)
199             return -1;
200
201         if (r)
202             return 0;
203
204         if (select(0, NULL, NULL, NULL, &tv) < 0)
205             return -1;
206     }
207 }
208
209 int daemon_pid_file_create(void) {
210     const char *fn;
211     int fd = -1;
212     int ret = -1;
213     int locked = -1;
214     char t[64];
215     ssize_t l;
216     mode_t u;
217
218     u = umask(022);
219
220     if (!(fn = daemon_pid_file_proc())) {
221         errno = EINVAL;
222         goto finish;
223     }
224
225     if ((fd = open(fn, O_CREAT|O_RDWR|O_EXCL, 0644)) < 0) {
226         daemon_log(LOG_ERR, "open(%s): %s", fn, strerror(errno));
227         goto finish;
228     }
229
230     if ((locked = lock_file(fd, 1)) < 0) {
231         int saved_errno = errno;
232         unlink(fn);
233         errno = saved_errno;
234         goto finish;
235     }
236
237     snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid());
238
239     l = strlen(t);
240     if (write(fd, t, l) != l) {
241         int saved_errno = errno;
242         daemon_log(LOG_WARNING, "write(): %s", strerror(errno));
243         unlink(fn);
244         errno = saved_errno;
245         goto finish;
246     }
247
248     ret = 0;
249
250 finish:
251
252     if (fd >= 0) {
253         int saved_errno = errno;
254
255         if (locked >= 0)
256             lock_file(fd, 0);
257
258         close(fd);
259         errno = saved_errno;
260     }
261
262     umask(u);
263
264     return ret;
265 }
266
267 int daemon_pid_file_remove(void) {
268     const char *fn;
269
270     if (!(fn = daemon_pid_file_proc())) {
271         errno = EINVAL;
272         return -1;
273     }
274
275     return unlink(fn);
276 }