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 "sd-daemon.h"
38 #include "alloc-util.h"
40 //#include "fs-util.h"
41 #include "parse-util.h"
42 #include "path-util.h"
43 #include "socket-util.h"
47 #define SNDBUF_SIZE (8*1024*1024)
49 /// UNNEEDED by elogind
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() != 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 (errno == ENOENT || errno == 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 (errno == ENOENT || errno == 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;
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 /// UNNEEDED by elogind
289 _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
290 union sockaddr_union sockaddr = {};
291 socklen_t l = sizeof(sockaddr);
294 assert_return(fd >= 0, -EBADF);
295 assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
297 r = sd_is_socket_internal(fd, type, listening);
301 if (getsockname(fd, &sockaddr.sa, &l) < 0)
304 if (l < sizeof(sa_family_t))
307 if (sockaddr.sa.sa_family != AF_INET &&
308 sockaddr.sa.sa_family != AF_INET6)
312 if (sockaddr.sa.sa_family != family)
316 if (sockaddr.sa.sa_family == AF_INET) {
317 if (l < sizeof(struct sockaddr_in))
320 return htons(port) == sockaddr.in.sin_port;
322 if (l < sizeof(struct sockaddr_in6))
325 return htons(port) == sockaddr.in6.sin6_port;
332 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
333 union sockaddr_union sockaddr = {};
334 socklen_t l = sizeof(sockaddr);
337 assert_return(fd >= 0, -EBADF);
339 r = sd_is_socket_internal(fd, type, listening);
343 if (getsockname(fd, &sockaddr.sa, &l) < 0)
346 if (l < sizeof(sa_family_t))
349 if (sockaddr.sa.sa_family != AF_UNIX)
354 length = strlen(path);
358 return l == offsetof(struct sockaddr_un, sun_path);
361 /* Normal path socket */
363 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
364 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
366 /* Abstract namespace socket */
368 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
369 memcmp(path, sockaddr.un.sun_path, length) == 0;
375 _public_ int sd_is_mq(int fd, const char *path) {
378 /* Check that the fd is valid */
379 assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
381 if (mq_getattr(fd, &attr) < 0) {
383 /* A non-mq fd (or an invalid one, but we ruled that out above) */
389 char fpath[PATH_MAX];
392 assert_return(path_is_absolute(path), -EINVAL);
394 if (fstat(fd, &a) < 0)
397 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
398 fpath[sizeof(fpath)-1] = 0;
400 if (stat(fpath, &b) < 0)
403 if (a.st_dev != b.st_dev ||
404 a.st_ino != b.st_ino)
412 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
413 union sockaddr_union sockaddr = {
414 .sa.sa_family = AF_UNIX,
416 struct iovec iovec = {
417 .iov_base = (char*) state,
419 struct msghdr msghdr = {
422 .msg_name = &sockaddr,
424 _cleanup_close_ int fd = -1;
425 struct cmsghdr *cmsg = NULL;
435 if (n_fds > 0 && !fds) {
440 e = getenv("NOTIFY_SOCKET");
444 /* Must be an abstract socket, or an absolute path */
445 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
450 if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
455 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
461 fd_inc_sndbuf(fd, SNDBUF_SIZE);
463 iovec.iov_len = strlen(state);
465 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
466 if (sockaddr.un.sun_path[0] == '@')
467 sockaddr.un.sun_path[0] = 0;
469 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
470 if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
471 msghdr.msg_namelen = sizeof(struct sockaddr_un);
473 have_pid = pid != 0 && pid != getpid();
475 if (n_fds > 0 || have_pid) {
476 /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
477 msghdr.msg_controllen =
478 (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
479 (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
481 msghdr.msg_control = alloca0(msghdr.msg_controllen);
483 cmsg = CMSG_FIRSTHDR(&msghdr);
485 cmsg->cmsg_level = SOL_SOCKET;
486 cmsg->cmsg_type = SCM_RIGHTS;
487 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
489 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
492 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
498 cmsg->cmsg_level = SOL_SOCKET;
499 cmsg->cmsg_type = SCM_CREDENTIALS;
500 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
502 ucred = (struct ucred*) CMSG_DATA(cmsg);
504 ucred->uid = getuid();
505 ucred->gid = getgid();
509 /* First try with fake ucred data, as requested */
510 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
515 /* If that failed, try with our own ucred instead */
517 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
518 if (msghdr.msg_controllen == 0)
519 msghdr.msg_control = NULL;
521 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
530 if (unset_environment)
531 unsetenv("NOTIFY_SOCKET");
536 /// UNNEEDED by elogind
538 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
539 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
543 _public_ int sd_notify(int unset_environment, const char *state) {
544 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
547 /// UNNEEDED by elogind
549 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
550 _cleanup_free_ char *p = NULL;
556 va_start(ap, format);
557 r = vasprintf(&p, format, ap);
564 return sd_pid_notify(pid, unset_environment, p);
567 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
568 _cleanup_free_ char *p = NULL;
574 va_start(ap, format);
575 r = vasprintf(&p, format, ap);
582 return sd_pid_notify(0, unset_environment, p);
585 _public_ int sd_booted(void) {
586 /* We test whether the runtime unit file directory has been
587 * created. This takes place in mount-setup.c, so is
588 * guaranteed to happen very early during boot. */
590 return laccess("/run/systemd/system/", F_OK) >= 0;
594 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
595 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
599 s = getenv("WATCHDOG_USEC");
603 r = safe_atou64(s, &u);
606 if (u <= 0 || u >= USEC_INFINITY) {
611 p = getenv("WATCHDOG_PID");
615 r = parse_pid(p, &pid);
619 /* Is this for us? */
620 if (getpid() != pid) {
632 if (unset_environment && s)
633 unsetenv("WATCHDOG_USEC");
634 if (unset_environment && p)
635 unsetenv("WATCHDOG_PID");