D-Bus  1.8.1
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 
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 }
#define NULL
A null pointer, defined appropriately for C or C++.