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 #if 0 /// UNNEEDED by elogind
50 static void unsetenv_all(bool unset_environment) {
52 if (!unset_environment)
55 unsetenv("LISTEN_PID");
56 unsetenv("LISTEN_FDS");
57 unsetenv("LISTEN_FDNAMES");
60 _public_ int sd_listen_fds(int unset_environment) {
65 e = getenv("LISTEN_PID");
71 r = parse_pid(e, &pid);
76 if (getpid() != pid) {
81 e = getenv("LISTEN_FDS");
91 assert_cc(SD_LISTEN_FDS_START < INT_MAX);
92 if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
97 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
98 r = fd_cloexec(fd, true);
106 unsetenv_all(unset_environment);
110 _public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
111 _cleanup_strv_free_ char **l = NULL;
113 int n_names = 0, n_fds;
118 return sd_listen_fds(unset_environment);
120 e = getenv("LISTEN_FDNAMES");
122 n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
124 unsetenv_all(unset_environment);
132 n_fds = sd_listen_fds(unset_environment);
137 if (n_names != n_fds)
140 r = strv_extend_n(&l, "unknown", n_fds);
151 _public_ int sd_is_fifo(int fd, const char *path) {
154 assert_return(fd >= 0, -EBADF);
156 if (fstat(fd, &st_fd) < 0)
159 if (!S_ISFIFO(st_fd.st_mode))
165 if (stat(path, &st_path) < 0) {
167 if (errno == ENOENT || errno == ENOTDIR)
174 st_path.st_dev == st_fd.st_dev &&
175 st_path.st_ino == st_fd.st_ino;
181 _public_ int sd_is_special(int fd, const char *path) {
184 assert_return(fd >= 0, -EBADF);
186 if (fstat(fd, &st_fd) < 0)
189 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
195 if (stat(path, &st_path) < 0) {
197 if (errno == ENOENT || errno == ENOTDIR)
203 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
205 st_path.st_dev == st_fd.st_dev &&
206 st_path.st_ino == st_fd.st_ino;
207 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
208 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 #if 0 /// UNNEEDED by elogind
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 (sockaddr.sa.sa_family != AF_INET &&
306 sockaddr.sa.sa_family != AF_INET6)
310 if (sockaddr.sa.sa_family != family)
314 if (sockaddr.sa.sa_family == AF_INET) {
315 if (l < sizeof(struct sockaddr_in))
318 return htons(port) == sockaddr.in.sin_port;
320 if (l < sizeof(struct sockaddr_in6))
323 return htons(port) == sockaddr.in6.sin6_port;
330 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
331 union sockaddr_union sockaddr = {};
332 socklen_t l = sizeof(sockaddr);
335 assert_return(fd >= 0, -EBADF);
337 r = sd_is_socket_internal(fd, type, listening);
341 if (getsockname(fd, &sockaddr.sa, &l) < 0)
344 if (l < sizeof(sa_family_t))
347 if (sockaddr.sa.sa_family != AF_UNIX)
352 length = strlen(path);
356 return l == offsetof(struct sockaddr_un, sun_path);
359 /* Normal path socket */
361 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
362 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
364 /* Abstract namespace socket */
366 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
367 memcmp(path, sockaddr.un.sun_path, length) == 0;
373 _public_ int sd_is_mq(int fd, const char *path) {
376 /* Check that the fd is valid */
377 assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
379 if (mq_getattr(fd, &attr) < 0) {
381 /* A non-mq fd (or an invalid one, but we ruled that out above) */
387 char fpath[PATH_MAX];
390 assert_return(path_is_absolute(path), -EINVAL);
392 if (fstat(fd, &a) < 0)
395 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
396 fpath[sizeof(fpath)-1] = 0;
398 if (stat(fpath, &b) < 0)
401 if (a.st_dev != b.st_dev ||
402 a.st_ino != b.st_ino)
410 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
411 union sockaddr_union sockaddr = {
412 .sa.sa_family = AF_UNIX,
414 struct iovec iovec = {
415 .iov_base = (char*) state,
417 struct msghdr msghdr = {
420 .msg_name = &sockaddr,
422 _cleanup_close_ int fd = -1;
423 struct cmsghdr *cmsg = NULL;
433 if (n_fds > 0 && !fds) {
438 e = getenv("NOTIFY_SOCKET");
442 /* Must be an abstract socket, or an absolute path */
443 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
448 if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
453 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
459 fd_inc_sndbuf(fd, SNDBUF_SIZE);
461 iovec.iov_len = strlen(state);
463 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
464 if (sockaddr.un.sun_path[0] == '@')
465 sockaddr.un.sun_path[0] = 0;
467 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
468 if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
469 msghdr.msg_namelen = sizeof(struct sockaddr_un);
471 have_pid = pid != 0 && pid != getpid();
473 if (n_fds > 0 || have_pid) {
474 /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
475 msghdr.msg_controllen =
476 (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
477 (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
479 msghdr.msg_control = alloca0(msghdr.msg_controllen);
481 cmsg = CMSG_FIRSTHDR(&msghdr);
483 cmsg->cmsg_level = SOL_SOCKET;
484 cmsg->cmsg_type = SCM_RIGHTS;
485 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
487 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
490 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
496 cmsg->cmsg_level = SOL_SOCKET;
497 cmsg->cmsg_type = SCM_CREDENTIALS;
498 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
500 ucred = (struct ucred*) CMSG_DATA(cmsg);
502 ucred->uid = getuid();
503 ucred->gid = getgid();
507 /* First try with fake ucred data, as requested */
508 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
513 /* If that failed, try with our own ucred instead */
515 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
516 if (msghdr.msg_controllen == 0)
517 msghdr.msg_control = NULL;
519 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
528 if (unset_environment)
529 unsetenv("NOTIFY_SOCKET");
534 #if 0 /// UNNEEDED by elogind
535 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
536 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
540 _public_ int sd_notify(int unset_environment, const char *state) {
541 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
544 #if 0 /// UNNEEDED by elogind
545 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
546 _cleanup_free_ char *p = NULL;
552 va_start(ap, format);
553 r = vasprintf(&p, format, ap);
560 return sd_pid_notify(pid, unset_environment, p);
563 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
564 _cleanup_free_ char *p = NULL;
570 va_start(ap, format);
571 r = vasprintf(&p, format, ap);
578 return sd_pid_notify(0, unset_environment, p);
581 _public_ int sd_booted(void) {
582 /* We test whether the runtime unit file directory has been
583 * created. This takes place in mount-setup.c, so is
584 * guaranteed to happen very early during boot. */
586 return laccess("/run/systemd/system/", F_OK) >= 0;
590 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
591 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
595 s = getenv("WATCHDOG_USEC");
599 r = safe_atou64(s, &u);
602 if (u <= 0 || u >= USEC_INFINITY) {
607 p = getenv("WATCHDOG_PID");
611 r = parse_pid(p, &pid);
615 /* Is this for us? */
616 if (getpid() != pid) {
628 if (unset_environment && s)
629 unsetenv("WATCHDOG_USEC");
630 if (unset_environment && p)
631 unsetenv("WATCHDOG_PID");