xref: /dragonfly/contrib/lvm2/dist/lib/uuid/uuid.c (revision d4ef6694)
1 /*	$NetBSD: uuid.c,v 1.1.1.3 2009/12/02 00:26:49 haad Exp $	*/
2 
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
6  *
7  * This file is part of LVM2.
8  *
9  * This copyrighted material is made available to anyone wishing to use,
10  * modify, copy, or redistribute it subject to the terms and conditions
11  * of the GNU Lesser General Public License v.2.1.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 
18 #include "lib.h"
19 #include "uuid.h"
20 #include "lvm-wrappers.h"
21 
22 #include <assert.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <ctype.h>
27 
28 static const char _c[] =
29     "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#";
30 
31 static int _built_inverse;
32 static char _inverse_c[256];
33 
34 int lvid_create(union lvid *lvid, struct id *vgid)
35 {
36 	memcpy(lvid->id, vgid, sizeof(*lvid->id));
37 	return id_create(&lvid->id[1]);
38 }
39 
40 void uuid_from_num(char *uuid, uint32_t num)
41 {
42 	unsigned i;
43 
44 	for (i = ID_LEN; i; i--) {
45 		uuid[i - 1] = _c[num % (sizeof(_c) - 1)];
46 		num /= sizeof(_c) - 1;
47 	}
48 }
49 
50 int lvid_from_lvnum(union lvid *lvid, struct id *vgid, uint32_t lv_num)
51 {
52 	int i;
53 
54 	memcpy(lvid->id, vgid, sizeof(*lvid->id));
55 
56 	for (i = ID_LEN; i; i--) {
57 		lvid->id[1].uuid[i - 1] = _c[lv_num % (sizeof(_c) - 1)];
58 		lv_num /= sizeof(_c) - 1;
59 	}
60 
61 	lvid->s[sizeof(lvid->s) - 1] = '\0';
62 
63 	return 1;
64 }
65 
66 int lvnum_from_lvid(union lvid *lvid)
67 {
68 	int i, lv_num = 0;
69 	char *c;
70 
71 	for (i = 0; i < ID_LEN; i++) {
72 		lv_num *= sizeof(_c) - 1;
73 		if ((c = strchr(_c, lvid->id[1].uuid[i])))
74 			lv_num += (int) (c - _c);
75 		if (lv_num < 0)
76 			lv_num = 0;
77 	}
78 
79 	return lv_num;
80 }
81 
82 int lvid_in_restricted_range(union lvid *lvid)
83 {
84 	int i;
85 
86 	for (i = 0; i < ID_LEN - 3; i++)
87 		if (lvid->id[1].uuid[i] != '0')
88 			return 0;
89 
90 	for (i = ID_LEN - 3; i < ID_LEN; i++)
91 		if (!isdigit(lvid->id[1].uuid[i]))
92 			return 0;
93 
94 	return 1;
95 }
96 
97 
98 int id_create(struct id *id)
99 {
100 	unsigned i;
101 	size_t len = sizeof(id->uuid);
102 
103 	memset(id->uuid, 0, len);
104 	if (!read_urandom(&id->uuid, len)) {
105 		return 0;
106 	}
107 
108 	/*
109 	 * Skip out the last 2 chars in randomized creation for LVM1
110 	 * backwards compatibility.
111 	 */
112 	for (i = 0; i < len; i++)
113 		id->uuid[i] = _c[id->uuid[i] % (sizeof(_c) - 3)];
114 
115 	return 1;
116 }
117 
118 /*
119  * The only validity check we have is that
120  * the uuid just contains characters from
121  * '_c'.  A checksum would have been nice :(
122  */
123 static void _build_inverse(void)
124 {
125 	const char *ptr;
126 
127 	if (_built_inverse)
128 		return;
129 
130 	memset(_inverse_c, 0, sizeof(_inverse_c));
131 
132 	for (ptr = _c; *ptr; ptr++)
133 		_inverse_c[(int) *ptr] = (char) 0x1;
134 }
135 
136 int id_valid(struct id *id)
137 {
138 	int i;
139 
140 	_build_inverse();
141 
142 	for (i = 0; i < ID_LEN; i++)
143 		if (!_inverse_c[id->uuid[i]]) {
144 			log_error("UUID contains invalid character");
145 			return 0;
146 		}
147 
148 	return 1;
149 }
150 
151 int id_equal(const struct id *lhs, const struct id *rhs)
152 {
153 	return !memcmp(lhs->uuid, rhs->uuid, sizeof(lhs->uuid));
154 }
155 
156 #define GROUPS (ID_LEN / 4)
157 
158 int id_write_format(const struct id *id, char *buffer, size_t size)
159 {
160 	int i, tot;
161 
162 	static unsigned group_size[] = { 6, 4, 4, 4, 4, 4, 6 };
163 
164 	assert(ID_LEN == 32);
165 
166 	/* split into groups separated by dashes */
167 	if (size < (32 + 6 + 1)) {
168 		log_error("Couldn't write uuid, buffer too small.");
169 		return 0;
170 	}
171 
172 	for (i = 0, tot = 0; i < 7; i++) {
173 		memcpy(buffer, id->uuid + tot, group_size[i]);
174 		buffer += group_size[i];
175 		tot += group_size[i];
176 		*buffer++ = '-';
177 	}
178 
179 	*--buffer = '\0';
180 	return 1;
181 }
182 
183 int id_read_format(struct id *id, const char *buffer)
184 {
185 	int out = 0;
186 
187 	/* just strip out any dashes */
188 	while (*buffer) {
189 
190 		if (*buffer == '-') {
191 			buffer++;
192 			continue;
193 		}
194 
195 		if (out >= ID_LEN) {
196 			log_error("Too many characters to be uuid.");
197 			return 0;
198 		}
199 
200 		id->uuid[out++] = *buffer++;
201 	}
202 
203 	if (out != ID_LEN) {
204 		log_error("Couldn't read uuid: incorrect number of "
205 			  "characters.");
206 		return 0;
207 	}
208 
209 	return id_valid(id);
210 }
211