31 #include <sys/types.h>
33 #include <sys/socket.h>
35 #include <sys/fcntl.h>
36 #include <netinet/in.h>
44 #include "sd-daemon.h"
46 int sd_listen_fds(
int unset_environment) {
48 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
56 if (!(e = getenv(
"LISTEN_PID"))) {
62 l = strtoul(e, &p, 10);
69 if (!p || *p || l <= 0) {
75 if (getpid() != (pid_t) l) {
80 if (!(e = getenv(
"LISTEN_FDS"))) {
86 l = strtoul(e, &p, 10);
98 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
101 if ((flags = fcntl(fd, F_GETFD)) < 0) {
106 if (flags & FD_CLOEXEC)
109 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
118 if (unset_environment) {
119 unsetenv(
"LISTEN_PID");
120 unsetenv(
"LISTEN_FDS");
127 int sd_is_fifo(
int fd,
const char *path) {
133 memset(&st_fd, 0,
sizeof(st_fd));
134 if (fstat(fd, &st_fd) < 0)
137 if (!S_ISFIFO(st_fd.st_mode))
143 memset(&st_path, 0,
sizeof(st_path));
144 if (stat(path, &st_path) < 0) {
146 if (errno == ENOENT || errno == ENOTDIR)
153 st_path.st_dev == st_fd.st_dev &&
154 st_path.st_ino == st_fd.st_ino;
160 static int sd_is_socket_internal(
int fd,
int type,
int listening) {
163 if (fd < 0 || type < 0)
166 if (fstat(fd, &st_fd) < 0)
169 if (!S_ISSOCK(st_fd.st_mode))
174 socklen_t l =
sizeof(other_type);
176 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
179 if (l !=
sizeof(other_type))
182 if (other_type != type)
186 if (listening >= 0) {
188 socklen_t l =
sizeof(accepting);
190 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
193 if (l !=
sizeof(accepting))
196 if (!accepting != !listening)
205 struct sockaddr_in in4;
206 struct sockaddr_in6 in6;
207 struct sockaddr_un un;
208 struct sockaddr_storage storage;
211 int sd_is_socket(
int fd,
int family,
int type,
int listening) {
217 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
224 memset(&sockaddr, 0,
sizeof(sockaddr));
225 l =
sizeof(sockaddr);
227 if (getsockname(fd, &sockaddr.sa, &l) < 0)
230 if (l <
sizeof(sa_family_t))
233 return sockaddr.sa.sa_family == family;
239 int sd_is_socket_inet(
int fd,
int family,
int type,
int listening, uint16_t port) {
244 if (family != 0 && family != AF_INET && family != AF_INET6)
247 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
250 memset(&sockaddr, 0,
sizeof(sockaddr));
251 l =
sizeof(sockaddr);
253 if (getsockname(fd, &sockaddr.sa, &l) < 0)
256 if (l <
sizeof(sa_family_t))
259 if (sockaddr.sa.sa_family != AF_INET &&
260 sockaddr.sa.sa_family != AF_INET6)
264 if (sockaddr.sa.sa_family != family)
268 if (sockaddr.sa.sa_family == AF_INET) {
269 if (l <
sizeof(
struct sockaddr_in))
272 return htons(port) == sockaddr.in4.sin_port;
274 if (l <
sizeof(
struct sockaddr_in6))
277 return htons(port) == sockaddr.in6.sin6_port;
284 int sd_is_socket_unix(
int fd,
int type,
int listening,
const char *path,
size_t length) {
289 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
292 memset(&sockaddr, 0,
sizeof(sockaddr));
293 l =
sizeof(sockaddr);
295 if (getsockname(fd, &sockaddr.sa, &l) < 0)
298 if (l <
sizeof(sa_family_t))
301 if (sockaddr.sa.sa_family != AF_UNIX)
306 length = strlen(path);
310 return l ==
sizeof(sa_family_t);
315 (l >=
sizeof(sa_family_t) + length + 1) &&
316 memcmp(path, sockaddr.un.sun_path, length+1) == 0;
320 (l ==
sizeof(sa_family_t) + length) &&
321 memcmp(path, sockaddr.un.sun_path, length) == 0;
327 int sd_notify(
int unset_environment,
const char *state) {
328 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
332 struct msghdr msghdr;
342 if (!(e = getenv(
"NOTIFY_SOCKET")))
346 if ((e[0] !=
'@' && e[0] !=
'/') || e[1] == 0) {
351 if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
356 memset(&sockaddr, 0,
sizeof(sockaddr));
357 sockaddr.sa.sa_family = AF_UNIX;
358 strncpy(sockaddr.un.sun_path, e,
sizeof(sockaddr.un.sun_path));
360 if (sockaddr.un.sun_path[0] ==
'@')
361 sockaddr.un.sun_path[0] = 0;
363 memset(&iovec, 0,
sizeof(iovec));
364 iovec.iov_base = (
char*) state;
365 iovec.iov_len = strlen(state);
367 memset(&msghdr, 0,
sizeof(msghdr));
368 msghdr.msg_name = &sockaddr;
369 msghdr.msg_namelen =
sizeof(sa_family_t) + strlen(e);
371 if (msghdr.msg_namelen >
sizeof(
struct sockaddr_un))
372 msghdr.msg_namelen =
sizeof(
struct sockaddr_un);
374 msghdr.msg_iov = &iovec;
375 msghdr.msg_iovlen = 1;
377 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
385 if (unset_environment)
386 unsetenv(
"NOTIFY_SOCKET");
395 int sd_notifyf(
int unset_environment,
const char *format, ...) {
396 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
403 va_start(ap, format);
404 r = vasprintf(&p, format, ap);
410 r = sd_notify(unset_environment, p);
417 int sd_booted(
void) {
418 #if defined(DISABLE_SYSTEMD) || !defined(__linux__)
427 if (lstat(
"/sys/fs/cgroup", &a) < 0)
430 if (lstat(
"/sys/fs/cgroup/systemd", &b) < 0)
433 return a.st_dev != b.st_dev;
#define NULL
A null pointer, defined appropriately for C or C++.