xref: /illumos-gate/usr/src/lib/libuuid/common/uuid_misc.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * The copyright in this file is taken from the original Leach
29  * & Salz UUID specification, from which this implementation
30  * is derived.
31  */
32 
33 /*
34  * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
35  * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
36  * Digital Equipment Corporation, Maynard, Mass.  Copyright (c) 1998
37  * Microsoft.  To anyone who acknowledges that this file is provided
38  * "AS IS" without any express or implied warranty: permission to use,
39  * copy, modify, and distribute this file for any purpose is hereby
40  * granted without fee, provided that the above copyright notices and
41  * this notice appears in all source code copies, and that none of the
42  * names of Open Software Foundation, Inc., Hewlett-Packard Company,
43  * or Digital Equipment Corporation be used in advertising or
44  * publicity pertaining to distribution of the software without
45  * specific, written prior permission.  Neither Open Software
46  * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
47  * Equipment Corporation makes any representations about the
48  * suitability of this software for any purpose.
49  */
50 
51 #include <uuid/uuid.h>
52 #include <stdlib.h>
53 #include <strings.h>
54 #include "uuid_misc.h"
55 
56 #define	UUCMP(u1, u2)		if (u1 != u2) return ((u1 < u2) ? -1 : 1)
57 #define	UUIDS_PER_TOD_CALL	10	/* tv_usec is multiplied by 10 */
58 
59 void		struct_to_string(uuid_t, struct uuid *);
60 void		string_to_struct(struct uuid *, uuid_t);
61 void		get_system_time(uuid_time_t *);
62 
63 /*
64  * Name:	get_current_time
65  *
66  * Description:	get-current_time -- get time as 60 bit 100ns ticks
67  *		since the beginning of unix time.
68  *		Compensate for the fact that real clock resolution is
69  *		less than 100ns.
70  *
71  * Returns:	None.
72  *
73  */
74 void
75 get_current_time(uuid_time_t *timestamp)
76 {
77 	uuid_time_t		time_now;
78 	static uuid_time_t	time_last = 0;
79 	static uint16_t		uuids_this_tick = 0;
80 	int			done;
81 
82 	done = 0;
83 	while (!done) {
84 		get_system_time(&time_now);
85 
86 		/*
87 		 * if clock reading changed since last UUID generated...
88 		 */
89 		if (time_last != time_now) {
90 			/*
91 			 * reset count of uuids generated with
92 			 * this clock reading
93 			 */
94 			uuids_this_tick = 0;
95 			done = 1;
96 		} else {
97 			uuids_this_tick++;
98 			if (uuids_this_tick < UUIDS_PER_TOD_CALL)
99 				done = 1;
100 		}
101 		/*
102 		 * too many UUIDs for this gettimeofday call; spin
103 		 */
104 	}
105 	time_last = time_now;
106 	/*
107 	 * add the count of uuids to low order bits of the clock reading
108 	 */
109 	*timestamp = time_now + uuids_this_tick;
110 }
111 
112 /*
113  * Name:	get_random
114  *
115  * Description:	Gets a random number.
116  *
117  * Returns:	nbytes of random information.
118  *
119  */
120 uint16_t
121 get_random(void)
122 {
123 	static int	initted = 0;
124 	uuid_time_t	time_now;
125 	long		seed;
126 
127 	if (!initted) {
128 		get_system_time(&time_now);
129 		time_now = time_now/UUIDS_PER_TOD_CALL;
130 		seed = (unsigned)(((time_now >> 32) ^ time_now)&0xffffffff);
131 		srand48(seed);
132 		initted = 1;
133 	}
134 	return (mrand48());
135 }
136 
137 /*
138  * Name:	uuid_compare
139  *
140  * Description: Compares 2 uuid strings
141  *
142  * Returns:	-1 if u1 < u2, 1 if u1 > u2 and 0 if both are equal
143  */
144 int
145 uuid_compare(uuid_t uu1, uuid_t uu2)
146 {
147 
148 	struct uuid	uuid1, uuid2;
149 
150 	string_to_struct(&uuid1, uu1);
151 	string_to_struct(&uuid2, uu2);
152 	UUCMP(uuid1.time_low, uuid2.time_low);
153 	UUCMP(uuid1.time_mid, uuid2.time_mid);
154 	UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
155 	UUCMP(uuid1.clock_seq_hi_and_reserved, uuid2.clock_seq_hi_and_reserved);
156 	UUCMP(uuid1.clock_seq_low, uuid2.clock_seq_low);
157 	return (memcmp(uuid1.node_addr, uuid2.node_addr, 6));
158 }
159 
160 /*
161  * Name:	get_system_time
162  *
163  * Description:	system dependent call to get the current system time.
164  *		Returned as 100ns ticks since Oct 15, 1582, but
165  *		resolution may be less than 100ns.
166  *
167  * Returns:	None
168  */
169 void
170 get_system_time(uuid_time_t *uuid_time)
171 {
172 	struct timeval tp;
173 
174 	(void) gettimeofday(&tp, (struct timezone *)0);
175 
176 	/*
177 	 * Offset between UUID formatted times and Unix formatted times.
178 	 * UUID UTC base time is October 15, 1582.
179 	 * Unix base time is January 1, 1970.
180 	 */
181 	*uuid_time = (uint64_t)tp.tv_sec * 10000000;
182 	*uuid_time += tp.tv_usec * 10;
183 	*uuid_time += 0x01B21DD213814000ULL;
184 }
185