chiark / gitweb /
libelogind: use IN_SET macro
[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 static void unsetenv_all(bool unset_environment) {
48
49         if (!unset_environment)
50                 return;
51
52         unsetenv("LISTEN_PID");
53         unsetenv("LISTEN_FDS");
54         unsetenv("LISTEN_FDNAMES");
55 }
56
57 _public_ int sd_listen_fds(int unset_environment) {
58         const char *e;
59         int n, r, fd;
60         pid_t pid;
61
62         e = getenv("LISTEN_PID");
63         if (!e) {
64                 r = 0;
65                 goto finish;
66         }
67
68         r = parse_pid(e, &pid);
69         if (r < 0)
70                 goto finish;
71
72         /* Is this for us? */
73         if (getpid_cached() != pid) {
74                 r = 0;
75                 goto finish;
76         }
77
78         e = getenv("LISTEN_FDS");
79         if (!e) {
80                 r = 0;
81                 goto finish;
82         }
83
84         r = safe_atoi(e, &n);
85         if (r < 0)
86                 goto finish;
87
88         assert_cc(SD_LISTEN_FDS_START < INT_MAX);
89         if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
90                 r = -EINVAL;
91                 goto finish;
92         }
93
94         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
95                 r = fd_cloexec(fd, true);
96                 if (r < 0)
97                         goto finish;
98         }
99
100         r = n;
101
102 finish:
103         unsetenv_all(unset_environment);
104         return r;
105 }
106
107 _public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
108         _cleanup_strv_free_ char **l = NULL;
109         bool have_names;
110         int n_names = 0, n_fds;
111         const char *e;
112         int r;
113
114         if (!names)
115                 return sd_listen_fds(unset_environment);
116
117         e = getenv("LISTEN_FDNAMES");
118         if (e) {
119                 n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
120                 if (n_names < 0) {
121                         unsetenv_all(unset_environment);
122                         return n_names;
123                 }
124
125                 have_names = true;
126         } else
127                 have_names = false;
128
129         n_fds = sd_listen_fds(unset_environment);
130         if (n_fds <= 0)
131                 return n_fds;
132
133         if (have_names) {
134                 if (n_names != n_fds)
135                         return -EINVAL;
136         } else {
137                 r = strv_extend_n(&l, "unknown", n_fds);
138                 if (r < 0)
139                         return r;
140         }
141
142         *names = l;
143         l = NULL;
144
145         return n_fds;
146 }
147
148 #if 0 /// UNNEEDED by elogind
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 (IN_SET(errno, ENOENT, 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 (IN_SET(errno, ENOENT, 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 (!IN_SET(sockaddr.sa.sa_family, AF_INET, AF_INET6))
304                 return 0;
305
306         if (family != 0)
307                 if (sockaddr.sa.sa_family != family)
308                         return 0;
309
310         if (port > 0) {
311                 if (sockaddr.sa.sa_family == AF_INET) {
312                         if (l < sizeof(struct sockaddr_in))
313                                 return -EINVAL;
314
315                         return htobe16(port) == sockaddr.in.sin_port;
316                 } else {
317                         if (l < sizeof(struct sockaddr_in6))
318                                 return -EINVAL;
319
320                         return htobe16(port) == sockaddr.in6.sin6_port;
321                 }
322         }
323
324         return 1;
325 }
326
327 _public_ int sd_is_socket_sockaddr(int fd, int type, const struct sockaddr* addr, unsigned addr_len, int listening) {
328         union sockaddr_union sockaddr = {};
329         socklen_t l = sizeof(sockaddr);
330         int r;
331
332         assert_return(fd >= 0, -EBADF);
333         assert_return(addr, -EINVAL);
334         assert_return(addr_len >= sizeof(sa_family_t), -ENOBUFS);
335         assert_return(IN_SET(addr->sa_family, AF_INET, AF_INET6), -EPFNOSUPPORT);
336
337         r = sd_is_socket_internal(fd, type, listening);
338         if (r <= 0)
339                 return r;
340
341         if (getsockname(fd, &sockaddr.sa, &l) < 0)
342                 return -errno;
343
344         if (l < sizeof(sa_family_t))
345                 return -EINVAL;
346
347         if (sockaddr.sa.sa_family != addr->sa_family)
348                 return 0;
349
350         if (sockaddr.sa.sa_family == AF_INET) {
351                 const struct sockaddr_in *in = (const struct sockaddr_in *) addr;
352
353                 if (l < sizeof(struct sockaddr_in) || addr_len < sizeof(struct sockaddr_in))
354                         return -EINVAL;
355
356                 if (in->sin_port != 0 &&
357                     sockaddr.in.sin_port != in->sin_port)
358                         return false;
359
360                 return sockaddr.in.sin_addr.s_addr == in->sin_addr.s_addr;
361
362         } else {
363                 const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) addr;
364
365                 if (l < sizeof(struct sockaddr_in6) || addr_len < sizeof(struct sockaddr_in6))
366                         return -EINVAL;
367
368                 if (in->sin6_port != 0 &&
369                     sockaddr.in6.sin6_port != in->sin6_port)
370                         return false;
371
372                 if (in->sin6_flowinfo != 0 &&
373                     sockaddr.in6.sin6_flowinfo != in->sin6_flowinfo)
374                         return false;
375
376                 if (in->sin6_scope_id != 0 &&
377                     sockaddr.in6.sin6_scope_id != in->sin6_scope_id)
378                         return false;
379
380                 return memcmp(sockaddr.in6.sin6_addr.s6_addr, in->sin6_addr.s6_addr,
381                               sizeof(in->sin6_addr.s6_addr)) == 0;
382         }
383 }
384
385 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
386         union sockaddr_union sockaddr = {};
387         socklen_t l = sizeof(sockaddr);
388         int r;
389
390         assert_return(fd >= 0, -EBADF);
391
392         r = sd_is_socket_internal(fd, type, listening);
393         if (r <= 0)
394                 return r;
395
396         if (getsockname(fd, &sockaddr.sa, &l) < 0)
397                 return -errno;
398
399         if (l < sizeof(sa_family_t))
400                 return -EINVAL;
401
402         if (sockaddr.sa.sa_family != AF_UNIX)
403                 return 0;
404
405         if (path) {
406                 if (length == 0)
407                         length = strlen(path);
408
409                 if (length == 0)
410                         /* Unnamed socket */
411                         return l == offsetof(struct sockaddr_un, sun_path);
412
413                 if (path[0])
414                         /* Normal path socket */
415                         return
416                                 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
417                                 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
418                 else
419                         /* Abstract namespace socket */
420                         return
421                                 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
422                                 memcmp(path, sockaddr.un.sun_path, length) == 0;
423         }
424
425         return 1;
426 }
427
428 _public_ int sd_is_mq(int fd, const char *path) {
429         struct mq_attr attr;
430
431         /* Check that the fd is valid */
432         assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
433
434         if (mq_getattr(fd, &attr) < 0) {
435                 if (errno == EBADF)
436                         /* A non-mq fd (or an invalid one, but we ruled that out above) */
437                         return 0;
438                 return -errno;
439         }
440
441         if (path) {
442                 char fpath[PATH_MAX];
443                 struct stat a, b;
444
445                 assert_return(path_is_absolute(path), -EINVAL);
446
447                 if (fstat(fd, &a) < 0)
448                         return -errno;
449
450                 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
451                 fpath[sizeof(fpath)-1] = 0;
452
453                 if (stat(fpath, &b) < 0)
454                         return -errno;
455
456                 if (a.st_dev != b.st_dev ||
457                     a.st_ino != b.st_ino)
458                         return 0;
459         }
460
461         return 1;
462 }
463 #endif // 0
464
465 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
466         union sockaddr_union sockaddr = {
467                 .sa.sa_family = AF_UNIX,
468         };
469         struct iovec iovec = {
470                 .iov_base = (char*) state,
471         };
472         struct msghdr msghdr = {
473                 .msg_iov = &iovec,
474                 .msg_iovlen = 1,
475                 .msg_name = &sockaddr,
476         };
477         _cleanup_close_ int fd = -1;
478         struct cmsghdr *cmsg = NULL;
479         const char *e;
480         bool have_pid;
481         int r;
482
483         if (!state) {
484                 r = -EINVAL;
485                 goto finish;
486         }
487
488         if (n_fds > 0 && !fds) {
489                 r = -EINVAL;
490                 goto finish;
491         }
492
493         e = getenv("NOTIFY_SOCKET");
494         if (!e)
495                 return 0;
496
497         /* Must be an abstract socket, or an absolute path */
498         if (!IN_SET(e[0], '@', '/') || e[1] == 0) {
499                 r = -EINVAL;
500                 goto finish;
501         }
502
503         if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
504                 r = -EINVAL;
505                 goto finish;
506         }
507
508         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
509         if (fd < 0) {
510                 r = -errno;
511                 goto finish;
512         }
513
514         fd_inc_sndbuf(fd, SNDBUF_SIZE);
515
516         iovec.iov_len = strlen(state);
517
518         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
519         if (sockaddr.un.sun_path[0] == '@')
520                 sockaddr.un.sun_path[0] = 0;
521
522         msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
523
524         have_pid = pid != 0 && pid != getpid_cached();
525
526         if (n_fds > 0 || have_pid) {
527                 /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
528                 msghdr.msg_controllen =
529                         (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
530                         (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
531
532                 msghdr.msg_control = alloca0(msghdr.msg_controllen);
533
534                 cmsg = CMSG_FIRSTHDR(&msghdr);
535                 if (n_fds > 0) {
536                         cmsg->cmsg_level = SOL_SOCKET;
537                         cmsg->cmsg_type = SCM_RIGHTS;
538                         cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
539
540                         memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
541
542                         if (have_pid)
543                                 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
544                 }
545
546                 if (have_pid) {
547                         struct ucred *ucred;
548
549                         cmsg->cmsg_level = SOL_SOCKET;
550                         cmsg->cmsg_type = SCM_CREDENTIALS;
551                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
552
553                         ucred = (struct ucred*) CMSG_DATA(cmsg);
554                         ucred->pid = pid;
555                         ucred->uid = getuid();
556                         ucred->gid = getgid();
557                 }
558         }
559
560         /* First try with fake ucred data, as requested */
561         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
562                 r = 1;
563                 goto finish;
564         }
565
566         /* If that failed, try with our own ucred instead */
567         if (have_pid) {
568                 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
569                 if (msghdr.msg_controllen == 0)
570                         msghdr.msg_control = NULL;
571
572                 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
573                         r = 1;
574                         goto finish;
575                 }
576         }
577
578         r = -errno;
579
580 finish:
581         if (unset_environment)
582                 unsetenv("NOTIFY_SOCKET");
583
584         return r;
585 }
586
587 #if 0 /// UNNEEDED by elogind
588 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
589         return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
590 }
591 #endif // 0
592
593 _public_ int sd_notify(int unset_environment, const char *state) {
594         return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
595 }
596
597 #if 0 /// UNNEEDED by elogind
598 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
599         _cleanup_free_ char *p = NULL;
600         int r;
601
602         if (format) {
603                 va_list ap;
604
605                 va_start(ap, format);
606                 r = vasprintf(&p, format, ap);
607                 va_end(ap);
608
609                 if (r < 0 || !p)
610                         return -ENOMEM;
611         }
612
613         return sd_pid_notify(pid, unset_environment, p);
614 }
615
616 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
617         _cleanup_free_ char *p = NULL;
618         int r;
619
620         if (format) {
621                 va_list ap;
622
623                 va_start(ap, format);
624                 r = vasprintf(&p, format, ap);
625                 va_end(ap);
626
627                 if (r < 0 || !p)
628                         return -ENOMEM;
629         }
630
631         return sd_pid_notify(0, unset_environment, p);
632 }
633 #endif // 0
634
635 _public_ int sd_booted(void) {
636         /* We test whether the runtime unit file directory has been
637          * created. This takes place in mount-setup.c, so is
638          * guaranteed to happen very early during boot. */
639
640         return laccess("/run/systemd/system/", F_OK) >= 0;
641 }
642
643 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
644         const char *s, *p = ""; /* p is set to dummy value to do unsetting */
645         uint64_t u;
646         int r = 0;
647
648         s = getenv("WATCHDOG_USEC");
649         if (!s)
650                 goto finish;
651
652         r = safe_atou64(s, &u);
653         if (r < 0)
654                 goto finish;
655         if (u <= 0 || u >= USEC_INFINITY) {
656                 r = -EINVAL;
657                 goto finish;
658         }
659
660         p = getenv("WATCHDOG_PID");
661         if (p) {
662                 pid_t pid;
663
664                 r = parse_pid(p, &pid);
665                 if (r < 0)
666                         goto finish;
667
668                 /* Is this for us? */
669                 if (getpid_cached() != pid) {
670                         r = 0;
671                         goto finish;
672                 }
673         }
674
675         if (usec)
676                 *usec = u;
677
678         r = 1;
679
680 finish:
681         if (unset_environment && s)
682                 unsetenv("WATCHDOG_USEC");
683         if (unset_environment && p)
684                 unsetenv("WATCHDOG_PID");
685
686         return r;
687 }