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 return (0); 177 } 178 179 void 180 uuid_reset_lookup(void) 181 { 182 uuid_urbtree_RB_SCAN(&uuid_urbroot, NULL, uuid_freenode, NULL); 183 uuid_name_loaded = 0; 184 } 185 186 static 187 void 188 uuid_loadcache(const char *path) 189 { 190 struct uuid_rbnode *node; 191 uint32_t status; 192 FILE *fp; 193 char *line; 194 char *uuid; 195 char *name; 196 char *last; 197 size_t len; 198 199 if ((fp = fopen(path, "r")) == NULL) 200 return; 201 while ((line = fgetln(fp, &len)) != NULL) { 202 if (len == 0 || *line == '#') 203 continue; 204 line[len-1] = 0; 205 uuid = strtok_r(line, " \t\r", &last); 206 if (uuid == NULL) 207 continue; 208 name = strtok_r(NULL, "", &last); 209 name = strchr(name, '"'); 210 if (name == NULL) 211 continue; 212 *name++ = 0; 213 if (strchr(name, '"') == NULL) 214 continue; 215 *strchr(name, '"') = 0; 216 node = malloc(sizeof(*node)); 217 node->name = strdup(name); 218 uuid_from_string(uuid, &node->uuid, &status); 219 if (status == 0) { 220 if (uuid_urbtree_RB_FIND(&uuid_urbroot, node) || 221 uuid_nrbtree_RB_FIND(&uuid_nrbroot, node)) 222 status = 1; 223 } 224 if (status == 0) { 225 uuid_urbtree_RB_INSERT(&uuid_urbroot, node); 226 uuid_nrbtree_RB_INSERT(&uuid_nrbroot, node); 227 } else { 228 free(node->name); 229 free(node); 230 } 231 } 232 fclose(fp); 233 } 234 235 236