Add two new UUID helper functions to libc, uuid_name_lookup() and
authorMatthew Dillon <dillon@dragonflybsd.org>
Sun, 17 Jun 2007 07:35:12 +0000 (07:35 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sun, 17 Jun 2007 07:35:12 +0000 (07:35 +0000)
uuid_addr_lookup().  These functions convert UUIDs to and from symbolic
names via the files /etc/uuids and /etc/uuids.local.

include/uuid.h
lib/libc/uuid/Makefile.inc
lib/libc/uuid/uuid.3
lib/libc/uuid/uuid_name_lookup.c [new file with mode: 0644]

index bbaefa9..82ac069 100644 (file)
@@ -25,7 +25,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/include/uuid.h,v 1.3 2005/01/03 02:56:15 marcel Exp $
- * $DragonFly: src/include/uuid.h,v 1.1 2007/06/16 19:57:11 dillon Exp $
+ * $DragonFly: src/include/uuid.h,v 1.2 2007/06/17 07:35:10 dillon Exp $
  */
 
 #ifndef _UUID_H_
@@ -45,6 +45,7 @@
 #define        uuid_s_bad_version              1
 #define        uuid_s_invalid_string_uuid      2
 #define        uuid_s_no_memory                3
+#define uuid_s_not_found               4
 
 __BEGIN_DECLS
 int32_t        uuid_compare(const uuid_t *, const uuid_t *, uint32_t *);
@@ -55,6 +56,9 @@ void  uuid_from_string(const char *, uuid_t *, uint32_t *);
 uint16_t uuid_hash(const uuid_t *, uint32_t *);
 int32_t        uuid_is_nil(const uuid_t *, uint32_t *);
 void   uuid_to_string(const uuid_t *, char **, uint32_t *);
+void    uuid_reset_lookup(void);
+void   uuid_addr_lookup(const uuid_t *, char **, uint32_t *);
+void   uuid_name_lookup(uuid_t *, const char *, uint32_t *);
 __END_DECLS
 
 #endif /* _UUID_H_ */
index bbd9245..109d13e 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/lib/libc/uuid/Makefile.inc,v 1.4 2006/03/13 01:15:01 deischen Exp $
-# $DragonFly: src/lib/libc/uuid/Makefile.inc,v 1.2 2007/06/16 20:43:47 dillon Exp $
+# $DragonFly: src/lib/libc/uuid/Makefile.inc,v 1.3 2007/06/17 07:35:12 dillon Exp $
 
 # DCE 1.1 UUID implementation sources
 
@@ -7,7 +7,8 @@
 .PATH: ${.CURDIR}/../libc/uuid
 
 SRCS+= uuid_compare.c uuid_create.c uuid_create_nil.c uuid_equal.c \
-       uuid_from_string.c uuid_hash.c uuid_is_nil.c uuid_to_string.c
+       uuid_from_string.c uuid_hash.c uuid_is_nil.c uuid_to_string.c \
+       uuid_name_lookup.c
 SYM_MAPS+=     ${.CURDIR}/uuid/Symbol.map
 
 MAN+=  uuid.3
index d0039da..ebb8431 100644 (file)
@@ -24,7 +24,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\" $FreeBSD: src/lib/libc/uuid/uuid.3,v 1.6 2005/11/24 07:04:20 ru Exp $
-.\" $DragonFly: src/lib/libc/uuid/uuid.3,v 1.1 2007/06/16 19:57:14 dillon Exp $
+.\" $DragonFly: src/lib/libc/uuid/uuid.3,v 1.2 2007/06/17 07:35:12 dillon Exp $
 .\"
 .Dd January 3, 2005
 .Dt UUID 3
 .Fn uuid_is_nil "const uuid_t *uuid" "uint32_t *status"
 .Ft void
 .Fn uuid_to_string "const uuid_t *uuid" "char **str" "uint32_t *status"
+.Ft void
+.Fn uuid_addr_lookup "const uuid_t *u" "char **strp" "uint32_t *status"
+.Ft void
+.Fn uuid_name_lookup "uuid_t *u" "const char *str" "uint32_t *status"
 .Sh DESCRIPTION
 The family of DCE 1.1 compliant UUID functions allow applications to operate
 on universally unique identifiers, or UUIDs.
@@ -75,6 +79,37 @@ or
 respectively.
 A 16-bit hash value can be obtained by calling
 .Fn uuid_hash .
+.Pp
+String equivalents to UUIDs may be available.  The
+.Fn uuid_addr_lookup
+function will lookup the symbolic name given a UUID.
+The variable *strp should be initialized to NULL.
+Successive calls to
+.Fn uuid_addr_lookup
+will free the previous contents prior to doing the lookup.  The last
+string may be freed by calling the function with a NULL UUID.
+If a lookup fails, *strp will be set to NULL and *status
+(if status is not NULL) will be set to uuid_s_not_found.  Otherwise
+*strp will be assigned to the symbolic name and *status will be
+set to uuid_s_ok.
+.Pp
+The
+.Fn uuid_name_lookup
+function will lookup a UUID given a symbolic name.
+The contents of the uuid will be zerod out if a lookup fails.
+.Pp
+The
+.Fn uuid_reset_lookup
+function will clear its in-memory cache of UUID<->NAME conversions.  The
+next lookup will reload the cache.
+.Sh FILES
+.TP 3n
+\fI/etc/uuids\fR
+A list of UUIDs and their symbolic names provided by the OS vendor
+.Pp
+.TP 3n
+\fI/etc/uuids.local\fR
+A list of UUIDs and their symbolic names provided by the system administrator
 .Sh RETURN VALUES
 The successful or unsuccessful completion of the function is returned in
 the
diff --git a/lib/libc/uuid/uuid_name_lookup.c b/lib/libc/uuid/uuid_name_lookup.c
new file mode 100644 (file)
index 0000000..9056ead
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
+ * 
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.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.
+ * 
+ * $DragonFly: src/lib/libc/uuid/uuid_name_lookup.c,v 1.1 2007/06/17 07:35:12 dillon Exp $
+ */
+/*
+ * Implement UUID-to-NAME and NAME-to-UUID functions
+ */
+
+#include <sys/types.h>
+#include <sys/tree.h>
+#include <uuid.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * Implement a Red-Black tree to cache the UUID table and perform lookups
+ */
+struct uuid_rbnode {
+       RB_ENTRY(uuid_rbnode) unode;
+       RB_ENTRY(uuid_rbnode) nnode;
+       struct uuid uuid;
+       char *name;
+};
+
+static void uuid_loadcache(const char *path);
+
+static int uuid_name_loaded;
+
+RB_HEAD(uuid_urbtree, uuid_rbnode);
+RB_STATIC_PROTOTYPE(uuid_urbtree, uuid_rbnode, unode, uuid_urbcmp);
+static struct uuid_urbtree uuid_urbroot = RB_INITIALIZER(uuid_urbroot);
+
+RB_HEAD(uuid_nrbtree, uuid_rbnode);
+RB_STATIC_PROTOTYPE(uuid_nrbtree, uuid_rbnode, nnode, uuid_nrbcmp);
+static struct uuid_nrbtree uuid_nrbroot = RB_INITIALIZER(uuid_nrbroot);
+
+static int
+uuid_urbcmp(struct uuid_rbnode *n1, struct uuid_rbnode *n2)
+{
+       return(uuid_compare(&n1->uuid, &n2->uuid, NULL));
+}
+
+static int
+uuid_nrbcmp(struct uuid_rbnode *n1, struct uuid_rbnode *n2)
+{
+       return(strcasecmp(n1->name, n2->name));
+}
+
+static int
+uuid_rbnamecmp(const char *name, struct uuid_rbnode *node)
+{
+       return (strcasecmp(name, node->name));
+}
+
+static int
+uuid_rbuuidcmp(const struct uuid *uuid, struct uuid_rbnode *node)
+{
+       return(uuid_compare(uuid, &node->uuid, NULL));
+}
+
+RB_STATIC_GENERATE(uuid_urbtree, uuid_rbnode, unode, uuid_urbcmp)
+RB_STATIC_GENERATE(uuid_nrbtree, uuid_rbnode, nnode, uuid_nrbcmp)
+RB_STATIC_GENERATE_XLOOKUP(uuid_urbtree, UUID, uuid_rbnode, unode,
+                          uuid_rbuuidcmp, const struct uuid *)
+RB_STATIC_GENERATE_XLOOKUP(uuid_nrbtree, NAME, uuid_rbnode, nnode,
+                          uuid_rbnamecmp, const char *)
+               
+
+/*
+ * Look up a UUID by its address.  Returns 0 on success or an error
+ */
+void
+uuid_addr_lookup(const uuid_t *u, char **strp, uint32_t *status)
+{
+       struct uuid_rbnode *node;
+
+       if (*strp) {
+               free(*strp);
+               *strp = NULL;
+       }
+       if (u) {
+               if (uuid_name_loaded == 0) {
+                       uuid_loadcache("/etc/uuids");
+                       uuid_loadcache("/etc/uuids.local");
+                       uuid_name_loaded = 1;
+               }
+               node = uuid_urbtree_RB_LOOKUP_UUID(&uuid_urbroot, u);
+               if (node) {
+                       *strp = strdup(node->name);
+                       if (status)
+                               *status = uuid_s_ok;
+                       return;
+               }
+       }
+       if (status)
+               *status = uuid_s_not_found;
+}
+
+/*
+ * Look up a UUID by its name.  Returns 0 on success or an error.
+ */
+void
+uuid_name_lookup(uuid_t *u, const char *name, uint32_t *status)
+{
+       struct uuid_rbnode *node;
+
+       if (name) {
+               if (uuid_name_loaded == 0) {
+                       uuid_loadcache("/etc/uuids");
+                       uuid_loadcache("/etc/uuids.local");
+                       uuid_name_loaded = 1;
+               }
+               node = uuid_nrbtree_RB_LOOKUP_NAME(&uuid_nrbroot, name);
+               if (node) {
+                       if (u)
+                               *u = node->uuid;
+                       if (status)
+                               *status = uuid_s_ok;
+                       return;
+               }
+       }
+       if (u)
+               bzero(u, sizeof(*u));
+       if (status)
+               *status = uuid_s_not_found;
+}
+
+/*
+ * Clear out the lookup cache.  The next lookup will reload the database
+ * or re-query or whatever.
+ */
+static
+int
+uuid_freenode(struct uuid_rbnode *node, void *arg __unused)
+{
+       uuid_urbtree_RB_REMOVE(&uuid_urbroot, node);
+       uuid_nrbtree_RB_REMOVE(&uuid_nrbroot, node);
+       free(node->name);
+       free(node);
+}
+
+void
+uuid_reset_lookup(void)
+{
+       uuid_urbtree_RB_SCAN(&uuid_urbroot, NULL, uuid_freenode, NULL);
+       uuid_name_loaded = 0;
+}
+
+static
+void
+uuid_loadcache(const char *path)
+{
+       struct uuid_rbnode *node;
+       uint32_t status;
+       FILE *fp;
+       char *line;
+       char *uuid;
+       char *name;
+       char *last;
+       size_t len;
+
+       if ((fp = fopen(path, "r")) == NULL)
+               return;
+       while ((line = fgetln(fp, &len)) != NULL) {
+               if (len == 0)
+                       continue;
+               line[len-1] = 0;
+               uuid = strtok_r(line, " \t\r", &last);
+               if (uuid == NULL)
+                       continue;
+               name = strtok_r(NULL, "", &last);
+               name = strchr(name, '"');
+               if (name == NULL)
+                       continue;
+               *name++ = 0;
+               if (strchr(name, '"') == NULL)
+                       continue;
+               *strchr(name, '"') = 0;
+               node = malloc(sizeof(*node));
+               node->name = strdup(name);
+               uuid_from_string(uuid, &node->uuid, &status);
+               if (status == 0) {
+                       if (uuid_urbtree_RB_FIND(&uuid_urbroot, node) ||
+                           uuid_nrbtree_RB_FIND(&uuid_nrbroot, node))
+                               status = 1;
+               }
+               if (status == 0) {
+                       uuid_urbtree_RB_INSERT(&uuid_urbroot, node);
+                       uuid_nrbtree_RB_INSERT(&uuid_nrbroot, node);
+               } else {
+                       free(node);
+                       free(node->name);
+               }
+       }
+       fclose(fp);
+}
+
+