systemadm: add a wrappable label and use it for status lines
[systemd_ALT/systemd_imz.git] / src / sd-daemon.c
blobe68b70875c749a22dcbbfc6d7338d2c848f3a317
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
3 /***
4 Copyright 2010 Lennart Poettering
6 Permission is hereby granted, free of charge, to any person
7 obtaining a copy of this software and associated documentation files
8 (the "Software"), to deal in the Software without restriction,
9 including without limitation the rights to use, copy, modify, merge,
10 publish, distribute, sublicense, and/or sell copies of the Software,
11 and to permit persons to whom the Software is furnished to do so,
12 subject to the following conditions:
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25 ***/
27 #ifndef _GNU_SOURCE
28 #define _GNU_SOURCE
29 #endif
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/socket.h>
34 #include <sys/un.h>
35 #include <sys/fcntl.h>
36 #include <netinet/in.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <stddef.h>
44 #include <limits.h>
46 #if defined(__linux__)
47 #include <mqueue.h>
48 #endif
50 #include "sd-daemon.h"
52 #if (__GNUC__ >= 4)
53 #ifdef SD_EXPORT_SYMBOLS
54 /* Export symbols */
55 #define _sd_export_ __attribute__ ((visibility("default")))
56 #else
57 /* Don't export the symbols */
58 #define _sd_export_ __attribute__ ((visibility("hidden")))
59 #endif
60 #else
61 #define _sd_export_
62 #endif
64 _sd_export_ int sd_listen_fds(int unset_environment) {
66 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
67 return 0;
68 #else
69 int r, fd;
70 const char *e;
71 char *p = NULL;
72 unsigned long l;
74 if (!(e = getenv("LISTEN_PID"))) {
75 r = 0;
76 goto finish;
79 errno = 0;
80 l = strtoul(e, &p, 10);
82 if (errno != 0) {
83 r = -errno;
84 goto finish;
87 if (!p || *p || l <= 0) {
88 r = -EINVAL;
89 goto finish;
92 /* Is this for us? */
93 if (getpid() != (pid_t) l) {
94 r = 0;
95 goto finish;
98 if (!(e = getenv("LISTEN_FDS"))) {
99 r = 0;
100 goto finish;
103 errno = 0;
104 l = strtoul(e, &p, 10);
106 if (errno != 0) {
107 r = -errno;
108 goto finish;
111 if (!p || *p) {
112 r = -EINVAL;
113 goto finish;
116 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
117 int flags;
119 if ((flags = fcntl(fd, F_GETFD)) < 0) {
120 r = -errno;
121 goto finish;
124 if (flags & FD_CLOEXEC)
125 continue;
127 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
128 r = -errno;
129 goto finish;
133 r = (int) l;
135 finish:
136 if (unset_environment) {
137 unsetenv("LISTEN_PID");
138 unsetenv("LISTEN_FDS");
141 return r;
142 #endif
145 _sd_export_ int sd_is_fifo(int fd, const char *path) {
146 struct stat st_fd;
148 if (fd < 0)
149 return -EINVAL;
151 memset(&st_fd, 0, sizeof(st_fd));
152 if (fstat(fd, &st_fd) < 0)
153 return -errno;
155 if (!S_ISFIFO(st_fd.st_mode))
156 return 0;
158 if (path) {
159 struct stat st_path;
161 memset(&st_path, 0, sizeof(st_path));
162 if (stat(path, &st_path) < 0) {
164 if (errno == ENOENT || errno == ENOTDIR)
165 return 0;
167 return -errno;
170 return
171 st_path.st_dev == st_fd.st_dev &&
172 st_path.st_ino == st_fd.st_ino;
175 return 1;
178 _sd_export_ int sd_is_special(int fd, const char *path) {
179 struct stat st_fd;
181 if (fd < 0)
182 return -EINVAL;
184 if (fstat(fd, &st_fd) < 0)
185 return -errno;
187 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
188 return 0;
190 if (path) {
191 struct stat st_path;
193 if (stat(path, &st_path) < 0) {
195 if (errno == ENOENT || errno == ENOTDIR)
196 return 0;
198 return -errno;
201 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
202 return
203 st_path.st_dev == st_fd.st_dev &&
204 st_path.st_ino == st_fd.st_ino;
205 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
206 return st_path.st_rdev == st_fd.st_rdev;
207 else
208 return 0;
211 return 1;
214 static int sd_is_socket_internal(int fd, int type, int listening) {
215 struct stat st_fd;
217 if (fd < 0 || type < 0)
218 return -EINVAL;
220 if (fstat(fd, &st_fd) < 0)
221 return -errno;
223 if (!S_ISSOCK(st_fd.st_mode))
224 return 0;
226 if (type != 0) {
227 int other_type = 0;
228 socklen_t l = sizeof(other_type);
230 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
231 return -errno;
233 if (l != sizeof(other_type))
234 return -EINVAL;
236 if (other_type != type)
237 return 0;
240 if (listening >= 0) {
241 int accepting = 0;
242 socklen_t l = sizeof(accepting);
244 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
245 return -errno;
247 if (l != sizeof(accepting))
248 return -EINVAL;
250 if (!accepting != !listening)
251 return 0;
254 return 1;
257 union sockaddr_union {
258 struct sockaddr sa;
259 struct sockaddr_in in4;
260 struct sockaddr_in6 in6;
261 struct sockaddr_un un;
262 struct sockaddr_storage storage;
265 _sd_export_ int sd_is_socket(int fd, int family, int type, int listening) {
266 int r;
268 if (family < 0)
269 return -EINVAL;
271 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
272 return r;
274 if (family > 0) {
275 union sockaddr_union sockaddr;
276 socklen_t l;
278 memset(&sockaddr, 0, sizeof(sockaddr));
279 l = sizeof(sockaddr);
281 if (getsockname(fd, &sockaddr.sa, &l) < 0)
282 return -errno;
284 if (l < sizeof(sa_family_t))
285 return -EINVAL;
287 return sockaddr.sa.sa_family == family;
290 return 1;
293 _sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
294 union sockaddr_union sockaddr;
295 socklen_t l;
296 int r;
298 if (family != 0 && family != AF_INET && family != AF_INET6)
299 return -EINVAL;
301 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
302 return r;
304 memset(&sockaddr, 0, sizeof(sockaddr));
305 l = sizeof(sockaddr);
307 if (getsockname(fd, &sockaddr.sa, &l) < 0)
308 return -errno;
310 if (l < sizeof(sa_family_t))
311 return -EINVAL;
313 if (sockaddr.sa.sa_family != AF_INET &&
314 sockaddr.sa.sa_family != AF_INET6)
315 return 0;
317 if (family > 0)
318 if (sockaddr.sa.sa_family != family)
319 return 0;
321 if (port > 0) {
322 if (sockaddr.sa.sa_family == AF_INET) {
323 if (l < sizeof(struct sockaddr_in))
324 return -EINVAL;
326 return htons(port) == sockaddr.in4.sin_port;
327 } else {
328 if (l < sizeof(struct sockaddr_in6))
329 return -EINVAL;
331 return htons(port) == sockaddr.in6.sin6_port;
335 return 1;
338 _sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
339 union sockaddr_union sockaddr;
340 socklen_t l;
341 int r;
343 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
344 return r;
346 memset(&sockaddr, 0, sizeof(sockaddr));
347 l = sizeof(sockaddr);
349 if (getsockname(fd, &sockaddr.sa, &l) < 0)
350 return -errno;
352 if (l < sizeof(sa_family_t))
353 return -EINVAL;
355 if (sockaddr.sa.sa_family != AF_UNIX)
356 return 0;
358 if (path) {
359 if (length <= 0)
360 length = strlen(path);
362 if (length <= 0)
363 /* Unnamed socket */
364 return l == offsetof(struct sockaddr_un, sun_path);
366 if (path[0])
367 /* Normal path socket */
368 return
369 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
370 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
371 else
372 /* Abstract namespace socket */
373 return
374 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
375 memcmp(path, sockaddr.un.sun_path, length) == 0;
378 return 1;
381 _sd_export_ int sd_is_mq(int fd, const char *path) {
382 #if !defined(__linux__)
383 return 0;
384 #else
385 struct mq_attr attr;
387 if (fd < 0)
388 return -EINVAL;
390 if (mq_getattr(fd, &attr) < 0)
391 return -errno;
393 if (path) {
394 char fpath[PATH_MAX];
395 struct stat a, b;
397 if (path[0] != '/')
398 return -EINVAL;
400 if (fstat(fd, &a) < 0)
401 return -errno;
403 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
404 fpath[sizeof(fpath)-1] = 0;
406 if (stat(fpath, &b) < 0)
407 return -errno;
409 if (a.st_dev != b.st_dev ||
410 a.st_ino != b.st_ino)
411 return 0;
414 return 1;
415 #endif
418 _sd_export_ int sd_notify(int unset_environment, const char *state) {
419 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
420 return 0;
421 #else
422 int fd = -1, r;
423 struct msghdr msghdr;
424 struct iovec iovec;
425 union sockaddr_union sockaddr;
426 const char *e;
428 if (!state) {
429 r = -EINVAL;
430 goto finish;
433 if (!(e = getenv("NOTIFY_SOCKET")))
434 return 0;
436 /* Must be an abstract socket, or an absolute path */
437 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
438 r = -EINVAL;
439 goto finish;
442 if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
443 r = -errno;
444 goto finish;
447 memset(&sockaddr, 0, sizeof(sockaddr));
448 sockaddr.sa.sa_family = AF_UNIX;
449 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
451 if (sockaddr.un.sun_path[0] == '@')
452 sockaddr.un.sun_path[0] = 0;
454 memset(&iovec, 0, sizeof(iovec));
455 iovec.iov_base = (char*) state;
456 iovec.iov_len = strlen(state);
458 memset(&msghdr, 0, sizeof(msghdr));
459 msghdr.msg_name = &sockaddr;
460 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
462 if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
463 msghdr.msg_namelen = sizeof(struct sockaddr_un);
465 msghdr.msg_iov = &iovec;
466 msghdr.msg_iovlen = 1;
468 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
469 r = -errno;
470 goto finish;
473 r = 1;
475 finish:
476 if (unset_environment)
477 unsetenv("NOTIFY_SOCKET");
479 if (fd >= 0)
480 close(fd);
482 return r;
483 #endif
486 _sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) {
487 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
488 return 0;
489 #else
490 va_list ap;
491 char *p = NULL;
492 int r;
494 va_start(ap, format);
495 r = vasprintf(&p, format, ap);
496 va_end(ap);
498 if (r < 0 || !p)
499 return -ENOMEM;
501 r = sd_notify(unset_environment, p);
502 free(p);
504 return r;
505 #endif
508 _sd_export_ int sd_booted(void) {
509 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
510 return 0;
511 #else
513 struct stat a, b;
515 /* We simply test whether the systemd cgroup hierarchy is
516 * mounted */
518 if (lstat("/sys/fs/cgroup", &a) < 0)
519 return 0;
521 if (lstat("/sys/fs/cgroup/systemd", &b) < 0)
522 return 0;
524 return a.st_dev != b.st_dev;
525 #endif