1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
22 #include <sys/types.h>
24 #include <sys/socket.h>
27 #include <netinet/in.h>
39 #include "path-util.h"
40 #include "socket-util.h"
41 #include "sd-daemon.h"
43 _public_ int sd_listen_fds(int unset_environment) {
49 e = getenv("LISTEN_PID");
55 r = parse_pid(e, &pid);
60 if (getpid() != pid) {
65 e = getenv("LISTEN_FDS");
75 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) n; fd ++) {
76 r = fd_cloexec(fd, true);
84 if (unset_environment) {
85 unsetenv("LISTEN_PID");
86 unsetenv("LISTEN_FDS");
92 _public_ int sd_is_fifo(int fd, const char *path) {
95 assert_return(fd >= 0, -EINVAL);
97 if (fstat(fd, &st_fd) < 0)
100 if (!S_ISFIFO(st_fd.st_mode))
106 if (stat(path, &st_path) < 0) {
108 if (errno == ENOENT || errno == ENOTDIR)
115 st_path.st_dev == st_fd.st_dev &&
116 st_path.st_ino == st_fd.st_ino;
122 _public_ int sd_is_special(int fd, const char *path) {
125 assert_return(fd >= 0, -EINVAL);
127 if (fstat(fd, &st_fd) < 0)
130 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
136 if (stat(path, &st_path) < 0) {
138 if (errno == ENOENT || errno == ENOTDIR)
144 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
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;
157 static int sd_is_socket_internal(int fd, int type, int listening) {
160 assert_return(fd >= 0, -EINVAL);
161 assert_return(type >= 0, -EINVAL);
163 if (fstat(fd, &st_fd) < 0)
166 if (!S_ISSOCK(st_fd.st_mode))
171 socklen_t l = sizeof(other_type);
173 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
176 if (l != sizeof(other_type))
179 if (other_type != type)
183 if (listening >= 0) {
185 socklen_t l = sizeof(accepting);
187 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
190 if (l != sizeof(accepting))
193 if (!accepting != !listening)
200 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
203 assert_return(fd >= 0, -EINVAL);
204 assert_return(family >= 0, -EINVAL);
206 r = sd_is_socket_internal(fd, type, listening);
211 union sockaddr_union sockaddr = {};
212 socklen_t l = sizeof(sockaddr);
214 if (getsockname(fd, &sockaddr.sa, &l) < 0)
217 if (l < sizeof(sa_family_t))
220 return sockaddr.sa.sa_family == family;
226 _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
227 union sockaddr_union sockaddr = {};
228 socklen_t l = sizeof(sockaddr);
231 assert_return(fd >= 0, -EINVAL);
232 assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
234 r = sd_is_socket_internal(fd, type, listening);
238 if (getsockname(fd, &sockaddr.sa, &l) < 0)
241 if (l < sizeof(sa_family_t))
244 if (sockaddr.sa.sa_family != AF_INET &&
245 sockaddr.sa.sa_family != AF_INET6)
249 if (sockaddr.sa.sa_family != family)
253 if (sockaddr.sa.sa_family == AF_INET) {
254 if (l < sizeof(struct sockaddr_in))
257 return htons(port) == sockaddr.in.sin_port;
259 if (l < sizeof(struct sockaddr_in6))
262 return htons(port) == sockaddr.in6.sin6_port;
269 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
270 union sockaddr_union sockaddr = {};
271 socklen_t l = sizeof(sockaddr);
274 assert_return(fd >= 0, -EINVAL);
276 r = sd_is_socket_internal(fd, type, listening);
280 if (getsockname(fd, &sockaddr.sa, &l) < 0)
283 if (l < sizeof(sa_family_t))
286 if (sockaddr.sa.sa_family != AF_UNIX)
291 length = strlen(path);
295 return l == offsetof(struct sockaddr_un, sun_path);
298 /* Normal path socket */
300 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
301 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
303 /* Abstract namespace socket */
305 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
306 memcmp(path, sockaddr.un.sun_path, length) == 0;
312 _public_ int sd_is_mq(int fd, const char *path) {
315 assert_return(fd >= 0, -EINVAL);
317 if (mq_getattr(fd, &attr) < 0)
321 char fpath[PATH_MAX];
324 assert_return(path_is_absolute(path), -EINVAL);
326 if (fstat(fd, &a) < 0)
329 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
330 fpath[sizeof(fpath)-1] = 0;
332 if (stat(fpath, &b) < 0)
335 if (a.st_dev != b.st_dev ||
336 a.st_ino != b.st_ino)
343 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
344 union sockaddr_union sockaddr = {
345 .sa.sa_family = AF_UNIX,
347 struct iovec iovec = {
348 .iov_base = (char*) state,
350 struct msghdr msghdr = {
353 .msg_name = &sockaddr,
356 struct cmsghdr cmsghdr;
357 uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
358 CMSG_SPACE(sizeof(int) * n_fds)];
360 _cleanup_close_ int fd = -1;
361 struct cmsghdr *cmsg = NULL;
363 size_t controllen_without_ucred = 0;
364 bool try_without_ucred = false;
372 if (n_fds > 0 && !fds) {
377 e = getenv("NOTIFY_SOCKET");
381 /* Must be an abstract socket, or an absolute path */
382 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
387 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
393 iovec.iov_len = strlen(state);
395 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
396 if (sockaddr.un.sun_path[0] == '@')
397 sockaddr.un.sun_path[0] = 0;
399 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
400 if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
401 msghdr.msg_namelen = sizeof(struct sockaddr_un);
404 msghdr.msg_control = &control;
405 msghdr.msg_controllen = CMSG_LEN(sizeof(int) * n_fds);
407 cmsg = CMSG_FIRSTHDR(&msghdr);
408 cmsg->cmsg_level = SOL_SOCKET;
409 cmsg->cmsg_type = SCM_RIGHTS;
410 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
412 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
415 if (pid != 0 && pid != getpid()) {
418 try_without_ucred = true;
419 controllen_without_ucred = msghdr.msg_controllen;
421 msghdr.msg_control = &control;
422 msghdr.msg_controllen += CMSG_LEN(sizeof(struct ucred));
425 cmsg = CMSG_NXTHDR(&msghdr, cmsg);
427 cmsg = CMSG_FIRSTHDR(&msghdr);
429 cmsg->cmsg_level = SOL_SOCKET;
430 cmsg->cmsg_type = SCM_CREDENTIALS;
431 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
433 ucred = (struct ucred*) CMSG_DATA(cmsg);
435 ucred->uid = getuid();
436 ucred->gid = getgid();
439 /* First try with fake ucred data, as requested */
440 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
445 /* If that failed, try with our own ucred instead */
446 if (try_without_ucred) {
447 if (controllen_without_ucred <= 0)
448 msghdr.msg_control = NULL;
449 msghdr.msg_controllen = controllen_without_ucred;
451 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
460 if (unset_environment)
461 unsetenv("NOTIFY_SOCKET");
466 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
467 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
470 _public_ int sd_notify(int unset_environment, const char *state) {
471 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
474 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
475 _cleanup_free_ char *p = NULL;
481 va_start(ap, format);
482 r = vasprintf(&p, format, ap);
489 return sd_pid_notify(pid, unset_environment, p);
492 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
493 _cleanup_free_ char *p = NULL;
499 va_start(ap, format);
500 r = vasprintf(&p, format, ap);
507 return sd_pid_notify(0, unset_environment, p);
510 _public_ int sd_booted(void) {
513 /* We test whether the runtime unit file directory has been
514 * created. This takes place in mount-setup.c, so is
515 * guaranteed to happen very early during boot. */
517 if (lstat("/run/systemd/system/", &st) < 0)
520 return !!S_ISDIR(st.st_mode);
523 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
524 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
528 s = getenv("WATCHDOG_USEC");
532 r = safe_atou64(s, &u);
540 p = getenv("WATCHDOG_PID");
544 r = parse_pid(p, &pid);
548 /* Is this for us? */
549 if (getpid() != pid) {
561 if (unset_environment && s)
562 unsetenv("WATCHDOG_USEC");
563 if (unset_environment && p)
564 unsetenv("WATCHDOG_PID");