mirror of
https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
synced 2026-10-24 00:48:53 +03:00
Free the list of line proxies stored for the duration of the program at
exit to fix a memory leak.
Note: these objects need to be kept alive for D-Bus events to work.
Fixes: a5ab76da1e ("dbus: add the D-Bus daemon, command-line client and tests")
Link: https://lore.kernel.org/r/20241007-dbus-memory-fixes-v1-3-0d56d1aa032d@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
193 lines
5.2 KiB
C
193 lines
5.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
// SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
|
|
|
|
#include <gio/gio.h>
|
|
#include <glib-unix.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "common.h"
|
|
|
|
typedef struct {
|
|
GList *lines;
|
|
} MonitorData;
|
|
|
|
static void on_edge_event(GpiodbusLine *line, GVariant *args,
|
|
gpointer user_data G_GNUC_UNUSED)
|
|
{
|
|
const char *name = gpiodbus_line_get_name(line);
|
|
guint64 global_seqno, line_seqno, timestamp;
|
|
gint32 edge;
|
|
|
|
g_variant_get(args, "(ittt)", &edge, ×tamp,
|
|
&global_seqno, &line_seqno);
|
|
|
|
g_print("%"G_GUINT64_FORMAT" %s ",
|
|
timestamp, edge ? "rising " : "falling");
|
|
if (strlen(name))
|
|
g_print("\"%s\"\n", name);
|
|
else
|
|
g_print("%u\n", gpiodbus_line_get_offset(line));
|
|
}
|
|
|
|
static void connect_edge_event(gpointer elem, gpointer user_data)
|
|
{
|
|
GpiodbusObject *line_obj = elem;
|
|
MonitorData *data = user_data;
|
|
g_autoptr(GError) err = NULL;
|
|
const gchar *line_obj_path;
|
|
GpiodbusLine *line;
|
|
|
|
line_obj_path = g_dbus_object_get_object_path(G_DBUS_OBJECT(line_obj));
|
|
|
|
line = gpiodbus_line_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
|
"io.gpiod1", line_obj_path,
|
|
NULL, &err);
|
|
if (err)
|
|
die_gerror(err, "Failed to get D-Bus proxy for '%s'",
|
|
line_obj_path);
|
|
|
|
if (!gpiodbus_line_get_managed(line))
|
|
die("Line must be managed by gpio-manager in order to be monitored");
|
|
|
|
if (g_strcmp0(gpiodbus_line_get_edge_detection(line), "none") == 0)
|
|
die("Edge detection must be enabled for monitored lines");
|
|
|
|
data->lines = g_list_append(data->lines, line);
|
|
|
|
g_signal_connect(line, "edge-event", G_CALLBACK(on_edge_event), NULL);
|
|
}
|
|
|
|
int gpiocli_monitor_main(int argc, char **argv)
|
|
{
|
|
static const gchar *const summary =
|
|
"Get values of one or more GPIO lines.";
|
|
|
|
static const gchar *const description =
|
|
"If -r/--request is specified then all the lines must belong to the same\n"
|
|
"request (and - by extension - the same chip).\n"
|
|
"\n"
|
|
"If no lines are specified but -r/--request was passed then all lines within\n"
|
|
"the request will be used.";
|
|
|
|
g_autoptr(GDBusObjectManager) manager = NULL;
|
|
const gchar *request_name = NULL, *chip_path;
|
|
g_autolist(GpiodbusObject) line_objs = NULL;
|
|
g_autoptr(GpiodbusObject) chip_obj = NULL;
|
|
g_autoptr(GpiodbusObject) req_obj = NULL;
|
|
g_autoptr(GArray) offsets = NULL;
|
|
g_autoptr(GMainLoop) loop = NULL;
|
|
g_auto(GStrv) lines = NULL;
|
|
GpiodbusRequest *request;
|
|
MonitorData data = { };
|
|
gsize num_lines, i;
|
|
guint watch_id;
|
|
gboolean ret;
|
|
|
|
const GOptionEntry opts[] = {
|
|
{
|
|
.long_name = "request",
|
|
.short_name = 'r',
|
|
.flags = G_OPTION_FLAG_NONE,
|
|
.arg = G_OPTION_ARG_STRING,
|
|
.arg_data = &request_name,
|
|
.description = "restrict scope to a particular request",
|
|
.arg_description = "<request>",
|
|
},
|
|
{
|
|
.long_name = G_OPTION_REMAINING,
|
|
.flags = G_OPTION_FLAG_NONE,
|
|
.arg = G_OPTION_ARG_STRING_ARRAY,
|
|
.arg_data = &lines,
|
|
.arg_description = "[line0] [line1]...",
|
|
},
|
|
{ }
|
|
};
|
|
|
|
parse_options(opts, summary, description, &argc, &argv);
|
|
|
|
watch_id = g_bus_watch_name(G_BUS_TYPE_SYSTEM, "io.gpiod1",
|
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
|
NULL, die_on_name_vanished, NULL, NULL);
|
|
check_manager();
|
|
|
|
if (!lines && !request_name)
|
|
die_parsing_opts("either at least one line or the request must be specified");
|
|
|
|
if (request_name) {
|
|
req_obj = get_request_obj(request_name);
|
|
request = gpiodbus_object_peek_request(req_obj);
|
|
chip_path = gpiodbus_request_get_chip_path(request);
|
|
chip_obj = get_chip_obj_by_path(chip_path);
|
|
offsets = g_array_new(FALSE, TRUE, sizeof(guint));
|
|
|
|
if (lines) {
|
|
num_lines = g_strv_length(lines);
|
|
|
|
for (i = 0; i < num_lines; i++) {
|
|
g_autoptr(GpiodbusObject) line_obj = NULL;
|
|
|
|
line_obj = get_line_obj_by_name_for_chip(
|
|
chip_obj, lines[i]);
|
|
if (!line_obj)
|
|
die("Line not found: %s\n", lines[i]);
|
|
|
|
line_objs = g_list_append(line_objs,
|
|
g_object_ref(line_obj));
|
|
}
|
|
} else {
|
|
offsets = get_request_offsets(request);
|
|
manager = get_object_manager_client(chip_path);
|
|
|
|
for (i = 0; i < offsets->len; i++) {
|
|
g_autoptr(GpiodbusObject) line_obj = NULL;
|
|
g_autofree char *obj_path = NULL;
|
|
|
|
obj_path = g_strdup_printf("%s/line%u",
|
|
chip_path,
|
|
g_array_index(
|
|
offsets,
|
|
guint, i));
|
|
|
|
line_obj = GPIODBUS_OBJECT(
|
|
g_dbus_object_manager_get_object(
|
|
manager,
|
|
obj_path));
|
|
if (!line_obj)
|
|
die("Line not found: %u\n",
|
|
g_array_index(offsets, guint, i));
|
|
|
|
line_objs = g_list_append(line_objs,
|
|
g_object_ref(line_obj));
|
|
}
|
|
}
|
|
} else {
|
|
num_lines = g_strv_length(lines);
|
|
|
|
for (i = 0; i < num_lines; i++) {
|
|
g_autoptr(GpiodbusObject) line_obj = NULL;
|
|
|
|
ret = get_line_obj_by_name(lines[i], &line_obj, NULL);
|
|
if (!ret)
|
|
die("Line not found: %s\n", lines[i]);
|
|
|
|
line_objs = g_list_append(line_objs,
|
|
g_object_ref(line_obj));
|
|
}
|
|
}
|
|
|
|
g_list_foreach(line_objs, connect_edge_event, &data);
|
|
|
|
loop = g_main_loop_new(NULL, FALSE);
|
|
g_unix_signal_add(SIGTERM, quit_main_loop_on_signal, loop);
|
|
g_unix_signal_add(SIGINT, quit_main_loop_on_signal, loop);
|
|
|
|
g_main_loop_run(loop);
|
|
|
|
g_list_free_full(data.lines, g_object_unref);
|
|
g_bus_unwatch_name(watch_id);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|