]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-daemon/sd-daemon.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / libsystemd / sd-daemon / sd-daemon.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
8c47c732 2
0ebee881 3#include <mqueue.h>
8dd4c05b 4#include <netinet/in.h>
4f07ddfa 5#include <poll.h>
8dd4c05b 6#include <stdio.h>
8dd4c05b
LP
7#include <sys/stat.h>
8#include <sys/un.h>
9#include <unistd.h>
abbbea81 10
07630cea
LP
11#include "sd-daemon.h"
12
b5efdb8a 13#include "alloc-util.h"
5cdf13c7 14#include "errno-util.h"
6553db60 15#include "extract-word.h"
3ffd4af2 16#include "fd-util.h"
f4f15635 17#include "fs-util.h"
cb310866 18#include "io-util.h"
bd1ae178 19#include "iovec-util.h"
93a1f792 20#include "log.h"
46b08447 21#include "missing_magic.h"
6bedfcbb 22#include "parse-util.h"
be8f4e9e 23#include "path-util.h"
46b08447 24#include "pidfd-util.h"
dccca82b 25#include "process-util.h"
3cb46740 26#include "socket-util.h"
a9dac7a6 27#include "stat-util.h"
8dd4c05b 28#include "strv.h"
4f07ddfa 29#include "time-util.h"
8dd4c05b 30
a47806fa
LP
31#define SNDBUF_SIZE (8*1024*1024)
32
66063489 33static void unsetenv_listen(bool unset_environment) {
8dd4c05b
LP
34 if (!unset_environment)
35 return;
36
44ee03d1
ZJS
37 assert_se(unsetenv("LISTEN_PID") == 0);
38 assert_se(unsetenv("LISTEN_FDS") == 0);
39 assert_se(unsetenv("LISTEN_FDNAMES") == 0);
8dd4c05b
LP
40}
41
0ebee881 42_public_ int sd_listen_fds(int unset_environment) {
abbbea81 43 const char *e;
fe96c0f8 44 int n, r;
be8f4e9e 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? */
df0ff127 58 if (getpid_cached() != 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
046c93f8 69 r = safe_atoi(e, &n);
be8f4e9e 70 if (r < 0)
abbbea81 71 goto finish;
8640e111 72
046c93f8
VC
73 assert_cc(SD_LISTEN_FDS_START < INT_MAX);
74 if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
75 r = -EINVAL;
76 goto finish;
77 }
78
b3a9d980 79 for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
be8f4e9e
LP
80 r = fd_cloexec(fd, true);
81 if (r < 0)
8640e111 82 goto finish;
8640e111
LP
83 }
84
046c93f8 85 r = n;
abbbea81
LP
86
87finish:
66063489 88 unsetenv_listen(unset_environment);
8dd4c05b
LP
89 return r;
90}
91
66063489 92_public_ int sd_listen_fds_with_names(int unset_environment, char ***ret_names) {
8dd4c05b
LP
93 _cleanup_strv_free_ char **l = NULL;
94 bool have_names;
95 int n_names = 0, n_fds;
96 const char *e;
97 int r;
98
66063489 99 if (!ret_names)
8dd4c05b
LP
100 return sd_listen_fds(unset_environment);
101
102 e = getenv("LISTEN_FDNAMES");
103 if (e) {
90e30d76 104 n_names = strv_split_full(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
8dd4c05b 105 if (n_names < 0) {
66063489 106 unsetenv_listen(unset_environment);
8dd4c05b
LP
107 return n_names;
108 }
109
110 have_names = true;
111 } else
112 have_names = false;
113
114 n_fds = sd_listen_fds(unset_environment);
115 if (n_fds <= 0)
116 return n_fds;
117
118 if (have_names) {
119 if (n_names != n_fds)
120 return -EINVAL;
121 } else {
122 r = strv_extend_n(&l, "unknown", n_fds);
123 if (r < 0)
124 return r;
abbbea81
LP
125 }
126
66063489 127 *ret_names = TAKE_PTR(l);
8dd4c05b 128 return n_fds;
abbbea81 129}
7c394faa 130
0ebee881 131_public_ int sd_is_fifo(int fd, const char *path) {
7c394faa
LP
132 struct stat st_fd;
133
e6803801 134 assert_return(fd >= 0, -EBADF);
7c394faa 135
7c394faa
LP
136 if (fstat(fd, &st_fd) < 0)
137 return -errno;
138
139 if (!S_ISFIFO(st_fd.st_mode))
140 return 0;
141
142 if (path) {
143 struct stat st_path;
144
fd8bccfb 145 if (stat(path, &st_path) < 0) {
7c394faa 146
945c2931 147 if (IN_SET(errno, ENOENT, ENOTDIR))
7c394faa
LP
148 return 0;
149
150 return -errno;
151 }
152
a9dac7a6 153 return stat_inode_same(&st_path, &st_fd);
7c394faa
LP
154 }
155
156 return 1;
157}
158
0ebee881 159_public_ int sd_is_special(int fd, const char *path) {
4160ec67
WD
160 struct stat st_fd;
161
e6803801 162 assert_return(fd >= 0, -EBADF);
4160ec67
WD
163
164 if (fstat(fd, &st_fd) < 0)
165 return -errno;
166
167 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
168 return 0;
169
170 if (path) {
171 struct stat st_path;
172
173 if (stat(path, &st_path) < 0) {
174
945c2931 175 if (IN_SET(errno, ENOENT, ENOTDIR))
4160ec67
WD
176 return 0;
177
178 return -errno;
179 }
180
181 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
a9dac7a6 182 return stat_inode_same(&st_path, &st_fd);
bea2237f 183 if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
4160ec67 184 return st_path.st_rdev == st_fd.st_rdev;
bea2237f
LP
185
186 return 0;
4160ec67
WD
187 }
188
189 return 1;
190}
191
3e4f1dc9 192static int is_socket_internal(int fd, int type, int listening) {
7c394faa
LP
193 struct stat st_fd;
194
e6803801 195 assert_return(fd >= 0, -EBADF);
be8f4e9e 196 assert_return(type >= 0, -EINVAL);
7c394faa
LP
197
198 if (fstat(fd, &st_fd) < 0)
199 return -errno;
200
201 if (!S_ISSOCK(st_fd.st_mode))
202 return 0;
203
204 if (type != 0) {
205 int other_type = 0;
206 socklen_t l = sizeof(other_type);
207
208 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
209 return -errno;
210
211 if (l != sizeof(other_type))
212 return -EINVAL;
213
214 if (other_type != type)
215 return 0;
216 }
217
218 if (listening >= 0) {
219 int accepting = 0;
220 socklen_t l = sizeof(accepting);
221
222 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
223 return -errno;
224
225 if (l != sizeof(accepting))
226 return -EINVAL;
227
dde770cf 228 if (!accepting != !listening)
7c394faa
LP
229 return 0;
230 }
231
232 return 1;
233}
234
0ebee881 235_public_ int sd_is_socket(int fd, int family, int type, int listening) {
88ce42f6
LP
236 int r;
237
e6803801 238 assert_return(fd >= 0, -EBADF);
be8f4e9e 239 assert_return(family >= 0, -EINVAL);
88ce42f6 240
3e4f1dc9 241 r = is_socket_internal(fd, type, listening);
50425d16 242 if (r <= 0)
88ce42f6
LP
243 return r;
244
245 if (family > 0) {
1c633045
ZJS
246 union sockaddr_union sockaddr = {};
247 socklen_t l = sizeof(sockaddr);
88ce42f6
LP
248
249 if (getsockname(fd, &sockaddr.sa, &l) < 0)
250 return -errno;
251
b7f42664 252 if (l < sizeof(sa_family_t))
88ce42f6
LP
253 return -EINVAL;
254
255 return sockaddr.sa.sa_family == family;
256 }
257
258 return 1;
259}
260
0ebee881 261_public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
1c633045
ZJS
262 union sockaddr_union sockaddr = {};
263 socklen_t l = sizeof(sockaddr);
7c394faa
LP
264 int r;
265
e6803801 266 assert_return(fd >= 0, -EBADF);
be8f4e9e 267 assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
88ce42f6 268
3e4f1dc9 269 r = is_socket_internal(fd, type, listening);
50425d16 270 if (r <= 0)
7c394faa
LP
271 return r;
272
7c394faa
LP
273 if (getsockname(fd, &sockaddr.sa, &l) < 0)
274 return -errno;
275
b7f42664 276 if (l < sizeof(sa_family_t))
7c394faa
LP
277 return -EINVAL;
278
945c2931 279 if (!IN_SET(sockaddr.sa.sa_family, AF_INET, AF_INET6))
7c394faa
LP
280 return 0;
281
be8f4e9e 282 if (family != 0)
88ce42f6
LP
283 if (sockaddr.sa.sa_family != family)
284 return 0;
285
7c394faa 286 if (port > 0) {
dfde7e8c 287 unsigned sa_port;
7c394faa 288
dfde7e8c
LP
289 r = sockaddr_port(&sockaddr.sa, &sa_port);
290 if (r < 0)
291 return r;
7c394faa 292
dfde7e8c 293 return port == sa_port;
7c394faa
LP
294 }
295
296 return 1;
297}
298
f6f372d2
ZJS
299_public_ int sd_is_socket_sockaddr(int fd, int type, const struct sockaddr* addr, unsigned addr_len, int listening) {
300 union sockaddr_union sockaddr = {};
301 socklen_t l = sizeof(sockaddr);
302 int r;
303
304 assert_return(fd >= 0, -EBADF);
305 assert_return(addr, -EINVAL);
306 assert_return(addr_len >= sizeof(sa_family_t), -ENOBUFS);
307 assert_return(IN_SET(addr->sa_family, AF_INET, AF_INET6), -EPFNOSUPPORT);
308
3e4f1dc9 309 r = is_socket_internal(fd, type, listening);
f6f372d2
ZJS
310 if (r <= 0)
311 return r;
312
313 if (getsockname(fd, &sockaddr.sa, &l) < 0)
314 return -errno;
315
316 if (l < sizeof(sa_family_t))
317 return -EINVAL;
318
319 if (sockaddr.sa.sa_family != addr->sa_family)
320 return 0;
321
322 if (sockaddr.sa.sa_family == AF_INET) {
323 const struct sockaddr_in *in = (const struct sockaddr_in *) addr;
324
325 if (l < sizeof(struct sockaddr_in) || addr_len < sizeof(struct sockaddr_in))
326 return -EINVAL;
327
328 if (in->sin_port != 0 &&
329 sockaddr.in.sin_port != in->sin_port)
330 return false;
331
332 return sockaddr.in.sin_addr.s_addr == in->sin_addr.s_addr;
333
334 } else {
335 const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) addr;
336
337 if (l < sizeof(struct sockaddr_in6) || addr_len < sizeof(struct sockaddr_in6))
338 return -EINVAL;
339
340 if (in->sin6_port != 0 &&
341 sockaddr.in6.sin6_port != in->sin6_port)
342 return false;
343
344 if (in->sin6_flowinfo != 0 &&
345 sockaddr.in6.sin6_flowinfo != in->sin6_flowinfo)
346 return false;
347
348 if (in->sin6_scope_id != 0 &&
349 sockaddr.in6.sin6_scope_id != in->sin6_scope_id)
350 return false;
351
352 return memcmp(sockaddr.in6.sin6_addr.s6_addr, in->sin6_addr.s6_addr,
353 sizeof(in->sin6_addr.s6_addr)) == 0;
354 }
355}
356
0ebee881 357_public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
1c633045
ZJS
358 union sockaddr_union sockaddr = {};
359 socklen_t l = sizeof(sockaddr);
7c394faa
LP
360 int r;
361
e6803801 362 assert_return(fd >= 0, -EBADF);
be8f4e9e 363
3e4f1dc9 364 r = is_socket_internal(fd, type, listening);
50425d16 365 if (r <= 0)
7c394faa
LP
366 return r;
367
7c394faa
LP
368 if (getsockname(fd, &sockaddr.sa, &l) < 0)
369 return -errno;
370
b7f42664 371 if (l < sizeof(sa_family_t))
7c394faa
LP
372 return -EINVAL;
373
374 if (sockaddr.sa.sa_family != AF_UNIX)
375 return 0;
376
377 if (path) {
d1d7caee 378 if (length == 0)
7c394faa
LP
379 length = strlen(path);
380
d1d7caee 381 if (length == 0)
7c394faa 382 /* Unnamed socket */
0e098b15 383 return l == offsetof(struct sockaddr_un, sun_path);
7c394faa 384
7c394faa
LP
385 if (path[0])
386 /* Normal path socket */
cd250a39 387 return
0e098b15 388 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
cd250a39 389 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
7c394faa
LP
390 else
391 /* Abstract namespace socket */
cd250a39 392 return
0e098b15 393 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
cd250a39 394 memcmp(path, sockaddr.un.sun_path, length) == 0;
7c394faa
LP
395 }
396
397 return 1;
398}
8c47c732 399
0ebee881 400_public_ int sd_is_mq(int fd, const char *path) {
916abb21 401 struct mq_attr attr;
6056663a 402 int r;
916abb21 403
0260d1d5 404 /* Check that the fd is valid */
6056663a
LP
405 r = fd_validate(fd);
406 if (r < 0)
407 return r;
916abb21 408
0260d1d5
ZJS
409 if (mq_getattr(fd, &attr) < 0) {
410 if (errno == EBADF)
411 /* A non-mq fd (or an invalid one, but we ruled that out above) */
412 return 0;
916abb21 413 return -errno;
0260d1d5 414 }
916abb21
LP
415
416 if (path) {
d6b218e7 417 _cleanup_free_ char *fpath = NULL;
916abb21
LP
418 struct stat a, b;
419
be8f4e9e 420 assert_return(path_is_absolute(path), -EINVAL);
916abb21
LP
421
422 if (fstat(fd, &a) < 0)
423 return -errno;
424
d6b218e7
LP
425 fpath = path_join("/dev/mqueue", path);
426 if (!fpath)
427 return -ENOMEM;
916abb21
LP
428
429 if (stat(fpath, &b) < 0)
430 return -errno;
431
a9dac7a6 432 if (!stat_inode_same(&a, &b))
916abb21
LP
433 return 0;
434 }
435
436 return 1;
916abb21
LP
437}
438
6c94cfcd
LB
439static int vsock_bind_privileged_port(int fd) {
440 union sockaddr_union sa = {
441 .vm.svm_family = AF_VSOCK,
442 .vm.svm_cid = VMADDR_CID_ANY,
443 .vm.svm_port = 1023,
444 };
445 int r;
446
447 assert(fd >= 0);
448
449 do
450 r = RET_NERRNO(bind(fd, &sa.sa, sizeof(sa.vm)));
451 while (r == -EADDRINUSE && --sa.vm.svm_port > 0);
452
453 return r;
454}
455
bdee762b 456static int pid_notify_with_fds_internal(
9e1d021e 457 pid_t pid,
9e1d021e
LP
458 const char *state,
459 const int *fds,
74806f71 460 size_t n_fds) {
3e9fcc21 461
6c94cfcd 462 SocketAddress address;
cb310866 463 struct iovec iovec;
a354329f
LP
464 struct msghdr msghdr = {
465 .msg_iov = &iovec,
466 .msg_iovlen = 1,
6c94cfcd 467 .msg_name = &address.sockaddr,
a354329f 468 };
254d1313 469 _cleanup_close_ int fd = -EBADF;
56d02f29 470 int type, r;
8c47c732 471
3e9fcc21
MY
472 assert_return(state, -EINVAL);
473 assert_return(fds || n_fds == 0, -EINVAL);
8c47c732 474
cb42df53
LP
475 /* Let's make sure the multiplications below don't overflow, and also return a recognizable error in
476 * case the caller tries to send more fds than the kernel limit. The kernel would return EINVAL which
477 * is not too useful I'd say. */
478 if (n_fds > SCM_MAX_FD)
479 return -E2BIG;
480
3e9fcc21 481 const char *e = getenv("NOTIFY_SOCKET");
50425d16 482 if (!e)
08bfb810 483 return 0;
8c47c732 484
6c94cfcd
LB
485 /* Allow AF_UNIX and AF_VSOCK, reject the rest. */
486 r = socket_address_parse_unix(&address, e);
487 if (r == -EPROTO)
488 r = socket_address_parse_vsock(&address, e);
f36a9d59 489 if (r < 0)
bdee762b 490 return r;
6c94cfcd 491 msghdr.msg_namelen = address.size;
638b56cd 492
6c94cfcd
LB
493 /* If we didn't get an address (which is a normal pattern when specifying VSOCK tuples) error out,
494 * we always require a specific CID. */
bdee762b
DDM
495 if (address.sockaddr.vm.svm_family == AF_VSOCK && address.sockaddr.vm.svm_cid == VMADDR_CID_ANY)
496 return -EINVAL;
8c47c732 497
56d02f29
DDM
498 type = address.type == 0 ? SOCK_DGRAM : address.type;
499
6c94cfcd
LB
500 /* At the time of writing QEMU does not yet support AF_VSOCK + SOCK_DGRAM and returns
501 * ENODEV. Fallback to SOCK_SEQPACKET in that case. */
56d02f29 502 fd = socket(address.sockaddr.sa.sa_family, type|SOCK_CLOEXEC, 0);
6c94cfcd 503 if (fd < 0) {
56d02f29
DDM
504 if (!(ERRNO_IS_NOT_SUPPORTED(errno) || errno == ENODEV) || address.sockaddr.sa.sa_family != AF_VSOCK || address.type > 0)
505 return log_debug_errno(errno, "Failed to open %s notify socket to '%s': %m", socket_address_type_to_string(type), e);
6c94cfcd 506
56d02f29
DDM
507 type = SOCK_SEQPACKET;
508 fd = socket(address.sockaddr.sa.sa_family, type|SOCK_CLOEXEC, 0);
7f78d343
DDM
509 if (fd < 0 && ERRNO_IS_NOT_SUPPORTED(errno)) {
510 type = SOCK_STREAM;
511 fd = socket(address.sockaddr.sa.sa_family, type|SOCK_CLOEXEC, 0);
512 }
bdee762b 513 if (fd < 0)
56d02f29
DDM
514 return log_debug_errno(errno, "Failed to open %s socket to '%s': %m", socket_address_type_to_string(type), e);
515 }
6c94cfcd 516
56d02f29 517 if (address.sockaddr.sa.sa_family == AF_VSOCK) {
6c94cfcd
LB
518 r = vsock_bind_privileged_port(fd);
519 if (r < 0 && !ERRNO_IS_PRIVILEGE(r))
5fbcad01 520 return log_debug_errno(r, "Failed to bind socket to privileged port: %m");
56d02f29 521 }
6c94cfcd 522
56d02f29 523 if (IN_SET(type, SOCK_STREAM, SOCK_SEQPACKET)) {
bdee762b 524 if (connect(fd, &address.sockaddr.sa, address.size) < 0)
5fbcad01 525 return log_debug_errno(errno, "Failed to connect socket to '%s': %m", e);
6c94cfcd
LB
526
527 msghdr.msg_name = NULL;
528 msghdr.msg_namelen = 0;
6c94cfcd
LB
529 }
530
9e1d021e 531 (void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
a47806fa 532
cb310866 533 iovec = IOVEC_MAKE_STRING(state);
a013bd94 534
3e9fcc21 535 bool send_ucred =
9e1d021e
LP
536 (pid != 0 && pid != getpid_cached()) ||
537 getuid() != geteuid() ||
538 getgid() != getegid();
d4a144fa 539
9e1d021e 540 if (n_fds > 0 || send_ucred) {
3e9fcc21
MY
541 struct cmsghdr *cmsg;
542
96d49011 543 /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
c463a6f1
LP
544 msghdr.msg_controllen =
545 (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
9e1d021e 546 (send_ucred ? CMSG_SPACE(sizeof(struct ucred)) : 0);
c463a6f1 547
40f44238 548 msghdr.msg_control = alloca0(msghdr.msg_controllen);
a354329f
LP
549
550 cmsg = CMSG_FIRSTHDR(&msghdr);
64144440
ZJS
551 if (n_fds > 0) {
552 cmsg->cmsg_level = SOL_SOCKET;
553 cmsg->cmsg_type = SCM_RIGHTS;
554 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
a354329f 555
64144440 556 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
be8f4e9e 557
9e1d021e 558 if (send_ucred)
64144440
ZJS
559 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
560 }
a354329f 561
9e1d021e 562 if (send_ucred) {
64144440 563 struct ucred *ucred;
be8f4e9e 564
64144440
ZJS
565 cmsg->cmsg_level = SOL_SOCKET;
566 cmsg->cmsg_type = SCM_CREDENTIALS;
567 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
be8f4e9e 568
b5d39bb3 569 ucred = CMSG_TYPED_DATA(cmsg, struct ucred);
9e1d021e 570 ucred->pid = pid != 0 ? pid : getpid_cached();
64144440
ZJS
571 ucred->uid = getuid();
572 ucred->gid = getgid();
573 }
be8f4e9e
LP
574 }
575
3e9fcc21
MY
576 ssize_t n;
577
7f78d343
DDM
578 do {
579 /* First try with fake ucred data, as requested */
580 n = sendmsg(fd, &msghdr, MSG_NOSIGNAL);
581 if (n < 0) {
582 if (!send_ucred)
583 return log_debug_errno(errno, "Failed to send notify message to '%s': %m", e);
584
585 /* If that failed, try with our own ucred instead */
586 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
587 if (msghdr.msg_controllen == 0)
588 msghdr.msg_control = NULL;
589
590 n = 0;
591 send_ucred = false;
592 } else {
593 /* Unless we're using SOCK_STREAM, we expect to write all the contents immediately. */
c24e0dbe 594 if (type != SOCK_STREAM && (size_t) n < iovec_total_size(msghdr.msg_iov, msghdr.msg_iovlen))
7f78d343
DDM
595 return -EIO;
596
597 /* Make sure we only send fds and ucred once, even if we're using SOCK_STREAM. */
a354329f 598 msghdr.msg_control = NULL;
7f78d343
DDM
599 msghdr.msg_controllen = 0;
600 }
986235a9 601 } while (!iovec_increment(msghdr.msg_iov, msghdr.msg_iovlen, n));
be8f4e9e 602
13b67b61
DDM
603 if (address.sockaddr.sa.sa_family == AF_VSOCK && IN_SET(type, SOCK_STREAM, SOCK_SEQPACKET)) {
604 /* For AF_VSOCK, we need to close the socket to signal the end of the message. */
605 if (shutdown(fd, SHUT_WR) < 0)
3baab23b 606 return log_debug_errno(errno, "Failed to shutdown notify socket: %m");
13b67b61 607
3baab23b
MY
608 char c;
609 n = recv(fd, &c, sizeof(c), MSG_NOSIGNAL);
13b67b61 610 if (n < 0)
3baab23b
MY
611 return log_debug_errno(errno, "Failed to wait for EOF on notify socket: %m");
612 if (n > 0)
613 return log_debug_errno(SYNTHETIC_ERRNO(EPROTO), "Unexpectedly received data on notify socket.");
13b67b61
DDM
614 }
615
7f78d343 616 return 1;
bdee762b
DDM
617}
618
66063489
LP
619static void unsetenv_notify(bool unset_environment) {
620 if (!unset_environment)
621 return;
622
623 assert_se(unsetenv("NOTIFY_SOCKET") == 0);
624}
625
bdee762b
DDM
626_public_ int sd_pid_notify_with_fds(
627 pid_t pid,
628 int unset_environment,
629 const char *state,
630 const int *fds,
631 unsigned n_fds) {
632
633 int r;
634
635 r = pid_notify_with_fds_internal(pid, state, fds, n_fds);
66063489 636 unsetenv_notify(unset_environment);
8c47c732 637 return r;
8c47c732
LP
638}
639
0de34318 640_public_ int sd_pid_notify_barrier(pid_t pid, int unset_environment, uint64_t timeout) {
71136404 641 _cleanup_close_pair_ int pipe_fd[2] = EBADF_PAIR;
4f07ddfa
KKD
642 int r;
643
66063489
LP
644 r = RET_NERRNO(pipe2(pipe_fd, O_CLOEXEC));
645 if (r < 0)
646 goto finish;
4f07ddfa 647
66063489 648 r = pid_notify_with_fds_internal(pid, "BARRIER=1", &pipe_fd[1], 1);
4f07ddfa 649 if (r <= 0)
66063489 650 goto finish;
4f07ddfa
KKD
651
652 pipe_fd[1] = safe_close(pipe_fd[1]);
653
0f2d351f 654 r = fd_wait_for_event(pipe_fd[0], 0 /* POLLHUP is implicit */, timeout);
4f07ddfa 655 if (r < 0)
66063489
LP
656 goto finish;
657 if (r == 0) {
658 r = -ETIMEDOUT;
659 goto finish;
660 }
4f07ddfa 661
66063489
LP
662 r = 1;
663finish:
664 unsetenv_notify(unset_environment);
665 return r;
4f07ddfa
KKD
666}
667
0de34318
LP
668_public_ int sd_notify_barrier(int unset_environment, uint64_t timeout) {
669 return sd_pid_notify_barrier(0, unset_environment, timeout);
670}
671
a354329f
LP
672_public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
673 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
674}
675
be8f4e9e 676_public_ int sd_notify(int unset_environment, const char *state) {
a354329f 677 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
be8f4e9e
LP
678}
679
680_public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
681 _cleanup_free_ char *p = NULL;
66063489 682 int r;
be8f4e9e
LP
683
684 if (format) {
685 va_list ap;
686
687 va_start(ap, format);
688 r = vasprintf(&p, format, ap);
689 va_end(ap);
690
66063489 691 if (r < 0) {
362dcfc5 692 r = -ENOMEM;
66063489 693 goto finish;
362dcfc5 694 }
be8f4e9e
LP
695 }
696
66063489
LP
697 r = pid_notify_with_fds_internal(pid, p, /* fds= */ NULL, /* n_fds= */ 0);
698
699finish:
700 unsetenv_notify(unset_environment);
701 return r;
be8f4e9e
LP
702}
703
0ebee881 704_public_ int sd_notifyf(int unset_environment, const char *format, ...) {
be8f4e9e 705 _cleanup_free_ char *p = NULL;
66063489 706 int r;
8c47c732 707
be8f4e9e
LP
708 if (format) {
709 va_list ap;
8c47c732 710
be8f4e9e
LP
711 va_start(ap, format);
712 r = vasprintf(&p, format, ap);
713 va_end(ap);
8c47c732 714
66063489 715 if (r < 0) {
362dcfc5 716 r = -ENOMEM;
66063489 717 goto finish;
362dcfc5 718 }
be8f4e9e 719 }
8c47c732 720
66063489
LP
721 r = pid_notify_with_fds_internal(/* pid= */ 0, p, /* fds= */ NULL, /* n_fds= */ 0);
722
723finish:
724 unsetenv_notify(unset_environment);
725 return r;
8c47c732 726}
40473a70 727
9857de4f 728_public_ int sd_pid_notifyf_with_fds(
4054d761
LP
729 pid_t pid,
730 int unset_environment,
731 const int *fds, size_t n_fds,
732 const char *format, ...) {
733
734 _cleanup_free_ char *p = NULL;
66063489 735 int r;
4054d761 736
74806f71 737 if (format) {
4054d761
LP
738 va_list ap;
739
740 va_start(ap, format);
741 r = vasprintf(&p, format, ap);
742 va_end(ap);
743
66063489 744 if (r < 0) {
362dcfc5 745 r = -ENOMEM;
66063489 746 goto finish;
362dcfc5 747 }
4054d761
LP
748 }
749
66063489
LP
750 r = pid_notify_with_fds_internal(pid, p, fds, n_fds);
751
752finish:
753 unsetenv_notify(unset_environment);
754 return r;
4054d761
LP
755}
756
46b08447
MY
757_public_ int sd_pidfd_get_inode_id(int pidfd, uint64_t *ret) {
758 int r;
759
760 assert_return(pidfd >= 0, -EBADF);
761
762 /* Are pidfds backed by pidfs where the unique inode id is relevant? Note that the pidfd
763 * passed to us is extrinsic and hence cannot be trusted to initialize our "have_pidfs" cache,
764 * instead pidfd_check_pidfs() will allocate one internally. */
765 r = pidfd_check_pidfs(/* pid_fd = */ -EBADF);
766 if (r <= 0)
767 return -EOPNOTSUPP;
768
769 r = fd_is_fs_type(pidfd, PID_FS_MAGIC);
770 if (r < 0)
771 return r;
772 if (r == 0)
773 return -EBADF; /* pidfs is definitely around, so it's the fd that's of invalid type */
774
775 return pidfd_get_inode_id_impl(pidfd, ret);
776}
777
0ebee881 778_public_ int sd_booted(void) {
7c1dd9e2 779 int r;
40473a70 780
7c1dd9e2
MY
781 /* We test whether the runtime unit file directory has been created. This takes place in mount-setup.c,
782 * so is guaranteed to happen very early during boot. */
21042737 783
3f8999a7 784 r = access_nofollow("/run/systemd/system/", F_OK);
7c1dd9e2
MY
785 if (r >= 0)
786 return true;
787 if (r == -ENOENT)
21042737
YW
788 return false;
789
7c1dd9e2 790 return r;
40473a70 791}
09812eb7 792
66063489
LP
793static void unsetenv_watchdog(bool unset_environment) {
794 if (!unset_environment)
795 return;
796
797 assert_se(unsetenv("WATCHDOG_USEC") == 0);
798 assert_se(unsetenv("WATCHDOG_PID") == 0);
799}
800
0ebee881 801_public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
a9becdd6 802 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
be8f4e9e 803 uint64_t u;
66063489 804 int r;
09812eb7 805
a9becdd6 806 s = getenv("WATCHDOG_USEC");
66063489
LP
807 if (!s) {
808 r = 0;
09812eb7 809 goto finish;
66063489 810 }
09812eb7 811
a9becdd6 812 r = safe_atou64(s, &u);
be8f4e9e 813 if (r < 0)
09812eb7 814 goto finish;
0da36375 815 if (!timestamp_is_set(u)) {
09812eb7
LP
816 r = -EINVAL;
817 goto finish;
818 }
819
a9becdd6
ZJS
820 p = getenv("WATCHDOG_PID");
821 if (p) {
822 pid_t pid;
823
824 r = parse_pid(p, &pid);
825 if (r < 0)
826 goto finish;
827
828 /* Is this for us? */
df0ff127 829 if (getpid_cached() != pid) {
a9becdd6
ZJS
830 r = 0;
831 goto finish;
832 }
09812eb7
LP
833 }
834
835 if (usec)
be8f4e9e 836 *usec = u;
09812eb7
LP
837
838 r = 1;
839
840finish:
66063489 841 unsetenv_watchdog(unset_environment);
09812eb7 842 return r;
09812eb7 843}