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