chiark / gitweb /
Prep v229: Remove remaining emacs settings [3/6] src/libelogind
[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 = offsetof(struct sockaddr_un, sun_path) + strlen(e);
466         if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
467                 msghdr.msg_namelen = sizeof(struct sockaddr_un);
468
469         have_pid = pid != 0 && pid != getpid();
470
471         if (n_fds > 0 || have_pid) {
472                 /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
473                 msghdr.msg_controllen =
474                         (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
475                         (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
476
477                 msghdr.msg_control = alloca0(msghdr.msg_controllen);
478
479                 cmsg = CMSG_FIRSTHDR(&msghdr);
480                 if (n_fds > 0) {
481                         cmsg->cmsg_level = SOL_SOCKET;
482                         cmsg->cmsg_type = SCM_RIGHTS;
483                         cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
484
485                         memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
486
487                         if (have_pid)
488                                 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
489                 }
490
491                 if (have_pid) {
492                         struct ucred *ucred;
493
494                         cmsg->cmsg_level = SOL_SOCKET;
495                         cmsg->cmsg_type = SCM_CREDENTIALS;
496                         cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
497
498                         ucred = (struct ucred*) CMSG_DATA(cmsg);
499                         ucred->pid = pid;
500                         ucred->uid = getuid();
501                         ucred->gid = getgid();
502                 }
503         }
504
505         /* First try with fake ucred data, as requested */
506         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
507                 r = 1;
508                 goto finish;
509         }
510
511         /* If that failed, try with our own ucred instead */
512         if (have_pid) {
513                 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
514                 if (msghdr.msg_controllen == 0)
515                         msghdr.msg_control = NULL;
516
517                 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
518                         r = 1;
519                         goto finish;
520                 }
521         }
522
523         r = -errno;
524
525 finish:
526         if (unset_environment)
527                 unsetenv("NOTIFY_SOCKET");
528
529         return r;
530 }
531
532 #if 0 /// UNNEEDED by elogind
533 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
534         return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
535 }
536 #endif // 0
537
538 _public_ int sd_notify(int unset_environment, const char *state) {
539         return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
540 }
541
542 #if 0 /// UNNEEDED by elogind
543 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
544         _cleanup_free_ char *p = NULL;
545         int r;
546
547         if (format) {
548                 va_list ap;
549
550                 va_start(ap, format);
551                 r = vasprintf(&p, format, ap);
552                 va_end(ap);
553
554                 if (r < 0 || !p)
555                         return -ENOMEM;
556         }
557
558         return sd_pid_notify(pid, unset_environment, p);
559 }
560
561 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
562         _cleanup_free_ char *p = NULL;
563         int r;
564
565         if (format) {
566                 va_list ap;
567
568                 va_start(ap, format);
569                 r = vasprintf(&p, format, ap);
570                 va_end(ap);
571
572                 if (r < 0 || !p)
573                         return -ENOMEM;
574         }
575
576         return sd_pid_notify(0, unset_environment, p);
577 }
578
579 _public_ int sd_booted(void) {
580         /* We test whether the runtime unit file directory has been
581          * created. This takes place in mount-setup.c, so is
582          * guaranteed to happen very early during boot. */
583
584         return laccess("/run/systemd/system/", F_OK) >= 0;
585 }
586 #endif // 0
587
588 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
589         const char *s, *p = ""; /* p is set to dummy value to do unsetting */
590         uint64_t u;
591         int r = 0;
592
593         s = getenv("WATCHDOG_USEC");
594         if (!s)
595                 goto finish;
596
597         r = safe_atou64(s, &u);
598         if (r < 0)
599                 goto finish;
600         if (u <= 0 || u >= USEC_INFINITY) {
601                 r = -EINVAL;
602                 goto finish;
603         }
604
605         p = getenv("WATCHDOG_PID");
606         if (p) {
607                 pid_t pid;
608
609                 r = parse_pid(p, &pid);
610                 if (r < 0)
611                         goto finish;
612
613                 /* Is this for us? */
614                 if (getpid() != pid) {
615                         r = 0;
616                         goto finish;
617                 }
618         }
619
620         if (usec)
621                 *usec = u;
622
623         r = 1;
624
625 finish:
626         if (unset_environment && s)
627                 unsetenv("WATCHDOG_USEC");
628         if (unset_environment && p)
629                 unsetenv("WATCHDOG_PID");
630
631         return r;
632 }