#include <sys/types.h>
#include <sys/tree.h>
#include <uuid.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct uuid_rbnode {
RB_ENTRY(uuid_rbnode) unode;
RB_ENTRY(uuid_rbnode) nnode;
struct uuid uuid;
char *name;
};
static void uuid_loadcache(const char *path);
static int uuid_name_loaded;
RB_HEAD(uuid_urbtree, uuid_rbnode);
RB_PROTOTYPE_STATIC(uuid_urbtree, uuid_rbnode, unode, uuid_urbcmp);
static struct uuid_urbtree uuid_urbroot = RB_INITIALIZER(uuid_urbroot);
RB_HEAD(uuid_nrbtree, uuid_rbnode);
RB_PROTOTYPE_STATIC(uuid_nrbtree, uuid_rbnode, nnode, uuid_nrbcmp);
static struct uuid_nrbtree uuid_nrbroot = RB_INITIALIZER(uuid_nrbroot);
static int
uuid_urbcmp(struct uuid_rbnode *n1, struct uuid_rbnode *n2)
{
return(uuid_compare(&n1->uuid, &n2->uuid, NULL));
}
static int
uuid_nrbcmp(struct uuid_rbnode *n1, struct uuid_rbnode *n2)
{
return(strcasecmp(n1->name, n2->name));
}
static int
uuid_rbnamecmp(const char *name, struct uuid_rbnode *node)
{
return (strcasecmp(name, node->name));
}
static int
uuid_rbuuidcmp(const struct uuid *uuid, struct uuid_rbnode *node)
{
return(uuid_compare(uuid, &node->uuid, NULL));
}
RB_GENERATE_STATIC(uuid_urbtree, uuid_rbnode, unode, uuid_urbcmp)
RB_GENERATE_STATIC(uuid_nrbtree, uuid_rbnode, nnode, uuid_nrbcmp)
RB_GENERATE_XLOOKUP_STATIC(uuid_urbtree, UUID, uuid_rbnode, unode,
uuid_rbuuidcmp, const struct uuid *)
RB_GENERATE_XLOOKUP_STATIC(uuid_nrbtree, NAME, uuid_rbnode, nnode,
uuid_rbnamecmp, const char *)
void
uuid_addr_lookup(const uuid_t *u, char **strp, uint32_t *status)
{
struct uuid_rbnode *node;
if (*strp) {
free(*strp);
*strp = NULL;
}
if (u) {
if (uuid_name_loaded == 0) {
uuid_loadcache("/etc/uuids");
uuid_loadcache("/etc/defaults/uuids");
uuid_name_loaded = 1;
}
node = uuid_urbtree_RB_LOOKUP_UUID(&uuid_urbroot, u);
if (node) {
*strp = strdup(node->name);
if (status)
*status = uuid_s_ok;
return;
}
}
if (status)
*status = uuid_s_not_found;
}
void
uuid_name_lookup(uuid_t *u, const char *name, uint32_t *status)
{
struct uuid_rbnode *node;
if (name) {
if (uuid_name_loaded == 0) {
uuid_loadcache("/etc/uuids");
uuid_loadcache("/etc/defaults/uuids");
uuid_name_loaded = 1;
}
node = uuid_nrbtree_RB_LOOKUP_NAME(&uuid_nrbroot, name);
if (node) {
if (u)
*u = node->uuid;
if (status)
*status = uuid_s_ok;
return;
}
}
if (u)
bzero(u, sizeof(*u));
if (status)
*status = uuid_s_not_found;
}
static
int
uuid_freenode(struct uuid_rbnode *node, void *arg __unused)
{
uuid_urbtree_RB_REMOVE(&uuid_urbroot, node);
uuid_nrbtree_RB_REMOVE(&uuid_nrbroot, node);
free(node->name);
free(node);
return (0);
}
void
uuid_reset_lookup(void)
{
uuid_urbtree_RB_SCAN(&uuid_urbroot, NULL, uuid_freenode, NULL);
uuid_name_loaded = 0;
}
static
void
uuid_loadcache(const char *path)
{
struct uuid_rbnode *node;
uint32_t status;
FILE *fp;
char *line;
char *uuid;
char *name;
char *last;
size_t len;
if ((fp = fopen(path, "r")) == NULL)
return;
while ((line = fgetln(fp, &len)) != NULL) {
if (len == 0 || *line == '#')
continue;
line[len-1] = 0;
uuid = strtok_r(line, " \t\r", &last);
if (uuid == NULL)
continue;
name = strtok_r(NULL, "", &last);
name = strchr(name, '"');
if (name == NULL)
continue;
*name++ = 0;
if (strchr(name, '"') == NULL)
continue;
*strchr(name, '"') = 0;
node = malloc(sizeof(*node));
node->name = strdup(name);
uuid_from_string(uuid, &node->uuid, &status);
if (status == 0) {
if (uuid_urbtree_RB_FIND(&uuid_urbroot, node) ||
uuid_nrbtree_RB_FIND(&uuid_nrbroot, node))
status = 1;
}
if (status == 0) {
uuid_urbtree_RB_INSERT(&uuid_urbroot, node);
uuid_nrbtree_RB_INSERT(&uuid_nrbroot, node);
} else {
free(node->name);
free(node);
}
}
fclose(fp);
}