chiark / gitweb /
Prep 229.9: Make all supportable API functions visible.
[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 /// Additional includes needed by elogind
46 #include "process-util.h"
47
48 #define SNDBUF_SIZE (8*1024*1024)
49
50 static void unsetenv_all(bool unset_environment) {
51
52         if (!unset_environment)
53                 return;
54
55         unsetenv("LISTEN_PID");
56         unsetenv("LISTEN_FDS");
57         unsetenv("LISTEN_FDNAMES");
58 }
59
60 _public_ int sd_listen_fds(int unset_environment) {
61         const char *e;
62         int n, r, fd;
63         pid_t pid;
64
65         e = getenv("LISTEN_PID");
66         if (!e) {
67                 r = 0;
68                 goto finish;
69         }
70
71         r = parse_pid(e, &pid);
72         if (r < 0)
73                 goto finish;
74
75         /* Is this for us? */
76         if (getpid_cached() != pid) {
77                 r = 0;
78                 goto finish;
79         }
80
81         e = getenv("LISTEN_FDS");
82         if (!e) {
83                 r = 0;
84                 goto finish;
85         }
86
87         r = safe_atoi(e, &n);
88         if (r < 0)
89                 goto finish;
90
91         assert_cc(SD_LISTEN_FDS_START < INT_MAX);
92         if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
93                 r = -EINVAL;
94                 goto finish;
95         }
96
97         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
98                 r = fd_cloexec(fd, true);
99                 if (r < 0)
100                         goto finish;
101         }
102
103         r = n;
104
105 finish:
106         unsetenv_all(unset_environment);
107         return r;
108 }
109
110 _public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
111         _cleanup_strv_free_ char **l = NULL;
112         bool have_names;
113         int n_names = 0, n_fds;
114         const char *e;
115         int r;
116
117         if (!names)
118                 return sd_listen_fds(unset_environment);
119
120         e = getenv("LISTEN_FDNAMES");
121         if (e) {
122                 n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
123                 if (n_names < 0) {
124                         unsetenv_all(unset_environment);
125                         return n_names;
126                 }
127
128                 have_names = true;
129         } else
130                 have_names = false;
131
132         n_fds = sd_listen_fds(unset_environment);
133         if (n_fds <= 0)
134                 return n_fds;
135
136         if (have_names) {
137                 if (n_names != n_fds)
138                         return -EINVAL;
139         } else {
140                 r = strv_extend_n(&l, "unknown", n_fds);
141                 if (r < 0)
142                         return r;
143         }
144
145         *names = l;
146         l = NULL;
147
148         return n_fds;
149 }
150
151 _public_ int sd_is_fifo(int fd, const char *path) {
152         struct stat st_fd;
153
154         assert_return(fd >= 0, -EBADF);
155
156         if (fstat(fd, &st_fd) < 0)
157                 return -errno;
158
159         if (!S_ISFIFO(st_fd.st_mode))
160                 return 0;
161
162         if (path) {
163                 struct stat st_path;
164
165                 if (stat(path, &st_path) < 0) {
166
167                         if (IN_SET(errno, ENOENT, ENOTDIR))
168                                 return 0;
169
170                         return -errno;
171                 }
172
173                 return
174                         st_path.st_dev == st_fd.st_dev &&
175                         st_path.st_ino == st_fd.st_ino;
176         }
177
178         return 1;
179 }
180
181 _public_ int sd_is_special(int fd, const char *path) {
182         struct stat st_fd;
183
184         assert_return(fd >= 0, -EBADF);
185
186         if (fstat(fd, &st_fd) < 0)
187                 return -errno;
188
189         if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
190                 return 0;
191
192         if (path) {
193                 struct stat st_path;
194
195                 if (stat(path, &st_path) < 0) {
196
197                         if (IN_SET(errno, ENOENT, ENOTDIR))
198                                 return 0;
199
200                         return -errno;
201                 }
202
203                 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
204                         return
205                                 st_path.st_dev == st_fd.st_dev &&
206                                 st_path.st_ino == st_fd.st_ino;
207                 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
208                         return st_path.st_rdev == st_fd.st_rdev;
209                 else
210                         return 0;
211         }
212
213         return 1;
214 }
215
216 static int sd_is_socket_internal(int fd, int type, int listening) {
217         struct stat st_fd;
218
219         assert_return(fd >= 0, -EBADF);
220         assert_return(type >= 0, -EINVAL);
221
222         if (fstat(fd, &st_fd) < 0)
223                 return -errno;
224
225         if (!S_ISSOCK(st_fd.st_mode))
226                 return 0;
227
228         if (type != 0) {
229                 int other_type = 0;
230                 socklen_t l = sizeof(other_type);
231
232                 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
233                         return -errno;
234
235                 if (l != sizeof(other_type))
236                         return -EINVAL;
237
238                 if (other_type != type)
239                         return 0;
240         }
241
242         if (listening >= 0) {
243                 int accepting = 0;
244                 socklen_t l = sizeof(accepting);
245
246                 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
247                         return -errno;
248
249                 if (l != sizeof(accepting))
250                         return -EINVAL;
251
252                 if (!accepting != !listening)
253                         return 0;
254         }
255
256         return 1;
257 }
258
259 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
260         int r;
261
262         assert_return(fd >= 0, -EBADF);
263         assert_return(family >= 0, -EINVAL);
264
265         r = sd_is_socket_internal(fd, type, listening);
266         if (r <= 0)
267                 return r;
268
269         if (family > 0) {
270                 union sockaddr_union sockaddr = {};
271                 socklen_t l = sizeof(sockaddr);
272
273                 if (getsockname(fd, &sockaddr.sa, &l) < 0)
274                         return -errno;
275
276                 if (l < sizeof(sa_family_t))
277                         return -EINVAL;
278
279                 return sockaddr.sa.sa_family == family;
280         }
281
282         return 1;
283 }
284
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 #if 0 /// UNNEEDED by elogind
429 _public_ int sd_is_mq(int fd, const char *path) {
430         struct mq_attr attr;
431
432         /* Check that the fd is valid */
433         assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
434
435         if (mq_getattr(fd, &attr) < 0) {
436                 if (errno == EBADF)
437                         /* A non-mq fd (or an invalid one, but we ruled that out above) */
438                         return 0;
439                 return -errno;
440         }
441
442         if (path) {
443                 char fpath[PATH_MAX];
444                 struct stat a, b;
445
446                 assert_return(path_is_absolute(path), -EINVAL);
447
448                 if (fstat(fd, &a) < 0)
449                         return -errno;
450
451                 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
452                 fpath[sizeof(fpath)-1] = 0;
453
454                 if (stat(fpath, &b) < 0)
455                         return -errno;
456
457                 if (a.st_dev != b.st_dev ||
458                     a.st_ino != b.st_ino)
459                         return 0;
460         }
461
462         return 1;
463 }
464 #endif // 0
465
466 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
467         union sockaddr_union sockaddr = {
468                 .sa.sa_family = AF_UNIX,
469         };
470         struct iovec iovec = {
471                 .iov_base = (char*) state,
472         };
473         struct msghdr msghdr = {
474                 .msg_iov = &iovec,
475                 .msg_iovlen = 1,
476                 .msg_name = &sockaddr,
477         };
478         _cleanup_close_ int fd = -1;
479         struct cmsghdr *cmsg = NULL;
480         const char *e;
481         bool have_pid;
482         int r;
483
484         if (!state) {
485                 r = -EINVAL;
486                 goto finish;
487         }
488
489         if (n_fds > 0 && !fds) {
490                 r = -EINVAL;
491                 goto finish;
492         }
493
494         e = getenv("NOTIFY_SOCKET");
495         if (!e)
496                 return 0;
497
498         /* Must be an abstract socket, or an absolute path */
499         if (!IN_SET(e[0], '@', '/') || e[1] == 0) {
500                 r = -EINVAL;
501                 goto finish;
502         }
503
504         if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
505                 r = -EINVAL;
506                 goto finish;
507         }
508
509         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
510         if (fd < 0) {
511                 r = -errno;
512                 goto finish;
513         }
514
515         fd_inc_sndbuf(fd, SNDBUF_SIZE);
516
517         iovec.iov_len = strlen(state);
518
519         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
520         if (sockaddr.un.sun_path[0] == '@')
521                 sockaddr.un.sun_path[0] = 0;
522
523         msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
524
525         have_pid = pid != 0 && pid != getpid_cached();
526
527         if (n_fds > 0 || have_pid) {
528                 /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
529                 msghdr.msg_controllen =
530                         (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
531                         (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
532
533                 msghdr.msg_control = alloca0(msghdr.msg_controllen);
534
535                 cmsg = CMSG_FIRSTHDR(&msghdr);
536                 if (n_fds > 0) {
537                         cmsg->cmsg_level = SOL_SOCKET;
538                         cmsg->cmsg_type = SCM_RIGHTS;
539                         cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
540
541                         memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
542
543                         if (have_pid)
544                                 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
545                 }
546
547                 if (have_pid) {
548                         struct ucred *ucred;
549
550                         cmsg->cmsg_level = SOL_SOCKET;
551                         cmsg->cmsg_type = SCM_CREDENTIALS;
552                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
553
554                         ucred = (struct ucred*) CMSG_DATA(cmsg);
555                         ucred->pid = pid;
556                         ucred->uid = getuid();
557                         ucred->gid = getgid();
558                 }
559         }
560
561         /* First try with fake ucred data, as requested */
562         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
563                 r = 1;
564                 goto finish;
565         }
566
567         /* If that failed, try with our own ucred instead */
568         if (have_pid) {
569                 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
570                 if (msghdr.msg_controllen == 0)
571                         msghdr.msg_control = NULL;
572
573                 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
574                         r = 1;
575                         goto finish;
576                 }
577         }
578
579         r = -errno;
580
581 finish:
582         if (unset_environment)
583                 unsetenv("NOTIFY_SOCKET");
584
585         return r;
586 }
587
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
592 _public_ int sd_notify(int unset_environment, const char *state) {
593         return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
594 }
595
596 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
597         _cleanup_free_ char *p = NULL;
598         int r;
599
600         if (format) {
601                 va_list ap;
602
603                 va_start(ap, format);
604                 r = vasprintf(&p, format, ap);
605                 va_end(ap);
606
607                 if (r < 0 || !p)
608                         return -ENOMEM;
609         }
610
611         return sd_pid_notify(pid, unset_environment, p);
612 }
613
614 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
615         _cleanup_free_ char *p = NULL;
616         int r;
617
618         if (format) {
619                 va_list ap;
620
621                 va_start(ap, format);
622                 r = vasprintf(&p, format, ap);
623                 va_end(ap);
624
625                 if (r < 0 || !p)
626                         return -ENOMEM;
627         }
628
629         return sd_pid_notify(0, unset_environment, p);
630 }
631
632 _public_ int sd_booted(void) {
633         /* We test whether the runtime unit file directory has been
634          * created. This takes place in mount-setup.c, so is
635          * guaranteed to happen very early during boot. */
636
637         return laccess("/run/systemd/system/", F_OK) >= 0;
638 }
639
640 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
641         const char *s, *p = ""; /* p is set to dummy value to do unsetting */
642         uint64_t u;
643         int r = 0;
644
645         s = getenv("WATCHDOG_USEC");
646         if (!s)
647                 goto finish;
648
649         r = safe_atou64(s, &u);
650         if (r < 0)
651                 goto finish;
652         if (u <= 0 || u >= USEC_INFINITY) {
653                 r = -EINVAL;
654                 goto finish;
655         }
656
657         p = getenv("WATCHDOG_PID");
658         if (p) {
659                 pid_t pid;
660
661                 r = parse_pid(p, &pid);
662                 if (r < 0)
663                         goto finish;
664
665                 /* Is this for us? */
666                 if (getpid_cached() != pid) {
667                         r = 0;
668                         goto finish;
669                 }
670         }
671
672         if (usec)
673                 *usec = u;
674
675         r = 1;
676
677 finish:
678         if (unset_environment && s)
679                 unsetenv("WATCHDOG_USEC");
680         if (unset_environment && p)
681                 unsetenv("WATCHDOG_PID");
682
683         return r;
684 }