Home | History | Annotate | Line # | Download | only in include
      1 /*	$NetBSD: sd-notify.h,v 1.2 2025/09/05 21:16:19 christos Exp $	*/
      2 
      3 /* SPDX-License-Identifier: MIT-0 */
      4 /* Implement the systemd notify protocol without external dependencies.
      5  * Supports both readiness notification on startup and on reloading,
      6  * according to the protocol defined at:
      7  * https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html
      8  * This protocol is guaranteed to be stable as per:
      9  * https://systemd.io/PORTABILITY_AND_STABILITY/ */
     10 #include <errno.h>
     11 #include <stdlib.h>
     12 #include <stdio.h>
     13 #include <sys/socket.h>
     14 #include <sys/un.h>
     15 #include <unistd.h>
     16 
     17 static int sd_notify(int ignore, const char *message) {
     18     union sockaddr_union {
     19 	struct sockaddr sa;
     20 	struct sockaddr_un sun;
     21     } socket_addr = {
     22 	.sun.sun_family = AF_UNIX,
     23     };
     24     size_t path_length, message_length;
     25     const char *socket_path;
     26     int fd = -1;
     27     int rc = 1;
     28 
     29     socket_path = getenv("NOTIFY_SOCKET");
     30     if (!socket_path)
     31 	return 0; /* Not running under systemd? Nothing to do */
     32 
     33     if (!message)
     34 	return -EINVAL;
     35 
     36     message_length = strlen(message);
     37     if (message_length == 0)
     38 	return -EINVAL;
     39 
     40     /* Only AF_UNIX is supported, with path or abstract sockets */
     41     if (socket_path[0] != '/' && socket_path[0] != '@')
     42 	return -EAFNOSUPPORT;
     43 
     44     path_length = strlen(socket_path);
     45     /* Ensure there is room for NUL byte */
     46     if (path_length >= sizeof(socket_addr.sun.sun_path))
     47 	return -E2BIG;
     48 
     49     memcpy(socket_addr.sun.sun_path, socket_path, path_length);
     50 
     51     /* Support for abstract socket */
     52     if (socket_addr.sun.sun_path[0] == '@')
     53 	socket_addr.sun.sun_path[0] = 0;
     54 
     55     fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
     56     if (fd < 0)
     57 	return -errno;
     58 
     59     ssize_t written = sendto(fd, message, message_length, 0,
     60 			     &socket_addr.sa, offsetof(struct sockaddr_un, sun_path) + path_length);
     61     if (written != (ssize_t) message_length)
     62 	rc = written < 0 ? -errno : -EPROTO;
     63 
     64     close(fd);
     65     return rc;
     66 }
     67