LCOV - code coverage report
Current view: top level - libsystemd/sd-daemon - sd-daemon.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 45 285 15.8 %
Date: 2015-07-29 18:47:03 Functions: 5 15 33.3 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2010 Lennart Poettering
       7             : 
       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.
      12             : 
      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.
      17             : 
      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/>.
      20             : ***/
      21             : 
      22             : #include <sys/stat.h>
      23             : #include <sys/socket.h>
      24             : #include <sys/un.h>
      25             : #include <netinet/in.h>
      26             : #include <stdlib.h>
      27             : #include <errno.h>
      28             : #include <unistd.h>
      29             : #include <string.h>
      30             : #include <stdarg.h>
      31             : #include <stdio.h>
      32             : #include <stddef.h>
      33             : #include <limits.h>
      34             : #include <mqueue.h>
      35             : 
      36             : #include "util.h"
      37             : #include "path-util.h"
      38             : #include "socket-util.h"
      39             : #include "sd-daemon.h"
      40             : 
      41           1 : _public_ int sd_listen_fds(int unset_environment) {
      42             :         const char *e;
      43             :         unsigned n;
      44             :         int r, fd;
      45             :         pid_t pid;
      46             : 
      47           1 :         e = getenv("LISTEN_PID");
      48           1 :         if (!e) {
      49           1 :                 r = 0;
      50           1 :                 goto finish;
      51             :         }
      52             : 
      53           0 :         r = parse_pid(e, &pid);
      54           0 :         if (r < 0)
      55           0 :                 goto finish;
      56             : 
      57             :         /* Is this for us? */
      58           0 :         if (getpid() != pid) {
      59           0 :                 r = 0;
      60           0 :                 goto finish;
      61             :         }
      62             : 
      63           0 :         e = getenv("LISTEN_FDS");
      64           0 :         if (!e) {
      65           0 :                 r = 0;
      66           0 :                 goto finish;
      67             :         }
      68             : 
      69           0 :         r = safe_atou(e, &n);
      70           0 :         if (r < 0)
      71           0 :                 goto finish;
      72             : 
      73           0 :         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) n; fd ++) {
      74           0 :                 r = fd_cloexec(fd, true);
      75           0 :                 if (r < 0)
      76           0 :                         goto finish;
      77             :         }
      78             : 
      79           0 :         r = (int) n;
      80             : 
      81             : finish:
      82           1 :         if (unset_environment) {
      83           1 :                 unsetenv("LISTEN_PID");
      84           1 :                 unsetenv("LISTEN_FDS");
      85             :         }
      86             : 
      87           1 :         return r;
      88             : }
      89             : 
      90           0 : _public_ int sd_is_fifo(int fd, const char *path) {
      91             :         struct stat st_fd;
      92             : 
      93           0 :         assert_return(fd >= 0, -EINVAL);
      94             : 
      95           0 :         if (fstat(fd, &st_fd) < 0)
      96           0 :                 return -errno;
      97             : 
      98           0 :         if (!S_ISFIFO(st_fd.st_mode))
      99           0 :                 return 0;
     100             : 
     101           0 :         if (path) {
     102             :                 struct stat st_path;
     103             : 
     104           0 :                 if (stat(path, &st_path) < 0) {
     105             : 
     106           0 :                         if (errno == ENOENT || errno == ENOTDIR)
     107           0 :                                 return 0;
     108             : 
     109           0 :                         return -errno;
     110             :                 }
     111             : 
     112             :                 return
     113           0 :                         st_path.st_dev == st_fd.st_dev &&
     114           0 :                         st_path.st_ino == st_fd.st_ino;
     115             :         }
     116             : 
     117           0 :         return 1;
     118             : }
     119             : 
     120           0 : _public_ int sd_is_special(int fd, const char *path) {
     121             :         struct stat st_fd;
     122             : 
     123           0 :         assert_return(fd >= 0, -EINVAL);
     124             : 
     125           0 :         if (fstat(fd, &st_fd) < 0)
     126           0 :                 return -errno;
     127             : 
     128           0 :         if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
     129           0 :                 return 0;
     130             : 
     131           0 :         if (path) {
     132             :                 struct stat st_path;
     133             : 
     134           0 :                 if (stat(path, &st_path) < 0) {
     135             : 
     136           0 :                         if (errno == ENOENT || errno == ENOTDIR)
     137           0 :                                 return 0;
     138             : 
     139           0 :                         return -errno;
     140             :                 }
     141             : 
     142           0 :                 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
     143             :                         return
     144           0 :                                 st_path.st_dev == st_fd.st_dev &&
     145           0 :                                 st_path.st_ino == st_fd.st_ino;
     146           0 :                 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
     147           0 :                         return st_path.st_rdev == st_fd.st_rdev;
     148             :                 else
     149           0 :                         return 0;
     150             :         }
     151             : 
     152           0 :         return 1;
     153             : }
     154             : 
     155          17 : static int sd_is_socket_internal(int fd, int type, int listening) {
     156             :         struct stat st_fd;
     157             : 
     158          17 :         assert_return(fd >= 0, -EINVAL);
     159          17 :         assert_return(type >= 0, -EINVAL);
     160             : 
     161          17 :         if (fstat(fd, &st_fd) < 0)
     162           0 :                 return -errno;
     163             : 
     164          17 :         if (!S_ISSOCK(st_fd.st_mode))
     165           0 :                 return 0;
     166             : 
     167          17 :         if (type != 0) {
     168           0 :                 int other_type = 0;
     169           0 :                 socklen_t l = sizeof(other_type);
     170             : 
     171           0 :                 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
     172           0 :                         return -errno;
     173             : 
     174           0 :                 if (l != sizeof(other_type))
     175           0 :                         return -EINVAL;
     176             : 
     177           0 :                 if (other_type != type)
     178           0 :                         return 0;
     179             :         }
     180             : 
     181          17 :         if (listening >= 0) {
     182          17 :                 int accepting = 0;
     183          17 :                 socklen_t l = sizeof(accepting);
     184             : 
     185          17 :                 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
     186           0 :                         return -errno;
     187             : 
     188          17 :                 if (l != sizeof(accepting))
     189           0 :                         return -EINVAL;
     190             : 
     191          17 :                 if (!accepting != !listening)
     192           0 :                         return 0;
     193             :         }
     194             : 
     195          17 :         return 1;
     196             : }
     197             : 
     198          17 : _public_ int sd_is_socket(int fd, int family, int type, int listening) {
     199             :         int r;
     200             : 
     201          17 :         assert_return(fd >= 0, -EINVAL);
     202          17 :         assert_return(family >= 0, -EINVAL);
     203             : 
     204          17 :         r = sd_is_socket_internal(fd, type, listening);
     205          17 :         if (r <= 0)
     206           0 :                 return r;
     207             : 
     208          17 :         if (family > 0) {
     209          17 :                 union sockaddr_union sockaddr = {};
     210          17 :                 socklen_t l = sizeof(sockaddr);
     211             : 
     212          17 :                 if (getsockname(fd, &sockaddr.sa, &l) < 0)
     213           0 :                         return -errno;
     214             : 
     215          17 :                 if (l < sizeof(sa_family_t))
     216           0 :                         return -EINVAL;
     217             : 
     218          17 :                 return sockaddr.sa.sa_family == family;
     219             :         }
     220             : 
     221           0 :         return 1;
     222             : }
     223             : 
     224           0 : _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
     225           0 :         union sockaddr_union sockaddr = {};
     226           0 :         socklen_t l = sizeof(sockaddr);
     227             :         int r;
     228             : 
     229           0 :         assert_return(fd >= 0, -EINVAL);
     230           0 :         assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
     231             : 
     232           0 :         r = sd_is_socket_internal(fd, type, listening);
     233           0 :         if (r <= 0)
     234           0 :                 return r;
     235             : 
     236           0 :         if (getsockname(fd, &sockaddr.sa, &l) < 0)
     237           0 :                 return -errno;
     238             : 
     239           0 :         if (l < sizeof(sa_family_t))
     240           0 :                 return -EINVAL;
     241             : 
     242           0 :         if (sockaddr.sa.sa_family != AF_INET &&
     243           0 :             sockaddr.sa.sa_family != AF_INET6)
     244           0 :                 return 0;
     245             : 
     246           0 :         if (family != 0)
     247           0 :                 if (sockaddr.sa.sa_family != family)
     248           0 :                         return 0;
     249             : 
     250           0 :         if (port > 0) {
     251           0 :                 if (sockaddr.sa.sa_family == AF_INET) {
     252           0 :                         if (l < sizeof(struct sockaddr_in))
     253           0 :                                 return -EINVAL;
     254             : 
     255           0 :                         return htons(port) == sockaddr.in.sin_port;
     256             :                 } else {
     257           0 :                         if (l < sizeof(struct sockaddr_in6))
     258           0 :                                 return -EINVAL;
     259             : 
     260           0 :                         return htons(port) == sockaddr.in6.sin6_port;
     261             :                 }
     262             :         }
     263             : 
     264           0 :         return 1;
     265             : }
     266             : 
     267           0 : _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
     268           0 :         union sockaddr_union sockaddr = {};
     269           0 :         socklen_t l = sizeof(sockaddr);
     270             :         int r;
     271             : 
     272           0 :         assert_return(fd >= 0, -EINVAL);
     273             : 
     274           0 :         r = sd_is_socket_internal(fd, type, listening);
     275           0 :         if (r <= 0)
     276           0 :                 return r;
     277             : 
     278           0 :         if (getsockname(fd, &sockaddr.sa, &l) < 0)
     279           0 :                 return -errno;
     280             : 
     281           0 :         if (l < sizeof(sa_family_t))
     282           0 :                 return -EINVAL;
     283             : 
     284           0 :         if (sockaddr.sa.sa_family != AF_UNIX)
     285           0 :                 return 0;
     286             : 
     287           0 :         if (path) {
     288           0 :                 if (length == 0)
     289           0 :                         length = strlen(path);
     290             : 
     291           0 :                 if (length == 0)
     292             :                         /* Unnamed socket */
     293           0 :                         return l == offsetof(struct sockaddr_un, sun_path);
     294             : 
     295           0 :                 if (path[0])
     296             :                         /* Normal path socket */
     297             :                         return
     298           0 :                                 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
     299           0 :                                 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
     300             :                 else
     301             :                         /* Abstract namespace socket */
     302             :                         return
     303           0 :                                 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
     304           0 :                                 memcmp(path, sockaddr.un.sun_path, length) == 0;
     305             :         }
     306             : 
     307           0 :         return 1;
     308             : }
     309             : 
     310           0 : _public_ int sd_is_mq(int fd, const char *path) {
     311             :         struct mq_attr attr;
     312             : 
     313           0 :         assert_return(fd >= 0, -EINVAL);
     314             : 
     315           0 :         if (mq_getattr(fd, &attr) < 0)
     316           0 :                 return -errno;
     317             : 
     318           0 :         if (path) {
     319             :                 char fpath[PATH_MAX];
     320             :                 struct stat a, b;
     321             : 
     322           0 :                 assert_return(path_is_absolute(path), -EINVAL);
     323             : 
     324           0 :                 if (fstat(fd, &a) < 0)
     325           0 :                         return -errno;
     326             : 
     327           0 :                 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
     328           0 :                 fpath[sizeof(fpath)-1] = 0;
     329             : 
     330           0 :                 if (stat(fpath, &b) < 0)
     331           0 :                         return -errno;
     332             : 
     333           0 :                 if (a.st_dev != b.st_dev ||
     334           0 :                     a.st_ino != b.st_ino)
     335           0 :                         return 0;
     336             :         }
     337             : 
     338           0 :         return 1;
     339             : }
     340             : 
     341           0 : _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
     342           0 :         union sockaddr_union sockaddr = {
     343             :                 .sa.sa_family = AF_UNIX,
     344             :         };
     345           0 :         struct iovec iovec = {
     346             :                 .iov_base = (char*) state,
     347             :         };
     348           0 :         struct msghdr msghdr = {
     349             :                 .msg_iov = &iovec,
     350             :                 .msg_iovlen = 1,
     351             :                 .msg_name = &sockaddr,
     352             :         };
     353           0 :         _cleanup_close_ int fd = -1;
     354           0 :         struct cmsghdr *cmsg = NULL;
     355             :         const char *e;
     356             :         bool have_pid;
     357             :         int r;
     358             : 
     359           0 :         if (!state) {
     360           0 :                 r = -EINVAL;
     361           0 :                 goto finish;
     362             :         }
     363             : 
     364           0 :         if (n_fds > 0 && !fds) {
     365           0 :                 r = -EINVAL;
     366           0 :                 goto finish;
     367             :         }
     368             : 
     369           0 :         e = getenv("NOTIFY_SOCKET");
     370           0 :         if (!e)
     371           0 :                 return 0;
     372             : 
     373             :         /* Must be an abstract socket, or an absolute path */
     374           0 :         if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
     375           0 :                 r = -EINVAL;
     376           0 :                 goto finish;
     377             :         }
     378             : 
     379           0 :         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
     380           0 :         if (fd < 0) {
     381           0 :                 r = -errno;
     382           0 :                 goto finish;
     383             :         }
     384             : 
     385           0 :         iovec.iov_len = strlen(state);
     386             : 
     387           0 :         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
     388           0 :         if (sockaddr.un.sun_path[0] == '@')
     389           0 :                 sockaddr.un.sun_path[0] = 0;
     390             : 
     391           0 :         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
     392           0 :         if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
     393           0 :                 msghdr.msg_namelen = sizeof(struct sockaddr_un);
     394             : 
     395           0 :         have_pid = pid != 0 && pid != getpid();
     396             : 
     397           0 :         if (n_fds > 0 || have_pid) {
     398           0 :                 msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds) +
     399           0 :                                         CMSG_SPACE(sizeof(struct ucred) * have_pid);
     400           0 :                 msghdr.msg_control = alloca(msghdr.msg_controllen);
     401             : 
     402           0 :                 cmsg = CMSG_FIRSTHDR(&msghdr);
     403           0 :                 if (n_fds > 0) {
     404           0 :                         cmsg->cmsg_level = SOL_SOCKET;
     405           0 :                         cmsg->cmsg_type = SCM_RIGHTS;
     406           0 :                         cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
     407             : 
     408           0 :                         memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
     409             : 
     410           0 :                         if (have_pid)
     411           0 :                                 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
     412             :                 }
     413             : 
     414           0 :                 if (have_pid) {
     415             :                         struct ucred *ucred;
     416             : 
     417           0 :                         cmsg->cmsg_level = SOL_SOCKET;
     418           0 :                         cmsg->cmsg_type = SCM_CREDENTIALS;
     419           0 :                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
     420             : 
     421           0 :                         ucred = (struct ucred*) CMSG_DATA(cmsg);
     422           0 :                         ucred->pid = pid;
     423           0 :                         ucred->uid = getuid();
     424           0 :                         ucred->gid = getgid();
     425             :                 }
     426             :         }
     427             : 
     428             :         /* First try with fake ucred data, as requested */
     429           0 :         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
     430           0 :                 r = 1;
     431           0 :                 goto finish;
     432             :         }
     433             : 
     434             :         /* If that failed, try with our own ucred instead */
     435           0 :         if (have_pid) {
     436           0 :                 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
     437           0 :                 if (msghdr.msg_controllen == 0)
     438           0 :                         msghdr.msg_control = NULL;
     439             : 
     440           0 :                 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
     441           0 :                         r = 1;
     442           0 :                         goto finish;
     443             :                 }
     444             :         }
     445             : 
     446           0 :         r = -errno;
     447             : 
     448             : finish:
     449           0 :         if (unset_environment)
     450           0 :                 unsetenv("NOTIFY_SOCKET");
     451             : 
     452           0 :         return r;
     453             : }
     454             : 
     455           0 : _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
     456           0 :         return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
     457             : }
     458             : 
     459           0 : _public_ int sd_notify(int unset_environment, const char *state) {
     460           0 :         return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
     461             : }
     462             : 
     463           0 : _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
     464           0 :         _cleanup_free_ char *p = NULL;
     465             :         int r;
     466             : 
     467           0 :         if (format) {
     468             :                 va_list ap;
     469             : 
     470           0 :                 va_start(ap, format);
     471           0 :                 r = vasprintf(&p, format, ap);
     472           0 :                 va_end(ap);
     473             : 
     474           0 :                 if (r < 0 || !p)
     475           0 :                         return -ENOMEM;
     476             :         }
     477             : 
     478           0 :         return sd_pid_notify(pid, unset_environment, p);
     479             : }
     480             : 
     481           0 : _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
     482           0 :         _cleanup_free_ char *p = NULL;
     483             :         int r;
     484             : 
     485           0 :         if (format) {
     486             :                 va_list ap;
     487             : 
     488           0 :                 va_start(ap, format);
     489           0 :                 r = vasprintf(&p, format, ap);
     490           0 :                 va_end(ap);
     491             : 
     492           0 :                 if (r < 0 || !p)
     493           0 :                         return -ENOMEM;
     494             :         }
     495             : 
     496           0 :         return sd_pid_notify(0, unset_environment, p);
     497             : }
     498             : 
     499           6 : _public_ int sd_booted(void) {
     500             :         struct stat st;
     501             : 
     502             :         /* We test whether the runtime unit file directory has been
     503             :          * created. This takes place in mount-setup.c, so is
     504             :          * guaranteed to happen very early during boot. */
     505             : 
     506           6 :         if (lstat("/run/systemd/system/", &st) < 0)
     507           0 :                 return 0;
     508             : 
     509           6 :         return !!S_ISDIR(st.st_mode);
     510             : }
     511             : 
     512           2 : _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
     513           2 :         const char *s, *p = ""; /* p is set to dummy value to do unsetting */
     514             :         uint64_t u;
     515           2 :         int r = 0;
     516             : 
     517           2 :         s = getenv("WATCHDOG_USEC");
     518           2 :         if (!s)
     519           2 :                 goto finish;
     520             : 
     521           0 :         r = safe_atou64(s, &u);
     522           0 :         if (r < 0)
     523           0 :                 goto finish;
     524           0 :         if (u <= 0) {
     525           0 :                 r = -EINVAL;
     526           0 :                 goto finish;
     527             :         }
     528             : 
     529           0 :         p = getenv("WATCHDOG_PID");
     530           0 :         if (p) {
     531             :                 pid_t pid;
     532             : 
     533           0 :                 r = parse_pid(p, &pid);
     534           0 :                 if (r < 0)
     535           0 :                         goto finish;
     536             : 
     537             :                 /* Is this for us? */
     538           0 :                 if (getpid() != pid) {
     539           0 :                         r = 0;
     540           0 :                         goto finish;
     541             :                 }
     542             :         }
     543             : 
     544           0 :         if (usec)
     545           0 :                 *usec = u;
     546             : 
     547           0 :         r = 1;
     548             : 
     549             : finish:
     550           2 :         if (unset_environment && s)
     551           0 :                 unsetenv("WATCHDOG_USEC");
     552           2 :         if (unset_environment && p)
     553           0 :                 unsetenv("WATCHDOG_PID");
     554             : 
     555           2 :         return r;
     556             : }

Generated by: LCOV version 1.11