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