31 #include <sys/types.h>
33 #include <sys/socket.h>
35 #include <sys/fcntl.h>
36 #include <netinet/in.h>
46 #if defined(__linux__)
50 #include "sd-daemon.h"
53 #ifdef SD_EXPORT_SYMBOLS
55 #define _sd_export_ __attribute__ ((visibility("default")))
58 #define _sd_export_ __attribute__ ((visibility("hidden")))
64 _sd_export_
int sd_listen_fds(
int unset_environment) {
66 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
74 if (!(e = getenv(
"LISTEN_PID"))) {
80 l = strtoul(e, &p, 10);
87 if (!p || *p || l <= 0) {
93 if (getpid() != (pid_t) l) {
98 if (!(e = secure_getenv(
"LISTEN_FDS"))) {
104 l = strtoul(e, &p, 10);
116 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
119 if ((flags = fcntl(fd, F_GETFD)) < 0) {
124 if (flags & FD_CLOEXEC)
127 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
136 if (unset_environment) {
137 unsetenv(
"LISTEN_PID");
138 unsetenv(
"LISTEN_FDS");
145 _sd_export_
int sd_is_fifo(
int fd,
const char *path) {
151 memset(&st_fd, 0,
sizeof(st_fd));
152 if (fstat(fd, &st_fd) < 0)
155 if (!S_ISFIFO(st_fd.st_mode))
161 memset(&st_path, 0,
sizeof(st_path));
162 if (stat(path, &st_path) < 0) {
164 if (errno == ENOENT || errno == ENOTDIR)
171 st_path.st_dev == st_fd.st_dev &&
172 st_path.st_ino == st_fd.st_ino;
178 _sd_export_
int sd_is_special(
int fd,
const char *path) {
184 if (fstat(fd, &st_fd) < 0)
187 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
193 if (stat(path, &st_path) < 0) {
195 if (errno == ENOENT || errno == ENOTDIR)
201 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
203 st_path.st_dev == st_fd.st_dev &&
204 st_path.st_ino == st_fd.st_ino;
205 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
206 return st_path.st_rdev == st_fd.st_rdev;
214 static int sd_is_socket_internal(
int fd,
int type,
int listening) {
217 if (fd < 0 || type < 0)
220 if (fstat(fd, &st_fd) < 0)
223 if (!S_ISSOCK(st_fd.st_mode))
228 socklen_t l =
sizeof(other_type);
230 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
233 if (l !=
sizeof(other_type))
236 if (other_type != type)
240 if (listening >= 0) {
242 socklen_t l =
sizeof(accepting);
244 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
247 if (l !=
sizeof(accepting))
250 if (!accepting != !listening)
259 struct sockaddr_in in4;
260 struct sockaddr_in6 in6;
261 struct sockaddr_un un;
262 struct sockaddr_storage storage;
265 _sd_export_
int sd_is_socket(
int fd,
int family,
int type,
int listening) {
271 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
278 memset(&sockaddr, 0,
sizeof(sockaddr));
279 l =
sizeof(sockaddr);
281 if (getsockname(fd, &sockaddr.sa, &l) < 0)
284 if (l <
sizeof(sa_family_t))
287 return sockaddr.sa.sa_family == family;
293 _sd_export_
int sd_is_socket_inet(
int fd,
int family,
int type,
int listening, uint16_t port) {
298 if (family != 0 && family != AF_INET && family != AF_INET6)
301 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
304 memset(&sockaddr, 0,
sizeof(sockaddr));
305 l =
sizeof(sockaddr);
307 if (getsockname(fd, &sockaddr.sa, &l) < 0)
310 if (l <
sizeof(sa_family_t))
313 if (sockaddr.sa.sa_family != AF_INET &&
314 sockaddr.sa.sa_family != AF_INET6)
318 if (sockaddr.sa.sa_family != family)
322 if (sockaddr.sa.sa_family == AF_INET) {
323 if (l <
sizeof(
struct sockaddr_in))
326 return htons(port) == sockaddr.in4.sin_port;
328 if (l <
sizeof(
struct sockaddr_in6))
331 return htons(port) == sockaddr.in6.sin6_port;
338 _sd_export_
int sd_is_socket_unix(
int fd,
int type,
int listening,
const char *path,
size_t length) {
343 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
346 memset(&sockaddr, 0,
sizeof(sockaddr));
347 l =
sizeof(sockaddr);
349 if (getsockname(fd, &sockaddr.sa, &l) < 0)
352 if (l <
sizeof(sa_family_t))
355 if (sockaddr.sa.sa_family != AF_UNIX)
360 length = strlen(path);
364 return l == offsetof(
struct sockaddr_un, sun_path);
369 (l >= offsetof(
struct sockaddr_un, sun_path) + length + 1) &&
370 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
374 (l == offsetof(
struct sockaddr_un, sun_path) + length) &&
375 memcmp(path, sockaddr.un.sun_path, length) == 0;
381 _sd_export_
int sd_is_mq(
int fd,
const char *path) {
382 #if !defined(__linux__)
390 if (mq_getattr(fd, &attr) < 0)
394 char fpath[PATH_MAX];
400 if (fstat(fd, &a) < 0)
403 strncpy(stpcpy(fpath,
"/dev/mqueue"), path,
sizeof(fpath) - 12);
404 fpath[
sizeof(fpath)-1] = 0;
406 if (stat(fpath, &b) < 0)
409 if (a.st_dev != b.st_dev ||
410 a.st_ino != b.st_ino)
418 _sd_export_
int sd_notify(
int unset_environment,
const char *state) {
419 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
423 struct msghdr msghdr;
433 if (!(e = getenv(
"NOTIFY_SOCKET")))
437 if ((e[0] !=
'@' && e[0] !=
'/') || e[1] == 0) {
442 if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
447 memset(&sockaddr, 0,
sizeof(sockaddr));
448 sockaddr.sa.sa_family = AF_UNIX;
449 strncpy(sockaddr.un.sun_path, e,
sizeof(sockaddr.un.sun_path));
451 if (sockaddr.un.sun_path[0] ==
'@')
452 sockaddr.un.sun_path[0] = 0;
454 memset(&iovec, 0,
sizeof(iovec));
455 iovec.iov_base = (
char*) state;
456 iovec.iov_len = strlen(state);
458 memset(&msghdr, 0,
sizeof(msghdr));
459 msghdr.msg_name = &sockaddr;
460 msghdr.msg_namelen = offsetof(
struct sockaddr_un, sun_path) + strlen(e);
462 if (msghdr.msg_namelen >
sizeof(
struct sockaddr_un))
463 msghdr.msg_namelen =
sizeof(
struct sockaddr_un);
465 msghdr.msg_iov = &iovec;
466 msghdr.msg_iovlen = 1;
468 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
476 if (unset_environment)
477 unsetenv(
"NOTIFY_SOCKET");
486 _sd_export_
int sd_notifyf(
int unset_environment,
const char *format, ...) {
487 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
494 va_start(ap, format);
495 r = vasprintf(&p, format, ap);
501 r = sd_notify(unset_environment, p);
508 _sd_export_
int sd_booted(
void) {
509 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
518 if (lstat(
"/sys/fs/cgroup", &a) < 0)
521 if (lstat(
"/sys/fs/cgroup/systemd", &b) < 0)
524 return a.st_dev != b.st_dev;