]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-daemon/sd-daemon.c
udev: properly calculate size of remaining data
[thirdparty/systemd.git] / src / libsystemd / sd-daemon / sd-daemon.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
abbbea81
LP
2
3/***
0ebee881
KS
4 This file is part of systemd.
5
abbbea81
LP
6 Copyright 2010 Lennart Poettering
7
0ebee881
KS
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.
abbbea81 17
0ebee881
KS
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***/
8c47c732 21
7c394faa
LP
22#include <sys/stat.h>
23#include <sys/socket.h>
24#include <sys/un.h>
25#include <netinet/in.h>
abbbea81
LP
26#include <stdlib.h>
27#include <errno.h>
abbbea81 28#include <unistd.h>
7c394faa 29#include <string.h>
8c47c732
LP
30#include <stdarg.h>
31#include <stdio.h>
0e098b15 32#include <stddef.h>
916abb21 33#include <limits.h>
0ebee881 34#include <mqueue.h>
abbbea81 35
29804cc1 36#include "util.h"
be8f4e9e 37#include "path-util.h"
3cb46740 38#include "socket-util.h"
abbbea81
LP
39#include "sd-daemon.h"
40
0ebee881 41_public_ int sd_listen_fds(int unset_environment) {
abbbea81 42 const char *e;
be8f4e9e
LP
43 unsigned n;
44 int r, fd;
45 pid_t pid;
abbbea81 46
50425d16
MS
47 e = getenv("LISTEN_PID");
48 if (!e) {
abbbea81
LP
49 r = 0;
50 goto finish;
51 }
52
be8f4e9e
LP
53 r = parse_pid(e, &pid);
54 if (r < 0)
abbbea81 55 goto finish;
abbbea81
LP
56
57 /* Is this for us? */
be8f4e9e 58 if (getpid() != pid) {
abbbea81
LP
59 r = 0;
60 goto finish;
61 }
62
50425d16
MS
63 e = getenv("LISTEN_FDS");
64 if (!e) {
abbbea81
LP
65 r = 0;
66 goto finish;
67 }
68
be8f4e9e
LP
69 r = safe_atou(e, &n);
70 if (r < 0)
abbbea81 71 goto finish;
8640e111 72
be8f4e9e
LP
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)
8640e111 76 goto finish;
8640e111
LP
77 }
78
be8f4e9e 79 r = (int) n;
abbbea81
LP
80
81finish:
82 if (unset_environment) {
83 unsetenv("LISTEN_PID");
84 unsetenv("LISTEN_FDS");
85 }
86
87 return r;
abbbea81 88}
7c394faa 89
0ebee881 90_public_ int sd_is_fifo(int fd, const char *path) {
7c394faa
LP
91 struct stat st_fd;
92
be8f4e9e 93 assert_return(fd >= 0, -EINVAL);
7c394faa 94
7c394faa
LP
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
fd8bccfb 104 if (stat(path, &st_path) < 0) {
7c394faa
LP
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
0ebee881 120_public_ int sd_is_special(int fd, const char *path) {
4160ec67
WD
121 struct stat st_fd;
122
be8f4e9e 123 assert_return(fd >= 0, -EINVAL);
4160ec67
WD
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
e6a3081a 155static int sd_is_socket_internal(int fd, int type, int listening) {
7c394faa
LP
156 struct stat st_fd;
157
be8f4e9e
LP
158 assert_return(fd >= 0, -EINVAL);
159 assert_return(type >= 0, -EINVAL);
7c394faa
LP
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
dde770cf 191 if (!accepting != !listening)
7c394faa
LP
192 return 0;
193 }
194
195 return 1;
196}
197
0ebee881 198_public_ int sd_is_socket(int fd, int family, int type, int listening) {
88ce42f6
LP
199 int r;
200
be8f4e9e
LP
201 assert_return(fd >= 0, -EINVAL);
202 assert_return(family >= 0, -EINVAL);
88ce42f6 203
50425d16
MS
204 r = sd_is_socket_internal(fd, type, listening);
205 if (r <= 0)
88ce42f6
LP
206 return r;
207
208 if (family > 0) {
1c633045
ZJS
209 union sockaddr_union sockaddr = {};
210 socklen_t l = sizeof(sockaddr);
88ce42f6
LP
211
212 if (getsockname(fd, &sockaddr.sa, &l) < 0)
213 return -errno;
214
b7f42664 215 if (l < sizeof(sa_family_t))
88ce42f6
LP
216 return -EINVAL;
217
218 return sockaddr.sa.sa_family == family;
219 }
220
221 return 1;
222}
223
0ebee881 224_public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
1c633045
ZJS
225 union sockaddr_union sockaddr = {};
226 socklen_t l = sizeof(sockaddr);
7c394faa
LP
227 int r;
228
be8f4e9e
LP
229 assert_return(fd >= 0, -EINVAL);
230 assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
88ce42f6 231
50425d16
MS
232 r = sd_is_socket_internal(fd, type, listening);
233 if (r <= 0)
7c394faa
LP
234 return r;
235
7c394faa
LP
236 if (getsockname(fd, &sockaddr.sa, &l) < 0)
237 return -errno;
238
b7f42664 239 if (l < sizeof(sa_family_t))
7c394faa
LP
240 return -EINVAL;
241
242 if (sockaddr.sa.sa_family != AF_INET &&
243 sockaddr.sa.sa_family != AF_INET6)
244 return 0;
245
be8f4e9e 246 if (family != 0)
88ce42f6
LP
247 if (sockaddr.sa.sa_family != family)
248 return 0;
249
7c394faa
LP
250 if (port > 0) {
251 if (sockaddr.sa.sa_family == AF_INET) {
252 if (l < sizeof(struct sockaddr_in))
253 return -EINVAL;
254
3cb46740 255 return htons(port) == sockaddr.in.sin_port;
7c394faa
LP
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
0ebee881 267_public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
1c633045
ZJS
268 union sockaddr_union sockaddr = {};
269 socklen_t l = sizeof(sockaddr);
7c394faa
LP
270 int r;
271
be8f4e9e
LP
272 assert_return(fd >= 0, -EINVAL);
273
50425d16
MS
274 r = sd_is_socket_internal(fd, type, listening);
275 if (r <= 0)
7c394faa
LP
276 return r;
277
7c394faa
LP
278 if (getsockname(fd, &sockaddr.sa, &l) < 0)
279 return -errno;
280
b7f42664 281 if (l < sizeof(sa_family_t))
7c394faa
LP
282 return -EINVAL;
283
284 if (sockaddr.sa.sa_family != AF_UNIX)
285 return 0;
286
287 if (path) {
d1d7caee 288 if (length == 0)
7c394faa
LP
289 length = strlen(path);
290
d1d7caee 291 if (length == 0)
7c394faa 292 /* Unnamed socket */
0e098b15 293 return l == offsetof(struct sockaddr_un, sun_path);
7c394faa 294
7c394faa
LP
295 if (path[0])
296 /* Normal path socket */
cd250a39 297 return
0e098b15 298 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
cd250a39 299 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
7c394faa
LP
300 else
301 /* Abstract namespace socket */
cd250a39 302 return
0e098b15 303 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
cd250a39 304 memcmp(path, sockaddr.un.sun_path, length) == 0;
7c394faa
LP
305 }
306
307 return 1;
308}
8c47c732 309
0ebee881 310_public_ int sd_is_mq(int fd, const char *path) {
916abb21
LP
311 struct mq_attr attr;
312
be8f4e9e 313 assert_return(fd >= 0, -EINVAL);
916abb21
LP
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
be8f4e9e 322 assert_return(path_is_absolute(path), -EINVAL);
916abb21
LP
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;
916abb21
LP
339}
340
a354329f
LP
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 };
d4a144fa 353 struct cmsghdr *control;
a354329f
LP
354 _cleanup_close_ int fd = -1;
355 struct cmsghdr *cmsg = NULL;
356 const char *e;
357 size_t controllen_without_ucred = 0;
358 bool try_without_ucred = false;
be8f4e9e 359 int r;
8c47c732
LP
360
361 if (!state) {
362 r = -EINVAL;
363 goto finish;
364 }
365
a354329f
LP
366 if (n_fds > 0 && !fds) {
367 r = -EINVAL;
368 goto finish;
369 }
370
50425d16
MS
371 e = getenv("NOTIFY_SOCKET");
372 if (!e)
08bfb810 373 return 0;
8c47c732
LP
374
375 /* Must be an abstract socket, or an absolute path */
376 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
377 r = -EINVAL;
378 goto finish;
379 }
380
50425d16
MS
381 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
382 if (fd < 0) {
8c47c732
LP
383 r = -errno;
384 goto finish;
385 }
386
a354329f 387 iovec.iov_len = strlen(state);
8c47c732 388
a354329f 389 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
8c47c732
LP
390 if (sockaddr.un.sun_path[0] == '@')
391 sockaddr.un.sun_path[0] = 0;
392
0e098b15 393 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
a013bd94
LP
394 if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
395 msghdr.msg_namelen = sizeof(struct sockaddr_un);
396
d4a144fa
LP
397 control = alloca(CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int) * n_fds));
398
a354329f 399 if (n_fds > 0) {
d4a144fa 400 msghdr.msg_control = control;
a354329f
LP
401 msghdr.msg_controllen = CMSG_LEN(sizeof(int) * n_fds);
402
403 cmsg = CMSG_FIRSTHDR(&msghdr);
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 }
8c47c732 410
be8f4e9e 411 if (pid != 0 && pid != getpid()) {
a354329f
LP
412 struct ucred *ucred;
413
414 try_without_ucred = true;
415 controllen_without_ucred = msghdr.msg_controllen;
be8f4e9e 416
d4a144fa 417 msghdr.msg_control = control;
a354329f
LP
418 msghdr.msg_controllen += CMSG_LEN(sizeof(struct ucred));
419
420 if (cmsg)
421 cmsg = CMSG_NXTHDR(&msghdr, cmsg);
422 else
423 cmsg = CMSG_FIRSTHDR(&msghdr);
be8f4e9e 424
be8f4e9e
LP
425 cmsg->cmsg_level = SOL_SOCKET;
426 cmsg->cmsg_type = SCM_CREDENTIALS;
427 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
428
a354329f
LP
429 ucred = (struct ucred*) CMSG_DATA(cmsg);
430 ucred->pid = pid;
431 ucred->uid = getuid();
432 ucred->gid = getgid();
be8f4e9e
LP
433 }
434
435 /* First try with fake ucred data, as requested */
436 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
437 r = 1;
8c47c732
LP
438 goto finish;
439 }
440
a354329f
LP
441 /* If that failed, try with our own ucred instead */
442 if (try_without_ucred) {
443 if (controllen_without_ucred <= 0)
444 msghdr.msg_control = NULL;
445 msghdr.msg_controllen = controllen_without_ucred;
be8f4e9e
LP
446
447 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
448 r = 1;
449 goto finish;
450 }
451 }
452
453 r = -errno;
8c47c732
LP
454
455finish:
456 if (unset_environment)
457 unsetenv("NOTIFY_SOCKET");
458
8c47c732 459 return r;
8c47c732
LP
460}
461
a354329f
LP
462_public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
463 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
464}
465
be8f4e9e 466_public_ int sd_notify(int unset_environment, const char *state) {
a354329f 467 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
be8f4e9e
LP
468}
469
470_public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
471 _cleanup_free_ char *p = NULL;
472 int r;
473
474 if (format) {
475 va_list ap;
476
477 va_start(ap, format);
478 r = vasprintf(&p, format, ap);
479 va_end(ap);
480
481 if (r < 0 || !p)
482 return -ENOMEM;
483 }
484
485 return sd_pid_notify(pid, unset_environment, p);
486}
487
0ebee881 488_public_ int sd_notifyf(int unset_environment, const char *format, ...) {
be8f4e9e 489 _cleanup_free_ char *p = NULL;
8c47c732
LP
490 int r;
491
be8f4e9e
LP
492 if (format) {
493 va_list ap;
8c47c732 494
be8f4e9e
LP
495 va_start(ap, format);
496 r = vasprintf(&p, format, ap);
497 va_end(ap);
8c47c732 498
be8f4e9e
LP
499 if (r < 0 || !p)
500 return -ENOMEM;
501 }
8c47c732 502
be8f4e9e 503 return sd_pid_notify(0, unset_environment, p);
8c47c732 504}
40473a70 505
0ebee881 506_public_ int sd_booted(void) {
66e41181 507 struct stat st;
40473a70 508
66e41181
LP
509 /* We test whether the runtime unit file directory has been
510 * created. This takes place in mount-setup.c, so is
511 * guaranteed to happen very early during boot. */
40473a70 512
66e41181 513 if (lstat("/run/systemd/system/", &st) < 0)
40473a70
LP
514 return 0;
515
66e41181 516 return !!S_ISDIR(st.st_mode);
40473a70 517}
09812eb7 518
0ebee881 519_public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
a9becdd6 520 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
be8f4e9e 521 uint64_t u;
a9becdd6 522 int r = 0;
09812eb7 523
a9becdd6
ZJS
524 s = getenv("WATCHDOG_USEC");
525 if (!s)
09812eb7 526 goto finish;
09812eb7 527
a9becdd6 528 r = safe_atou64(s, &u);
be8f4e9e 529 if (r < 0)
09812eb7 530 goto finish;
a9becdd6 531 if (u <= 0) {
09812eb7
LP
532 r = -EINVAL;
533 goto finish;
534 }
535
a9becdd6
ZJS
536 p = getenv("WATCHDOG_PID");
537 if (p) {
538 pid_t pid;
539
540 r = parse_pid(p, &pid);
541 if (r < 0)
542 goto finish;
543
544 /* Is this for us? */
545 if (getpid() != pid) {
546 r = 0;
547 goto finish;
548 }
09812eb7
LP
549 }
550
551 if (usec)
be8f4e9e 552 *usec = u;
09812eb7
LP
553
554 r = 1;
555
556finish:
a9becdd6 557 if (unset_environment && s)
09812eb7 558 unsetenv("WATCHDOG_USEC");
a9becdd6
ZJS
559 if (unset_environment && p)
560 unsetenv("WATCHDOG_PID");
09812eb7
LP
561
562 return r;
09812eb7 563}