1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-08 08:58:27 +03:00

Merge pull request #3777 from poettering/id128-rework

uuid/id128 code rework
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2016-07-22 21:18:41 -04:00 committed by GitHub
commit 31b14fdb6f
22 changed files with 437 additions and 384 deletions

View File

@ -242,6 +242,7 @@ AM_CPPFLAGS = \
-I $(top_srcdir)/src/libsystemd/sd-network \
-I $(top_srcdir)/src/libsystemd/sd-hwdb \
-I $(top_srcdir)/src/libsystemd/sd-device \
-I $(top_srcdir)/src/libsystemd/sd-id128 \
-I $(top_srcdir)/src/libsystemd-network \
$(OUR_CPPFLAGS)
@ -3074,9 +3075,7 @@ systemd_nspawn_SOURCES = \
src/core/mount-setup.c \
src/core/mount-setup.h \
src/core/loopback-setup.c \
src/core/loopback-setup.h \
src/core/machine-id-setup.c \
src/core/machine-id-setup.h
src/core/loopback-setup.h
nodist_systemd_nspawn_SOURCES = \
src/nspawn/nspawn-gperf.c
@ -3213,6 +3212,8 @@ libsystemd_internal_la_SOURCES = \
src/libsystemd/sd-netlink/local-addresses.h \
src/libsystemd/sd-netlink/local-addresses.c \
src/libsystemd/sd-id128/sd-id128.c \
src/libsystemd/sd-id128/id128-util.h \
src/libsystemd/sd-id128/id128-util.c \
src/libsystemd/sd-daemon/sd-daemon.c \
src/libsystemd/sd-login/sd-login.c \
src/libsystemd/sd-path/sd-path.c \

View File

@ -74,13 +74,11 @@
lowercase hexadecimal digits and be terminated by a
<constant>NUL</constant> byte.</para>
<para><function>sd_id128_from_string()</function> implements the
reverse operation: it takes a 33 character string with 32
hexadecimal digits (either lowercase or uppercase, terminated by
<constant>NUL</constant>) and parses them back into a 128-bit ID
returned in <parameter>ret</parameter>. Alternatively, this call
can also parse a 37-character string with a 128-bit ID formatted
as RFC UUID.</para>
<para><function>sd_id128_from_string()</function> implements the reverse operation: it takes a 33 character string
with 32 hexadecimal digits (either lowercase or uppercase, terminated by <constant>NUL</constant>) and parses them
back into a 128-bit ID returned in <parameter>ret</parameter>. Alternatively, this call can also parse a
37-character string with a 128-bit ID formatted as RFC UUID. If <parameter>ret</parameter> is passed as NULL the
function will validate the passed ID string, but not actually return it in parsed form.</para>
<para>For more information about the <literal>sd_id128_t</literal>
type see

View File

@ -151,6 +151,12 @@
early boot service.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--print</option></term>
<listitem><para>Print the machine ID generated or commited after the operation is complete.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>

View File

@ -581,47 +581,6 @@ int on_ac_power(void) {
return found_online || !found_offline;
}
bool id128_is_valid(const char *s) {
size_t i, l;
l = strlen(s);
if (l == 32) {
/* Simple formatted 128bit hex string */
for (i = 0; i < l; i++) {
char c = s[i];
if (!(c >= '0' && c <= '9') &&
!(c >= 'a' && c <= 'z') &&
!(c >= 'A' && c <= 'Z'))
return false;
}
} else if (l == 36) {
/* Formatted UUID */
for (i = 0; i < l; i++) {
char c = s[i];
if ((i == 8 || i == 13 || i == 18 || i == 23)) {
if (c != '-')
return false;
} else {
if (!(c >= '0' && c <= '9') &&
!(c >= 'a' && c <= 'z') &&
!(c >= 'A' && c <= 'Z'))
return false;
}
}
} else
return false;
return true;
}
int container_get_leader(const char *machine, pid_t *pid) {
_cleanup_free_ char *s = NULL, *class = NULL;
const char *p;

View File

@ -176,8 +176,6 @@ static inline unsigned log2u_round_up(unsigned x) {
return log2u(x - 1) + 1;
}
bool id128_is_valid(const char *s) _pure_;
int container_get_leader(const char *machine, pid_t *pid);
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);

View File

@ -311,7 +311,7 @@ static int print_efi_option(uint16_t id, bool in_order) {
return r;
/* print only configured entries with partition information */
if (!path || sd_id128_equal(partition, SD_ID128_NULL))
if (!path || sd_id128_is_null(partition))
return 0;
efi_tilt_backslashes(path);
@ -1072,7 +1072,7 @@ static int bootctl_main(int argc, char*argv[]) {
printf("Loader:\n");
printf(" Product: %s\n", strna(loader));
if (!sd_id128_equal(loader_part_uuid, SD_ID128_NULL))
if (!sd_id128_is_null(loader_part_uuid))
printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
SD_ID128_FORMAT_VAL(loader_part_uuid));
else

View File

@ -17,11 +17,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <sys/mount.h>
#include <unistd.h>
@ -29,10 +26,8 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "hexdecoct.h"
#include "io-util.h"
#include "id128-util.h"
#include "log.h"
#include "machine-id-setup.h"
#include "macro.h"
@ -46,101 +41,23 @@
#include "util.h"
#include "virt.h"
static int shorten_uuid(char destination[34], const char source[36]) {
unsigned i, j;
assert(destination);
assert(source);
/* Converts a UUID into a machine ID, by lowercasing it and
* removing dashes. Validates everything. */
for (i = 0, j = 0; i < 36 && j < 32; i++) {
int t;
t = unhexchar(source[i]);
if (t < 0)
continue;
destination[j++] = hexchar(t);
}
if (i != 36 || j != 32)
return -EINVAL;
destination[32] = '\n';
destination[33] = 0;
return 0;
}
static int read_machine_id(int fd, char id[34]) {
char id_to_validate[34];
int r;
assert(fd >= 0);
assert(id);
/* Reads a machine ID from a file, validates it, and returns
* it. The returned ID ends in a newline. */
r = loop_read_exact(fd, id_to_validate, 33, false);
if (r < 0)
return r;
if (id_to_validate[32] != '\n')
return -EINVAL;
id_to_validate[32] = 0;
if (!id128_is_valid(id_to_validate))
return -EINVAL;
memcpy(id, id_to_validate, 32);
id[32] = '\n';
id[33] = 0;
return 0;
}
static int write_machine_id(int fd, const char id[34]) {
int r;
assert(fd >= 0);
assert(id);
if (lseek(fd, 0, SEEK_SET) < 0)
return -errno;
r = loop_write(fd, id, 33, false);
if (r < 0)
return r;
if (fsync(fd) < 0)
return -errno;
return 0;
}
static int generate_machine_id(char id[34], const char *root) {
int fd, r;
unsigned char *p;
sd_id128_t buf;
char *q;
static int generate_machine_id(const char *root, sd_id128_t *ret) {
const char *dbus_machine_id;
_cleanup_close_ int fd = -1;
int r;
assert(id);
dbus_machine_id = prefix_roota(root, "/var/lib/dbus/machine-id");
assert(ret);
/* First, try reading the D-Bus machine id, unless it is a symlink */
dbus_machine_id = prefix_roota(root, "/var/lib/dbus/machine-id");
fd = open(dbus_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd >= 0) {
r = read_machine_id(fd, id);
safe_close(fd);
if (r >= 0) {
if (id128_read_fd(fd, ID128_PLAIN, ret) >= 0) {
log_info("Initializing machine ID from D-Bus machine ID.");
return 0;
}
fd = safe_close(fd);
}
if (isempty(root)) {
@ -151,13 +68,10 @@ static int generate_machine_id(char id[34], const char *root) {
if (detect_container() > 0) {
_cleanup_free_ char *e = NULL;
r = getenv_for_pid(1, "container_uuid", &e);
if (r > 0) {
r = shorten_uuid(id, e);
if (r >= 0) {
log_info("Initializing machine ID from container UUID.");
return 0;
}
if (getenv_for_pid(1, "container_uuid", &e) > 0 &&
sd_id128_from_string(e, ret) >= 0) {
log_info("Initializing machine ID from container UUID.");
return 0;
}
} else if (detect_vm() == VIRTUALIZATION_KVM) {
@ -166,51 +80,29 @@ static int generate_machine_id(char id[34], const char *root) {
* running in qemu/kvm and a machine ID was passed in
* via -uuid on the qemu/kvm command line */
char uuid[36];
fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd >= 0) {
r = loop_read_exact(fd, uuid, 36, false);
safe_close(fd);
if (r >= 0) {
r = shorten_uuid(id, uuid);
if (r >= 0) {
log_info("Initializing machine ID from KVM UUID.");
return 0;
}
}
if (id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, ret) >= 0) {
log_info("Initializing machine ID from KVM UUID.");
return 0;
}
}
}
/* If that didn't work, generate a random machine id */
r = sd_id128_randomize(&buf);
r = sd_id128_randomize(ret);
if (r < 0)
return log_error_errno(r, "Failed to open /dev/urandom: %m");
for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) {
q[0] = hexchar(*p >> 4);
q[1] = hexchar(*p & 15);
}
id[32] = '\n';
id[33] = 0;
return log_error_errno(r, "Failed to generate randomized : %m");
log_info("Initializing machine ID from random generator.");
return 0;
}
int machine_id_setup(const char *root, sd_id128_t machine_id) {
int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
const char *etc_machine_id, *run_machine_id;
_cleanup_close_ int fd = -1;
bool writable = true;
char id[34]; /* 32 + \n + \0 */
bool writable;
int r;
etc_machine_id = prefix_roota(root, "/etc/machine-id");
run_machine_id = prefix_roota(root, "/run/machine-id");
RUN_WITH_UMASK(0000) {
/* We create this 0444, to indicate that this isn't really
@ -218,7 +110,7 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
* will be owned by root it doesn't matter much, but maybe
* people look. */
mkdir_parents(etc_machine_id, 0755);
(void) mkdir_parents(etc_machine_id, 0755);
fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
if (fd < 0) {
int old_errno = errno;
@ -239,41 +131,41 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
}
writable = false;
}
} else
writable = true;
}
/* A machine id argument overrides all other machined-ids */
if (!sd_id128_is_null(machine_id)) {
sd_id128_to_string(machine_id, id);
id[32] = '\n';
id[33] = 0;
} else {
if (read_machine_id(fd, id) >= 0)
/* A we got a valid machine ID argument, that's what counts */
if (sd_id128_is_null(machine_id)) {
/* Try to read any existing machine ID */
if (id128_read_fd(fd, ID128_PLAIN, ret) >= 0)
return 0;
/* Hmm, so, the id currently stored is not useful, then let's
* generate one */
r = generate_machine_id(id, root);
/* Hmm, so, the id currently stored is not useful, then let's generate one */
r = generate_machine_id(root, &machine_id);
if (r < 0)
return r;
if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
return log_error_errno(errno, "Failed to seek: %m");
}
if (writable)
if (write_machine_id(fd, id) >= 0)
return 0;
if (id128_write_fd(fd, ID128_PLAIN, machine_id, true) >= 0)
goto finish;
fd = safe_close(fd);
/* Hmm, we couldn't write it? So let's write it to
* /run/machine-id as a replacement */
/* Hmm, we couldn't write it? So let's write it to /run/machine-id as a replacement */
RUN_WITH_UMASK(0022) {
r = write_string_file(run_machine_id, id, WRITE_STRING_FILE_CREATE);
if (r < 0) {
(void) unlink(run_machine_id);
return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
}
run_machine_id = prefix_roota(root, "/run/machine-id");
RUN_WITH_UMASK(0022)
r = id128_write(run_machine_id, ID128_PLAIN, machine_id, false);
if (r < 0) {
(void) unlink(run_machine_id);
return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
}
/* And now, let's mount it over */
@ -286,7 +178,11 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
/* Mark the mount read-only */
if (mount(NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0)
log_warning_errno(errno, "Failed to make transient %s read-only: %m", etc_machine_id);
log_warning_errno(errno, "Failed to make transient %s read-only, ignoring: %m", etc_machine_id);
finish:
if (ret)
*ret = machine_id;
return 0;
}
@ -294,9 +190,13 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
int machine_id_commit(const char *root) {
_cleanup_close_ int fd = -1, initial_mntns_fd = -1;
const char *etc_machine_id;
char id[34]; /* 32 + \n + \0 */
sd_id128_t id;
int r;
/* Replaces a tmpfs bind mount of /etc/machine-id by a proper file, atomically. For this, the umount is removed
* in a mount namespace, a new file is created at the right place. Afterwards the mount is also removed in the
* original mount namespace, thus revealing the file that was just created. */
etc_machine_id = prefix_roota(root, "/etc/machine-id");
r = path_is_mount_point(etc_machine_id, 0);
@ -312,10 +212,6 @@ int machine_id_commit(const char *root) {
if (fd < 0)
return log_error_errno(errno, "Cannot open %s: %m", etc_machine_id);
r = read_machine_id(fd, id);
if (r < 0)
return log_error_errno(r, "We didn't find a valid machine ID in %s.", etc_machine_id);
r = fd_is_temporary_fs(fd);
if (r < 0)
return log_error_errno(r, "Failed to determine whether %s is on a temporary file system: %m", etc_machine_id);
@ -324,6 +220,10 @@ int machine_id_commit(const char *root) {
return -EROFS;
}
r = id128_read_fd(fd, ID128_PLAIN, &id);
if (r < 0)
return log_error_errno(r, "We didn't find a valid machine ID in %s.", etc_machine_id);
fd = safe_close(fd);
/* Store current mount namespace */
@ -342,15 +242,9 @@ int machine_id_commit(const char *root) {
return log_error_errno(errno, "Failed to unmount transient %s file in our private namespace: %m", etc_machine_id);
/* Update a persistent version of etc_machine_id */
fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
if (fd < 0)
return log_error_errno(errno, "Cannot open for writing %s. This is mandatory to get a persistent machine-id: %m", etc_machine_id);
r = write_machine_id(fd, id);
r = id128_write(etc_machine_id, ID128_PLAIN, id, true);
if (r < 0)
return log_error_errno(r, "Cannot write %s: %m", etc_machine_id);
fd = safe_close(fd);
return log_error_errno(r, "Cannot write %s. This is mandatory to get a persistent machine ID: %m", etc_machine_id);
/* Return to initial namespace and proceed a lazy tmpfs unmount */
r = namespace_enter(-1, initial_mntns_fd, -1, -1, -1);

View File

@ -20,4 +20,4 @@
***/
int machine_id_commit(const char *root);
int machine_id_setup(const char *root, sd_id128_t machine_id);
int machine_id_setup(const char *root, sd_id128_t requested, sd_id128_t *ret);

View File

@ -291,14 +291,16 @@ static int parse_crash_chvt(const char *value) {
}
static int set_machine_id(const char *m) {
sd_id128_t t;
assert(m);
if (sd_id128_from_string(m, &arg_machine_id) < 0)
if (sd_id128_from_string(m, &t) < 0)
return -EINVAL;
if (sd_id128_is_null(arg_machine_id))
if (sd_id128_is_null(t))
return -EINVAL;
arg_machine_id = t;
return 0;
}
@ -1721,7 +1723,7 @@ int main(int argc, char *argv[]) {
status_welcome();
hostname_setup();
machine_id_setup(NULL, arg_machine_id);
machine_id_setup(NULL, arg_machine_id, NULL);
loopback_setup();
bump_unix_max_dgram_qlen();

View File

@ -427,7 +427,7 @@ static int process_machine_id(void) {
if (laccess(etc_machine_id, F_OK) >= 0)
return 0;
if (sd_id128_equal(arg_machine_id, SD_ID128_NULL))
if (sd_id128_is_null(arg_machine_id))
return 0;
mkdir_parents(etc_machine_id, 0755);

View File

@ -1266,7 +1266,7 @@ static int add_boot(sd_journal *j) {
/* Take a shortcut and use the current boot_id, which we can do very quickly.
* We can do this only when we logs are coming from the current machine,
* so take the slow path if log location is specified. */
if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL) &&
if (arg_boot_offset == 0 && sd_id128_is_null(arg_boot_id) &&
!arg_directory && !arg_file)
return add_match_this_boot(j, arg_machine);

View File

@ -877,7 +877,7 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
assert_cc(6 == LOG_INFO);
IOVEC_SET_STRING(iovec[n++], "PRIORITY=6");
if (!sd_id128_equal(message_id, SD_ID128_NULL)) {
if (!sd_id128_is_null(message_id)) {
snprintf(mid, sizeof(mid), LOG_MESSAGE_ID(message_id));
IOVEC_SET_STRING(iovec[n++], mid);
}

View File

@ -221,7 +221,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) {
peer.bytes[i/2] = ((uint8_t) x << 4 | (uint8_t) y);
}
if (!sd_id128_equal(b->server_id, SD_ID128_NULL) &&
if (!sd_id128_is_null(b->server_id) &&
!sd_id128_equal(b->server_id, peer))
return -EPERM;

View File

@ -0,0 +1,182 @@
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <fcntl.h>
#include <unistd.h>
#include "fd-util.h"
#include "hexdecoct.h"
#include "id128-util.h"
#include "io-util.h"
#include "stdio-util.h"
char *id128_to_uuid_string(sd_id128_t id, char s[37]) {
unsigned n, k = 0;
assert(s);
/* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
for (n = 0; n < 16; n++) {
if (IN_SET(n, 4, 6, 8, 10))
s[k++] = '-';
s[k++] = hexchar(id.bytes[n] >> 4);
s[k++] = hexchar(id.bytes[n] & 0xF);
}
assert(k == 36);
s[k] = 0;
return s;
}
bool id128_is_valid(const char *s) {
size_t i, l;
assert(s);
l = strlen(s);
if (l == 32) {
/* Plain formatted 128bit hex string */
for (i = 0; i < l; i++) {
char c = s[i];
if (!(c >= '0' && c <= '9') &&
!(c >= 'a' && c <= 'z') &&
!(c >= 'A' && c <= 'Z'))
return false;
}
} else if (l == 36) {
/* Formatted UUID */
for (i = 0; i < l; i++) {
char c = s[i];
if ((i == 8 || i == 13 || i == 18 || i == 23)) {
if (c != '-')
return false;
} else {
if (!(c >= '0' && c <= '9') &&
!(c >= 'a' && c <= 'z') &&
!(c >= 'A' && c <= 'Z'))
return false;
}
}
} else
return false;
return true;
}
int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
char buffer[36 + 2];
ssize_t l;
assert(fd >= 0);
assert(f < _ID128_FORMAT_MAX);
/* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
* followed by a newline and nothing else. */
l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 33 or 37 chars */
if (l < 0)
return (int) l;
if (l == 0) /* empty? */
return -ENOMEDIUM;
if (l == 33) {
if (f == ID128_UUID)
return -EINVAL;
if (buffer[32] != '\n')
return -EINVAL;
buffer[32] = 0;
} else if (l == 37) {
if (f == ID128_PLAIN)
return -EINVAL;
if (buffer[36] != '\n')
return -EINVAL;
buffer[36] = 0;
} else
return -EINVAL;
return sd_id128_from_string(buffer, ret);
}
int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
_cleanup_close_ int fd = -1;
fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return -errno;
return id128_read_fd(fd, f, ret);
}
int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
char buffer[36 + 2];
size_t sz;
int r;
assert(fd >= 0);
assert(f < _ID128_FORMAT_MAX);
if (f != ID128_UUID) {
sd_id128_to_string(id, buffer);
buffer[32] = '\n';
sz = 33;
} else {
id128_to_uuid_string(id, buffer);
buffer[36] = '\n';
sz = 37;
}
r = loop_write(fd, buffer, sz, false);
if (r < 0)
return r;
if (do_sync) {
if (fsync(fd) < 0)
return -errno;
}
return r;
}
int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
_cleanup_close_ int fd = -1;
fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
if (fd < 0)
return -errno;
return id128_write_fd(fd, f, id, do_sync);
}

View File

@ -0,0 +1,45 @@
#pragma once
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdbool.h>
#include "sd-id128.h"
#include "macro.h"
char *id128_to_uuid_string(sd_id128_t id, char s[37]);
/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */
#define ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
bool id128_is_valid(const char *s) _pure_;
typedef enum Id128Format {
ID128_ANY,
ID128_PLAIN, /* formatted as 32 hex chars as-is */
ID128_UUID, /* formatted as 36 character uuid string */
_ID128_FORMAT_MAX,
} Id128Format;
int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret);
int id128_read(const char *p, Id128Format f, sd_id128_t *ret);
int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync);
int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);

View File

@ -25,6 +25,7 @@
#include "fd-util.h"
#include "hexdecoct.h"
#include "id128-util.h"
#include "io-util.h"
#include "macro.h"
#include "random-util.h"
@ -51,7 +52,6 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
bool is_guid = false;
assert_return(s, -EINVAL);
assert_return(ret, -EINVAL);
for (n = 0, i = 0; n < 16;) {
int a, b;
@ -89,7 +89,43 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
if (s[i] != 0)
return -EINVAL;
*ret = t;
if (ret)
*ret = t;
return 0;
}
_public_ int sd_id128_get_machine(sd_id128_t *ret) {
static thread_local sd_id128_t saved_machine_id = {};
int r;
assert_return(ret, -EINVAL);
if (sd_id128_is_null(saved_machine_id)) {
r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id);
if (r < 0)
return r;
if (sd_id128_is_null(saved_machine_id))
return -EINVAL;
}
*ret = saved_machine_id;
return 0;
}
_public_ int sd_id128_get_boot(sd_id128_t *ret) {
static thread_local sd_id128_t saved_boot_id = {};
int r;
assert_return(ret, -EINVAL);
if (sd_id128_is_null(saved_boot_id)) {
r = id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID, &saved_boot_id);
if (r < 0)
return r;
}
*ret = saved_boot_id;
return 0;
}
@ -106,106 +142,6 @@ static sd_id128_t make_v4_uuid(sd_id128_t id) {
return id;
}
_public_ int sd_id128_get_machine(sd_id128_t *ret) {
static thread_local sd_id128_t saved_machine_id;
static thread_local bool saved_machine_id_valid = false;
_cleanup_close_ int fd = -1;
char buf[33];
unsigned j;
sd_id128_t t;
int r;
assert_return(ret, -EINVAL);
if (saved_machine_id_valid) {
*ret = saved_machine_id;
return 0;
}
fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return -errno;
r = loop_read_exact(fd, buf, 33, false);
if (r < 0)
return r;
if (buf[32] !='\n')
return -EIO;
for (j = 0; j < 16; j++) {
int a, b;
a = unhexchar(buf[j*2]);
b = unhexchar(buf[j*2+1]);
if (a < 0 || b < 0)
return -EIO;
t.bytes[j] = a << 4 | b;
}
saved_machine_id = t;
saved_machine_id_valid = true;
*ret = t;
return 0;
}
_public_ int sd_id128_get_boot(sd_id128_t *ret) {
static thread_local sd_id128_t saved_boot_id;
static thread_local bool saved_boot_id_valid = false;
_cleanup_close_ int fd = -1;
char buf[36];
unsigned j;
sd_id128_t t;
char *p;
int r;
assert_return(ret, -EINVAL);
if (saved_boot_id_valid) {
*ret = saved_boot_id;
return 0;
}
fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return -errno;
r = loop_read_exact(fd, buf, 36, false);
if (r < 0)
return r;
for (j = 0, p = buf; j < 16; j++) {
int a, b;
if (p >= buf + 35)
return -EIO;
if (*p == '-') {
p++;
if (p >= buf + 35)
return -EIO;
}
a = unhexchar(p[0]);
b = unhexchar(p[1]);
if (a < 0 || b < 0)
return -EIO;
t.bytes[j] = a << 4 | b;
p += 2;
}
saved_boot_id = t;
saved_boot_id_valid = true;
*ret = t;
return 0;
}
_public_ int sd_id128_randomize(sd_id128_t *ret) {
sd_id128_t t;
int r;

View File

@ -29,6 +29,7 @@
static char *arg_root = NULL;
static bool arg_commit = false;
static bool arg_print = false;
static void help(void) {
printf("%s [OPTIONS...]\n\n"
@ -37,6 +38,7 @@ static void help(void) {
" --version Show package version\n"
" --root=ROOT Filesystem root\n"
" --commit Commit transient ID\n"
" --print Print used machine ID\n"
, program_invocation_short_name);
}
@ -46,6 +48,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERSION = 0x100,
ARG_ROOT,
ARG_COMMIT,
ARG_PRINT,
};
static const struct option options[] = {
@ -53,6 +56,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "version", no_argument, NULL, ARG_VERSION },
{ "root", required_argument, NULL, ARG_ROOT },
{ "commit", no_argument, NULL, ARG_COMMIT },
{ "print", no_argument, NULL, ARG_PRINT },
{}
};
@ -82,6 +86,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_commit = true;
break;
case ARG_PRINT:
arg_print = true;
break;
case '?':
return -EINVAL;
@ -98,6 +106,8 @@ static int parse_argv(int argc, char *argv[]) {
}
int main(int argc, char *argv[]) {
char buf[SD_ID128_STRING_MAX];
sd_id128_t id;
int r;
log_parse_environment();
@ -107,10 +117,24 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
if (arg_commit)
if (arg_commit) {
r = machine_id_commit(arg_root);
else
r = machine_id_setup(arg_root, SD_ID128_NULL);
if (r < 0)
goto finish;
r = sd_id128_get_machine(&id);
if (r < 0) {
log_error_errno(r, "Failed to read machine ID back: %m");
goto finish;
}
} else {
r = machine_id_setup(arg_root, SD_ID128_NULL, &id);
if (r < 0)
goto finish;
}
if (arg_print)
puts(sd_id128_to_string(id, buf));
finish:
free(arg_root);

View File

@ -181,7 +181,7 @@ int machine_save(Machine *m) {
fprintf(f, "ROOT=%s\n", escaped);
}
if (!sd_id128_equal(m->id, SD_ID128_NULL))
if (!sd_id128_is_null(m->id))
fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
if (m->leader != 0)

View File

@ -528,7 +528,7 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
fputs(strna(i->name), stdout);
if (!sd_id128_equal(i->id, SD_ID128_NULL))
if (!sd_id128_is_null(i->id))
printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
else
putchar('\n');

View File

@ -61,9 +61,9 @@
#include "fs-util.h"
#include "gpt.h"
#include "hostname-util.h"
#include "id128-util.h"
#include "log.h"
#include "loopback-setup.h"
#include "machine-id-setup.h"
#include "machine-image.h"
#include "macro.h"
#include "missing.h"
@ -76,10 +76,10 @@
#include "nspawn-network.h"
#include "nspawn-patch-uid.h"
#include "nspawn-register.h"
#include "nspawn-seccomp.h"
#include "nspawn-settings.h"
#include "nspawn-setuid.h"
#include "nspawn-stub-pid1.h"
#include "nspawn-seccomp.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
@ -594,9 +594,12 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_UUID:
r = sd_id128_from_string(optarg, &arg_uuid);
if (r < 0) {
log_error("Invalid UUID: %s", optarg);
return r;
if (r < 0)
return log_error_errno(r, "Invalid UUID: %s", optarg);
if (sd_id128_is_null(arg_uuid)) {
log_error("Machine UUID may not be all zeroes.");
return -EINVAL;
}
arg_settings_mask |= SETTING_MACHINE_ID;
@ -1266,20 +1269,9 @@ static int setup_resolv_conf(const char *dest) {
return 0;
}
static char* id128_format_as_uuid(sd_id128_t id, char s[37]) {
assert(s);
snprintf(s, 37,
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
SD_ID128_FORMAT_VAL(id));
return s;
}
static int setup_boot_id(const char *dest) {
sd_id128_t rnd = SD_ID128_NULL;
const char *from, *to;
sd_id128_t rnd = {};
char as_uuid[37];
int r;
if (arg_share_system)
@ -1295,18 +1287,16 @@ static int setup_boot_id(const char *dest) {
if (r < 0)
return log_error_errno(r, "Failed to generate random boot id: %m");
id128_format_as_uuid(rnd, as_uuid);
r = write_string_file(from, as_uuid, WRITE_STRING_FILE_CREATE);
r = id128_write(from, ID128_UUID, rnd, false);
if (r < 0)
return log_error_errno(r, "Failed to write boot id: %m");
if (mount(from, to, NULL, MS_BIND, NULL) < 0)
r = log_error_errno(errno, "Failed to bind mount boot id: %m");
else if (mount(NULL, to, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|MS_NODEV, NULL) < 0)
log_warning_errno(errno, "Failed to make boot id read-only: %m");
log_warning_errno(errno, "Failed to make boot id read-only, ignoring: %m");
unlink(from);
(void) unlink(from);
return r;
}
@ -2232,33 +2222,37 @@ static int mount_device(const char *what, const char *where, const char *directo
}
static int setup_machine_id(const char *directory) {
const char *etc_machine_id;
sd_id128_t id;
int r;
const char *etc_machine_id, *t;
_cleanup_free_ char *s = NULL;
/* If the UUID in the container is already set, then that's what counts, and we use. If it isn't set, and the
* caller passed --uuid=, then we'll pass it in the $container_uuid env var to PID 1 of the container. The
* assumption is that PID 1 will then write it to /etc/machine-id to make it persistent. If --uuid= is not
* passed we generate a random UUID, and pass it via $container_uuid. In effect this means that /etc/machine-id
* in the container and our idea of the container UUID will always be in sync (at least if PID 1 in the
* container behaves nicely). */
etc_machine_id = prefix_roota(directory, "/etc/machine-id");
r = read_one_line_file(etc_machine_id, &s);
if (r < 0)
return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id);
r = id128_read(etc_machine_id, ID128_PLAIN, &id);
if (r < 0) {
if (!IN_SET(r, -ENOENT, -ENOMEDIUM)) /* If the file is missing or empty, we don't mind */
return log_error_errno(r, "Failed to read machine ID from container image: %m");
t = strstrip(s);
if (!isempty(t)) {
r = sd_id128_from_string(t, &arg_uuid);
if (r < 0)
return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id);
} else {
if (sd_id128_is_null(arg_uuid)) {
r = sd_id128_randomize(&arg_uuid);
if (r < 0)
return log_error_errno(r, "Failed to generate random machine ID: %m");
return log_error_errno(r, "Failed to acquire randomized machine UUID: %m");
}
} else {
if (sd_id128_is_null(id)) {
log_error("Machine ID in container image is zero, refusing.");
return -EINVAL;
}
}
r = machine_id_setup(directory, arg_uuid);
if (r < 0)
return log_error_errno(r, "Failed to setup machine ID: %m");
arg_uuid = id;
}
return 0;
}
@ -2663,9 +2657,9 @@ static int inner_child(
(asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0))
return log_oom();
assert(!sd_id128_equal(arg_uuid, SD_ID128_NULL));
assert(!sd_id128_is_null(arg_uuid));
if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0)
if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_to_uuid_string(arg_uuid, as_uuid)) < 0)
return log_oom();
if (fdset_size(fds) > 0) {

View File

@ -3764,7 +3764,7 @@ static void print_status_info(
if (i->running) {
_cleanup_free_ char *comm = NULL;
get_process_comm(i->main_pid, &comm);
(void) get_process_comm(i->main_pid, &comm);
if (comm)
printf(" (%s)", comm);
} else if (i->exit_code > 0) {
@ -3783,17 +3783,19 @@ static void print_status_info(
printf("signal=%s", signal_to_string(i->exit_status));
printf(")");
}
if (i->control_pid > 0)
printf(";");
}
if (i->control_pid > 0) {
_cleanup_free_ char *c = NULL;
printf(" %8s: "PID_FMT, i->main_pid ? "" : " Control", i->control_pid);
if (i->main_pid > 0)
fputs("; Control PID: ", stdout);
else
fputs("Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */
get_process_comm(i->control_pid, &c);
printf(PID_FMT, i->control_pid);
(void) get_process_comm(i->control_pid, &c);
if (c)
printf(" (%s)", c);
}
@ -3810,7 +3812,7 @@ static void print_status_info(
printf(" Tasks: %" PRIu64, i->tasks_current);
if (i->tasks_max != (uint64_t) -1)
printf(" (limit: %" PRIi64 ")\n", i->tasks_max);
printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
else
printf("\n");
}

View File

@ -26,6 +26,7 @@
#include "macro.h"
#include "string-util.h"
#include "util.h"
#include "id128-util.h"
#define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10)
#define STR_WALDI "0102030405060708090a0b0c0d0e0f10"
@ -33,7 +34,7 @@
int main(int argc, char *argv[]) {
sd_id128_t id, id2;
char t[33];
char t[33], q[37];
_cleanup_free_ char *b = NULL;
assert_se(sd_id128_randomize(&id) == 0);
@ -57,6 +58,17 @@ int main(int argc, char *argv[]) {
printf("waldi2: %s\n", b);
assert_se(streq(t, b));
printf("waldi3: %s\n", id128_to_uuid_string(ID128_WALDI, q));
assert_se(streq(q, UUID_WALDI));
b = mfree(b);
assert_se(asprintf(&b, ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 36);
printf("waldi4: %s\n", b);
assert_se(streq(q, b));
assert_se(sd_id128_from_string(STR_WALDI, &id) >= 0);
assert_se(sd_id128_equal(id, ID128_WALDI));
assert_se(sd_id128_from_string(UUID_WALDI, &id) >= 0);
assert_se(sd_id128_equal(id, ID128_WALDI));