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