8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libuuid / common / uuid.c
blob481f11082a788048fd5b8687cf517397c6c403d4
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 * Copyright 2015 Joyent, Inc. All rights reserved.
26 * Copyright 2014 Andrew Stormont.
30 * The copyright in this file is taken from the original Leach & Salz
31 * UUID specification, from which this implementation is derived.
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.
53 * This module is the workhorse for generating abstract
54 * UUIDs. It delegates system-specific tasks (such
55 * as obtaining the node identifier or system time)
56 * to the sysdep module.
59 #include <ctype.h>
60 #include <sys/param.h>
61 #include <sys/stat.h>
62 #include <errno.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <strings.h>
66 #include <fcntl.h>
67 #include <unistd.h>
68 #include <synch.h>
69 #include <sys/mman.h>
70 #include "uuid_misc.h"
72 shared_buffer_t *data;
74 static uuid_node_t node_id_cache;
75 static int node_init;
76 static int file_type;
77 static int fd;
80 * misc routines
82 uint16_t get_random(void);
83 void get_current_time(uuid_time_t *);
85 void struct_to_string(uuid_t, struct uuid *);
86 void string_to_struct(struct uuid *, uuid_t);
87 int get_ethernet_address(uuid_node_t *);
90 * local functions
92 static int map_state();
93 static void format_uuid(struct uuid *, uint16_t, uuid_time_t,
94 uuid_node_t);
95 static int uuid_create(struct uuid *);
96 static void gen_ethernet_address(uuid_node_t *);
97 static void revalidate_data(uuid_node_t *);
100 * Generates a uuid based on version 1 format.
101 * Returns 0 on success and -1 on failure.
103 static int
104 uuid_create(struct uuid *uuid)
106 uuid_time_t timestamp;
107 uuid_node_t system_node;
108 int ret, non_unique = 0;
111 * Get the system MAC address and/or cache it
113 if (node_init) {
114 bcopy(&node_id_cache, &system_node, sizeof (uuid_node_t));
115 } else {
116 gen_ethernet_address(&system_node);
117 bcopy(&system_node, &node_id_cache, sizeof (uuid_node_t));
118 node_init = 1;
122 * Access the state file, mmap it and initialize the shared lock.
123 * file_type tells us whether we had access to the state file or
124 * created a temporary one.
126 if (map_state() == -1)
127 return (-1);
130 * Acquire the lock
132 for (;;) {
133 if ((ret = mutex_lock(&data->lock)) == 0)
134 break;
135 else
136 switch (ret) {
137 case EOWNERDEAD:
138 revalidate_data(&system_node);
139 (void) mutex_consistent(&data->lock);
140 (void) mutex_unlock(&data->lock);
141 break;
142 case ENOTRECOVERABLE:
143 return (ret);
147 /* State file is either new or is temporary, get a random clock seq */
148 if (data->state.clock == 0) {
149 data->state.clock = get_random();
150 non_unique++;
153 if (memcmp(&system_node, &data->state.node, sizeof (uuid_node_t)) != 0)
154 data->state.clock++;
156 get_current_time(&timestamp);
159 * If timestamp is not set or is not in the past, bump
160 * data->state.clock
162 if ((data->state.ts == 0) || (data->state.ts >= timestamp)) {
163 data->state.clock++;
164 data->state.ts = timestamp;
167 if (non_unique)
168 system_node.nodeID[0] |= 0x80;
170 /* Stuff fields into the UUID struct */
171 format_uuid(uuid, data->state.clock, timestamp, system_node);
173 (void) mutex_unlock(&data->lock);
175 return (0);
179 * Fills system_node with Ethernet address if available,
180 * else fills random numbers
182 static void
183 gen_ethernet_address(uuid_node_t *system_node)
185 uchar_t node[6];
187 if (get_ethernet_address(system_node) != 0) {
188 arc4random_buf(node, 6);
189 (void) memcpy(system_node->nodeID, node, 6);
191 * use 8:0:20 with the multicast bit set
192 * to avoid namespace collisions.
194 system_node->nodeID[0] = 0x88;
195 system_node->nodeID[1] = 0x00;
196 system_node->nodeID[2] = 0x20;
201 * Formats a UUID, given the clock_seq timestamp, and node address.
202 * Fills in passed-in pointer with the resulting uuid.
204 static void
205 format_uuid(struct uuid *uuid, uint16_t clock_seq,
206 uuid_time_t timestamp, uuid_node_t node)
210 * First set up the first 60 bits from the timestamp
212 uuid->time_low = (uint32_t)(timestamp & 0xFFFFFFFF);
213 uuid->time_mid = (uint16_t)((timestamp >> 32) & 0xFFFF);
214 uuid->time_hi_and_version = (uint16_t)((timestamp >> 48) & 0x0FFF);
217 * This is version 1, so say so in the UUID version field (4 bits)
219 uuid->time_hi_and_version |= (1 << 12);
222 * Now do the clock sequence
224 uuid->clock_seq_low = clock_seq & 0xFF;
227 * We must save the most-significant 2 bits for the reserved field
229 uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
232 * The variant for this format is the 2 high bits set to 10,
233 * so here it is
235 uuid->clock_seq_hi_and_reserved |= 0x80;
238 * write result to passed-in pointer
240 (void) memcpy(&uuid->node_addr, &node, sizeof (uuid->node_addr));
244 * Opens/creates the state file, falling back to a tmp
246 static int
247 map_state()
249 FILE *tmp;
251 /* If file's mapped, return */
252 if (file_type != 0)
253 return (1);
255 if ((fd = open(STATE_LOCATION, O_RDWR)) < 0) {
256 file_type = TEMP_FILE;
258 if ((tmp = tmpfile()) == NULL)
259 return (-1);
260 else
261 fd = fileno(tmp);
262 } else {
263 file_type = STATE_FILE;
266 (void) ftruncate(fd, (off_t)sizeof (shared_buffer_t));
268 /* LINTED - alignment */
269 data = (shared_buffer_t *)mmap(NULL, sizeof (shared_buffer_t),
270 PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
272 if (data == MAP_FAILED)
273 return (-1);
275 (void) mutex_init(&data->lock, USYNC_PROCESS|LOCK_ROBUST, 0);
277 (void) close(fd);
279 return (1);
282 static void
283 revalidate_data(uuid_node_t *node)
285 int i;
287 data->state.ts = 0;
289 for (i = 0; i < sizeof (data->state.node.nodeID); i++)
290 data->state.node.nodeID[i] = 0;
292 data->state.clock = 0;
294 gen_ethernet_address(node);
295 bcopy(node, &node_id_cache, sizeof (uuid_node_t));
296 node_init = 1;
300 * Prints a nicely-formatted uuid to stdout.
302 void
303 uuid_print(struct uuid u)
305 int i;
307 (void) printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
308 u.time_hi_and_version, u.clock_seq_hi_and_reserved,
309 u.clock_seq_low);
310 for (i = 0; i < 6; i++)
311 (void) printf("%2.2x", u.node_addr[i]);
312 (void) printf("\n");
316 * Unpacks the structure members in "struct uuid" to a char string "uuid_t".
318 void
319 struct_to_string(uuid_t ptr, struct uuid *uu)
321 uint_t tmp;
322 uchar_t *out = ptr;
324 tmp = uu->time_low;
325 out[3] = (uchar_t)tmp;
326 tmp >>= 8;
327 out[2] = (uchar_t)tmp;
328 tmp >>= 8;
329 out[1] = (uchar_t)tmp;
330 tmp >>= 8;
331 out[0] = (uchar_t)tmp;
333 tmp = uu->time_mid;
334 out[5] = (uchar_t)tmp;
335 tmp >>= 8;
336 out[4] = (uchar_t)tmp;
338 tmp = uu->time_hi_and_version;
339 out[7] = (uchar_t)tmp;
340 tmp >>= 8;
341 out[6] = (uchar_t)tmp;
343 tmp = uu->clock_seq_hi_and_reserved;
344 out[8] = (uchar_t)tmp;
345 tmp = uu->clock_seq_low;
346 out[9] = (uchar_t)tmp;
348 (void) memcpy(out+10, uu->node_addr, 6);
353 * Packs the values in the "uuid_t" string into "struct uuid".
355 void
356 string_to_struct(struct uuid *uuid, uuid_t in)
358 uchar_t *ptr;
359 uint_t tmp;
361 ptr = in;
363 tmp = *ptr++;
364 tmp = (tmp << 8) | *ptr++;
365 tmp = (tmp << 8) | *ptr++;
366 tmp = (tmp << 8) | *ptr++;
367 uuid->time_low = tmp;
369 tmp = *ptr++;
370 tmp = (tmp << 8) | *ptr++;
371 uuid->time_mid = tmp;
373 tmp = *ptr++;
374 tmp = (tmp << 8) | *ptr++;
375 uuid->time_hi_and_version = tmp;
377 tmp = *ptr++;
378 uuid->clock_seq_hi_and_reserved = tmp;
380 tmp = *ptr++;
381 uuid->clock_seq_low = tmp;
383 (void) memcpy(uuid->node_addr, ptr, 6);
388 * Generates UUID based on DCE Version 4
390 void
391 uuid_generate_random(uuid_t uu)
393 struct uuid uuid;
395 if (uu == NULL)
396 return;
398 (void) memset(uu, 0, sizeof (uuid_t));
399 (void) memset(&uuid, 0, sizeof (struct uuid));
401 arc4random_buf(uu, sizeof (uuid_t));
402 string_to_struct(&uuid, uu);
404 * This is version 4, so say so in the UUID version field (4 bits)
406 uuid.time_hi_and_version |= (1 << 14);
408 * we don't want the bit 1 to be set also which is for version 1
410 uuid.time_hi_and_version &= VER1_MASK;
413 * The variant for this format is the 2 high bits set to 10,
414 * so here it is
416 uuid.clock_seq_hi_and_reserved |= 0x80;
419 * Set MSB of Ethernet address to 1 to indicate that it was generated
420 * randomly
422 uuid.node_addr[0] |= 0x80;
423 struct_to_string(uu, &uuid);
427 * Generates UUID based on DCE Version 1.
429 void
430 uuid_generate_time(uuid_t uu)
432 struct uuid uuid;
434 if (uu == NULL)
435 return;
437 if (uuid_create(&uuid) < 0) {
438 uuid_generate_random(uu);
439 return;
442 struct_to_string(uu, &uuid);
446 * Creates a new UUID. The uuid will be generated based on high-quality
447 * randomness from arc4random(3C).
449 void
450 uuid_generate(uuid_t uu)
452 uuid_generate_random(uu);
456 * Copies the UUID variable src to dst.
458 void
459 uuid_copy(uuid_t dst, uuid_t src)
461 (void) memcpy(dst, src, UUID_LEN);
465 * Sets the value of the supplied uuid variable uu, to the NULL value.
467 void
468 uuid_clear(uuid_t uu)
470 (void) memset(uu, 0, UUID_LEN);
474 * This function converts the supplied UUID uu from the internal
475 * binary format into a 36-byte string (plus trailing null char)
476 * and stores this value in the character string pointed to by out.
478 static void
479 uuid_unparse_common(uuid_t uu, char *out, boolean_t upper)
481 struct uuid uuid;
482 uint16_t clock_seq;
483 char etheraddr[13];
484 int index = 0, i;
486 /* basic sanity checking */
487 if (uu == NULL) {
488 return;
491 string_to_struct(&uuid, uu);
492 clock_seq = uuid.clock_seq_hi_and_reserved;
493 clock_seq = (clock_seq << 8) | uuid.clock_seq_low;
494 for (i = 0; i < 6; i++) {
495 (void) sprintf(&etheraddr[index++], upper ? "%.2X" : "%.2x",
496 uuid.node_addr[i]);
497 index++;
499 etheraddr[index] = '\0';
501 (void) snprintf(out, 25,
502 upper ? "%08X-%04X-%04X-%04X-" : "%08x-%04x-%04x-%04x-",
503 uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, clock_seq);
504 (void) strlcat(out, etheraddr, UUID_PRINTABLE_STRING_LENGTH);
507 void
508 uuid_unparse_upper(uuid_t uu, char *out)
510 uuid_unparse_common(uu, out, B_TRUE);
513 void
514 uuid_unparse_lower(uuid_t uu, char *out)
516 uuid_unparse_common(uu, out, B_FALSE);
519 void
520 uuid_unparse(uuid_t uu, char *out)
523 * Historically uuid_unparse on Solaris returns lower case,
524 * for compatibility we preserve this behaviour.
526 uuid_unparse_common(uu, out, B_FALSE);
530 * The uuid_is_null function compares the value of the supplied
531 * UUID variable uu to the NULL value. If the value is equal
532 * to the NULL UUID, 1 is returned, otherwise 0 is returned.
535 uuid_is_null(uuid_t uu)
537 int i;
538 uuid_t null_uu;
540 (void) memset(null_uu, 0, sizeof (uuid_t));
541 i = memcmp(uu, null_uu, sizeof (uuid_t));
542 if (i == 0) {
543 /* uu is NULL uuid */
544 return (1);
545 } else {
546 return (0);
551 * uuid_parse converts the UUID string given by 'in' into the
552 * internal uuid_t format. The input UUID is a string of the form
553 * cefa7a9c-1dd2-11b2-8350-880020adbeef in printf(3C) format.
554 * Upon successfully parsing the input string, UUID is stored
555 * in the location pointed to by uu
558 uuid_parse(char *in, uuid_t uu)
561 char *ptr, buf[3];
562 int i;
563 struct uuid uuid;
564 uint16_t clock_seq;
566 /* do some sanity checking */
567 if ((strlen(in) != 36) || (uu == NULL) || (in[36] != '\0')) {
568 return (-1);
571 ptr = in;
572 for (i = 0; i < 36; i++, ptr++) {
573 if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
574 if (*ptr != '-') {
575 return (-1);
577 } else {
578 if (!isxdigit(*ptr)) {
579 return (-1);
584 uuid.time_low = strtoul(in, NULL, 16);
585 uuid.time_mid = strtoul(in+9, NULL, 16);
586 uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
587 clock_seq = strtoul(in+19, NULL, 16);
588 uuid.clock_seq_hi_and_reserved = (clock_seq & 0xFF00) >> 8;
589 uuid.clock_seq_low = (clock_seq & 0xFF);
591 ptr = in+24;
592 buf[2] = '\0';
593 for (i = 0; i < 6; i++) {
594 buf[0] = *ptr++;
595 buf[1] = *ptr++;
596 uuid.node_addr[i] = strtoul(buf, NULL, 16);
598 struct_to_string(uu, &uuid);
599 return (0);
603 * uuid_time extracts the time at which the supplied UUID uu
604 * was created. This function can only extract the creation
605 * time for UUIDs created with the uuid_generate_time function.
606 * The time at which the UUID was created, in seconds and
607 * microseconds since the epoch is stored in the location
608 * pointed to by ret_tv.
610 time_t
611 uuid_time(uuid_t uu, struct timeval *ret_tv)
613 struct uuid uuid;
614 uint_t high;
615 struct timeval tv;
616 u_longlong_t clock_reg;
617 uint_t tmp;
618 uint8_t clk;
620 string_to_struct(&uuid, uu);
621 tmp = (uuid.time_hi_and_version & 0xF000) >> 12;
622 clk = uuid.clock_seq_hi_and_reserved;
624 /* check if uu is NULL, Version = 1 of DCE and Variant = 0b10x */
625 if ((uu == NULL) || ((tmp & 0x01) != 0x01) || ((clk & 0x80) != 0x80)) {
626 return (-1);
628 high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
629 clock_reg = uuid.time_low | ((u_longlong_t)high << 32);
631 clock_reg -= (((u_longlong_t)0x01B21DD2) << 32) + 0x13814000;
632 tv.tv_sec = clock_reg / 10000000;
633 tv.tv_usec = (clock_reg % 10000000) / 10;
635 if (ret_tv) {
636 *ret_tv = tv;
639 return (tv.tv_sec);