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