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