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 assert_return(fd >= 0, -EBADF);
320 if (mq_getattr(fd, &attr) < 0)
324 char fpath[PATH_MAX];
327 assert_return(path_is_absolute(path), -EINVAL);
329 if (fstat(fd, &a) < 0)
332 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
333 fpath[sizeof(fpath)-1] = 0;
335 if (stat(fpath, &b) < 0)
338 if (a.st_dev != b.st_dev ||
339 a.st_ino != b.st_ino)
347 _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char *state, const int *fds, unsigned n_fds) {
348 union sockaddr_union sockaddr = {
349 .sa.sa_family = AF_UNIX,
351 struct iovec iovec = {
352 .iov_base = (char*) state,
354 struct msghdr msghdr = {
357 .msg_name = &sockaddr,
359 _cleanup_close_ int fd = -1;
360 struct cmsghdr *cmsg = NULL;
370 if (n_fds > 0 && !fds) {
375 e = getenv("NOTIFY_SOCKET");
379 /* Must be an abstract socket, or an absolute path */
380 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
385 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
391 iovec.iov_len = strlen(state);
393 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
394 if (sockaddr.un.sun_path[0] == '@')
395 sockaddr.un.sun_path[0] = 0;
397 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
398 if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
399 msghdr.msg_namelen = sizeof(struct sockaddr_un);
401 have_pid = pid != 0 && pid != getpid();
403 if (n_fds > 0 || have_pid) {
404 msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds) +
405 CMSG_SPACE(sizeof(struct ucred) * have_pid);
406 msghdr.msg_control = alloca(msghdr.msg_controllen);
408 cmsg = CMSG_FIRSTHDR(&msghdr);
410 cmsg->cmsg_level = SOL_SOCKET;
411 cmsg->cmsg_type = SCM_RIGHTS;
412 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
414 memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
417 assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
423 cmsg->cmsg_level = SOL_SOCKET;
424 cmsg->cmsg_type = SCM_CREDENTIALS;
425 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
427 ucred = (struct ucred*) CMSG_DATA(cmsg);
429 ucred->uid = getuid();
430 ucred->gid = getgid();
434 /* First try with fake ucred data, as requested */
435 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
440 /* If that failed, try with our own ucred instead */
442 msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
443 if (msghdr.msg_controllen == 0)
444 msghdr.msg_control = NULL;
446 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
455 if (unset_environment)
456 unsetenv("NOTIFY_SOCKET");
461 _public_ int sd_pid_notify(pid_t pid, int unset_environment, const char *state) {
462 return sd_pid_notify_with_fds(pid, unset_environment, state, NULL, 0);
465 _public_ int sd_notify(int unset_environment, const char *state) {
466 return sd_pid_notify_with_fds(0, unset_environment, state, NULL, 0);
469 /// UNNEEDED by elogind
471 _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
472 _cleanup_free_ char *p = NULL;
478 va_start(ap, format);
479 r = vasprintf(&p, format, ap);
486 return sd_pid_notify(pid, unset_environment, p);
489 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
490 _cleanup_free_ char *p = NULL;
496 va_start(ap, format);
497 r = vasprintf(&p, format, ap);
504 return sd_pid_notify(0, unset_environment, p);
507 _public_ int sd_booted(void) {
510 /* We test whether the runtime unit file directory has been
511 * created. This takes place in mount-setup.c, so is
512 * guaranteed to happen very early during boot. */
514 if (lstat("/run/systemd/system/", &st) < 0)
517 return !!S_ISDIR(st.st_mode);
521 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
522 const char *s, *p = ""; /* p is set to dummy value to do unsetting */
526 s = getenv("WATCHDOG_USEC");
530 r = safe_atou64(s, &u);
538 p = getenv("WATCHDOG_PID");
542 r = parse_pid(p, &pid);
546 /* Is this for us? */
547 if (getpid() != pid) {
559 if (unset_environment && s)
560 unsetenv("WATCHDOG_USEC");
561 if (unset_environment && p)
562 unsetenv("WATCHDOG_PID");