linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] udevadm monitor --filter= with GL_PLAIN comparison
@ 2009-03-18 19:34 Petr Lautrbach
  2009-03-19  1:33 ` Kay Sievers
  2009-03-19  9:38 ` Petr Lautrbach
  0 siblings, 2 replies; 3+ messages in thread
From: Petr Lautrbach @ 2009-03-18 19:34 UTC (permalink / raw)
  To: linux-hotplug

Hello.

My idea is to allow user to specify simple filters for monitoring udev events.

Events are printed only if pass all of filters. 

There is only GL_PLAIN comparison now. 

e.g.:
$ udevadm monitor --filter='SUBSYSTEM="bluetooth"' --filter='ACTION!="add"' 

This command prints only events which match "bluetooth" SUBSYSTEM and ACTION other 
than "add". 

I'll be glad to hear your opinions

---
 udev/udevadm-monitor.c |  209 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 206 insertions(+), 3 deletions(-)

diff --git a/udev/udevadm-monitor.c b/udev/udevadm-monitor.c
index 77d98fa..0daae41 100644
--- a/udev/udevadm-monitor.c
+++ b/udev/udevadm-monitor.c
@@ -33,6 +33,18 @@
 
 #include "udev.h"
 
+enum operation_type {
+	OP_MATCH,
+	OP_NOMATCH
+};
+
+struct filter_rule {
+	char *key;
+	char *value;
+	enum operation_type op;
+	struct filter_rule *next;
+};
+
 static int udev_exit;
 
 static void asmlinkage sig_handler(int signum)
@@ -64,6 +76,174 @@ static void print_device(struct udev_device *device, const char *source, int env
 	}
 }
 
+static int add_filter_rule (struct filter_rule **rules, const char *filter) {
+	char *filterpos = NULL;
+	char *keypos;
+	
+	filterpos = strdup(filter);
+	if (filterpos = NULL)
+		return -1;
+
+	keypos = filterpos;
+	while (*keypos != '\0') {
+		char *key;
+		char *value;
+		char *temp;
+		enum operation_type op;
+		struct filter_rule *new_rule;
+
+		/* udev-rules.c:877 */
+		/* skip whitespace */
+		while (isspace(*keypos) || *keypos = ',') {
+			keypos++;
+		}
+
+		/* end of filter, no conflict */
+		if (*keypos = '\0') {
+			free(filterpos);
+			return 0;
+		}
+		
+		/* find end of key */
+		key = keypos;
+		while (1) {
+			keypos++;
+			if (keypos[0] = '\0') {
+				goto error;
+			}
+			if (isspace(keypos[0]))
+				break;
+			if (keypos[0] = '=')
+				break;
+			if ((keypos[0] = '+') || (keypos[0] = '!') || (keypos[0] = ':'))
+				if (keypos[1] = '=')
+					break;
+		}
+
+		temp = keypos;
+		while (isspace(keypos[0]))
+			keypos++;
+		if (keypos[0] = '\0') {
+			goto error;
+		}
+	
+		/* get operation type */
+		if (keypos[0] = '=' && keypos[1] = '=') {
+			op = OP_MATCH;
+			keypos += 2;
+		} else if (keypos[0] = '!' && keypos[1] = '=') {
+			op = OP_NOMATCH;
+			keypos += 2;
+		}  
+		else {
+			goto error;
+		}
+
+		/* terminate key */
+		temp[0] = '\0';
+
+		/* skip whitespace after operator */
+		while (isspace(keypos[0]))
+			keypos++;
+		if (keypos[0] = '\0') {
+			goto error;
+		}
+	
+		/* get the value */
+		if (keypos[0] = '"')
+			keypos++;
+		else {
+			goto error;
+		}
+		value = keypos;
+	
+		/* terminate */
+		temp = strchr(keypos, '"');
+		if (!temp) {
+			goto error;
+		}
+		temp[0] = '\0';
+		keypos = temp + 1 ;
+
+		new_rule = (struct filter_rule *)malloc(sizeof(struct filter_rule));
+		if (new_rule = NULL)
+			goto error;
+		
+		new_rule->key = strdup(key);
+		if (new_rule->key = NULL) {
+			free(new_rule);
+			goto error;
+		}
+
+		new_rule->value = strdup(value);
+		if (new_rule->value = NULL) {
+			free(new_rule->key);	
+			free(new_rule);
+			goto error;
+		}
+
+		new_rule->op = op;
+
+		new_rule->next = *rules; 
+		*rules = new_rule;
+	}
+
+	free(filterpos);
+	return 0;
+
+error:
+	free(filterpos);
+	return -1;
+}
+
+static int free_rules(struct filter_rule *rules) {
+	struct filter_rule *rulespos, *rulestmp;
+
+	for (rulespos = rules; rulespos; rulespos = rulespos->next) {
+		rulestmp = rulespos;
+		free(rulestmp->key);
+		free(rulestmp->value);
+		free(rulestmp);
+	}
+	return 0;
+}
+
+static int filter_device(struct udev_device *device, struct filter_rule *filter) {
+	struct filter_rule *filterpos;
+	struct udev_list_entry *list_entry;
+
+	list_entry = udev_device_get_properties_list_entry(device);
+	if (list_entry = NULL) {
+		return 0;
+	}
+
+	for (filterpos = filter; filterpos; filterpos = filterpos->next) {
+		int match;
+		struct udev_list_entry *entry;
+
+		entry = udev_list_entry_get_by_name(list_entry, filterpos->key);
+		if (entry = NULL) {
+			return 0;
+		}
+
+		/*udev-rules.c:1871 GL_PLAIN*/
+		/* TODO: GL_GLOB, GL_SPLIT, GL_SPLIT_GLOB 
+		 * TODO: ATTR*/
+
+		match = ! strcasecmp(filterpos->value, udev_list_entry_get_value(entry));
+
+		/* udev-rules.c:1930 */
+		if ( !match && (filterpos->op = OP_MATCH)) {
+			return 0;
+		}
+		if ( !match && (filterpos->op = OP_NOMATCH)) {
+			return 0;
+		}
+	}
+	return 1;
+}
+		
+
 int udevadm_monitor(struct udev *udev, int argc, char *argv[])
 {
 	struct sigaction act;
@@ -76,16 +256,19 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
 	fd_set readfds;
 	int rc = 0;
 
+	struct filter_rule *filter = NULL;
+
 	static const struct option options[] = {
 		{ "environment", no_argument, NULL, 'e' },
 		{ "kernel", no_argument, NULL, 'k' },
 		{ "udev", no_argument, NULL, 'u' },
+		{ "filter", required_argument, NULL, 'f' },
 		{ "help", no_argument, NULL, 'h' },
 		{}
 	};
 
 	while (1) {
-		option = getopt_long(argc, argv, "ekuh", options, NULL);
+		option = getopt_long(argc, argv, "ekuf:h", options, NULL);
 		if (option = -1)
 			break;
 
@@ -99,11 +282,20 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
 		case 'u':
 			print_udev = 1;
 			break;
+		case 'f':
+			if (add_filter_rule(&filter, optarg) < 0) {
+				/* error */
+				fprintf(stderr, "can't parse filter: %s\n", optarg);
+				goto out;
+			}
+			break;
+
 		case 'h':
 			printf("Usage: udevadm monitor [--environment] [--kernel] [--udev] [--help]\n"
 			       "  --env    print the whole event environment\n"
 			       "  --kernel print kernel uevents\n"
 			       "  --udev   print udev events\n"
+			       "  --filter=<udev rule>   print udev events matching rule\n"
 			       "  --help\n\n");
 		default:
 			goto out;
@@ -139,6 +331,7 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
 			rc = 2;
 			goto out;
 		}
+
 		printf("UDEV the event which udev sends out after rule processing\n");
 	}
 	if (print_kernel) {
@@ -178,7 +371,9 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
 			device = udev_monitor_receive_device(kernel_monitor);
 			if (device = NULL)
 				continue;
-			print_device(device, "UEVENT", env);
+
+			if ( !filter || filter_device(device, filter))  
+					print_device(device, "UEVENT", env);
 			udev_device_unref(device);
 		}
 
@@ -188,13 +383,21 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[])
 			device = udev_monitor_receive_device(udev_monitor);
 			if (device = NULL)
 				continue;
-			print_device(device, "UDEV", env);
+
+			if ( !filter || filter_device(device, filter)) 
+					print_device(device, "UDEV", env);
 			udev_device_unref(device);
 		}
 	}
 
+
 out:
 	udev_monitor_unref(udev_monitor);
 	udev_monitor_unref(kernel_monitor);
+
+	if (filter)
+		/* clean filter */
+		free_rules(filter);
+
 	return rc;
 }
-- 
1.6.0.6


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

end of thread, other threads:[~2009-03-19  9:38 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-18 19:34 [PATCH] udevadm monitor --filter= with GL_PLAIN comparison Petr Lautrbach
2009-03-19  1:33 ` Kay Sievers
2009-03-19  9:38 ` Petr Lautrbach

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).