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