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