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 "socket-util.h"
46 /// Additional includes needed by elogind
47 #include "process-util.h"
49 #define SNDBUF_SIZE (8*1024*1024)
51 static void unsetenv_all(bool unset_environment) {
53 if (!unset_environment)
56 unsetenv("LISTEN_PID");
57 unsetenv("LISTEN_FDS");
58 unsetenv("LISTEN_FDNAMES");
61 _public_ int sd_listen_fds(int unset_environment) {
66 e = getenv("LISTEN_PID");
72 r = parse_pid(e, &pid);
77 if (getpid_cached() != pid) {
82 e = getenv("LISTEN_FDS");
92 assert_cc(SD_LISTEN_FDS_START < INT_MAX);
93 if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
98 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
99 r = fd_cloexec(fd, true);
107 unsetenv_all(unset_environment);
111 _public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
112 _cleanup_strv_free_ char **l = NULL;
114 int n_names = 0, n_fds;
119 return sd_listen_fds(unset_environment);
121 e = getenv("LISTEN_FDNAMES");
123 n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
125 unsetenv_all(unset_environment);
133 n_fds = sd_listen_fds(unset_environment);
138 if (n_names != n_fds)
141 r = strv_extend_n(&l, "unknown", n_fds);
152 _public_ int sd_is_fifo(int fd, const char *path) {
155 assert_return(fd >= 0, -EBADF);
157 if (fstat(fd, &st_fd) < 0)
160 if (!S_ISFIFO(st_fd.st_mode))
166 if (stat(path, &st_path) < 0) {
168 if (IN_SET(errno, ENOENT, ENOTDIR))
175 st_path.st_dev == st_fd.st_dev &&
176 st_path.st_ino == st_fd.st_ino;
182 _public_ int sd_is_special(int fd, const char *path) {
185 assert_return(fd >= 0, -EBADF);
187 if (fstat(fd, &st_fd) < 0)
190 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
196 if (stat(path, &st_path) < 0) {
198 if (IN_SET(errno, ENOENT, ENOTDIR))
204 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
206 st_path.st_dev == st_fd.st_dev &&
207 st_path.st_ino == st_fd.st_ino;
208 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
209 return st_path.st_rdev == st_fd.st_rdev;
217 static int sd_is_socket_internal(int fd, int type, int listening) {
220 assert_return(fd >= 0, -EBADF);
221 assert_return(type >= 0, -EINVAL);
223 if (fstat(fd, &st_fd) < 0)
226 if (!S_ISSOCK(st_fd.st_mode))
231 socklen_t l = sizeof(other_type);
233 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
236 if (l != sizeof(other_type))
239 if (other_type != type)
243 if (listening >= 0) {
245 socklen_t l = sizeof(accepting);
247 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
250 if (l != sizeof(accepting))
253 if (!accepting != !listening)
260 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
263 assert_return(fd >= 0, -EBADF);
264 assert_return(family >= 0, -EINVAL);
266 r = sd_is_socket_internal(fd, type, listening);
271 union sockaddr_union sockaddr = {};
272 socklen_t l = sizeof(sockaddr);
274 if (getsockname(fd, &sockaddr.sa, &l) < 0)
277 if (l < sizeof(sa_family_t))
280 return sockaddr.sa.sa_family == family;
286 _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
287 union sockaddr_union sockaddr = {};
288 socklen_t l = sizeof(sockaddr);
291 assert_return(fd >= 0, -EBADF);
292 assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
294 r = sd_is_socket_internal(fd, type, listening);
298 if (getsockname(fd, &sockaddr.sa, &l) < 0)
301 if (l < sizeof(sa_family_t))
304 if (!IN_SET(sockaddr.sa.sa_family, AF_INET, AF_INET6))
308 if (sockaddr.sa.sa_family != family)
314 r = sockaddr_port(&sockaddr.sa, &sa_port);
318 return port == sa_port;
324 _public_ int sd_is_socket_sockaddr(int fd, int type, const struct sockaddr* addr, unsigned addr_len, int listening) {
325 union sockaddr_union sockaddr = {};
326 socklen_t l = sizeof(sockaddr);
329 assert_return(fd >= 0, -EBADF);
330 assert_return(addr, -EINVAL);
331 assert_return(addr_len >= sizeof(sa_family_t), -ENOBUFS);
332 assert_return(IN_SET(addr->sa_family, AF_INET, AF_INET6), -EPFNOSUPPORT);
334 r = sd_is_socket_internal(fd, type, listening);
338 if (getsockname(fd, &sockaddr.sa, &l) < 0)
341 if (l < sizeof(sa_family_t))
344 if (sockaddr.sa.sa_family != addr->sa_family)
347 if (sockaddr.sa.sa_family == AF_INET) {
348 const struct sockaddr_in *in = (const struct sockaddr_in *) addr;
350 if (l < sizeof(struct sockaddr_in) || addr_len < sizeof(struct sockaddr_in))
353 if (in->sin_port != 0 &&
354 sockaddr.in.sin_port != in->sin_port)
357 return sockaddr.in.sin_addr.s_addr == in->sin_addr.s_addr;
360 const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) addr;
362 if (l < sizeof(struct sockaddr_in6) || addr_len < sizeof(struct sockaddr_in6))
365 if (in->sin6_port != 0 &&
366 sockaddr.in6.sin6_port != in->sin6_port)
369 if (in->sin6_flowinfo != 0 &&
370 sockaddr.in6.sin6_flowinfo != in->sin6_flowinfo)
373 if (in->sin6_scope_id != 0 &&
374 sockaddr.in6.sin6_scope_id != in->sin6_scope_id)
377 return memcmp(sockaddr.in6.sin6_addr.s6_addr, in->sin6_addr.s6_addr,
378 sizeof(in->sin6_addr.s6_addr)) == 0;
382 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
383 union sockaddr_union sockaddr = {};
384 socklen_t l = sizeof(sockaddr);
387 assert_return(fd >= 0, -EBADF);
389 r = sd_is_socket_internal(fd, type, listening);
393 if (getsockname(fd, &sockaddr.sa, &l) < 0)
396 if (l < sizeof(sa_family_t))
399 if (sockaddr.sa.sa_family != AF_UNIX)
404 length = strlen(path);
408 return l == offsetof(struct sockaddr_un, sun_path);
411 /* Normal path socket */
413 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
414 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
416 /* Abstract namespace socket */
418 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
419 memcmp(path, sockaddr.un.sun_path, length) == 0;
425 #if 0 /// UNNEEDED by elogind
426 _public_ int sd_is_mq(int fd, const char *path) {
429 /* Check that the fd is valid */
430 assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
432 if (mq_getattr(fd, &attr) < 0) {
434 /* A non-mq fd (or an invalid one, but we ruled that out above) */
440 char fpath[PATH_MAX];
443 assert_return(path_is_absolute(path), -EINVAL);
445 if (fstat(fd, &a) < 0)
448 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
449 fpath[sizeof(fpath)-1] = 0;
451 if (stat(fpath, &b) < 0)
454 if (a.st_dev != b.st_dev ||
455 a.st_ino != b.st_ino)
463 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
464 union sockaddr_union sockaddr = {
465 .sa.sa_family = AF_UNIX,
467 struct iovec iovec = {
468 .iov_base = (char*) state,
470 struct msghdr msghdr = {
473 .msg_name = &sockaddr,
475 _cleanup_close_ int fd = -1;
476 struct cmsghdr *cmsg = NULL;
486 if (n_fds > 0 && !fds) {
491 e = getenv("NOTIFY_SOCKET");
495 /* Must be an abstract socket, or an absolute path */
496 if (!IN_SET(e[0], '@', '/') || e[1] == 0) {
501 if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
506 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
512 fd_inc_sndbuf(fd, SNDBUF_SIZE);
514 iovec.iov_len = strlen(state);
516 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
517 if (sockaddr.un.sun_path[0] == '@')
518 sockaddr.un.sun_path[0] = 0;
520 msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
522 have_pid = pid != 0 && pid != getpid_cached();
524 if (n_fds > 0 || have_pid) {
525 /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
526 msghdr.msg_controllen =
527 (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
528 (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
530 msghdr.msg_control = alloca0(msghdr.msg_controllen);
532 cmsg = CMSG_FIRSTHDR(&msghdr);
534 cmsg->cmsg_level = SOL_SOCKET;
535 cmsg->cmsg_type = SCM_RIGHTS;
536 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
538 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
541 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
547 cmsg->cmsg_level = SOL_SOCKET;
548 cmsg->cmsg_type = SCM_CREDENTIALS;
549 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
551 ucred = (struct ucred*) CMSG_DATA(cmsg);
553 ucred->uid = getuid();
554 ucred->gid = getgid();
558 /* First try with fake ucred data, as requested */
559 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
564 /* If that failed, try with our own ucred instead */
566 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
567 if (msghdr.msg_controllen == 0)
568 msghdr.msg_control = NULL;
570 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
579 if (unset_environment)
580 unsetenv("NOTIFY_SOCKET");
585 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
586 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
589 _public_ int sd_notify(int unset_environment, const char *state) {
590 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
593 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
594 _cleanup_free_ char *p = NULL;
600 va_start(ap, format);
601 r = vasprintf(&p, format, ap);
608 return sd_pid_notify(pid, unset_environment, p);
611 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
612 _cleanup_free_ char *p = NULL;
618 va_start(ap, format);
619 r = vasprintf(&p, format, ap);
626 return sd_pid_notify(0, unset_environment, p);
629 _public_ int sd_booted(void) {
630 /* We test whether the runtime unit file directory has been
631 * created. This takes place in mount-setup.c, so is
632 * guaranteed to happen very early during boot. */
634 #if 0 /// elogind is always used without systemd running the show. (Well, it should...)
635 return laccess("/run/systemd/system/", F_OK) >= 0;
641 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
642 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
646 s = getenv("WATCHDOG_USEC");
650 r = safe_atou64(s, &u);
653 if (u <= 0 || u >= USEC_INFINITY) {
658 p = getenv("WATCHDOG_PID");
662 r = parse_pid(p, &pid);
666 /* Is this for us? */
667 if (getpid_cached() != pid) {
679 if (unset_environment && s)
680 unsetenv("WATCHDOG_USEC");
681 if (unset_environment && p)
682 unsetenv("WATCHDOG_PID");