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 #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 #endif // 0
149
150 _public_ int sd_is_fifo(int fd, const char *path) {
151         struct stat st_fd;
152
153         assert_return(fd >= 0, -EBADF);
154
155         if (fstat(fd, &st_fd) < 0)
156                 return -errno;
157
158         if (!S_ISFIFO(st_fd.st_mode))
159                 return 0;
160
161         if (path) {
162                 struct stat st_path;
163
164                 if (stat(path, &st_path) < 0) {
165
166                         if (errno == ENOENT || errno == ENOTDIR)
167                                 return 0;
168
169                         return -errno;
170                 }
171
172                 return
173                         st_path.st_dev == st_fd.st_dev &&
174                         st_path.st_ino == st_fd.st_ino;
175         }
176
177         return 1;
178 }
179
180 _public_ int sd_is_special(int fd, const char *path) {
181         struct stat st_fd;
182
183         assert_return(fd >= 0, -EBADF);
184
185         if (fstat(fd, &st_fd) < 0)
186                 return -errno;
187
188         if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
189                 return 0;
190
191         if (path) {
192                 struct stat st_path;
193
194                 if (stat(path, &st_path) < 0) {
195
196                         if (errno == ENOENT || errno == ENOTDIR)
197                                 return 0;
198
199                         return -errno;
200                 }
201
202                 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
203                         return
204                                 st_path.st_dev == st_fd.st_dev &&
205                                 st_path.st_ino == st_fd.st_ino;
206                 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
207                         return st_path.st_rdev == st_fd.st_rdev;
208                 else
209                         return 0;
210         }
211
212         return 1;
213 }
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 _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
285         union sockaddr_union sockaddr = {};
286         socklen_t l = sizeof(sockaddr);
287         int r;
288
289         assert_return(fd >= 0, -EBADF);
290         assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
291
292         r = sd_is_socket_internal(fd, type, listening);
293         if (r <= 0)
294                 return r;
295
296         if (getsockname(fd, &sockaddr.sa, &l) < 0)
297                 return -errno;
298
299         if (l < sizeof(sa_family_t))
300                 return -EINVAL;
301
302         if (sockaddr.sa.sa_family != AF_INET &&
303             sockaddr.sa.sa_family != 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 #if 0 /// UNNEEDED by elogind
328 _public_ int sd_is_socket_sockaddr(int fd, int type, const struct sockaddr* addr, unsigned addr_len, int listening) {
329         union sockaddr_union sockaddr = {};
330         socklen_t l = sizeof(sockaddr);
331         int r;
332
333         assert_return(fd >= 0, -EBADF);
334         assert_return(addr, -EINVAL);
335         assert_return(addr_len >= sizeof(sa_family_t), -ENOBUFS);
336         assert_return(IN_SET(addr->sa_family, AF_INET, AF_INET6), -EPFNOSUPPORT);
337
338         r = sd_is_socket_internal(fd, type, listening);
339         if (r <= 0)
340                 return r;
341
342         if (getsockname(fd, &sockaddr.sa, &l) < 0)
343                 return -errno;
344
345         if (l < sizeof(sa_family_t))
346                 return -EINVAL;
347
348         if (sockaddr.sa.sa_family != addr->sa_family)
349                 return 0;
350
351         if (sockaddr.sa.sa_family == AF_INET) {
352                 const struct sockaddr_in *in = (const struct sockaddr_in *) addr;
353
354                 if (l < sizeof(struct sockaddr_in) || addr_len < sizeof(struct sockaddr_in))
355                         return -EINVAL;
356
357                 if (in->sin_port != 0 &&
358                     sockaddr.in.sin_port != in->sin_port)
359                         return false;
360
361                 return sockaddr.in.sin_addr.s_addr == in->sin_addr.s_addr;
362
363         } else {
364                 const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) addr;
365
366                 if (l < sizeof(struct sockaddr_in6) || addr_len < sizeof(struct sockaddr_in6))
367                         return -EINVAL;
368
369                 if (in->sin6_port != 0 &&
370                     sockaddr.in6.sin6_port != in->sin6_port)
371                         return false;
372
373                 if (in->sin6_flowinfo != 0 &&
374                     sockaddr.in6.sin6_flowinfo != in->sin6_flowinfo)
375                         return false;
376
377                 if (in->sin6_scope_id != 0 &&
378                     sockaddr.in6.sin6_scope_id != in->sin6_scope_id)
379                         return false;
380
381                 return memcmp(sockaddr.in6.sin6_addr.s6_addr, in->sin6_addr.s6_addr,
382                               sizeof(in->sin6_addr.s6_addr)) == 0;
383         }
384 }
385 #endif // 0
386
387 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
388         union sockaddr_union sockaddr = {};
389         socklen_t l = sizeof(sockaddr);
390         int r;
391
392         assert_return(fd >= 0, -EBADF);
393
394         r = sd_is_socket_internal(fd, type, listening);
395         if (r <= 0)
396                 return r;
397
398         if (getsockname(fd, &sockaddr.sa, &l) < 0)
399                 return -errno;
400
401         if (l < sizeof(sa_family_t))
402                 return -EINVAL;
403
404         if (sockaddr.sa.sa_family != AF_UNIX)
405                 return 0;
406
407         if (path) {
408                 if (length == 0)
409                         length = strlen(path);
410
411                 if (length == 0)
412                         /* Unnamed socket */
413                         return l == offsetof(struct sockaddr_un, sun_path);
414
415                 if (path[0])
416                         /* Normal path socket */
417                         return
418                                 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
419                                 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
420                 else
421                         /* Abstract namespace socket */
422                         return
423                                 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
424                                 memcmp(path, sockaddr.un.sun_path, length) == 0;
425         }
426
427         return 1;
428 }
429
430 #if 0 /// UNNEEDED by elogind
431 _public_ int sd_is_mq(int fd, const char *path) {
432         struct mq_attr attr;
433
434         /* Check that the fd is valid */
435         assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
436
437         if (mq_getattr(fd, &attr) < 0) {
438                 if (errno == EBADF)
439                         /* A non-mq fd (or an invalid one, but we ruled that out above) */
440                         return 0;
441                 return -errno;
442         }
443
444         if (path) {
445                 char fpath[PATH_MAX];
446                 struct stat a, b;
447
448                 assert_return(path_is_absolute(path), -EINVAL);
449
450                 if (fstat(fd, &a) < 0)
451                         return -errno;
452
453                 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
454                 fpath[sizeof(fpath)-1] = 0;
455
456                 if (stat(fpath, &b) < 0)
457                         return -errno;
458
459                 if (a.st_dev != b.st_dev ||
460                     a.st_ino != b.st_ino)
461                         return 0;
462         }
463
464         return 1;
465 }
466 #endif // 0
467
468 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
469         union sockaddr_union sockaddr = {
470                 .sa.sa_family = AF_UNIX,
471         };
472         struct iovec iovec = {
473                 .iov_base = (char*) state,
474         };
475         struct msghdr msghdr = {
476                 .msg_iov = &iovec,
477                 .msg_iovlen = 1,
478                 .msg_name = &sockaddr,
479         };
480         _cleanup_close_ int fd = -1;
481         struct cmsghdr *cmsg = NULL;
482         const char *e;
483         bool have_pid;
484         int r;
485
486         if (!state) {
487                 r = -EINVAL;
488                 goto finish;
489         }
490
491         if (n_fds > 0 && !fds) {
492                 r = -EINVAL;
493                 goto finish;
494         }
495
496         e = getenv("NOTIFY_SOCKET");
497         if (!e)
498                 return 0;
499
500         /* Must be an abstract socket, or an absolute path */
501         if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
502                 r = -EINVAL;
503                 goto finish;
504         }
505
506         if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
507                 r = -EINVAL;
508                 goto finish;
509         }
510
511         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
512         if (fd < 0) {
513                 r = -errno;
514                 goto finish;
515         }
516
517         fd_inc_sndbuf(fd, SNDBUF_SIZE);
518
519         iovec.iov_len = strlen(state);
520
521         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
522         if (sockaddr.un.sun_path[0] == '@')
523                 sockaddr.un.sun_path[0] = 0;
524
525         msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
526
527         have_pid = pid != 0 && pid != getpid();
528
529         if (n_fds > 0 || have_pid) {
530                 /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
531                 msghdr.msg_controllen =
532                         (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
533                         (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
534
535                 msghdr.msg_control = alloca0(msghdr.msg_controllen);
536
537                 cmsg = CMSG_FIRSTHDR(&msghdr);
538                 if (n_fds > 0) {
539                         cmsg->cmsg_level = SOL_SOCKET;
540                         cmsg->cmsg_type = SCM_RIGHTS;
541                         cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
542
543                         memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
544
545                         if (have_pid)
546                                 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
547                 }
548
549                 if (have_pid) {
550                         struct ucred *ucred;
551
552                         cmsg->cmsg_level = SOL_SOCKET;
553                         cmsg->cmsg_type = SCM_CREDENTIALS;
554                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
555
556                         ucred = (struct ucred*) CMSG_DATA(cmsg);
557                         ucred->pid = pid;
558                         ucred->uid = getuid();
559                         ucred->gid = getgid();
560                 }
561         }
562
563         /* First try with fake ucred data, as requested */
564         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
565                 r = 1;
566                 goto finish;
567         }
568
569         /* If that failed, try with our own ucred instead */
570         if (have_pid) {
571                 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
572                 if (msghdr.msg_controllen == 0)
573                         msghdr.msg_control = NULL;
574
575                 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
576                         r = 1;
577                         goto finish;
578                 }
579         }
580
581         r = -errno;
582
583 finish:
584         if (unset_environment)
585                 unsetenv("NOTIFY_SOCKET");
586
587         return r;
588 }
589
590 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
591         return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
592 }
593
594 _public_ int sd_notify(int unset_environment, const char *state) {
595         return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
596 }
597
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
634 _public_ int sd_booted(void) {
635 #if 0 /// With elogind, the system is (should never be) booted by systemd
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 #else
642         return 0;
643 #endif // 0
644 }
645
646 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
647         const char *s, *p = ""; /* p is set to dummy value to do unsetting */
648         uint64_t u;
649         int r = 0;
650
651         s = getenv("WATCHDOG_USEC");
652         if (!s)
653                 goto finish;
654
655         r = safe_atou64(s, &u);
656         if (r < 0)
657                 goto finish;
658         if (u <= 0 || u >= USEC_INFINITY) {
659                 r = -EINVAL;
660                 goto finish;
661         }
662
663         p = getenv("WATCHDOG_PID");
664         if (p) {
665                 pid_t pid;
666
667                 r = parse_pid(p, &pid);
668                 if (r < 0)
669                         goto finish;
670
671                 /* Is this for us? */
672                 if (getpid() != pid) {
673                         r = 0;
674                         goto finish;
675                 }
676         }
677
678         if (usec)
679                 *usec = u;
680
681         r = 1;
682
683 finish:
684         if (unset_environment && s)
685                 unsetenv("WATCHDOG_USEC");
686         if (unset_environment && p)
687                 unsetenv("WATCHDOG_PID");
688
689         return r;
690 }