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
lvid_create(union lvid * lvid,struct id * vgid)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
uuid_from_num(char * uuid,uint32_t num)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
lvid_from_lvnum(union lvid * lvid,struct id * vgid,uint32_t lv_num)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
lvnum_from_lvid(union lvid * lvid)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
lvid_in_restricted_range(union lvid * lvid)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
id_create(struct id * id)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 */
_build_inverse(void)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
id_valid(struct id * id)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
id_equal(const struct id * lhs,const struct id * rhs)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
id_write_format(const struct id * id,char * buffer,size_t size)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
id_read_format(struct id * id,const char * buffer)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