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
daemon_pid_file_proc_default(void)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
lock_file(int fd,int enable)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
daemon_pid_file_is_running(void)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
daemon_pid_file_kill(int s)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
daemon_pid_file_kill_wait(int s,int m)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
daemon_pid_file_create(void)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
daemon_pid_file_remove(void)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 }
277