devattr - a tool to expose the libdevattr functionality
authorNolan Lum <nol888@gmail.com>
Tue, 7 Dec 2010 06:03:30 +0000 (06:03 +0000)
committerAlex Hornung <ahornung@gmail.com>
Tue, 7 Dec 2010 06:09:07 +0000 (06:09 +0000)
sbin/Makefile
sbin/devattr/Makefile [new file with mode: 0644]
sbin/devattr/devattr.8 [new file with mode: 0644]
sbin/devattr/devattr.c [new file with mode: 0644]

index b6ba284..0b9f004 100644 (file)
@@ -13,6 +13,7 @@ SUBDIR=       adjkerntz \
        clri \
        comcontrol \
        cryptdisks \
+       devattr \
        devd \
        devfsctl \
        dhclient \
diff --git a/sbin/devattr/Makefile b/sbin/devattr/Makefile
new file mode 100644 (file)
index 0000000..897aee4
--- /dev/null
@@ -0,0 +1,7 @@
+PROG=   devattr
+MAN=   devattr.8
+WARNS?= 6
+
+LDADD=  -ldevattr -lprop
+
+.include <bsd.prog.mk>
diff --git a/sbin/devattr/devattr.8 b/sbin/devattr/devattr.8
new file mode 100644 (file)
index 0000000..2c372b7
--- /dev/null
@@ -0,0 +1,121 @@
+.\"
+.\" Copyright (c) 2010 The DragonFly Project.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to The DragonFly Project
+.\" by Nolan Lum <nol888@gmail.com>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in
+.\"    the documentation and/or other materials provided with the
+.\"    distribution.
+.\" 3. Neither the name of The DragonFly Project nor the names of its
+.\"    contributors may be used to endorse or promote products derived
+.\"    from this software without specific, prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED.    IN NO EVENT SHALL THE
+.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.Dd December 6, 2010
+.Os
+.Dt DEVATTR 8
+.Sh NAME
+.Nm devattr
+.Nd tool for displaying devices and their associated properties
+.Sh SYNOPSIS
+.Nm
+.Op Fl Ah
+.Op Fl p Ar property
+.Op Fl d Ar device
+.Op Fl m Ar key:value
+.Op Fl r Ar key:value
+.Sh DESCRIPTION
+The
+.Nm
+tool is for displaying a list of devices and some
+associated properties such as their name. This tool exposes the
+same functionality provided by the
+.Xr devattr 3
+library, namely the filtering capabilites offered.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl A
+Excludes aliases from the listing.
+.\"
+.It Fl h
+Displays a help message.
+.\"
+.It Fl p
+Only display property
+.Fl p .
+This can be can be specified multiple times and combined
+with all other options.
+.\"
+.It Fl d
+Only display devices with name
+.Fl d .
+When used with
+.Fl p ,
+only properties 
+.Fl p
+of device
+.Fl d
+are listed. Can be specified multiple times. Allows wildcards.
+.\"
+.It Fl m
+Only display devices whose property 
+.I key
+matches with wildcards value
+.I value
+unless the key\-value pair starts with ~, in which case
+the match is inverted. Stacks with
+.Fl p ,
+.Fl d ,
+.Fl m .
+Can be specified multiple times.
+.\"
+.It Fl r
+Behaves similarly to 
+.Fl m ,
+but matches with regex.
+.Sh EXAMPLES
+List all devices named 'pts/0'.
+.Bd -ragged -offset indent
+.Nm Fl d 
+pts/0
+.Ed
+.Pp
+List all devices whose major number is 64.
+.Bd -ragged -offset indent
+.Nm Fl m
+major:64
+.Ed
+.Pp
+List all devices whose name is 'pts/0' and major number is not 64.
+.Bd -ragged -offset indent
+.Nm Fl d
+pts/0
+.Fl m
+~major:64
+.Ed
+.Sh SEE ALSO
+.Xr devattr 3 ,
+.Xr udevd 8 
+.Sh AUTHORS
+.An Nolan Lum
+
diff --git a/sbin/devattr/devattr.c b/sbin/devattr/devattr.c
new file mode 100644 (file)
index 0000000..78982f9
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2010
+ *             The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Nolan Lum <nol888@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.     IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+
+#include <ctype.h>
+#include <devattr.h>
+#include <err.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+static SLIST_HEAD(, sl_entry) props = SLIST_HEAD_INITIALIZER(props);
+struct sl_entry {
+       char *val;
+       SLIST_ENTRY(sl_entry) entries;
+} *ent;
+
+static void
+usage(const char* name) {
+       fprintf(stderr, "Usage: %s [-Ah] [-p property] [-d device] [-m key:value] [-r key:value]\n"
+                    "Valid options are:\n"
+                                       " -A\n"
+                                       "       Don't display aliases.\n"
+                                       " -h\n"
+                                       "       Print this help message.\n\n"
+
+                                       "Valid options with their arguments are:\n"
+                                       " -p <property>\n"
+                                       "       Only display property; can be specified multiple times and\n"
+                                       "       combined with all other options.\n"
+                                       " -d <device>\n"
+                                       "       Only display devices with name `device'. When used with\n"
+                                       "       -p, only properties `-p' of device `-d' are listed. Can be\n"
+                                       "       specified multiple times. Allows wildcards.\n"
+                                       " -m <key:value>\n"
+                    "  Only display devices whose property `key' matches with wildcards\n"
+                                       "       value `value' unless the key-value pair starts with ~, in which\n"
+                                       "       case the match is inverted. Stacks with -p, -d, and -m.\n"
+                                       "       Can be specified multiple times.\n"
+                                       " -r <key:value>\n"
+                                       "       Behaves similarly to `-m', but matches with regex.\n"
+                       , name);
+}
+
+static int
+parse_args(int argc, char* argv[], struct udev_enumerate *enumerate) {
+       int ch, invert;
+       char *colon;
+
+       SLIST_INIT(&props);
+
+       /* A = no aliases */
+       /* p = properties to list (defaults to all) */
+       /* d = devices to list (defaults to all) */
+       /* m = display only devices in d that match these prop values */
+       /* r = display only devices in d that match these prop values (regex) */
+       while ((ch = getopt(argc, argv, "Ap:d:m:r:h")) != -1) {
+               invert = false;
+
+               switch (ch) {
+               case 'A':
+                       udev_enumerate_add_match_property(enumerate, "alias", "0");
+                       break;
+               case 'p':
+                       ent = malloc(sizeof(struct sl_entry));
+                       ent->val = optarg;
+                       SLIST_INSERT_HEAD(&props, ent, entries);
+                       break;
+               case 'd':
+                       udev_enumerate_add_match_expr(enumerate, "name", optarg);
+                       break;
+               case 'm':
+               case 'r':
+                       /* Check for exclusion. */
+                       invert = *optarg == '~';
+
+                       /* Split into key/value. */
+                       colon = strchr(optarg, ':');
+                       if (colon == NULL) {
+                               fprintf(stderr,
+                                   "Invalid property key/value pair `%s'.\n",
+                                   optarg);
+                               return (0);
+                       }
+
+                       *colon = '\0';
+                       if (invert) {
+                               if (ch == 'r')
+                                       udev_enumerate_add_nomatch_regex(enumerate,
+                                           optarg + 1, colon + 1);
+                               else
+                                       udev_enumerate_add_nomatch_expr(enumerate,
+                                           optarg + 1, colon + 1);
+                       } else {
+                               if (ch == 'r')
+                                       udev_enumerate_add_match_regex(enumerate,
+                                           optarg, colon + 1);
+                               else
+                                       udev_enumerate_add_match_expr(enumerate,
+                                           optarg, colon + 1);
+                       }
+                       break;
+               case 'h':
+                       usage(argv[0]);
+                       return (-1);
+               case '?':
+                       usage(argv[0]);
+                       return (-1);
+               }
+       }
+       return (0);
+}
+
+static void
+print_prop(const char* key, prop_object_t value) {
+       char *val_str;
+
+       printf("\t%s = ", key);
+
+       prop_type_t val_type = prop_object_type(value);
+       switch (val_type) {
+       case PROP_TYPE_BOOL:
+               printf("%s\n", prop_bool_true((prop_bool_t) value) ? "true" : "false");
+               break;
+       case PROP_TYPE_NUMBER:
+               if (prop_number_unsigned((prop_number_t) value))
+                       printf("%1$"PRIu64" (0x%1$"PRIx64")\n",
+                           prop_number_unsigned_integer_value((prop_number_t) value));
+               else
+                       printf("%"PRId64"\n",
+                           prop_number_integer_value((prop_number_t) value));
+               break;
+       case PROP_TYPE_STRING:
+               val_str = prop_string_cstring(value);
+               printf("%s\n", val_str);
+               free(val_str);
+               break;
+       default:
+               break;
+       }
+}
+
+int
+main(int argc, char* argv[]) {
+       struct udev *ctx;
+       struct udev_enumerate *enumerate;
+       struct udev_list_entry *current;
+       struct udev_device *dev;
+       prop_object_t key_val;
+       prop_dictionary_t dict;
+       prop_dictionary_keysym_t cur_key;
+       prop_object_iterator_t iter;
+       const char *key_str;
+       char *dev_name;
+       int ret;
+
+       ctx = udev_new();
+       if (ctx == NULL)
+               err(EX_UNAVAILABLE, "udev_new");
+
+       enumerate = udev_enumerate_new(ctx);
+       if (enumerate == NULL)
+               err(EX_UNAVAILABLE, "udev_enumerate_new");
+
+       ret = parse_args(argc, argv, enumerate);
+       if (ret != 0)
+               return (EX_USAGE);
+
+       ret = udev_enumerate_scan_devices(enumerate);
+       if (ret != 0)
+               err(EX_UNAVAILABLE, "udev_enumerate_scan_devices ret = %d", ret);
+
+       current = udev_enumerate_get_list_entry(enumerate);
+       if (current == NULL) {
+               printf("No devices found.\n");
+       } else {
+               udev_list_entry_foreach (current, current) {
+                       dev = udev_list_entry_get_device(current);
+                       if (dev == NULL)
+                               continue;
+                       dict = udev_device_get_dictionary(dev);
+                       if (dict == NULL)
+                               continue;
+                       iter = prop_dictionary_iterator(dict);
+                       cur_key = NULL;
+
+                       dev_name = prop_string_cstring(prop_dictionary_get(dict, "name"));
+                       printf("Device %s:\n", dev_name);
+                       free(dev_name);
+
+                       if (!SLIST_EMPTY(&props)) {
+                               SLIST_FOREACH(ent, &props, entries) {
+                                       key_val = prop_dictionary_get(dict, ent->val);
+                                       if (key_val != NULL)
+                                               print_prop(ent->val, key_val);
+                               }
+                       } else {
+                               while ((cur_key = (prop_dictionary_keysym_t) prop_object_iterator_next(iter)) != NULL) {
+                                       key_str = prop_dictionary_keysym_cstring_nocopy(cur_key);
+                                       key_val = prop_dictionary_get_keysym(dict, cur_key);
+                                       print_prop(key_str, key_val);
+                               }
+                       }
+
+                       printf("\n");
+               }
+       }
+
+       udev_enumerate_unref(enumerate);
+       udev_unref(ctx);
+
+       return (0);
+}