i3
sd-daemon.c
Go to the documentation of this file.
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 <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 
45 #include "sd-daemon.h"
46 
47 int sd_listen_fds(int unset_environment) {
48 
49 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
50  return 0;
51 #else
52  int r, fd;
53  const char *e;
54  char *p = NULL;
55  unsigned long l;
56 
57  if (!(e = getenv("LISTEN_PID"))) {
58  r = 0;
59  goto finish;
60  }
61 
62  errno = 0;
63  l = strtoul(e, &p, 10);
64 
65  if (errno != 0) {
66  r = -errno;
67  goto finish;
68  }
69 
70  if (!p || *p || l <= 0) {
71  r = -EINVAL;
72  goto finish;
73  }
74 
75  /* Is this for us? */
76  if (getpid() != (pid_t) l) {
77  r = 0;
78  goto finish;
79  }
80 
81  if (!(e = getenv("LISTEN_FDS"))) {
82  r = 0;
83  goto finish;
84  }
85 
86  errno = 0;
87  l = strtoul(e, &p, 10);
88 
89  if (errno != 0) {
90  r = -errno;
91  goto finish;
92  }
93 
94  if (!p || *p) {
95  r = -EINVAL;
96  goto finish;
97  }
98 
99  for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
100  int flags;
101 
102  if ((flags = fcntl(fd, F_GETFD)) < 0) {
103  r = -errno;
104  goto finish;
105  }
106 
107  if (flags & FD_CLOEXEC)
108  continue;
109 
110  if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
111  r = -errno;
112  goto finish;
113  }
114  }
115 
116  r = (int) l;
117 
118 finish:
119  if (unset_environment) {
120  unsetenv("LISTEN_PID");
121  unsetenv("LISTEN_FDS");
122  }
123 
124  return r;
125 #endif
126 }
127 
128 int sd_is_fifo(int fd, const char *path) {
129  struct stat st_fd;
130 
131  if (fd < 0)
132  return -EINVAL;
133 
134  memset(&st_fd, 0, sizeof(st_fd));
135  if (fstat(fd, &st_fd) < 0)
136  return -errno;
137 
138  if (!S_ISFIFO(st_fd.st_mode))
139  return 0;
140 
141  if (path) {
142  struct stat st_path;
143 
144  memset(&st_path, 0, sizeof(st_path));
145  if (stat(path, &st_path) < 0) {
146 
147  if (errno == ENOENT || errno == ENOTDIR)
148  return 0;
149 
150  return -errno;
151  }
152 
153  return
154  st_path.st_dev == st_fd.st_dev &&
155  st_path.st_ino == st_fd.st_ino;
156  }
157 
158  return 1;
159 }
160 
161 static int sd_is_socket_internal(int fd, int type, int listening) {
162  struct stat st_fd;
163 
164  if (fd < 0 || type < 0)
165  return -EINVAL;
166 
167  if (fstat(fd, &st_fd) < 0)
168  return -errno;
169 
170  if (!S_ISSOCK(st_fd.st_mode))
171  return 0;
172 
173  if (type != 0) {
174  int other_type = 0;
175  socklen_t l = sizeof(other_type);
176 
177  if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
178  return -errno;
179 
180  if (l != sizeof(other_type))
181  return -EINVAL;
182 
183  if (other_type != type)
184  return 0;
185  }
186 
187  if (listening >= 0) {
188  int accepting = 0;
189  socklen_t l = sizeof(accepting);
190 
191  if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
192  return -errno;
193 
194  if (l != sizeof(accepting))
195  return -EINVAL;
196 
197  if (!accepting != !listening)
198  return 0;
199  }
200 
201  return 1;
202 }
203 
205  struct sockaddr sa;
206  struct sockaddr_in in4;
207  struct sockaddr_in6 in6;
208  struct sockaddr_un un;
209  struct sockaddr_storage storage;
210 };
211 
212 int sd_is_socket(int fd, int family, int type, int listening) {
213  int r;
214 
215  if (family < 0)
216  return -EINVAL;
217 
218  if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
219  return r;
220 
221  if (family > 0) {
222  union sockaddr_union sockaddr;
223  socklen_t l;
224 
225  memset(&sockaddr, 0, sizeof(sockaddr));
226  l = sizeof(sockaddr);
227 
228  if (getsockname(fd, &sockaddr.sa, &l) < 0)
229  return -errno;
230 
231  if (l < sizeof(sa_family_t))
232  return -EINVAL;
233 
234  return sockaddr.sa.sa_family == family;
235  }
236 
237  return 1;
238 }
239 
240 int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
241  union sockaddr_union sockaddr;
242  socklen_t l;
243  int r;
244 
245  if (family != 0 && family != AF_INET && family != AF_INET6)
246  return -EINVAL;
247 
248  if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
249  return r;
250 
251  memset(&sockaddr, 0, sizeof(sockaddr));
252  l = sizeof(sockaddr);
253 
254  if (getsockname(fd, &sockaddr.sa, &l) < 0)
255  return -errno;
256 
257  if (l < sizeof(sa_family_t))
258  return -EINVAL;
259 
260  if (sockaddr.sa.sa_family != AF_INET &&
261  sockaddr.sa.sa_family != AF_INET6)
262  return 0;
263 
264  if (family > 0)
265  if (sockaddr.sa.sa_family != family)
266  return 0;
267 
268  if (port > 0) {
269  if (sockaddr.sa.sa_family == AF_INET) {
270  if (l < sizeof(struct sockaddr_in))
271  return -EINVAL;
272 
273  return htons(port) == sockaddr.in4.sin_port;
274  } else {
275  if (l < sizeof(struct sockaddr_in6))
276  return -EINVAL;
277 
278  return htons(port) == sockaddr.in6.sin6_port;
279  }
280  }
281 
282  return 1;
283 }
284 
285 int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
286  union sockaddr_union sockaddr;
287  socklen_t l;
288  int r;
289 
290  if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
291  return r;
292 
293  memset(&sockaddr, 0, sizeof(sockaddr));
294  l = sizeof(sockaddr);
295 
296  if (getsockname(fd, &sockaddr.sa, &l) < 0)
297  return -errno;
298 
299  if (l < sizeof(sa_family_t))
300  return -EINVAL;
301 
302  if (sockaddr.sa.sa_family != AF_UNIX)
303  return 0;
304 
305  if (path) {
306  if (length <= 0)
307  length = strlen(path);
308 
309  if (length <= 0)
310  /* Unnamed socket */
311  return l == offsetof(struct sockaddr_un, sun_path);
312 
313  if (path[0])
314  /* Normal path socket */
315  return
316  (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
317  memcmp(path, sockaddr.un.sun_path, length+1) == 0;
318  else
319  /* Abstract namespace socket */
320  return
321  (l == offsetof(struct sockaddr_un, sun_path) + length) &&
322  memcmp(path, sockaddr.un.sun_path, length) == 0;
323  }
324 
325  return 1;
326 }
327 
328 int sd_notify(int unset_environment, const char *state) {
329 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
330  return 0;
331 #else
332  int fd = -1, r;
333  struct msghdr msghdr;
334  struct iovec iovec;
335  union sockaddr_union sockaddr;
336  const char *e;
337 
338  if (!state) {
339  r = -EINVAL;
340  goto finish;
341  }
342 
343  if (!(e = getenv("NOTIFY_SOCKET")))
344  return 0;
345 
346  /* Must be an abstract socket, or an absolute path */
347  if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
348  r = -EINVAL;
349  goto finish;
350  }
351 
352  if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
353  r = -errno;
354  goto finish;
355  }
356 
357  memset(&sockaddr, 0, sizeof(sockaddr));
358  sockaddr.sa.sa_family = AF_UNIX;
359  strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
360 
361  if (sockaddr.un.sun_path[0] == '@')
362  sockaddr.un.sun_path[0] = 0;
363 
364  memset(&iovec, 0, sizeof(iovec));
365  iovec.iov_base = (char*) state;
366  iovec.iov_len = strlen(state);
367 
368  memset(&msghdr, 0, sizeof(msghdr));
369  msghdr.msg_name = &sockaddr;
370  msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
371 
372  if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
373  msghdr.msg_namelen = sizeof(struct sockaddr_un);
374 
375  msghdr.msg_iov = &iovec;
376  msghdr.msg_iovlen = 1;
377 
378  if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
379  r = -errno;
380  goto finish;
381  }
382 
383  r = 1;
384 
385 finish:
386  if (unset_environment)
387  unsetenv("NOTIFY_SOCKET");
388 
389  if (fd >= 0)
390  close(fd);
391 
392  return r;
393 #endif
394 }
395 
396 int sd_notifyf(int unset_environment, const char *format, ...) {
397 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
398  return 0;
399 #else
400  va_list ap;
401  char *p = NULL;
402  int r;
403 
404  va_start(ap, format);
405  r = vasprintf(&p, format, ap);
406  va_end(ap);
407 
408  if (r < 0 || !p)
409  return -ENOMEM;
410 
411  r = sd_notify(unset_environment, p);
412  free(p);
413 
414  return r;
415 #endif
416 }
417 
418 int sd_booted(void) {
419 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
420  return 0;
421 #else
422 
423  struct stat a, b;
424 
425  /* We simply test whether the systemd cgroup hierarchy is
426  * mounted */
427 
428  if (lstat("/sys/fs/cgroup", &a) < 0)
429  return 0;
430 
431  if (lstat("/sys/fs/cgroup/systemd", &b) < 0)
432  return 0;
433 
434  return a.st_dev != b.st_dev;
435 #endif
436 }
int sd_notify(int unset_environment, const char *state)
Definition: sd-daemon.c:328
int sd_notifyf(int unset_environment, const char *format,...)
Definition: sd-daemon.c:396
int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port)
Definition: sd-daemon.c:240
int sd_is_socket(int fd, int family, int type, int listening)
Definition: sd-daemon.c:212
int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length)
Definition: sd-daemon.c:285
static int sd_is_socket_internal(int fd, int type, int listening)
Definition: sd-daemon.c:161
struct sockaddr_un un
Definition: sd-daemon.c:208
struct sockaddr_in in4
Definition: sd-daemon.c:206
#define SD_LISTEN_FDS_START
Definition: sd-daemon.h:103
int sd_listen_fds(int unset_environment)
Definition: sd-daemon.c:47
static cmdp_state state
struct sockaddr sa
Definition: sd-daemon.c:205
struct sockaddr_in6 in6
Definition: sd-daemon.c:207
int sd_is_fifo(int fd, const char *path)
Definition: sd-daemon.c:128
struct sockaddr_storage storage
Definition: sd-daemon.c:209
int sd_booted(void)
Definition: sd-daemon.c:418