177 lines
5.1 KiB
C
177 lines
5.1 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
/* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Copyright (C) 2009 Red Hat, Inc.
|
|
*/
|
|
|
|
#include <glib.h>
|
|
#include <gudev/gudev.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <signal.h>
|
|
|
|
static GMainLoop *loop = NULL;
|
|
|
|
static void
|
|
signal_handler (int signo)
|
|
{
|
|
if (signo == SIGINT || signo == SIGTERM) {
|
|
g_message ("Caught signal %d, shutting down...", signo);
|
|
g_main_loop_quit (loop);
|
|
}
|
|
}
|
|
|
|
static void
|
|
setup_signals (void)
|
|
{
|
|
struct sigaction action;
|
|
sigset_t mask;
|
|
|
|
sigemptyset (&mask);
|
|
action.sa_handler = signal_handler;
|
|
action.sa_mask = mask;
|
|
action.sa_flags = 0;
|
|
sigaction (SIGTERM, &action, NULL);
|
|
sigaction (SIGINT, &action, NULL);
|
|
}
|
|
|
|
static void println (guint indent, const char *fmt, ...) __attribute__((__format__ (__printf__, 2, 3)));
|
|
|
|
static void
|
|
println (guint indent, const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
GString *output;
|
|
guint i;
|
|
|
|
g_return_if_fail (fmt != NULL);
|
|
|
|
output = g_string_sized_new (250);
|
|
|
|
for (i = 0; i < indent; i++)
|
|
g_string_append_c (output, ' ');
|
|
|
|
va_start (args, fmt);
|
|
g_string_append_vprintf (output, fmt, args);
|
|
va_end (args);
|
|
|
|
g_print ("%s\n", output->str);
|
|
g_string_free (output, TRUE);
|
|
}
|
|
|
|
static void
|
|
dump_device_and_parent (GUdevDevice *device, guint indent)
|
|
{
|
|
const char **list, **iter;
|
|
GUdevDevice *parent;
|
|
char propstr[500];
|
|
guint32 namelen = 0, i;
|
|
|
|
println (indent, "------------------------------------------------------");
|
|
println (indent, "Name: %s", g_udev_device_get_name (device));
|
|
println (indent, "Type: %s", g_udev_device_get_devtype (device));
|
|
println (indent, "Subsys: %s", g_udev_device_get_subsystem (device));
|
|
println (indent, "Number: %s", g_udev_device_get_number (device));
|
|
println (indent, "Path: %s", g_udev_device_get_sysfs_path (device));
|
|
println (indent, "Driver: %s", g_udev_device_get_driver (device));
|
|
println (indent, "Action: %s", g_udev_device_get_action (device));
|
|
println (indent, "Seq Num: %" G_GUINT64_FORMAT, g_udev_device_get_seqnum (device));
|
|
println (indent, "Dev File: %s", g_udev_device_get_device_file (device));
|
|
println (indent, "-----------");
|
|
println (indent, "Properties:");
|
|
|
|
/* Get longest property name length for alignment */
|
|
list = (const char **) g_udev_device_get_property_keys (device);
|
|
for (iter = list; iter && *iter; iter++) {
|
|
if (strlen (*iter) > namelen)
|
|
namelen = strlen (*iter);
|
|
}
|
|
namelen++;
|
|
|
|
for (iter = list; iter && *iter; iter++) {
|
|
strcpy (propstr, *iter);
|
|
strcat (propstr, ":");
|
|
for (i = 0; i < namelen - strlen (*iter); i++)
|
|
strcat (propstr, " ");
|
|
strcat (propstr, g_udev_device_get_property (device, *iter));
|
|
println (indent + 2, "%s", propstr);
|
|
}
|
|
|
|
parent = g_udev_device_get_parent (device);
|
|
if (parent) {
|
|
dump_device_and_parent (parent, indent + 4);
|
|
g_object_unref (parent);
|
|
}
|
|
}
|
|
|
|
static void
|
|
handle_uevent (GUdevClient *client,
|
|
const char *action,
|
|
GUdevDevice *device,
|
|
gpointer user_data)
|
|
{
|
|
const char *expected_subsys = user_data;
|
|
const char *subsys;
|
|
|
|
g_return_if_fail (client != NULL);
|
|
g_return_if_fail (action != NULL);
|
|
g_return_if_fail (device != NULL);
|
|
|
|
/* A bit paranoid */
|
|
subsys = g_udev_device_get_subsystem (device);
|
|
g_return_if_fail (subsys != NULL);
|
|
|
|
g_return_if_fail (!strcmp (subsys, expected_subsys));
|
|
|
|
g_print ("---- (EVENT: %s) ----\n", action);
|
|
dump_device_and_parent (device, 0);
|
|
g_print ("\n");
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
GUdevClient *client;
|
|
const char *subsys[2] = { NULL, NULL };
|
|
GList *list, *iter;
|
|
|
|
if (argc != 2) {
|
|
g_warning ("Usage: %s [subsystem]", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
setup_signals ();
|
|
|
|
subsys[0] = argv[1];
|
|
client = g_udev_client_new (subsys);
|
|
g_signal_connect (client, "uevent", G_CALLBACK (handle_uevent), (gpointer) subsys[0]);
|
|
|
|
list = g_udev_client_query_by_subsystem (client, subsys[0]);
|
|
for (iter = list; iter; iter = g_list_next (iter)) {
|
|
dump_device_and_parent (G_UDEV_DEVICE (iter->data), 0);
|
|
g_print ("\n");
|
|
g_object_unref (G_UDEV_DEVICE (iter->data));
|
|
}
|
|
|
|
g_main_loop_run (loop);
|
|
|
|
return 0;
|
|
}
|