]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-daemon/sd-daemon.c
Merge pull request #1426 from poettering/log-syntax
[thirdparty/systemd.git] / src / libsystemd / sd-daemon / sd-daemon.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/stat.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <netinet/in.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stddef.h>
33 #include <limits.h>
34 #include <mqueue.h>
35
36 #include "util.h"
37 #include "path-util.h"
38 #include "socket-util.h"
39 #include "sd-daemon.h"
40
41 _public_ int sd_listen_fds(int unset_environment) {
42 const char *e;
43 unsigned n;
44 int r, fd;
45 pid_t pid;
46
47 e = getenv("LISTEN_PID");
48 if (!e) {
49 r = 0;
50 goto finish;
51 }
52
53 r = parse_pid(e, &pid);
54 if (r < 0)
55 goto finish;
56
57 /* Is this for us? */
58 if (getpid() != pid) {
59 r = 0;
60 goto finish;
61 }
62
63 e = getenv("LISTEN_FDS");
64 if (!e) {
65 r = 0;
66 goto finish;
67 }
68
69 r = safe_atou(e, &n);
70 if (r < 0)
71 goto finish;
72
73 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) n; fd ++) {
74 r = fd_cloexec(fd, true);
75 if (r < 0)
76 goto finish;
77 }
78
79 r = (int) n;
80
81 finish:
82 if (unset_environment) {
83 unsetenv("LISTEN_PID");
84 unsetenv("LISTEN_FDS");
85 }
86
87 return r;
88 }
89
90 _public_ int sd_is_fifo(int fd, const char *path) {
91 struct stat st_fd;
92
93 assert_return(fd >= 0, -EBADF);
94
95 if (fstat(fd, &st_fd) < 0)
96 return -errno;
97
98 if (!S_ISFIFO(st_fd.st_mode))
99 return 0;
100
101 if (path) {
102 struct stat st_path;
103
104 if (stat(path, &st_path) < 0) {
105
106 if (errno == ENOENT || errno == ENOTDIR)
107 return 0;
108
109 return -errno;
110 }
111
112 return
113 st_path.st_dev == st_fd.st_dev &&
114 st_path.st_ino == st_fd.st_ino;
115 }
116
117 return 1;
118 }
119
120 _public_ int sd_is_special(int fd, const char *path) {
121 struct stat st_fd;
122
123 assert_return(fd >= 0, -EBADF);
124
125 if (fstat(fd, &st_fd) < 0)
126 return -errno;
127
128 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
129 return 0;
130
131 if (path) {
132 struct stat st_path;
133
134 if (stat(path, &st_path) < 0) {
135
136 if (errno == ENOENT || errno == ENOTDIR)
137 return 0;
138
139 return -errno;
140 }
141
142 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
143 return
144 st_path.st_dev == st_fd.st_dev &&
145 st_path.st_ino == st_fd.st_ino;
146 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
147 return st_path.st_rdev == st_fd.st_rdev;
148 else
149 return 0;
150 }
151
152 return 1;
153 }
154
155 static int sd_is_socket_internal(int fd, int type, int listening) {
156 struct stat st_fd;
157
158 assert_return(fd >= 0, -EBADF);
159 assert_return(type >= 0, -EINVAL);
160
161 if (fstat(fd, &st_fd) < 0)
162 return -errno;
163
164 if (!S_ISSOCK(st_fd.st_mode))
165 return 0;
166
167 if (type != 0) {
168 int other_type = 0;
169 socklen_t l = sizeof(other_type);
170
171 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
172 return -errno;
173
174 if (l != sizeof(other_type))
175 return -EINVAL;
176
177 if (other_type != type)
178 return 0;
179 }
180
181 if (listening >= 0) {
182 int accepting = 0;
183 socklen_t l = sizeof(accepting);
184
185 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
186 return -errno;
187
188 if (l != sizeof(accepting))
189 return -EINVAL;
190
191 if (!accepting != !listening)
192 return 0;
193 }
194
195 return 1;
196 }
197
198 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
199 int r;
200
201 assert_return(fd >= 0, -EBADF);
202 assert_return(family >= 0, -EINVAL);
203
204 r = sd_is_socket_internal(fd, type, listening);
205 if (r <= 0)
206 return r;
207
208 if (family > 0) {
209 union sockaddr_union sockaddr = {};
210 socklen_t l = sizeof(sockaddr);
211
212 if (getsockname(fd, &sockaddr.sa, &l) < 0)
213 return -errno;
214
215 if (l < sizeof(sa_family_t))
216 return -EINVAL;
217
218 return sockaddr.sa.sa_family == family;
219 }
220
221 return 1;
222 }
223
224 _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
225 union sockaddr_union sockaddr = {};
226 socklen_t l = sizeof(sockaddr);
227 int r;
228
229 assert_return(fd >= 0, -EBADF);
230 assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
231
232 r = sd_is_socket_internal(fd, type, listening);
233 if (r <= 0)
234 return r;
235
236 if (getsockname(fd, &sockaddr.sa, &l) < 0)
237 return -errno;
238
239 if (l < sizeof(sa_family_t))
240 return -EINVAL;
241
242 if (sockaddr.sa.sa_family != AF_INET &&
243 sockaddr.sa.sa_family != AF_INET6)
244 return 0;
245
246 if (family != 0)
247 if (sockaddr.sa.sa_family != family)
248 return 0;
249
250 if (port > 0) {
251 if (sockaddr.sa.sa_family == AF_INET) {
252 if (l < sizeof(struct sockaddr_in))
253 return -EINVAL;
254
255 return htons(port) == sockaddr.in.sin_port;
256 } else {
257 if (l < sizeof(struct sockaddr_in6))
258 return -EINVAL;
259
260 return htons(port) == sockaddr.in6.sin6_port;
261 }
262 }
263
264 return 1;
265 }
266
267 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
268 union sockaddr_union sockaddr = {};
269 socklen_t l = sizeof(sockaddr);
270 int r;
271
272 assert_return(fd >= 0, -EBADF);
273
274 r = sd_is_socket_internal(fd, type, listening);
275 if (r <= 0)
276 return r;
277
278 if (getsockname(fd, &sockaddr.sa, &l) < 0)
279 return -errno;
280
281 if (l < sizeof(sa_family_t))
282 return -EINVAL;
283
284 if (sockaddr.sa.sa_family != AF_UNIX)
285 return 0;
286
287 if (path) {
288 if (length == 0)
289 length = strlen(path);
290
291 if (length == 0)
292 /* Unnamed socket */
293 return l == offsetof(struct sockaddr_un, sun_path);
294
295 if (path[0])
296 /* Normal path socket */
297 return
298 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
299 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
300 else
301 /* Abstract namespace socket */
302 return
303 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
304 memcmp(path, sockaddr.un.sun_path, length) == 0;
305 }
306
307 return 1;
308 }
309
310 _public_ int sd_is_mq(int fd, const char *path) {
311 struct mq_attr attr;
312
313 /* Check that the fd is valid */
314 assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
315
316 if (mq_getattr(fd, &attr) < 0) {
317 if (errno == EBADF)
318 /* A non-mq fd (or an invalid one, but we ruled that out above) */
319 return 0;
320 return -errno;
321 }
322
323 if (path) {
324 char fpath[PATH_MAX];
325 struct stat a, b;
326
327 assert_return(path_is_absolute(path), -EINVAL);
328
329 if (fstat(fd, &a) < 0)
330 return -errno;
331
332 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
333 fpath[sizeof(fpath)-1] = 0;
334
335 if (stat(fpath, &b) < 0)
336 return -errno;
337
338 if (a.st_dev != b.st_dev ||
339 a.st_ino != b.st_ino)
340 return 0;
341 }
342
343 return 1;
344 }
345
346 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
347 union sockaddr_union sockaddr = {
348 .sa.sa_family = AF_UNIX,
349 };
350 struct iovec iovec = {
351 .iov_base = (char*) state,
352 };
353 struct msghdr msghdr = {
354 .msg_iov = &iovec,
355 .msg_iovlen = 1,
356 .msg_name = &sockaddr,
357 };
358 _cleanup_close_ int fd = -1;
359 struct cmsghdr *cmsg = NULL;
360 const char *e;
361 bool have_pid;
362 int r;
363
364 if (!state) {
365 r = -EINVAL;
366 goto finish;
367 }
368
369 if (n_fds > 0 && !fds) {
370 r = -EINVAL;
371 goto finish;
372 }
373
374 e = getenv("NOTIFY_SOCKET");
375 if (!e)
376 return 0;
377
378 /* Must be an abstract socket, or an absolute path */
379 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
380 r = -EINVAL;
381 goto finish;
382 }
383
384 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
385 if (fd < 0) {
386 r = -errno;
387 goto finish;
388 }
389
390 iovec.iov_len = strlen(state);
391
392 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
393 if (sockaddr.un.sun_path[0] == '@')
394 sockaddr.un.sun_path[0] = 0;
395
396 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
397 if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
398 msghdr.msg_namelen = sizeof(struct sockaddr_un);
399
400 have_pid = pid != 0 && pid != getpid();
401
402 if (n_fds > 0 || have_pid) {
403 /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
404 msghdr.msg_controllen = (n_fds ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
405 CMSG_SPACE(sizeof(struct ucred)) * have_pid;
406 msghdr.msg_control = alloca(msghdr.msg_controllen);
407
408 cmsg = CMSG_FIRSTHDR(&msghdr);
409 if (n_fds > 0) {
410 cmsg->cmsg_level = SOL_SOCKET;
411 cmsg->cmsg_type = SCM_RIGHTS;
412 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
413
414 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
415
416 if (have_pid)
417 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
418 }
419
420 if (have_pid) {
421 struct ucred *ucred;
422
423 cmsg->cmsg_level = SOL_SOCKET;
424 cmsg->cmsg_type = SCM_CREDENTIALS;
425 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
426
427 ucred = (struct ucred*) CMSG_DATA(cmsg);
428 ucred->pid = pid;
429 ucred->uid = getuid();
430 ucred->gid = getgid();
431 }
432 }
433
434 /* First try with fake ucred data, as requested */
435 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
436 r = 1;
437 goto finish;
438 }
439
440 /* If that failed, try with our own ucred instead */
441 if (have_pid) {
442 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
443 if (msghdr.msg_controllen == 0)
444 msghdr.msg_control = NULL;
445
446 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
447 r = 1;
448 goto finish;
449 }
450 }
451
452 r = -errno;
453
454 finish:
455 if (unset_environment)
456 unsetenv("NOTIFY_SOCKET");
457
458 return r;
459 }
460
461 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
462 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
463 }
464
465 _public_ int sd_notify(int unset_environment, const char *state) {
466 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
467 }
468
469 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
470 _cleanup_free_ char *p = NULL;
471 int r;
472
473 if (format) {
474 va_list ap;
475
476 va_start(ap, format);
477 r = vasprintf(&p, format, ap);
478 va_end(ap);
479
480 if (r < 0 || !p)
481 return -ENOMEM;
482 }
483
484 return sd_pid_notify(pid, unset_environment, p);
485 }
486
487 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
488 _cleanup_free_ char *p = NULL;
489 int r;
490
491 if (format) {
492 va_list ap;
493
494 va_start(ap, format);
495 r = vasprintf(&p, format, ap);
496 va_end(ap);
497
498 if (r < 0 || !p)
499 return -ENOMEM;
500 }
501
502 return sd_pid_notify(0, unset_environment, p);
503 }
504
505 _public_ int sd_booted(void) {
506 /* We test whether the runtime unit file directory has been
507 * created. This takes place in mount-setup.c, so is
508 * guaranteed to happen very early during boot. */
509
510 return laccess("/run/systemd/system/", F_OK) >= 0;
511 }
512
513 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
514 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
515 uint64_t u;
516 int r = 0;
517
518 s = getenv("WATCHDOG_USEC");
519 if (!s)
520 goto finish;
521
522 r = safe_atou64(s, &u);
523 if (r < 0)
524 goto finish;
525 if (u <= 0) {
526 r = -EINVAL;
527 goto finish;
528 }
529
530 p = getenv("WATCHDOG_PID");
531 if (p) {
532 pid_t pid;
533
534 r = parse_pid(p, &pid);
535 if (r < 0)
536 goto finish;
537
538 /* Is this for us? */
539 if (getpid() != pid) {
540 r = 0;
541 goto finish;
542 }
543 }
544
545 if (usec)
546 *usec = u;
547
548 r = 1;
549
550 finish:
551 if (unset_environment && s)
552 unsetenv("WATCHDOG_USEC");
553 if (unset_environment && p)
554 unsetenv("WATCHDOG_PID");
555
556 return r;
557 }