Home | History | Annotate | Download | only in libdaemon
      1 /***
      2   This file is part of libdaemon.
      3 
      4   Copyright 2003-2008 Lennart Poettering
      5 
      6   Permission is hereby granted, free of charge, to any person obtaining a copy
      7   of this software and associated documentation files (the "Software"), to deal
      8   in the Software without restriction, including without limitation the rights
      9   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10   copies of the Software, and to permit persons to whom the Software is
     11   furnished to do so, subject to the following conditions:
     12 
     13   The above copyright notice and this permission notice shall be included in
     14   all copies or substantial portions of the Software.
     15 
     16   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     19   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22   SOFTWARE.
     23 
     24 ***/
     25 
     26 #ifdef HAVE_CONFIG_H
     27 #include <config.h>
     28 #endif
     29 
     30 #include <limits.h>
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <signal.h>
     34 #include <string.h>
     35 #include <unistd.h>
     36 #include <errno.h>
     37 #include <sys/types.h>
     38 #include <sys/stat.h>
     39 #include <time.h>
     40 #include <sys/select.h>
     41 #include <fcntl.h>
     42 #include <stddef.h>
     43 #include <sys/time.h>
     44 
     45 #include "dpid.h"
     46 #include "dlog.h"
     47 
     48 #ifndef ETIME
     49 #define ETIME ETIMEDOUT /* For FreeBSD */
     50 #endif
     51 
     52 #ifndef PATH_MAX
     53 #define PATH_MAX 512
     54 #endif
     55 
     56 #define VARRUN LOCALSTATEDIR "/run"
     57 
     58 const char *daemon_pid_file_ident = NULL;
     59 daemon_pid_file_proc_t daemon_pid_file_proc = daemon_pid_file_proc_default;
     60 
     61 const char *daemon_pid_file_proc_default(void) {
     62 #ifdef HAVE_ASPRINTF
     63     static char *fn = NULL;
     64     free(fn);
     65     asprintf(&fn,  "%s/%s.pid", VARRUN, daemon_pid_file_ident ? daemon_pid_file_ident : "unknown");
     66 #else
     67     static char fn[PATH_MAX];
     68     snprintf(fn, sizeof(fn), "%s/%s.pid", VARRUN, daemon_pid_file_ident ? daemon_pid_file_ident : "unknown");
     69 #endif
     70 
     71     return fn;
     72 }
     73 
     74 static int lock_file(int fd, int enable) {
     75     struct flock f;
     76 
     77     memset(&f, 0, sizeof(f));
     78     f.l_type = enable ? F_WRLCK : F_UNLCK;
     79     f.l_whence = SEEK_SET;
     80     f.l_start = 0;
     81     f.l_len = 0;
     82 
     83     if (fcntl(fd, F_SETLKW, &f) < 0) {
     84 
     85         if (enable && errno == EBADF) {
     86             f.l_type = F_RDLCK;
     87 
     88             if (fcntl(fd, F_SETLKW, &f) >= 0)
     89                 return 0;
     90         }
     91 
     92         daemon_log(LOG_WARNING, "fcntl(F_SETLKW) failed: %s", strerror(errno));
     93         return -1;
     94     }
     95 
     96     return 0;
     97 }
     98 
     99 pid_t daemon_pid_file_is_running(void) {
    100     const char *fn;
    101     static char txt[256];
    102     int fd = -1, locked = -1;
    103     pid_t ret = (pid_t) -1, pid;
    104     ssize_t l;
    105     long lpid;
    106     char *e = NULL;
    107 
    108     if (!(fn = daemon_pid_file_proc())) {
    109         errno = EINVAL;
    110         goto finish;
    111     }
    112 
    113     if ((fd = open(fn, O_RDWR, 0644)) < 0) {
    114         if ((fd = open(fn, O_RDONLY, 0644)) < 0) {
    115             if (errno != ENOENT)
    116                 daemon_log(LOG_WARNING, "Failed to open PID file: %s", strerror(errno));
    117 
    118             goto finish;
    119         }
    120     }
    121 
    122     if ((locked = lock_file(fd, 1)) < 0)
    123         goto finish;
    124 
    125     if ((l = read(fd, txt, sizeof(txt)-1)) < 0) {
    126         int saved_errno = errno;
    127         daemon_log(LOG_WARNING, "read(): %s", strerror(errno));
    128         unlink(fn);
    129         errno = saved_errno;
    130         goto finish;
    131     }
    132 
    133     txt[l] = 0;
    134     txt[strcspn(txt, "\r\n")] = 0;
    135 
    136     errno = 0;
    137     lpid = strtol(txt, &e, 10);
    138     pid = (pid_t) lpid;
    139 
    140     if (errno != 0 || !e || *e || (long) pid != lpid) {
    141         daemon_log(LOG_WARNING, "PID file corrupt, removing. (%s)", fn);
    142         unlink(fn);
    143         errno = EINVAL;
    144         goto finish;
    145     }
    146 
    147     if (kill(pid, 0) != 0 && errno != EPERM) {
    148         int saved_errno = errno;
    149         daemon_log(LOG_WARNING, "Process %lu died: %s; trying to remove PID file. (%s)", (unsigned long) pid, strerror(errno), fn);
    150         unlink(fn);
    151         errno = saved_errno;
    152         goto finish;
    153     }
    154 
    155     ret = pid;
    156 
    157 finish:
    158 
    159     if (fd >= 0) {
    160         int saved_errno = errno;
    161         if (locked >= 0)
    162             lock_file(fd, 0);
    163         close(fd);
    164         errno = saved_errno;
    165     }
    166 
    167     return ret;
    168 }
    169 
    170 int daemon_pid_file_kill(int s) {
    171     pid_t pid;
    172 
    173     if ((pid = daemon_pid_file_is_running()) == (pid_t) -1)
    174         return -1;
    175 
    176     if (kill(pid, s) < 0)
    177         return -1;
    178 
    179     return 0;
    180 }
    181 
    182 int daemon_pid_file_kill_wait(int s, int m) {
    183     pid_t pid;
    184     time_t t;
    185 
    186     if ((pid = daemon_pid_file_is_running()) < 0)
    187         return -1;
    188 
    189     if (kill(pid, s) < 0)
    190         return -1;
    191 
    192     t = time(NULL) + m;
    193 
    194     for (;;) {
    195         int r;
    196         struct timeval tv = { 0, 100000 };
    197 
    198         if (time(NULL) > t) {
    199             errno = ETIME;
    200             return -1;
    201         }
    202 
    203         if ((r = kill(pid, 0)) < 0 && errno != ESRCH)
    204             return -1;
    205 
    206         if (r)
    207             return 0;
    208 
    209         if (select(0, NULL, NULL, NULL, &tv) < 0)
    210             return -1;
    211     }
    212 }
    213 
    214 int daemon_pid_file_create(void) {
    215     const char *fn;
    216     int fd = -1;
    217     int ret = -1;
    218     int locked = -1;
    219     char t[64];
    220     ssize_t l;
    221     mode_t u;
    222 
    223     u = umask(022);
    224 
    225     if (!(fn = daemon_pid_file_proc())) {
    226         errno = EINVAL;
    227         goto finish;
    228     }
    229 
    230     if ((fd = open(fn, O_CREAT|O_RDWR|O_EXCL, 0644)) < 0) {
    231         daemon_log(LOG_ERR, "open(%s): %s", fn, strerror(errno));
    232         goto finish;
    233     }
    234 
    235     if ((locked = lock_file(fd, 1)) < 0) {
    236         int saved_errno = errno;
    237         unlink(fn);
    238         errno = saved_errno;
    239         goto finish;
    240     }
    241 
    242     snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid());
    243 
    244     l = strlen(t);
    245     if (write(fd, t, l) != l) {
    246         int saved_errno = errno;
    247         daemon_log(LOG_WARNING, "write(): %s", strerror(errno));
    248         unlink(fn);
    249         errno = saved_errno;
    250         goto finish;
    251     }
    252 
    253     ret = 0;
    254 
    255 finish:
    256 
    257     if (fd >= 0) {
    258         int saved_errno = errno;
    259 
    260         if (locked >= 0)
    261             lock_file(fd, 0);
    262 
    263         close(fd);
    264         errno = saved_errno;
    265     }
    266 
    267     umask(u);
    268 
    269     return ret;
    270 }
    271 
    272 int daemon_pid_file_remove(void) {
    273     const char *fn;
    274 
    275     if (!(fn = daemon_pid_file_proc())) {
    276         errno = EINVAL;
    277         return -1;
    278     }
    279 
    280     return unlink(fn);
    281 }
    282