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