]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-daemon/sd-daemon.c
Merge pull request #918 from thomasmey/uml-fix
[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 assert_return(fd >= 0, -EBADF);
314
315 if (mq_getattr(fd, &attr) < 0)
316 return -errno;
317
318 if (path) {
319 char fpath[PATH_MAX];
320 struct stat a, b;
321
322 assert_return(path_is_absolute(path), -EINVAL);
323
324 if (fstat(fd, &a) < 0)
325 return -errno;
326
327 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
328 fpath[sizeof(fpath)-1] = 0;
329
330 if (stat(fpath, &b) < 0)
331 return -errno;
332
333 if (a.st_dev != b.st_dev ||
334 a.st_ino != b.st_ino)
335 return 0;
336 }
337
338 return 1;
339 }
340
341 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
342 union sockaddr_union sockaddr = {
343 .sa.sa_family = AF_UNIX,
344 };
345 struct iovec iovec = {
346 .iov_base = (char*) state,
347 };
348 struct msghdr msghdr = {
349 .msg_iov = &iovec,
350 .msg_iovlen = 1,
351 .msg_name = &sockaddr,
352 };
353 _cleanup_close_ int fd = -1;
354 struct cmsghdr *cmsg = NULL;
355 const char *e;
356 bool have_pid;
357 int r;
358
359 if (!state) {
360 r = -EINVAL;
361 goto finish;
362 }
363
364 if (n_fds > 0 && !fds) {
365 r = -EINVAL;
366 goto finish;
367 }
368
369 e = getenv("NOTIFY_SOCKET");
370 if (!e)
371 return 0;
372
373 /* Must be an abstract socket, or an absolute path */
374 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
375 r = -EINVAL;
376 goto finish;
377 }
378
379 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
380 if (fd < 0) {
381 r = -errno;
382 goto finish;
383 }
384
385 iovec.iov_len = strlen(state);
386
387 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
388 if (sockaddr.un.sun_path[0] == '@')
389 sockaddr.un.sun_path[0] = 0;
390
391 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
392 if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
393 msghdr.msg_namelen = sizeof(struct sockaddr_un);
394
395 have_pid = pid != 0 && pid != getpid();
396
397 if (n_fds > 0 || have_pid) {
398 msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds) +
399 CMSG_SPACE(sizeof(struct ucred) * have_pid);
400 msghdr.msg_control = alloca(msghdr.msg_controllen);
401
402 cmsg = CMSG_FIRSTHDR(&msghdr);
403 if (n_fds > 0) {
404 cmsg->cmsg_level = SOL_SOCKET;
405 cmsg->cmsg_type = SCM_RIGHTS;
406 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
407
408 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
409
410 if (have_pid)
411 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
412 }
413
414 if (have_pid) {
415 struct ucred *ucred;
416
417 cmsg->cmsg_level = SOL_SOCKET;
418 cmsg->cmsg_type = SCM_CREDENTIALS;
419 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
420
421 ucred = (struct ucred*) CMSG_DATA(cmsg);
422 ucred->pid = pid;
423 ucred->uid = getuid();
424 ucred->gid = getgid();
425 }
426 }
427
428 /* First try with fake ucred data, as requested */
429 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
430 r = 1;
431 goto finish;
432 }
433
434 /* If that failed, try with our own ucred instead */
435 if (have_pid) {
436 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
437 if (msghdr.msg_controllen == 0)
438 msghdr.msg_control = NULL;
439
440 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
441 r = 1;
442 goto finish;
443 }
444 }
445
446 r = -errno;
447
448 finish:
449 if (unset_environment)
450 unsetenv("NOTIFY_SOCKET");
451
452 return r;
453 }
454
455 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
456 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
457 }
458
459 _public_ int sd_notify(int unset_environment, const char *state) {
460 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
461 }
462
463 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
464 _cleanup_free_ char *p = NULL;
465 int r;
466
467 if (format) {
468 va_list ap;
469
470 va_start(ap, format);
471 r = vasprintf(&p, format, ap);
472 va_end(ap);
473
474 if (r < 0 || !p)
475 return -ENOMEM;
476 }
477
478 return sd_pid_notify(pid, unset_environment, p);
479 }
480
481 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
482 _cleanup_free_ char *p = NULL;
483 int r;
484
485 if (format) {
486 va_list ap;
487
488 va_start(ap, format);
489 r = vasprintf(&p, format, ap);
490 va_end(ap);
491
492 if (r < 0 || !p)
493 return -ENOMEM;
494 }
495
496 return sd_pid_notify(0, unset_environment, p);
497 }
498
499 _public_ int sd_booted(void) {
500 struct stat st;
501
502 /* We test whether the runtime unit file directory has been
503 * created. This takes place in mount-setup.c, so is
504 * guaranteed to happen very early during boot. */
505
506 if (lstat("/run/systemd/system/", &st) < 0)
507 return 0;
508
509 return !!S_ISDIR(st.st_mode);
510 }
511
512 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
513 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
514 uint64_t u;
515 int r = 0;
516
517 s = getenv("WATCHDOG_USEC");
518 if (!s)
519 goto finish;
520
521 r = safe_atou64(s, &u);
522 if (r < 0)
523 goto finish;
524 if (u <= 0) {
525 r = -EINVAL;
526 goto finish;
527 }
528
529 p = getenv("WATCHDOG_PID");
530 if (p) {
531 pid_t pid;
532
533 r = parse_pid(p, &pid);
534 if (r < 0)
535 goto finish;
536
537 /* Is this for us? */
538 if (getpid() != pid) {
539 r = 0;
540 goto finish;
541 }
542 }
543
544 if (usec)
545 *usec = u;
546
547 r = 1;
548
549 finish:
550 if (unset_environment && s)
551 unsetenv("WATCHDOG_USEC");
552 if (unset_environment && p)
553 unsetenv("WATCHDOG_PID");
554
555 return r;
556 }