|
D-Bus
1.8.20
|
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 }
1.7.6.1