xref: /dragonfly/lib/libc/uuid/uuid_name_lookup.c (revision 68b2c890)
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