Home | History | Annotate | Line # | Download | only in uuid
      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