chiark / gitweb /
0842aba9cbfa4ebcfe62c75532743ccb75fefbbd
[elogind.git] / src / libsystemd / sd-daemon / sd-daemon.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/stat.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <netinet/in.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stddef.h>
33 #include <limits.h>
34 #include <mqueue.h>
35
36 #include "util.h"
37 #include "path-util.h"
38 #include "socket-util.h"
39 #include "sd-daemon.h"
40
41 _public_ int sd_listen_fds(int unset_environment) {
42         const char *e;
43         unsigned n;
44         int r, fd;
45         pid_t pid;
46
47         e = getenv("LISTEN_PID");
48         if (!e) {
49                 r = 0;
50                 goto finish;
51         }
52
53         r = parse_pid(e, &pid);
54         if (r < 0)
55                 goto finish;
56
57         /* Is this for us? */
58         if (getpid() != pid) {
59                 r = 0;
60                 goto finish;
61         }
62
63         e = getenv("LISTEN_FDS");
64         if (!e) {
65                 r = 0;
66                 goto finish;
67         }
68
69         r = safe_atou(e, &n);
70         if (r < 0)
71                 goto finish;
72
73         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) n; fd ++) {
74                 r = fd_cloexec(fd, true);
75                 if (r < 0)
76                         goto finish;
77         }
78
79         r = (int) n;
80
81 finish:
82         if (unset_environment) {
83                 unsetenv("LISTEN_PID");
84                 unsetenv("LISTEN_FDS");
85         }
86
87         return r;
88 }
89
90 _public_ int sd_is_fifo(int fd, const char *path) {
91         struct stat st_fd;
92
93         assert_return(fd >= 0, -EINVAL);
94
95         if (fstat(fd, &st_fd) < 0)
96                 return -errno;
97
98         if (!S_ISFIFO(st_fd.st_mode))
99                 return 0;
100
101         if (path) {
102                 struct stat st_path;
103
104                 if (stat(path, &st_path) < 0) {
105
106                         if (errno == ENOENT || errno == ENOTDIR)
107                                 return 0;
108
109                         return -errno;
110                 }
111
112                 return
113                         st_path.st_dev == st_fd.st_dev &&
114                         st_path.st_ino == st_fd.st_ino;
115         }
116
117         return 1;
118 }
119
120 _public_ int sd_is_special(int fd, const char *path) {
121         struct stat st_fd;
122
123         assert_return(fd >= 0, -EINVAL);
124
125         if (fstat(fd, &st_fd) < 0)
126                 return -errno;
127
128         if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
129                 return 0;
130
131         if (path) {
132                 struct stat st_path;
133
134                 if (stat(path, &st_path) < 0) {
135
136                         if (errno == ENOENT || errno == ENOTDIR)
137                                 return 0;
138
139                         return -errno;
140                 }
141
142                 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
143                         return
144                                 st_path.st_dev == st_fd.st_dev &&
145                                 st_path.st_ino == st_fd.st_ino;
146                 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
147                         return st_path.st_rdev == st_fd.st_rdev;
148                 else
149                         return 0;
150         }
151
152         return 1;
153 }
154
155 static int sd_is_socket_internal(int fd, int type, int listening) {
156         struct stat st_fd;
157
158         assert_return(fd >= 0, -EINVAL);
159         assert_return(type >= 0, -EINVAL);
160
161         if (fstat(fd, &st_fd) < 0)
162                 return -errno;
163
164         if (!S_ISSOCK(st_fd.st_mode))
165                 return 0;
166
167         if (type != 0) {
168                 int other_type = 0;
169                 socklen_t l = sizeof(other_type);
170
171                 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
172                         return -errno;
173
174                 if (l != sizeof(other_type))
175                         return -EINVAL;
176
177                 if (other_type != type)
178                         return 0;
179         }
180
181         if (listening >= 0) {
182                 int accepting = 0;
183                 socklen_t l = sizeof(accepting);
184
185                 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
186                         return -errno;
187
188                 if (l != sizeof(accepting))
189                         return -EINVAL;
190
191                 if (!accepting != !listening)
192                         return 0;
193         }
194
195         return 1;
196 }
197
198 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
199         int r;
200
201         assert_return(fd >= 0, -EINVAL);
202         assert_return(family >= 0, -EINVAL);
203
204         r = sd_is_socket_internal(fd, type, listening);
205         if (r <= 0)
206                 return r;
207
208         if (family > 0) {
209                 union sockaddr_union sockaddr = {};
210                 socklen_t l = sizeof(sockaddr);
211
212                 if (getsockname(fd, &sockaddr.sa, &l) < 0)
213                         return -errno;
214
215                 if (l < sizeof(sa_family_t))
216                         return -EINVAL;
217
218                 return sockaddr.sa.sa_family == family;
219         }
220
221         return 1;
222 }
223
224 _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
225         union sockaddr_union sockaddr = {};
226         socklen_t l = sizeof(sockaddr);
227         int r;
228
229         assert_return(fd >= 0, -EINVAL);
230         assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
231
232         r = sd_is_socket_internal(fd, type, listening);
233         if (r <= 0)
234                 return r;
235
236         if (getsockname(fd, &sockaddr.sa, &l) < 0)
237                 return -errno;
238
239         if (l < sizeof(sa_family_t))
240                 return -EINVAL;
241
242         if (sockaddr.sa.sa_family != AF_INET &&
243             sockaddr.sa.sa_family != AF_INET6)
244                 return 0;
245
246         if (family != 0)
247                 if (sockaddr.sa.sa_family != family)
248                         return 0;
249
250         if (port > 0) {
251                 if (sockaddr.sa.sa_family == AF_INET) {
252                         if (l < sizeof(struct sockaddr_in))
253                                 return -EINVAL;
254
255                         return htons(port) == sockaddr.in.sin_port;
256                 } else {
257                         if (l < sizeof(struct sockaddr_in6))
258                                 return -EINVAL;
259
260                         return htons(port) == sockaddr.in6.sin6_port;
261                 }
262         }
263
264         return 1;
265 }
266
267 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
268         union sockaddr_union sockaddr = {};
269         socklen_t l = sizeof(sockaddr);
270         int r;
271
272         assert_return(fd >= 0, -EINVAL);
273
274         r = sd_is_socket_internal(fd, type, listening);
275         if (r <= 0)
276                 return r;
277
278         if (getsockname(fd, &sockaddr.sa, &l) < 0)
279                 return -errno;
280
281         if (l < sizeof(sa_family_t))
282                 return -EINVAL;
283
284         if (sockaddr.sa.sa_family != AF_UNIX)
285                 return 0;
286
287         if (path) {
288                 if (length == 0)
289                         length = strlen(path);
290
291                 if (length == 0)
292                         /* Unnamed socket */
293                         return l == offsetof(struct sockaddr_un, sun_path);
294
295                 if (path[0])
296                         /* Normal path socket */
297                         return
298                                 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
299                                 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
300                 else
301                         /* Abstract namespace socket */
302                         return
303                                 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
304                                 memcmp(path, sockaddr.un.sun_path, length) == 0;
305         }
306
307         return 1;
308 }
309
310 _public_ int sd_is_mq(int fd, const char *path) {
311         struct mq_attr attr;
312
313         assert_return(fd >= 0, -EINVAL);
314
315         if (mq_getattr(fd, &attr) < 0)
316                 return -errno;
317
318         if (path) {
319                 char fpath[PATH_MAX];
320                 struct stat a, b;
321
322                 assert_return(path_is_absolute(path), -EINVAL);
323
324                 if (fstat(fd, &a) < 0)
325                         return -errno;
326
327                 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
328                 fpath[sizeof(fpath)-1] = 0;
329
330                 if (stat(fpath, &b) < 0)
331                         return -errno;
332
333                 if (a.st_dev != b.st_dev ||
334                     a.st_ino != b.st_ino)
335                         return 0;
336         }
337
338         return 1;
339 }
340
341 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
342         union sockaddr_union sockaddr = {
343                 .sa.sa_family = AF_UNIX,
344         };
345         struct iovec iovec = {
346                 .iov_base = (char*) state,
347         };
348         struct msghdr msghdr = {
349                 .msg_iov = &iovec,
350                 .msg_iovlen = 1,
351                 .msg_name = &sockaddr,
352         };
353         struct cmsghdr *control;
354         _cleanup_close_ int fd = -1;
355         struct cmsghdr *cmsg = NULL;
356         const char *e;
357         size_t controllen_without_ucred = 0;
358         bool try_without_ucred = false;
359         int r;
360
361         if (!state) {
362                 r = -EINVAL;
363                 goto finish;
364         }
365
366         if (n_fds > 0 && !fds) {
367                 r = -EINVAL;
368                 goto finish;
369         }
370
371         e = getenv("NOTIFY_SOCKET");
372         if (!e)
373                 return 0;
374
375         /* Must be an abstract socket, or an absolute path */
376         if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
377                 r = -EINVAL;
378                 goto finish;
379         }
380
381         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
382         if (fd < 0) {
383                 r = -errno;
384                 goto finish;
385         }
386
387         iovec.iov_len = strlen(state);
388
389         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
390         if (sockaddr.un.sun_path[0] == '@')
391                 sockaddr.un.sun_path[0] = 0;
392
393         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
394         if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
395                 msghdr.msg_namelen = sizeof(struct sockaddr_un);
396
397         control = alloca(CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int) * n_fds));
398
399         if (n_fds > 0) {
400                 msghdr.msg_control = control;
401                 msghdr.msg_controllen = CMSG_LEN(sizeof(int) * n_fds);
402
403                 cmsg = CMSG_FIRSTHDR(&msghdr);
404                 cmsg->cmsg_level = SOL_SOCKET;
405                 cmsg->cmsg_type = SCM_RIGHTS;
406                 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
407
408                 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
409         }
410
411         if (pid != 0 && pid != getpid()) {
412                 struct ucred *ucred;
413
414                 try_without_ucred = true;
415                 controllen_without_ucred = msghdr.msg_controllen;
416
417                 msghdr.msg_control = control;
418                 msghdr.msg_controllen += CMSG_LEN(sizeof(struct ucred));
419
420                 if (cmsg)
421                         cmsg = CMSG_NXTHDR(&msghdr, cmsg);
422                 else
423                         cmsg = CMSG_FIRSTHDR(&msghdr);
424
425                 cmsg->cmsg_level = SOL_SOCKET;
426                 cmsg->cmsg_type = SCM_CREDENTIALS;
427                 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
428
429                 ucred = (struct ucred*) CMSG_DATA(cmsg);
430                 ucred->pid = pid;
431                 ucred->uid = getuid();
432                 ucred->gid = getgid();
433         }
434
435         /* First try with fake ucred data, as requested */
436         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
437                 r = 1;
438                 goto finish;
439         }
440
441         /* If that failed, try with our own ucred instead */
442         if (try_without_ucred) {
443                 if (controllen_without_ucred <= 0)
444                         msghdr.msg_control = NULL;
445                 msghdr.msg_controllen = controllen_without_ucred;
446
447                 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
448                         r = 1;
449                         goto finish;
450                 }
451         }
452
453         r = -errno;
454
455 finish:
456         if (unset_environment)
457                 unsetenv("NOTIFY_SOCKET");
458
459         return r;
460 }
461
462 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
463         return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
464 }
465
466 _public_ int sd_notify(int unset_environment, const char *state) {
467         return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
468 }
469
470 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
471         _cleanup_free_ char *p = NULL;
472         int r;
473
474         if (format) {
475                 va_list ap;
476
477                 va_start(ap, format);
478                 r = vasprintf(&p, format, ap);
479                 va_end(ap);
480
481                 if (r < 0 || !p)
482                         return -ENOMEM;
483         }
484
485         return sd_pid_notify(pid, unset_environment, p);
486 }
487
488 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
489         _cleanup_free_ char *p = NULL;
490         int r;
491
492         if (format) {
493                 va_list ap;
494
495                 va_start(ap, format);
496                 r = vasprintf(&p, format, ap);
497                 va_end(ap);
498
499                 if (r < 0 || !p)
500                         return -ENOMEM;
501         }
502
503         return sd_pid_notify(0, unset_environment, p);
504 }
505
506 _public_ int sd_booted(void) {
507         struct stat st;
508
509         /* We test whether the runtime unit file directory has been
510          * created. This takes place in mount-setup.c, so is
511          * guaranteed to happen very early during boot. */
512
513         if (lstat("/run/systemd/system/", &st) < 0)
514                 return 0;
515
516         return !!S_ISDIR(st.st_mode);
517 }
518
519 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
520         const char *s, *p = ""; /* p is set to dummy value to do unsetting */
521         uint64_t u;
522         int r = 0;
523
524         s = getenv("WATCHDOG_USEC");
525         if (!s)
526                 goto finish;
527
528         r = safe_atou64(s, &u);
529         if (r < 0)
530                 goto finish;
531         if (u <= 0) {
532                 r = -EINVAL;
533                 goto finish;
534         }
535
536         p = getenv("WATCHDOG_PID");
537         if (p) {
538                 pid_t pid;
539
540                 r = parse_pid(p, &pid);
541                 if (r < 0)
542                         goto finish;
543
544                 /* Is this for us? */
545                 if (getpid() != pid) {
546                         r = 0;
547                         goto finish;
548                 }
549         }
550
551         if (usec)
552                 *usec = u;
553
554         r = 1;
555
556 finish:
557         if (unset_environment && s)
558                 unsetenv("WATCHDOG_USEC");
559         if (unset_environment && p)
560                 unsetenv("WATCHDOG_PID");
561
562         return r;
563 }