00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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 <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
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
00310 return l == sizeof(sa_family_t);
00311
00312 if (path[0])
00313
00314 return
00315 (l >= sizeof(sa_family_t) + length + 1) &&
00316 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
00317 else
00318
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
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
00425
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 }