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