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 "sd-daemon.h"
41 _public_ int sd_listen_fds(int unset_environment) {
47 e = getenv("LISTEN_PID");
54 l = strtoul(e, &p, 10);
61 if (!p || p == e || *p || l <= 0) {
67 if (getpid() != (pid_t) l) {
72 e = getenv("LISTEN_FDS");
79 l = strtoul(e, &p, 10);
86 if (!p || p == e || *p) {
91 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
94 flags = fcntl(fd, F_GETFD);
100 if (flags & FD_CLOEXEC)
103 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
112 if (unset_environment) {
113 unsetenv("LISTEN_PID");
114 unsetenv("LISTEN_FDS");
120 _public_ int sd_is_fifo(int fd, const char *path) {
126 if (fstat(fd, &st_fd) < 0)
129 if (!S_ISFIFO(st_fd.st_mode))
135 if (stat(path, &st_path) < 0) {
137 if (errno == ENOENT || errno == ENOTDIR)
144 st_path.st_dev == st_fd.st_dev &&
145 st_path.st_ino == st_fd.st_ino;
151 _public_ int sd_is_special(int fd, const char *path) {
157 if (fstat(fd, &st_fd) < 0)
160 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
166 if (stat(path, &st_path) < 0) {
168 if (errno == ENOENT || errno == ENOTDIR)
174 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
176 st_path.st_dev == st_fd.st_dev &&
177 st_path.st_ino == st_fd.st_ino;
178 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
179 return st_path.st_rdev == st_fd.st_rdev;
187 static int sd_is_socket_internal(int fd, int type, int listening) {
190 if (fd < 0 || type < 0)
193 if (fstat(fd, &st_fd) < 0)
196 if (!S_ISSOCK(st_fd.st_mode))
201 socklen_t l = sizeof(other_type);
203 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
206 if (l != sizeof(other_type))
209 if (other_type != type)
213 if (listening >= 0) {
215 socklen_t l = sizeof(accepting);
217 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
220 if (l != sizeof(accepting))
223 if (!accepting != !listening)
230 union sockaddr_union {
232 struct sockaddr_in in4;
233 struct sockaddr_in6 in6;
234 struct sockaddr_un un;
235 struct sockaddr_storage storage;
238 _public_ int sd_is_socket(int fd, int family, int type, int listening) {
244 r = sd_is_socket_internal(fd, type, listening);
249 union sockaddr_union sockaddr = {};
250 socklen_t l = sizeof(sockaddr);
252 if (getsockname(fd, &sockaddr.sa, &l) < 0)
255 if (l < sizeof(sa_family_t))
258 return sockaddr.sa.sa_family == family;
264 _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
265 union sockaddr_union sockaddr = {};
266 socklen_t l = sizeof(sockaddr);
269 if (family != 0 && family != AF_INET && family != AF_INET6)
272 r = sd_is_socket_internal(fd, type, listening);
276 if (getsockname(fd, &sockaddr.sa, &l) < 0)
279 if (l < sizeof(sa_family_t))
282 if (sockaddr.sa.sa_family != AF_INET &&
283 sockaddr.sa.sa_family != AF_INET6)
287 if (sockaddr.sa.sa_family != family)
291 if (sockaddr.sa.sa_family == AF_INET) {
292 if (l < sizeof(struct sockaddr_in))
295 return htons(port) == sockaddr.in4.sin_port;
297 if (l < sizeof(struct sockaddr_in6))
300 return htons(port) == sockaddr.in6.sin6_port;
307 _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
308 union sockaddr_union sockaddr = {};
309 socklen_t l = sizeof(sockaddr);
312 r = sd_is_socket_internal(fd, type, listening);
316 if (getsockname(fd, &sockaddr.sa, &l) < 0)
319 if (l < sizeof(sa_family_t))
322 if (sockaddr.sa.sa_family != AF_UNIX)
327 length = strlen(path);
331 return l == offsetof(struct sockaddr_un, sun_path);
334 /* Normal path socket */
336 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
337 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
339 /* Abstract namespace socket */
341 (l == offsetof(struct sockaddr_un, sun_path) + length) &&
342 memcmp(path, sockaddr.un.sun_path, length) == 0;
348 _public_ int sd_is_mq(int fd, const char *path) {
354 if (mq_getattr(fd, &attr) < 0)
358 char fpath[PATH_MAX];
364 if (fstat(fd, &a) < 0)
367 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
368 fpath[sizeof(fpath)-1] = 0;
370 if (stat(fpath, &b) < 0)
373 if (a.st_dev != b.st_dev ||
374 a.st_ino != b.st_ino)
381 _public_ int sd_notify(int unset_environment, const char *state) {
383 struct msghdr msghdr;
385 union sockaddr_union sockaddr;
393 e = getenv("NOTIFY_SOCKET");
397 /* Must be an abstract socket, or an absolute path */
398 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
403 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
409 memzero(&sockaddr, sizeof(sockaddr));
410 sockaddr.sa.sa_family = AF_UNIX;
411 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
413 if (sockaddr.un.sun_path[0] == '@')
414 sockaddr.un.sun_path[0] = 0;
416 memzero(&iovec, sizeof(iovec));
417 iovec.iov_base = (char*) state;
418 iovec.iov_len = strlen(state);
420 memzero(&msghdr, sizeof(msghdr));
421 msghdr.msg_name = &sockaddr;
422 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
424 if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
425 msghdr.msg_namelen = sizeof(struct sockaddr_un);
427 msghdr.msg_iov = &iovec;
428 msghdr.msg_iovlen = 1;
430 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
438 if (unset_environment)
439 unsetenv("NOTIFY_SOCKET");
447 _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
452 va_start(ap, format);
453 r = vasprintf(&p, format, ap);
459 r = sd_notify(unset_environment, p);
465 _public_ int sd_booted(void) {
468 /* We test whether the runtime unit file directory has been
469 * created. This takes place in mount-setup.c, so is
470 * guaranteed to happen very early during boot. */
472 if (lstat("/run/systemd/system/", &st) < 0)
475 return !!S_ISDIR(st.st_mode);
478 _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
479 unsigned long long ll;
485 e = getenv("WATCHDOG_PID");
492 l = strtoul(e, &p, 10);
497 if (!p || p == e || *p || l <= 0) {
502 /* Is this for us? */
503 if (getpid() != (pid_t) l) {
508 e = getenv("WATCHDOG_USEC");
515 ll = strtoull(e, &p, 10);
520 if (!p || p == e || *p || l <= 0) {
531 if (unset_environment) {
532 unsetenv("WATCHDOG_PID");
533 unsetenv("WATCHDOG_USEC");