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(×tamp); 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(ðeraddr[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