linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch] first stupid try for a rule compose gui
@ 2004-03-15 20:28 Kay Sievers
  2004-03-18  2:55 ` Kay Sievers
  2004-03-23 18:46 ` Greg KH
  0 siblings, 2 replies; 3+ messages in thread
From: Kay Sievers @ 2004-03-15 20:28 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 417 bytes --]

Here is a first simple and pretty stupid try to make a simple tool for
composing of a udev rule.

It reads the udevdb to get all currently handled devices and presents a
list, where you can choose the device to compose the rule for.

The composed rule is just printed out in a window, nothing else by now.

Do we want something like this?
Nevermind, I always wanted to know, how this newt thing works :)

thanks,
Kay

[-- Attachment #2: 02-udevruler.patch --]
[-- Type: text/plain, Size: 11827 bytes --]

diff -Nru a/Makefile b/Makefile
--- a/Makefile	Mon Mar 15 21:11:57 2004
+++ b/Makefile	Mon Mar 15 21:11:57 2004
@@ -36,6 +36,7 @@
 INFO =		udevinfo
 TESTER =	udevtest
 STARTER =	udevstart
+RULER =		udevruler
 VERSION =	021_bk
 INSTALL_DIR =	/usr/local/bin
 RELEASE_NAME =	$(ROOT)-$(VERSION)
@@ -175,7 +176,7 @@
 
 CFLAGS += -I$(PWD)/libsysfs
 
-all: $(ROOT) $(SENDER) $(DAEMON) $(INFO) $(TESTER) $(STARTER)
+all: $(ROOT) $(SENDER) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(RULER)
 	@extras="$(EXTRAS)" ; for target in $$extras ; do \
 		echo $$target ; \
 		$(MAKE) prefix=$(prefix) \
@@ -294,10 +295,14 @@
 	$(LD) $(LDFLAGS) -o $@ $(CRT0) udevstart.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
 	$(STRIPCMD) $@
 
+$(RULER): $(RULER).o $(OBJS) $(HEADERS) $(LIBC)
+	$(LD) $(LDFLAGS) -o $@ $(CRT0) udevruler.o udev_config.o udevdb.o $(SYSFS) $(TDB) $(LIB_OBJS) $(ARCH_LIB_OBJS) -lnewt
+	$(STRIPCMD) $@
+
 clean:
 	-find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \
 	 | xargs rm -f 
-	-rm -f core $(ROOT) $(GEN_HEADERS) $(GEN_CONFIGS) $(INFO) $(DAEMON) $(SENDER) $(TESTER) $(STARTER)
+	-rm -f core $(ROOT) $(GEN_HEADERS) $(GEN_CONFIGS) $(INFO) $(DAEMON) $(SENDER) $(TESTER) $(STARTER) $(RULER)
 	$(MAKE) -C klibc clean
 	@extras="$(EXTRAS)" ; for target in $$extras ; do \
 		echo $$target ; \
diff -Nru a/udevruler.c b/udevruler.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/udevruler.c	Mon Mar 15 21:11:57 2004
@@ -0,0 +1,407 @@
+/*
+ * udevruler.c - simple udev-rule composer
+ *
+ * Reads the udev-db to get all currently known devices and
+ * scans the sysfs device chain for the choosen device to select attributes
+ * to compose a rule for the udev.rules file to uniquely name this device.
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *	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 version 2 of the License.
+ * 
+ *	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.,
+ *	675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <newt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "udev.h"
+#include "udev_version.h"
+#include "udevdb.h"
+#include "libsysfs/sysfs.h"
+#include "list.h"
+
+#ifdef LOG
+unsigned char logname[LOGNAME_SIZE];
+void log_message(int level, const char *format, ...)
+{
+	va_list args;
+
+	if (!udev_log)
+		return;
+
+	va_start(args, format);
+	vsyslog(level, format, args);
+	va_end(args);
+}
+#endif
+
+static char *dev_blacklist[] = {
+	"tty",
+	"pty",
+	"zero",
+	"null",
+	"kmsg",
+	"rtc",
+	"timer",
+	""
+};
+
+struct device {
+	struct list_head list;
+	char name[NAME_SIZE];
+	char devpath[DEVPATH_SIZE];
+};
+
+LIST_HEAD(device_list);
+int device_count;
+
+/* callback for database dump */
+static int add_record(char *path, struct udevice *udev)
+{
+	struct device *dev;
+	int i = 0;
+
+	while (dev_blacklist[i][0] != '\0') {
+		if (strncmp(udev->name, dev_blacklist[i], strlen(dev_blacklist[i])) == 0)
+			goto exit;
+		i++;
+	}
+
+	dev = malloc(sizeof(struct device));
+	if (dev == NULL) {
+		printf("error malloc\n");
+		exit(2);
+	}
+	strfieldcpy(dev->name, udev->name);
+	strfieldcpy(dev->devpath, path);
+	list_add_tail(&dev->list, &device_list);
+	device_count++;
+
+exit:
+	return 0;
+}
+
+/* get all devices from udev database */
+static int get_all_devices(void)
+{
+	int retval;
+
+	device_count = 0;
+	INIT_LIST_HEAD(&device_list);
+
+	retval = udevdb_open_ro();
+	if (retval != 0) {
+		printf("unable to open udev database\n");
+		exit(1);
+	}
+
+	udevdb_call_foreach(add_record);
+	udevdb_exit();
+
+	return 0;
+}
+
+struct attribute {
+	struct list_head list;
+	int level;
+	char key[NAME_SIZE];
+};
+
+LIST_HEAD(attribute_list);
+int attribute_count;
+
+static int add_attribute(const char *key, int level)
+{
+	struct attribute *attr;
+
+	dbg("add attribute '%s'", key);
+	attr = malloc(sizeof(struct attribute));
+	if (attr == NULL) {
+		printf("error malloc\n");
+		exit(2);
+	}
+
+	strfieldcpy(attr->key, key);
+	attr->level = level;
+	list_add_tail(&attr->list, &attribute_list);
+	attribute_count++;
+	return 0;
+}
+
+static int add_all_attributes(const char *path, int level)
+{
+	struct dlist *attributes;
+	struct sysfs_attribute *attr;
+	struct sysfs_directory *sysfs_dir;
+	char value[NAME_SIZE];
+	char key[NAME_SIZE];
+	int len;
+	int retval = 0;
+
+	dbg("look at '%s', level %i", path, level);
+
+	sysfs_dir = sysfs_open_directory(path);
+	if (sysfs_dir == NULL)
+		return -1;
+
+	attributes = sysfs_get_dir_attributes(sysfs_dir);
+	if (attributes == NULL) {
+		retval = -1;
+		return 0;
+	}
+
+	dlist_for_each_data(attributes, attr, struct sysfs_attribute)
+		if (attr->value != NULL) {
+			dbg("found attribute '%s'", attr->name);
+			strfieldcpy(value, attr->value);
+			len = strlen(value);
+			if (len == 0)
+				continue;
+
+			/* skip very long attributes */
+			if (len > 40)
+				continue;
+
+			/* remove trailing newline */
+			if (value[len-1] == '\n') {
+				value[len-1] = '\0';
+				len--;
+			}
+
+			/* skip nonprintable values */
+			while (len) {
+				if (!isprint(value[len-1]))
+					break;
+				len--;
+			}
+			if (len == 0) {
+				sprintf(key, "SYSFS{%s}=\"%s\"", attr->name, value);
+				add_attribute(key, level);
+			}
+		}
+
+	return 0;
+}
+
+static int get_all_attributes(char *path)
+{
+	struct sysfs_class_device *class_dev;
+	struct sysfs_class_device *class_dev_parent;
+	struct sysfs_attribute *attr;
+	struct sysfs_device *sysfs_dev;
+	struct sysfs_device *sysfs_dev_parent;
+	char key[NAME_SIZE];
+	int retval = 0;
+	int level = 0;
+
+	attribute_count = 0;
+	INIT_LIST_HEAD(&attribute_list);
+
+	/*  get the class dev */
+	class_dev = sysfs_open_class_device_path(path);
+	if (class_dev == NULL) {
+		dbg("couldn't get the class device");
+		return -1;
+	}
+
+	/* read the 'dev' file for major/minor*/
+	attr = sysfs_get_classdev_attr(class_dev, "dev");
+	if (attr == NULL) {
+		dbg("couldn't get the \"dev\" file");
+		retval = -1;
+		goto exit;
+	}
+
+	sysfs_close_attribute(attr);
+
+	/* open sysfs class device directory and get all attributes */
+	if (add_all_attributes(class_dev->path, level) != 0) {
+		dbg("couldn't open class device directory");
+		retval = -1;
+		goto exit;
+	}
+	level++;
+
+	/* get the device link (if parent exists look here) */
+	class_dev_parent = sysfs_get_classdev_parent(class_dev);
+	if (class_dev_parent != NULL) {
+		//sysfs_close_class_device(class_dev);
+		class_dev = class_dev_parent;
+	}
+	sysfs_dev = sysfs_get_classdev_device(class_dev);
+
+	/* look the device chain upwards */
+	while (sysfs_dev != NULL) {
+		if (sysfs_dev->bus[0] != '\0') {
+			add_attribute("", level);
+			sprintf(key, "BUS=\"%s\"", sysfs_dev->bus);
+			add_attribute(key, level);
+			sprintf(key, "ID=\"%s\"", sysfs_dev->bus_id);
+			add_attribute(key, level);
+
+			/* open sysfs device directory and print all attributes */
+			add_all_attributes(sysfs_dev->path, level);
+		}
+		level++;
+
+		sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
+		if (sysfs_dev_parent == NULL)
+			break;
+
+		//sysfs_close_device(sysfs_dev);
+		sysfs_dev = sysfs_dev_parent;
+	}
+	sysfs_close_device(sysfs_dev);
+
+exit:
+	//sysfs_close_class_device(class_dev);
+	return retval;
+}
+
+
+int main(int argc, char *argv[]) {
+	newtComponent lbox, run, lattr;
+	newtComponent quit, form, answer;
+	newtGrid grid, grid2;
+	char *devpath;
+	char roottext[81];
+	char path[NAME_SIZE];
+	struct device *dev;
+
+	newtInit();
+	newtCls();
+
+	newtWinMessage("udevruler", "Ok",
+		       "This program lets you select a device currently present "
+		       "on the system and you may choose the attributes to uniquely "
+		       "name the device with a udev rule.\n"
+		       "No configuration will be changed, it just prints the rule "
+		       "to place in a udev.rules configuration file. The \"%k\" in the "
+		       "NAME key of the printed rule may be replaced by the name the "
+		       "node should have.");
+
+	init_logging("udevruler");
+	udev_init_config();
+	get_all_devices();
+
+	lbox = newtListbox(2, 1, 10, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
+	list_for_each_entry(dev, &device_list, list)
+		newtListboxAppendEntry(lbox, dev->name, (void*) dev->devpath);
+
+	newtPushHelpLine("    <Tab>/<Alt-Tab> between elements  |    Use <Enter> to select a device");
+	snprintf(roottext, sizeof(roottext), "simple udev rule composer, version %s, (c) 2004 can't sleep team", UDEV_VERSION);
+	roottext[sizeof(roottext)-1] = '\0';
+	newtDrawRootText(0, 0, roottext);
+
+	form = newtForm(NULL, NULL, 0);
+	grid = newtCreateGrid(1, 2);
+	grid2 = newtButtonBar("Select device", &run, "Quit", &quit, NULL);
+	newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, lbox, 1, 0, 1, 0, NEWT_ANCHOR_TOP, 0);
+	newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, grid2, 0, 1, 0, 0, NEWT_ANCHOR_TOP, 0);
+	newtFormAddComponents(form, lbox, run, quit, NULL);
+	newtGridWrappedWindow(grid,"Choose the device for which to compose a rule");
+	newtGridFree(grid, 1);
+
+	while (1) {
+		struct attribute *attr;
+		newtComponent ok, back, form2, answer2;
+		newtGrid grid3, grid4;
+		int i;
+		int numitems;
+		struct attribute **selattr;
+
+		answer = newtRunForm(form);
+		if (answer == quit)
+			break;
+
+		devpath = (char *) newtListboxGetCurrent(lbox);
+		strfieldcpy(path, sysfs_path);
+		strfieldcat(path, devpath);
+		dbg("look at sysfs device '%s'", path);
+		get_all_attributes(path);
+
+		grid3 = newtCreateGrid(1, 2);
+		form2 = newtForm(NULL, NULL, 0);
+		grid4 = newtButtonBar("Ok", &ok, "Back", &back, NULL);
+
+		lattr = newtListbox(2, 1, 10, NEWT_FLAG_MULTIPLE | NEWT_FLAG_BORDER | NEWT_FLAG_RETURNEXIT);
+		list_for_each_entry(attr, &attribute_list, list)
+			newtListboxAddEntry(lattr, attr->key, (void *) attr);
+
+		newtGridSetField(grid3, 0, 0, NEWT_GRID_COMPONENT, lattr, 0, 0, 0, 1, 0, 0);
+		newtGridSetField(grid3, 0, 1, NEWT_GRID_SUBGRID, grid4, 0, 1, 0, 0, NEWT_ANCHOR_TOP, 0);
+
+		newtFormAddComponents(form2, lattr, ok, back, NULL);
+		newtGridWrappedWindow(grid3, "Select one ore more attributes within one section with the space bar");
+		newtGridFree(grid3, 1);
+
+		while (1) {
+			char rule[255];
+			int onelevel;
+			int skipped;
+
+			answer2 = newtRunForm(form2);
+			if (answer2 == back)
+				break;
+
+			selattr = (struct attribute **) newtListboxGetSelection(lattr, &numitems);
+			if (selattr != NULL) {
+				rule[0] = '\0';
+				onelevel = -1;
+				skipped = 0;
+				for (i = 0; i < numitems; i++) {
+					if (selattr[i]->key[0] == '\0')
+						continue;
+
+					if (onelevel != -1) {
+						if (onelevel != selattr[i]->level) {
+							skipped = 1;
+							continue;
+						}
+					} else {
+						onelevel = selattr[i]->level;
+					}
+
+					dbg("'%s'\n", selattr[i]->key);
+					strfieldcat(rule, selattr[i]->key);
+					strfieldcat(rule, ", ");
+				}
+				if (skipped) {
+					newtWinMessage("error", "Ok", "Please select only attributes within one section");
+					continue;
+				}
+
+				if (strlen(rule) > 200) {
+					newtWinMessage("error", "Ok", "The line is too long, please select fewer attributes.");
+				} else {
+					if (rule[0] == '\0')
+						continue;
+
+					strfieldcat(rule, "NAME=\"%k\"");
+					newtWinMessage("the rule to place in config file", "Ok", rule);
+				}
+			}
+		}
+
+		newtPopWindow();
+	}
+
+	newtPopWindow();
+	newtFormDestroy(form);
+	newtFinished();
+	return 0;
+}

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2004-03-23 18:46 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-03-15 20:28 [patch] first stupid try for a rule compose gui Kay Sievers
2004-03-18  2:55 ` Kay Sievers
2004-03-23 18:46 ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).