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)
312 if (sockaddr.sa.sa_family == AF_INET) {
313 if (l < sizeof(struct sockaddr_in))
316 return htobe16(port) == sockaddr.in.sin_port;
318 if (l < sizeof(struct sockaddr_in6))
321 return htobe16(port) == sockaddr.in6.sin6_port;
328 _public_ int sd_is_socket_sockaddr(int fd, int type, const struct sockaddr* addr, unsigned addr_len, int listening) {
329 union sockaddr_union sockaddr = {};
330 socklen_t l = sizeof(sockaddr);
333 assert_return(fd >= 0, -EBADF);
334 assert_return(addr, -EINVAL);
335 assert_return(addr_len >= sizeof(sa_family_t), -ENOBUFS);
336 assert_return(IN_SET(addr->sa_family, AF_INET, AF_INET6), -EPFNOSUPPORT);
338 r = sd_is_socket_internal(fd, type, listening);
342 if (getsockname(fd, &sockaddr.sa, &l) < 0)
345 if (l < sizeof(sa_family_t))
348 if (sockaddr.sa.sa_family != addr->sa_family)
351 if (sockaddr.sa.sa_family == AF_INET) {
352 const struct sockaddr_in *in = (const struct sockaddr_in *) addr;
354 if (l < sizeof(struct sockaddr_in) || addr_len < sizeof(struct sockaddr_in))
357 if (in->sin_port != 0 &&
358 sockaddr.in.sin_port != in->sin_port)
361 return sockaddr.in.sin_addr.s_addr == in->sin_addr.s_addr;
364 const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) addr;
366 if (l < sizeof(struct sockaddr_in6) || addr_len < sizeof(struct sockaddr_in6))
369 if (in->sin6_port != 0 &&
370 sockaddr.in6.sin6_port != in->sin6_port)
373 if (in->sin6_flowinfo != 0 &&
374 sockaddr.in6.sin6_flowinfo != in->sin6_flowinfo)
377 if (in->sin6_scope_id != 0 &&
378 sockaddr.in6.sin6_scope_id != in->sin6_scope_id)
381 return memcmp(sockaddr.in6.sin6_addr.s6_addr, in->sin6_addr.s6_addr,
382 sizeof(in->sin6_addr.s6_addr)) == 0;
386 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
387 union sockaddr_union sockaddr = {};
388 socklen_t l = sizeof(sockaddr);
391 assert_return(fd >= 0, -EBADF);
393 r = sd_is_socket_internal(fd, type, listening);
397 if (getsockname(fd, &sockaddr.sa, &l) < 0)
400 if (l < sizeof(sa_family_t))
403 if (sockaddr.sa.sa_family != AF_UNIX)
408 length = strlen(path);
412 return l == offsetof(struct sockaddr_un, sun_path);
415 /* Normal path socket */
417 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
418 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
420 /* Abstract namespace socket */
422 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
423 memcmp(path, sockaddr.un.sun_path, length) == 0;
429 #if 0 /// UNNEEDED by elogind
430 _public_ int sd_is_mq(int fd, const char *path) {
433 /* Check that the fd is valid */
434 assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
436 if (mq_getattr(fd, &attr) < 0) {
438 /* A non-mq fd (or an invalid one, but we ruled that out above) */
444 char fpath[PATH_MAX];
447 assert_return(path_is_absolute(path), -EINVAL);
449 if (fstat(fd, &a) < 0)
452 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
453 fpath[sizeof(fpath)-1] = 0;
455 if (stat(fpath, &b) < 0)
458 if (a.st_dev != b.st_dev ||
459 a.st_ino != b.st_ino)
467 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
468 union sockaddr_union sockaddr = {
469 .sa.sa_family = AF_UNIX,
471 struct iovec iovec = {
472 .iov_base = (char*) state,
474 struct msghdr msghdr = {
477 .msg_name = &sockaddr,
479 _cleanup_close_ int fd = -1;
480 struct cmsghdr *cmsg = NULL;
490 if (n_fds > 0 && !fds) {
495 e = getenv("NOTIFY_SOCKET");
499 /* Must be an abstract socket, or an absolute path */
500 if (!IN_SET(e[0], '@', '/') || e[1] == 0) {
505 if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
510 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
516 fd_inc_sndbuf(fd, SNDBUF_SIZE);
518 iovec.iov_len = strlen(state);
520 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
521 if (sockaddr.un.sun_path[0] == '@')
522 sockaddr.un.sun_path[0] = 0;
524 msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
526 have_pid = pid != 0 && pid != getpid_cached();
528 if (n_fds > 0 || have_pid) {
529 /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
530 msghdr.msg_controllen =
531 (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
532 (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
534 msghdr.msg_control = alloca0(msghdr.msg_controllen);
536 cmsg = CMSG_FIRSTHDR(&msghdr);
538 cmsg->cmsg_level = SOL_SOCKET;
539 cmsg->cmsg_type = SCM_RIGHTS;
540 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
542 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
545 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
551 cmsg->cmsg_level = SOL_SOCKET;
552 cmsg->cmsg_type = SCM_CREDENTIALS;
553 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
555 ucred = (struct ucred*) CMSG_DATA(cmsg);
557 ucred->uid = getuid();
558 ucred->gid = getgid();
562 /* First try with fake ucred data, as requested */
563 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
568 /* If that failed, try with our own ucred instead */
570 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
571 if (msghdr.msg_controllen == 0)
572 msghdr.msg_control = NULL;
574 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
583 if (unset_environment)
584 unsetenv("NOTIFY_SOCKET");
589 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
590 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
593 _public_ int sd_notify(int unset_environment, const char *state) {
594 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
597 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
598 _cleanup_free_ char *p = NULL;
604 va_start(ap, format);
605 r = vasprintf(&p, format, ap);
612 return sd_pid_notify(pid, unset_environment, p);
615 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
616 _cleanup_free_ char *p = NULL;
622 va_start(ap, format);
623 r = vasprintf(&p, format, ap);
630 return sd_pid_notify(0, unset_environment, p);
633 _public_ int sd_booted(void) {
634 /* We test whether the runtime unit file directory has been
635 * created. This takes place in mount-setup.c, so is
636 * guaranteed to happen very early during boot. */
638 #if 0 /// elogind is always used without systemd running the show. (Well, it should...)
639 return laccess("/run/systemd/system/", F_OK) >= 0;
645 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
646 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
650 s = getenv("WATCHDOG_USEC");
654 r = safe_atou64(s, &u);
657 if (u <= 0 || u >= USEC_INFINITY) {
662 p = getenv("WATCHDOG_PID");
666 r = parse_pid(p, &pid);
670 /* Is this for us? */
671 if (getpid_cached() != pid) {
683 if (unset_environment && s)
684 unsetenv("WATCHDOG_USEC");
685 if (unset_environment && p)
686 unsetenv("WATCHDOG_PID");