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