bin/uuidgen: add support for v4 uuids

The version 4 UUID is meant for generating UUIDs from truly-random or
pseudo-random numbers. [1]

bin/uuidgen gained the new flag '-r' to create version 4 UUID.

[1] RFC 4122, https://www.rfc-editor.org/rfc/rfc4122#section-4.4

Reviewed by:		pstef
Approved by:		bapt
MFC after:		1 week
Differential Revision:	https://reviews.freebsd.org/D37695
This commit is contained in:
Tobias C. Berner 2022-12-14 06:59:36 +01:00
parent 195f1b124d
commit f176fe8e7f
2 changed files with 67 additions and 12 deletions

View File

@ -33,6 +33,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl 1 .Op Fl 1
.Op Fl r
.Op Fl n Ar count .Op Fl n Ar count
.Op Fl o Ar filename .Op Fl o Ar filename
.Sh DESCRIPTION .Sh DESCRIPTION
@ -50,6 +51,8 @@ This option only has effect if multiple identifiers are to be generated and
instructs instructs
.Nm .Nm
to not generate them in batch, but one at a time. to not generate them in batch, but one at a time.
.It Fl r
This option controls creation of random UUID (version 4).
.It Fl n .It Fl n
This option controls the number of identifiers generated. This option controls the number of identifiers generated.
By default, multiple identifiers are generated in batch. By default, multiple identifiers are generated in batch.

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2002 Marcel Moolenaar * Copyright (c) 2002 Marcel Moolenaar
* Copyright (c) 2022 Tobias C. Berner
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -40,26 +41,63 @@ __FBSDID("$FreeBSD$");
static void static void
usage(void) usage(void)
{ {
(void)fprintf(stderr, "usage: uuidgen [-1] [-n count] [-o filename]\n"); (void)fprintf(stderr,
"usage: uuidgen [-1] [-r] [-n count] [-o filename]\n");
exit(1); exit(1);
} }
static int
uuidgen_v4(struct uuid *store, int count)
{
int size;
struct uuid *item;
if (count < 1) {
errno = EINVAL;
return (-1);
}
size = sizeof(struct uuid) * count;
arc4random_buf(store, size);
item = store;
for (int i = 0; i < count; ++i) {
/*
* Set the two most significant bits (bits 6 and 7) of the
* clock_seq_hi_and_reserved to zero and one, respectively.
*/
item->clock_seq_hi_and_reserved &= ~(3 << 6);
item->clock_seq_hi_and_reserved |= (2 << 6);
/*
* Set the four most significant bits (bits 12 through 15) of
* the time_hi_and_version field to the 4-bit version number
* from Section 4.1.3.
*/
item->time_hi_and_version &= ~(15 << 12);
item->time_hi_and_version |= (4 << 12);
item++;
};
return (0);
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
FILE *fp; FILE *fp;
uuid_t *store, *uuid; uuid_t *store, *uuid;
char *p; char *p;
int ch, count, i, iterate, status; int ch, count, i, iterate, status, version;
count = -1; /* no count yet */ count = -1; /* no count yet */
fp = stdout; /* default output file */ fp = stdout; /* default output file */
iterate = 0; /* not one at a time */ iterate = 0; /* not one at a time */
while ((ch = getopt(argc, argv, "1n:o:")) != -1) version = 1; /* create uuid v1 by default */
while ((ch = getopt(argc, argv, "1rn:o:")) != -1)
switch (ch) { switch (ch) {
case '1': case '1':
iterate = 1; iterate = 1;
break; break;
case 'r':
version = 4;
break;
case 'n': case 'n':
if (count > 0) if (count > 0)
usage(); usage();
@ -92,19 +130,33 @@ main(int argc, char *argv[])
if (count == -1) if (count == -1)
count = 1; count = 1;
store = (uuid_t*)malloc(sizeof(uuid_t) * count); store = (uuid_t *)malloc(sizeof(uuid_t) * count);
if (store == NULL) if (store == NULL)
err(1, "malloc()"); err(1, "malloc()");
if (!iterate) { if (!iterate) {
/* Get them all in a single batch */ /* Get them all in a single batch */
if (uuidgen(store, count) != 0) if (version == 1) {
err(1, "uuidgen()"); if (uuidgen(store, count) != 0)
err(1, "uuidgen()");
} else if (version == 4) {
if (uuidgen_v4(store, count) != 0)
err(1, "uuidgen_v4()");
} else {
err(1, "unsupported version");
}
} else { } else {
uuid = store; uuid = store;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
if (uuidgen(uuid++, 1) != 0) if (version == 1) {
err(1, "uuidgen()"); if (uuidgen(uuid++, 1) != 0)
err(1, "uuidgen()");
} else if (version == 4) {
if (uuidgen_v4(uuid++, 1) != 0)
err(1, "uuidgen_v4()");
} else {
err(1, "unsupported version");
}
} }
} }
@ -112,7 +164,7 @@ main(int argc, char *argv[])
while (count--) { while (count--) {
uuid_to_string(uuid++, &p, &status); uuid_to_string(uuid++, &p, &status);
if (status != uuid_s_ok) if (status != uuid_s_ok)
err(1, "cannot stringify a UUID"); err(1, "cannot stringify a UUID");
fprintf(fp, "%s\n", p); fprintf(fp, "%s\n", p);
free(p); free(p);
} }