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