dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / hal / tools / hal-device.c
blob9173769ef6d7e10803fb7223aea768f9c681a12f
1 /***************************************************************************
2 * CVSID: $Id$
4 * hal-device.c : add devices HAL
6 * Copyright (C) 2005 SuSE Linux Gmbh
8 * Authors:
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
29 #define _GNU_SOURCE
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
35 #include <stdio.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <ctype.h>
40 #include <inttypes.h>
41 #include <getopt.h>
43 #ifndef DBUS_API_SUBJECT_TO_CHANGE
44 #define DBUS_API_SUBJECT_TO_CHANGE 1
45 #endif
47 #include <dbus/dbus.h>
48 #include <libhal.h>
50 typedef struct {
51 char *udi;
52 char *real_udi;
53 } new_dev_t;
55 typedef struct lh_prop_s {
56 struct lh_prop_s *next;
57 LibHalPropertyType type;
58 char *key;
59 union {
60 char *str_value;
61 dbus_int32_t int_value;
62 dbus_uint64_t uint64_value;
63 double double_value;
64 dbus_bool_t bool_value;
65 char **strlist_value;
66 } v;
67 } lh_prop_t;
70 void help(void);
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);
83 new_dev_t new_dev;
85 struct {
86 unsigned remove:1;
87 unsigned add:1;
88 unsigned list:1;
89 char *udi;
90 } opt;
92 struct option options[] = {
93 { "remove", 1, NULL, 'r' },
94 { "add", 1, NULL, 'a' },
95 { "help", 0, NULL, 'h' },
96 { 0, 0, 0, 0 }
100 int main(int argc, char **argv)
102 DBusError error;
103 DBusConnection *conn;
104 LibHalContext *hal_ctx;
105 int i, err;
107 opterr = 0;
108 opt.list = 1;
110 while ((i = getopt_long(argc, argv, "a:hr:", options, NULL)) != -1) {
111 switch (i) {
112 case 'a':
113 opt.add = 1;
114 opt.list = 0;
115 opt.udi = optarg;
116 break;
117 case 'r':
118 opt.remove = 1;
119 opt.list = 0;
120 opt.udi = optarg;
121 break;
122 case 'h':
123 help();
124 return 0;
125 default:
126 help();
127 return 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);
136 return 2;
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");
149 return 5;
152 err = 0;
153 if (opt.list)
154 err = dump_devices(hal_ctx, argv[optind]);
155 else if (opt.remove)
156 err = remove_udi(hal_ctx, opt.udi);
157 else if (opt.add)
158 err = add_udi(hal_ctx, opt.udi);
159 else
160 err = 6;
162 libhal_ctx_shutdown(hal_ctx, &error);
163 libhal_ctx_free(hal_ctx);
164 dbus_connection_unref(conn);
165 dbus_error_free(&error);
167 return err;
171 void help()
173 fprintf(stderr,
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"
186 * Dump all devices.
188 int dump_devices(LibHalContext *hal_ctx, char *arg)
190 int i;
191 int num_devices;
192 char **device_names;
193 DBusError error;
194 char *udi = NULL;
196 if (arg) {
197 if (*arg == '/') {
198 udi = arg;
199 } else {
200 #ifdef HAVE_ASPRINTF
201 asprintf(&udi, "/org/freedesktop/Hal/devices/%s", arg);
202 #else
203 udi = calloc(1, sizeof ("/org/freedesktop/Hal/devices/%s") + strlen(arg));
204 sprintf(udi, "/org/freedesktop/Hal/devices/%s", arg);
206 #endif
210 dbus_error_init(&error);
212 if (!udi) {
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);
216 return 31;
218 } else {
219 device_names = calloc(2, sizeof *device_names);
220 device_names[0] = strdup(udi);
221 num_devices = 1;
224 for(i = 0; i < num_devices; i++) {
225 LibHalPropertySet *props;
226 LibHalPropertySetIterator it;
227 int type;
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);
232 continue;
235 if (!udi)
236 printf("%d: ", i);
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);
241 switch (type) {
242 case LIBHAL_PROPERTY_TYPE_STRING:
243 printf(" %s = '%s' (string)\n",
244 libhal_psi_get_key(&it),
245 libhal_psi_get_string(&it)
247 break;
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)
254 break;
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)
261 break;
262 case LIBHAL_PROPERTY_TYPE_DOUBLE:
263 printf(" %s = %g (double)\n",
264 libhal_psi_get_key(&it),
265 libhal_psi_get_double(&it)
267 break;
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"
273 break;
274 case LIBHAL_PROPERTY_TYPE_STRLIST:
276 char **strlist;
278 printf (" %s = { ", libhal_psi_get_key(&it));
279 strlist = libhal_psi_get_strlist(&it);
280 while (*strlist) {
281 printf("'%s'%s", *strlist, strlist[1] ? ", " : "");
282 strlist++;
284 printf(" } (string list)\n");
286 break;
287 default:
288 printf("Unknown type %d = 0x%02x\n", type, type);
289 break;
293 libhal_free_property_set(props);
294 printf("\n");
297 libhal_free_string_array(device_names);
298 dbus_error_free(&error);
300 return 0;
304 int remove_udi(LibHalContext *hal_ctx, char *arg)
306 DBusError error;
307 char *udi;
309 if (!arg) return 11;
311 if (*arg == '/') {
312 udi = arg;
313 } else {
314 #ifdef HAVE_ASPRINTF
315 asprintf(&udi, "/org/freedesktop/Hal/devices/%s", arg);
316 #else
317 udi = calloc(1, sizeof ("/org/freedesktop/Hal/devices/%s") + strlen(arg));
318 sprintf(udi, "/org/freedesktop/Hal/devices/%s", arg);
319 #endif
323 dbus_error_init(&error);
325 if (opt.remove) {
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);
329 return 12;
332 fprintf(stderr, "removed: %s\n", udi);
333 return 13;
336 return 0;
340 int add_udi(LibHalContext *hal_ctx, char *arg)
342 DBusError error;
343 dbus_bool_t dev_exists = FALSE;
344 char *udi = NULL, buf[1024];
345 lh_prop_t *prop;
346 int err;
348 if (!arg)
349 return 21;
351 if (*arg == '/') {
352 udi = arg;
353 } else {
354 #ifdef HAVE_ASPRINTF
355 asprintf(&udi, "/org/freedesktop/Hal/devices/%s", arg);
356 #else
357 udi = calloc(1, sizeof ("/org/freedesktop/Hal/devices/%s") + strlen(arg));
358 sprintf(udi, "/org/freedesktop/Hal/devices/%s", arg);
359 #endif
362 if (udi)
363 new_dev.udi = strdup(udi);
365 dbus_error_init(&error);
367 if (udi)
368 dev_exists = libhal_device_exists(hal_ctx, udi, &error);
370 if (dev_exists) {
371 new_dev.real_udi = strdup(new_dev.udi);
372 } else {
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);
380 return 22;
383 printf("tmp udi: %s\n", new_dev.real_udi);
386 prop = NULL;
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);
396 if (!dev_exists) {
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);
408 return err;
412 char *skip_space(char *s)
414 while (isspace(*s)) s++;
416 return s;
420 char *skip_non_eq_or_space(char *s)
422 while (*s && *s != '=' && !isspace(*s))
423 s++;
425 return s;
429 char *skip_number(char *s)
431 while (*s == '-' || *s == '+' || *s == '.' || isdigit(*s))
432 s++;
434 return s;
438 char *skip_nonquote(char *s)
440 while (*s && *s != '\'')
441 s++;
443 return s;
447 void process_property(LibHalContext *hal_ctx, char *buf, lh_prop_t **prop)
449 char *s, *s1;
450 char *key, *s_val = NULL;
451 lh_prop_t *p;
452 unsigned len;
453 int remove = 0;
455 s = skip_space(buf);
457 if (*s == '-') {
458 remove = 1;
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);
465 *s++ = 0;
466 if (!*key)
467 return;
469 if (*key == '#')
470 return;
472 if (*s == '=')
473 s++;
474 s = skip_space(s);
476 if (!*s)
477 remove = 1;
479 p = calloc(1, sizeof *p);
480 p->type = LIBHAL_PROPERTY_TYPE_INVALID;
481 p->key = strdup(key);
483 if (remove) {
484 p->next = *prop;
485 *prop = p;
486 return;
489 if (*s == '\'') {
490 s_val = s + 1;
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 == '{') {
496 s_val = s + 1;
497 s1 = strrchr(s_val, '}');
498 if (s1) *s1 = 0;
499 p->type = LIBHAL_PROPERTY_TYPE_STRLIST;
500 len = 0;
501 p->v.strlist_value = calloc(1, sizeof *p->v.strlist_value);
502 while (*s_val++ == '\'') {
503 s = skip_nonquote(s_val);
504 if (*s) *s++ = 0;
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)) {
512 s += 4;
513 p->type = LIBHAL_PROPERTY_TYPE_BOOLEAN;
514 p->v.bool_value = TRUE;
515 } else if (!strncmp(s, "false", 5)) {
516 s += 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)")) {
521 *s1++ = 0;
522 p->type = LIBHAL_PROPERTY_TYPE_INT32;
523 p->v.int_value = strtol(s, NULL, 10);
524 } else if (strstr(s1, "(uint64)")) {
525 *s1++ = 0;
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);
533 s = s1;
536 if (p->type == LIBHAL_PROPERTY_TYPE_INVALID) {
537 free(p->key);
538 free(p);
539 } else {
540 p->next = *prop;
541 *prop = p;
546 int add_properties(LibHalContext *hal_ctx, new_dev_t *nd, lh_prop_t *prop)
548 DBusError error;
549 lh_prop_t *p;
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;
558 continue;
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);
569 return 41;
573 switch (p->type) {
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);
578 return 42;
580 break;
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);
585 return 42;
587 break;
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);
592 return 42;
594 break;
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);
599 return 42;
601 break;
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);
607 return 42;
609 break;
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);
615 return 42;
618 break;
619 default:
620 break;
624 if (udi2) udi3 = NULL;
625 if (udi3) udi2 = udi3;
627 if (udi2 && !nd->udi)
628 nd->udi = strdup(udi2);
630 return 0;
634 lh_prop_t *free_properties(lh_prop_t *prop)
636 lh_prop_t *next;
637 char **s;
639 for(; prop; prop = next) {
640 next = prop->next;
642 free(prop->key);
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);
648 free(prop);
651 return NULL;