hal/tools Makefile.am,1.15,1.16 hal-device.c,NONE,1.1

David Zeuthen david at freedesktop.org
Fri Jul 8 16:02:31 PDT 2005


Update of /cvs/hal/hal/tools
In directory gabe:/tmp/cvs-serv25462/tools

Modified Files:
	Makefile.am 
Added Files:
	hal-device.c 
Log Message:
2005-07-08  David Zeuthen  <davidz at redhat.com>

        Make it possible to create and remove HAL devices without kernel and
        sysfs support. Some legacy devices or userspace driven devices may be
        useful in HAL too, but need to be maintained by an application instead
        of the kernel itself. Patch from Steffen Winterfeldt <snwint at suse.de>.

        * tools/hal-device.c: New file

        * tools/Makefile.am: Add build rules for hal-device

        * libhal/libhal.[ch]: Remove the _agent prefix from the agent_manager
        functions

        * hald/hald_dbus.h: Add prototypes for new functions

        * hald/hald_dbus.c (manager_new_device)
        (manager_remove_done, manager_remove)
        (manager_commit_done)
        (manager_commit_preprobing_done)
        (manager_commit_to_gdl): New functions
        (hald_dbus_filter_handle_methods): Add handlers for new D-BUS methods



Index: Makefile.am
===================================================================
RCS file: /cvs/hal/hal/tools/Makefile.am,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- Makefile.am	13 May 2005 15:56:23 -0000	1.15
+++ Makefile.am	8 Jul 2005 23:02:29 -0000	1.16
@@ -9,7 +9,7 @@
 	-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_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

--- NEW FILE: hal-device.c ---
/***************************************************************************
 * CVSID: $Id: hal-device.c,v 1.1 2005/07/08 23:02:29 david Exp $
 *
 * 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_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_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_device_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;
}




More information about the hal-commit mailing list