master
c 148 lines 4.59 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "libnetdata/libnetdata.h"
4 #include "daemon-systemd-watcher.h"
5 #include "daemon-service.h"
6 #include "daemon-shutdown.h"
7
8 #include <systemd/sd-bus.h>
9
10 /* Callback function to handle the PrepareForShutdown signal.
11 * The signal sends a boolean: true indicates that shutdown is starting,
12 * false indicates that a previously initiated shutdown was canceled.
13 */
14 static int shutdown_event_handler(sd_bus_message *m, void *userdata __maybe_unused, sd_bus_error *ret_error __maybe_unused) {
15 int shutdown;
16 int r = sd_bus_message_read(m, "b", &shutdown);
17 if (r < 0) {
18 nd_log(NDLS_DAEMON, NDLP_ERR,
19 "SYSTEMD DBUS: Failed to parse shutdown message: %s",
20 strerror(-r));
21 return r;
22 }
23
24 nd_log(NDLS_DAEMON, NDLP_NOTICE,
25 "SYSTEMD DBUS: Received PrepareForShutdown signal: shutdown=%s",
26 shutdown ? "true" : "false");
27
28 if(shutdown)
29 netdata_exit_gracefully(EXIT_REASON_SYSTEM_SHUTDOWN, true);
30
31 return 0;
32 }
33
34 /* Callback function to handle the PrepareForSleep signal.
35 * The signal sends a boolean: true indicates that the system is preparing to suspend,
36 * false indicates that a previous suspend was canceled (i.e. resuming).
37 */
38 static int suspend_event_handler(sd_bus_message *m, void *userdata __maybe_unused, sd_bus_error *ret_error __maybe_unused) {
39 int suspend;
40 int r = sd_bus_message_read(m, "b", &suspend);
41 if (r < 0) {
42 nd_log(NDLS_DAEMON, NDLP_ERR,
43 "SYSTEMD DBUS: Failed to parse suspend message: %s",
44 strerror(-r));
45 return r;
46 }
47
48 nd_log(NDLS_DAEMON, NDLP_NOTICE,
49 "SYSTEMD DBUS: Received PrepareForSleep signal: suspend=%s\n",
50 suspend ? "true (suspending)" : "false (resuming)");
51
52 // Here you can trigger your suspend/resume logic.
53 return 0;
54 }
55
56 /* Function that sets up the sd-bus listener for shutdown and suspend events.
57 * This function blocks in a loop processing bus events.
58 */
59 static void listen_for_systemd_dbus_events(void) {
60 sd_bus *bus = NULL;
61 sd_bus_slot *shutdown_slot = NULL;
62 sd_bus_slot *suspend_slot = NULL;
63 int r;
64
65 // Connect to the system bus.
66 r = sd_bus_open_system(&bus);
67 if (r < 0) {
68 nd_log(NDLS_DAEMON, NDLP_ERR,
69 "SYSTEMD DBUS: Failed to connect to system bus: %s",
70 strerror(-r));
71 goto finish;
72 }
73
74 // Add a match rule for the PrepareForShutdown signal on the login1 manager.
75 r = sd_bus_add_match(
76 bus,
77 &shutdown_slot,
78 "type='signal',"
79 "sender='org.freedesktop.login1',"
80 "interface='org.freedesktop.login1.Manager',"
81 "member='PrepareForShutdown'",
82 shutdown_event_handler,
83 NULL);
84 if (r < 0) {
85 nd_log(NDLS_DAEMON, NDLP_ERR,
86 "SYSTEMD DBUS: Failed to add signal match for shutdown: %s",
87 strerror(-r));
88 goto finish;
89 }
90
91 // Add a match rule for the PrepareForSleep signal on the login1 manager.
92 r = sd_bus_add_match(
93 bus,
94 &suspend_slot,
95 "type='signal',"
96 "sender='org.freedesktop.login1',"
97 "interface='org.freedesktop.login1.Manager',"
98 "member='PrepareForSleep'",
99 suspend_event_handler,
100 NULL);
101 if (r < 0) {
102 nd_log(NDLS_DAEMON, NDLP_ERR,
103 "SYSTEMD DBUS: Failed to add signal match for suspend: %s",
104 strerror(-r));
105 goto finish;
106 }
107
108 // Process incoming D-Bus messages.
109 while (service_running(SERVICE_SYSTEMD) && bus != NULL) {
110 // Process any pending messages.
111 r = sd_bus_process(bus, NULL);
112 if (r < 0) {
113 nd_log(NDLS_DAEMON, NDLP_ERR,
114 "SYSTEMD DBUS: Failed to process bus: %s",
115 strerror(-r));
116 goto finish;
117 }
118 if (r > 0) // Message was processed; check for more.
119 continue;
120
121 // Wait for the next signal.
122 do {
123 r = sd_bus_wait(bus, USEC_PER_SEC);
124 } while((r == 0 || r == -EINTR) && service_running(SERVICE_SYSTEMD));
125
126 if (r < 0) {
127 nd_log(NDLS_DAEMON, NDLP_ERR, "SYSTEMD DBUS: Failed to wait on bus: %s", strerror(-r));
128 break;
129 }
130 }
131
132 finish:
133 sd_bus_slot_unref(shutdown_slot);
134 sd_bus_slot_unref(suspend_slot);
135 sd_bus_unref(bus);
136 }
137
138 void systemd_watcher_thread(void *arg) {
139 struct netdata_static_thread *static_thread = arg;
140
141 service_register(NULL, NULL, NULL);
142
143 listen_for_systemd_dbus_events();
144
145 service_exits();
146 worker_unregister();
147 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
148 }