1 /* 2 * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/lib/libc/uuid/uuid_name_lookup.c,v 1.6 2008/01/07 01:22:30 corecode Exp $ 35 */ 36 /* 37 * Implement UUID-to-NAME and NAME-to-UUID functions 38 */ 39 40 #include <sys/types.h> 41 #include <sys/tree.h> 42 #include <uuid.h> 43 #include <errno.h> 44 #include <string.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 48 /* 49 * Implement a Red-Black tree to cache the UUID table and perform lookups 50 */ 51 struct uuid_rbnode { 52 RB_ENTRY(uuid_rbnode) unode; 53 RB_ENTRY(uuid_rbnode) nnode; 54 struct uuid uuid; 55 char *name; 56 }; 57 58 static void uuid_loadcache(const char *path); 59 60 static int uuid_name_loaded; 61 62 RB_HEAD(uuid_urbtree, uuid_rbnode); 63 RB_PROTOTYPE_STATIC(uuid_urbtree, uuid_rbnode, unode, uuid_urbcmp); 64 static struct uuid_urbtree uuid_urbroot = RB_INITIALIZER(uuid_urbroot); 65 66 RB_HEAD(uuid_nrbtree, uuid_rbnode); 67 RB_PROTOTYPE_STATIC(uuid_nrbtree, uuid_rbnode, nnode, uuid_nrbcmp); 68 static struct uuid_nrbtree uuid_nrbroot = RB_INITIALIZER(uuid_nrbroot); 69 70 static int 71 uuid_urbcmp(struct uuid_rbnode *n1, struct uuid_rbnode *n2) 72 { 73 return(uuid_compare(&n1->uuid, &n2->uuid, NULL)); 74 } 75 76 static int 77 uuid_nrbcmp(struct uuid_rbnode *n1, struct uuid_rbnode *n2) 78 { 79 return(strcasecmp(n1->name, n2->name)); 80 } 81 82 static int 83 uuid_rbnamecmp(const char *name, struct uuid_rbnode *node) 84 { 85 return (strcasecmp(name, node->name)); 86 } 87 88 static int 89 uuid_rbuuidcmp(const struct uuid *uuid, struct uuid_rbnode *node) 90 { 91 return(uuid_compare(uuid, &node->uuid, NULL)); 92 } 93 94 RB_GENERATE_STATIC(uuid_urbtree, uuid_rbnode, unode, uuid_urbcmp) 95 RB_GENERATE_STATIC(uuid_nrbtree, uuid_rbnode, nnode, uuid_nrbcmp) 96 RB_GENERATE_XLOOKUP_STATIC(uuid_urbtree, UUID, uuid_rbnode, unode, 97 uuid_rbuuidcmp, const struct uuid *) 98 RB_GENERATE_XLOOKUP_STATIC(uuid_nrbtree, NAME, uuid_rbnode, nnode, 99 uuid_rbnamecmp, const char *) 100 101 102 /* 103 * Look up a UUID by its address. Returns 0 on success or an error 104 */ 105 void 106 uuid_addr_lookup(const uuid_t *u, char **strp, uint32_t *status) 107 { 108 struct uuid_rbnode *node; 109 110 if (*strp) { 111 free(*strp); 112 *strp = NULL; 113 } 114 if (u) { 115 if (uuid_name_loaded == 0) { 116 /* 117 * /etc/uuids will override /etc/defaults/uuids 118 */ 119 uuid_loadcache("/etc/uuids"); 120 uuid_loadcache("/etc/defaults/uuids"); 121 uuid_name_loaded = 1; 122 } 123 node = uuid_urbtree_RB_LOOKUP_UUID(&uuid_urbroot, u); 124 if (node) { 125 *strp = strdup(node->name); 126 if (status) 127 *status = uuid_s_ok; 128 return; 129 } 130 } 131 if (status) 132 *status = uuid_s_not_found; 133 } 134 135 /* 136 * Look up a UUID by its name. Returns 0 on success or an error. 137 */ 138 void 139 uuid_name_lookup(uuid_t *u, const char *name, uint32_t *status) 140 { 141 struct uuid_rbnode *node; 142 143 if (name) { 144 if (uuid_name_loaded == 0) { 145 uuid_loadcache("/etc/uuids"); 146 uuid_loadcache("/etc/defaults/uuids"); 147 uuid_name_loaded = 1; 148 } 149 node = uuid_nrbtree_RB_LOOKUP_NAME(&uuid_nrbroot, name); 150 if (node) { 151 if (u) 152 *u = node->uuid; 153 if (status) 154 *status = uuid_s_ok; 155 return; 156 } 157 } 158 if (u) 159 bzero(u, sizeof(*u)); 160 if (status) 161 *status = uuid_s_not_found; 162 } 163 164 /* 165 * Clear out the lookup cache. The next lookup will reload the database 166 * or re-query or whatever. 167 */ 168 static 169 int 170 uuid_freenode(struct uuid_rbnode *node, void *arg __unused) 171 { 172 uuid_urbtree_RB_REMOVE(&uuid_urbroot, node); 173 uuid_nrbtree_RB_REMOVE(&uuid_nrbroot, node); 174 free(node->name); 175 free(node); 176 } 177 178 void 179 uuid_reset_lookup(void) 180 { 181 uuid_urbtree_RB_SCAN(&uuid_urbroot, NULL, uuid_freenode, NULL); 182 uuid_name_loaded = 0; 183 } 184 185 static 186 void 187 uuid_loadcache(const char *path) 188 { 189 struct uuid_rbnode *node; 190 uint32_t status; 191 FILE *fp; 192 char *line; 193 char *uuid; 194 char *name; 195 char *last; 196 size_t len; 197 198 if ((fp = fopen(path, "r")) == NULL) 199 return; 200 while ((line = fgetln(fp, &len)) != NULL) { 201 if (len == 0 || *line == '#') 202 continue; 203 line[len-1] = 0; 204 uuid = strtok_r(line, " \t\r", &last); 205 if (uuid == NULL) 206 continue; 207 name = strtok_r(NULL, "", &last); 208 name = strchr(name, '"'); 209 if (name == NULL) 210 continue; 211 *name++ = 0; 212 if (strchr(name, '"') == NULL) 213 continue; 214 *strchr(name, '"') = 0; 215 node = malloc(sizeof(*node)); 216 node->name = strdup(name); 217 uuid_from_string(uuid, &node->uuid, &status); 218 if (status == 0) { 219 if (uuid_urbtree_RB_FIND(&uuid_urbroot, node) || 220 uuid_nrbtree_RB_FIND(&uuid_nrbroot, node)) 221 status = 1; 222 } 223 if (status == 0) { 224 uuid_urbtree_RB_INSERT(&uuid_urbroot, node); 225 uuid_nrbtree_RB_INSERT(&uuid_nrbroot, node); 226 } else { 227 free(node); 228 free(node->name); 229 } 230 } 231 fclose(fp); 232 } 233 234 235