chiark / gitweb /
85edfea2135ac9d8f89bc62db6f7b4d2cb248aeb
[elogind.git] / src / libelogind / sd-daemon / sd-daemon.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <limits.h>
22 #include <mqueue.h>
23 #include <netinet/in.h>
24 #include <stdarg.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/un.h>
32 #include <unistd.h>
33
34 #include "sd-daemon.h"
35
36 #include "alloc-util.h"
37 #include "fd-util.h"
38 //#include "fs-util.h"
39 #include "parse-util.h"
40 #include "path-util.h"
41 #include "socket-util.h"
42 #include "strv.h"
43 #include "util.h"
44
45 #define SNDBUF_SIZE (8*1024*1024)
46
47 #if 0 /// UNNEEDED by elogind
48 static void unsetenv_all(bool unset_environment) {
49
50         if (!unset_environment)
51                 return;
52
53         unsetenv("LISTEN_PID");
54         unsetenv("LISTEN_FDS");
55         unsetenv("LISTEN_FDNAMES");
56 }
57
58 _public_ int sd_listen_fds(int unset_environment) {
59         const char *e;
60         int n, r, fd;
61         pid_t pid;
62
63         e = getenv("LISTEN_PID");
64         if (!e) {
65                 r = 0;
66                 goto finish;
67         }
68
69         r = parse_pid(e, &pid);
70         if (r < 0)
71                 goto finish;
72
73         /* Is this for us? */
74         if (getpid() != pid) {
75                 r = 0;
76                 goto finish;
77         }
78
79         e = getenv("LISTEN_FDS");
80         if (!e) {
81                 r = 0;
82                 goto finish;
83         }
84
85         r = safe_atoi(e, &n);
86         if (r < 0)
87                 goto finish;
88
89         assert_cc(SD_LISTEN_FDS_START < INT_MAX);
90         if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
91                 r = -EINVAL;
92                 goto finish;
93         }
94
95         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
96                 r = fd_cloexec(fd, true);
97                 if (r < 0)
98                         goto finish;
99         }
100
101         r = n;
102
103 finish:
104         unsetenv_all(unset_environment);
105         return r;
106 }
107
108 _public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
109         _cleanup_strv_free_ char **l = NULL;
110         bool have_names;
111         int n_names = 0, n_fds;
112         const char *e;
113         int r;
114
115         if (!names)
116                 return sd_listen_fds(unset_environment);
117
118         e = getenv("LISTEN_FDNAMES");
119         if (e) {
120                 n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
121                 if (n_names < 0) {
122                         unsetenv_all(unset_environment);
123                         return n_names;
124                 }
125
126                 have_names = true;
127         } else
128                 have_names = false;
129
130         n_fds = sd_listen_fds(unset_environment);
131         if (n_fds <= 0)
132                 return n_fds;
133
134         if (have_names) {
135                 if (n_names != n_fds)
136                         return -EINVAL;
137         } else {
138                 r = strv_extend_n(&l, "unknown", n_fds);
139                 if (r < 0)
140                         return r;
141         }
142
143         *names = l;
144         l = NULL;
145
146         return n_fds;
147 }
148
149 _public_ int sd_is_fifo(int fd, const char *path) {
150         struct stat st_fd;
151
152         assert_return(fd >= 0, -EBADF);
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 _public_ int sd_is_special(int fd, const char *path) {
180         struct stat st_fd;
181
182         assert_return(fd >= 0, -EBADF);
183
184         if (fstat(fd, &st_fd) < 0)
185                 return -errno;
186
187         if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
188                 return 0;
189
190         if (path) {
191                 struct stat st_path;
192
193                 if (stat(path, &st_path) < 0) {
194
195                         if (errno == ENOENT || errno == ENOTDIR)
196                                 return 0;
197
198                         return -errno;
199                 }
200
201                 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
202                         return
203                                 st_path.st_dev == st_fd.st_dev &&
204                                 st_path.st_ino == st_fd.st_ino;
205                 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
206                         return st_path.st_rdev == st_fd.st_rdev;
207                 else
208                         return 0;
209         }
210
211         return 1;
212 }
213 #endif // 0
214
215 static int sd_is_socket_internal(int fd, int type, int listening) {
216         struct stat st_fd;
217
218         assert_return(fd >= 0, -EBADF);
219         assert_return(type >= 0, -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 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
259         int r;
260
261         assert_return(fd >= 0, -EBADF);
262         assert_return(family >= 0, -EINVAL);
263
264         r = sd_is_socket_internal(fd, type, listening);
265         if (r <= 0)
266                 return r;
267
268         if (family > 0) {
269                 union sockaddr_union sockaddr = {};
270                 socklen_t l = sizeof(sockaddr);
271
272                 if (getsockname(fd, &sockaddr.sa, &l) < 0)
273                         return -errno;
274
275                 if (l < sizeof(sa_family_t))
276                         return -EINVAL;
277
278                 return sockaddr.sa.sa_family == family;
279         }
280
281         return 1;
282 }
283
284 #if 0 /// UNNEEDED by elogind
285 _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
286         union sockaddr_union sockaddr = {};
287         socklen_t l = sizeof(sockaddr);
288         int r;
289
290         assert_return(fd >= 0, -EBADF);
291         assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
292
293         r = sd_is_socket_internal(fd, type, listening);
294         if (r <= 0)
295                 return r;
296
297         if (getsockname(fd, &sockaddr.sa, &l) < 0)
298                 return -errno;
299
300         if (l < sizeof(sa_family_t))
301                 return -EINVAL;
302
303         if (sockaddr.sa.sa_family != AF_INET &&
304             sockaddr.sa.sa_family != AF_INET6)
305                 return 0;
306
307         if (family != 0)
308                 if (sockaddr.sa.sa_family != family)
309                         return 0;
310
311         if (port > 0) {
312                 if (sockaddr.sa.sa_family == AF_INET) {
313                         if (l < sizeof(struct sockaddr_in))
314                                 return -EINVAL;
315
316                         return htons(port) == sockaddr.in.sin_port;
317                 } else {
318                         if (l < sizeof(struct sockaddr_in6))
319                                 return -EINVAL;
320
321                         return htons(port) == sockaddr.in6.sin6_port;
322                 }
323         }
324
325         return 1;
326 }
327
328 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
329         union sockaddr_union sockaddr = {};
330         socklen_t l = sizeof(sockaddr);
331         int r;
332
333         assert_return(fd >= 0, -EBADF);
334
335         r = sd_is_socket_internal(fd, type, listening);
336         if (r <= 0)
337                 return r;
338
339         if (getsockname(fd, &sockaddr.sa, &l) < 0)
340                 return -errno;
341
342         if (l < sizeof(sa_family_t))
343                 return -EINVAL;
344
345         if (sockaddr.sa.sa_family != AF_UNIX)
346                 return 0;
347
348         if (path) {
349                 if (length == 0)
350                         length = strlen(path);
351
352                 if (length == 0)
353                         /* Unnamed socket */
354                         return l == offsetof(struct sockaddr_un, sun_path);
355
356                 if (path[0])
357                         /* Normal path socket */
358                         return
359                                 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
360                                 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
361                 else
362                         /* Abstract namespace socket */
363                         return
364                                 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
365                                 memcmp(path, sockaddr.un.sun_path, length) == 0;
366         }
367
368         return 1;
369 }
370
371 _public_ int sd_is_mq(int fd, const char *path) {
372         struct mq_attr attr;
373
374         /* Check that the fd is valid */
375         assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
376
377         if (mq_getattr(fd, &attr) < 0) {
378                 if (errno == EBADF)
379                         /* A non-mq fd (or an invalid one, but we ruled that out above) */
380                         return 0;
381                 return -errno;
382         }
383
384         if (path) {
385                 char fpath[PATH_MAX];
386                 struct stat a, b;
387
388                 assert_return(path_is_absolute(path), -EINVAL);
389
390                 if (fstat(fd, &a) < 0)
391                         return -errno;
392
393                 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
394                 fpath[sizeof(fpath)-1] = 0;
395
396                 if (stat(fpath, &b) < 0)
397                         return -errno;
398
399                 if (a.st_dev != b.st_dev ||
400                     a.st_ino != b.st_ino)
401                         return 0;
402         }
403
404         return 1;
405 }
406 #endif // 0
407
408 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
409         union sockaddr_union sockaddr = {
410                 .sa.sa_family = AF_UNIX,
411         };
412         struct iovec iovec = {
413                 .iov_base = (char*) state,
414         };
415         struct msghdr msghdr = {
416                 .msg_iov = &iovec,
417                 .msg_iovlen = 1,
418                 .msg_name = &sockaddr,
419         };
420         _cleanup_close_ int fd = -1;
421         struct cmsghdr *cmsg = NULL;
422         const char *e;
423         bool have_pid;
424         int r;
425
426         if (!state) {
427                 r = -EINVAL;
428                 goto finish;
429         }
430
431         if (n_fds > 0 && !fds) {
432                 r = -EINVAL;
433                 goto finish;
434         }
435
436         e = getenv("NOTIFY_SOCKET");
437         if (!e)
438                 return 0;
439
440         /* Must be an abstract socket, or an absolute path */
441         if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
442                 r = -EINVAL;
443                 goto finish;
444         }
445
446         if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
447                 r = -EINVAL;
448                 goto finish;
449         }
450
451         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
452         if (fd < 0) {
453                 r = -errno;
454                 goto finish;
455         }
456
457         fd_inc_sndbuf(fd, SNDBUF_SIZE);
458
459         iovec.iov_len = strlen(state);
460
461         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
462         if (sockaddr.un.sun_path[0] == '@')
463                 sockaddr.un.sun_path[0] = 0;
464
465         msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
466
467         have_pid = pid != 0 && pid != getpid();
468
469         if (n_fds > 0 || have_pid) {
470                 /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
471                 msghdr.msg_controllen =
472                         (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
473                         (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
474
475                 msghdr.msg_control = alloca0(msghdr.msg_controllen);
476
477                 cmsg = CMSG_FIRSTHDR(&msghdr);
478                 if (n_fds > 0) {
479                         cmsg->cmsg_level = SOL_SOCKET;
480                         cmsg->cmsg_type = SCM_RIGHTS;
481                         cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
482
483                         memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
484
485                         if (have_pid)
486                                 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
487                 }
488
489                 if (have_pid) {
490                         struct ucred *ucred;
491
492                         cmsg->cmsg_level = SOL_SOCKET;
493                         cmsg->cmsg_type = SCM_CREDENTIALS;
494                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
495
496                         ucred = (struct ucred*) CMSG_DATA(cmsg);
497                         ucred->pid = pid;
498                         ucred->uid = getuid();
499                         ucred->gid = getgid();
500                 }
501         }
502
503         /* First try with fake ucred data, as requested */
504         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
505                 r = 1;
506                 goto finish;
507         }
508
509         /* If that failed, try with our own ucred instead */
510         if (have_pid) {
511                 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
512                 if (msghdr.msg_controllen == 0)
513                         msghdr.msg_control = NULL;
514
515                 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
516                         r = 1;
517                         goto finish;
518                 }
519         }
520
521         r = -errno;
522
523 finish:
524         if (unset_environment)
525                 unsetenv("NOTIFY_SOCKET");
526
527         return r;
528 }
529
530 #if 0 /// UNNEEDED by elogind
531 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
532         return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
533 }
534 #endif // 0
535
536 _public_ int sd_notify(int unset_environment, const char *state) {
537         return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
538 }
539
540 #if 0 /// UNNEEDED by elogind
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 }