• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/libdaemon/libdaemon/
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
53const char *daemon_pid_file_ident = NULL;
54daemon_pid_file_proc_t daemon_pid_file_proc = daemon_pid_file_proc_default;
55
56const 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
69static 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
94pid_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
152finish:
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
165int 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
177int 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
209int 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
250finish:
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
267int 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