Home | History | Annotate | Download | only in uuid
      1 /*
      2  * gen_uuid.c --- generate a DCE-compatible uuid
      3  *
      4  * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
      5  *
      6  * %Begin-Header%
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, and the entire permission notice in its entirety,
     12  *    including the disclaimer of warranties.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. The name of the author may not be used to endorse or promote
     17  *    products derived from this software without specific prior
     18  *    written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
     21  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
     23  * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
     24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
     26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     27  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
     30  * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
     31  * DAMAGE.
     32  * %End-Header%
     33  */
     34 
     35 /*
     36  * Force inclusion of SVID stuff since we need it if we're compiling in
     37  * gcc-wall wall mode
     38  */
     39 #define _SVID_SOURCE
     40 
     41 #ifdef _WIN32
     42 #define _WIN32_WINNT 0x0500
     43 #include <windows.h>
     44 #define UUID MYUUID
     45 #endif
     46 #include <stdio.h>
     47 #ifdef HAVE_UNISTD_H
     48 #include <unistd.h>
     49 #endif
     50 #ifdef HAVE_STDLIB_H
     51 #include <stdlib.h>
     52 #endif
     53 #include <string.h>
     54 #include <fcntl.h>
     55 #include <errno.h>
     56 #include <sys/types.h>
     57 #ifdef HAVE_SYS_TIME_H
     58 #include <sys/time.h>
     59 #endif
     60 #include <sys/wait.h>
     61 #include <sys/stat.h>
     62 #ifdef HAVE_SYS_FILE_H
     63 #include <sys/file.h>
     64 #endif
     65 #ifdef HAVE_SYS_IOCTL_H
     66 #include <sys/ioctl.h>
     67 #endif
     68 #ifdef HAVE_SYS_SOCKET_H
     69 #include <sys/socket.h>
     70 #endif
     71 #ifdef HAVE_SYS_UN_H
     72 #include <sys/un.h>
     73 #endif
     74 #ifdef HAVE_SYS_SOCKIO_H
     75 #include <sys/sockio.h>
     76 #endif
     77 #ifdef HAVE_NET_IF_H
     78 #include <net/if.h>
     79 #endif
     80 #ifdef HAVE_NETINET_IN_H
     81 #include <netinet/in.h>
     82 #endif
     83 #ifdef HAVE_NET_IF_DL_H
     84 #include <net/if_dl.h>
     85 #endif
     86 #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
     87 #include <sys/syscall.h>
     88 #endif
     89 #ifdef HAVE_SYS_RESOURCE_H
     90 #include <sys/resource.h>
     91 #endif
     92 
     93 #include "uuidP.h"
     94 #include "uuidd.h"
     95 
     96 #ifdef HAVE_SRANDOM
     97 #define srand(x) 	srandom(x)
     98 #define rand() 		random()
     99 #endif
    100 
    101 #ifdef TLS
    102 #define THREAD_LOCAL static TLS
    103 #else
    104 #define THREAD_LOCAL static
    105 #endif
    106 
    107 #if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48)
    108 #define DO_JRAND_MIX
    109 THREAD_LOCAL unsigned short jrand_seed[3];
    110 #endif
    111 
    112 #ifdef _WIN32
    113 static void gettimeofday (struct timeval *tv, void *dummy)
    114 {
    115 	FILETIME	ftime;
    116 	uint64_t	n;
    117 
    118 	GetSystemTimeAsFileTime (&ftime);
    119 	n = (((uint64_t) ftime.dwHighDateTime << 32)
    120 	     + (uint64_t) ftime.dwLowDateTime);
    121 	if (n) {
    122 		n /= 10;
    123 		n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000;
    124 	}
    125 
    126 	tv->tv_sec = n / 1000000;
    127 	tv->tv_usec = n % 1000000;
    128 }
    129 
    130 static int getuid (void)
    131 {
    132 	return 1;
    133 }
    134 #endif
    135 
    136 static int get_random_fd(void)
    137 {
    138 	struct timeval	tv;
    139 	static int	fd = -2;
    140 	int		i;
    141 
    142 	if (fd == -2) {
    143 		gettimeofday(&tv, 0);
    144 #ifndef _WIN32
    145 		fd = open("/dev/urandom", O_RDONLY);
    146 		if (fd == -1)
    147 			fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
    148 		if (fd >= 0) {
    149 			i = fcntl(fd, F_GETFD);
    150 			if (i >= 0)
    151 				fcntl(fd, F_SETFD, i | FD_CLOEXEC);
    152 		}
    153 #endif
    154 		srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
    155 #ifdef DO_JRAND_MIX
    156 		jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF);
    157 		jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF);
    158 		jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16;
    159 #endif
    160 	}
    161 	/* Crank the random number generator a few times */
    162 	gettimeofday(&tv, 0);
    163 	for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
    164 		rand();
    165 	return fd;
    166 }
    167 
    168 
    169 /*
    170  * Generate a series of random bytes.  Use /dev/urandom if possible,
    171  * and if not, use srandom/random.
    172  */
    173 static void get_random_bytes(void *buf, int nbytes)
    174 {
    175 	int i, n = nbytes, fd = get_random_fd();
    176 	int lose_counter = 0;
    177 	unsigned char *cp = (unsigned char *) buf;
    178 	unsigned short tmp_seed[3];
    179 
    180 	if (fd >= 0) {
    181 		while (n > 0) {
    182 			i = read(fd, cp, n);
    183 			if (i <= 0) {
    184 				if (lose_counter++ > 16)
    185 					break;
    186 				continue;
    187 			}
    188 			n -= i;
    189 			cp += i;
    190 			lose_counter = 0;
    191 		}
    192 	}
    193 
    194 	/*
    195 	 * We do this all the time, but this is the only source of
    196 	 * randomness if /dev/random/urandom is out to lunch.
    197 	 */
    198 	for (cp = buf, i = 0; i < nbytes; i++)
    199 		*cp++ ^= (rand() >> 7) & 0xFF;
    200 #ifdef DO_JRAND_MIX
    201 	memcpy(tmp_seed, jrand_seed, sizeof(tmp_seed));
    202 	jrand_seed[2] = jrand_seed[2] ^ syscall(__NR_gettid);
    203 	for (cp = buf, i = 0; i < nbytes; i++)
    204 		*cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF;
    205 	memcpy(jrand_seed, tmp_seed,
    206 	       sizeof(jrand_seed)-sizeof(unsigned short));
    207 #endif
    208 
    209 	return;
    210 }
    211 
    212 /*
    213  * Get the ethernet hardware address, if we can find it...
    214  *
    215  * XXX for a windows version, probably should use GetAdaptersInfo:
    216  * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451
    217  * commenting out get_node_id just to get gen_uuid to compile under windows
    218  * is not the right way to go!
    219  */
    220 static int get_node_id(unsigned char *node_id)
    221 {
    222 #ifdef HAVE_NET_IF_H
    223 	int 		sd;
    224 	struct ifreq 	ifr, *ifrp;
    225 	struct ifconf 	ifc;
    226 	char buf[1024];
    227 	int		n, i;
    228 	unsigned char 	*a;
    229 #ifdef HAVE_NET_IF_DL_H
    230 	struct sockaddr_dl *sdlp;
    231 #endif
    232 
    233 /*
    234  * BSD 4.4 defines the size of an ifreq to be
    235  * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
    236  * However, under earlier systems, sa_len isn't present, so the size is
    237  * just sizeof(struct ifreq)
    238  */
    239 #ifdef HAVE_SA_LEN
    240 #ifndef max
    241 #define max(a,b) ((a) > (b) ? (a) : (b))
    242 #endif
    243 #define ifreq_size(i) max(sizeof(struct ifreq),\
    244      sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
    245 #else
    246 #define ifreq_size(i) sizeof(struct ifreq)
    247 #endif /* HAVE_SA_LEN*/
    248 
    249 	sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    250 	if (sd < 0) {
    251 		return -1;
    252 	}
    253 	memset(buf, 0, sizeof(buf));
    254 	ifc.ifc_len = sizeof(buf);
    255 	ifc.ifc_buf = buf;
    256 	if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
    257 		close(sd);
    258 		return -1;
    259 	}
    260 	n = ifc.ifc_len;
    261 	for (i = 0; i < n; i+= ifreq_size(*ifrp) ) {
    262 		ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
    263 		strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
    264 #ifdef SIOCGIFHWADDR
    265 		if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
    266 			continue;
    267 		a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
    268 #else
    269 #ifdef SIOCGENADDR
    270 		if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
    271 			continue;
    272 		a = (unsigned char *) ifr.ifr_enaddr;
    273 #else
    274 #ifdef HAVE_NET_IF_DL_H
    275 		sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
    276 		if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
    277 			continue;
    278 		a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
    279 #else
    280 		/*
    281 		 * XXX we don't have a way of getting the hardware
    282 		 * address
    283 		 */
    284 		close(sd);
    285 		return 0;
    286 #endif /* HAVE_NET_IF_DL_H */
    287 #endif /* SIOCGENADDR */
    288 #endif /* SIOCGIFHWADDR */
    289 		if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
    290 			continue;
    291 		if (node_id) {
    292 			memcpy(node_id, a, 6);
    293 			close(sd);
    294 			return 1;
    295 		}
    296 	}
    297 	close(sd);
    298 #endif
    299 	return 0;
    300 }
    301 
    302 /* Assume that the gettimeofday() has microsecond granularity */
    303 #define MAX_ADJUSTMENT 10
    304 
    305 static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
    306 		     uint16_t *ret_clock_seq, int *num)
    307 {
    308 	THREAD_LOCAL int		adjustment = 0;
    309 	THREAD_LOCAL struct timeval	last = {0, 0};
    310 	THREAD_LOCAL int		state_fd = -2;
    311 	THREAD_LOCAL FILE		*state_f;
    312 	THREAD_LOCAL uint16_t		clock_seq;
    313 	struct timeval 			tv;
    314 	struct flock			fl;
    315 	uint64_t			clock_reg;
    316 	mode_t				save_umask;
    317 	int				len;
    318 
    319 	if (state_fd == -2) {
    320 		save_umask = umask(0);
    321 		state_fd = open("/var/lib/libuuid/clock.txt",
    322 				O_RDWR|O_CREAT, 0660);
    323 		(void) umask(save_umask);
    324 		state_f = fdopen(state_fd, "r+");
    325 		if (!state_f) {
    326 			close(state_fd);
    327 			state_fd = -1;
    328 		}
    329 	}
    330 	fl.l_type = F_WRLCK;
    331 	fl.l_whence = SEEK_SET;
    332 	fl.l_start = 0;
    333 	fl.l_len = 0;
    334 	fl.l_pid = 0;
    335 	if (state_fd >= 0) {
    336 		rewind(state_f);
    337 		while (fcntl(state_fd, F_SETLKW, &fl) < 0) {
    338 			if ((errno == EAGAIN) || (errno == EINTR))
    339 				continue;
    340 			fclose(state_f);
    341 			close(state_fd);
    342 			state_fd = -1;
    343 			break;
    344 		}
    345 	}
    346 	if (state_fd >= 0) {
    347 		unsigned int cl;
    348 		unsigned long tv1, tv2;
    349 		int a;
    350 
    351 		if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n",
    352 			   &cl, &tv1, &tv2, &a) == 4) {
    353 			clock_seq = cl & 0x3FFF;
    354 			last.tv_sec = tv1;
    355 			last.tv_usec = tv2;
    356 			adjustment = a;
    357 		}
    358 	}
    359 
    360 	if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
    361 		get_random_bytes(&clock_seq, sizeof(clock_seq));
    362 		clock_seq &= 0x3FFF;
    363 		gettimeofday(&last, 0);
    364 		last.tv_sec--;
    365 	}
    366 
    367 try_again:
    368 	gettimeofday(&tv, 0);
    369 	if ((tv.tv_sec < last.tv_sec) ||
    370 	    ((tv.tv_sec == last.tv_sec) &&
    371 	     (tv.tv_usec < last.tv_usec))) {
    372 		clock_seq = (clock_seq+1) & 0x3FFF;
    373 		adjustment = 0;
    374 		last = tv;
    375 	} else if ((tv.tv_sec == last.tv_sec) &&
    376 	    (tv.tv_usec == last.tv_usec)) {
    377 		if (adjustment >= MAX_ADJUSTMENT)
    378 			goto try_again;
    379 		adjustment++;
    380 	} else {
    381 		adjustment = 0;
    382 		last = tv;
    383 	}
    384 
    385 	clock_reg = tv.tv_usec*10 + adjustment;
    386 	clock_reg += ((uint64_t) tv.tv_sec)*10000000;
    387 	clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
    388 
    389 	if (num && (*num > 1)) {
    390 		adjustment += *num - 1;
    391 		last.tv_usec += adjustment / 10;
    392 		adjustment = adjustment % 10;
    393 		last.tv_sec += last.tv_usec / 1000000;
    394 		last.tv_usec = last.tv_usec % 1000000;
    395 	}
    396 
    397 	if (state_fd > 0) {
    398 		rewind(state_f);
    399 		len = fprintf(state_f,
    400 			      "clock: %04x tv: %016lu %08lu adj: %08d\n",
    401 			      clock_seq, last.tv_sec, last.tv_usec, adjustment);
    402 		fflush(state_f);
    403 		if (ftruncate(state_fd, len) < 0) {
    404 			fprintf(state_f, "                   \n");
    405 			fflush(state_f);
    406 		}
    407 		rewind(state_f);
    408 		fl.l_type = F_UNLCK;
    409 		fcntl(state_fd, F_SETLK, &fl);
    410 	}
    411 
    412 	*clock_high = clock_reg >> 32;
    413 	*clock_low = clock_reg;
    414 	*ret_clock_seq = clock_seq;
    415 	return 0;
    416 }
    417 
    418 static ssize_t read_all(int fd, char *buf, size_t count)
    419 {
    420 	ssize_t ret;
    421 	ssize_t c = 0;
    422 	int tries = 0;
    423 
    424 	memset(buf, 0, count);
    425 	while (count > 0) {
    426 		ret = read(fd, buf, count);
    427 		if (ret <= 0) {
    428 			if ((errno == EAGAIN || errno == EINTR || ret == 0) &&
    429 			    (tries++ < 5))
    430 				continue;
    431 			return c ? c : -1;
    432 		}
    433 		if (ret > 0)
    434 			tries = 0;
    435 		count -= ret;
    436 		buf += ret;
    437 		c += ret;
    438 	}
    439 	return c;
    440 }
    441 
    442 /*
    443  * Close all file descriptors
    444  */
    445 static void close_all_fds(void)
    446 {
    447 	int i, max;
    448 
    449 #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
    450 	max = sysconf(_SC_OPEN_MAX);
    451 #elif defined(HAVE_GETDTABLESIZE)
    452 	max = getdtablesize();
    453 #elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
    454 	struct rlimit rl;
    455 
    456 	getrlimit(RLIMIT_NOFILE, &rl);
    457 	max = rl.rlim_cur;
    458 #else
    459 	max = OPEN_MAX;
    460 #endif
    461 
    462 	for (i=0; i < max; i++) {
    463 		close(i);
    464 		if (i <= 2)
    465 			open("/dev/null", O_RDWR);
    466 	}
    467 }
    468 
    469 
    470 /*
    471  * Try using the uuidd daemon to generate the UUID
    472  *
    473  * Returns 0 on success, non-zero on failure.
    474  */
    475 static int get_uuid_via_daemon(int op, uuid_t out, int *num)
    476 {
    477 #if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H)
    478 	char op_buf[64];
    479 	int op_len;
    480 	int s;
    481 	ssize_t ret;
    482 	int32_t reply_len = 0, expected = 16;
    483 	struct sockaddr_un srv_addr;
    484 	struct stat st;
    485 	pid_t pid;
    486 	static const char *uuidd_path = UUIDD_PATH;
    487 	static int access_ret = -2;
    488 	static int start_attempts = 0;
    489 
    490 	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
    491 		return -1;
    492 
    493 	srv_addr.sun_family = AF_UNIX;
    494 	strcpy(srv_addr.sun_path, UUIDD_SOCKET_PATH);
    495 
    496 	if (connect(s, (const struct sockaddr *) &srv_addr,
    497 		    sizeof(struct sockaddr_un)) < 0) {
    498 		if (access_ret == -2)
    499 			access_ret = access(uuidd_path, X_OK);
    500 		if (access_ret == 0)
    501 			access_ret = stat(uuidd_path, &st);
    502 		if (access_ret == 0 && (st.st_mode & (S_ISUID | S_ISGID)) == 0)
    503 			access_ret = access(UUIDD_DIR, W_OK);
    504 		if (access_ret == 0 && start_attempts++ < 5) {
    505 			if ((pid = fork()) == 0) {
    506 				close_all_fds();
    507 				execl(uuidd_path, "uuidd", "-qT", "300",
    508 				      (char *) NULL);
    509 				exit(1);
    510 			}
    511 			(void) waitpid(pid, 0, 0);
    512 			if (connect(s, (const struct sockaddr *) &srv_addr,
    513 				    sizeof(struct sockaddr_un)) < 0)
    514 				goto fail;
    515 		} else
    516 			goto fail;
    517 	}
    518 	op_buf[0] = op;
    519 	op_len = 1;
    520 	if (op == UUIDD_OP_BULK_TIME_UUID) {
    521 		memcpy(op_buf+1, num, sizeof(*num));
    522 		op_len += sizeof(*num);
    523 		expected += sizeof(*num);
    524 	}
    525 
    526 	ret = write(s, op_buf, op_len);
    527 	if (ret < 1)
    528 		goto fail;
    529 
    530 	ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
    531 	if (ret < 0)
    532 		goto fail;
    533 
    534 	if (reply_len != expected)
    535 		goto fail;
    536 
    537 	ret = read_all(s, op_buf, reply_len);
    538 
    539 	if (op == UUIDD_OP_BULK_TIME_UUID)
    540 		memcpy(op_buf+16, num, sizeof(int));
    541 
    542 	memcpy(out, op_buf, 16);
    543 
    544 	close(s);
    545 	return ((ret == expected) ? 0 : -1);
    546 
    547 fail:
    548 	close(s);
    549 #endif
    550 	return -1;
    551 }
    552 
    553 void uuid__generate_time(uuid_t out, int *num)
    554 {
    555 	static unsigned char node_id[6];
    556 	static int has_init = 0;
    557 	struct uuid uu;
    558 	uint32_t	clock_mid;
    559 
    560 	if (!has_init) {
    561 		if (get_node_id(node_id) <= 0) {
    562 			get_random_bytes(node_id, 6);
    563 			/*
    564 			 * Set multicast bit, to prevent conflicts
    565 			 * with IEEE 802 addresses obtained from
    566 			 * network cards
    567 			 */
    568 			node_id[0] |= 0x01;
    569 		}
    570 		has_init = 1;
    571 	}
    572 	get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num);
    573 	uu.clock_seq |= 0x8000;
    574 	uu.time_mid = (uint16_t) clock_mid;
    575 	uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000;
    576 	memcpy(uu.node, node_id, 6);
    577 	uuid_pack(&uu, out);
    578 }
    579 
    580 void uuid_generate_time(uuid_t out)
    581 {
    582 #ifdef TLS
    583 	THREAD_LOCAL int		num = 0;
    584 	THREAD_LOCAL struct uuid	uu;
    585 	THREAD_LOCAL time_t		last_time = 0;
    586 	time_t				now;
    587 
    588 	if (num > 0) {
    589 		now = time(0);
    590 		if (now > last_time+1)
    591 			num = 0;
    592 	}
    593 	if (num <= 0) {
    594 		num = 1000;
    595 		if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID,
    596 					out, &num) == 0) {
    597 			last_time = time(0);
    598 			uuid_unpack(out, &uu);
    599 			num--;
    600 			return;
    601 		}
    602 		num = 0;
    603 	}
    604 	if (num > 0) {
    605 		uu.time_low++;
    606 		if (uu.time_low == 0) {
    607 			uu.time_mid++;
    608 			if (uu.time_mid == 0)
    609 				uu.time_hi_and_version++;
    610 		}
    611 		num--;
    612 		uuid_pack(&uu, out);
    613 		return;
    614 	}
    615 #else
    616 	if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, 0) == 0)
    617 		return;
    618 #endif
    619 
    620 	uuid__generate_time(out, 0);
    621 }
    622 
    623 
    624 void uuid__generate_random(uuid_t out, int *num)
    625 {
    626 	uuid_t	buf;
    627 	struct uuid uu;
    628 	int i, n;
    629 
    630 	if (!num || !*num)
    631 		n = 1;
    632 	else
    633 		n = *num;
    634 
    635 	for (i = 0; i < n; i++) {
    636 		get_random_bytes(buf, sizeof(buf));
    637 		uuid_unpack(buf, &uu);
    638 
    639 		uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
    640 		uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF)
    641 			| 0x4000;
    642 		uuid_pack(&uu, out);
    643 		out += sizeof(uuid_t);
    644 	}
    645 }
    646 
    647 void uuid_generate_random(uuid_t out)
    648 {
    649 	int	num = 1;
    650 	/* No real reason to use the daemon for random uuid's -- yet */
    651 
    652 	uuid__generate_random(out, &num);
    653 }
    654 
    655 
    656 /*
    657  * This is the generic front-end to uuid_generate_random and
    658  * uuid_generate_time.  It uses uuid_generate_random only if
    659  * /dev/urandom is available, since otherwise we won't have
    660  * high-quality randomness.
    661  */
    662 void uuid_generate(uuid_t out)
    663 {
    664 	if (get_random_fd() >= 0)
    665 		uuid_generate_random(out);
    666 	else
    667 		uuid_generate_time(out);
    668 }
    669