1:255.13-alt1
[systemd_ALT.git] / man / logcontrol-example.c
blobc199ec7a0f2b1c33d57924c63f785d4052aae238
1 /* SPDX-License-Identifier: MIT-0 */
3 /* Implements the LogControl1 interface as per specification:
4 * https://www.freedesktop.org/software/systemd/man/org.freedesktop.LogControl1.html
6 * Compile with 'cc logcontrol-example.c $(pkg-config --libs --cflags libsystemd)'
8 * To get and set properties via busctl:
10 * $ busctl --user get-property org.freedesktop.Example \
11 * /org/freedesktop/LogControl1 \
12 * org.freedesktop.LogControl1 \
13 * SyslogIdentifier
14 * s "example"
15 * $ busctl --user get-property org.freedesktop.Example \
16 * /org/freedesktop/LogControl1 \
17 * org.freedesktop.LogControl1 \
18 * LogTarget
19 * s "journal"
20 * $ busctl --user get-property org.freedesktop.Example \
21 * /org/freedesktop/LogControl1 \
22 * org.freedesktop.LogControl1 \
23 * LogLevel
24 * s "info"
25 * $ busctl --user set-property org.freedesktop.Example \
26 * /org/freedesktop/LogControl1 \
27 * org.freedesktop.LogControl1 \
28 * LogLevel \
29 * "s" debug
30 * $ busctl --user get-property org.freedesktop.Example \
31 * /org/freedesktop/LogControl1 \
32 * org.freedesktop.LogControl1 \
33 * LogLevel
34 * s "debug"
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <syslog.h>
41 #include <systemd/sd-bus.h>
42 #include <systemd/sd-journal.h>
44 #define _cleanup_(f) __attribute__((cleanup(f)))
46 #define check(log_level, x) ({ \
47 int _r = (x); \
48 errno = _r < 0 ? -_r : 0; \
49 sd_journal_print((log_level), #x ": %m"); \
50 if (_r < 0) \
51 return EXIT_FAILURE; \
54 typedef enum LogTarget {
55 LOG_TARGET_JOURNAL,
56 LOG_TARGET_KMSG,
57 LOG_TARGET_SYSLOG,
58 LOG_TARGET_CONSOLE,
59 _LOG_TARGET_MAX,
60 } LogTarget;
62 static const char* const log_target_table[_LOG_TARGET_MAX] = {
63 [LOG_TARGET_JOURNAL] = "journal",
64 [LOG_TARGET_KMSG] = "kmsg",
65 [LOG_TARGET_SYSLOG] = "syslog",
66 [LOG_TARGET_CONSOLE] = "console",
69 static const char* const log_level_table[LOG_DEBUG + 1] = {
70 [LOG_EMERG] = "emerg",
71 [LOG_ALERT] = "alert",
72 [LOG_CRIT] = "crit",
73 [LOG_ERR] = "err",
74 [LOG_WARNING] = "warning",
75 [LOG_NOTICE] = "notice",
76 [LOG_INFO] = "info",
77 [LOG_DEBUG] = "debug",
80 typedef struct object {
81 const char *syslog_identifier;
82 LogTarget log_target;
83 int log_level;
84 } object;
86 static int property_get(
87 sd_bus *bus,
88 const char *path,
89 const char *interface,
90 const char *property,
91 sd_bus_message *reply,
92 void *userdata,
93 sd_bus_error *error) {
95 object *o = userdata;
97 if (strcmp(property, "LogLevel") == 0)
98 return sd_bus_message_append(reply, "s", log_level_table[o->log_level]);
100 if (strcmp(property, "LogTarget") == 0)
101 return sd_bus_message_append(reply, "s", log_target_table[o->log_target]);
103 if (strcmp(property, "SyslogIdentifier") == 0)
104 return sd_bus_message_append(reply, "s", o->syslog_identifier);
106 return sd_bus_error_setf(error,
107 SD_BUS_ERROR_UNKNOWN_PROPERTY,
108 "Unknown property '%s'",
109 property);
112 static int property_set(
113 sd_bus *bus,
114 const char *path,
115 const char *interface,
116 const char *property,
117 sd_bus_message *message,
118 void *userdata,
119 sd_bus_error *error) {
121 object *o = userdata;
122 const char *value;
123 int r;
125 r = sd_bus_message_read(message, "s", &value);
126 if (r < 0)
127 return r;
129 if (strcmp(property, "LogLevel") == 0) {
130 for (int i = 0; i < LOG_DEBUG + 1; i++)
131 if (strcmp(value, log_level_table[i]) == 0) {
132 o->log_level = i;
133 setlogmask(LOG_UPTO(i));
134 return 0;
137 return sd_bus_error_setf(error,
138 SD_BUS_ERROR_INVALID_ARGS,
139 "Invalid value for LogLevel: '%s'",
140 value);
143 if (strcmp(property, "LogTarget") == 0) {
144 for (LogTarget i = 0; i < _LOG_TARGET_MAX; i++)
145 if (strcmp(value, log_target_table[i]) == 0) {
146 o->log_target = i;
147 return 0;
150 return sd_bus_error_setf(error,
151 SD_BUS_ERROR_INVALID_ARGS,
152 "Invalid value for LogTarget: '%s'",
153 value);
156 return sd_bus_error_setf(error,
157 SD_BUS_ERROR_UNKNOWN_PROPERTY,
158 "Unknown property '%s'",
159 property);
162 /* https://www.freedesktop.org/software/systemd/man/sd_bus_add_object.html
164 static const sd_bus_vtable vtable[] = {
165 SD_BUS_VTABLE_START(0),
166 SD_BUS_WRITABLE_PROPERTY(
167 "LogLevel", "s",
168 property_get, property_set,
171 SD_BUS_WRITABLE_PROPERTY(
172 "LogTarget", "s",
173 property_get, property_set,
176 SD_BUS_PROPERTY(
177 "SyslogIdentifier", "s",
178 property_get,
180 SD_BUS_VTABLE_PROPERTY_CONST),
181 SD_BUS_VTABLE_END
184 int main(int argc, char **argv) {
185 /* The bus should be relinquished before the program terminates. The cleanup
186 * attribute allows us to do it nicely and cleanly whenever we exit the
187 * block.
189 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
191 object o = {
192 .log_level = LOG_INFO,
193 .log_target = LOG_TARGET_JOURNAL,
194 .syslog_identifier = "example",
197 /* https://man7.org/linux/man-pages/man3/setlogmask.3.html
198 * Programs using syslog() instead of sd_journal can use this API to cut logs
199 * emission at the source.
201 setlogmask(LOG_UPTO(o.log_level));
203 /* Acquire a connection to the bus, letting the library work out the details.
204 * https://www.freedesktop.org/software/systemd/man/sd_bus_default.html
206 check(o.log_level, sd_bus_default(&bus));
208 /* Publish an interface on the bus, specifying our well-known object access
209 * path and public interface name.
210 * https://www.freedesktop.org/software/systemd/man/sd_bus_add_object.html
211 * https://dbus.freedesktop.org/doc/dbus-tutorial.html
213 check(o.log_level, sd_bus_add_object_vtable(bus, NULL,
214 "/org/freedesktop/LogControl1",
215 "org.freedesktop.LogControl1",
216 vtable,
217 &o));
219 /* By default the service is assigned an ephemeral name. Also add a fixed
220 * one, so that clients know whom to call.
221 * https://www.freedesktop.org/software/systemd/man/sd_bus_request_name.html
223 check(o.log_level, sd_bus_request_name(bus, "org.freedesktop.Example", 0));
225 for (;;) {
226 /* https://www.freedesktop.org/software/systemd/man/sd_bus_wait.html
228 check(o.log_level, sd_bus_wait(bus, UINT64_MAX));
229 /* https://www.freedesktop.org/software/systemd/man/sd_bus_process.html
231 check(o.log_level, sd_bus_process(bus, NULL));
234 /* https://www.freedesktop.org/software/systemd/man/sd_bus_release_name.html
236 check(o.log_level, sd_bus_release_name(bus, "org.freedesktop.Example"));
238 return 0;