]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
man: add working example to LogControl1 manpage
authorLuca Boccassi <bluca@debian.org>
Fri, 21 Apr 2023 22:35:08 +0000 (23:35 +0100)
committerLuca Boccassi <bluca@debian.org>
Sat, 22 Apr 2023 16:41:17 +0000 (17:41 +0100)
Add fully working and documented example that can be copied and pasted

man/logcontrol-example.c [new file with mode: 0644]
man/org.freedesktop.LogControl1.xml

diff --git a/man/logcontrol-example.c b/man/logcontrol-example.c
new file mode 100644 (file)
index 0000000..ec177f2
--- /dev/null
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: MIT-0 */
+
+/* Implements the LogControl1 interface as per specification:
+ * https://www.freedesktop.org/software/systemd/man/org.freedesktop.LogControl1.html
+ *
+ * Compile with 'cc logcontrol-example.c $(pkg-config --libs --cflags libsystemd)'
+ *
+ * To get and set properties via busctl:
+ *
+ * $ busctl --user get-property org.freedesktop.Example \
+ *                              /org/freedesktop/LogControl1 \
+ *                              org.freedesktop.LogControl1 \
+ *                              SyslogIdentifier
+ *   s "example"
+ * $ busctl --user get-property org.freedesktop.Example \
+ *                              /org/freedesktop/LogControl1 \
+ *                              org.freedesktop.LogControl1 \
+ *                              LogTarget
+ *   s "journal"
+ * $ busctl --user get-property org.freedesktop.Example \
+ *                              /org/freedesktop/LogControl1 \
+ *                              org.freedesktop.LogControl1 \
+ *                              LogLevel
+ *   s "info"
+ * $ busctl --user set-property org.freedesktop.Example \
+ *                              /org/freedesktop/LogControl1 \
+ *                              org.freedesktop.LogControl1 \
+ *                              LogLevel \
+ *                              "s" debug
+ * $ busctl --user get-property org.freedesktop.Example \
+ *                              /org/freedesktop/LogControl1 \
+ *                              org.freedesktop.LogControl1 \
+ *                              LogLevel
+ *   s "debug"
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <systemd/sd-bus.h>
+#include <systemd/sd-journal.h>
+
+#define _cleanup_(f) __attribute__((cleanup(f)))
+
+#define check(log_level, x) ({                  \
+  int _r = (x);                                 \
+  errno = _r < 0 ? -_r : 0;                     \
+  sd_journal_print((log_level), #x ": %m");     \
+  if (_r < 0)                                   \
+    return EXIT_FAILURE;                        \
+  })
+
+typedef enum LogTarget {
+  LOG_TARGET_JOURNAL,
+  LOG_TARGET_KMSG,
+  LOG_TARGET_SYSLOG,
+  LOG_TARGET_CONSOLE,
+  _LOG_TARGET_MAX,
+} LogTarget;
+
+static const char* const log_target_table[_LOG_TARGET_MAX] = {
+  [LOG_TARGET_JOURNAL] = "journal",
+  [LOG_TARGET_KMSG]    = "kmsg",
+  [LOG_TARGET_SYSLOG]  = "syslog",
+  [LOG_TARGET_CONSOLE] = "console",
+};
+
+static const char* const log_level_table[LOG_DEBUG + 1] = {
+  [LOG_EMERG]   = "emerg",
+  [LOG_ALERT]   = "alert",
+  [LOG_CRIT]    = "crit",
+  [LOG_ERR]     = "err",
+  [LOG_WARNING] = "warning",
+  [LOG_NOTICE]  = "notice",
+  [LOG_INFO]    = "info",
+  [LOG_DEBUG]   = "debug",
+};
+
+typedef struct object {
+  const char *syslog_identifier;
+  LogTarget log_target;
+  int log_level;
+} object;
+
+static int property_get(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+  object *o = userdata;
+
+  if (strcmp(property, "LogLevel") == 0)
+    return sd_bus_message_append(reply, "s", log_level_table[o->log_level]);
+
+  if (strcmp(property, "LogTarget") == 0)
+    return sd_bus_message_append(reply, "s", log_target_table[o->log_target]);
+
+  if (strcmp(property, "SyslogIdentifier") == 0)
+    return sd_bus_message_append(reply, "s", o->syslog_identifier);
+
+  return sd_bus_error_setf(error,
+                           SD_BUS_ERROR_INVALID_ARGS,
+                           "Unknown property '%s'",
+                           property);
+}
+
+static int property_set(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *message,
+                void *userdata,
+                sd_bus_error *error) {
+
+  object *o = userdata;
+  const char *value;
+  int r;
+
+  r = sd_bus_message_read(message, "s", &value);
+  if (r < 0)
+    return r;
+
+  if (strcmp(property, "LogLevel") == 0) {
+    for (int i = 0; i < LOG_DEBUG + 1; i++)
+      if (strcmp(value, log_level_table[i]) == 0) {
+        o->log_level = i;
+        return 0;
+      }
+
+    return sd_bus_error_setf(error,
+                             SD_BUS_ERROR_INVALID_ARGS,
+                             "Invalid value for LogLevel: '%s'",
+                             value);
+  }
+
+  if (strcmp(value, "LogTarget") == 0) {
+    for (LogTarget i = 0; i < _LOG_TARGET_MAX; i++)
+      if (strcmp(value, log_target_table[i]) == 0) {
+        o->log_target = i;
+        return 0;
+      }
+
+    return sd_bus_error_setf(error,
+                             SD_BUS_ERROR_INVALID_ARGS,
+                             "Invalid value for LogTarget: '%s'",
+                             value);
+  }
+
+  return sd_bus_error_setf(error,
+                           SD_BUS_ERROR_INVALID_ARGS,
+                           "Unknown property '%s'",
+                           property);
+}
+
+/* https://www.freedesktop.org/software/systemd/man/sd_bus_add_object.html
+ */
+static const sd_bus_vtable vtable[] = {
+  SD_BUS_VTABLE_START(0),
+  SD_BUS_WRITABLE_PROPERTY(
+    "LogLevel", "s",
+    property_get, property_set,
+    0,
+    0),
+  SD_BUS_WRITABLE_PROPERTY(
+    "LogTarget", "s",
+    property_get, property_set,
+    0,
+    0),
+  SD_BUS_PROPERTY(
+    "SyslogIdentifier", "s",
+    property_get,
+    0,
+    SD_BUS_VTABLE_PROPERTY_CONST),
+  SD_BUS_VTABLE_END
+};
+
+int main(int argc, char **argv) {
+  /* The bus should be relinquished before the program terminates. The cleanup
+   * attribute allows us to do it nicely and cleanly whenever we exit the
+   * block.
+   */
+  _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+
+  /* Acquire a connection to the bus, letting the library work out the details.
+   * https://www.freedesktop.org/software/systemd/man/sd_bus_default.html
+   */
+  sd_bus_default(&bus);
+
+  object o = {
+    .log_level = LOG_INFO,
+    .log_target = LOG_TARGET_JOURNAL,
+    .syslog_identifier = "example",
+  };
+
+  /* Publish an interface on the bus, specifying our well-known object access
+   * path and public interface name.
+   * https://www.freedesktop.org/software/systemd/man/sd_bus_add_object.html
+   * https://dbus.freedesktop.org/doc/dbus-tutorial.html
+   */
+  check(o.log_level, sd_bus_add_object_vtable(bus, NULL,
+                                              "/org/freedesktop/LogControl1",
+                                              "org.freedesktop.LogControl1",
+                                              vtable,
+                                              &o));
+
+  /* By default the service is assigned an ephemeral name. Also add a fixed
+   * one, so that clients know whom to call.
+   * https://www.freedesktop.org/software/systemd/man/sd_bus_request_name.html
+   */
+  check(o.log_level, sd_bus_request_name(bus, "org.freedesktop.Example", 0));
+
+  for (;;) {
+    /* https://www.freedesktop.org/software/systemd/man/sd_bus_wait.html
+     */
+    check(o.log_level, sd_bus_wait(bus, UINT64_MAX));
+    /* https://www.freedesktop.org/software/systemd/man/sd_bus_process.html
+     */
+    check(o.log_level, sd_bus_process(bus, NULL));
+  }
+
+  /* https://www.freedesktop.org/software/systemd/man/sd_bus_release_name.html
+   */
+  check(o.log_level, sd_bus_release_name(bus, "org.freedesktop.Example"));
+
+  return 0;
+}
index da6dd7628e281732e7ccfc2f48a820c00e9bd317..1694453bafce0b1666e9fa5d1e4145a3c1c09a60 100644 (file)
@@ -116,6 +116,20 @@ node /org/freedesktop/LogControl1 {
     for details about <varname>BusName=</varname>.)</para>
   </refsect1>
 
+  <refsect1>
+    <title>Example</title>
+
+    <example>
+      <title>Create a simple listener on the bus that implements LogControl1</title>
+
+      <programlisting><xi:include href="logcontrol-example.c" parse="text"/></programlisting>
+
+      <para>This creates a simple server on the bus. It implements the LogControl1 interface by providing
+      the required properties and allowing to set the writable ones. It logs at the configured log level using
+      <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+    </example>
+  </refsect1>
+
   <refsect1>
     <title>See Also</title>
     <para>