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