From e2427cb71d758d85128a956fc2088a99b7af5cc3 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sun, 17 Jun 2007 07:35:12 +0000 Subject: [PATCH] Add two new UUID helper functions to libc, uuid_name_lookup() and uuid_addr_lookup(). These functions convert UUIDs to and from symbolic names via the files /etc/uuids and /etc/uuids.local. --- include/uuid.h | 6 +- lib/libc/uuid/Makefile.inc | 5 +- lib/libc/uuid/uuid.3 | 37 ++++- lib/libc/uuid/uuid_name_lookup.c | 230 +++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+), 4 deletions(-) create mode 100644 lib/libc/uuid/uuid_name_lookup.c diff --git a/include/uuid.h b/include/uuid.h index bbaefa94f9..82ac069040 100644 --- a/include/uuid.h +++ b/include/uuid.h @@ -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_ */ diff --git a/lib/libc/uuid/Makefile.inc b/lib/libc/uuid/Makefile.inc index bbd924507b..109d13e293 100644 --- a/lib/libc/uuid/Makefile.inc +++ b/lib/libc/uuid/Makefile.inc @@ -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 diff --git a/lib/libc/uuid/uuid.3 b/lib/libc/uuid/uuid.3 index d0039da2cf..ebb843169a 100644 --- a/lib/libc/uuid/uuid.3 +++ b/lib/libc/uuid/uuid.3 @@ -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 @@ -53,6 +53,10 @@ .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 index 0000000000..9056eadcd5 --- /dev/null +++ b/lib/libc/uuid/uuid_name_lookup.c @@ -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 + * + * 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 +#include +#include +#include +#include +#include + +/* + * 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); +} + + -- 2.41.0