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/>.
23 #include <sys/socket.h>
25 #include <netinet/in.h>
37 #include "path-util.h"
38 #include "socket-util.h"
39 #include "sd-daemon.h"
41 /// UNNEEDED by elogind
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, -EBADF);
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, -EBADF);
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;
158 static int sd_is_socket_internal(int fd, int type, int listening) {
161 assert_return(fd >= 0, -EBADF);
162 assert_return(type >= 0, -EINVAL);
164 if (fstat(fd, &st_fd) < 0)
167 if (!S_ISSOCK(st_fd.st_mode))
172 socklen_t l = sizeof(other_type);
174 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
177 if (l != sizeof(other_type))
180 if (other_type != type)
184 if (listening >= 0) {
186 socklen_t l = sizeof(accepting);
188 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
191 if (l != sizeof(accepting))
194 if (!accepting != !listening)
201 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
204 assert_return(fd >= 0, -EBADF);
205 assert_return(family >= 0, -EINVAL);
207 r = sd_is_socket_internal(fd, type, listening);
212 union sockaddr_union sockaddr = {};
213 socklen_t l = sizeof(sockaddr);
215 if (getsockname(fd, &sockaddr.sa, &l) < 0)
218 if (l < sizeof(sa_family_t))
221 return sockaddr.sa.sa_family == family;
227 /// UNNEEDED by elogind
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);
234 assert_return(fd >= 0, -EBADF);
235 assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL);
237 r = sd_is_socket_internal(fd, type, listening);
241 if (getsockname(fd, &sockaddr.sa, &l) < 0)
244 if (l < sizeof(sa_family_t))
247 if (sockaddr.sa.sa_family != AF_INET &&
248 sockaddr.sa.sa_family != AF_INET6)
252 if (sockaddr.sa.sa_family != family)
256 if (sockaddr.sa.sa_family == AF_INET) {
257 if (l < sizeof(struct sockaddr_in))
260 return htons(port) == sockaddr.in.sin_port;
262 if (l < sizeof(struct sockaddr_in6))
265 return htons(port) == sockaddr.in6.sin6_port;
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);
277 assert_return(fd >= 0, -EBADF);
279 r = sd_is_socket_internal(fd, type, listening);
283 if (getsockname(fd, &sockaddr.sa, &l) < 0)
286 if (l < sizeof(sa_family_t))
289 if (sockaddr.sa.sa_family != AF_UNIX)
294 length = strlen(path);
298 return l == offsetof(struct sockaddr_un, sun_path);
301 /* Normal path socket */
303 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
304 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
306 /* Abstract namespace socket */
308 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
309 memcmp(path, sockaddr.un.sun_path, length) == 0;
315 _public_ int sd_is_mq(int fd, const char *path) {
318 /* Check that the fd is valid */
319 assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
321 if (mq_getattr(fd, &attr) < 0) {
323 /* A non-mq fd (or an invalid one, but we ruled that out above) */
329 char fpath[PATH_MAX];
332 assert_return(path_is_absolute(path), -EINVAL);
334 if (fstat(fd, &a) < 0)
337 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
338 fpath[sizeof(fpath)-1] = 0;
340 if (stat(fpath, &b) < 0)
343 if (a.st_dev != b.st_dev ||
344 a.st_ino != b.st_ino)
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,
356 struct iovec iovec = {
357 .iov_base = (char*) state,
359 struct msghdr msghdr = {
362 .msg_name = &sockaddr,
364 _cleanup_close_ int fd = -1;
365 struct cmsghdr *cmsg = NULL;
375 if (n_fds > 0 && !fds) {
380 e = getenv("NOTIFY_SOCKET");
384 /* Must be an abstract socket, or an absolute path */
385 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
390 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
396 iovec.iov_len = strlen(state);
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;
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);
406 have_pid = pid != 0 && pid != getpid();
408 if (n_fds > 0 || have_pid) {
409 msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds) +
410 CMSG_SPACE(sizeof(struct ucred) * have_pid);
411 msghdr.msg_control = alloca(msghdr.msg_controllen);
413 cmsg = CMSG_FIRSTHDR(&msghdr);
415 cmsg->cmsg_level = SOL_SOCKET;
416 cmsg->cmsg_type = SCM_RIGHTS;
417 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
419 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
422 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
428 cmsg->cmsg_level = SOL_SOCKET;
429 cmsg->cmsg_type = SCM_CREDENTIALS;
430 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
432 ucred = (struct ucred*) CMSG_DATA(cmsg);
434 ucred->uid = getuid();
435 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 */
447 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
448 if (msghdr.msg_controllen == 0)
449 msghdr.msg_control = NULL;
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 /// UNNEEDED by elogind
476 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
477 _cleanup_free_ char *p = NULL;
483 va_start(ap, format);
484 r = vasprintf(&p, format, ap);
491 return sd_pid_notify(pid, unset_environment, p);
494 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
495 _cleanup_free_ char *p = NULL;
501 va_start(ap, format);
502 r = vasprintf(&p, format, ap);
509 return sd_pid_notify(0, unset_environment, p);
512 _public_ int sd_booted(void) {
515 /* We test whether the runtime unit file directory has been
516 * created. This takes place in mount-setup.c, so is
517 * guaranteed to happen very early during boot. */
519 if (lstat("/run/systemd/system/", &st) < 0)
522 return !!S_ISDIR(st.st_mode);
526 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
527 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
531 s = getenv("WATCHDOG_USEC");
535 r = safe_atou64(s, &u);
543 p = getenv("WATCHDOG_PID");
547 r = parse_pid(p, &pid);
551 /* Is this for us? */
552 if (getpid() != pid) {
564 if (unset_environment && s)
565 unsetenv("WATCHDOG_USEC");
566 if (unset_environment && p)
567 unsetenv("WATCHDOG_PID");