From: Petr Lautrbach <plautrba@redhat.com>
To: linux-hotplug@vger.kernel.org
Subject: [PATCH] udevadm monitor --filter= with GL_PLAIN comparison
Date: Wed, 18 Mar 2009 19:34:41 +0000 [thread overview]
Message-ID: <1237404881-1342-1-git-send-email-plautrba@redhat.com> (raw)
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
next reply other threads:[~2009-03-18 19:34 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-18 19:34 Petr Lautrbach [this message]
2009-03-19 1:33 ` [PATCH] udevadm monitor --filter= with GL_PLAIN comparison Kay Sievers
2009-03-19 9:38 ` Petr Lautrbach
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1237404881-1342-1-git-send-email-plautrba@redhat.com \
--to=plautrba@redhat.com \
--cc=linux-hotplug@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).