1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2022-2023 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
#include <gio/gio.h>
#include <signal.h>
#include "daemon-process.h"
struct _GpiodbusDaemonProcess {
GObject parent_instance;
GSubprocess *proc;
};
G_DEFINE_TYPE(GpiodbusDaemonProcess, gpiodbus_daemon_process, G_TYPE_OBJECT);
static gboolean on_timeout(gpointer data G_GNUC_UNUSED)
{
g_error("timeout reached waiting for the daemon name to appear on the system bus");
return G_SOURCE_REMOVE;
}
static void on_name_appeared(GDBusConnection *con G_GNUC_UNUSED,
const gchar *name G_GNUC_UNUSED,
const gchar *name_owner G_GNUC_UNUSED,
gpointer data)
{
gboolean *name_state = data;
*name_state = TRUE;
}
static void gpiodbus_daemon_process_constructed(GObject *obj)
{
GpiodbusDaemonProcess *self = GPIODBUS_DAEMON_PROCESS_OBJ(obj);
const gchar *path = g_getenv("GPIODBUS_TEST_DAEMON_PATH");
g_autoptr(GDBusConnection) con = NULL;
g_autofree gchar *addr = NULL;
g_autoptr(GError) err = NULL;
gboolean name_state = FALSE;
guint watch_id, timeout_id;
if (!path)
g_error("GPIODBUS_TEST_DAEMON_PATH environment variable must be set");
addr = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
if (!addr)
g_error("failed to get an address for system bus: %s",
err->message);
con = g_dbus_connection_new_for_address_sync(addr,
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
NULL, NULL, &err);
if (!con)
g_error("failed to get a dbus connection: %s", err->message);
watch_id = g_bus_watch_name_on_connection(con, "io.gpiod1",
G_BUS_NAME_WATCHER_FLAGS_NONE,
on_name_appeared, NULL,
&name_state, NULL);
self->proc = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_SILENCE |
G_SUBPROCESS_FLAGS_STDERR_SILENCE,
&err, path, NULL);
if (!self->proc)
g_error("failed to launch the gpio-manager process: %s",
err->message);
timeout_id = g_timeout_add_seconds(5, on_timeout, NULL);
while (!name_state)
g_main_context_iteration(NULL, TRUE);
g_bus_unwatch_name(watch_id);
g_source_remove(timeout_id);
G_OBJECT_CLASS(gpiodbus_daemon_process_parent_class)->constructed(obj);
}
static void gpiodbus_daemon_process_kill(GSubprocess *proc)
{
g_autoptr(GError) err = NULL;
gint status;
g_subprocess_send_signal(proc, SIGTERM);
g_subprocess_wait(proc, NULL, &err);
if (err)
g_error("failed to collect the exit status of gpio-manager: %s",
err->message);
if (!g_subprocess_get_if_exited(proc))
g_error("dbus-manager process did not exit normally");
status = g_subprocess_get_exit_status(proc);
if (status != 0)
g_error("dbus-manager process exited with a non-zero status: %d",
status);
g_object_unref(proc);
}
static void gpiodbus_daemon_process_dispose(GObject *obj)
{
GpiodbusDaemonProcess *self = GPIODBUS_DAEMON_PROCESS_OBJ(obj);
g_clear_pointer(&self->proc, gpiodbus_daemon_process_kill);
G_OBJECT_CLASS(gpiodbus_daemon_process_parent_class)->dispose(obj);
}
static void
gpiodbus_daemon_process_class_init(GpiodbusDaemonProcessClass *proc_class)
{
GObjectClass *class = G_OBJECT_CLASS(proc_class);
class->constructed = gpiodbus_daemon_process_constructed;
class->dispose = gpiodbus_daemon_process_dispose;
}
static void gpiodbus_daemon_process_init(GpiodbusDaemonProcess *self)
{
self->proc = NULL;
}
GpiodbusDaemonProcess *gpiodbus_daemon_process_new(void)
{
return g_object_new(GPIODBUS_DAEMON_PROCESS_TYPE, NULL);
}
|