systemd-id128: a new tool to print machine/boot/invocation/app-specific ids
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 21 Aug 2018 14:08:48 +0000 (16:08 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 2 Oct 2018 13:15:10 +0000 (15:15 +0200)
The raison d'etre for this program is printing machine-app-specific IDs. We
provide a library function for that, but not a convenient API. We can hardly
ask people to quickly hack their own C programs or call libsystemd through CFFI
in python or another scripting language if they just want to print an ID.

Verb 'new' was already available as 'journalctl --new-id128', but this makes
it more discoverable.

v2:
- rename binary to systemd-id128
- make --app-specific= into a switch that applies to boot-id and machine-id

man/sd_id128_get_machine.xml
meson.build
src/id128/id128.c [new file with mode: 0644]
src/journal/journalctl.c
src/shared/id128-print.c
src/shared/id128-print.h

index 8425add..f797a8a 100644 (file)
@@ -78,7 +78,7 @@
     <function>sd_id128_get_machine()</function> when passing an ID to untrusted environments, in order to make sure
     that the original machine ID may not be determined externally. This way, the ID used by the application remains
     stable on a given machine, but cannot be easily correlated with IDs used in other applications on the same
-    machine. The application-specific ID should be generated via a tool like <command>journalctl --new-id128</command>,
+    machine. The application-specific ID should be generated via a tool like <command>systemd-id128 new</command>,
     and may be compiled into the application. This function will return the same application-specific ID for each
     combination of machine ID and application ID. Internally, this function calculates HMAC-SHA256 of the application
     ID, keyed by the machine ID.</para>
 
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-id128</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd-id128</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
index 1c4febf..49da682 100644 (file)
@@ -2323,6 +2323,14 @@ executable('systemd-cgroups-agent',
            install : true,
            install_dir : rootlibexecdir)
 
+exe = executable('systemd-id128',
+                 'src/id128/id128.c',
+                 include_directories : includes,
+                 link_with : [libshared],
+                 install_rpath : rootlibexecdir,
+                 install : true)
+public_programs += exe
+
 exe = executable('systemd-path',
                  'src/path/path.c',
                  include_directories : includes,
diff --git a/src/id128/id128.c b/src/id128/id128.c
new file mode 100644 (file)
index 0000000..a639131
--- /dev/null
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+#include <stdio.h>
+
+#include "alloc-util.h"
+#include "id128-print.h"
+#include "terminal-util.h"
+#include "util.h"
+#include "verbs.h"
+
+static bool arg_pretty = false;
+static sd_id128_t arg_app = {};
+
+static int verb_new(int argc, char **argv, void *userdata) {
+        return id128_print_new(arg_pretty);
+}
+
+static int verb_machine_id(int argc, char **argv, void *userdata) {
+        sd_id128_t id;
+        int r;
+
+        if (sd_id128_is_null(arg_app))
+                r = sd_id128_get_machine(&id);
+        else
+                r = sd_id128_get_machine_app_specific(arg_app, &id);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get %smachine-ID: %m",
+                                       sd_id128_is_null(arg_app) ? "" : "app-specific ");
+
+        return id128_pretty_print(id, arg_pretty);
+}
+
+static int verb_boot_id(int argc, char **argv, void *userdata) {
+        sd_id128_t id;
+        int r;
+
+        if (sd_id128_is_null(arg_app))
+                r = sd_id128_get_boot(&id);
+        else
+                r = sd_id128_get_boot_app_specific(arg_app, &id);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get %sboot-ID: %m",
+                                       sd_id128_is_null(arg_app) ? "" : "app-specific ");
+
+        return id128_pretty_print(id, arg_pretty);
+}
+
+static int verb_invocation_id(int argc, char **argv, void *userdata) {
+        sd_id128_t id;
+        int r;
+
+        if (!sd_id128_is_null(arg_app))
+                return log_error_errno(EINVAL, "Verb \"invocation-id\" cannot be combined with --app-specific=.");
+
+        r = sd_id128_get_invocation(&id);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get invocation-ID: %m");
+
+        return id128_pretty_print(id, arg_pretty);
+}
+
+static int help(void) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        r = terminal_urlify_man("systemd-id128", "1", &link);
+        if (r < 0)
+                return log_oom();
+
+        printf("%s [OPTIONS...] {COMMAND} ...\n\n"
+               "Generate and print id128 strings.\n\n"
+               "  -h --help               Show this help\n\n"
+               "  -p --pretty             Generate samples of program code\n\n"
+               "  -a --app-specific=ID    Generate app-specific IDs\n\n"
+               "Commands:\n"
+               "  new                     Generate a new id128 string\n"
+               "  machine-id              Print the ID of current machine\n"
+               "  boot-id                 Print the ID of current boot\n"
+               "  invocation-id           Print the ID of current invocation\n"
+               "  help                    Show this help\n"
+               "\nSee the %s for details.\n"
+               , program_invocation_short_name
+               , link
+        );
+
+        return 0;
+}
+
+static int verb_help(int argc, char **argv, void *userdata) {
+        return help();
+}
+
+static int parse_argv(int argc, char *argv[]) {
+        enum {
+                ARG_VERSION = 0x100,
+        };
+
+        static const struct option options[] = {
+                { "help",         no_argument,       NULL, 'h'              },
+                { "version",      no_argument,       NULL, ARG_VERSION      },
+                { "app-specific", required_argument, NULL, 'a'              },
+                {},
+        };
+
+        int c, r;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "hpa:", options, NULL)) >= 0)
+                switch (c) {
+
+                case 'h':
+                        return help();
+
+                case ARG_VERSION:
+                        return version();
+
+                case 'p':
+                        arg_pretty = true;
+                        break;
+
+                case 'a':
+                        r = sd_id128_from_string(optarg, &arg_app);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse \"%s\" as application-ID: %m", optarg);
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option");
+                }
+
+        return 1;
+}
+
+static int id128_main(int argc, char *argv[]) {
+        static const Verb verbs[] = {
+                { "new",            VERB_ANY, 1,        0,  verb_new           },
+                { "machine-id",     VERB_ANY, 1,        0,  verb_machine_id    },
+                { "boot-id",        VERB_ANY, 1,        0,  verb_boot_id       },
+                { "invocation-id",  VERB_ANY, 1,        0,  verb_invocation_id },
+                { "help",           VERB_ANY, VERB_ANY, 0,  verb_help          },
+                {}
+        };
+
+        return dispatch_verb(argc, argv, verbs, NULL);
+}
+
+int main(int argc, char *argv[]) {
+        int r;
+
+        log_parse_environment();
+        log_open();
+
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                goto finish;
+
+        r = id128_main(argc, argv);
+
+ finish:
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
index 3ff4d29..b42f676 100644 (file)
@@ -2064,7 +2064,7 @@ int main(int argc, char *argv[]) {
         switch (arg_action) {
 
         case ACTION_NEW_ID128:
-                r = id128_generate_new();
+                r = id128_print_new(true);
                 goto finish;
 
         case ACTION_SETUP_KEYS:
index 212080f..5b5dac6 100644 (file)
@@ -7,14 +7,14 @@
 #include "id128-print.h"
 #include "log.h"
 
-int id128_generate_new(void) {
-        sd_id128_t id;
-        int r;
+int id128_pretty_print(sd_id128_t id, bool pretty) {
         unsigned i;
 
-        r = sd_id128_randomize(&id);
-        if (r < 0)
-                return log_error_errno(r, "Failed to generate ID: %m");
+        if (!pretty) {
+                printf(SD_ID128_FORMAT_STR "\n",
+                       SD_ID128_FORMAT_VAL(id));
+                return 0;
+        }
 
         printf("As string:\n"
                SD_ID128_FORMAT_STR "\n\n"
@@ -35,3 +35,14 @@ int id128_generate_new(void) {
 
         return 0;
 }
+
+int id128_print_new(bool pretty) {
+        sd_id128_t id;
+        int r;
+
+        r = sd_id128_randomize(&id);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate ID: %m");
+
+        return id128_pretty_print(id, pretty);
+}
index 6b5b331..5d50de0 100644 (file)
@@ -2,4 +2,9 @@
 
 #pragma once
 
-int id128_generate_new(void);
+#include <stdbool.h>
+
+#include "sd-id128.h"
+
+int id128_pretty_print(sd_id128_t id, bool pretty);
+int id128_print_new(bool pretty);