210 lines
4.9 KiB
C
210 lines
4.9 KiB
C
/*
|
|
* gen_uuid.c --- generate a DCE-compatible uuid
|
|
*
|
|
* Copyright (C) 1999, Andreas Dilger and Theodore Ts'o
|
|
*
|
|
* %Begin-Header%
|
|
* This file may be redistributed under the terms of the GNU Public
|
|
* License.
|
|
* %End-Header%
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <getopt.h>
|
|
|
|
#include "uuid.h"
|
|
#include "nls.h"
|
|
#include "c.h"
|
|
#include "closestream.h"
|
|
|
|
static void __attribute__((__noreturn__)) usage(void)
|
|
{
|
|
FILE *out = stdout;
|
|
fputs(USAGE_HEADER, out);
|
|
fprintf(out,
|
|
_(" %s [options]\n"), program_invocation_short_name);
|
|
|
|
fputs(USAGE_SEPARATOR, out);
|
|
fputs(_("Create a new UUID value.\n"), out);
|
|
|
|
fputs(USAGE_OPTIONS, out);
|
|
fputs(_(" -r, --random generate random-based uuid\n"), out);
|
|
fputs(_(" -t, --time generate time-based uuid\n"), out);
|
|
fputs(_(" -n, --namespace ns generate hash-based uuid in this namespace\n"), out);
|
|
fputs(_(" -N, --name name generate hash-based uuid from this name\n"), out);
|
|
fputs(_(" -m, --md5 generate md5 hash\n"), out);
|
|
fputs(_(" -s, --sha1 generate sha1 hash\n"), out);
|
|
fputs(_(" -x, --hex interpret name as hex string\n"), out);
|
|
fputs(USAGE_SEPARATOR, out);
|
|
printf(USAGE_HELP_OPTIONS(18));
|
|
printf(USAGE_MAN_TAIL("uuidgen(1)"));
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
static char *unhex(const char *value, size_t *valuelen)
|
|
{
|
|
char c, *value2;
|
|
unsigned n, x;
|
|
|
|
if (*valuelen % 2 != 0) {
|
|
badstring:
|
|
fprintf(stderr, "%s: not a valid hex string\n", program_invocation_short_name);
|
|
errtryhelp(EXIT_FAILURE);
|
|
}
|
|
|
|
value2 = malloc(*valuelen / 2 + 1);
|
|
|
|
for (x = n = 0; n < *valuelen; n++) {
|
|
c = value[n];
|
|
if ('0' <= c && c <= '9')
|
|
x += c - '0';
|
|
else if (('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'))
|
|
x += (c - 'A' + 10) & 0xf;
|
|
else
|
|
goto badstring;
|
|
|
|
if (n % 2 == 0)
|
|
x *= 16;
|
|
else {
|
|
value2[n / 2] = x;
|
|
x = 0;
|
|
}
|
|
}
|
|
value2[n / 2] = '\0';
|
|
|
|
*valuelen = (n / 2);
|
|
|
|
return value2;
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
int c;
|
|
int do_type = 0, is_hex = 0;
|
|
char str[UUID_STR_LEN];
|
|
char *namespace = NULL, *name = NULL;
|
|
size_t namelen = 0;
|
|
uuid_t ns, uu;
|
|
|
|
static const struct option longopts[] = {
|
|
{"random", no_argument, NULL, 'r'},
|
|
{"time", no_argument, NULL, 't'},
|
|
{"version", no_argument, NULL, 'V'},
|
|
{"help", no_argument, NULL, 'h'},
|
|
{"namespace", required_argument, NULL, 'n'},
|
|
{"name", required_argument, NULL, 'N'},
|
|
{"md5", no_argument, NULL, 'm'},
|
|
{"sha1", no_argument, NULL, 's'},
|
|
{"hex", no_argument, NULL, 'x'},
|
|
{NULL, 0, NULL, 0}
|
|
};
|
|
|
|
setlocale(LC_ALL, "");
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
textdomain(PACKAGE);
|
|
close_stdout_atexit();
|
|
|
|
while ((c = getopt_long(argc, argv, "rtVhn:N:msx", longopts, NULL)) != -1)
|
|
switch (c) {
|
|
case 't':
|
|
do_type = UUID_TYPE_DCE_TIME;
|
|
break;
|
|
case 'r':
|
|
do_type = UUID_TYPE_DCE_RANDOM;
|
|
break;
|
|
case 'n':
|
|
namespace = optarg;
|
|
break;
|
|
case 'N':
|
|
name = optarg;
|
|
break;
|
|
case 'm':
|
|
do_type = UUID_TYPE_DCE_MD5;
|
|
break;
|
|
case 's':
|
|
do_type = UUID_TYPE_DCE_SHA1;
|
|
break;
|
|
case 'x':
|
|
is_hex = 1;
|
|
break;
|
|
|
|
case 'h':
|
|
usage();
|
|
case 'V':
|
|
print_version(EXIT_SUCCESS);
|
|
default:
|
|
errtryhelp(EXIT_FAILURE);
|
|
}
|
|
|
|
if (namespace) {
|
|
if (!name) {
|
|
fprintf(stderr, "%s: --namespace requires --name argument\n", program_invocation_short_name);
|
|
errtryhelp(EXIT_FAILURE);
|
|
}
|
|
if (do_type != UUID_TYPE_DCE_MD5 && do_type != UUID_TYPE_DCE_SHA1) {
|
|
fprintf(stderr, "%s: --namespace requires --md5 or --sha1\n", program_invocation_short_name);
|
|
errtryhelp(EXIT_FAILURE);
|
|
}
|
|
} else {
|
|
if (name) {
|
|
fprintf(stderr, "%s: --name requires --namespace argument\n", program_invocation_short_name);
|
|
errtryhelp(EXIT_FAILURE);
|
|
}
|
|
if (do_type == UUID_TYPE_DCE_MD5 || do_type == UUID_TYPE_DCE_SHA1) {
|
|
fprintf(stderr, "%s: --md5 or --sha1 require --namespace\n", program_invocation_short_name);
|
|
errtryhelp(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
if (name) {
|
|
namelen = strlen(name);
|
|
if (is_hex)
|
|
name = unhex(name, &namelen);
|
|
}
|
|
|
|
switch (do_type) {
|
|
case UUID_TYPE_DCE_TIME:
|
|
uuid_generate_time(uu);
|
|
break;
|
|
case UUID_TYPE_DCE_RANDOM:
|
|
uuid_generate_random(uu);
|
|
break;
|
|
case UUID_TYPE_DCE_MD5:
|
|
case UUID_TYPE_DCE_SHA1:
|
|
if (namespace[0] == '@' && namespace[1] != '\0') {
|
|
const uuid_t *uuidptr;
|
|
|
|
uuidptr = uuid_get_template(&namespace[1]);
|
|
if (uuidptr == NULL) {
|
|
fprintf(stderr, "%s: unknown namespace alias '%s'\n", program_invocation_short_name, namespace);
|
|
errtryhelp(EXIT_FAILURE);
|
|
}
|
|
memcpy(ns, *uuidptr, sizeof(ns));
|
|
} else {
|
|
if (uuid_parse(namespace, ns) != 0) {
|
|
fprintf(stderr, "%s: invalid uuid for namespace '%s'\n", program_invocation_short_name, namespace);
|
|
errtryhelp(EXIT_FAILURE);
|
|
}
|
|
}
|
|
if (do_type == UUID_TYPE_DCE_MD5)
|
|
uuid_generate_md5(uu, ns, name, namelen);
|
|
else
|
|
uuid_generate_sha1(uu, ns, name, namelen);
|
|
break;
|
|
default:
|
|
uuid_generate(uu);
|
|
break;
|
|
}
|
|
|
|
uuid_unparse(uu, str);
|
|
|
|
printf("%s\n", str);
|
|
|
|
if (is_hex)
|
|
free(name);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|