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.4 2007/06/17 07:56:58 dillon 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 47 /* 48 * Implement a Red-Black tree to cache the UUID table and perform lookups 49 */ 50 struct uuid_rbnode { 51 RB_ENTRY(uuid_rbnode) unode; 52 RB_ENTRY(uuid_rbnode) nnode; 53 struct uuid uuid; 54 char *name; 55 }; 56 57 static void uuid_loadcache(const char *path); 58 59 static int uuid_name_loaded; 60 61 RB_HEAD(uuid_urbtree, uuid_rbnode); 62 RB_STATIC_PROTOTYPE(uuid_urbtree, uuid_rbnode, unode, uuid_urbcmp); 63 static struct uuid_urbtree uuid_urbroot = RB_INITIALIZER(uuid_urbroot); 64 65 RB_HEAD(uuid_nrbtree, uuid_rbnode); 66 RB_STATIC_PROTOTYPE(uuid_nrbtree, uuid_rbnode, nnode, uuid_nrbcmp); 67 static struct uuid_nrbtree uuid_nrbroot = RB_INITIALIZER(uuid_nrbroot); 68 69 static int 70 uuid_urbcmp(struct uuid_rbnode *n1, struct uuid_rbnode *n2) 71 { 72 return(uuid_compare(&n1->uuid, &n2->uuid, NULL)); 73 } 74 75 static int 76 uuid_nrbcmp(struct uuid_rbnode *n1, struct uuid_rbnode *n2) 77 { 78 return(strcasecmp(n1->name, n2->name)); 79 } 80 81 static int 82 uuid_rbnamecmp(const char *name, struct uuid_rbnode *node) 83 { 84 return (strcasecmp(name, node->name)); 85 } 86 87 static int 88 uuid_rbuuidcmp(const struct uuid *uuid, struct uuid_rbnode *node) 89 { 90 return(uuid_compare(uuid, &node->uuid, NULL)); 91 } 92 93 RB_STATIC_GENERATE(uuid_urbtree, uuid_rbnode, unode, uuid_urbcmp) 94 RB_STATIC_GENERATE(uuid_nrbtree, uuid_rbnode, nnode, uuid_nrbcmp) 95 RB_STATIC_GENERATE_XLOOKUP(uuid_urbtree, UUID, uuid_rbnode, unode, 96 uuid_rbuuidcmp, const struct uuid *) 97 RB_STATIC_GENERATE_XLOOKUP(uuid_nrbtree, NAME, uuid_rbnode, nnode, 98 uuid_rbnamecmp, const char *) 99 100 101 /* 102 * Look up a UUID by its address. Returns 0 on success or an error 103 */ 104 void 105 uuid_addr_lookup(const uuid_t *u, char **strp, uint32_t *status) 106 { 107 struct uuid_rbnode *node; 108 109 if (*strp) { 110 free(*strp); 111 *strp = NULL; 112 } 113 if (u) { 114 if (uuid_name_loaded == 0) { 115 /* 116 * /etc/uuids will override /etc/defaults/uuids 117 */ 118 uuid_loadcache("/etc/uuids"); 119 uuid_loadcache("/etc/defaults/uuids"); 120 uuid_name_loaded = 1; 121 } 122 node = uuid_urbtree_RB_LOOKUP_UUID(&uuid_urbroot, u); 123 if (node) { 124 *strp = strdup(node->name); 125 if (status) 126 *status = uuid_s_ok; 127 return; 128 } 129 } 130 if (status) 131 *status = uuid_s_not_found; 132 } 133 134 /* 135 * Look up a UUID by its name. Returns 0 on success or an error. 136 */ 137 void 138 uuid_name_lookup(uuid_t *u, const char *name, uint32_t *status) 139 { 140 struct uuid_rbnode *node; 141 142 if (name) { 143 if (uuid_name_loaded == 0) { 144 uuid_loadcache("/etc/uuids"); 145 uuid_loadcache("/etc/defaults/uuids"); 146 uuid_name_loaded = 1; 147 } 148 node = uuid_nrbtree_RB_LOOKUP_NAME(&uuid_nrbroot, name); 149 if (node) { 150 if (u) 151 *u = node->uuid; 152 if (status) 153 *status = uuid_s_ok; 154 return; 155 } 156 } 157 if (u) 158 bzero(u, sizeof(*u)); 159 if (status) 160 *status = uuid_s_not_found; 161 } 162 163 /* 164 * Clear out the lookup cache. The next lookup will reload the database 165 * or re-query or whatever. 166 */ 167 static 168 int 169 uuid_freenode(struct uuid_rbnode *node, void *arg __unused) 170 { 171 uuid_urbtree_RB_REMOVE(&uuid_urbroot, node); 172 uuid_nrbtree_RB_REMOVE(&uuid_nrbroot, node); 173 free(node->name); 174 free(node); 175 } 176 177 void 178 uuid_reset_lookup(void) 179 { 180 uuid_urbtree_RB_SCAN(&uuid_urbroot, NULL, uuid_freenode, NULL); 181 uuid_name_loaded = 0; 182 } 183 184 static 185 void 186 uuid_loadcache(const char *path) 187 { 188 struct uuid_rbnode *node; 189 uint32_t status; 190 FILE *fp; 191 char *line; 192 char *uuid; 193 char *name; 194 char *last; 195 size_t len; 196 197 if ((fp = fopen(path, "r")) == NULL) 198 return; 199 while ((line = fgetln(fp, &len)) != NULL) { 200 if (len == 0 || *line == '#') 201 continue; 202 line[len-1] = 0; 203 uuid = strtok_r(line, " \t\r", &last); 204 if (uuid == NULL) 205 continue; 206 name = strtok_r(NULL, "", &last); 207 name = strchr(name, '"'); 208 if (name == NULL) 209 continue; 210 *name++ = 0; 211 if (strchr(name, '"') == NULL) 212 continue; 213 *strchr(name, '"') = 0; 214 node = malloc(sizeof(*node)); 215 node->name = strdup(name); 216 uuid_from_string(uuid, &node->uuid, &status); 217 if (status == 0) { 218 if (uuid_urbtree_RB_FIND(&uuid_urbroot, node) || 219 uuid_nrbtree_RB_FIND(&uuid_nrbroot, node)) 220 status = 1; 221 } 222 if (status == 0) { 223 uuid_urbtree_RB_INSERT(&uuid_urbroot, node); 224 uuid_nrbtree_RB_INSERT(&uuid_nrbroot, node); 225 } else { 226 free(node); 227 free(node->name); 228 } 229 } 230 fclose(fp); 231 } 232 233 234