1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
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.
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.
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/>.
24 #include <netinet/in.h>
30 #include <sys/socket.h>
35 #include "sd-daemon.h"
37 #include "alloc-util.h"
40 #include "parse-util.h"
41 #include "path-util.h"
42 //#include "process-util.h"
43 #include "socket-util.h"
47 /// Additional includes needed by elogind
48 #include "process-util.h"
50 #define SNDBUF_SIZE (8*1024*1024)
52 static void unsetenv_all(bool unset_environment) {
54 if (!unset_environment)
57 unsetenv("LISTEN_PID");
58 unsetenv("LISTEN_FDS");
59 unsetenv("LISTEN_FDNAMES");
62 _public_ int sd_listen_fds(int unset_environment) {
67 e = getenv("LISTEN_PID");
73 r = parse_pid(e, &pid);
78 if (getpid_cached() != pid) {
83 e = getenv("LISTEN_FDS");
93 assert_cc(SD_LISTEN_FDS_START < INT_MAX);
94 if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
99 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
100 r = fd_cloexec(fd, true);
108 unsetenv_all(unset_environment);
112 _public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
113 _cleanup_strv_free_ char **l = NULL;
115 int n_names = 0, n_fds;
120 return sd_listen_fds(unset_environment);
122 e = getenv("LISTEN_FDNAMES");
124 n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
126 unsetenv_all(unset_environment);
134 n_fds = sd_listen_fds(unset_environment);
139 if (n_names != n_fds)
142 r = strv_extend_n(&l, "unknown", n_fds);
153 _public_ int sd_is_fifo(int fd, const char *path) {
156 assert_return(fd >= 0, -EBADF);
158 if (fstat(fd, &st_fd) < 0)
161 if (!S_ISFIFO(st_fd.st_mode))
167 if (stat(path, &st_path) < 0) {
169 if (IN_SET(errno, ENOENT, ENOTDIR))
176 st_path.st_dev == st_fd.st_dev &&
177 st_path.st_ino == st_fd.st_ino;
183 _public_ int sd_is_special(int fd, const char *path) {
186 assert_return(fd >= 0, -EBADF);
188 if (fstat(fd, &st_fd) < 0)
191 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
197 if (stat(path, &st_path) < 0) {
199 if (IN_SET(errno, ENOENT, ENOTDIR))
205 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
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;
218 static int sd_is_socket_internal(int fd, int type, int listening) {
221 assert_return(fd >= 0, -EBADF);
222 assert_return(type >= 0, -EINVAL);
224 if (fstat(fd, &st_fd) < 0)
227 if (!S_ISSOCK(st_fd.st_mode))
232 socklen_t l = sizeof(other_type);
234 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
237 if (l != sizeof(other_type))
240 if (other_type != type)
244 if (listening >= 0) {
246 socklen_t l = sizeof(accepting);
248 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
251 if (l != sizeof(accepting))
254 if (!accepting != !listening)
261 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
264 assert_return(fd >= 0, -EBADF);
265 assert_return(family >= 0, -EINVAL);
267 r = sd_is_socket_internal(fd, type, listening);
272 union sockaddr_union sockaddr = {};
273 socklen_t l = sizeof(sockaddr);
275 if (getsockname(fd, &sockaddr.sa, &l) < 0)
278 if (l < sizeof(sa_family_t))
281 return sockaddr.sa.sa_family == family;
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);
292 assert_return(fd >= 0, -EBADF);
293 assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
295 r = sd_is_socket_internal(fd, type, listening);
299 if (getsockname(fd, &sockaddr.sa, &l) < 0)
302 if (l < sizeof(sa_family_t))
305 if (!IN_SET(sockaddr.sa.sa_family, AF_INET, AF_INET6))
309 if (sockaddr.sa.sa_family != family)
315 r = sockaddr_port(&sockaddr.sa, &sa_port);
319 return port == sa_port;
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);
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);
335 r = sd_is_socket_internal(fd, type, listening);
339 if (getsockname(fd, &sockaddr.sa, &l) < 0)
342 if (l < sizeof(sa_family_t))
345 if (sockaddr.sa.sa_family != addr->sa_family)
348 if (sockaddr.sa.sa_family == AF_INET) {
349 const struct sockaddr_in *in = (const struct sockaddr_in *) addr;
351 if (l < sizeof(struct sockaddr_in) || addr_len < sizeof(struct sockaddr_in))
354 if (in->sin_port != 0 &&
355 sockaddr.in.sin_port != in->sin_port)
358 return sockaddr.in.sin_addr.s_addr == in->sin_addr.s_addr;
361 const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) addr;
363 if (l < sizeof(struct sockaddr_in6) || addr_len < sizeof(struct sockaddr_in6))
366 if (in->sin6_port != 0 &&
367 sockaddr.in6.sin6_port != in->sin6_port)
370 if (in->sin6_flowinfo != 0 &&
371 sockaddr.in6.sin6_flowinfo != in->sin6_flowinfo)
374 if (in->sin6_scope_id != 0 &&
375 sockaddr.in6.sin6_scope_id != in->sin6_scope_id)
378 return memcmp(sockaddr.in6.sin6_addr.s6_addr, in->sin6_addr.s6_addr,
379 sizeof(in->sin6_addr.s6_addr)) == 0;
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);
388 assert_return(fd >= 0, -EBADF);
390 r = sd_is_socket_internal(fd, type, listening);
394 if (getsockname(fd, &sockaddr.sa, &l) < 0)
397 if (l < sizeof(sa_family_t))
400 if (sockaddr.sa.sa_family != AF_UNIX)
405 length = strlen(path);
409 return l == offsetof(struct sockaddr_un, sun_path);
412 /* Normal path socket */
414 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
415 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
417 /* Abstract namespace socket */
419 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
420 memcmp(path, sockaddr.un.sun_path, length) == 0;
426 #if 0 /// UNNEEDED by elogind
427 _public_ int sd_is_mq(int fd, const char *path) {
430 /* Check that the fd is valid */
431 assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
433 if (mq_getattr(fd, &attr) < 0) {
435 /* A non-mq fd (or an invalid one, but we ruled that out above) */
441 char fpath[PATH_MAX];
444 assert_return(path_is_absolute(path), -EINVAL);
446 if (fstat(fd, &a) < 0)
449 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
450 fpath[sizeof(fpath)-1] = 0;
452 if (stat(fpath, &b) < 0)
455 if (a.st_dev != b.st_dev ||
456 a.st_ino != b.st_ino)
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,
468 struct iovec iovec = {
469 .iov_base = (char*) state,
471 struct msghdr msghdr = {
474 .msg_name = &sockaddr,
476 _cleanup_close_ int fd = -1;
477 struct cmsghdr *cmsg = NULL;
487 if (n_fds > 0 && !fds) {
492 e = getenv("NOTIFY_SOCKET");
496 /* Must be an abstract socket, or an absolute path */
497 if (!IN_SET(e[0], '@', '/') || e[1] == 0) {
502 if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
507 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
513 fd_inc_sndbuf(fd, SNDBUF_SIZE);
515 iovec.iov_len = strlen(state);
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;
521 msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
523 have_pid = pid != 0 && pid != getpid_cached();
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);
531 msghdr.msg_control = alloca0(msghdr.msg_controllen);
533 cmsg = CMSG_FIRSTHDR(&msghdr);
535 cmsg->cmsg_level = SOL_SOCKET;
536 cmsg->cmsg_type = SCM_RIGHTS;
537 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
539 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
542 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
548 cmsg->cmsg_level = SOL_SOCKET;
549 cmsg->cmsg_type = SCM_CREDENTIALS;
550 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
552 ucred = (struct ucred*) CMSG_DATA(cmsg);
554 ucred->uid = getuid();
555 ucred->gid = getgid();
559 /* First try with fake ucred data, as requested */
560 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
565 /* If that failed, try with our own ucred instead */
567 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
568 if (msghdr.msg_controllen == 0)
569 msghdr.msg_control = NULL;
571 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
580 if (unset_environment)
581 unsetenv("NOTIFY_SOCKET");
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);
590 _public_ int sd_notify(int unset_environment, const char *state) {
591 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
594 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
595 _cleanup_free_ char *p = NULL;
601 va_start(ap, format);
602 r = vasprintf(&p, format, ap);
609 return sd_pid_notify(pid, unset_environment, p);
612 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
613 _cleanup_free_ char *p = NULL;
619 va_start(ap, format);
620 r = vasprintf(&p, format, ap);
627 return sd_pid_notify(0, unset_environment, p);
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. */
635 #if 0 /// elogind is always used without systemd running the show. (Well, it should...)
636 return laccess("/run/systemd/system/", F_OK) >= 0;
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 */
647 s = getenv("WATCHDOG_USEC");
651 r = safe_atou64(s, &u);
654 if (u <= 0 || u >= USEC_INFINITY) {
659 p = getenv("WATCHDOG_PID");
663 r = parse_pid(p, &pid);
667 /* Is this for us? */
668 if (getpid_cached() != pid) {
680 if (unset_environment && s)
681 unsetenv("WATCHDOG_USEC");
682 if (unset_environment && p)
683 unsetenv("WATCHDOG_PID");