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