1 /***************************************************************************
4 * lshal.c : Show devices managed by HAL
6 * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
7 * Copyright (C) 2005 Pierre Ossman, <drzeus@drzeus.cx>
9 * Licensed under the Academic Free License version 2.1
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 **************************************************************************/
39 #include <dbus/dbus-glib-lowlevel.h>
40 #include <dbus/dbus-glib.h>
45 * @defgroup HalLsHal List HAL devices
48 * @brief A commandline tool, lshal, for displaying and, optionally,
49 * monitor the devices managed by the HAL daemon. Uses libhal.
54 /** Macro for terminating the program on an unrecoverable error */
55 #define DIE(expr) do {printf("*** [DIE] %s:%s():%d : ", __FILE__, __FUNCTION__, __LINE__); printf expr; printf("\n"); exit(1); } while(0)
57 #define UDI_BASE "/org/freedesktop/Hal/devices/"
59 static LibHalContext
*hal_ctx
;
60 static dbus_bool_t long_list
= FALSE
;
61 static dbus_bool_t tree_view
= FALSE
;
62 static dbus_bool_t short_list
= FALSE
;
63 static char *show_device
= NULL
;
70 /** Generate a short name for a device
72 * @param udi Universal Device Id
75 short_name (const char *udi
)
77 return &udi
[sizeof(UDI_BASE
) - 1];
80 /** Print all properties of a device
82 * @param udi Universal Device Id
86 print_props (const char *udi
)
89 LibHalPropertySet
*props
;
90 LibHalPropertySetIterator it
;
93 dbus_error_init (&error
);
95 props
= libhal_device_get_all_properties (hal_ctx
, udi
, &error
);
97 /* NOTE : This may be NULL if the device was removed
98 * in the daemon; this is because
99 * hal_device_get_all_properties() is a in
100 * essence an IPC call and other stuff may
104 LIBHAL_FREE_DBUS_ERROR (&error
);
108 for (libhal_psi_init (&it
, props
); libhal_psi_has_more (&it
); libhal_psi_next (&it
)) {
109 type
= libhal_psi_get_type (&it
);
111 case LIBHAL_PROPERTY_TYPE_STRING
:
112 printf (" %s = '%s' (string)\n",
113 libhal_psi_get_key (&it
),
114 libhal_psi_get_string (&it
));
117 case LIBHAL_PROPERTY_TYPE_INT32
:
118 printf (" %s = %d (0x%x) (int)\n",
119 libhal_psi_get_key (&it
),
120 libhal_psi_get_int (&it
),
121 libhal_psi_get_int (&it
));
124 case LIBHAL_PROPERTY_TYPE_UINT64
:
125 printf (" %s = %llu (0x%llx) (uint64)\n",
126 libhal_psi_get_key (&it
),
127 (long long unsigned int) libhal_psi_get_uint64 (&it
),
128 (long long unsigned int) libhal_psi_get_uint64 (&it
));
131 case LIBHAL_PROPERTY_TYPE_DOUBLE
:
132 printf (" %s = %g (double)\n",
133 libhal_psi_get_key (&it
),
134 libhal_psi_get_double (&it
));
137 case LIBHAL_PROPERTY_TYPE_BOOLEAN
:
138 printf (" %s = %s (bool)\n",
139 libhal_psi_get_key (&it
),
140 libhal_psi_get_bool (&it
) ? "true" :
144 case LIBHAL_PROPERTY_TYPE_STRLIST
:
149 printf (" %s = {", libhal_psi_get_key (&it
));
151 strlist
= libhal_psi_get_strlist (&it
);
152 for (i
= 0; strlist
[i
] != 0; i
++) {
153 printf ("'%s'", strlist
[i
]);
154 if (strlist
[i
+1] != NULL
)
157 printf ("} (string list)\n");
162 printf ("Unknown type %d=0x%02x\n", type
, type
);
167 libhal_free_property_set (props
);
170 /** Dumps information about a single device
172 * @param udi Universal Device Id
176 dump_device (const char *udi
)
180 dbus_error_init (&error
);
182 if (!libhal_device_exists (hal_ctx
, udi
, &error
)) {
183 LIBHAL_FREE_DBUS_ERROR (&error
);
188 printf ("udi = '%s'\n", udi
);
194 printf ("%s\n", short_name (udi
));
197 /** Dump all children of device
199 * @param udi Universal Device Id of parent
200 * @param num_devices Total number of devices in device list
201 * @param devices List of devices
202 * @param depth Current recursion depth
206 dump_children (char *udi
, int num_devices
, struct Device
*devices
, int depth
)
210 for (i
= 0; i
< num_devices
; i
++) {
212 if (devices
[i
].parent
)
216 if (!devices
[i
].parent
)
218 if (strcmp (devices
[i
].parent
, udi
))
223 printf ("udi = '%s'\n", devices
[i
].name
);
227 for (j
= 0;j
< depth
;j
++)
230 printf ("%s\n", short_name (devices
[i
].name
));
234 print_props (devices
[i
].name
);
238 dump_children(devices
[i
].name
, num_devices
, devices
, depth
+ 1);
242 /** Dump all devices to stdout
251 struct Device
*devices
;
254 dbus_error_init (&error
);
256 device_names
= libhal_get_all_devices (hal_ctx
, &num_devices
, &error
);
257 if (device_names
== NULL
) {
258 LIBHAL_FREE_DBUS_ERROR (&error
);
259 DIE (("Couldn't obtain list of devices\n"));
262 devices
= malloc (sizeof(struct Device
) * num_devices
);
264 libhal_free_string_array (device_names
);
268 for (i
= 0;i
< num_devices
;i
++) {
269 devices
[i
].name
= device_names
[i
];
270 devices
[i
].parent
= libhal_device_get_property_string (hal_ctx
,
271 device_names
[i
], "info.parent", &error
);
273 if (dbus_error_is_set (&error
)) {
274 /* Free the error (which include a dbus_error_init())
275 This should prevent errors if a call above fails */
276 dbus_error_free (&error
);
282 "Dumping %d device(s) from the Global Device List:\n"
283 "-------------------------------------------------\n",
287 dump_children(NULL
, num_devices
, devices
, 0);
289 for (i
= 0;i
< num_devices
;i
++) {
290 if (devices
[i
].parent
)
291 libhal_free_string (devices
[i
].parent
);
295 libhal_free_string_array (device_names
);
299 "Dumped %d device(s) from the Global Device List.\n"
300 "------------------------------------------------\n",
307 /** Invoked when a device is added to the Global Device List. Simply prints
308 * a message on stdout.
310 * @param udi Universal Device Id
313 device_added (LibHalContext
*ctx
,
316 if (show_device
&& strcmp(show_device
, udi
))
320 printf ("*** lshal: device_added, udi='%s'\n", udi
);
323 printf ("%s added\n", short_name (udi
));
326 /** Invoked when a device is removed from the Global Device List. Simply
327 * prints a message on stdout.
329 * @param udi Universal Device Id
332 device_removed (LibHalContext
*ctx
,
335 if (show_device
&& strcmp(show_device
, udi
))
339 printf ("*** lshal: device_removed, udi='%s'\n", udi
);
341 printf ("%s removed\n", short_name (udi
));
344 /** Invoked when device in the Global Device List acquires a new capability.
345 * Prints the name of the capability to stdout.
347 * @param udi Universal Device Id
348 * @param capability Name of capability
351 device_new_capability (LibHalContext
*ctx
,
353 const char *capability
)
355 if (show_device
&& strcmp(show_device
, udi
))
359 printf ("*** lshal: new_capability, udi='%s'\n", udi
);
360 printf ("*** capability: %s\n", capability
);
362 printf ("%s capability %s added\n", short_name (udi
),
366 /** Invoked when device in the Global Device List loses a capability.
367 * Prints the name of the capability to stdout.
369 * @param udi Universal Device Id
370 * @param capability Name of capability
373 device_lost_capability (LibHalContext
*ctx
,
375 const char *capability
)
377 if (show_device
&& strcmp(show_device
, udi
))
381 printf ("*** lshal: lost_capability, udi='%s'\n", udi
);
382 printf ("*** capability: %s\n", capability
);
384 printf ("%s capability %s lost\n", short_name (udi
),
388 /** Acquires and prints the value of of a property to stdout.
390 * @param udi Universal Device Id
391 * @param key Key of property
394 print_property (const char *udi
, const char *key
)
400 dbus_error_init (&error
);
402 type
= libhal_device_get_property_type (hal_ctx
, udi
, key
, &error
);
405 case LIBHAL_PROPERTY_TYPE_STRING
:
406 str
= libhal_device_get_property_string (hal_ctx
, udi
, key
, &error
);
407 printf (long_list
?"*** new value: '%s' (string)\n":"'%s'", str
);
408 libhal_free_string (str
);
410 case LIBHAL_PROPERTY_TYPE_INT32
:
412 dbus_int32_t value
= libhal_device_get_property_int (hal_ctx
, udi
, key
, &error
);
413 printf (long_list
?"*** new value: %d (0x%x) (int)\n":"%d (0x%x)",
417 case LIBHAL_PROPERTY_TYPE_UINT64
:
419 dbus_uint64_t value
= libhal_device_get_property_uint64 (hal_ctx
, udi
, key
, &error
);
420 printf (long_list
?"*** new value: %llu (0x%llx) (uint64)\n":"%llu (0x%llx)",
421 (long long unsigned int) value
, (long long unsigned int) value
);
424 case LIBHAL_PROPERTY_TYPE_DOUBLE
:
425 printf (long_list
?"*** new value: %g (double)\n":"%g",
426 libhal_device_get_property_double (hal_ctx
, udi
, key
, &error
));
428 case LIBHAL_PROPERTY_TYPE_BOOLEAN
:
429 printf (long_list
?"*** new value: %s (bool)\n":"%s",
430 libhal_device_get_property_bool (hal_ctx
, udi
, key
, &error
) ? "true" : "false");
432 case LIBHAL_PROPERTY_TYPE_STRLIST
:
438 printf ("*** new value: {");
442 strlist
= libhal_device_get_property_strlist (hal_ctx
, udi
, key
, &error
);
443 for (i
= 0; strlist
[i
] != 0; i
++) {
444 printf ("'%s'", strlist
[i
]);
445 if (strlist
[i
+1] != NULL
)
449 printf ("} (string list)\n");
452 libhal_free_string_array (strlist
);
457 fprintf (stderr
, "Unknown type %d='%c'\n", type
, type
);
461 if (dbus_error_is_set (&error
))
462 dbus_error_free (&error
);
465 /** Invoked when a property of a device in the Global Device List is
466 * changed, and we have we have subscribed to changes for that device.
468 * @param udi Univerisal Device Id
469 * @param key Key of property
472 property_modified (LibHalContext
*ctx
,
475 dbus_bool_t is_removed
,
476 dbus_bool_t is_added
)
478 if (show_device
&& strcmp(show_device
, udi
))
482 printf ("*** lshal: property_modified, udi=%s, key=%s\n",
484 printf (" is_removed=%s, is_added=%s\n",
485 is_removed
? "true" : "false",
486 is_added
? "true" : "false");
488 print_property (udi
, key
);
491 printf ("%s property %s ", short_name (udi
), key
);
496 print_property (udi
, key
);
506 /** Invoked when a property of a device in the Global Device List is
507 * changed, and we have we have subscribed to changes for that device.
509 * @param udi Univerisal Device Id
510 * @param condition_name Name of condition
511 * @param message D-BUS message with parameters
514 device_condition (LibHalContext
*ctx
,
516 const char *condition_name
,
517 const char *condition_details
)
519 if (show_device
&& strcmp(show_device
, udi
))
523 printf ("*** lshal: device_condition, udi=%s\n", udi
);
524 printf (" condition_name=%s\n", condition_name
);
525 printf (" condition_details=%s\n", condition_details
);
528 printf ("%s condition %s = %s\n", short_name (udi
),
529 condition_name
, condition_details
);
534 /** Print out program usage.
536 * @param argc Number of arguments given to program
537 * @param argv Arguments given to program
540 usage (int argc
, char *argv
[])
542 fprintf (stderr
, "lshal version " PACKAGE_VERSION
"\n");
544 fprintf (stderr
, "\n" "usage : %s [options]\n", argv
[0]);
548 " -m, --monitor Monitor device list\n"
549 " -s, --short short output (print only nonstatic part of udi)\n"
550 " -l, --long Long output\n"
551 " -t, --tree Tree view\n"
552 " -u, --show <udi> Show only the specified device\n"
554 " -h, --help Show this information and exit\n"
555 " -V, --version Print version number\n"
557 "Without any given options lshal will start with option --long."
559 "Shows all devices and their properties. If the --monitor option is given\n"
560 "then the device list and all devices are monitored for changes.\n"
566 * @param argc Number of arguments given to program
567 * @param argv Arguments given to program
568 * @return Return code
571 main (int argc
, char *argv
[])
574 dbus_bool_t do_monitor
= FALSE
;
576 DBusConnection
*conn
;
579 /* This is the default case lshal without any options */
583 static const struct option long_options
[] = {
584 {"monitor", no_argument
, NULL
, 'm'},
585 {"long", no_argument
, NULL
, 'l'},
586 {"short", no_argument
, NULL
, 's'},
587 {"tree", no_argument
, NULL
, 't'},
588 {"show", required_argument
, NULL
, 'u'},
589 {"help", no_argument
, NULL
, 'h'},
590 {"usage", no_argument
, NULL
, 'U'},
591 {"version", no_argument
, NULL
, 'V'},
598 c
= getopt_long (argc
, argv
, "mlstu:hUV", long_options
, NULL
);
601 /* this should happen e.g. if 'lshal -' and this is incorrect/incomplete option */
602 if (!do_monitor
&& !long_list
&& !short_list
&& !tree_view
&& !show_device
) {
629 if (strchr(optarg
, '/') != NULL
)
630 show_device
= strdup(optarg
);
632 show_device
= malloc(strlen(UDI_BASE
) + strlen(optarg
) + 1);
633 memcpy(show_device
, UDI_BASE
, strlen(UDI_BASE
));
634 memcpy(show_device
+ strlen(UDI_BASE
), optarg
, strlen(optarg
) + 1);
645 printf ("lshal version " PACKAGE_VERSION
"\n");
656 loop
= g_main_loop_new (NULL
, FALSE
);
660 dbus_error_init (&error
);
661 conn
= dbus_bus_get (DBUS_BUS_SYSTEM
, &error
);
663 fprintf (stderr
, "error: dbus_bus_get: %s: %s\n",
664 error
.name
, error
.message
);
665 LIBHAL_FREE_DBUS_ERROR (&error
);
670 dbus_connection_setup_with_g_main (conn
, NULL
);
672 if ((hal_ctx
= libhal_ctx_new ()) == NULL
) {
673 fprintf (stderr
, "error: libhal_ctx_new\n");
676 if (!libhal_ctx_set_dbus_connection (hal_ctx
, conn
)) {
677 fprintf (stderr
, "error: libhal_ctx_set_dbus_connection: %s: %s\n",
678 error
.name
, error
.message
);
681 if (!libhal_ctx_init (hal_ctx
, &error
)) {
682 if (dbus_error_is_set(&error
)) {
683 fprintf (stderr
, "error: libhal_ctx_init: %s: %s\n", error
.name
, error
.message
);
684 LIBHAL_FREE_DBUS_ERROR (&error
);
686 fprintf (stderr
, "Could not initialise connection to hald.\n"
687 "Normally this means the HAL daemon (hald) is not running or not ready.\n");
691 libhal_ctx_set_device_added (hal_ctx
, device_added
);
692 libhal_ctx_set_device_removed (hal_ctx
, device_removed
);
693 libhal_ctx_set_device_new_capability (hal_ctx
, device_new_capability
);
694 libhal_ctx_set_device_lost_capability (hal_ctx
, device_lost_capability
);
695 libhal_ctx_set_device_property_modified (hal_ctx
, property_modified
);
696 libhal_ctx_set_device_condition (hal_ctx
, device_condition
);
699 dump_device (show_device
);
700 else if (!do_monitor
)
703 /* run the main loop only if we should monitor */
704 if (do_monitor
&& loop
!= NULL
) {
705 if( long_list
|| short_list
|| tree_view
)
708 if ( libhal_device_property_watch_all (hal_ctx
, &error
) == FALSE
) {
709 fprintf (stderr
, "error: monitoring devicelist - libhal_device_property_watch_all: %s: %s\n",
710 error
.name
, error
.message
);
711 LIBHAL_FREE_DBUS_ERROR (&error
);
714 printf ("\nStart monitoring devicelist:\n"
715 "-------------------------------------------------\n");
716 g_main_loop_run (loop
);
719 if ( libhal_ctx_shutdown (hal_ctx
, &error
) == FALSE
)
720 LIBHAL_FREE_DBUS_ERROR (&error
);
721 libhal_ctx_free (hal_ctx
);
723 dbus_connection_unref (conn
);