dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / hal / tools / lshal.c
blob258b39ccc1b5d3613d901dcaeceb2241a4b58f76
1 /***************************************************************************
2 * CVSID: $Id$
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 **************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <getopt.h>
38 #include <glib.h>
39 #include <dbus/dbus-glib-lowlevel.h>
40 #include <dbus/dbus-glib.h>
41 #include <libhal.h>
44 /**
45 * @defgroup HalLsHal List HAL devices
46 * @ingroup HalMisc
48 * @brief A commandline tool, lshal, for displaying and, optionally,
49 * monitor the devices managed by the HAL daemon. Uses libhal.
51 * @{
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;
65 struct Device {
66 char *name;
67 char *parent;
70 /** Generate a short name for a device
72 * @param udi Universal Device Id
74 static const char *
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
85 static void
86 print_props (const char *udi)
88 DBusError error;
89 LibHalPropertySet *props;
90 LibHalPropertySetIterator it;
91 int type;
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
101 * be happening..
103 if (props == NULL) {
104 LIBHAL_FREE_DBUS_ERROR (&error);
105 return;
108 for (libhal_psi_init (&it, props); libhal_psi_has_more (&it); libhal_psi_next (&it)) {
109 type = libhal_psi_get_type (&it);
110 switch (type) {
111 case LIBHAL_PROPERTY_TYPE_STRING:
112 printf (" %s = '%s' (string)\n",
113 libhal_psi_get_key (&it),
114 libhal_psi_get_string (&it));
115 break;
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));
122 break;
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));
129 break;
131 case LIBHAL_PROPERTY_TYPE_DOUBLE:
132 printf (" %s = %g (double)\n",
133 libhal_psi_get_key (&it),
134 libhal_psi_get_double (&it));
135 break;
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" :
141 "false");
142 break;
144 case LIBHAL_PROPERTY_TYPE_STRLIST:
146 unsigned int i;
147 char **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)
155 printf (", ");
157 printf ("} (string list)\n");
158 break;
161 default:
162 printf ("Unknown type %d=0x%02x\n", type, type);
163 break;
167 libhal_free_property_set (props);
170 /** Dumps information about a single device
172 * @param udi Universal Device Id
175 static void
176 dump_device (const char *udi)
178 DBusError error;
180 dbus_error_init (&error);
182 if (!libhal_device_exists (hal_ctx, udi, &error)) {
183 LIBHAL_FREE_DBUS_ERROR (&error);
184 return;
187 if (long_list) {
188 printf ("udi = '%s'\n", udi);
190 print_props (udi);
191 printf ("\n");
193 else
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
205 static void
206 dump_children (char *udi, int num_devices, struct Device *devices, int depth)
208 int i;
210 for (i = 0; i < num_devices; i++) {
211 if (!udi) {
212 if (devices[i].parent)
213 continue;
215 else {
216 if (!devices[i].parent)
217 continue;
218 if (strcmp (devices[i].parent, udi))
219 continue;
222 if (long_list)
223 printf ("udi = '%s'\n", devices[i].name);
224 else {
225 int j;
226 if (tree_view) {
227 for (j = 0;j < depth;j++)
228 printf(" ");
230 printf ("%s\n", short_name (devices[i].name));
233 if (long_list) {
234 print_props (devices[i].name);
235 printf ("\n");
238 dump_children(devices[i].name, num_devices, devices, depth + 1);
242 /** Dump all devices to stdout
245 static void
246 dump_devices (void)
248 int i;
249 int num_devices;
250 char **device_names;
251 struct Device *devices;
252 DBusError error;
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);
263 if (!devices) {
264 libhal_free_string_array (device_names);
265 return;
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);
280 if (long_list) {
281 printf ("\n"
282 "Dumping %d device(s) from the Global Device List:\n"
283 "-------------------------------------------------\n",
284 num_devices);
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);
294 free (devices);
295 libhal_free_string_array (device_names);
297 if (long_list) {
298 printf ("\n"
299 "Dumped %d device(s) from the Global Device List.\n"
300 "------------------------------------------------\n",
301 num_devices);
303 printf ("\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
312 static void
313 device_added (LibHalContext *ctx,
314 const char *udi)
316 if (show_device && strcmp(show_device, udi))
317 return;
319 if (long_list) {
320 printf ("*** lshal: device_added, udi='%s'\n", udi);
321 print_props (udi);
322 } else
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
331 static void
332 device_removed (LibHalContext *ctx,
333 const char *udi)
335 if (show_device && strcmp(show_device, udi))
336 return;
338 if (long_list)
339 printf ("*** lshal: device_removed, udi='%s'\n", udi);
340 else
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
350 static void
351 device_new_capability (LibHalContext *ctx,
352 const char *udi,
353 const char *capability)
355 if (show_device && strcmp(show_device, udi))
356 return;
358 if (long_list) {
359 printf ("*** lshal: new_capability, udi='%s'\n", udi);
360 printf ("*** capability: %s\n", capability);
361 } else
362 printf ("%s capability %s added\n", short_name (udi),
363 capability);
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
372 static void
373 device_lost_capability (LibHalContext *ctx,
374 const char *udi,
375 const char *capability)
377 if (show_device && strcmp(show_device, udi))
378 return;
380 if (long_list) {
381 printf ("*** lshal: lost_capability, udi='%s'\n", udi);
382 printf ("*** capability: %s\n", capability);
383 } else
384 printf ("%s capability %s lost\n", short_name (udi),
385 capability);
388 /** Acquires and prints the value of of a property to stdout.
390 * @param udi Universal Device Id
391 * @param key Key of property
393 static void
394 print_property (const char *udi, const char *key)
396 int type;
397 char *str;
398 DBusError error;
400 dbus_error_init (&error);
402 type = libhal_device_get_property_type (hal_ctx, udi, key, &error);
404 switch (type) {
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);
409 break;
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)",
414 value, value);
416 break;
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);
423 break;
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));
427 break;
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");
431 break;
432 case LIBHAL_PROPERTY_TYPE_STRLIST:
434 unsigned int i;
435 char **strlist;
437 if (long_list)
438 printf ("*** new value: {");
439 else
440 printf ("{");
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)
446 printf (", ");
448 if (long_list)
449 printf ("} (string list)\n");
450 else
451 printf ("}");
452 libhal_free_string_array (strlist);
453 break;
456 default:
457 fprintf (stderr, "Unknown type %d='%c'\n", type, type);
458 break;
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
471 static void
472 property_modified (LibHalContext *ctx,
473 const char *udi,
474 const char *key,
475 dbus_bool_t is_removed,
476 dbus_bool_t is_added)
478 if (show_device && strcmp(show_device, udi))
479 return;
481 if (long_list) {
482 printf ("*** lshal: property_modified, udi=%s, key=%s\n",
483 udi, key);
484 printf (" is_removed=%s, is_added=%s\n",
485 is_removed ? "true" : "false",
486 is_added ? "true" : "false");
487 if (!is_removed)
488 print_property (udi, key);
489 printf ("\n");
490 } else {
491 printf ("%s property %s ", short_name (udi), key);
492 if (is_removed)
493 printf ("removed");
494 else {
495 printf ("= ");
496 print_property (udi, key);
498 if (is_added)
499 printf (" (new)");
501 printf ("\n");
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
513 static void
514 device_condition (LibHalContext *ctx,
515 const char *udi,
516 const char *condition_name,
517 const char *condition_details)
519 if (show_device && strcmp(show_device, udi))
520 return;
522 if (long_list) {
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);
526 printf ("\n");
527 } else {
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
539 static void
540 usage (int argc, char *argv[])
542 fprintf (stderr, "lshal version " PACKAGE_VERSION "\n");
544 fprintf (stderr, "\n" "usage : %s [options]\n", argv[0]);
545 fprintf (stderr,
546 "\n"
547 "Options:\n"
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"
553 "\n"
554 " -h, --help Show this information and exit\n"
555 " -V, --version Print version number\n"
556 "\n"
557 "Without any given options lshal will start with option --long."
558 "\n"
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"
561 "\n");
564 /** Entry point
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[])
573 DBusError error;
574 dbus_bool_t do_monitor = FALSE;
575 GMainLoop *loop;
576 DBusConnection *conn;
578 if (argc == 1) {
579 /* This is the default case lshal without any options */
580 long_list = TRUE;
582 else {
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'},
592 {NULL, 0, NULL, 0}
595 while (1) {
596 int c;
598 c = getopt_long (argc, argv, "mlstu:hUV", long_options, NULL);
600 if (c == -1) {
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) {
603 usage (argc, argv);
604 return 1;
607 break;
610 switch (c) {
611 case 'm':
612 do_monitor = TRUE;
613 break;
615 case 'l':
616 long_list = TRUE;
617 break;
619 case 's':
620 short_list = TRUE;
621 long_list = FALSE;
622 break;
624 case 't':
625 tree_view = TRUE;
626 break;
628 case 'u':
629 if (strchr(optarg, '/') != NULL)
630 show_device = strdup(optarg);
631 else {
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);
637 break;
639 case 'h':
640 case 'U':
641 usage (argc, argv);
642 return 0;
644 case 'V':
645 printf ("lshal version " PACKAGE_VERSION "\n");
646 return 0;
648 default:
649 usage (argc, argv);
650 return 1;
655 if (do_monitor)
656 loop = g_main_loop_new (NULL, FALSE);
657 else
658 loop = NULL;
660 dbus_error_init (&error);
661 conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
662 if (conn == NULL) {
663 fprintf (stderr, "error: dbus_bus_get: %s: %s\n",
664 error.name, error.message);
665 LIBHAL_FREE_DBUS_ERROR (&error);
666 return 1;
669 if (do_monitor)
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");
674 return 1;
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);
679 return 1;
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");
688 return 1;
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);
698 if (show_device)
699 dump_device (show_device);
700 else if (!do_monitor)
701 dump_devices ();
703 /* run the main loop only if we should monitor */
704 if (do_monitor && loop != NULL) {
705 if( long_list || short_list || tree_view )
706 dump_devices ();
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);
712 return 1;
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);
725 free(show_device);
727 return 0;
731 * @}