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