]>
git.ipfire.org Git - thirdparty/systemd.git/blob - man/notify-selfcontained-example.c
1 /* SPDX-License-Identifier: MIT-0 */
3 /* Implement the systemd notify protocol without external dependencies.
4 * Supports both readiness notification on startup and on reloading,
5 * according to the protocol defined at:
6 * https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html
7 * This protocol is guaranteed to be stable as per:
8 * https://systemd.io/PORTABILITY_AND_STABILITY/ */
18 #include <sys/socket.h>
23 #define _cleanup_(f) __attribute__((cleanup(f)))
25 static void closep(int *fd
) {
33 static int notify(const char *message
) {
34 union sockaddr_union
{
36 struct sockaddr_un sun
;
38 .sun
.sun_family
= AF_UNIX
,
40 size_t path_length
, message_length
;
41 _cleanup_(closep
) int fd
= -1;
42 const char *socket_path
;
44 /* Verify the argument first */
48 message_length
= strlen(message
);
49 if (message_length
== 0)
52 /* If the variable is not set, the protocol is a noop */
53 socket_path
= getenv("NOTIFY_SOCKET");
55 return 0; /* Not set? Nothing to do */
57 /* Only AF_UNIX is supported, with path or abstract sockets */
58 if (socket_path
[0] != '/' && socket_path
[0] != '@')
61 path_length
= strlen(socket_path
);
62 /* Ensure there is room for NUL byte */
63 if (path_length
>= sizeof(socket_addr
.sun
.sun_path
))
66 memcpy(socket_addr
.sun
.sun_path
, socket_path
, path_length
);
68 /* Support for abstract socket */
69 if (socket_addr
.sun
.sun_path
[0] == '@')
70 socket_addr
.sun
.sun_path
[0] = 0;
72 fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0);
76 if (connect(fd
, &socket_addr
.sa
, offsetof(struct sockaddr_un
, sun_path
) + path_length
) != 0)
79 ssize_t written
= write(fd
, message
, message_length
);
80 if (written
!= (ssize_t
) message_length
)
81 return written
< 0 ? -errno
: -EPROTO
;
83 return 1; /* Notified! */
86 static int notify_ready(void) {
87 return notify("READY=1");
90 static int notify_reloading(void) {
91 /* A buffer with length sufficient to format the maximum UINT64 value. */
92 char reload_message
[sizeof("RELOADING=1\nMONOTONIC_USEC=18446744073709551615")];
96 /* Notify systemd that we are reloading, including a CLOCK_MONOTONIC timestamp in usec
97 * so that the program is compatible with a Type=notify-reload service. */
99 if (clock_gettime(CLOCK_MONOTONIC
, &ts
) < 0)
102 if (ts
.tv_sec
< 0 || ts
.tv_nsec
< 0 ||
103 (uint64_t) ts
.tv_sec
> (UINT64_MAX
- (ts
.tv_nsec
/ 1000ULL)) / 1000000ULL)
106 now
= (uint64_t) ts
.tv_sec
* 1000000ULL + (uint64_t) ts
.tv_nsec
/ 1000ULL;
108 if (snprintf(reload_message
, sizeof(reload_message
), "RELOADING=1\nMONOTONIC_USEC=%" PRIu64
, now
) < 0)
111 return notify(reload_message
);
114 static int notify_stopping(void) {
115 return notify("STOPPING=1");
118 static volatile sig_atomic_t reloading
= 0;
119 static volatile sig_atomic_t terminating
= 0;
121 static void signal_handler(int sig
) {
124 else if (sig
== SIGINT
|| sig
== SIGTERM
)
128 int main(int argc
, char **argv
) {
129 struct sigaction sa
= {
130 .sa_handler
= signal_handler
,
131 .sa_flags
= SA_RESTART
,
135 /* Setup signal handlers */
136 sigemptyset(&sa
.sa_mask
);
137 sigaction(SIGHUP
, &sa
, NULL
);
138 sigaction(SIGINT
, &sa
, NULL
);
139 sigaction(SIGTERM
, &sa
, NULL
);
141 /* Do more service initialization work here … */
143 /* Now that all the preparations steps are done, signal readiness */
147 fprintf(stderr
, "Failed to notify readiness to $NOTIFY_SOCKET: %s\n", strerror(-r
));
151 while (!terminating
) {
155 /* As a separate but related feature, we can also notify the manager
156 * when reloading configuration. This allows accurate state-tracking,
157 * and also automated hook-in of 'systemctl reload' without having to
158 * specify manually an ExecReload= line in the unit file. */
160 r
= notify_reloading();
162 fprintf(stderr
, "Failed to notify reloading to $NOTIFY_SOCKET: %s\n", strerror(-r
));
166 /* Do some reconfiguration work here … */
170 fprintf(stderr
, "Failed to notify readiness to $NOTIFY_SOCKET: %s\n", strerror(-r
));
175 /* Do some daemon work here … */
179 r
= notify_stopping();
181 fprintf(stderr
, "Failed to report termination to $NOTIFY_SOCKET: %s\n", strerror(-r
));
185 /* Do some shutdown work here … */