]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libutil/pidfile.c
getaddrinfo: distinguish missing addrs from unresolvable names
[FreeBSD/FreeBSD.git] / lib / libutil / pidfile.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/capsicum.h>
35 #include <sys/file.h>
36 #include <sys/stat.h>
37
38 #include <err.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <libgen.h>
42 #include <libutil.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <time.h>
48 #include <unistd.h>
49
50 struct pidfh {
51         int     pf_dirfd;
52         int     pf_fd;
53         char    pf_dir[MAXPATHLEN + 1];
54         char    pf_filename[MAXPATHLEN + 1];
55         dev_t   pf_dev;
56         ino_t   pf_ino;
57 };
58
59 static int _pidfile_remove(struct pidfh *pfh, int freeit);
60
61 static int
62 pidfile_verify(const struct pidfh *pfh)
63 {
64         struct stat sb;
65
66         if (pfh == NULL || pfh->pf_fd == -1)
67                 return (EDOOFUS);
68         /*
69          * Check remembered descriptor.
70          */
71         if (fstat(pfh->pf_fd, &sb) == -1)
72                 return (errno);
73         if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino)
74                 return (EDOOFUS);
75         return (0);
76 }
77
78 static int
79 pidfile_read_impl(int dirfd, const char *filename, pid_t *pidptr)
80 {
81         char buf[16], *endptr;
82         int error, fd, i;
83
84         fd = openat(dirfd, filename, O_RDONLY | O_CLOEXEC);
85         if (fd == -1)
86                 return (errno);
87
88         i = read(fd, buf, sizeof(buf) - 1);
89         error = errno;  /* Remember errno in case close() wants to change it. */
90         close(fd);
91         if (i == -1)
92                 return (error);
93         else if (i == 0)
94                 return (EAGAIN);
95         buf[i] = '\0';
96
97         *pidptr = strtol(buf, &endptr, 10);
98         if (endptr != &buf[i])
99                 return (EINVAL);
100
101         return (0);
102 }
103
104 static int
105 pidfile_read(int dirfd, const char *filename, pid_t *pidptr)
106 {
107         struct timespec rqtp;
108         int count;
109
110         count = 20;
111         rqtp.tv_sec = 0;
112         rqtp.tv_nsec = 5000000;
113         for (;;) {
114                 errno = pidfile_read_impl(dirfd, filename, pidptr);
115                 if (errno != EAGAIN || --count == 0)
116                         break;
117                 nanosleep(&rqtp, 0);
118         }
119         if (errno == EAGAIN)
120                 *pidptr = -1;
121         return (errno);
122 }
123
124 struct pidfh *
125 pidfile_open(const char *pathp, mode_t mode, pid_t *pidptr)
126 {
127         char path[MAXPATHLEN];
128         struct pidfh *pfh;
129         struct stat sb;
130         int error, fd, dirfd, dirlen, filenamelen;
131         cap_rights_t caprights;
132
133         pfh = malloc(sizeof(*pfh));
134         if (pfh == NULL)
135                 return (NULL);
136
137         if (pathp == NULL) {
138                 dirlen = snprintf(pfh->pf_dir, sizeof(pfh->pf_dir),
139                     "/var/run/");
140                 filenamelen = snprintf(pfh->pf_filename,
141                     sizeof(pfh->pf_filename), "%s.pid", getprogname());
142         } else {
143                 if (strlcpy(path, pathp, sizeof(path)) >= sizeof(path)) {
144                         free(pfh);
145                         errno = ENAMETOOLONG;
146                         return (NULL);
147                 }
148                 dirlen = strlcpy(pfh->pf_dir, dirname(path),
149                     sizeof(pfh->pf_dir));
150                 (void)strlcpy(path, pathp, sizeof(path));
151                 filenamelen = strlcpy(pfh->pf_filename, basename(path),
152                     sizeof(pfh->pf_filename));
153         }
154
155         if (dirlen >= (int)sizeof(pfh->pf_dir) ||
156             filenamelen >= (int)sizeof(pfh->pf_filename)) {
157                 free(pfh);
158                 errno = ENAMETOOLONG;
159                 return (NULL);
160         }
161
162         dirfd = open(pfh->pf_dir, O_CLOEXEC | O_DIRECTORY | O_NONBLOCK);
163         if (dirfd == -1) {
164                 error = errno;
165                 free(pfh);
166                 errno = error;
167                 return (NULL);
168         }
169
170         /*
171          * Open the PID file and obtain exclusive lock.
172          * We truncate PID file here only to remove old PID immediately,
173          * PID file will be truncated again in pidfile_write(), so
174          * pidfile_write() can be called multiple times.
175          */
176         fd = flopenat(dirfd, pfh->pf_filename,
177             O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode);
178         if (fd == -1) {
179                 if (errno == EWOULDBLOCK) {
180                         if (pidptr == NULL) {
181                                 errno = EEXIST;
182                         } else {
183                                 errno = pidfile_read(dirfd,
184                                     pfh->pf_filename, pidptr);
185                                 if (errno == 0 || errno == EAGAIN)
186                                         errno = EEXIST;
187                         }
188                 }
189                 error = errno;
190                 close(dirfd);
191                 free(pfh);
192                 errno = error;
193                 return (NULL);
194         }
195
196         /*
197          * Remember file information, so in pidfile_write() we are sure we write
198          * to the proper descriptor.
199          */
200         if (fstat(fd, &sb) == -1) {
201                 goto failed;
202         }
203
204         if (cap_rights_limit(dirfd,
205             cap_rights_init(&caprights, CAP_UNLINKAT)) < 0 && errno != ENOSYS) {
206                 goto failed;
207         }
208
209         if (cap_rights_limit(fd, cap_rights_init(&caprights, CAP_PWRITE,
210             CAP_FSTAT, CAP_FTRUNCATE, CAP_EVENT)) < 0 &&
211             errno != ENOSYS) {
212                 goto failed;
213         }
214
215         pfh->pf_dirfd = dirfd;
216         pfh->pf_fd = fd;
217         pfh->pf_dev = sb.st_dev;
218         pfh->pf_ino = sb.st_ino;
219
220         return (pfh);
221
222 failed:
223         error = errno;
224         unlinkat(dirfd, pfh->pf_filename, 0);
225         close(dirfd);
226         close(fd);
227         free(pfh);
228         errno = error;
229         return (NULL);
230 }
231
232 int
233 pidfile_write(struct pidfh *pfh)
234 {
235         char pidstr[16];
236         int error, fd;
237
238         /*
239          * Check remembered descriptor, so we don't overwrite some other
240          * file if pidfile was closed and descriptor reused.
241          */
242         errno = pidfile_verify(pfh);
243         if (errno != 0) {
244                 /*
245                  * Don't close descriptor, because we are not sure if it's ours.
246                  */
247                 return (-1);
248         }
249         fd = pfh->pf_fd;
250
251         /*
252          * Truncate PID file, so multiple calls of pidfile_write() are allowed.
253          */
254         if (ftruncate(fd, 0) == -1) {
255                 error = errno;
256                 _pidfile_remove(pfh, 0);
257                 errno = error;
258                 return (-1);
259         }
260
261         snprintf(pidstr, sizeof(pidstr), "%u", getpid());
262         if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
263                 error = errno;
264                 _pidfile_remove(pfh, 0);
265                 errno = error;
266                 return (-1);
267         }
268
269         return (0);
270 }
271
272 int
273 pidfile_close(struct pidfh *pfh)
274 {
275         int error;
276
277         error = pidfile_verify(pfh);
278         if (error != 0) {
279                 errno = error;
280                 return (-1);
281         }
282
283         if (close(pfh->pf_fd) == -1)
284                 error = errno;
285         if (close(pfh->pf_dirfd) == -1 && error == 0)
286                 error = errno;
287
288         free(pfh);
289         if (error != 0) {
290                 errno = error;
291                 return (-1);
292         }
293         return (0);
294 }
295
296 static int
297 _pidfile_remove(struct pidfh *pfh, int freeit)
298 {
299         int error;
300
301         error = pidfile_verify(pfh);
302         if (error != 0) {
303                 errno = error;
304                 return (-1);
305         }
306
307         if (funlinkat(pfh->pf_dirfd, pfh->pf_filename, pfh->pf_fd, 0) == -1) {
308                 if (errno == EDEADLK)
309                         return (-1);
310                 error = errno;
311         }
312         if (close(pfh->pf_fd) == -1 && error == 0)
313                 error = errno;
314         if (close(pfh->pf_dirfd) == -1 && error == 0)
315                 error = errno;
316         if (freeit)
317                 free(pfh);
318         else
319                 pfh->pf_fd = -1;
320         if (error != 0) {
321                 errno = error;
322                 return (-1);
323         }
324         return (0);
325 }
326
327 int
328 pidfile_remove(struct pidfh *pfh)
329 {
330
331         return (_pidfile_remove(pfh, 1));
332 }
333
334 int
335 pidfile_fileno(const struct pidfh *pfh)
336 {
337
338         if (pfh == NULL || pfh->pf_fd == -1) {
339                 errno = EDOOFUS;
340                 return (-1);
341         }
342         return (pfh->pf_fd);
343 }
344
345 int
346 pidfile_signal(const char *pathp, int sig, pid_t *pidptr)
347 {
348         pid_t pid;
349         int fd;
350
351         fd = flopenat(AT_FDCWD, pathp,
352             O_RDONLY | O_CLOEXEC | O_NONBLOCK);
353         if (fd >= 0) {
354                 /*
355                  * The file exists but is not locked,
356                  * so the daemon is dead. Nothing to do.
357                  */
358                 close(fd);
359                 errno = ENOENT;
360                 return (errno);
361         }
362         if (errno != EWOULDBLOCK) {
363                 return (errno);
364         }
365         errno = pidfile_read(AT_FDCWD, pathp, &pid);
366         if (errno != 0)
367                 return (errno);
368         /*
369          * Refuse to send broadcast or group signals, this has
370          * happened due to the bugs in pidfile(3).
371          */
372         if (pid <= 0)
373                 return (EDOM);
374         kill(pid, sig);
375         if (pidptr != NULL)
376                 *pidptr = pid;
377         return (errno);
378 }