Print this page
3087 libuuid has a lot of dependencies
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libuuid/common/uuid.c
+++ new/usr/src/lib/libuuid/common/uuid.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 * Copyright 2012 Milan Jurik. All rights reserved.
25 25 * Copyright 2015 Joyent, Inc. All rights reserved.
26 26 * Copyright 2014 Andrew Stormont.
27 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 28 */
28 29
29 30 /*
30 31 * The copyright in this file is taken from the original Leach & Salz
31 32 * UUID specification, from which this implementation is derived.
32 33 */
33 34
34 35 /*
35 36 * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
36 37 * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
37 38 * Digital Equipment Corporation, Maynard, Mass. Copyright (c) 1998
38 39 * Microsoft. To anyone who acknowledges that this file is provided
39 40 * "AS IS" without any express or implied warranty: permission to use,
40 41 * copy, modify, and distribute this file for any purpose is hereby
41 42 * granted without fee, provided that the above copyright notices and
42 43 * this notice appears in all source code copies, and that none of the
43 44 * names of Open Software Foundation, Inc., Hewlett-Packard Company,
44 45 * or Digital Equipment Corporation be used in advertising or
45 46 * publicity pertaining to distribution of the software without
46 47 * specific, written prior permission. Neither Open Software
47 48 * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
48 49 * Equipment Corporation makes any representations about the
49 50 * suitability of this software for any purpose.
50 51 */
51 52
52 53 /*
53 54 * This module is the workhorse for generating abstract
54 55 * UUIDs. It delegates system-specific tasks (such
55 56 * as obtaining the node identifier or system time)
56 57 * to the sysdep module.
57 58 */
58 59
59 60 #include <ctype.h>
60 61 #include <sys/param.h>
61 62 #include <sys/stat.h>
62 63 #include <errno.h>
63 64 #include <stdio.h>
64 65 #include <stdlib.h>
65 66 #include <strings.h>
66 67 #include <fcntl.h>
67 68 #include <unistd.h>
68 69 #include <synch.h>
69 70 #include <sys/mman.h>
70 71 #include "uuid_misc.h"
71 72
72 73 shared_buffer_t *data;
73 74
74 75 static uuid_node_t node_id_cache;
75 76 static int node_init;
76 77 static int file_type;
77 78 static int fd;
78 79
79 80 /*
80 81 * misc routines
81 82 */
82 83 uint16_t get_random(void);
83 84 void get_current_time(uuid_time_t *);
84 85
85 86 void struct_to_string(uuid_t, struct uuid *);
86 87 void string_to_struct(struct uuid *, uuid_t);
87 88 int get_ethernet_address(uuid_node_t *);
88 89
89 90 /*
90 91 * local functions
91 92 */
92 93 static int map_state();
93 94 static void format_uuid(struct uuid *, uint16_t, uuid_time_t,
94 95 uuid_node_t);
95 96 static int uuid_create(struct uuid *);
96 97 static void gen_ethernet_address(uuid_node_t *);
97 98 static void revalidate_data(uuid_node_t *);
98 99
99 100 /*
100 101 * Generates a uuid based on version 1 format.
101 102 * Returns 0 on success and -1 on failure.
102 103 */
103 104 static int
104 105 uuid_create(struct uuid *uuid)
105 106 {
106 107 uuid_time_t timestamp;
107 108 uuid_node_t system_node;
108 109 int ret, non_unique = 0;
109 110
110 111 /*
111 112 * Get the system MAC address and/or cache it
112 113 */
113 114 if (node_init) {
114 115 bcopy(&node_id_cache, &system_node, sizeof (uuid_node_t));
115 116 } else {
116 117 gen_ethernet_address(&system_node);
117 118 bcopy(&system_node, &node_id_cache, sizeof (uuid_node_t));
118 119 node_init = 1;
119 120 }
120 121
121 122 /*
122 123 * Access the state file, mmap it and initialize the shared lock.
123 124 * file_type tells us whether we had access to the state file or
124 125 * created a temporary one.
125 126 */
126 127 if (map_state() == -1)
127 128 return (-1);
128 129
129 130 /*
130 131 * Acquire the lock
131 132 */
132 133 for (;;) {
133 134 if ((ret = mutex_lock(&data->lock)) == 0)
134 135 break;
135 136 else
136 137 switch (ret) {
137 138 case EOWNERDEAD:
138 139 revalidate_data(&system_node);
139 140 (void) mutex_consistent(&data->lock);
140 141 (void) mutex_unlock(&data->lock);
141 142 break;
142 143 case ENOTRECOVERABLE:
143 144 return (ret);
144 145 }
145 146 }
146 147
147 148 /* State file is either new or is temporary, get a random clock seq */
148 149 if (data->state.clock == 0) {
149 150 data->state.clock = get_random();
150 151 non_unique++;
151 152 }
152 153
153 154 if (memcmp(&system_node, &data->state.node, sizeof (uuid_node_t)) != 0)
154 155 data->state.clock++;
155 156
156 157 get_current_time(×tamp);
157 158
158 159 /*
159 160 * If timestamp is not set or is not in the past, bump
160 161 * data->state.clock
161 162 */
162 163 if ((data->state.ts == 0) || (data->state.ts >= timestamp)) {
163 164 data->state.clock++;
164 165 data->state.ts = timestamp;
165 166 }
166 167
167 168 if (non_unique)
168 169 system_node.nodeID[0] |= 0x80;
169 170
170 171 /* Stuff fields into the UUID struct */
171 172 format_uuid(uuid, data->state.clock, timestamp, system_node);
172 173
173 174 (void) mutex_unlock(&data->lock);
174 175
175 176 return (0);
176 177 }
177 178
178 179 /*
179 180 * Fills system_node with Ethernet address if available,
180 181 * else fills random numbers
↓ open down ↓ |
144 lines elided |
↑ open up ↑ |
181 182 */
182 183 static void
183 184 gen_ethernet_address(uuid_node_t *system_node)
184 185 {
185 186 uchar_t node[6];
186 187
187 188 if (get_ethernet_address(system_node) != 0) {
188 189 arc4random_buf(node, 6);
189 190 (void) memcpy(system_node->nodeID, node, 6);
190 191 /*
191 - * use 8:0:20 with the multicast bit set
192 - * to avoid namespace collisions.
192 + * use 8:.. with the multicast bit set
193 + * to reduce namespace collisions.
193 194 */
194 195 system_node->nodeID[0] = 0x88;
195 - system_node->nodeID[1] = 0x00;
196 - system_node->nodeID[2] = 0x20;
197 196 }
198 197 }
199 198
200 199 /*
201 200 * Formats a UUID, given the clock_seq timestamp, and node address.
202 201 * Fills in passed-in pointer with the resulting uuid.
203 202 */
204 203 static void
205 204 format_uuid(struct uuid *uuid, uint16_t clock_seq,
206 205 uuid_time_t timestamp, uuid_node_t node)
207 206 {
208 207
209 208 /*
210 209 * First set up the first 60 bits from the timestamp
211 210 */
212 211 uuid->time_low = (uint32_t)(timestamp & 0xFFFFFFFF);
213 212 uuid->time_mid = (uint16_t)((timestamp >> 32) & 0xFFFF);
214 213 uuid->time_hi_and_version = (uint16_t)((timestamp >> 48) & 0x0FFF);
215 214
216 215 /*
217 216 * This is version 1, so say so in the UUID version field (4 bits)
218 217 */
219 218 uuid->time_hi_and_version |= (1 << 12);
220 219
221 220 /*
222 221 * Now do the clock sequence
223 222 */
224 223 uuid->clock_seq_low = clock_seq & 0xFF;
225 224
226 225 /*
227 226 * We must save the most-significant 2 bits for the reserved field
228 227 */
229 228 uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
230 229
231 230 /*
232 231 * The variant for this format is the 2 high bits set to 10,
233 232 * so here it is
234 233 */
235 234 uuid->clock_seq_hi_and_reserved |= 0x80;
236 235
237 236 /*
238 237 * write result to passed-in pointer
239 238 */
240 239 (void) memcpy(&uuid->node_addr, &node, sizeof (uuid->node_addr));
241 240 }
242 241
243 242 /*
244 243 * Opens/creates the state file, falling back to a tmp
245 244 */
246 245 static int
247 246 map_state()
248 247 {
249 248 FILE *tmp;
250 249
251 250 /* If file's mapped, return */
252 251 if (file_type != 0)
253 252 return (1);
254 253
255 254 if ((fd = open(STATE_LOCATION, O_RDWR)) < 0) {
256 255 file_type = TEMP_FILE;
257 256
258 257 if ((tmp = tmpfile()) == NULL)
259 258 return (-1);
260 259 else
261 260 fd = fileno(tmp);
262 261 } else {
263 262 file_type = STATE_FILE;
264 263 }
265 264
266 265 (void) ftruncate(fd, (off_t)sizeof (shared_buffer_t));
267 266
268 267 /* LINTED - alignment */
269 268 data = (shared_buffer_t *)mmap(NULL, sizeof (shared_buffer_t),
270 269 PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
271 270
272 271 if (data == MAP_FAILED)
273 272 return (-1);
274 273
275 274 (void) mutex_init(&data->lock, USYNC_PROCESS|LOCK_ROBUST, 0);
276 275
277 276 (void) close(fd);
278 277
279 278 return (1);
280 279 }
281 280
282 281 static void
283 282 revalidate_data(uuid_node_t *node)
284 283 {
285 284 int i;
286 285
287 286 data->state.ts = 0;
288 287
289 288 for (i = 0; i < sizeof (data->state.node.nodeID); i++)
290 289 data->state.node.nodeID[i] = 0;
291 290
292 291 data->state.clock = 0;
293 292
294 293 gen_ethernet_address(node);
295 294 bcopy(node, &node_id_cache, sizeof (uuid_node_t));
296 295 node_init = 1;
297 296 }
298 297
299 298 /*
300 299 * Prints a nicely-formatted uuid to stdout.
301 300 */
302 301 void
303 302 uuid_print(struct uuid u)
304 303 {
305 304 int i;
306 305
307 306 (void) printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
308 307 u.time_hi_and_version, u.clock_seq_hi_and_reserved,
309 308 u.clock_seq_low);
310 309 for (i = 0; i < 6; i++)
311 310 (void) printf("%2.2x", u.node_addr[i]);
312 311 (void) printf("\n");
313 312 }
314 313
315 314 /*
316 315 * Unpacks the structure members in "struct uuid" to a char string "uuid_t".
317 316 */
318 317 void
319 318 struct_to_string(uuid_t ptr, struct uuid *uu)
320 319 {
321 320 uint_t tmp;
322 321 uchar_t *out = ptr;
323 322
324 323 tmp = uu->time_low;
325 324 out[3] = (uchar_t)tmp;
326 325 tmp >>= 8;
327 326 out[2] = (uchar_t)tmp;
328 327 tmp >>= 8;
329 328 out[1] = (uchar_t)tmp;
330 329 tmp >>= 8;
331 330 out[0] = (uchar_t)tmp;
332 331
333 332 tmp = uu->time_mid;
334 333 out[5] = (uchar_t)tmp;
335 334 tmp >>= 8;
336 335 out[4] = (uchar_t)tmp;
337 336
338 337 tmp = uu->time_hi_and_version;
339 338 out[7] = (uchar_t)tmp;
340 339 tmp >>= 8;
341 340 out[6] = (uchar_t)tmp;
342 341
343 342 tmp = uu->clock_seq_hi_and_reserved;
344 343 out[8] = (uchar_t)tmp;
345 344 tmp = uu->clock_seq_low;
346 345 out[9] = (uchar_t)tmp;
347 346
348 347 (void) memcpy(out+10, uu->node_addr, 6);
349 348
350 349 }
351 350
352 351 /*
353 352 * Packs the values in the "uuid_t" string into "struct uuid".
354 353 */
355 354 void
356 355 string_to_struct(struct uuid *uuid, uuid_t in)
357 356 {
358 357 uchar_t *ptr;
359 358 uint_t tmp;
360 359
361 360 ptr = in;
362 361
363 362 tmp = *ptr++;
364 363 tmp = (tmp << 8) | *ptr++;
365 364 tmp = (tmp << 8) | *ptr++;
366 365 tmp = (tmp << 8) | *ptr++;
367 366 uuid->time_low = tmp;
368 367
369 368 tmp = *ptr++;
370 369 tmp = (tmp << 8) | *ptr++;
371 370 uuid->time_mid = tmp;
372 371
373 372 tmp = *ptr++;
374 373 tmp = (tmp << 8) | *ptr++;
375 374 uuid->time_hi_and_version = tmp;
376 375
377 376 tmp = *ptr++;
378 377 uuid->clock_seq_hi_and_reserved = tmp;
379 378
380 379 tmp = *ptr++;
381 380 uuid->clock_seq_low = tmp;
382 381
383 382 (void) memcpy(uuid->node_addr, ptr, 6);
384 383
385 384 }
386 385
387 386 /*
388 387 * Generates UUID based on DCE Version 4
389 388 */
390 389 void
391 390 uuid_generate_random(uuid_t uu)
392 391 {
393 392 struct uuid uuid;
394 393
395 394 if (uu == NULL)
396 395 return;
397 396
398 397 (void) memset(uu, 0, sizeof (uuid_t));
399 398 (void) memset(&uuid, 0, sizeof (struct uuid));
400 399
401 400 arc4random_buf(uu, sizeof (uuid_t));
402 401 string_to_struct(&uuid, uu);
403 402 /*
404 403 * This is version 4, so say so in the UUID version field (4 bits)
405 404 */
406 405 uuid.time_hi_and_version |= (1 << 14);
407 406 /*
408 407 * we don't want the bit 1 to be set also which is for version 1
409 408 */
410 409 uuid.time_hi_and_version &= VER1_MASK;
411 410
412 411 /*
413 412 * The variant for this format is the 2 high bits set to 10,
414 413 * so here it is
415 414 */
416 415 uuid.clock_seq_hi_and_reserved |= 0x80;
417 416
418 417 /*
419 418 * Set MSB of Ethernet address to 1 to indicate that it was generated
420 419 * randomly
421 420 */
422 421 uuid.node_addr[0] |= 0x80;
423 422 struct_to_string(uu, &uuid);
424 423 }
425 424
426 425 /*
427 426 * Generates UUID based on DCE Version 1.
428 427 */
429 428 void
430 429 uuid_generate_time(uuid_t uu)
431 430 {
432 431 struct uuid uuid;
433 432
434 433 if (uu == NULL)
435 434 return;
436 435
437 436 if (uuid_create(&uuid) < 0) {
438 437 uuid_generate_random(uu);
439 438 return;
440 439 }
441 440
442 441 struct_to_string(uu, &uuid);
443 442 }
444 443
445 444 /*
446 445 * Creates a new UUID. The uuid will be generated based on high-quality
447 446 * randomness from arc4random(3C).
448 447 */
449 448 void
450 449 uuid_generate(uuid_t uu)
451 450 {
452 451 uuid_generate_random(uu);
453 452 }
454 453
455 454 /*
456 455 * Copies the UUID variable src to dst.
457 456 */
458 457 void
459 458 uuid_copy(uuid_t dst, uuid_t src)
460 459 {
461 460 (void) memcpy(dst, src, UUID_LEN);
462 461 }
463 462
464 463 /*
465 464 * Sets the value of the supplied uuid variable uu, to the NULL value.
466 465 */
467 466 void
468 467 uuid_clear(uuid_t uu)
469 468 {
470 469 (void) memset(uu, 0, UUID_LEN);
471 470 }
472 471
473 472 /*
474 473 * This function converts the supplied UUID uu from the internal
475 474 * binary format into a 36-byte string (plus trailing null char)
476 475 * and stores this value in the character string pointed to by out.
477 476 */
478 477 static void
479 478 uuid_unparse_common(uuid_t uu, char *out, boolean_t upper)
480 479 {
481 480 struct uuid uuid;
482 481 uint16_t clock_seq;
483 482 char etheraddr[13];
484 483 int index = 0, i;
485 484
486 485 /* basic sanity checking */
487 486 if (uu == NULL) {
488 487 return;
489 488 }
490 489
491 490 string_to_struct(&uuid, uu);
492 491 clock_seq = uuid.clock_seq_hi_and_reserved;
493 492 clock_seq = (clock_seq << 8) | uuid.clock_seq_low;
494 493 for (i = 0; i < 6; i++) {
495 494 (void) sprintf(ðeraddr[index++], upper ? "%.2X" : "%.2x",
496 495 uuid.node_addr[i]);
497 496 index++;
498 497 }
499 498 etheraddr[index] = '\0';
500 499
501 500 (void) snprintf(out, 25,
502 501 upper ? "%08X-%04X-%04X-%04X-" : "%08x-%04x-%04x-%04x-",
503 502 uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, clock_seq);
504 503 (void) strlcat(out, etheraddr, UUID_PRINTABLE_STRING_LENGTH);
505 504 }
506 505
507 506 void
508 507 uuid_unparse_upper(uuid_t uu, char *out)
509 508 {
510 509 uuid_unparse_common(uu, out, B_TRUE);
511 510 }
512 511
513 512 void
514 513 uuid_unparse_lower(uuid_t uu, char *out)
515 514 {
516 515 uuid_unparse_common(uu, out, B_FALSE);
517 516 }
518 517
519 518 void
520 519 uuid_unparse(uuid_t uu, char *out)
521 520 {
522 521 /*
523 522 * Historically uuid_unparse on Solaris returns lower case,
524 523 * for compatibility we preserve this behaviour.
525 524 */
526 525 uuid_unparse_common(uu, out, B_FALSE);
527 526 }
528 527
529 528 /*
530 529 * The uuid_is_null function compares the value of the supplied
531 530 * UUID variable uu to the NULL value. If the value is equal
532 531 * to the NULL UUID, 1 is returned, otherwise 0 is returned.
533 532 */
534 533 int
535 534 uuid_is_null(uuid_t uu)
536 535 {
537 536 int i;
538 537 uuid_t null_uu;
539 538
540 539 (void) memset(null_uu, 0, sizeof (uuid_t));
541 540 i = memcmp(uu, null_uu, sizeof (uuid_t));
542 541 if (i == 0) {
543 542 /* uu is NULL uuid */
544 543 return (1);
545 544 } else {
546 545 return (0);
547 546 }
548 547 }
549 548
550 549 /*
551 550 * uuid_parse converts the UUID string given by 'in' into the
552 551 * internal uuid_t format. The input UUID is a string of the form
553 552 * cefa7a9c-1dd2-11b2-8350-880020adbeef in printf(3C) format.
554 553 * Upon successfully parsing the input string, UUID is stored
555 554 * in the location pointed to by uu
556 555 */
557 556 int
558 557 uuid_parse(char *in, uuid_t uu)
559 558 {
560 559
561 560 char *ptr, buf[3];
562 561 int i;
563 562 struct uuid uuid;
564 563 uint16_t clock_seq;
565 564
566 565 /* do some sanity checking */
567 566 if ((strlen(in) != 36) || (uu == NULL) || (in[36] != '\0')) {
568 567 return (-1);
569 568 }
570 569
571 570 ptr = in;
572 571 for (i = 0; i < 36; i++, ptr++) {
573 572 if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
574 573 if (*ptr != '-') {
575 574 return (-1);
576 575 }
577 576 } else {
578 577 if (!isxdigit(*ptr)) {
579 578 return (-1);
580 579 }
581 580 }
582 581 }
583 582
584 583 uuid.time_low = strtoul(in, NULL, 16);
585 584 uuid.time_mid = strtoul(in+9, NULL, 16);
586 585 uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
587 586 clock_seq = strtoul(in+19, NULL, 16);
588 587 uuid.clock_seq_hi_and_reserved = (clock_seq & 0xFF00) >> 8;
589 588 uuid.clock_seq_low = (clock_seq & 0xFF);
590 589
591 590 ptr = in+24;
592 591 buf[2] = '\0';
593 592 for (i = 0; i < 6; i++) {
594 593 buf[0] = *ptr++;
595 594 buf[1] = *ptr++;
596 595 uuid.node_addr[i] = strtoul(buf, NULL, 16);
597 596 }
598 597 struct_to_string(uu, &uuid);
599 598 return (0);
600 599 }
601 600
602 601 /*
603 602 * uuid_time extracts the time at which the supplied UUID uu
604 603 * was created. This function can only extract the creation
605 604 * time for UUIDs created with the uuid_generate_time function.
606 605 * The time at which the UUID was created, in seconds and
607 606 * microseconds since the epoch is stored in the location
608 607 * pointed to by ret_tv.
609 608 */
610 609 time_t
611 610 uuid_time(uuid_t uu, struct timeval *ret_tv)
612 611 {
613 612 struct uuid uuid;
614 613 uint_t high;
615 614 struct timeval tv;
616 615 u_longlong_t clock_reg;
617 616 uint_t tmp;
618 617 uint8_t clk;
619 618
620 619 string_to_struct(&uuid, uu);
621 620 tmp = (uuid.time_hi_and_version & 0xF000) >> 12;
622 621 clk = uuid.clock_seq_hi_and_reserved;
623 622
624 623 /* check if uu is NULL, Version = 1 of DCE and Variant = 0b10x */
625 624 if ((uu == NULL) || ((tmp & 0x01) != 0x01) || ((clk & 0x80) != 0x80)) {
626 625 return (-1);
627 626 }
628 627 high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
629 628 clock_reg = uuid.time_low | ((u_longlong_t)high << 32);
630 629
631 630 clock_reg -= (((u_longlong_t)0x01B21DD2) << 32) + 0x13814000;
632 631 tv.tv_sec = clock_reg / 10000000;
633 632 tv.tv_usec = (clock_reg % 10000000) / 10;
634 633
635 634 if (ret_tv) {
636 635 *ret_tv = tv;
637 636 }
638 637
639 638 return (tv.tv_sec);
640 639 }
↓ open down ↓ |
434 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX