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>
44 #define __FUNCTION__ __func__
48 * @defgroup HalLsHal List HAL devices
51 * @brief A commandline tool, lshal, for displaying and, optionally,
52 * monitor the devices managed by the HAL daemon. Uses libhal.
57 /** Macro for terminating the program on an unrecoverable error */
58 #define DIE(expr) do {printf("*** [DIE] %s:%s():%d : ", __FILE__, __FUNCTION__, __LINE__); printf expr; printf("\n"); exit(1); } while(0)
60 #define UDI_BASE "/org/freedesktop/Hal/devices/"
62 static LibHalContext
*hal_ctx
;
63 static dbus_bool_t long_list
= FALSE
;
64 static dbus_bool_t tree_view
= FALSE
;
65 static dbus_bool_t short_list
= FALSE
;
66 static char *show_device
= NULL
;
73 /** Generate a short name for a device
75 * @param udi Universal Device Id
78 short_name (const char *udi
)
80 return &udi
[sizeof(UDI_BASE
) - 1];
83 /** Print all properties of a device
85 * @param udi Universal Device Id
89 print_props (const char *udi
)
92 LibHalPropertySet
*props
;
93 LibHalPropertySetIterator it
;
96 dbus_error_init (&error
);
98 props
= libhal_device_get_all_properties (hal_ctx
, udi
, &error
);
100 /* NOTE : This may be NULL if the device was removed
101 * in the daemon; this is because
102 * hal_device_get_all_properties() is a in
103 * essence an IPC call and other stuff may
107 LIBHAL_FREE_DBUS_ERROR (&error
);
111 for (libhal_psi_init (&it
, props
); libhal_psi_has_more (&it
); libhal_psi_next (&it
)) {
112 type
= libhal_psi_get_type (&it
);
114 case LIBHAL_PROPERTY_TYPE_STRING
:
115 printf (" %s = '%s' (string)\n",
116 libhal_psi_get_key (&it
),
117 libhal_psi_get_string (&it
));
120 case LIBHAL_PROPERTY_TYPE_INT32
:
121 printf (" %s = %d (0x%x) (int)\n",
122 libhal_psi_get_key (&it
),
123 libhal_psi_get_int (&it
),
124 libhal_psi_get_int (&it
));
127 case LIBHAL_PROPERTY_TYPE_UINT64
:
128 printf (" %s = %llu (0x%llx) (uint64)\n",
129 libhal_psi_get_key (&it
),
130 (long long unsigned int) libhal_psi_get_uint64 (&it
),
131 (long long unsigned int) libhal_psi_get_uint64 (&it
));
134 case LIBHAL_PROPERTY_TYPE_DOUBLE
:
135 printf (" %s = %g (double)\n",
136 libhal_psi_get_key (&it
),
137 libhal_psi_get_double (&it
));
140 case LIBHAL_PROPERTY_TYPE_BOOLEAN
:
141 printf (" %s = %s (bool)\n",
142 libhal_psi_get_key (&it
),
143 libhal_psi_get_bool (&it
) ? "true" :
147 case LIBHAL_PROPERTY_TYPE_STRLIST
:
152 printf (" %s = {", libhal_psi_get_key (&it
));
154 strlist
= libhal_psi_get_strlist (&it
);
155 for (i
= 0; strlist
[i
] != 0; i
++) {
156 printf ("'%s'", strlist
[i
]);
157 if (strlist
[i
+1] != NULL
)
160 printf ("} (string list)\n");
165 printf ("Unknown type %d=0x%02x\n", type
, type
);
170 libhal_free_property_set (props
);
173 /** Dumps information about a single device
175 * @param udi Universal Device Id
179 dump_device (const char *udi
)
183 dbus_error_init (&error
);
185 if (!libhal_device_exists (hal_ctx
, udi
, &error
)) {
186 LIBHAL_FREE_DBUS_ERROR (&error
);
191 printf ("udi = '%s'\n", udi
);
197 printf ("%s\n", short_name (udi
));
200 /** Dump all children of device
202 * @param udi Universal Device Id of parent
203 * @param num_devices Total number of devices in device list
204 * @param devices List of devices
205 * @param depth Current recursion depth
209 dump_children (char *udi
, int num_devices
, struct Device
*devices
, int depth
)
213 for (i
= 0; i
< num_devices
; i
++) {
215 if (devices
[i
].parent
)
219 if (!devices
[i
].parent
)
221 if (strcmp (devices
[i
].parent
, udi
))
226 printf ("udi = '%s'\n", devices
[i
].name
);
230 for (j
= 0;j
< depth
;j
++)
233 printf ("%s\n", short_name (devices
[i
].name
));
237 print_props (devices
[i
].name
);
241 dump_children(devices
[i
].name
, num_devices
, devices
, depth
+ 1);
245 /** Dump all devices to stdout
254 struct Device
*devices
;
257 dbus_error_init (&error
);
259 device_names
= libhal_get_all_devices (hal_ctx
, &num_devices
, &error
);
260 if (device_names
== NULL
) {
261 LIBHAL_FREE_DBUS_ERROR (&error
);
262 DIE (("Couldn't obtain list of devices\n"));
265 devices
= malloc (sizeof(struct Device
) * num_devices
);
267 libhal_free_string_array (device_names
);
271 for (i
= 0;i
< num_devices
;i
++) {
272 devices
[i
].name
= device_names
[i
];
273 devices
[i
].parent
= libhal_device_get_property_string (hal_ctx
,
274 device_names
[i
], "info.parent", &error
);
276 if (dbus_error_is_set (&error
)) {
277 /* Free the error (which include a dbus_error_init())
278 This should prevent errors if a call above fails */
279 dbus_error_free (&error
);
285 "Dumping %d device(s) from the Global Device List:\n"
286 "-------------------------------------------------\n",
290 dump_children(NULL
, num_devices
, devices
, 0);
292 for (i
= 0;i
< num_devices
;i
++) {
293 if (devices
[i
].parent
)
294 libhal_free_string (devices
[i
].parent
);
298 libhal_free_string_array (device_names
);
302 "Dumped %d device(s) from the Global Device List.\n"
303 "------------------------------------------------\n",
310 /** Invoked when a device is added to the Global Device List. Simply prints
311 * a message on stdout.
313 * @param udi Universal Device Id
316 device_added (LibHalContext
*ctx
,
319 if (show_device
&& strcmp(show_device
, udi
))
323 printf ("*** lshal: device_added, udi='%s'\n", udi
);
326 printf ("%s added\n", short_name (udi
));
329 /** Invoked when a device is removed from the Global Device List. Simply
330 * prints a message on stdout.
332 * @param udi Universal Device Id
335 device_removed (LibHalContext
*ctx
,
338 if (show_device
&& strcmp(show_device
, udi
))
342 printf ("*** lshal: device_removed, udi='%s'\n", udi
);
344 printf ("%s removed\n", short_name (udi
));
347 /** Invoked when device in the Global Device List acquires a new capability.
348 * Prints the name of the capability to stdout.
350 * @param udi Universal Device Id
351 * @param capability Name of capability
354 device_new_capability (LibHalContext
*ctx
,
356 const char *capability
)
358 if (show_device
&& strcmp(show_device
, udi
))
362 printf ("*** lshal: new_capability, udi='%s'\n", udi
);
363 printf ("*** capability: %s\n", capability
);
365 printf ("%s capability %s added\n", short_name (udi
),
369 /** Invoked when device in the Global Device List loses a capability.
370 * Prints the name of the capability to stdout.
372 * @param udi Universal Device Id
373 * @param capability Name of capability
376 device_lost_capability (LibHalContext
*ctx
,
378 const char *capability
)
380 if (show_device
&& strcmp(show_device
, udi
))
384 printf ("*** lshal: lost_capability, udi='%s'\n", udi
);
385 printf ("*** capability: %s\n", capability
);
387 printf ("%s capability %s lost\n", short_name (udi
),
391 /** Acquires and prints the value of of a property to stdout.
393 * @param udi Universal Device Id
394 * @param key Key of property
397 print_property (const char *udi
, const char *key
)
403 dbus_error_init (&error
);
405 type
= libhal_device_get_property_type (hal_ctx
, udi
, key
, &error
);
408 case LIBHAL_PROPERTY_TYPE_STRING
:
409 str
= libhal_device_get_property_string (hal_ctx
, udi
, key
, &error
);
410 printf (long_list
?"*** new value: '%s' (string)\n":"'%s'", str
);
411 libhal_free_string (str
);
413 case LIBHAL_PROPERTY_TYPE_INT32
:
415 dbus_int32_t value
= libhal_device_get_property_int (hal_ctx
, udi
, key
, &error
);
416 printf (long_list
?"*** new value: %d (0x%x) (int)\n":"%d (0x%x)",
420 case LIBHAL_PROPERTY_TYPE_UINT64
:
422 dbus_uint64_t value
= libhal_device_get_property_uint64 (hal_ctx
, udi
, key
, &error
);
423 printf (long_list
?"*** new value: %llu (0x%llx) (uint64)\n":"%llu (0x%llx)",
424 (long long unsigned int) value
, (long long unsigned int) value
);
427 case LIBHAL_PROPERTY_TYPE_DOUBLE
:
428 printf (long_list
?"*** new value: %g (double)\n":"%g",
429 libhal_device_get_property_double (hal_ctx
, udi
, key
, &error
));
431 case LIBHAL_PROPERTY_TYPE_BOOLEAN
:
432 printf (long_list
?"*** new value: %s (bool)\n":"%s",
433 libhal_device_get_property_bool (hal_ctx
, udi
, key
, &error
) ? "true" : "false");
435 case LIBHAL_PROPERTY_TYPE_STRLIST
:
441 printf ("*** new value: {");
445 strlist
= libhal_device_get_property_strlist (hal_ctx
, udi
, key
, &error
);
446 for (i
= 0; strlist
[i
] != 0; i
++) {
447 printf ("'%s'", strlist
[i
]);
448 if (strlist
[i
+1] != NULL
)
452 printf ("} (string list)\n");
455 libhal_free_string_array (strlist
);
460 fprintf (stderr
, "Unknown type %d='%c'\n", type
, type
);
464 if (dbus_error_is_set (&error
))
465 dbus_error_free (&error
);
468 /** Invoked when a property of a device in the Global Device List is
469 * changed, and we have we have subscribed to changes for that device.
471 * @param udi Univerisal Device Id
472 * @param key Key of property
475 property_modified (LibHalContext
*ctx
,
478 dbus_bool_t is_removed
,
479 dbus_bool_t is_added
)
481 if (show_device
&& strcmp(show_device
, udi
))
485 printf ("*** lshal: property_modified, udi=%s, key=%s\n",
487 printf (" is_removed=%s, is_added=%s\n",
488 is_removed
? "true" : "false",
489 is_added
? "true" : "false");
491 print_property (udi
, key
);
494 printf ("%s property %s ", short_name (udi
), key
);
499 print_property (udi
, key
);
509 /** Invoked when a property of a device in the Global Device List is
510 * changed, and we have we have subscribed to changes for that device.
512 * @param udi Univerisal Device Id
513 * @param condition_name Name of condition
514 * @param message D-BUS message with parameters
517 device_condition (LibHalContext
*ctx
,
519 const char *condition_name
,
520 const char *condition_details
)
522 if (show_device
&& strcmp(show_device
, udi
))
526 printf ("*** lshal: device_condition, udi=%s\n", udi
);
527 printf (" condition_name=%s\n", condition_name
);
528 printf (" condition_details=%s\n", condition_details
);
531 printf ("%s condition %s = %s\n", short_name (udi
),
532 condition_name
, condition_details
);
537 /** Print out program usage.
539 * @param argc Number of arguments given to program
540 * @param argv Arguments given to program
543 usage (int argc
, char *argv
[])
545 fprintf (stderr
, "lshal version " PACKAGE_VERSION
"\n");
547 fprintf (stderr
, "\n" "usage : %s [options]\n", argv
[0]);
551 " -m, --monitor Monitor device list\n"
552 " -s, --short short output (print only nonstatic part of udi)\n"
553 " -l, --long Long output\n"
554 " -t, --tree Tree view\n"
555 " -u, --show <udi> Show only the specified device\n"
557 " -h, --help Show this information and exit\n"
558 " -V, --version Print version number\n"
560 "Without any given options lshal will start with option --long."
562 "Shows all devices and their properties. If the --monitor option is given\n"
563 "then the device list and all devices are monitored for changes.\n"
569 * @param argc Number of arguments given to program
570 * @param argv Arguments given to program
571 * @return Return code
574 main (int argc
, char *argv
[])
577 dbus_bool_t do_monitor
= FALSE
;
579 DBusConnection
*conn
;
582 /* This is the default case lshal without any options */
586 static const struct option long_options
[] = {
587 {"monitor", no_argument
, NULL
, 'm'},
588 {"long", no_argument
, NULL
, 'l'},
589 {"short", no_argument
, NULL
, 's'},
590 {"tree", no_argument
, NULL
, 't'},
591 {"show", required_argument
, NULL
, 'u'},
592 {"help", no_argument
, NULL
, 'h'},
593 {"usage", no_argument
, NULL
, 'U'},
594 {"version", no_argument
, NULL
, 'V'},
601 c
= getopt_long (argc
, argv
, "mlstu:hUV", long_options
, NULL
);
604 /* this should happen e.g. if 'lshal -' and this is incorrect/incomplete option */
605 if (!do_monitor
&& !long_list
&& !short_list
&& !tree_view
&& !show_device
) {
632 if (strchr(optarg
, '/') != NULL
)
633 show_device
= strdup(optarg
);
635 show_device
= malloc(strlen(UDI_BASE
) + strlen(optarg
) + 1);
636 memcpy(show_device
, UDI_BASE
, strlen(UDI_BASE
));
637 memcpy(show_device
+ strlen(UDI_BASE
), optarg
, strlen(optarg
) + 1);
648 printf ("lshal version " PACKAGE_VERSION
"\n");
659 loop
= g_main_loop_new (NULL
, FALSE
);
663 dbus_error_init (&error
);
664 conn
= dbus_bus_get (DBUS_BUS_SYSTEM
, &error
);
666 fprintf (stderr
, "error: dbus_bus_get: %s: %s\n",
667 error
.name
, error
.message
);
668 LIBHAL_FREE_DBUS_ERROR (&error
);
673 dbus_connection_setup_with_g_main (conn
, NULL
);
675 if ((hal_ctx
= libhal_ctx_new ()) == NULL
) {
676 fprintf (stderr
, "error: libhal_ctx_new\n");
679 if (!libhal_ctx_set_dbus_connection (hal_ctx
, conn
)) {
680 fprintf (stderr
, "error: libhal_ctx_set_dbus_connection: %s: %s\n",
681 error
.name
, error
.message
);
684 if (!libhal_ctx_init (hal_ctx
, &error
)) {
685 if (dbus_error_is_set(&error
)) {
686 fprintf (stderr
, "error: libhal_ctx_init: %s: %s\n", error
.name
, error
.message
);
687 LIBHAL_FREE_DBUS_ERROR (&error
);
689 fprintf (stderr
, "Could not initialise connection to hald.\n"
690 "Normally this means the HAL daemon (hald) is not running or not ready.\n");
694 libhal_ctx_set_device_added (hal_ctx
, device_added
);
695 libhal_ctx_set_device_removed (hal_ctx
, device_removed
);
696 libhal_ctx_set_device_new_capability (hal_ctx
, device_new_capability
);
697 libhal_ctx_set_device_lost_capability (hal_ctx
, device_lost_capability
);
698 libhal_ctx_set_device_property_modified (hal_ctx
, property_modified
);
699 libhal_ctx_set_device_condition (hal_ctx
, device_condition
);
702 dump_device (show_device
);
703 else if (!do_monitor
)
706 /* run the main loop only if we should monitor */
707 if (do_monitor
&& loop
!= NULL
) {
708 if( long_list
|| short_list
|| tree_view
)
711 if ( libhal_device_property_watch_all (hal_ctx
, &error
) == FALSE
) {
712 fprintf (stderr
, "error: monitoring devicelist - libhal_device_property_watch_all: %s: %s\n",
713 error
.name
, error
.message
);
714 LIBHAL_FREE_DBUS_ERROR (&error
);
717 printf ("\nStart monitoring devicelist:\n"
718 "-------------------------------------------------\n");
719 g_main_loop_run (loop
);
722 if ( libhal_ctx_shutdown (hal_ctx
, &error
) == FALSE
)
723 LIBHAL_FREE_DBUS_ERROR (&error
);
724 libhal_ctx_free (hal_ctx
);
726 dbus_connection_unref (conn
);