[PATCH] add tool to add/remove HAL devices
Kay Sievers
kay.sievers at vrfy.org
Sat Jul 2 09:46:23 PDT 2005
This adds a tool to add/remove devices to/from the HAL store.
It depends on the patch to implement the corresponding functions
in hald.
usage: hal-device [--help] [--add udi] [--remove udi] [udi]
-a, --add udi Add new device.
Reads property list in 'lshal' syntax from stdin.
-r, --remove udi Remove device.
-h, --help Show this text.
Thanks to Steffen Winterfeldt <snwint at suse.de>.
Ok to commit?
Thanks,
Kay
-------------- next part --------------
Index: tools/Makefile.am
===================================================================
RCS file: /cvs/hal/hal/tools/Makefile.am,v
retrieving revision 1.15
diff -u -p -r1.15 Makefile.am
--- tools/Makefile.am 13 May 2005 15:56:23 -0000 1.15
+++ tools/Makefile.am 2 Jul 2005 13:37:29 -0000
@@ -9,7 +9,7 @@ INCLUDES = \
-I$(top_srcdir) -I$(top_srcdir)/libhal \
@PACKAGE_CFLAGS@
-bin_PROGRAMS = lshal hal-get-property hal-set-property hal-find-by-capability hal-find-by-property
+bin_PROGRAMS = lshal hal-get-property hal-set-property hal-find-by-capability hal-find-by-property hal-device
if FSTAB_SYNC_ENABLED
sbin_PROGRAMS = fstab-sync
@@ -30,6 +30,9 @@ hal_find_by_capability_LDADD = @DBUS_LIB
hal_find_by_property_SOURCES = hal_find_by_property.c
hal_find_by_property_LDADD = @DBUS_LIBS@ $(top_builddir)/libhal/libhal.la
+hal_device_SOURCES = hal-device.c
+hal_device_LDADD = @DBUS_LIBS@ $(top_builddir)/libhal/libhal.la
+
if FSTAB_SYNC_ENABLED
fstab_sync_SOURCES = fstab-sync.c
fstab_sync_LDADD = -lpopt $(top_builddir)/libhal/libhal.la $(top_builddir)/libhal-storage/libhal-storage.la
Index: tools/hal-device.c
===================================================================
--- /dev/null 2005-06-29 03:39:32.000000000 +0200
+++ tools/hal-device.c 2005-07-02 15:46:10.000000000 +0200
@@ -0,0 +1,618 @@
+/***************************************************************************
+ * CVSID: $Id: $
+ *
+ * hal-device.c : add devices HAL
+ *
+ * Copyright (C) 2005 SuSE Linux Gmbh
+ *
+ * Authors:
+ * Steffen Winterfeldt <snwint at suse.de>
+ *
+ * Licensed under the Academic Free License version 2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#define _GNU_SOURCE
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <getopt.h>
+
+#ifndef DBUS_API_SUBJECT_TO_CHANGE
+#define DBUS_API_SUBJECT_TO_CHANGE 1
+#endif
+
+#include <dbus/dbus.h>
+#include <libhal/libhal.h>
+
+typedef struct {
+ char *udi;
+ char *real_udi;
+} new_dev_t;
+
+typedef struct lh_prop_s {
+ struct lh_prop_s *next;
+ LibHalPropertyType type;
+ char *key;
+ union {
+ char *str_value;
+ dbus_int32_t int_value;
+ dbus_uint64_t uint64_value;
+ double double_value;
+ dbus_bool_t bool_value;
+ char **strlist_value;
+ };
+} lh_prop_t;
+
+
+void help(void);
+int dump_devices(LibHalContext *hal_ctx, char *arg);
+int remove_udi(LibHalContext *hal_ctx, char *arg);
+int add_udi(LibHalContext *hal_ctx, char *arg);
+void process_property(LibHalContext *hal_ctx, char *buf, lh_prop_t **prop);
+int add_properties(LibHalContext *hal_ctx, new_dev_t *nd, lh_prop_t *prop);
+lh_prop_t *free_properties(lh_prop_t *prop);
+static char *skip_space(char *s);
+static char *skip_non_eq_or_space(char *s);
+static char *skip_number(char *s);
+static char *skip_nonquote(char *s);
+
+
+new_dev_t new_dev;
+
+struct {
+ unsigned remove:1;
+ unsigned add:1;
+ unsigned list:1;
+ char *udi;
+} opt;
+
+struct option options[] = {
+ { "remove", 1, NULL, 'r' },
+ { "add", 1, NULL, 'a' },
+ { "help", 0, NULL, 'h' },
+ {}
+};
+
+
+int main(int argc, char **argv)
+{
+ DBusError error;
+ DBusConnection *conn;
+ LibHalContext *hal_ctx;
+ int i, err;
+
+ opterr = 0;
+ opt.list = 1;
+
+ while ((i = getopt_long(argc, argv, "a:hr:", options, NULL)) != -1) {
+ switch (i) {
+ case 'a':
+ opt.add = 1;
+ opt.list = 0;
+ opt.udi = optarg;
+ break;
+ case 'r':
+ opt.remove = 1;
+ opt.list = 0;
+ opt.udi = optarg;
+ break;
+ case 'h':
+ help();
+ return 0;
+ default:
+ help();
+ return 1;
+ }
+ }
+
+ dbus_error_init(&error);
+
+ if (!(conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
+ fprintf(stderr, "error: dbus_bus_get: %s: %s\n", error.name, error.message);
+ return 2;
+ }
+
+ // fprintf(stderr, "connected to: %s\n", dbus_bus_get_unique_name(conn));
+ if (!(hal_ctx = libhal_ctx_new())) return 3;
+ if (!libhal_ctx_set_dbus_connection(hal_ctx, conn)) return 4;
+ if (!libhal_ctx_init(hal_ctx, &error)) {
+ fprintf(stderr, "error: libhal_ctx_init: %s: %s\n", error.name, error.message);
+ return 5;
+ }
+
+ err = 0;
+ if (opt.list)
+ err = dump_devices(hal_ctx, argv[optind]);
+ else if (opt.remove)
+ err = remove_udi(hal_ctx, opt.udi);
+ else if (opt.add)
+ err = add_udi(hal_ctx, opt.udi);
+ else
+ err = 6;
+
+ libhal_ctx_shutdown(hal_ctx, &error);
+ libhal_ctx_free(hal_ctx);
+ dbus_connection_disconnect(conn);
+ dbus_connection_unref(conn);
+ dbus_error_free(&error);
+
+ return err;
+}
+
+
+void help()
+{
+ fprintf(stderr,
+ "usage: hal-device [--help] [--add udi] [--remove udi] [udi]\n"
+ "Create, remove, or show HAL device. If no udi is given, shows all devices.\n"
+ "If udi doesn't start with a '/', '/org/freedesktop/Hal/devices/' is prepended.\n"
+ " -a, --add udi\t\tAdd new device.\n"
+ " \t\t\tReads property list in 'lshal' syntax from stdin.\n"
+ " -r, --remove udi\tRemove device.\n"
+ " -h, --help\t\tShow this text.\n"
+ );
+}
+
+
+/*
+ * Dump all devices.
+ */
+int dump_devices(LibHalContext *hal_ctx, char *arg)
+{
+ int i;
+ int num_devices;
+ char **device_names;
+ DBusError error;
+ char *udi = NULL;
+
+ if (arg) {
+ if (*arg == '/') {
+ udi = arg;
+ } else {
+ asprintf(&udi, "/org/freedesktop/Hal/devices/%s", arg);
+ }
+ }
+
+ dbus_error_init(&error);
+
+ if (!udi) {
+ if (!(device_names = libhal_get_all_devices(hal_ctx, &num_devices, &error))) {
+ fprintf(stderr, "Empty HAL device list.\n");
+ return 31;
+ }
+ } else {
+ device_names = calloc(2, sizeof *device_names);
+ device_names[0] = strdup(udi);
+ num_devices = 1;
+ }
+
+ for(i = 0; i < num_devices; i++) {
+ LibHalPropertySet *props;
+ LibHalPropertySetIterator it;
+ int type;
+
+ if (!(props = libhal_device_get_all_properties(hal_ctx, device_names[i], &error))) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ dbus_error_init(&error);
+ continue;
+ }
+
+ if (!udi)
+ printf("%d: ", i);
+ printf("udi = '%s'\n", device_names[i]);
+
+ for(libhal_psi_init(&it, props); libhal_psi_has_more(&it); libhal_psi_next(&it)) {
+ type = libhal_psi_get_type(&it);
+ switch (type) {
+ case LIBHAL_PROPERTY_TYPE_STRING:
+ printf(" %s = '%s' (string)\n",
+ libhal_psi_get_key(&it),
+ libhal_psi_get_string(&it)
+ );
+ break;
+ case LIBHAL_PROPERTY_TYPE_INT32:
+ printf(" %s = %d (0x%x) (int)\n",
+ libhal_psi_get_key(&it),
+ libhal_psi_get_int(&it),
+ libhal_psi_get_int(&it)
+ );
+ break;
+ case LIBHAL_PROPERTY_TYPE_UINT64:
+ printf(" %s = %lld (0x%llx) (uint64)\n",
+ libhal_psi_get_key(&it),
+ (long long) libhal_psi_get_uint64(&it),
+ (long long) libhal_psi_get_uint64(&it)
+ );
+ break;
+ case LIBHAL_PROPERTY_TYPE_DOUBLE:
+ printf(" %s = %g (double)\n",
+ libhal_psi_get_key(&it),
+ libhal_psi_get_double(&it)
+ );
+ break;
+ case LIBHAL_PROPERTY_TYPE_BOOLEAN:
+ printf(" %s = %s (bool)\n",
+ libhal_psi_get_key(&it),
+ libhal_psi_get_bool(&it) ? "true" : "false"
+ );
+ break;
+ case LIBHAL_PROPERTY_TYPE_STRLIST:
+ {
+ char **strlist;
+
+ printf (" %s = { ", libhal_psi_get_key(&it));
+ strlist = libhal_psi_get_strlist(&it);
+ while (*strlist) {
+ printf("'%s'%s", *strlist, strlist[1] ? ", " : "");
+ strlist++;
+ }
+ printf(" } (string list)\n");
+ }
+ break;
+ default:
+ printf("Unknown type %d = 0x%02x\n", type, type);
+ break;
+ }
+ }
+
+ libhal_free_property_set(props);
+ printf("\n");
+ }
+
+ libhal_free_string_array(device_names);
+ dbus_error_free(&error);
+
+ return 0;
+}
+
+
+int remove_udi(LibHalContext *hal_ctx, char *arg)
+{
+ DBusError error;
+ char *udi;
+
+ if (!arg) return 11;
+
+ if (*arg == '/') {
+ udi = arg;
+ } else {
+ asprintf(&udi, "/org/freedesktop/Hal/devices/%s", arg);
+ }
+
+ dbus_error_init(&error);
+
+ if (remove) {
+ if (!libhal_agent_remove_device(hal_ctx, udi, &error)) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ return 12;
+ }
+
+ fprintf(stderr, "removed: %s\n", udi);
+ return 13;
+ }
+
+ return 0;
+}
+
+
+int add_udi(LibHalContext *hal_ctx, char *arg)
+{
+ DBusError error;
+ dbus_bool_t dev_exists = FALSE;
+ char *udi = NULL, buf[1024];
+ lh_prop_t *prop;
+ int err;
+
+ if (!arg)
+ return 21;
+
+ if (*arg == '/') {
+ udi = arg;
+ } else {
+ asprintf(&udi, "/org/freedesktop/Hal/devices/%s", arg);
+ }
+
+ if (udi)
+ new_dev.udi = strdup(udi);
+
+ dbus_error_init(&error);
+
+ if (udi)
+ dev_exists = libhal_device_exists(hal_ctx, udi, &error);
+
+ if (dev_exists) {
+ new_dev.real_udi = strdup(new_dev.udi);
+ } else {
+ new_dev.real_udi = libhal_agent_new_device(hal_ctx, &error);
+
+ if (!new_dev.real_udi) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ free(new_dev.real_udi);
+
+ return 22;
+ }
+
+ printf("tmp udi: %s\n", new_dev.real_udi);
+ }
+
+ prop = NULL;
+
+ while (fgets(buf, sizeof buf, stdin)) {
+ process_property(hal_ctx, buf, &prop);
+ }
+
+ err = add_properties(hal_ctx, &new_dev, prop);
+
+ prop = free_properties(prop);
+
+ if (!dev_exists) {
+ if (!libhal_agent_commit_to_gdl(hal_ctx, new_dev.real_udi, new_dev.udi, &error)) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ free(new_dev.real_udi);
+
+ err = err ?: 23;
+ }
+ }
+
+ printf("%s: %s\n", dev_exists ? "merged": "created", new_dev.udi);
+
+ return err;
+}
+
+
+char *skip_space(char *s)
+{
+ while (isspace(*s)) s++;
+
+ return s;
+}
+
+
+char *skip_non_eq_or_space(char *s)
+{
+ while (*s && *s != '=' && !isspace(*s))
+ s++;
+
+ return s;
+}
+
+
+char *skip_number(char *s)
+{
+ while (*s == '-' || *s == '+' || *s == '.' || isdigit(*s))
+ s++;
+
+ return s;
+}
+
+
+char *skip_nonquote(char *s)
+{
+ while (*s && *s != '\'')
+ s++;
+
+ return s;
+}
+
+
+void process_property(LibHalContext *hal_ctx, char *buf, lh_prop_t **prop)
+{
+ char *s, *s1;
+ char *key, *s_val = NULL;
+ lh_prop_t *p;
+ unsigned len;
+ int remove = 0;
+
+ s = skip_space(buf);
+
+ if (*s == '-') {
+ remove = 1;
+ s = skip_space(s + 1);
+ }
+
+ if ((s1 = skip_number(s), s1 != s) && *s1 == ':') s = skip_space(s1 + 1);
+
+ s = skip_non_eq_or_space(key = s);
+ *s++ = 0;
+ if (!*key)
+ return;
+
+ if (*key == '#')
+ return;
+
+ if (*s == '=')
+ s++;
+ s = skip_space(s);
+
+ if (!*s)
+ remove = 1;
+
+ p = calloc(1, sizeof *p);
+ p->type = LIBHAL_PROPERTY_TYPE_INVALID;
+ p->key = strdup(key);
+
+ if (remove) {
+ p->next = *prop;
+ *prop = p;
+ return;
+ }
+
+ if (*s == '\'') {
+ s_val = s + 1;
+ s = strrchr(s_val, '\'');
+ *(s ?: s_val) = 0;
+ p->type = LIBHAL_PROPERTY_TYPE_STRING;
+ p->str_value = strdup(s_val);
+ } else if (*s == '{') {
+ s_val = s + 1;
+ s1 = strrchr(s_val, '}');
+ if (s1) *s1 = 0;
+ p->type = LIBHAL_PROPERTY_TYPE_STRLIST;
+ len = 0;
+ p->strlist_value = calloc(1, sizeof *p->strlist_value);
+ while (*s_val++ == '\'') {
+ s = skip_nonquote(s_val);
+ if (*s) *s++ = 0;
+ p->strlist_value = realloc(p->strlist_value, (len + 2) * sizeof *p->strlist_value);
+ p->strlist_value[len] = strdup(s_val);
+ p->strlist_value[++len] = NULL;
+ s_val = skip_nonquote(s);
+ }
+ } else if (!strncmp(s, "true", 4)) {
+ s += 4;
+ p->type = LIBHAL_PROPERTY_TYPE_BOOLEAN;
+ p->bool_value = TRUE;
+ } else if (!strncmp(s, "false", 5)) {
+ s += 5;
+ p->type = LIBHAL_PROPERTY_TYPE_BOOLEAN;
+ p->bool_value = FALSE;
+ } else if ((s1 = skip_number(s)) != s) {
+ if (strstr(s1, "(int)")) {
+ *s1++ = 0;
+ p->type = LIBHAL_PROPERTY_TYPE_INT32;
+ p->int_value = strtol(s, NULL, 10);;
+ } else if (strstr(s1, "(uint64)")) {
+ *s1++ = 0;
+ p->type = LIBHAL_PROPERTY_TYPE_UINT64;
+ p->uint64_value = strtoull(s, NULL, 10);
+ } else if (strstr(s1, "(double)")) {
+ p->type = LIBHAL_PROPERTY_TYPE_DOUBLE;
+ p->double_value = strtod(s, NULL);
+ }
+
+ s = s1;
+ }
+
+ if (p->type == LIBHAL_PROPERTY_TYPE_INVALID) {
+ free(p->key);
+ free(p);
+ } else {
+ p->next = *prop;
+ *prop = p;
+ }
+}
+
+
+int add_properties(LibHalContext *hal_ctx, new_dev_t *nd, lh_prop_t *prop)
+{
+ DBusError error;
+ lh_prop_t *p;
+ char *udi2 = NULL, *udi3 = NULL, **s;
+ LibHalPropertyType old_type;
+
+ dbus_error_init(&error);
+
+ for(p = prop; p; p = p->next) {
+ if (!strcmp(p->key, "udi") && p->type == LIBHAL_PROPERTY_TYPE_STRING) {
+ udi2 = p->str_value;
+ continue;
+ }
+
+ old_type = libhal_device_get_property_type(hal_ctx, nd->real_udi, p->key, &error);
+ dbus_error_init(&error);
+
+ if (old_type != LIBHAL_PROPERTY_TYPE_INVALID &&
+ ( p->type != old_type || p->type == LIBHAL_PROPERTY_TYPE_STRLIST)) {
+ if (!libhal_device_remove_property(hal_ctx, nd->real_udi, p->key, &error)) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ return 41;
+ }
+ }
+
+ switch (p->type) {
+ case LIBHAL_PROPERTY_TYPE_INVALID:
+ break;
+ case LIBHAL_PROPERTY_TYPE_BOOLEAN:
+ if (!libhal_device_set_property_bool(hal_ctx, nd->real_udi, p->key, p->bool_value, &error)) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ return 42;
+ }
+ break;
+ case LIBHAL_PROPERTY_TYPE_INT32:
+ if (!libhal_device_set_property_int(hal_ctx, nd->real_udi, p->key, p->int_value, &error)) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ return 42;
+ }
+ break;
+ case LIBHAL_PROPERTY_TYPE_UINT64:
+ if (!libhal_device_set_property_uint64(hal_ctx, nd->real_udi, p->key, p->uint64_value, &error)) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ return 42;
+ }
+ break;
+ case LIBHAL_PROPERTY_TYPE_DOUBLE:
+ if (!libhal_device_set_property_double(hal_ctx, nd->real_udi, p->key, p->double_value, &error)) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ return 42;
+ }
+ break;
+ case LIBHAL_PROPERTY_TYPE_STRING:
+ if (!strcmp(p->key, "info.udi")) udi3 = p->str_value;
+ if (!libhal_device_set_property_string(hal_ctx, nd->real_udi, p->key, p->str_value, &error)) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ return 42;
+ }
+ break;
+ case LIBHAL_PROPERTY_TYPE_STRLIST:
+ for(s = p->strlist_value; *s; s++) {
+ if (!libhal_device_property_strlist_append(hal_ctx, nd->real_udi, p->key, *s, &error)) {
+ fprintf(stderr, "%s: %s\n", error.name, error.message);
+ return 42;
+ }
+ }
+ break;
+ }
+ }
+
+ if (udi2) udi3 = NULL;
+ if (udi3) udi2 = udi3;
+
+ if (udi2 && !nd->udi)
+ nd->udi = strdup(udi2);
+
+ return 0;
+}
+
+
+lh_prop_t *free_properties(lh_prop_t *prop)
+{
+ lh_prop_t *next;
+ char **s;
+
+ for(; prop; prop = next) {
+ next = prop->next;
+
+ free(prop->key);
+ if (prop->type == LIBHAL_PROPERTY_TYPE_STRING) free(prop->str_value);
+ if (prop->type == LIBHAL_PROPERTY_TYPE_STRLIST && prop->strlist_value) {
+ for(s = prop->strlist_value; *s; ) free(*s++);
+ free(prop->strlist_value);
+ }
+ free(prop);
+ }
+
+ return NULL;
+}
-------------- next part --------------
_______________________________________________
hal mailing list
hal at lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/hal
More information about the Hal
mailing list