chiark / gitweb /
e47da68a66f3cd6a0bcd82998292e15a14b6b8f2
[elogind.git] / src / libelogind / 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 <errno.h>
23 #include <limits.h>
24 //#include <mqueue.h>
25 #include <netinet/in.h>
26 #include <stdarg.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <sys/un.h>
34 #include <unistd.h>
35
36 #include "path-util.h"
37 #include "socket-util.h"
38 //#include "strv.h"
39 #include "util.h"
40
41 #include "sd-daemon.h"
42
43 /// UNNEEDED by elogind
44 #if 0
45 static void unsetenv_all(bool unset_environment) {
46
47         if (!unset_environment)
48                 return;
49
50         unsetenv("LISTEN_PID");
51         unsetenv("LISTEN_FDS");
52         unsetenv("LISTEN_FDNAMES");
53 }
54
55 _public_ int sd_listen_fds(int unset_environment) {
56         const char *e;
57         int n, r, fd;
58         pid_t pid;
59
60         e = getenv("LISTEN_PID");
61         if (!e) {
62                 r = 0;
63                 goto finish;
64         }
65
66         r = parse_pid(e, &pid);
67         if (r < 0)
68                 goto finish;
69
70         /* Is this for us? */
71         if (getpid() != pid) {
72                 r = 0;
73                 goto finish;
74         }
75
76         e = getenv("LISTEN_FDS");
77         if (!e) {
78                 r = 0;
79                 goto finish;
80         }
81
82         r = safe_atoi(e, &n);
83         if (r < 0)
84                 goto finish;
85
86         assert_cc(SD_LISTEN_FDS_START < INT_MAX);
87         if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
88                 r = -EINVAL;
89                 goto finish;
90         }
91
92         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
93                 r = fd_cloexec(fd, true);
94                 if (r < 0)
95                         goto finish;
96         }
97
98         r = n;
99
100 finish:
101         unsetenv_all(unset_environment);
102         return r;
103         }
104
105 _public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
106         _cleanup_strv_free_ char **l = NULL;
107         bool have_names;
108         int n_names = 0, n_fds;
109         const char *e;
110         int r;
111
112         if (!names)
113                 return sd_listen_fds(unset_environment);
114
115         e = getenv("LISTEN_FDNAMES");
116         if (e) {
117                 n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
118                 if (n_names < 0) {
119                         unsetenv_all(unset_environment);
120                         return n_names;
121                 }
122
123                 have_names = true;
124         } else
125                 have_names = false;
126
127         n_fds = sd_listen_fds(unset_environment);
128         if (n_fds <= 0)
129                 return n_fds;
130
131         if (have_names) {
132                 if (n_names != n_fds)
133                         return -EINVAL;
134         } else {
135                 r = strv_extend_n(&l, "unknown", n_fds);
136                 if (r < 0)
137         return r;
138 }
139
140         *names = l;
141         l = NULL;
142
143         return n_fds;
144 }
145
146 _public_ int sd_is_fifo(int fd, const char *path) {
147         struct stat st_fd;
148
149         assert_return(fd >= 0, -EBADF);
150
151         if (fstat(fd, &st_fd) < 0)
152                 return -errno;
153
154         if (!S_ISFIFO(st_fd.st_mode))
155                 return 0;
156
157         if (path) {
158                 struct stat st_path;
159
160                 if (stat(path, &st_path) < 0) {
161
162                         if (errno == ENOENT || errno == ENOTDIR)
163                                 return 0;
164
165                         return -errno;
166                 }
167
168                 return
169                         st_path.st_dev == st_fd.st_dev &&
170                         st_path.st_ino == st_fd.st_ino;
171         }
172
173         return 1;
174 }
175
176 _public_ int sd_is_special(int fd, const char *path) {
177         struct stat st_fd;
178
179         assert_return(fd >= 0, -EBADF);
180
181         if (fstat(fd, &st_fd) < 0)
182                 return -errno;
183
184         if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
185                 return 0;
186
187         if (path) {
188                 struct stat st_path;
189
190                 if (stat(path, &st_path) < 0) {
191
192                         if (errno == ENOENT || errno == ENOTDIR)
193                                 return 0;
194
195                         return -errno;
196                 }
197
198                 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
199                         return
200                                 st_path.st_dev == st_fd.st_dev &&
201                                 st_path.st_ino == st_fd.st_ino;
202                 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
203                         return st_path.st_rdev == st_fd.st_rdev;
204                 else
205                         return 0;
206         }
207
208         return 1;
209 }
210 #endif // 0
211
212 static int sd_is_socket_internal(int fd, int type, int listening) {
213         struct stat st_fd;
214
215         assert_return(fd >= 0, -EBADF);
216         assert_return(type >= 0, -EINVAL);
217
218         if (fstat(fd, &st_fd) < 0)
219                 return -errno;
220
221         if (!S_ISSOCK(st_fd.st_mode))
222                 return 0;
223
224         if (type != 0) {
225                 int other_type = 0;
226                 socklen_t l = sizeof(other_type);
227
228                 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
229                         return -errno;
230
231                 if (l != sizeof(other_type))
232                         return -EINVAL;
233
234                 if (other_type != type)
235                         return 0;
236         }
237
238         if (listening >= 0) {
239                 int accepting = 0;
240                 socklen_t l = sizeof(accepting);
241
242                 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
243                         return -errno;
244
245                 if (l != sizeof(accepting))
246                         return -EINVAL;
247
248                 if (!accepting != !listening)
249                         return 0;
250         }
251
252         return 1;
253 }
254
255 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
256         int r;
257
258         assert_return(fd >= 0, -EBADF);
259         assert_return(family >= 0, -EINVAL);
260
261         r = sd_is_socket_internal(fd, type, listening);
262         if (r <= 0)
263                 return r;
264
265         if (family > 0) {
266                 union sockaddr_union sockaddr = {};
267                 socklen_t l = sizeof(sockaddr);
268
269                 if (getsockname(fd, &sockaddr.sa, &l) < 0)
270                         return -errno;
271
272                 if (l < sizeof(sa_family_t))
273                         return -EINVAL;
274
275                 return sockaddr.sa.sa_family == family;
276         }
277
278         return 1;
279 }
280
281 /// UNNEEDED by elogind
282 #if 0
283 _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
284         union sockaddr_union sockaddr = {};
285         socklen_t l = sizeof(sockaddr);
286         int r;
287
288         assert_return(fd >= 0, -EBADF);
289         assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
290
291         r = sd_is_socket_internal(fd, type, listening);
292         if (r <= 0)
293                 return r;
294
295         if (getsockname(fd, &sockaddr.sa, &l) < 0)
296                 return -errno;
297
298         if (l < sizeof(sa_family_t))
299                 return -EINVAL;
300
301         if (sockaddr.sa.sa_family != AF_INET &&
302             sockaddr.sa.sa_family != AF_INET6)
303                 return 0;
304
305         if (family != 0)
306                 if (sockaddr.sa.sa_family != family)
307                         return 0;
308
309         if (port > 0) {
310                 if (sockaddr.sa.sa_family == AF_INET) {
311                         if (l < sizeof(struct sockaddr_in))
312                                 return -EINVAL;
313
314                         return htons(port) == sockaddr.in.sin_port;
315                 } else {
316                         if (l < sizeof(struct sockaddr_in6))
317                                 return -EINVAL;
318
319                         return htons(port) == sockaddr.in6.sin6_port;
320                 }
321         }
322
323         return 1;
324 }
325
326 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
327         union sockaddr_union sockaddr = {};
328         socklen_t l = sizeof(sockaddr);
329         int r;
330
331         assert_return(fd >= 0, -EBADF);
332
333         r = sd_is_socket_internal(fd, type, listening);
334         if (r <= 0)
335                 return r;
336
337         if (getsockname(fd, &sockaddr.sa, &l) < 0)
338                 return -errno;
339
340         if (l < sizeof(sa_family_t))
341                 return -EINVAL;
342
343         if (sockaddr.sa.sa_family != AF_UNIX)
344                 return 0;
345
346         if (path) {
347                 if (length == 0)
348                         length = strlen(path);
349
350                 if (length == 0)
351                         /* Unnamed socket */
352                         return l == offsetof(struct sockaddr_un, sun_path);
353
354                 if (path[0])
355                         /* Normal path socket */
356                         return
357                                 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
358                                 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
359                 else
360                         /* Abstract namespace socket */
361                         return
362                                 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
363                                 memcmp(path, sockaddr.un.sun_path, length) == 0;
364         }
365
366         return 1;
367 }
368
369 _public_ int sd_is_mq(int fd, const char *path) {
370         struct mq_attr attr;
371
372         /* Check that the fd is valid */
373         assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
374
375         if (mq_getattr(fd, &attr) < 0) {
376                 if (errno == EBADF)
377                         /* A non-mq fd (or an invalid one, but we ruled that out above) */
378                         return 0;
379                 return -errno;
380         }
381
382         if (path) {
383                 char fpath[PATH_MAX];
384                 struct stat a, b;
385
386                 assert_return(path_is_absolute(path), -EINVAL);
387
388                 if (fstat(fd, &a) < 0)
389                         return -errno;
390
391                 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
392                 fpath[sizeof(fpath)-1] = 0;
393
394                 if (stat(fpath, &b) < 0)
395                         return -errno;
396
397                 if (a.st_dev != b.st_dev ||
398                     a.st_ino != b.st_ino)
399                         return 0;
400         }
401
402         return 1;
403 }
404 #endif // 0
405
406 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
407         union sockaddr_union sockaddr = {
408                 .sa.sa_family = AF_UNIX,
409         };
410         struct iovec iovec = {
411                 .iov_base = (char*) state,
412         };
413         struct msghdr msghdr = {
414                 .msg_iov = &iovec,
415                 .msg_iovlen = 1,
416                 .msg_name = &sockaddr,
417         };
418         _cleanup_close_ int fd = -1;
419         struct cmsghdr *cmsg = NULL;
420         const char *e;
421         bool have_pid;
422         int r;
423
424         if (!state) {
425                 r = -EINVAL;
426                 goto finish;
427         }
428
429         if (n_fds > 0 && !fds) {
430                 r = -EINVAL;
431                 goto finish;
432         }
433
434         e = getenv("NOTIFY_SOCKET");
435         if (!e)
436                 return 0;
437
438         /* Must be an abstract socket, or an absolute path */
439         if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
440                 r = -EINVAL;
441                 goto finish;
442         }
443
444         if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
445                 r = -EINVAL;
446                 goto finish;
447         }
448
449         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
450         if (fd < 0) {
451                 r = -errno;
452                 goto finish;
453         }
454
455         iovec.iov_len = strlen(state);
456
457         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
458         if (sockaddr.un.sun_path[0] == '@')
459                 sockaddr.un.sun_path[0] = 0;
460
461         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);
464
465         have_pid = pid != 0 && pid != getpid();
466
467         if (n_fds > 0 || have_pid) {
468                 /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
469                 msghdr.msg_controllen =
470                         (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
471                         (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
472
473                 msghdr.msg_control = alloca0(msghdr.msg_controllen);
474
475                 cmsg = CMSG_FIRSTHDR(&msghdr);
476                 if (n_fds > 0) {
477                         cmsg->cmsg_level = SOL_SOCKET;
478                         cmsg->cmsg_type = SCM_RIGHTS;
479                         cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
480
481                         memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
482
483                         if (have_pid)
484                                 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
485                 }
486
487                 if (have_pid) {
488                         struct ucred *ucred;
489
490                         cmsg->cmsg_level = SOL_SOCKET;
491                         cmsg->cmsg_type = SCM_CREDENTIALS;
492                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
493
494                         ucred = (struct ucred*) CMSG_DATA(cmsg);
495                         ucred->pid = pid;
496                         ucred->uid = getuid();
497                         ucred->gid = getgid();
498                 }
499         }
500
501         /* First try with fake ucred data, as requested */
502         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
503                 r = 1;
504                 goto finish;
505         }
506
507         /* If that failed, try with our own ucred instead */
508         if (have_pid) {
509                 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
510                 if (msghdr.msg_controllen == 0)
511                         msghdr.msg_control = NULL;
512
513                 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
514                         r = 1;
515                         goto finish;
516                 }
517         }
518
519         r = -errno;
520
521 finish:
522         if (unset_environment)
523                 unsetenv("NOTIFY_SOCKET");
524
525         return r;
526 }
527
528 /// UNNEEDED by elogind
529 #if 0
530 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
531         return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
532 }
533 #endif // 0
534
535 _public_ int sd_notify(int unset_environment, const char *state) {
536         return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
537 }
538
539 /// UNNEEDED by elogind
540 #if 0
541 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
542         _cleanup_free_ char *p = NULL;
543         int r;
544
545         if (format) {
546                 va_list ap;
547
548                 va_start(ap, format);
549                 r = vasprintf(&p, format, ap);
550                 va_end(ap);
551
552                 if (r < 0 || !p)
553                         return -ENOMEM;
554         }
555
556         return sd_pid_notify(pid, unset_environment, p);
557 }
558
559 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
560         _cleanup_free_ char *p = NULL;
561         int r;
562
563         if (format) {
564                 va_list ap;
565
566                 va_start(ap, format);
567                 r = vasprintf(&p, format, ap);
568                 va_end(ap);
569
570                 if (r < 0 || !p)
571                         return -ENOMEM;
572         }
573
574         return sd_pid_notify(0, unset_environment, p);
575 }
576
577 _public_ int sd_booted(void) {
578         /* We test whether the runtime unit file directory has been
579          * created. This takes place in mount-setup.c, so is
580          * guaranteed to happen very early during boot. */
581
582         return laccess("/run/systemd/system/", F_OK) >= 0;
583 }
584 #endif // 0
585
586 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
587         const char *s, *p = ""; /* p is set to dummy value to do unsetting */
588         uint64_t u;
589         int r = 0;
590
591         s = getenv("WATCHDOG_USEC");
592         if (!s)
593                 goto finish;
594
595         r = safe_atou64(s, &u);
596         if (r < 0)
597                 goto finish;
598         if (u <= 0 || u >= USEC_INFINITY) {
599                 r = -EINVAL;
600                 goto finish;
601         }
602
603         p = getenv("WATCHDOG_PID");
604         if (p) {
605                 pid_t pid;
606
607                 r = parse_pid(p, &pid);
608                 if (r < 0)
609                         goto finish;
610
611                 /* Is this for us? */
612                 if (getpid() != pid) {
613                         r = 0;
614                         goto finish;
615                 }
616         }
617
618         if (usec)
619                 *usec = u;
620
621         r = 1;
622
623 finish:
624         if (unset_environment && s)
625                 unsetenv("WATCHDOG_USEC");
626         if (unset_environment && p)
627                 unsetenv("WATCHDOG_PID");
628
629         return r;
630 }