xref: /dragonfly/lib/libc/uuid/uuid_name_lookup.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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
uuid_urbcmp(struct uuid_rbnode * n1,struct uuid_rbnode * n2)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
uuid_nrbcmp(struct uuid_rbnode * n1,struct uuid_rbnode * n2)77 uuid_nrbcmp(struct uuid_rbnode *n1, struct uuid_rbnode *n2)
78 {
79           return(strcasecmp(n1->name, n2->name));
80 }
81 
82 static int
uuid_rbnamecmp(const char * name,struct uuid_rbnode * node)83 uuid_rbnamecmp(const char *name, struct uuid_rbnode *node)
84 {
85           return (strcasecmp(name, node->name));
86 }
87 
88 static int
uuid_rbuuidcmp(const struct uuid * uuid,struct uuid_rbnode * node)89 uuid_rbuuidcmp(const struct uuid *uuid, struct uuid_rbnode *node)
90 {
91           return(uuid_compare(uuid, &node->uuid, NULL));
92 }
93 
RB_GENERATE_STATIC(uuid_urbtree,uuid_rbnode,unode,uuid_urbcmp)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
uuid_name_lookup(uuid_t * u,const char * name,uint32_t * status)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
uuid_freenode(struct uuid_rbnode * node,void * arg __unused)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
uuid_reset_lookup(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
uuid_loadcache(const char * path)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