D-Bus  1.8.20
sd-daemon.c
00001 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
00002 
00003 /***
00004   Copyright 2010 Lennart Poettering
00005 
00006   Permission is hereby granted, free of charge, to any person
00007   obtaining a copy of this software and associated documentation files
00008   (the "Software"), to deal in the Software without restriction,
00009   including without limitation the rights to use, copy, modify, merge,
00010   publish, distribute, sublicense, and/or sell copies of the Software,
00011   and to permit persons to whom the Software is furnished to do so,
00012   subject to the following conditions:
00013 
00014   The above copyright notice and this permission notice shall be
00015   included in all copies or substantial portions of the Software.
00016 
00017   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00018   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00019   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00020   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
00021   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
00022   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00023   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00024   SOFTWARE.
00025 ***/
00026 
00027 #define __EXTENSIONS__
00028 
00029 #ifndef _GNU_SOURCE
00030 #  define _GNU_SOURCE
00031 #endif
00032 
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <sys/socket.h>
00036 #include <sys/un.h>
00037 #include <fcntl.h>
00038 #include <netinet/in.h>
00039 #include <stdlib.h>
00040 #include <errno.h>
00041 #include <unistd.h>
00042 #include <string.h>
00043 #include <stdarg.h>
00044 #include <stdio.h>
00045 #include <stddef.h>
00046 #include <limits.h>
00047 
00048 #if defined(__linux__) && !defined(SD_DAEMON_DISABLE_MQ)
00049 #  include <mqueue.h>
00050 #endif
00051 
00052 #include "sd-daemon.h"
00053 
00054 #if (__GNUC__ >= 4)
00055 #  ifdef SD_EXPORT_SYMBOLS
00056 /* Export symbols */
00057 #    define _sd_export_ __attribute__ ((visibility("default")))
00058 #  else
00059 /* Don't export the symbols */
00060 #    define _sd_export_ __attribute__ ((visibility("hidden")))
00061 #  endif
00062 #else
00063 #  define _sd_export_
00064 #endif
00065 
00066 _sd_export_ int sd_listen_fds(int unset_environment) {
00067 
00068 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
00069         return 0;
00070 #else
00071         int r, fd;
00072         const char *e;
00073         char *p = NULL;
00074         unsigned long l;
00075 
00076         e = getenv("LISTEN_PID");
00077         if (!e) {
00078                 r = 0;
00079                 goto finish;
00080         }
00081 
00082         errno = 0;
00083         l = strtoul(e, &p, 10);
00084 
00085         if (errno > 0) {
00086                 r = -errno;
00087                 goto finish;
00088         }
00089 
00090         if (!p || p == e || *p || l <= 0) {
00091                 r = -EINVAL;
00092                 goto finish;
00093         }
00094 
00095         /* Is this for us? */
00096         if (getpid() != (pid_t) l) {
00097                 r = 0;
00098                 goto finish;
00099         }
00100 
00101         e = getenv("LISTEN_FDS");
00102         if (!e) {
00103                 r = 0;
00104                 goto finish;
00105         }
00106 
00107         errno = 0;
00108         l = strtoul(e, &p, 10);
00109 
00110         if (errno > 0) {
00111                 r = -errno;
00112                 goto finish;
00113         }
00114 
00115         if (!p || p == e || *p) {
00116                 r = -EINVAL;
00117                 goto finish;
00118         }
00119 
00120         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
00121                 int flags;
00122 
00123                 flags = fcntl(fd, F_GETFD);
00124                 if (flags < 0) {
00125                         r = -errno;
00126                         goto finish;
00127                 }
00128 
00129                 if (flags & FD_CLOEXEC)
00130                         continue;
00131 
00132                 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
00133                         r = -errno;
00134                         goto finish;
00135                 }
00136         }
00137 
00138         r = (int) l;
00139 
00140 finish:
00141         if (unset_environment) {
00142                 unsetenv("LISTEN_PID");
00143                 unsetenv("LISTEN_FDS");
00144         }
00145 
00146         return r;
00147 #endif
00148 }
00149 
00150 _sd_export_ int sd_is_fifo(int fd, const char *path) {
00151         struct stat st_fd;
00152 
00153         if (fd < 0)
00154                 return -EINVAL;
00155 
00156         if (fstat(fd, &st_fd) < 0)
00157                 return -errno;
00158 
00159         if (!S_ISFIFO(st_fd.st_mode))
00160                 return 0;
00161 
00162         if (path) {
00163                 struct stat st_path;
00164 
00165                 if (stat(path, &st_path) < 0) {
00166 
00167                         if (errno == ENOENT || errno == ENOTDIR)
00168                                 return 0;
00169 
00170                         return -errno;
00171                 }
00172 
00173                 return
00174                         st_path.st_dev == st_fd.st_dev &&
00175                         st_path.st_ino == st_fd.st_ino;
00176         }
00177 
00178         return 1;
00179 }
00180 
00181 _sd_export_ int sd_is_special(int fd, const char *path) {
00182         struct stat st_fd;
00183 
00184         if (fd < 0)
00185                 return -EINVAL;
00186 
00187         if (fstat(fd, &st_fd) < 0)
00188                 return -errno;
00189 
00190         if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
00191                 return 0;
00192 
00193         if (path) {
00194                 struct stat st_path;
00195 
00196                 if (stat(path, &st_path) < 0) {
00197 
00198                         if (errno == ENOENT || errno == ENOTDIR)
00199                                 return 0;
00200 
00201                         return -errno;
00202                 }
00203 
00204                 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
00205                         return
00206                                 st_path.st_dev == st_fd.st_dev &&
00207                                 st_path.st_ino == st_fd.st_ino;
00208                 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
00209                         return st_path.st_rdev == st_fd.st_rdev;
00210                 else
00211                         return 0;
00212         }
00213 
00214         return 1;
00215 }
00216 
00217 static int sd_is_socket_internal(int fd, int type, int listening) {
00218         struct stat st_fd;
00219 
00220         if (fd < 0 || type < 0)
00221                 return -EINVAL;
00222 
00223         if (fstat(fd, &st_fd) < 0)
00224                 return -errno;
00225 
00226         if (!S_ISSOCK(st_fd.st_mode))
00227                 return 0;
00228 
00229         if (type != 0) {
00230                 int other_type = 0;
00231                 socklen_t l = sizeof(other_type);
00232 
00233                 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
00234                         return -errno;
00235 
00236                 if (l != sizeof(other_type))
00237                         return -EINVAL;
00238 
00239                 if (other_type != type)
00240                         return 0;
00241         }
00242 
00243         if (listening >= 0) {
00244                 int accepting = 0;
00245                 socklen_t l = sizeof(accepting);
00246 
00247                 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
00248                         return -errno;
00249 
00250                 if (l != sizeof(accepting))
00251                         return -EINVAL;
00252 
00253                 if (!accepting != !listening)
00254                         return 0;
00255         }
00256 
00257         return 1;
00258 }
00259 
00260 union sockaddr_union {
00261         struct sockaddr sa;
00262         struct sockaddr_in in4;
00263         struct sockaddr_in6 in6;
00264         struct sockaddr_un un;
00265         struct sockaddr_storage storage;
00266 };
00267 
00268 _sd_export_ int sd_is_socket(int fd, int family, int type, int listening) {
00269         int r;
00270 
00271         if (family < 0)
00272                 return -EINVAL;
00273 
00274         r = sd_is_socket_internal(fd, type, listening);
00275         if (r <= 0)
00276                 return r;
00277 
00278         if (family > 0) {
00279                 union sockaddr_union sockaddr = {};
00280                 socklen_t l = sizeof(sockaddr);
00281 
00282                 if (getsockname(fd, &sockaddr.sa, &l) < 0)
00283                         return -errno;
00284 
00285                 if (l < sizeof(sa_family_t))
00286                         return -EINVAL;
00287 
00288                 return sockaddr.sa.sa_family == family;
00289         }
00290 
00291         return 1;
00292 }
00293 
00294 _sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
00295         union sockaddr_union sockaddr = {};
00296         socklen_t l = sizeof(sockaddr);
00297         int r;
00298 
00299         if (family != 0 && family != AF_INET && family != AF_INET6)
00300                 return -EINVAL;
00301 
00302         r = sd_is_socket_internal(fd, type, listening);
00303         if (r <= 0)
00304                 return r;
00305 
00306         if (getsockname(fd, &sockaddr.sa, &l) < 0)
00307                 return -errno;
00308 
00309         if (l < sizeof(sa_family_t))
00310                 return -EINVAL;
00311 
00312         if (sockaddr.sa.sa_family != AF_INET &&
00313             sockaddr.sa.sa_family != AF_INET6)
00314                 return 0;
00315 
00316         if (family > 0)
00317                 if (sockaddr.sa.sa_family != family)
00318                         return 0;
00319 
00320         if (port > 0) {
00321                 if (sockaddr.sa.sa_family == AF_INET) {
00322                         if (l < sizeof(struct sockaddr_in))
00323                                 return -EINVAL;
00324 
00325                         return htons(port) == sockaddr.in4.sin_port;
00326                 } else {
00327                         if (l < sizeof(struct sockaddr_in6))
00328                                 return -EINVAL;
00329 
00330                         return htons(port) == sockaddr.in6.sin6_port;
00331                 }
00332         }
00333 
00334         return 1;
00335 }
00336 
00337 _sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
00338         union sockaddr_union sockaddr = {};
00339         socklen_t l = sizeof(sockaddr);
00340         int r;
00341 
00342         r = sd_is_socket_internal(fd, type, listening);
00343         if (r <= 0)
00344                 return r;
00345 
00346         if (getsockname(fd, &sockaddr.sa, &l) < 0)
00347                 return -errno;
00348 
00349         if (l < sizeof(sa_family_t))
00350                 return -EINVAL;
00351 
00352         if (sockaddr.sa.sa_family != AF_UNIX)
00353                 return 0;
00354 
00355         if (path) {
00356                 if (length == 0)
00357                         length = strlen(path);
00358 
00359                 if (length == 0)
00360                         /* Unnamed socket */
00361                         return l == offsetof(struct sockaddr_un, sun_path);
00362 
00363                 if (path[0])
00364                         /* Normal path socket */
00365                         return
00366                                 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
00367                                 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
00368                 else
00369                         /* Abstract namespace socket */
00370                         return
00371                                 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
00372                                 memcmp(path, sockaddr.un.sun_path, length) == 0;
00373         }
00374 
00375         return 1;
00376 }
00377 
00378 _sd_export_ int sd_is_mq(int fd, const char *path) {
00379 #if !defined(__linux__) || defined(SD_DAEMON_DISABLE_MQ)
00380         return 0;
00381 #else
00382         struct mq_attr attr;
00383 
00384         if (fd < 0)
00385                 return -EINVAL;
00386 
00387         if (mq_getattr(fd, &attr) < 0)
00388                 return -errno;
00389 
00390         if (path) {
00391                 char fpath[PATH_MAX];
00392                 struct stat a, b;
00393 
00394                 if (path[0] != '/')
00395                         return -EINVAL;
00396 
00397                 if (fstat(fd, &a) < 0)
00398                         return -errno;
00399 
00400                 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
00401                 fpath[sizeof(fpath)-1] = 0;
00402 
00403                 if (stat(fpath, &b) < 0)
00404                         return -errno;
00405 
00406                 if (a.st_dev != b.st_dev ||
00407                     a.st_ino != b.st_ino)
00408                         return 0;
00409         }
00410 
00411         return 1;
00412 #endif
00413 }
00414 
00415 _sd_export_ int sd_notify(int unset_environment, const char *state) {
00416 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
00417         return 0;
00418 #else
00419         int fd = -1, r;
00420         struct msghdr msghdr;
00421         struct iovec iovec;
00422         union sockaddr_union sockaddr;
00423         const char *e;
00424 
00425         if (!state) {
00426                 r = -EINVAL;
00427                 goto finish;
00428         }
00429 
00430         e = getenv("NOTIFY_SOCKET");
00431         if (!e)
00432                 return 0;
00433 
00434         /* Must be an abstract socket, or an absolute path */
00435         if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
00436                 r = -EINVAL;
00437                 goto finish;
00438         }
00439 
00440         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
00441         if (fd < 0) {
00442                 r = -errno;
00443                 goto finish;
00444         }
00445 
00446         memset(&sockaddr, 0, sizeof(sockaddr));
00447         sockaddr.sa.sa_family = AF_UNIX;
00448         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
00449 
00450         if (sockaddr.un.sun_path[0] == '@')
00451                 sockaddr.un.sun_path[0] = 0;
00452 
00453         memset(&iovec, 0, sizeof(iovec));
00454         iovec.iov_base = (char*) state;
00455         iovec.iov_len = strlen(state);
00456 
00457         memset(&msghdr, 0, sizeof(msghdr));
00458         msghdr.msg_name = &sockaddr;
00459         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
00460 
00461         if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
00462                 msghdr.msg_namelen = sizeof(struct sockaddr_un);
00463 
00464         msghdr.msg_iov = &iovec;
00465         msghdr.msg_iovlen = 1;
00466 
00467         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
00468                 r = -errno;
00469                 goto finish;
00470         }
00471 
00472         r = 1;
00473 
00474 finish:
00475         if (unset_environment)
00476                 unsetenv("NOTIFY_SOCKET");
00477 
00478         if (fd >= 0)
00479                 close(fd);
00480 
00481         return r;
00482 #endif
00483 }
00484 
00485 _sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) {
00486 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
00487         return 0;
00488 #else
00489         va_list ap;
00490         char *p = NULL;
00491         int r;
00492 
00493         va_start(ap, format);
00494         r = vasprintf(&p, format, ap);
00495         va_end(ap);
00496 
00497         if (r < 0 || !p)
00498                 return -ENOMEM;
00499 
00500         r = sd_notify(unset_environment, p);
00501         free(p);
00502 
00503         return r;
00504 #endif
00505 }
00506 
00507 _sd_export_ int sd_booted(void) {
00508 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
00509         return 0;
00510 #else
00511         struct stat st;
00512 
00513         /* We test whether the runtime unit file directory has been
00514          * created. This takes place in mount-setup.c, so is
00515          * guaranteed to happen very early during boot. */
00516 
00517         if (lstat("/run/systemd/system/", &st) < 0)
00518                 return 0;
00519 
00520         return !!S_ISDIR(st.st_mode);
00521 #endif
00522 }