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