1 /***************************************************************************
4 * hal-device.c : add devices HAL
6 * Copyright (C) 2005 SuSE Linux Gmbh
9 * Steffen Winterfeldt <snwint@suse.de>
11 * Licensed under the Academic Free License version 2.1
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
43 #ifndef DBUS_API_SUBJECT_TO_CHANGE
44 #define DBUS_API_SUBJECT_TO_CHANGE 1
47 #include <dbus/dbus.h>
55 typedef struct lh_prop_s
{
56 struct lh_prop_s
*next
;
57 LibHalPropertyType type
;
61 dbus_int32_t int_value
;
62 dbus_uint64_t uint64_value
;
64 dbus_bool_t bool_value
;
71 int dump_devices(LibHalContext
*hal_ctx
, char *arg
);
72 int remove_udi(LibHalContext
*hal_ctx
, char *arg
);
73 int add_udi(LibHalContext
*hal_ctx
, char *arg
);
74 void process_property(LibHalContext
*hal_ctx
, char *buf
, lh_prop_t
**prop
);
75 int add_properties(LibHalContext
*hal_ctx
, new_dev_t
*nd
, lh_prop_t
*prop
);
76 lh_prop_t
*free_properties(lh_prop_t
*prop
);
77 static char *skip_space(char *s
);
78 static char *skip_non_eq_or_space(char *s
);
79 static char *skip_number(char *s
);
80 static char *skip_nonquote(char *s
);
92 struct option options
[] = {
93 { "remove", 1, NULL
, 'r' },
94 { "add", 1, NULL
, 'a' },
95 { "help", 0, NULL
, 'h' },
100 int main(int argc
, char **argv
)
103 DBusConnection
*conn
;
104 LibHalContext
*hal_ctx
;
110 while ((i
= getopt_long(argc
, argv
, "a:hr:", options
, NULL
)) != -1) {
131 dbus_error_init(&error
);
133 if (!(conn
= dbus_bus_get(DBUS_BUS_SYSTEM
, &error
))) {
134 fprintf(stderr
, "error: dbus_bus_get: %s: %s\n", error
.name
, error
.message
);
135 LIBHAL_FREE_DBUS_ERROR (&error
);
139 /* fprintf(stderr, "connected to: %s\n", dbus_bus_get_unique_name(conn)); */
140 if (!(hal_ctx
= libhal_ctx_new())) return 3;
141 if (!libhal_ctx_set_dbus_connection(hal_ctx
, conn
)) return 4;
142 if (!libhal_ctx_init(hal_ctx
, &error
)) {
143 if (dbus_error_is_set(&error
)) {
144 fprintf (stderr
, "error: libhal_ctx_init: %s: %s\n", error
.name
, error
.message
);
145 LIBHAL_FREE_DBUS_ERROR (&error
);
147 fprintf (stderr
, "Could not initialise connection to hald.\n"
148 "Normally this means the HAL daemon (hald) is not running or not ready.\n");
154 err
= dump_devices(hal_ctx
, argv
[optind
]);
156 err
= remove_udi(hal_ctx
, opt
.udi
);
158 err
= add_udi(hal_ctx
, opt
.udi
);
162 libhal_ctx_shutdown(hal_ctx
, &error
);
163 libhal_ctx_free(hal_ctx
);
164 dbus_connection_unref(conn
);
165 dbus_error_free(&error
);
174 "usage: hal-device [--help] [--add udi] [--remove udi] [udi]\n"
175 "Create, remove, or show HAL device. If no udi is given, shows all devices.\n"
176 "If udi doesn't start with a '/', '/org/freedesktop/Hal/devices/' is prepended.\n"
177 " -a, --add udi\t\tAdd new device.\n"
178 " \t\t\tReads property list in 'lshal' syntax from stdin.\n"
179 " -r, --remove udi\tRemove device.\n"
180 " -h, --help\t\tShow this text.\n"
188 int dump_devices(LibHalContext
*hal_ctx
, char *arg
)
201 asprintf(&udi
, "/org/freedesktop/Hal/devices/%s", arg
);
203 udi
= calloc(1, sizeof ("/org/freedesktop/Hal/devices/%s") + strlen(arg
));
204 sprintf(udi
, "/org/freedesktop/Hal/devices/%s", arg
);
210 dbus_error_init(&error
);
213 if (!(device_names
= libhal_get_all_devices(hal_ctx
, &num_devices
, &error
))) {
214 fprintf(stderr
, "Empty HAL device list.\n");
215 LIBHAL_FREE_DBUS_ERROR (&error
);
219 device_names
= calloc(2, sizeof *device_names
);
220 device_names
[0] = strdup(udi
);
224 for(i
= 0; i
< num_devices
; i
++) {
225 LibHalPropertySet
*props
;
226 LibHalPropertySetIterator it
;
229 if (!(props
= libhal_device_get_all_properties(hal_ctx
, device_names
[i
], &error
))) {
230 fprintf(stderr
, "%s: %s\n", error
.name
, error
.message
);
231 dbus_error_init(&error
);
237 printf("udi = '%s'\n", device_names
[i
]);
239 for(libhal_psi_init(&it
, props
); libhal_psi_has_more(&it
); libhal_psi_next(&it
)) {
240 type
= libhal_psi_get_type(&it
);
242 case LIBHAL_PROPERTY_TYPE_STRING
:
243 printf(" %s = '%s' (string)\n",
244 libhal_psi_get_key(&it
),
245 libhal_psi_get_string(&it
)
248 case LIBHAL_PROPERTY_TYPE_INT32
:
249 printf(" %s = %d (0x%x) (int)\n",
250 libhal_psi_get_key(&it
),
251 libhal_psi_get_int(&it
),
252 libhal_psi_get_int(&it
)
255 case LIBHAL_PROPERTY_TYPE_UINT64
:
256 printf(" %s = %lld (0x%llx) (uint64)\n",
257 libhal_psi_get_key(&it
),
258 (long long) libhal_psi_get_uint64(&it
),
259 (long long) libhal_psi_get_uint64(&it
)
262 case LIBHAL_PROPERTY_TYPE_DOUBLE
:
263 printf(" %s = %g (double)\n",
264 libhal_psi_get_key(&it
),
265 libhal_psi_get_double(&it
)
268 case LIBHAL_PROPERTY_TYPE_BOOLEAN
:
269 printf(" %s = %s (bool)\n",
270 libhal_psi_get_key(&it
),
271 libhal_psi_get_bool(&it
) ? "true" : "false"
274 case LIBHAL_PROPERTY_TYPE_STRLIST
:
278 printf (" %s = { ", libhal_psi_get_key(&it
));
279 strlist
= libhal_psi_get_strlist(&it
);
281 printf("'%s'%s", *strlist
, strlist
[1] ? ", " : "");
284 printf(" } (string list)\n");
288 printf("Unknown type %d = 0x%02x\n", type
, type
);
293 libhal_free_property_set(props
);
297 libhal_free_string_array(device_names
);
298 dbus_error_free(&error
);
304 int remove_udi(LibHalContext
*hal_ctx
, char *arg
)
315 asprintf(&udi
, "/org/freedesktop/Hal/devices/%s", arg
);
317 udi
= calloc(1, sizeof ("/org/freedesktop/Hal/devices/%s") + strlen(arg
));
318 sprintf(udi
, "/org/freedesktop/Hal/devices/%s", arg
);
323 dbus_error_init(&error
);
326 if (!libhal_remove_device(hal_ctx
, udi
, &error
)) {
327 fprintf(stderr
, "%s: %s\n", error
.name
, error
.message
);
328 LIBHAL_FREE_DBUS_ERROR (&error
);
332 fprintf(stderr
, "removed: %s\n", udi
);
340 int add_udi(LibHalContext
*hal_ctx
, char *arg
)
343 dbus_bool_t dev_exists
= FALSE
;
344 char *udi
= NULL
, buf
[1024];
355 asprintf(&udi
, "/org/freedesktop/Hal/devices/%s", arg
);
357 udi
= calloc(1, sizeof ("/org/freedesktop/Hal/devices/%s") + strlen(arg
));
358 sprintf(udi
, "/org/freedesktop/Hal/devices/%s", arg
);
363 new_dev
.udi
= strdup(udi
);
365 dbus_error_init(&error
);
368 dev_exists
= libhal_device_exists(hal_ctx
, udi
, &error
);
371 new_dev
.real_udi
= strdup(new_dev
.udi
);
373 new_dev
.real_udi
= libhal_new_device(hal_ctx
, &error
);
375 if (!new_dev
.real_udi
) {
376 fprintf(stderr
, "%s: %s\n", error
.name
, error
.message
);
377 LIBHAL_FREE_DBUS_ERROR (&error
);
378 free(new_dev
.real_udi
);
383 printf("tmp udi: %s\n", new_dev
.real_udi
);
388 while (fgets(buf
, sizeof buf
, stdin
)) {
389 process_property(hal_ctx
, buf
, &prop
);
392 err
= add_properties(hal_ctx
, &new_dev
, prop
);
394 prop
= free_properties(prop
);
397 if (!libhal_device_commit_to_gdl(hal_ctx
, new_dev
.real_udi
, new_dev
.udi
, &error
)) {
398 fprintf(stderr
, "%s: %s\n", error
.name
, error
.message
);
399 LIBHAL_FREE_DBUS_ERROR (&error
);
400 free(new_dev
.real_udi
);
402 err
= err
? err
: 23;
406 printf("%s: %s\n", dev_exists
? "merged": "created", new_dev
.udi
);
412 char *skip_space(char *s
)
414 while (isspace(*s
)) s
++;
420 char *skip_non_eq_or_space(char *s
)
422 while (*s
&& *s
!= '=' && !isspace(*s
))
429 char *skip_number(char *s
)
431 while (*s
== '-' || *s
== '+' || *s
== '.' || isdigit(*s
))
438 char *skip_nonquote(char *s
)
440 while (*s
&& *s
!= '\'')
447 void process_property(LibHalContext
*hal_ctx
, char *buf
, lh_prop_t
**prop
)
450 char *key
, *s_val
= NULL
;
459 s
= skip_space(s
+ 1);
462 if ((s1
= skip_number(s
), s1
!= s
) && *s1
== ':') s
= skip_space(s1
+ 1);
464 s
= skip_non_eq_or_space(key
= s
);
479 p
= calloc(1, sizeof *p
);
480 p
->type
= LIBHAL_PROPERTY_TYPE_INVALID
;
481 p
->key
= strdup(key
);
491 s
= strrchr(s_val
, '\'');
492 *(s
? s
: s_val
) = 0;
493 p
->type
= LIBHAL_PROPERTY_TYPE_STRING
;
494 p
->v
.str_value
= strdup(s_val
);
495 } else if (*s
== '{') {
497 s1
= strrchr(s_val
, '}');
499 p
->type
= LIBHAL_PROPERTY_TYPE_STRLIST
;
501 p
->v
.strlist_value
= calloc(1, sizeof *p
->v
.strlist_value
);
502 while (*s_val
++ == '\'') {
503 s
= skip_nonquote(s_val
);
505 p
->v
.strlist_value
= reallocarray(p
->v
.strlist_value
,
506 len
+ 2, sizeof *p
->v
.strlist_value
);
507 p
->v
.strlist_value
[len
] = strdup(s_val
);
508 p
->v
.strlist_value
[++len
] = NULL
;
509 s_val
= skip_nonquote(s
);
511 } else if (!strncmp(s
, "true", 4)) {
513 p
->type
= LIBHAL_PROPERTY_TYPE_BOOLEAN
;
514 p
->v
.bool_value
= TRUE
;
515 } else if (!strncmp(s
, "false", 5)) {
517 p
->type
= LIBHAL_PROPERTY_TYPE_BOOLEAN
;
518 p
->v
.bool_value
= FALSE
;
519 } else if ((s1
= skip_number(s
)) != s
) {
520 if (strstr(s1
, "(int)")) {
522 p
->type
= LIBHAL_PROPERTY_TYPE_INT32
;
523 p
->v
.int_value
= strtol(s
, NULL
, 10);
524 } else if (strstr(s1
, "(uint64)")) {
526 p
->type
= LIBHAL_PROPERTY_TYPE_UINT64
;
527 p
->v
.uint64_value
= strtoull(s
, NULL
, 10);
528 } else if (strstr(s1
, "(double)")) {
529 p
->type
= LIBHAL_PROPERTY_TYPE_DOUBLE
;
530 p
->v
.double_value
= strtod(s
, NULL
);
536 if (p
->type
== LIBHAL_PROPERTY_TYPE_INVALID
) {
546 int add_properties(LibHalContext
*hal_ctx
, new_dev_t
*nd
, lh_prop_t
*prop
)
550 char *udi2
= NULL
, *udi3
= NULL
, **s
;
551 LibHalPropertyType old_type
;
553 dbus_error_init(&error
);
555 for(p
= prop
; p
; p
= p
->next
) {
556 if (!strcmp(p
->key
, "udi") && p
->type
== LIBHAL_PROPERTY_TYPE_STRING
) {
557 udi2
= p
->v
.str_value
;
561 old_type
= libhal_device_get_property_type(hal_ctx
, nd
->real_udi
, p
->key
, &error
);
562 dbus_error_init(&error
);
564 if (old_type
!= LIBHAL_PROPERTY_TYPE_INVALID
&&
565 ( p
->type
!= old_type
|| p
->type
== LIBHAL_PROPERTY_TYPE_STRLIST
)) {
566 if (!libhal_device_remove_property(hal_ctx
, nd
->real_udi
, p
->key
, &error
)) {
567 fprintf(stderr
, "%s: %s\n", error
.name
, error
.message
);
568 LIBHAL_FREE_DBUS_ERROR (&error
);
574 case LIBHAL_PROPERTY_TYPE_BOOLEAN
:
575 if (!libhal_device_set_property_bool(hal_ctx
, nd
->real_udi
, p
->key
, p
->v
.bool_value
, &error
)) {
576 fprintf(stderr
, "%s: %s\n", error
.name
, error
.message
);
577 LIBHAL_FREE_DBUS_ERROR (&error
);
581 case LIBHAL_PROPERTY_TYPE_INT32
:
582 if (!libhal_device_set_property_int(hal_ctx
, nd
->real_udi
, p
->key
, p
->v
.int_value
, &error
)) {
583 fprintf(stderr
, "%s: %s\n", error
.name
, error
.message
);
584 LIBHAL_FREE_DBUS_ERROR (&error
);
588 case LIBHAL_PROPERTY_TYPE_UINT64
:
589 if (!libhal_device_set_property_uint64(hal_ctx
, nd
->real_udi
, p
->key
, p
->v
.uint64_value
, &error
)) {
590 fprintf(stderr
, "%s: %s\n", error
.name
, error
.message
);
591 LIBHAL_FREE_DBUS_ERROR (&error
);
595 case LIBHAL_PROPERTY_TYPE_DOUBLE
:
596 if (!libhal_device_set_property_double(hal_ctx
, nd
->real_udi
, p
->key
, p
->v
.double_value
, &error
)) {
597 fprintf(stderr
, "%s: %s\n", error
.name
, error
.message
);
598 LIBHAL_FREE_DBUS_ERROR (&error
);
602 case LIBHAL_PROPERTY_TYPE_STRING
:
603 if (!strcmp(p
->key
, "info.udi")) udi3
= p
->v
.str_value
;
604 if (!libhal_device_set_property_string(hal_ctx
, nd
->real_udi
, p
->key
, p
->v
.str_value
, &error
)) {
605 fprintf(stderr
, "%s: %s\n", error
.name
, error
.message
);
606 LIBHAL_FREE_DBUS_ERROR (&error
);
610 case LIBHAL_PROPERTY_TYPE_STRLIST
:
611 for(s
= p
->v
.strlist_value
; *s
; s
++) {
612 if (!libhal_device_property_strlist_append(hal_ctx
, nd
->real_udi
, p
->key
, *s
, &error
)) {
613 fprintf(stderr
, "%s: %s\n", error
.name
, error
.message
);
614 LIBHAL_FREE_DBUS_ERROR (&error
);
624 if (udi2
) udi3
= NULL
;
625 if (udi3
) udi2
= udi3
;
627 if (udi2
&& !nd
->udi
)
628 nd
->udi
= strdup(udi2
);
634 lh_prop_t
*free_properties(lh_prop_t
*prop
)
639 for(; prop
; prop
= next
) {
643 if (prop
->type
== LIBHAL_PROPERTY_TYPE_STRING
) free(prop
->v
.str_value
);
644 if (prop
->type
== LIBHAL_PROPERTY_TYPE_STRLIST
&& prop
->v
.strlist_value
) {
645 for(s
= prop
->v
.strlist_value
; *s
; ) free(*s
++);
646 free(prop
->v
.strlist_value
);