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 /* 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);
414 cmsg = CMSG_FIRSTHDR(&msghdr);
416 cmsg->cmsg_level = SOL_SOCKET;
417 cmsg->cmsg_type = SCM_RIGHTS;
418 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
420 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
423 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
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();
440 /* First try with fake ucred data, as requested */
441 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
446 /* If that failed, try with our own ucred instead */
448 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
449 if (msghdr.msg_controllen == 0)
450 msghdr.msg_control = NULL;
452 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
461 if (unset_environment)
462 unsetenv("NOTIFY_SOCKET");
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);
471 _public_ int sd_notify(int unset_environment, const char *state) {
472 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
475 /// UNNEEDED by elogind
477 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
478 _cleanup_free_ char *p = NULL;
484 va_start(ap, format);
485 r = vasprintf(&p, format, ap);
492 return sd_pid_notify(pid, unset_environment, p);
495 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
496 _cleanup_free_ char *p = NULL;
502 va_start(ap, format);
503 r = vasprintf(&p, format, ap);
510 return sd_pid_notify(0, unset_environment, p);
513 _public_ int sd_booted(void) {
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. */
520 if (lstat("/run/systemd/system/", &st) < 0)
523 return !!S_ISDIR(st.st_mode);
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 */
532 s = getenv("WATCHDOG_USEC");
536 r = safe_atou64(s, &u);
544 p = getenv("WATCHDOG_PID");
548 r = parse_pid(p, &pid);
552 /* Is this for us? */
553 if (getpid() != pid) {
565 if (unset_environment && s)
566 unsetenv("WATCHDOG_USEC");
567 if (unset_environment && p)
568 unsetenv("WATCHDOG_PID");