pcsc-lite  1.8.2
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 #ifndef _GNU_SOURCE
00028 #define _GNU_SOURCE
00029 #endif
00030 
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 #include <sys/socket.h>
00034 #include <sys/un.h>
00035 #include <sys/fcntl.h>
00036 #include <netinet/in.h>
00037 #include <stdlib.h>
00038 #include <errno.h>
00039 #include <unistd.h>
00040 #include <string.h>
00041 #include <stdarg.h>
00042 #include <stdio.h>
00043 #include <stddef.h>
00044 #include <limits.h>
00045 
00046 #if defined(__linux__)
00047 #include <mqueue.h>
00048 #endif
00049 
00050 #include "sd-daemon.h"
00051 
00052 #if (__GNUC__ >= 4)
00053 #ifdef SD_EXPORT_SYMBOLS
00054 /* Export symbols */
00055 #define _sd_export_ __attribute__ ((visibility("default")))
00056 #else
00057 /* Don't export the symbols */
00058 #define _sd_export_ __attribute__ ((visibility("hidden")))
00059 #endif
00060 #else
00061 #define _sd_export_
00062 #endif
00063 
00064 _sd_export_ int sd_listen_fds(int unset_environment) {
00065 
00066 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
00067         return 0;
00068 #else
00069         int r, fd;
00070         const char *e;
00071         char *p = NULL;
00072         unsigned long l;
00073 
00074         if (!(e = getenv("LISTEN_PID"))) {
00075                 r = 0;
00076                 goto finish;
00077         }
00078 
00079         errno = 0;
00080         l = strtoul(e, &p, 10);
00081 
00082         if (errno != 0) {
00083                 r = -errno;
00084                 goto finish;
00085         }
00086 
00087         if (!p || *p || l <= 0) {
00088                 r = -EINVAL;
00089                 goto finish;
00090         }
00091 
00092         /* Is this for us? */
00093         if (getpid() != (pid_t) l) {
00094                 r = 0;
00095                 goto finish;
00096         }
00097 
00098         if (!(e = getenv("LISTEN_FDS"))) {
00099                 r = 0;
00100                 goto finish;
00101         }
00102 
00103         errno = 0;
00104         l = strtoul(e, &p, 10);
00105 
00106         if (errno != 0) {
00107                 r = -errno;
00108                 goto finish;
00109         }
00110 
00111         if (!p || *p) {
00112                 r = -EINVAL;
00113                 goto finish;
00114         }
00115 
00116         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
00117                 int flags;
00118 
00119                 if ((flags = fcntl(fd, F_GETFD)) < 0) {
00120                         r = -errno;
00121                         goto finish;
00122                 }
00123 
00124                 if (flags & FD_CLOEXEC)
00125                         continue;
00126 
00127                 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
00128                         r = -errno;
00129                         goto finish;
00130                 }
00131         }
00132 
00133         r = (int) l;
00134 
00135 finish:
00136         if (unset_environment) {
00137                 unsetenv("LISTEN_PID");
00138                 unsetenv("LISTEN_FDS");
00139         }
00140 
00141         return r;
00142 #endif
00143 }
00144 
00145 _sd_export_ int sd_is_fifo(int fd, const char *path) {
00146         struct stat st_fd;
00147 
00148         if (fd < 0)
00149                 return -EINVAL;
00150 
00151         memset(&st_fd, 0, sizeof(st_fd));
00152         if (fstat(fd, &st_fd) < 0)
00153                 return -errno;
00154 
00155         if (!S_ISFIFO(st_fd.st_mode))
00156                 return 0;
00157 
00158         if (path) {
00159                 struct stat st_path;
00160 
00161                 memset(&st_path, 0, sizeof(st_path));
00162                 if (stat(path, &st_path) < 0) {
00163 
00164                         if (errno == ENOENT || errno == ENOTDIR)
00165                                 return 0;
00166 
00167                         return -errno;
00168                 }
00169 
00170                 return
00171                         st_path.st_dev == st_fd.st_dev &&
00172                         st_path.st_ino == st_fd.st_ino;
00173         }
00174 
00175         return 1;
00176 }
00177 
00178 _sd_export_ int sd_is_special(int fd, const char *path) {
00179         struct stat st_fd;
00180 
00181         if (fd < 0)
00182                 return -EINVAL;
00183 
00184         if (fstat(fd, &st_fd) < 0)
00185                 return -errno;
00186 
00187         if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
00188                 return 0;
00189 
00190         if (path) {
00191                 struct stat st_path;
00192 
00193                 if (stat(path, &st_path) < 0) {
00194 
00195                         if (errno == ENOENT || errno == ENOTDIR)
00196                                 return 0;
00197 
00198                         return -errno;
00199                 }
00200 
00201                 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
00202                         return
00203                                 st_path.st_dev == st_fd.st_dev &&
00204                                 st_path.st_ino == st_fd.st_ino;
00205                 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
00206                         return st_path.st_rdev == st_fd.st_rdev;
00207                 else
00208                         return 0;
00209         }
00210 
00211         return 1;
00212 }
00213 
00214 static int sd_is_socket_internal(int fd, int type, int listening) {
00215         struct stat st_fd;
00216 
00217         if (fd < 0 || type < 0)
00218                 return -EINVAL;
00219 
00220         if (fstat(fd, &st_fd) < 0)
00221                 return -errno;
00222 
00223         if (!S_ISSOCK(st_fd.st_mode))
00224                 return 0;
00225 
00226         if (type != 0) {
00227                 int other_type = 0;
00228                 socklen_t l = sizeof(other_type);
00229 
00230                 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
00231                         return -errno;
00232 
00233                 if (l != sizeof(other_type))
00234                         return -EINVAL;
00235 
00236                 if (other_type != type)
00237                         return 0;
00238         }
00239 
00240         if (listening >= 0) {
00241                 int accepting = 0;
00242                 socklen_t l = sizeof(accepting);
00243 
00244                 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
00245                         return -errno;
00246 
00247                 if (l != sizeof(accepting))
00248                         return -EINVAL;
00249 
00250                 if (!accepting != !listening)
00251                         return 0;
00252         }
00253 
00254         return 1;
00255 }
00256 
00257 union sockaddr_union {
00258         struct sockaddr sa;
00259         struct sockaddr_in in4;
00260         struct sockaddr_in6 in6;
00261         struct sockaddr_un un;
00262         struct sockaddr_storage storage;
00263 };
00264 
00265 _sd_export_ int sd_is_socket(int fd, int family, int type, int listening) {
00266         int r;
00267 
00268         if (family < 0)
00269                 return -EINVAL;
00270 
00271         if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
00272                 return r;
00273 
00274         if (family > 0) {
00275                 union sockaddr_union sockaddr;
00276                 socklen_t l;
00277 
00278                 memset(&sockaddr, 0, sizeof(sockaddr));
00279                 l = sizeof(sockaddr);
00280 
00281                 if (getsockname(fd, &sockaddr.sa, &l) < 0)
00282                         return -errno;
00283 
00284                 if (l < sizeof(sa_family_t))
00285                         return -EINVAL;
00286 
00287                 return sockaddr.sa.sa_family == family;
00288         }
00289 
00290         return 1;
00291 }
00292 
00293 _sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
00294         union sockaddr_union sockaddr;
00295         socklen_t l;
00296         int r;
00297 
00298         if (family != 0 && family != AF_INET && family != AF_INET6)
00299                 return -EINVAL;
00300 
00301         if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
00302                 return r;
00303 
00304         memset(&sockaddr, 0, sizeof(sockaddr));
00305         l = sizeof(sockaddr);
00306 
00307         if (getsockname(fd, &sockaddr.sa, &l) < 0)
00308                 return -errno;
00309 
00310         if (l < sizeof(sa_family_t))
00311                 return -EINVAL;
00312 
00313         if (sockaddr.sa.sa_family != AF_INET &&
00314             sockaddr.sa.sa_family != AF_INET6)
00315                 return 0;
00316 
00317         if (family > 0)
00318                 if (sockaddr.sa.sa_family != family)
00319                         return 0;
00320 
00321         if (port > 0) {
00322                 if (sockaddr.sa.sa_family == AF_INET) {
00323                         if (l < sizeof(struct sockaddr_in))
00324                                 return -EINVAL;
00325 
00326                         return htons(port) == sockaddr.in4.sin_port;
00327                 } else {
00328                         if (l < sizeof(struct sockaddr_in6))
00329                                 return -EINVAL;
00330 
00331                         return htons(port) == sockaddr.in6.sin6_port;
00332                 }
00333         }
00334 
00335         return 1;
00336 }
00337 
00338 _sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
00339         union sockaddr_union sockaddr;
00340         socklen_t l;
00341         int r;
00342 
00343         if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
00344                 return r;
00345 
00346         memset(&sockaddr, 0, sizeof(sockaddr));
00347         l = sizeof(sockaddr);
00348 
00349         if (getsockname(fd, &sockaddr.sa, &l) < 0)
00350                 return -errno;
00351 
00352         if (l < sizeof(sa_family_t))
00353                 return -EINVAL;
00354 
00355         if (sockaddr.sa.sa_family != AF_UNIX)
00356                 return 0;
00357 
00358         if (path) {
00359                 if (length <= 0)
00360                         length = strlen(path);
00361 
00362                 if (length <= 0)
00363                         /* Unnamed socket */
00364                         return l == offsetof(struct sockaddr_un, sun_path);
00365 
00366                 if (path[0])
00367                         /* Normal path socket */
00368                         return
00369                                 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
00370                                 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
00371                 else
00372                         /* Abstract namespace socket */
00373                         return
00374                                 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
00375                                 memcmp(path, sockaddr.un.sun_path, length) == 0;
00376         }
00377 
00378         return 1;
00379 }
00380 
00381 _sd_export_ int sd_is_mq(int fd, const char *path) {
00382 #if !defined(__linux__)
00383         return 0;
00384 #else
00385         struct mq_attr attr;
00386 
00387         if (fd < 0)
00388                 return -EINVAL;
00389 
00390         if (mq_getattr(fd, &attr) < 0)
00391                 return -errno;
00392 
00393         if (path) {
00394                 char fpath[PATH_MAX];
00395                 struct stat a, b;
00396 
00397                 if (path[0] != '/')
00398                         return -EINVAL;
00399 
00400                 if (fstat(fd, &a) < 0)
00401                         return -errno;
00402 
00403                 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
00404                 fpath[sizeof(fpath)-1] = 0;
00405 
00406                 if (stat(fpath, &b) < 0)
00407                         return -errno;
00408 
00409                 if (a.st_dev != b.st_dev ||
00410                     a.st_ino != b.st_ino)
00411                         return 0;
00412         }
00413 
00414         return 1;
00415 #endif
00416 }
00417 
00418 _sd_export_ int sd_notify(int unset_environment, const char *state) {
00419 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
00420         return 0;
00421 #else
00422         int fd = -1, r;
00423         struct msghdr msghdr;
00424         struct iovec iovec;
00425         union sockaddr_union sockaddr;
00426         const char *e;
00427 
00428         if (!state) {
00429                 r = -EINVAL;
00430                 goto finish;
00431         }
00432 
00433         if (!(e = getenv("NOTIFY_SOCKET")))
00434                 return 0;
00435 
00436         /* Must be an abstract socket, or an absolute path */
00437         if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
00438                 r = -EINVAL;
00439                 goto finish;
00440         }
00441 
00442         if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
00443                 r = -errno;
00444                 goto finish;
00445         }
00446 
00447         memset(&sockaddr, 0, sizeof(sockaddr));
00448         sockaddr.sa.sa_family = AF_UNIX;
00449         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
00450 
00451         if (sockaddr.un.sun_path[0] == '@')
00452                 sockaddr.un.sun_path[0] = 0;
00453 
00454         memset(&iovec, 0, sizeof(iovec));
00455         iovec.iov_base = (char*) state;
00456         iovec.iov_len = strlen(state);
00457 
00458         memset(&msghdr, 0, sizeof(msghdr));
00459         msghdr.msg_name = &sockaddr;
00460         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
00461 
00462         if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
00463                 msghdr.msg_namelen = sizeof(struct sockaddr_un);
00464 
00465         msghdr.msg_iov = &iovec;
00466         msghdr.msg_iovlen = 1;
00467 
00468         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
00469                 r = -errno;
00470                 goto finish;
00471         }
00472 
00473         r = 1;
00474 
00475 finish:
00476         if (unset_environment)
00477                 unsetenv("NOTIFY_SOCKET");
00478 
00479         if (fd >= 0)
00480                 close(fd);
00481 
00482         return r;
00483 #endif
00484 }
00485 
00486 _sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) {
00487 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
00488         return 0;
00489 #else
00490         va_list ap;
00491         char *p = NULL;
00492         int r;
00493 
00494         va_start(ap, format);
00495         r = vasprintf(&p, format, ap);
00496         va_end(ap);
00497 
00498         if (r < 0 || !p)
00499                 return -ENOMEM;
00500 
00501         r = sd_notify(unset_environment, p);
00502         free(p);
00503 
00504         return r;
00505 #endif
00506 }
00507 
00508 _sd_export_ int sd_booted(void) {
00509 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
00510         return 0;
00511 #else
00512 
00513         struct stat a, b;
00514 
00515         /* We simply test whether the systemd cgroup hierarchy is
00516          * mounted */
00517 
00518         if (lstat("/sys/fs/cgroup", &a) < 0)
00519                 return 0;
00520 
00521         if (lstat("/sys/fs/cgroup/systemd", &b) < 0)
00522                 return 0;
00523 
00524         return a.st_dev != b.st_dev;
00525 #endif
00526 }