xref: /titanic_50/usr/src/lib/libuuid/common/uuid.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * The copyright in this file is taken from the original Leach & Salz
31*7c478bd9Sstevel@tonic-gate  * UUID specification, from which this implementation is derived.
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate /*
35*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
36*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
37*7c478bd9Sstevel@tonic-gate  * Digital Equipment Corporation, Maynard, Mass.  Copyright (c) 1998
38*7c478bd9Sstevel@tonic-gate  * Microsoft.  To anyone who acknowledges that this file is provided
39*7c478bd9Sstevel@tonic-gate  * "AS IS" without any express or implied warranty: permission to use,
40*7c478bd9Sstevel@tonic-gate  * copy, modify, and distribute this file for any purpose is hereby
41*7c478bd9Sstevel@tonic-gate  * granted without fee, provided that the above copyright notices and
42*7c478bd9Sstevel@tonic-gate  * this notice appears in all source code copies, and that none of the
43*7c478bd9Sstevel@tonic-gate  * names of Open Software Foundation, Inc., Hewlett-Packard Company,
44*7c478bd9Sstevel@tonic-gate  * or Digital Equipment Corporation be used in advertising or
45*7c478bd9Sstevel@tonic-gate  * publicity pertaining to distribution of the software without
46*7c478bd9Sstevel@tonic-gate  * specific, written prior permission.  Neither Open Software
47*7c478bd9Sstevel@tonic-gate  * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
48*7c478bd9Sstevel@tonic-gate  * Equipment Corporation makes any representations about the
49*7c478bd9Sstevel@tonic-gate  * suitability of this software for any purpose.
50*7c478bd9Sstevel@tonic-gate  */
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /*
53*7c478bd9Sstevel@tonic-gate  * Module:		uuid.c
54*7c478bd9Sstevel@tonic-gate  *
55*7c478bd9Sstevel@tonic-gate  * Description:		This module is the workhorse for generating abstract
56*7c478bd9Sstevel@tonic-gate  *			UUIDs.  It delegates system-specific tasks (such
57*7c478bd9Sstevel@tonic-gate  *			as obtaining the node identifier or system time)
58*7c478bd9Sstevel@tonic-gate  *			to the sysdep module.
59*7c478bd9Sstevel@tonic-gate  */
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #include <ctype.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
64*7c478bd9Sstevel@tonic-gate #include <errno.h>
65*7c478bd9Sstevel@tonic-gate #include <stdio.h>
66*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
67*7c478bd9Sstevel@tonic-gate #include <strings.h>
68*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
69*7c478bd9Sstevel@tonic-gate #include <unistd.h>
70*7c478bd9Sstevel@tonic-gate #include <uuid/uuid.h>
71*7c478bd9Sstevel@tonic-gate #include <thread.h>
72*7c478bd9Sstevel@tonic-gate #include <synch.h>
73*7c478bd9Sstevel@tonic-gate #include "uuid_misc.h"
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate #define	STATE_LOCATION		"/var/sadm/system/uuid_state"
76*7c478bd9Sstevel@tonic-gate #define	URANDOM_PATH		"/dev/urandom"
77*7c478bd9Sstevel@tonic-gate #define	MAX_RETRY		8
78*7c478bd9Sstevel@tonic-gate #define	UUID_PRINTF_SIZE	37
79*7c478bd9Sstevel@tonic-gate #define	VER1_MASK		0xefff
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate static	mutex_t			ulock = DEFAULTMUTEX;
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate uint16_t	_get_random(void);
84*7c478bd9Sstevel@tonic-gate void		_get_current_time(uuid_time_t *);
85*7c478bd9Sstevel@tonic-gate void		struct_to_string(uuid_t, struct uuid *);
86*7c478bd9Sstevel@tonic-gate void		string_to_struct(struct uuid *, uuid_t);
87*7c478bd9Sstevel@tonic-gate int		get_ethernet_address(uuid_node_t *);
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate /*
90*7c478bd9Sstevel@tonic-gate  * local functions
91*7c478bd9Sstevel@tonic-gate  */
92*7c478bd9Sstevel@tonic-gate static	int	_lock_state(char *);
93*7c478bd9Sstevel@tonic-gate static	void	_unlock_state(int);
94*7c478bd9Sstevel@tonic-gate static	void	_read_state(int, uint16_t *, uuid_time_t *,
95*7c478bd9Sstevel@tonic-gate 		    uuid_node_t *);
96*7c478bd9Sstevel@tonic-gate static	int	_write_state(int, uint16_t, uuid_time_t, uuid_node_t);
97*7c478bd9Sstevel@tonic-gate static	void 	_format_uuid(struct uuid *, uint16_t, uuid_time_t,
98*7c478bd9Sstevel@tonic-gate 		    uuid_node_t);
99*7c478bd9Sstevel@tonic-gate static	void	fill_random_bytes(uchar_t *, int);
100*7c478bd9Sstevel@tonic-gate static	int	uuid_create(struct uuid *);
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate static	void	gen_ethernet_address(uuid_node_t *);
103*7c478bd9Sstevel@tonic-gate /*
104*7c478bd9Sstevel@tonic-gate  * Name:		uuid_create.
105*7c478bd9Sstevel@tonic-gate  *
106*7c478bd9Sstevel@tonic-gate  * Description:	Generates a uuid based on Version 1 format
107*7c478bd9Sstevel@tonic-gate  *
108*7c478bd9Sstevel@tonic-gate  * Returns:	0 on success, -1 on Error
109*7c478bd9Sstevel@tonic-gate  */
110*7c478bd9Sstevel@tonic-gate static int
111*7c478bd9Sstevel@tonic-gate uuid_create(struct uuid *uuid)
112*7c478bd9Sstevel@tonic-gate {
113*7c478bd9Sstevel@tonic-gate 	uuid_time_t	timestamp, last_time;
114*7c478bd9Sstevel@tonic-gate 	uint16_t	clockseq = 0;
115*7c478bd9Sstevel@tonic-gate 	uuid_node_t	last_node;
116*7c478bd9Sstevel@tonic-gate 	uuid_node_t	system_node;
117*7c478bd9Sstevel@tonic-gate 	int		locked_state_fd;
118*7c478bd9Sstevel@tonic-gate 	int		non_unique = 0;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	if (mutex_lock(&ulock) != 0) {
121*7c478bd9Sstevel@tonic-gate 	    return (-1);
122*7c478bd9Sstevel@tonic-gate 	}
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	gen_ethernet_address(&system_node);
125*7c478bd9Sstevel@tonic-gate 	/*
126*7c478bd9Sstevel@tonic-gate 	 * acquire system wide lock so we're alone
127*7c478bd9Sstevel@tonic-gate 	 */
128*7c478bd9Sstevel@tonic-gate 	locked_state_fd = _lock_state(STATE_LOCATION);
129*7c478bd9Sstevel@tonic-gate 	if (locked_state_fd < 0) {
130*7c478bd9Sstevel@tonic-gate 	    /* couldn't create and/or lock state; don't have access */
131*7c478bd9Sstevel@tonic-gate 	    non_unique++;
132*7c478bd9Sstevel@tonic-gate 	} else {
133*7c478bd9Sstevel@tonic-gate 	    /* read saved state from disk */
134*7c478bd9Sstevel@tonic-gate 	    _read_state(locked_state_fd, &clockseq, &last_time,
135*7c478bd9Sstevel@tonic-gate 			&last_node);
136*7c478bd9Sstevel@tonic-gate 	}
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	if (clockseq == 0) {
139*7c478bd9Sstevel@tonic-gate 	    /* couldn't read clock sequence; generate a random one */
140*7c478bd9Sstevel@tonic-gate 	    clockseq = _get_random();
141*7c478bd9Sstevel@tonic-gate 	    non_unique++;
142*7c478bd9Sstevel@tonic-gate 	}
143*7c478bd9Sstevel@tonic-gate 	if (memcmp(&system_node, &last_node, sizeof (uuid_node_t)) != 0) {
144*7c478bd9Sstevel@tonic-gate 	    clockseq++;
145*7c478bd9Sstevel@tonic-gate 	}
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	/*
148*7c478bd9Sstevel@tonic-gate 	 * get current time
149*7c478bd9Sstevel@tonic-gate 	 */
150*7c478bd9Sstevel@tonic-gate 	_get_current_time(&timestamp);
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	/*
153*7c478bd9Sstevel@tonic-gate 	 * If timestamp is not set or is not in the past,
154*7c478bd9Sstevel@tonic-gate 	 * increment clock sequence.
155*7c478bd9Sstevel@tonic-gate 	 */
156*7c478bd9Sstevel@tonic-gate 	if ((last_time == 0) || (last_time >= timestamp)) {
157*7c478bd9Sstevel@tonic-gate 	    clockseq++;
158*7c478bd9Sstevel@tonic-gate 	    last_time = timestamp;
159*7c478bd9Sstevel@tonic-gate 	}
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	if (non_unique)
162*7c478bd9Sstevel@tonic-gate 		system_node.nodeID[0] |= 0x80;
163*7c478bd9Sstevel@tonic-gate 	/*
164*7c478bd9Sstevel@tonic-gate 	 * stuff fields into the UUID
165*7c478bd9Sstevel@tonic-gate 	 */
166*7c478bd9Sstevel@tonic-gate 	_format_uuid(uuid, clockseq, timestamp, system_node);
167*7c478bd9Sstevel@tonic-gate 	if ((locked_state_fd >= 0) &&
168*7c478bd9Sstevel@tonic-gate 		(_write_state(locked_state_fd, clockseq, timestamp,
169*7c478bd9Sstevel@tonic-gate 		system_node) == -1)) {
170*7c478bd9Sstevel@tonic-gate 	    _unlock_state(locked_state_fd);
171*7c478bd9Sstevel@tonic-gate 	    (void) mutex_unlock(&ulock);
172*7c478bd9Sstevel@tonic-gate 	    return (-1);
173*7c478bd9Sstevel@tonic-gate 	}
174*7c478bd9Sstevel@tonic-gate 	/*
175*7c478bd9Sstevel@tonic-gate 	 * Unlock system-wide lock
176*7c478bd9Sstevel@tonic-gate 	 */
177*7c478bd9Sstevel@tonic-gate 	_unlock_state(locked_state_fd);
178*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&ulock);
179*7c478bd9Sstevel@tonic-gate 	return (0);
180*7c478bd9Sstevel@tonic-gate }
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate  * Name:	gen_ethernet_address
184*7c478bd9Sstevel@tonic-gate  *
185*7c478bd9Sstevel@tonic-gate  * Description: Fills system_node with Ethernet address if available,
186*7c478bd9Sstevel@tonic-gate  *		else fills random numbers
187*7c478bd9Sstevel@tonic-gate  *
188*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing
189*7c478bd9Sstevel@tonic-gate  */
190*7c478bd9Sstevel@tonic-gate static void
191*7c478bd9Sstevel@tonic-gate gen_ethernet_address(uuid_node_t *system_node)
192*7c478bd9Sstevel@tonic-gate {
193*7c478bd9Sstevel@tonic-gate 	uchar_t		node[6];
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	if (get_ethernet_address(system_node) != 0) {
196*7c478bd9Sstevel@tonic-gate 		fill_random_bytes(node, 6);
197*7c478bd9Sstevel@tonic-gate 		(void) memcpy(system_node->nodeID, node, 6);
198*7c478bd9Sstevel@tonic-gate 		/*
199*7c478bd9Sstevel@tonic-gate 		 * use 8:0:20 with the multicast bit set
200*7c478bd9Sstevel@tonic-gate 		 * to avoid namespace collisions.
201*7c478bd9Sstevel@tonic-gate 		 */
202*7c478bd9Sstevel@tonic-gate 		system_node->nodeID[0] = 0x88;
203*7c478bd9Sstevel@tonic-gate 		system_node->nodeID[1] = 0x00;
204*7c478bd9Sstevel@tonic-gate 		system_node->nodeID[2] = 0x20;
205*7c478bd9Sstevel@tonic-gate 	}
206*7c478bd9Sstevel@tonic-gate }
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate /*
209*7c478bd9Sstevel@tonic-gate  * Name:	_format_uuid
210*7c478bd9Sstevel@tonic-gate  *
211*7c478bd9Sstevel@tonic-gate  * Description: Formats a UUID, given the clock_seq timestamp,
212*7c478bd9Sstevel@tonic-gate  * 		and node address.  Fills in passed-in pointer with
213*7c478bd9Sstevel@tonic-gate  *		the resulting uuid.
214*7c478bd9Sstevel@tonic-gate  *
215*7c478bd9Sstevel@tonic-gate  * Returns:	None.
216*7c478bd9Sstevel@tonic-gate  */
217*7c478bd9Sstevel@tonic-gate static void
218*7c478bd9Sstevel@tonic-gate _format_uuid(struct uuid *uuid, uint16_t clock_seq,
219*7c478bd9Sstevel@tonic-gate     uuid_time_t timestamp, uuid_node_t node)
220*7c478bd9Sstevel@tonic-gate {
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	/*
223*7c478bd9Sstevel@tonic-gate 	 * First set up the first 60 bits from the timestamp
224*7c478bd9Sstevel@tonic-gate 	 */
225*7c478bd9Sstevel@tonic-gate 	uuid->time_low = (uint32_t)(timestamp & 0xFFFFFFFF);
226*7c478bd9Sstevel@tonic-gate 	uuid->time_mid = (uint16_t)((timestamp >> 32) & 0xFFFF);
227*7c478bd9Sstevel@tonic-gate 	uuid->time_hi_and_version = (uint16_t)((timestamp >> 48) &
228*7c478bd9Sstevel@tonic-gate 	    0x0FFF);
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	/*
231*7c478bd9Sstevel@tonic-gate 	 * This is version 1, so say so in the UUID version field (4 bits)
232*7c478bd9Sstevel@tonic-gate 	 */
233*7c478bd9Sstevel@tonic-gate 	uuid->time_hi_and_version |= (1 << 12);
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	/*
236*7c478bd9Sstevel@tonic-gate 	 * Now do the clock sequence
237*7c478bd9Sstevel@tonic-gate 	 */
238*7c478bd9Sstevel@tonic-gate 	uuid->clock_seq_low = clock_seq & 0xFF;
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	/*
241*7c478bd9Sstevel@tonic-gate 	 * We must save the most-significant 2 bits for the reserved field
242*7c478bd9Sstevel@tonic-gate 	 */
243*7c478bd9Sstevel@tonic-gate 	uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	/*
246*7c478bd9Sstevel@tonic-gate 	 * The variant for this format is the 2 high bits set to 10,
247*7c478bd9Sstevel@tonic-gate 	 * so here it is
248*7c478bd9Sstevel@tonic-gate 	 */
249*7c478bd9Sstevel@tonic-gate 	uuid->clock_seq_hi_and_reserved |= 0x80;
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	/*
252*7c478bd9Sstevel@tonic-gate 	 * write result to passed-in pointer
253*7c478bd9Sstevel@tonic-gate 	 */
254*7c478bd9Sstevel@tonic-gate 	(void) memcpy(&uuid->node_addr, &node, sizeof (uuid->node_addr));
255*7c478bd9Sstevel@tonic-gate }
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate /*
258*7c478bd9Sstevel@tonic-gate  * Name:	_read_state
259*7c478bd9Sstevel@tonic-gate  *
260*7c478bd9Sstevel@tonic-gate  * Description: Reads non-volatile state from a (possibly) saved statefile.
261*7c478bd9Sstevel@tonic-gate  * 		For each non-null pointer passed-in, the corresponding
262*7c478bd9Sstevel@tonic-gate  *		information from the statefile is filled in.
263*7c478bd9Sstevel@tonic-gate  *		the resulting uuid.
264*7c478bd9Sstevel@tonic-gate  *
265*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing.
266*7c478bd9Sstevel@tonic-gate  */
267*7c478bd9Sstevel@tonic-gate static void
268*7c478bd9Sstevel@tonic-gate _read_state(int fd, uint16_t *clockseq,
269*7c478bd9Sstevel@tonic-gate     uuid_time_t *timestamp, uuid_node_t *node)
270*7c478bd9Sstevel@tonic-gate {
271*7c478bd9Sstevel@tonic-gate 	uuid_state_t	vol_state;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	bzero(node, sizeof (uuid_node_t));
274*7c478bd9Sstevel@tonic-gate 	*timestamp = 0;
275*7c478bd9Sstevel@tonic-gate 	*clockseq = 0;
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	if (read(fd, &vol_state, sizeof (uuid_state_t)) <
278*7c478bd9Sstevel@tonic-gate 	    sizeof (uuid_state_t)) {
279*7c478bd9Sstevel@tonic-gate 		/* This file is being accessed the first time */
280*7c478bd9Sstevel@tonic-gate 	}
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	*node = vol_state.node;
283*7c478bd9Sstevel@tonic-gate 	*timestamp = vol_state.ts;
284*7c478bd9Sstevel@tonic-gate 	*clockseq = vol_state.cs;
285*7c478bd9Sstevel@tonic-gate }
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate /*
289*7c478bd9Sstevel@tonic-gate  * Name:	_write_state
290*7c478bd9Sstevel@tonic-gate  *
291*7c478bd9Sstevel@tonic-gate  * Description: Writes non-volatile state from the passed-in information.
292*7c478bd9Sstevel@tonic-gate  *
293*7c478bd9Sstevel@tonic-gate  * Returns:	-1 on error, 0 otherwise.
294*7c478bd9Sstevel@tonic-gate  */
295*7c478bd9Sstevel@tonic-gate static int
296*7c478bd9Sstevel@tonic-gate _write_state(int fd, uint16_t clockseq,
297*7c478bd9Sstevel@tonic-gate     uuid_time_t timestamp, uuid_node_t node)
298*7c478bd9Sstevel@tonic-gate {
299*7c478bd9Sstevel@tonic-gate 	uuid_state_t	vol_state;
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	vol_state.cs = clockseq;
302*7c478bd9Sstevel@tonic-gate 	vol_state.ts = timestamp;
303*7c478bd9Sstevel@tonic-gate 	vol_state.node = node;
304*7c478bd9Sstevel@tonic-gate 	/*
305*7c478bd9Sstevel@tonic-gate 	 * seek to beginning of file and write data
306*7c478bd9Sstevel@tonic-gate 	 */
307*7c478bd9Sstevel@tonic-gate 	if (lseek(fd, 0, SEEK_SET) != -1) {
308*7c478bd9Sstevel@tonic-gate 	    if (write(fd, &vol_state, sizeof (uuid_state_t)) != -1) {
309*7c478bd9Sstevel@tonic-gate 		return (0);
310*7c478bd9Sstevel@tonic-gate 	    }
311*7c478bd9Sstevel@tonic-gate 	}
312*7c478bd9Sstevel@tonic-gate 	return (-1);
313*7c478bd9Sstevel@tonic-gate }
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate /*
318*7c478bd9Sstevel@tonic-gate  * Name:	_uuid_print
319*7c478bd9Sstevel@tonic-gate  *
320*7c478bd9Sstevel@tonic-gate  * Description:	Prints a nicely-formatted uuid to stdout.
321*7c478bd9Sstevel@tonic-gate  *
322*7c478bd9Sstevel@tonic-gate  * Returns:	None.
323*7c478bd9Sstevel@tonic-gate  *
324*7c478bd9Sstevel@tonic-gate  */
325*7c478bd9Sstevel@tonic-gate void
326*7c478bd9Sstevel@tonic-gate uuid_print(struct uuid u)
327*7c478bd9Sstevel@tonic-gate {
328*7c478bd9Sstevel@tonic-gate 	int i;
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	(void) printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
331*7c478bd9Sstevel@tonic-gate 	    u.time_hi_and_version, u.clock_seq_hi_and_reserved,
332*7c478bd9Sstevel@tonic-gate 	    u.clock_seq_low);
333*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 6; i++)
334*7c478bd9Sstevel@tonic-gate 		(void) printf("%2.2x", u.node_addr[i]);
335*7c478bd9Sstevel@tonic-gate 	(void) printf("\n");
336*7c478bd9Sstevel@tonic-gate }
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate /*
339*7c478bd9Sstevel@tonic-gate  * Name:	_lock_state
340*7c478bd9Sstevel@tonic-gate  *
341*7c478bd9Sstevel@tonic-gate  * Description:	Locks down the statefile, by first creating the file
342*7c478bd9Sstevel@tonic-gate  *		if it doesn't exist.
343*7c478bd9Sstevel@tonic-gate  *
344*7c478bd9Sstevel@tonic-gate  * Returns:	A non-negative file descriptor referring to the locked
345*7c478bd9Sstevel@tonic-gate  *		state file, if it was able to be created and/or locked,
346*7c478bd9Sstevel@tonic-gate  *		or -1 otherwise.
347*7c478bd9Sstevel@tonic-gate  */
348*7c478bd9Sstevel@tonic-gate static int
349*7c478bd9Sstevel@tonic-gate _lock_state(char *loc)
350*7c478bd9Sstevel@tonic-gate {
351*7c478bd9Sstevel@tonic-gate 	int fd;
352*7c478bd9Sstevel@tonic-gate 	struct flock lock;
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	fd = open(loc, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	if (fd < 0) {
357*7c478bd9Sstevel@tonic-gate 		return (-1);
358*7c478bd9Sstevel@tonic-gate 	}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	lock.l_type = F_WRLCK;
361*7c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
362*7c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
363*7c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	if (fcntl(fd, F_SETLKW, &lock) == -1) {
366*7c478bd9Sstevel@tonic-gate 		/*
367*7c478bd9Sstevel@tonic-gate 		 * File could not be locked, bail
368*7c478bd9Sstevel@tonic-gate 		 */
369*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
370*7c478bd9Sstevel@tonic-gate 		return (-1);
371*7c478bd9Sstevel@tonic-gate 	}
372*7c478bd9Sstevel@tonic-gate 	return (fd);
373*7c478bd9Sstevel@tonic-gate }
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate /*
376*7c478bd9Sstevel@tonic-gate  * Name:	_unlock_state
377*7c478bd9Sstevel@tonic-gate  *
378*7c478bd9Sstevel@tonic-gate  * Description:	Unlocks a locked statefile, and close()'s the file.
379*7c478bd9Sstevel@tonic-gate  *
380*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing.
381*7c478bd9Sstevel@tonic-gate  */
382*7c478bd9Sstevel@tonic-gate void
383*7c478bd9Sstevel@tonic-gate _unlock_state(int fd)
384*7c478bd9Sstevel@tonic-gate {
385*7c478bd9Sstevel@tonic-gate 	struct flock lock;
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	lock.l_type = F_UNLCK;
388*7c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
389*7c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
390*7c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 	(void) fcntl(fd, F_SETLK, &lock);
393*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
394*7c478bd9Sstevel@tonic-gate }
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate /*
397*7c478bd9Sstevel@tonic-gate  * Name:	fill_random_bytes
398*7c478bd9Sstevel@tonic-gate  *
399*7c478bd9Sstevel@tonic-gate  * Description:	fills buf with random numbers - nbytes is the number of bytes
400*7c478bd9Sstevel@tonic-gate  *		to fill-in. Tries to use /dev/urandom random number generator-
401*7c478bd9Sstevel@tonic-gate  *		if that fails for some reason, it retries MAX_RETRY times. If
402*7c478bd9Sstevel@tonic-gate  *		it still fails then it uses srand48(3C)
403*7c478bd9Sstevel@tonic-gate  *
404*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing.
405*7c478bd9Sstevel@tonic-gate  */
406*7c478bd9Sstevel@tonic-gate static void
407*7c478bd9Sstevel@tonic-gate fill_random_bytes(uchar_t *buf, int nbytes)
408*7c478bd9Sstevel@tonic-gate {
409*7c478bd9Sstevel@tonic-gate 	int i, fd, retries = 0;
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	fd = open(URANDOM_PATH, O_RDONLY);
412*7c478bd9Sstevel@tonic-gate 	if (fd >= 0) {
413*7c478bd9Sstevel@tonic-gate 	    while (nbytes > 0) {
414*7c478bd9Sstevel@tonic-gate 		i = read(fd, buf, nbytes);
415*7c478bd9Sstevel@tonic-gate 		if ((i < 0) && (errno == EINTR)) {
416*7c478bd9Sstevel@tonic-gate 		    continue;
417*7c478bd9Sstevel@tonic-gate 		}
418*7c478bd9Sstevel@tonic-gate 		if (i <= 0) {
419*7c478bd9Sstevel@tonic-gate 		    if (retries++ == MAX_RETRY)
420*7c478bd9Sstevel@tonic-gate 			break;
421*7c478bd9Sstevel@tonic-gate 		    continue;
422*7c478bd9Sstevel@tonic-gate 		}
423*7c478bd9Sstevel@tonic-gate 		nbytes -= i;
424*7c478bd9Sstevel@tonic-gate 		buf += i;
425*7c478bd9Sstevel@tonic-gate 		retries = 0;
426*7c478bd9Sstevel@tonic-gate 	    }
427*7c478bd9Sstevel@tonic-gate 	    if (nbytes == 0) {
428*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
429*7c478bd9Sstevel@tonic-gate 		return;
430*7c478bd9Sstevel@tonic-gate 	    }
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nbytes; i++) {
433*7c478bd9Sstevel@tonic-gate 	    *buf++ = _get_random() & 0xFF;
434*7c478bd9Sstevel@tonic-gate 	}
435*7c478bd9Sstevel@tonic-gate 	if (fd >= 0) {
436*7c478bd9Sstevel@tonic-gate 	    (void) close(fd);
437*7c478bd9Sstevel@tonic-gate 	}
438*7c478bd9Sstevel@tonic-gate }
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate /*
441*7c478bd9Sstevel@tonic-gate  * Name:	struct_to_string
442*7c478bd9Sstevel@tonic-gate  *
443*7c478bd9Sstevel@tonic-gate  * Description:	Unpacks the structure members in "struct uuid" to a char
444*7c478bd9Sstevel@tonic-gate  *		string "uuid_t".
445*7c478bd9Sstevel@tonic-gate  *
446*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing.
447*7c478bd9Sstevel@tonic-gate  */
448*7c478bd9Sstevel@tonic-gate void
449*7c478bd9Sstevel@tonic-gate struct_to_string(uuid_t ptr, struct uuid *uu)
450*7c478bd9Sstevel@tonic-gate {
451*7c478bd9Sstevel@tonic-gate 	uint_t		tmp;
452*7c478bd9Sstevel@tonic-gate 	uchar_t		*out = ptr;
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	tmp = uu->time_low;
455*7c478bd9Sstevel@tonic-gate 	out[3] = (uchar_t)tmp;
456*7c478bd9Sstevel@tonic-gate 	tmp >>= 8;
457*7c478bd9Sstevel@tonic-gate 	out[2] = (uchar_t)tmp;
458*7c478bd9Sstevel@tonic-gate 	tmp >>= 8;
459*7c478bd9Sstevel@tonic-gate 	out[1] = (uchar_t)tmp;
460*7c478bd9Sstevel@tonic-gate 	tmp >>= 8;
461*7c478bd9Sstevel@tonic-gate 	out[0] = (uchar_t)tmp;
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	tmp = uu->time_mid;
464*7c478bd9Sstevel@tonic-gate 	out[5] = (uchar_t)tmp;
465*7c478bd9Sstevel@tonic-gate 	tmp >>= 8;
466*7c478bd9Sstevel@tonic-gate 	out[4] = (uchar_t)tmp;
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	tmp = uu->time_hi_and_version;
469*7c478bd9Sstevel@tonic-gate 	out[7] = (uchar_t)tmp;
470*7c478bd9Sstevel@tonic-gate 	tmp >>= 8;
471*7c478bd9Sstevel@tonic-gate 	out[6] = (uchar_t)tmp;
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	tmp = uu->clock_seq_hi_and_reserved;
474*7c478bd9Sstevel@tonic-gate 	out[8] = (uchar_t)tmp;
475*7c478bd9Sstevel@tonic-gate 	tmp = uu->clock_seq_low;
476*7c478bd9Sstevel@tonic-gate 	out[9] = (uchar_t)tmp;
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	(void) memcpy(out+10, uu->node_addr, 6);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate }
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate /*
483*7c478bd9Sstevel@tonic-gate  * Name:	string_to_struct
484*7c478bd9Sstevel@tonic-gate  *
485*7c478bd9Sstevel@tonic-gate  * Description:	Packs the values in the "uuid_t" string into "struct uuid".
486*7c478bd9Sstevel@tonic-gate  *
487*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing
488*7c478bd9Sstevel@tonic-gate  */
489*7c478bd9Sstevel@tonic-gate void
490*7c478bd9Sstevel@tonic-gate string_to_struct(struct uuid *uuid, uuid_t in)
491*7c478bd9Sstevel@tonic-gate {
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	uchar_t 	*ptr;
494*7c478bd9Sstevel@tonic-gate 	uint_t		tmp;
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	ptr = in;
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	tmp = *ptr++;
499*7c478bd9Sstevel@tonic-gate 	tmp = (tmp << 8) | *ptr++;
500*7c478bd9Sstevel@tonic-gate 	tmp = (tmp << 8) | *ptr++;
501*7c478bd9Sstevel@tonic-gate 	tmp = (tmp << 8) | *ptr++;
502*7c478bd9Sstevel@tonic-gate 	uuid->time_low = tmp;
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	tmp = *ptr++;
505*7c478bd9Sstevel@tonic-gate 	tmp = (tmp << 8) | *ptr++;
506*7c478bd9Sstevel@tonic-gate 	uuid->time_mid = tmp;
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	tmp = *ptr++;
509*7c478bd9Sstevel@tonic-gate 	tmp = (tmp << 8) | *ptr++;
510*7c478bd9Sstevel@tonic-gate 	uuid->time_hi_and_version = tmp;
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	tmp = *ptr++;
513*7c478bd9Sstevel@tonic-gate 	uuid->clock_seq_hi_and_reserved = tmp;
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	tmp = *ptr++;
516*7c478bd9Sstevel@tonic-gate 	uuid->clock_seq_low = tmp;
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	(void) memcpy(uuid->node_addr, ptr, 6);
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate }
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate /*
523*7c478bd9Sstevel@tonic-gate  * Name:	uuid_generate_random
524*7c478bd9Sstevel@tonic-gate  *
525*7c478bd9Sstevel@tonic-gate  * Description:	Generates UUID based on DCE Version 4
526*7c478bd9Sstevel@tonic-gate  *
527*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing. uu contains the newly generated UUID
528*7c478bd9Sstevel@tonic-gate  */
529*7c478bd9Sstevel@tonic-gate void
530*7c478bd9Sstevel@tonic-gate uuid_generate_random(uuid_t uu)
531*7c478bd9Sstevel@tonic-gate {
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	struct uuid	uuid;
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	if (uu == NULL)
536*7c478bd9Sstevel@tonic-gate 	    return;
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate 	(void) memset(uu, 0, sizeof (uuid_t));
539*7c478bd9Sstevel@tonic-gate 	(void) memset(&uuid, 0, sizeof (struct uuid));
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 	fill_random_bytes(uu, sizeof (uuid_t));
542*7c478bd9Sstevel@tonic-gate 	string_to_struct(&uuid, uu);
543*7c478bd9Sstevel@tonic-gate 	/*
544*7c478bd9Sstevel@tonic-gate 	 * This is version 4, so say so in the UUID version field (4 bits)
545*7c478bd9Sstevel@tonic-gate 	 */
546*7c478bd9Sstevel@tonic-gate 	uuid.time_hi_and_version |= (1 << 14);
547*7c478bd9Sstevel@tonic-gate 	/*
548*7c478bd9Sstevel@tonic-gate 	 * we don't want the bit 1 to be set also which is for version 1
549*7c478bd9Sstevel@tonic-gate 	 */
550*7c478bd9Sstevel@tonic-gate 	uuid.time_hi_and_version &= VER1_MASK;
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	/*
553*7c478bd9Sstevel@tonic-gate 	 * The variant for this format is the 2 high bits set to 10,
554*7c478bd9Sstevel@tonic-gate 	 * so here it is
555*7c478bd9Sstevel@tonic-gate 	 */
556*7c478bd9Sstevel@tonic-gate 	uuid.clock_seq_hi_and_reserved |= 0x80;
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 	/*
559*7c478bd9Sstevel@tonic-gate 	 * Set MSB of Ethernet address to 1 to indicate that it was generated
560*7c478bd9Sstevel@tonic-gate 	 * randomly
561*7c478bd9Sstevel@tonic-gate 	 */
562*7c478bd9Sstevel@tonic-gate 	uuid.node_addr[0] |= 0x80;
563*7c478bd9Sstevel@tonic-gate 	struct_to_string(uu, &uuid);
564*7c478bd9Sstevel@tonic-gate }
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate /*
567*7c478bd9Sstevel@tonic-gate  * Name:	uuid_generate_time
568*7c478bd9Sstevel@tonic-gate  *
569*7c478bd9Sstevel@tonic-gate  * Description:	Generates UUID based on DCE Version 1.
570*7c478bd9Sstevel@tonic-gate  *
571*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing. uu contains the newly generated UUID.
572*7c478bd9Sstevel@tonic-gate  */
573*7c478bd9Sstevel@tonic-gate void
574*7c478bd9Sstevel@tonic-gate uuid_generate_time(uuid_t uu)
575*7c478bd9Sstevel@tonic-gate {
576*7c478bd9Sstevel@tonic-gate 	struct uuid uuid;
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	if (uu == NULL)
579*7c478bd9Sstevel@tonic-gate 	    return;
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	if (uuid_create(&uuid) == -1) {
582*7c478bd9Sstevel@tonic-gate 	    uuid_generate_random(uu);
583*7c478bd9Sstevel@tonic-gate 	    return;
584*7c478bd9Sstevel@tonic-gate 	}
585*7c478bd9Sstevel@tonic-gate 	struct_to_string(uu, &uuid);
586*7c478bd9Sstevel@tonic-gate }
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate /*
589*7c478bd9Sstevel@tonic-gate  * Name:	uuid_generate
590*7c478bd9Sstevel@tonic-gate  *
591*7c478bd9Sstevel@tonic-gate  * Description:	Creates a new UUID. The uuid will be generated based on
592*7c478bd9Sstevel@tonic-gate  *		high-quality randomness from /dev/urandom, if available by
593*7c478bd9Sstevel@tonic-gate  *		calling uuid_generate_random. If it failed to generate UUID
594*7c478bd9Sstevel@tonic-gate  *		then uuid_generate will call uuid_generate_time.
595*7c478bd9Sstevel@tonic-gate  *
596*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing. uu contains the newly generated UUID.
597*7c478bd9Sstevel@tonic-gate  */
598*7c478bd9Sstevel@tonic-gate void
599*7c478bd9Sstevel@tonic-gate uuid_generate(uuid_t uu)
600*7c478bd9Sstevel@tonic-gate {
601*7c478bd9Sstevel@tonic-gate 	int fd;
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 	if (uu == NULL) {
604*7c478bd9Sstevel@tonic-gate 	    return;
605*7c478bd9Sstevel@tonic-gate 	}
606*7c478bd9Sstevel@tonic-gate 	fd = open(URANDOM_PATH, O_RDONLY);
607*7c478bd9Sstevel@tonic-gate 	if (fd >= 0) {
608*7c478bd9Sstevel@tonic-gate 	    (void) close(fd);
609*7c478bd9Sstevel@tonic-gate 	    uuid_generate_random(uu);
610*7c478bd9Sstevel@tonic-gate 	} else {
611*7c478bd9Sstevel@tonic-gate 	    (void) uuid_generate_time(uu);
612*7c478bd9Sstevel@tonic-gate 	}
613*7c478bd9Sstevel@tonic-gate }
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate /*
616*7c478bd9Sstevel@tonic-gate  * Name:	uuid_copy
617*7c478bd9Sstevel@tonic-gate  *
618*7c478bd9Sstevel@tonic-gate  * Description:	The uuid_copy function copies the UUID variable src to dst
619*7c478bd9Sstevel@tonic-gate  *
620*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing
621*7c478bd9Sstevel@tonic-gate  */
622*7c478bd9Sstevel@tonic-gate void
623*7c478bd9Sstevel@tonic-gate uuid_copy(uuid_t dst, uuid_t src)
624*7c478bd9Sstevel@tonic-gate {
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	(void) memcpy(dst, src, UUID_LEN);
627*7c478bd9Sstevel@tonic-gate }
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate /*
630*7c478bd9Sstevel@tonic-gate  * Name:	uuid_clear
631*7c478bd9Sstevel@tonic-gate  *
632*7c478bd9Sstevel@tonic-gate  * Description:	The uuid_clear function sets the value of the supplied uuid
633*7c478bd9Sstevel@tonic-gate  *		variable uu, to the NULL value.
634*7c478bd9Sstevel@tonic-gate  *
635*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing
636*7c478bd9Sstevel@tonic-gate  */
637*7c478bd9Sstevel@tonic-gate void
638*7c478bd9Sstevel@tonic-gate uuid_clear(uuid_t uu)
639*7c478bd9Sstevel@tonic-gate {
640*7c478bd9Sstevel@tonic-gate 	(void) memset(uu, 0, UUID_LEN);
641*7c478bd9Sstevel@tonic-gate }
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate /*
644*7c478bd9Sstevel@tonic-gate  * Name:	uuid_unparse
645*7c478bd9Sstevel@tonic-gate  *
646*7c478bd9Sstevel@tonic-gate  * Description:	This function converts the supplied UUID uu from the internal
647*7c478bd9Sstevel@tonic-gate  *		binary format into a 36-byte string (plus trailing null char)
648*7c478bd9Sstevel@tonic-gate  *		and stores this value in the character string pointed to by out
649*7c478bd9Sstevel@tonic-gate  *
650*7c478bd9Sstevel@tonic-gate  * Returns:	Nothing.
651*7c478bd9Sstevel@tonic-gate  */
652*7c478bd9Sstevel@tonic-gate void
653*7c478bd9Sstevel@tonic-gate uuid_unparse(uuid_t uu, char *out)
654*7c478bd9Sstevel@tonic-gate {
655*7c478bd9Sstevel@tonic-gate 	struct uuid 	uuid;
656*7c478bd9Sstevel@tonic-gate 	uint16_t	clock_seq;
657*7c478bd9Sstevel@tonic-gate 	char		etheraddr[13];
658*7c478bd9Sstevel@tonic-gate 	int		index = 0, i;
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	/* basic sanity checking */
661*7c478bd9Sstevel@tonic-gate 	if (uu == NULL) {
662*7c478bd9Sstevel@tonic-gate 	    return;
663*7c478bd9Sstevel@tonic-gate 	}
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	/* XXX user should have allocated enough memory */
666*7c478bd9Sstevel@tonic-gate 	/*
667*7c478bd9Sstevel@tonic-gate 	 * if (strlen(out) < UUID_PRINTF_SIZE) {
668*7c478bd9Sstevel@tonic-gate 	 * return;
669*7c478bd9Sstevel@tonic-gate 	 * }
670*7c478bd9Sstevel@tonic-gate 	 */
671*7c478bd9Sstevel@tonic-gate 	string_to_struct(&uuid, uu);
672*7c478bd9Sstevel@tonic-gate 	clock_seq = uuid.clock_seq_hi_and_reserved;
673*7c478bd9Sstevel@tonic-gate 	clock_seq = (clock_seq  << 8) | uuid.clock_seq_low;
674*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 6; i++) {
675*7c478bd9Sstevel@tonic-gate 	    (void) sprintf(&etheraddr[index++], "%.2x", uuid.node_addr[i]);
676*7c478bd9Sstevel@tonic-gate 	    index++;
677*7c478bd9Sstevel@tonic-gate 	}
678*7c478bd9Sstevel@tonic-gate 	etheraddr[index] = '\0';
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 	(void) snprintf(out, 25, "%08x-%04x-%04x-%04x-",
681*7c478bd9Sstevel@tonic-gate 	    uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
682*7c478bd9Sstevel@tonic-gate 		clock_seq);
683*7c478bd9Sstevel@tonic-gate 	(void) strlcat(out, etheraddr, UUID_PRINTF_SIZE);
684*7c478bd9Sstevel@tonic-gate }
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate /*
687*7c478bd9Sstevel@tonic-gate  * Name:	uuid_is_null
688*7c478bd9Sstevel@tonic-gate  *
689*7c478bd9Sstevel@tonic-gate  * Description:	The uuid_is_null function compares the value of the supplied
690*7c478bd9Sstevel@tonic-gate  *		UUID variable uu to the NULL value. If the value is equal
691*7c478bd9Sstevel@tonic-gate  *		to the NULL UUID, 1 is returned, otherwise 0 is returned.
692*7c478bd9Sstevel@tonic-gate  *
693*7c478bd9Sstevel@tonic-gate  * Returns:	0 if uu is NOT null, 1 if uu is NULL.
694*7c478bd9Sstevel@tonic-gate  */
695*7c478bd9Sstevel@tonic-gate int
696*7c478bd9Sstevel@tonic-gate uuid_is_null(uuid_t uu)
697*7c478bd9Sstevel@tonic-gate {
698*7c478bd9Sstevel@tonic-gate 	int		i;
699*7c478bd9Sstevel@tonic-gate 	uuid_t		null_uu;
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	(void) memset(null_uu, 0, sizeof (uuid_t));
702*7c478bd9Sstevel@tonic-gate 	i = memcmp(uu, null_uu, sizeof (uuid_t));
703*7c478bd9Sstevel@tonic-gate 	if (i == 0) {
704*7c478bd9Sstevel@tonic-gate 	/* uu is NULL uuid */
705*7c478bd9Sstevel@tonic-gate 	    return (1);
706*7c478bd9Sstevel@tonic-gate 	} else {
707*7c478bd9Sstevel@tonic-gate 	    return (0);
708*7c478bd9Sstevel@tonic-gate 	}
709*7c478bd9Sstevel@tonic-gate }
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate /*
712*7c478bd9Sstevel@tonic-gate  * Name:	uuid_parse
713*7c478bd9Sstevel@tonic-gate  *
714*7c478bd9Sstevel@tonic-gate  * Description:	uuid_parse converts the UUID string given by 'in' into the
715*7c478bd9Sstevel@tonic-gate  *		internal uuid_t format. The input UUID is a string of the form
716*7c478bd9Sstevel@tonic-gate  *		cefa7a9c-1dd2-11b2-8350-880020adbeef in printf(3C) format.
717*7c478bd9Sstevel@tonic-gate  *		Upon successfully parsing the input string, UUID is stored
718*7c478bd9Sstevel@tonic-gate  *		in the location pointed to by uu
719*7c478bd9Sstevel@tonic-gate  *
720*7c478bd9Sstevel@tonic-gate  * Returns:	0 if the UUID is successfully stored, -1 otherwise.
721*7c478bd9Sstevel@tonic-gate  */
722*7c478bd9Sstevel@tonic-gate int
723*7c478bd9Sstevel@tonic-gate uuid_parse(char *in, uuid_t uu)
724*7c478bd9Sstevel@tonic-gate {
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	char		*ptr, buf[3];
727*7c478bd9Sstevel@tonic-gate 	int		i;
728*7c478bd9Sstevel@tonic-gate 	struct uuid	uuid;
729*7c478bd9Sstevel@tonic-gate 	uint16_t	clock_seq;
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 	/* do some sanity checking */
732*7c478bd9Sstevel@tonic-gate 	if ((strlen(in) != 36) || (uu == NULL) || (in[36] != '\0')) {
733*7c478bd9Sstevel@tonic-gate 	    return (-1);
734*7c478bd9Sstevel@tonic-gate 	}
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	ptr = in;
737*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 36; i++, ptr++) {
738*7c478bd9Sstevel@tonic-gate 	    if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
739*7c478bd9Sstevel@tonic-gate 		if (*ptr != '-') {
740*7c478bd9Sstevel@tonic-gate 		    return (-1);
741*7c478bd9Sstevel@tonic-gate 		}
742*7c478bd9Sstevel@tonic-gate 	    } else {
743*7c478bd9Sstevel@tonic-gate 		if (!isxdigit(*ptr)) {
744*7c478bd9Sstevel@tonic-gate 		    return (-1);
745*7c478bd9Sstevel@tonic-gate 		}
746*7c478bd9Sstevel@tonic-gate 	    }
747*7c478bd9Sstevel@tonic-gate 	}
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 	uuid.time_low = strtoul(in, NULL, 16);
750*7c478bd9Sstevel@tonic-gate 	uuid.time_mid = strtoul(in+9, NULL, 16);
751*7c478bd9Sstevel@tonic-gate 	uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
752*7c478bd9Sstevel@tonic-gate 	clock_seq = strtoul(in+19, NULL, 16);
753*7c478bd9Sstevel@tonic-gate 	uuid.clock_seq_hi_and_reserved = (clock_seq & 0xFF00) >> 8;
754*7c478bd9Sstevel@tonic-gate 	uuid.clock_seq_low = (clock_seq & 0xFF);
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	ptr = in+24;
757*7c478bd9Sstevel@tonic-gate 	buf[2] = '\0';
758*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 6; i++) {
759*7c478bd9Sstevel@tonic-gate 	    buf[0] = *ptr++;
760*7c478bd9Sstevel@tonic-gate 	    buf[1] = *ptr++;
761*7c478bd9Sstevel@tonic-gate 	    uuid.node_addr[i] = strtoul(buf, NULL, 16);
762*7c478bd9Sstevel@tonic-gate 	}
763*7c478bd9Sstevel@tonic-gate 	struct_to_string(uu, &uuid);
764*7c478bd9Sstevel@tonic-gate 	return (0);
765*7c478bd9Sstevel@tonic-gate }
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate /*
768*7c478bd9Sstevel@tonic-gate  * Name:	uuid_time
769*7c478bd9Sstevel@tonic-gate  *
770*7c478bd9Sstevel@tonic-gate  * Description:	uuid_time extracts the time at which the supplied UUID uu
771*7c478bd9Sstevel@tonic-gate  *		was created. This function can only extract the creation
772*7c478bd9Sstevel@tonic-gate  *		time for UUIDs created with the uuid_generate_time function.
773*7c478bd9Sstevel@tonic-gate  *		The time at which the UUID was created, in seconds and
774*7c478bd9Sstevel@tonic-gate  *		microseconds since the epoch is stored in the location
775*7c478bd9Sstevel@tonic-gate  *		pointed to by ret_tv.
776*7c478bd9Sstevel@tonic-gate  *
777*7c478bd9Sstevel@tonic-gate  * Returns:	The time at which the UUID was created, in seconds since
778*7c478bd9Sstevel@tonic-gate  *		January  1, 1970 GMT (the epoch). -1 otherwise.
779*7c478bd9Sstevel@tonic-gate  */
780*7c478bd9Sstevel@tonic-gate time_t
781*7c478bd9Sstevel@tonic-gate uuid_time(uuid_t uu, struct timeval *ret_tv)
782*7c478bd9Sstevel@tonic-gate {
783*7c478bd9Sstevel@tonic-gate 	struct uuid	uuid;
784*7c478bd9Sstevel@tonic-gate 	uint_t		high;
785*7c478bd9Sstevel@tonic-gate 	struct timeval	tv;
786*7c478bd9Sstevel@tonic-gate 	u_longlong_t	clock_reg;
787*7c478bd9Sstevel@tonic-gate 	uint_t		tmp;
788*7c478bd9Sstevel@tonic-gate 	uint8_t		clk;
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	string_to_struct(&uuid, uu);
791*7c478bd9Sstevel@tonic-gate 	tmp = (uuid.time_hi_and_version & 0xF000) >> 12;
792*7c478bd9Sstevel@tonic-gate 	clk = uuid.clock_seq_hi_and_reserved;
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	/* check if uu is NULL, Version = 1 of DCE and Variant = 0b10x */
795*7c478bd9Sstevel@tonic-gate 	if ((uu == NULL) || ((tmp & 0x01) != 0x01) || ((clk & 0x80) != 0x80)) {
796*7c478bd9Sstevel@tonic-gate 	    return (-1);
797*7c478bd9Sstevel@tonic-gate 	}
798*7c478bd9Sstevel@tonic-gate 	high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
799*7c478bd9Sstevel@tonic-gate 	clock_reg = uuid.time_low | ((u_longlong_t)high << 32);
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 	clock_reg -= (((u_longlong_t)0x01B21DD2) << 32) + 0x13814000;
802*7c478bd9Sstevel@tonic-gate 	tv.tv_sec = clock_reg / 10000000;
803*7c478bd9Sstevel@tonic-gate 	tv.tv_usec = (clock_reg % 10000000) / 10;
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	if (ret_tv) {
806*7c478bd9Sstevel@tonic-gate 	    *ret_tv = tv;
807*7c478bd9Sstevel@tonic-gate 	}
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 	return (tv.tv_sec);
810*7c478bd9Sstevel@tonic-gate }
811