1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <netinet/in.h>
31 #include <sys/socket.h>
36 #include "path-util.h"
37 #include "socket-util.h"
41 #include "sd-daemon.h"
43 /// UNNEEDED by elogind
45 static void unsetenv_all(bool unset_environment) {
47 if (!unset_environment)
50 unsetenv("LISTEN_PID");
51 unsetenv("LISTEN_FDS");
52 unsetenv("LISTEN_FDNAMES");
55 _public_ int sd_listen_fds(int unset_environment) {
61 e = getenv("LISTEN_PID");
67 r = parse_pid(e, &pid);
72 if (getpid() != pid) {
77 e = getenv("LISTEN_FDS");
87 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) n; fd ++) {
88 r = fd_cloexec(fd, true);
96 unsetenv_all(unset_environment);
100 _public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
101 _cleanup_strv_free_ char **l = NULL;
103 int n_names = 0, n_fds;
108 return sd_listen_fds(unset_environment);
110 e = getenv("LISTEN_FDNAMES");
112 n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
114 unsetenv_all(unset_environment);
122 n_fds = sd_listen_fds(unset_environment);
127 if (n_names != n_fds)
130 r = strv_extend_n(&l, "unknown", n_fds);
141 _public_ int sd_is_fifo(int fd, const char *path) {
144 assert_return(fd >= 0, -EBADF);
146 if (fstat(fd, &st_fd) < 0)
149 if (!S_ISFIFO(st_fd.st_mode))
155 if (stat(path, &st_path) < 0) {
157 if (errno == ENOENT || errno == ENOTDIR)
164 st_path.st_dev == st_fd.st_dev &&
165 st_path.st_ino == st_fd.st_ino;
171 _public_ int sd_is_special(int fd, const char *path) {
174 assert_return(fd >= 0, -EBADF);
176 if (fstat(fd, &st_fd) < 0)
179 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
185 if (stat(path, &st_path) < 0) {
187 if (errno == ENOENT || errno == ENOTDIR)
193 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
195 st_path.st_dev == st_fd.st_dev &&
196 st_path.st_ino == st_fd.st_ino;
197 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
198 return st_path.st_rdev == st_fd.st_rdev;
207 static int sd_is_socket_internal(int fd, int type, int listening) {
210 assert_return(fd >= 0, -EBADF);
211 assert_return(type >= 0, -EINVAL);
213 if (fstat(fd, &st_fd) < 0)
216 if (!S_ISSOCK(st_fd.st_mode))
221 socklen_t l = sizeof(other_type);
223 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
226 if (l != sizeof(other_type))
229 if (other_type != type)
233 if (listening >= 0) {
235 socklen_t l = sizeof(accepting);
237 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
240 if (l != sizeof(accepting))
243 if (!accepting != !listening)
250 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
253 assert_return(fd >= 0, -EBADF);
254 assert_return(family >= 0, -EINVAL);
256 r = sd_is_socket_internal(fd, type, listening);
261 union sockaddr_union sockaddr = {};
262 socklen_t l = sizeof(sockaddr);
264 if (getsockname(fd, &sockaddr.sa, &l) < 0)
267 if (l < sizeof(sa_family_t))
270 return sockaddr.sa.sa_family == family;
276 /// UNNEEDED by elogind
278 _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
279 union sockaddr_union sockaddr = {};
280 socklen_t l = sizeof(sockaddr);
283 assert_return(fd >= 0, -EBADF);
284 assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
286 r = sd_is_socket_internal(fd, type, listening);
290 if (getsockname(fd, &sockaddr.sa, &l) < 0)
293 if (l < sizeof(sa_family_t))
296 if (sockaddr.sa.sa_family != AF_INET &&
297 sockaddr.sa.sa_family != AF_INET6)
301 if (sockaddr.sa.sa_family != family)
305 if (sockaddr.sa.sa_family == AF_INET) {
306 if (l < sizeof(struct sockaddr_in))
309 return htons(port) == sockaddr.in.sin_port;
311 if (l < sizeof(struct sockaddr_in6))
314 return htons(port) == sockaddr.in6.sin6_port;
321 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
322 union sockaddr_union sockaddr = {};
323 socklen_t l = sizeof(sockaddr);
326 assert_return(fd >= 0, -EBADF);
328 r = sd_is_socket_internal(fd, type, listening);
332 if (getsockname(fd, &sockaddr.sa, &l) < 0)
335 if (l < sizeof(sa_family_t))
338 if (sockaddr.sa.sa_family != AF_UNIX)
343 length = strlen(path);
347 return l == offsetof(struct sockaddr_un, sun_path);
350 /* Normal path socket */
352 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
353 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
355 /* Abstract namespace socket */
357 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
358 memcmp(path, sockaddr.un.sun_path, length) == 0;
364 _public_ int sd_is_mq(int fd, const char *path) {
367 /* Check that the fd is valid */
368 assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
370 if (mq_getattr(fd, &attr) < 0) {
372 /* A non-mq fd (or an invalid one, but we ruled that out above) */
378 char fpath[PATH_MAX];
381 assert_return(path_is_absolute(path), -EINVAL);
383 if (fstat(fd, &a) < 0)
386 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
387 fpath[sizeof(fpath)-1] = 0;
389 if (stat(fpath, &b) < 0)
392 if (a.st_dev != b.st_dev ||
393 a.st_ino != b.st_ino)
401 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
402 union sockaddr_union sockaddr = {
403 .sa.sa_family = AF_UNIX,
405 struct iovec iovec = {
406 .iov_base = (char*) state,
408 struct msghdr msghdr = {
411 .msg_name = &sockaddr,
413 _cleanup_close_ int fd = -1;
414 struct cmsghdr *cmsg = NULL;
424 if (n_fds > 0 && !fds) {
429 e = getenv("NOTIFY_SOCKET");
433 /* Must be an abstract socket, or an absolute path */
434 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
439 if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
444 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
450 iovec.iov_len = strlen(state);
452 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
453 if (sockaddr.un.sun_path[0] == '@')
454 sockaddr.un.sun_path[0] = 0;
456 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
457 if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
458 msghdr.msg_namelen = sizeof(struct sockaddr_un);
460 have_pid = pid != 0 && pid != getpid();
462 if (n_fds > 0 || have_pid) {
463 /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
464 msghdr.msg_controllen =
465 (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
466 (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
468 msghdr.msg_control = alloca0(msghdr.msg_controllen);
470 cmsg = CMSG_FIRSTHDR(&msghdr);
472 cmsg->cmsg_level = SOL_SOCKET;
473 cmsg->cmsg_type = SCM_RIGHTS;
474 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
476 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
479 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
485 cmsg->cmsg_level = SOL_SOCKET;
486 cmsg->cmsg_type = SCM_CREDENTIALS;
487 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
489 ucred = (struct ucred*) CMSG_DATA(cmsg);
491 ucred->uid = getuid();
492 ucred->gid = getgid();
496 /* First try with fake ucred data, as requested */
497 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
502 /* If that failed, try with our own ucred instead */
504 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
505 if (msghdr.msg_controllen == 0)
506 msghdr.msg_control = NULL;
508 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
517 if (unset_environment)
518 unsetenv("NOTIFY_SOCKET");
523 /// UNNEEDED by elogind
525 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
526 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
530 _public_ int sd_notify(int unset_environment, const char *state) {
531 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
534 /// UNNEEDED by elogind
536 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
537 _cleanup_free_ char *p = NULL;
543 va_start(ap, format);
544 r = vasprintf(&p, format, ap);
551 return sd_pid_notify(pid, unset_environment, p);
554 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
555 _cleanup_free_ char *p = NULL;
561 va_start(ap, format);
562 r = vasprintf(&p, format, ap);
569 return sd_pid_notify(0, unset_environment, p);
572 _public_ int sd_booted(void) {
573 /* We test whether the runtime unit file directory has been
574 * created. This takes place in mount-setup.c, so is
575 * guaranteed to happen very early during boot. */
577 return laccess("/run/systemd/system/", F_OK) >= 0;
581 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
582 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
586 s = getenv("WATCHDOG_USEC");
590 r = safe_atou64(s, &u);
598 p = getenv("WATCHDOG_PID");
602 r = parse_pid(p, &pid);
606 /* Is this for us? */
607 if (getpid() != pid) {
619 if (unset_environment && s)
620 unsetenv("WATCHDOG_USEC");
621 if (unset_environment && p)
622 unsetenv("WATCHDOG_PID");