]> git.proxmox.com Git - systemd.git/blob - src/libsystemd-daemon/sd-daemon.c
Imported Upstream version 204
[systemd.git] / src / libsystemd-daemon / sd-daemon.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 Copyright 2010 Lennart Poettering
5
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:
13
14 The above copyright notice and this permission notice shall be
15 included in all copies or substantial portions of the Software.
16
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 ***/
26
27 #ifndef _GNU_SOURCE
28 # define _GNU_SOURCE
29 #endif
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/socket.h>
34 #include <sys/un.h>
35 #include <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>
45
46 #if defined(__linux__) && !defined(SD_DAEMON_DISABLE_MQ)
47 # include <mqueue.h>
48 #endif
49
50 #include "sd-daemon.h"
51
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
63
64 _sd_export_ int sd_listen_fds(int unset_environment) {
65
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;
73
74 e = getenv("LISTEN_PID");
75 if (!e) {
76 r = 0;
77 goto finish;
78 }
79
80 errno = 0;
81 l = strtoul(e, &p, 10);
82
83 if (errno > 0) {
84 r = -errno;
85 goto finish;
86 }
87
88 if (!p || p == e || *p || l <= 0) {
89 r = -EINVAL;
90 goto finish;
91 }
92
93 /* Is this for us? */
94 if (getpid() != (pid_t) l) {
95 r = 0;
96 goto finish;
97 }
98
99 e = getenv("LISTEN_FDS");
100 if (!e) {
101 r = 0;
102 goto finish;
103 }
104
105 errno = 0;
106 l = strtoul(e, &p, 10);
107
108 if (errno > 0) {
109 r = -errno;
110 goto finish;
111 }
112
113 if (!p || p == e || *p) {
114 r = -EINVAL;
115 goto finish;
116 }
117
118 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
119 int flags;
120
121 flags = fcntl(fd, F_GETFD);
122 if (flags < 0) {
123 r = -errno;
124 goto finish;
125 }
126
127 if (flags & FD_CLOEXEC)
128 continue;
129
130 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
131 r = -errno;
132 goto finish;
133 }
134 }
135
136 r = (int) l;
137
138 finish:
139 if (unset_environment) {
140 unsetenv("LISTEN_PID");
141 unsetenv("LISTEN_FDS");
142 }
143
144 return r;
145 #endif
146 }
147
148 _sd_export_ int sd_is_fifo(int fd, const char *path) {
149 struct stat st_fd;
150
151 if (fd < 0)
152 return -EINVAL;
153
154 if (fstat(fd, &st_fd) < 0)
155 return -errno;
156
157 if (!S_ISFIFO(st_fd.st_mode))
158 return 0;
159
160 if (path) {
161 struct stat st_path;
162
163 if (stat(path, &st_path) < 0) {
164
165 if (errno == ENOENT || errno == ENOTDIR)
166 return 0;
167
168 return -errno;
169 }
170
171 return
172 st_path.st_dev == st_fd.st_dev &&
173 st_path.st_ino == st_fd.st_ino;
174 }
175
176 return 1;
177 }
178
179 _sd_export_ int sd_is_special(int fd, const char *path) {
180 struct stat st_fd;
181
182 if (fd < 0)
183 return -EINVAL;
184
185 if (fstat(fd, &st_fd) < 0)
186 return -errno;
187
188 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
189 return 0;
190
191 if (path) {
192 struct stat st_path;
193
194 if (stat(path, &st_path) < 0) {
195
196 if (errno == ENOENT || errno == ENOTDIR)
197 return 0;
198
199 return -errno;
200 }
201
202 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
203 return
204 st_path.st_dev == st_fd.st_dev &&
205 st_path.st_ino == st_fd.st_ino;
206 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
207 return st_path.st_rdev == st_fd.st_rdev;
208 else
209 return 0;
210 }
211
212 return 1;
213 }
214
215 static int sd_is_socket_internal(int fd, int type, int listening) {
216 struct stat st_fd;
217
218 if (fd < 0 || type < 0)
219 return -EINVAL;
220
221 if (fstat(fd, &st_fd) < 0)
222 return -errno;
223
224 if (!S_ISSOCK(st_fd.st_mode))
225 return 0;
226
227 if (type != 0) {
228 int other_type = 0;
229 socklen_t l = sizeof(other_type);
230
231 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
232 return -errno;
233
234 if (l != sizeof(other_type))
235 return -EINVAL;
236
237 if (other_type != type)
238 return 0;
239 }
240
241 if (listening >= 0) {
242 int accepting = 0;
243 socklen_t l = sizeof(accepting);
244
245 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
246 return -errno;
247
248 if (l != sizeof(accepting))
249 return -EINVAL;
250
251 if (!accepting != !listening)
252 return 0;
253 }
254
255 return 1;
256 }
257
258 union sockaddr_union {
259 struct sockaddr sa;
260 struct sockaddr_in in4;
261 struct sockaddr_in6 in6;
262 struct sockaddr_un un;
263 struct sockaddr_storage storage;
264 };
265
266 _sd_export_ int sd_is_socket(int fd, int family, int type, int listening) {
267 int r;
268
269 if (family < 0)
270 return -EINVAL;
271
272 r = sd_is_socket_internal(fd, type, listening);
273 if (r <= 0)
274 return r;
275
276 if (family > 0) {
277 union sockaddr_union sockaddr = {};
278 socklen_t l = sizeof(sockaddr);
279
280 if (getsockname(fd, &sockaddr.sa, &l) < 0)
281 return -errno;
282
283 if (l < sizeof(sa_family_t))
284 return -EINVAL;
285
286 return sockaddr.sa.sa_family == family;
287 }
288
289 return 1;
290 }
291
292 _sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
293 union sockaddr_union sockaddr = {};
294 socklen_t l = sizeof(sockaddr);
295 int r;
296
297 if (family != 0 && family != AF_INET && family != AF_INET6)
298 return -EINVAL;
299
300 r = sd_is_socket_internal(fd, type, listening);
301 if (r <= 0)
302 return r;
303
304 if (getsockname(fd, &sockaddr.sa, &l) < 0)
305 return -errno;
306
307 if (l < sizeof(sa_family_t))
308 return -EINVAL;
309
310 if (sockaddr.sa.sa_family != AF_INET &&
311 sockaddr.sa.sa_family != AF_INET6)
312 return 0;
313
314 if (family > 0)
315 if (sockaddr.sa.sa_family != family)
316 return 0;
317
318 if (port > 0) {
319 if (sockaddr.sa.sa_family == AF_INET) {
320 if (l < sizeof(struct sockaddr_in))
321 return -EINVAL;
322
323 return htons(port) == sockaddr.in4.sin_port;
324 } else {
325 if (l < sizeof(struct sockaddr_in6))
326 return -EINVAL;
327
328 return htons(port) == sockaddr.in6.sin6_port;
329 }
330 }
331
332 return 1;
333 }
334
335 _sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
336 union sockaddr_union sockaddr = {};
337 socklen_t l = sizeof(sockaddr);
338 int r;
339
340 r = sd_is_socket_internal(fd, type, listening);
341 if (r <= 0)
342 return r;
343
344 if (getsockname(fd, &sockaddr.sa, &l) < 0)
345 return -errno;
346
347 if (l < sizeof(sa_family_t))
348 return -EINVAL;
349
350 if (sockaddr.sa.sa_family != AF_UNIX)
351 return 0;
352
353 if (path) {
354 if (length == 0)
355 length = strlen(path);
356
357 if (length == 0)
358 /* Unnamed socket */
359 return l == offsetof(struct sockaddr_un, sun_path);
360
361 if (path[0])
362 /* Normal path socket */
363 return
364 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
365 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
366 else
367 /* Abstract namespace socket */
368 return
369 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
370 memcmp(path, sockaddr.un.sun_path, length) == 0;
371 }
372
373 return 1;
374 }
375
376 _sd_export_ int sd_is_mq(int fd, const char *path) {
377 #if !defined(__linux__) || defined(SD_DAEMON_DISABLE_MQ)
378 return 0;
379 #else
380 struct mq_attr attr;
381
382 if (fd < 0)
383 return -EINVAL;
384
385 if (mq_getattr(fd, &attr) < 0)
386 return -errno;
387
388 if (path) {
389 char fpath[PATH_MAX];
390 struct stat a, b;
391
392 if (path[0] != '/')
393 return -EINVAL;
394
395 if (fstat(fd, &a) < 0)
396 return -errno;
397
398 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
399 fpath[sizeof(fpath)-1] = 0;
400
401 if (stat(fpath, &b) < 0)
402 return -errno;
403
404 if (a.st_dev != b.st_dev ||
405 a.st_ino != b.st_ino)
406 return 0;
407 }
408
409 return 1;
410 #endif
411 }
412
413 _sd_export_ int sd_notify(int unset_environment, const char *state) {
414 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
415 return 0;
416 #else
417 int fd = -1, r;
418 struct msghdr msghdr;
419 struct iovec iovec;
420 union sockaddr_union sockaddr;
421 const char *e;
422
423 if (!state) {
424 r = -EINVAL;
425 goto finish;
426 }
427
428 e = getenv("NOTIFY_SOCKET");
429 if (!e)
430 return 0;
431
432 /* Must be an abstract socket, or an absolute path */
433 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
434 r = -EINVAL;
435 goto finish;
436 }
437
438 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
439 if (fd < 0) {
440 r = -errno;
441 goto finish;
442 }
443
444 memset(&sockaddr, 0, sizeof(sockaddr));
445 sockaddr.sa.sa_family = AF_UNIX;
446 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
447
448 if (sockaddr.un.sun_path[0] == '@')
449 sockaddr.un.sun_path[0] = 0;
450
451 memset(&iovec, 0, sizeof(iovec));
452 iovec.iov_base = (char*) state;
453 iovec.iov_len = strlen(state);
454
455 memset(&msghdr, 0, sizeof(msghdr));
456 msghdr.msg_name = &sockaddr;
457 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
458
459 if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
460 msghdr.msg_namelen = sizeof(struct sockaddr_un);
461
462 msghdr.msg_iov = &iovec;
463 msghdr.msg_iovlen = 1;
464
465 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
466 r = -errno;
467 goto finish;
468 }
469
470 r = 1;
471
472 finish:
473 if (unset_environment)
474 unsetenv("NOTIFY_SOCKET");
475
476 if (fd >= 0)
477 close(fd);
478
479 return r;
480 #endif
481 }
482
483 _sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) {
484 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
485 return 0;
486 #else
487 va_list ap;
488 char *p = NULL;
489 int r;
490
491 va_start(ap, format);
492 r = vasprintf(&p, format, ap);
493 va_end(ap);
494
495 if (r < 0 || !p)
496 return -ENOMEM;
497
498 r = sd_notify(unset_environment, p);
499 free(p);
500
501 return r;
502 #endif
503 }
504
505 _sd_export_ int sd_booted(void) {
506 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
507 return 0;
508 #else
509 struct stat st;
510
511 /* We test whether the runtime unit file directory has been
512 * created. This takes place in mount-setup.c, so is
513 * guaranteed to happen very early during boot. */
514
515 if (lstat("/run/systemd/system/", &st) < 0)
516 return 0;
517
518 return !!S_ISDIR(st.st_mode);
519 #endif
520 }