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