mirror of
https://github.com/systemd/systemd.git
synced 2025-03-31 14:50:15 +03:00
Merge pull request #7335 from poettering/dissect-meta-info
beef up image dissection, to gather image metadata
This commit is contained in:
commit
54c552eae6
@ -25,6 +25,8 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "def.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "hostname-util.h"
|
||||
@ -219,35 +221,55 @@ int sethostname_idempotent(const char *s) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int read_hostname_config(const char *path, char **hostname) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
char l[LINE_MAX];
|
||||
char *name = NULL;
|
||||
int read_etc_hostname_stream(FILE *f, char **ret) {
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(hostname);
|
||||
assert(f);
|
||||
assert(ret);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
char *p;
|
||||
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
|
||||
return -ENOENT;
|
||||
|
||||
p = strstrip(line);
|
||||
|
||||
/* File may have empty lines or comments, ignore them */
|
||||
if (!IN_SET(*p, '\0', '#')) {
|
||||
char *copy;
|
||||
|
||||
hostname_cleanup(p); /* normalize the hostname */
|
||||
|
||||
if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */
|
||||
return -EBADMSG;
|
||||
|
||||
copy = strdup(p);
|
||||
if (!copy)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = copy;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int read_etc_hostname(const char *path, char **ret) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
assert(ret);
|
||||
|
||||
if (!path)
|
||||
path = "/etc/hostname";
|
||||
|
||||
f = fopen(path, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
/* may have comments, ignore them */
|
||||
FOREACH_LINE(l, f, return -errno) {
|
||||
truncate_nl(l);
|
||||
if (!IN_SET(l[0], '\0', '#')) {
|
||||
/* found line with value */
|
||||
name = hostname_cleanup(l);
|
||||
name = strdup(name);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return read_etc_hostname_stream(f, ret);
|
||||
|
||||
if (!name)
|
||||
/* no non-empty line found */
|
||||
return -ENOENT;
|
||||
|
||||
*hostname = name;
|
||||
return 0;
|
||||
}
|
||||
|
@ -39,4 +39,5 @@ bool is_gateway_hostname(const char *hostname);
|
||||
|
||||
int sethostname_idempotent(const char *s);
|
||||
|
||||
int read_hostname_config(const char *path, char **hostname);
|
||||
int read_etc_hostname_stream(FILE *f, char **ret);
|
||||
int read_etc_hostname(const char *path, char **ret);
|
||||
|
@ -45,11 +45,11 @@ static inline void block_signals_reset(sigset_t *ss) {
|
||||
assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0);
|
||||
}
|
||||
|
||||
#define BLOCK_SIGNALS(...) \
|
||||
_cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \
|
||||
sigset_t t; \
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \
|
||||
t; \
|
||||
#define BLOCK_SIGNALS(...) \
|
||||
_cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \
|
||||
sigset_t _t; \
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__, -1) >= 0); \
|
||||
_t; \
|
||||
})
|
||||
|
||||
static inline bool SIGNAL_VALID(int signo) {
|
||||
|
@ -181,3 +181,11 @@ char **strv_skip(char **l, size_t n);
|
||||
int strv_extend_n(char ***l, const char *value, size_t n);
|
||||
|
||||
int fputstrv(FILE *f, char **l, const char *separator, bool *space);
|
||||
|
||||
#define strv_free_and_replace(a, b) \
|
||||
({ \
|
||||
strv_free(a); \
|
||||
(a) = (b); \
|
||||
(b) = NULL; \
|
||||
0; \
|
||||
})
|
||||
|
@ -37,7 +37,7 @@ int hostname_setup(void) {
|
||||
const char *hn;
|
||||
int r;
|
||||
|
||||
r = read_hostname_config("/etc/hostname", &b);
|
||||
r = read_etc_hostname(NULL, &b);
|
||||
if (r < 0) {
|
||||
if (r == -ENOENT)
|
||||
enoent = true;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "log.h"
|
||||
#include "loop-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "util.h"
|
||||
|
||||
static enum {
|
||||
@ -264,6 +265,36 @@ int main(int argc, char *argv[]) {
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
r = dissected_image_acquire_metadata(m);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to acquire image metadata: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (m->hostname)
|
||||
printf(" Hostname: %s\n", m->hostname);
|
||||
|
||||
if (!sd_id128_is_null(m->machine_id))
|
||||
printf("Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->machine_id));
|
||||
|
||||
if (!strv_isempty(m->machine_info)) {
|
||||
char **p, **q;
|
||||
|
||||
STRV_FOREACH_PAIR(p, q, m->machine_info)
|
||||
printf("%s %s=%s\n",
|
||||
p == m->machine_info ? "Mach. Info:" : " ",
|
||||
*p, *q);
|
||||
}
|
||||
|
||||
if (!strv_isempty(m->os_release)) {
|
||||
char **p, **q;
|
||||
|
||||
STRV_FOREACH_PAIR(p, q, m->os_release)
|
||||
printf("%s %s=%s\n",
|
||||
p == m->os_release ? "OS Release:" : " ",
|
||||
*p, *q);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ static int context_read_data(Context *c) {
|
||||
if (!c->data[PROP_HOSTNAME])
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_hostname_config("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
|
||||
r = read_etc_hostname(NULL, &c->data[PROP_STATIC_HOSTNAME]);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
|
@ -290,124 +290,68 @@ int bus_image_method_set_limit(
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
#define EXIT_NOT_FOUND 2
|
||||
int bus_image_method_get_hostname(
|
||||
sd_bus_message *message,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
static int directory_image_get_os_release(Image *image, char ***ret, sd_bus_error *error) {
|
||||
|
||||
_cleanup_free_ char *path = NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
Image *image = userdata;
|
||||
int r;
|
||||
|
||||
assert(image);
|
||||
assert(ret);
|
||||
|
||||
r = chase_symlinks("/etc/os-release", image->path, CHASE_PREFIX_ROOT, &path);
|
||||
if (r == -ENOENT)
|
||||
r = chase_symlinks("/usr/lib/os-release", image->path, CHASE_PREFIX_ROOT, &path);
|
||||
if (r == -ENOENT)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Image does not contain OS release information");
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to resolve %s: %m", image->path);
|
||||
|
||||
r = load_env_file_pairs(NULL, path, NULL, ret);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to open %s: %m", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_image_get_os_release(Image *image, char ***ret, sd_bus_error *error) {
|
||||
_cleanup_(rmdir_and_freep) char *t = NULL;
|
||||
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
|
||||
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
|
||||
_cleanup_(sigkill_waitp) pid_t child = 0;
|
||||
_cleanup_close_pair_ int pair[2] = { -1, -1 };
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_strv_free_ char **v = NULL;
|
||||
siginfo_t si;
|
||||
int r;
|
||||
|
||||
assert(image);
|
||||
assert(ret);
|
||||
|
||||
r = mkdtemp_malloc("/tmp/machined-root-XXXXXX", &t);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to create temporary directory: %m");
|
||||
|
||||
r = loop_device_make_by_path(image->path, O_RDONLY, &d);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to set up loop block device for %s: %m", image->path);
|
||||
|
||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
|
||||
if (r == -ENOPKG)
|
||||
return sd_bus_error_set_errnof(error, r, "Disk image %s not understood: %m", image->path);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to dissect image %s: %m", image->path);
|
||||
|
||||
if (pipe2(pair, O_CLOEXEC) < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to create communication pipe: %m");
|
||||
|
||||
child = raw_clone(SIGCHLD|CLONE_NEWNS);
|
||||
if (child < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
|
||||
|
||||
if (child == 0) {
|
||||
int fd;
|
||||
|
||||
pair[0] = safe_close(pair[0]);
|
||||
|
||||
/* Make sure we never propagate to the host */
|
||||
if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
r = dissected_image_mount(m, t, DISSECT_IMAGE_READ_ONLY);
|
||||
if (!image->metadata_valid) {
|
||||
r = image_read_metadata(image);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
r = mount_move_root(t);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0 && errno == ENOENT) {
|
||||
fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0 && errno == ENOENT)
|
||||
_exit(EXIT_NOT_FOUND);
|
||||
}
|
||||
if (fd < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
r = copy_bytes(fd, pair[1], (uint64_t) -1, 0);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
|
||||
}
|
||||
|
||||
pair[1] = safe_close(pair[1]);
|
||||
return sd_bus_reply_method_return(message, "s", image->hostname);
|
||||
}
|
||||
|
||||
f = fdopen(pair[0], "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
int bus_image_method_get_machine_id(
|
||||
sd_bus_message *message,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
pair[0] = -1;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
Image *image = userdata;
|
||||
int r;
|
||||
|
||||
r = load_env_file_pairs(f, "os-release", NULL, &v);
|
||||
if (!image->metadata_valid) {
|
||||
r = image_read_metadata(image);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
|
||||
}
|
||||
|
||||
r = sd_bus_message_new_method_return(message, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = wait_for_terminate(child, &si);
|
||||
if (sd_id128_is_null(image->machine_id)) /* Add an empty array if the ID is zero */
|
||||
r = sd_bus_message_append(reply, "ay", 0);
|
||||
else
|
||||
r = sd_bus_message_append_array(reply, 'y', image->machine_id.bytes, 16);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
|
||||
child = 0;
|
||||
if (si.si_code == CLD_EXITED && si.si_status == EXIT_NOT_FOUND)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Image does not contain OS release information");
|
||||
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
|
||||
return r;
|
||||
|
||||
*ret = v;
|
||||
v = NULL;
|
||||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
int bus_image_method_get_machine_info(
|
||||
sd_bus_message *message,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
Image *image = userdata;
|
||||
int r;
|
||||
|
||||
if (!image->metadata_valid) {
|
||||
r = image_read_metadata(image);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
|
||||
}
|
||||
|
||||
return bus_reply_pair_array(message, image->machine_info);
|
||||
}
|
||||
|
||||
int bus_image_method_get_os_release(
|
||||
@ -415,34 +359,16 @@ int bus_image_method_get_os_release(
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
|
||||
_cleanup_strv_free_ char **v = NULL;
|
||||
Image *image = userdata;
|
||||
int r;
|
||||
|
||||
r = image_path_lock(image->path, LOCK_SH|LOCK_NB, &tree_global_lock, &tree_local_lock);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to lock image: %m");
|
||||
|
||||
switch (image->type) {
|
||||
|
||||
case IMAGE_DIRECTORY:
|
||||
case IMAGE_SUBVOLUME:
|
||||
r = directory_image_get_os_release(image, &v, error);
|
||||
break;
|
||||
|
||||
case IMAGE_RAW:
|
||||
case IMAGE_BLOCK:
|
||||
r = raw_image_get_os_release(image, &v, error);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Unknown image type");
|
||||
if (!image->metadata_valid) {
|
||||
r = image_read_metadata(image);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return bus_reply_pair_array(message, v);
|
||||
return bus_reply_pair_array(message, image->os_release);
|
||||
}
|
||||
|
||||
const sd_bus_vtable image_vtable[] = {
|
||||
@ -462,6 +388,9 @@ const sd_bus_vtable image_vtable[] = {
|
||||
SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetHostname", NULL, "s", bus_image_method_get_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetMachineID", NULL, "ay", bus_image_method_get_machine_id, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetMachineInfo", NULL, "a{ss}", bus_image_method_get_machine_info, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_image_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
@ -34,4 +34,7 @@ int bus_image_method_rename(sd_bus_message *message, void *userdata, sd_bus_erro
|
||||
int bus_image_method_clone(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_image_method_mark_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_image_method_set_limit(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_image_method_get_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_image_method_get_machine_id(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_image_method_get_machine_info(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
int bus_image_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error);
|
||||
|
@ -900,6 +900,100 @@ static int show_machine(int argc, char *argv[], void *userdata) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int print_image_hostname(sd_bus *bus, const char *name) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
const char *hn;
|
||||
int r;
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.machine1",
|
||||
"/org/freedesktop/machine1",
|
||||
"org.freedesktop.machine1.Manager",
|
||||
"GetImageHostname",
|
||||
NULL, &reply, "s", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(reply, "s", &hn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!isempty(hn))
|
||||
printf("\tHostname: %s\n", hn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_image_machine_id(sd_bus *bus, const char *name) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
sd_id128_t id = SD_ID128_NULL;
|
||||
const void *p;
|
||||
size_t size;
|
||||
int r;
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.machine1",
|
||||
"/org/freedesktop/machine1",
|
||||
"org.freedesktop.machine1.Manager",
|
||||
"GetImageMachineID",
|
||||
NULL, &reply, "s", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read_array(reply, 'y', &p, &size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (size == sizeof(sd_id128_t))
|
||||
memcpy(&id, p, size);
|
||||
|
||||
if (!sd_id128_is_null(id))
|
||||
printf(" Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_image_machine_info(sd_bus *bus, const char *name) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
int r;
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.machine1",
|
||||
"/org/freedesktop/machine1",
|
||||
"org.freedesktop.machine1.Manager",
|
||||
"GetImageMachineInfo",
|
||||
NULL, &reply, "s", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "{ss}");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
const char *p, *q;
|
||||
|
||||
r = sd_bus_message_read(reply, "{ss}", &p, &q);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (streq(p, "DEPLOYMENT"))
|
||||
printf(" Deployment: %s\n", q);
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct ImageStatusInfo {
|
||||
char *name;
|
||||
char *path;
|
||||
@ -914,12 +1008,13 @@ typedef struct ImageStatusInfo {
|
||||
} ImageStatusInfo;
|
||||
|
||||
static void image_status_info_clear(ImageStatusInfo *info) {
|
||||
if (info) {
|
||||
free(info->name);
|
||||
free(info->path);
|
||||
free(info->type);
|
||||
zero(*info);
|
||||
}
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
free(info->name);
|
||||
free(info->path);
|
||||
free(info->type);
|
||||
zero(*info);
|
||||
}
|
||||
|
||||
static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
|
||||
@ -942,6 +1037,10 @@ static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
|
||||
if (i->path)
|
||||
printf("\t Path: %s\n", i->path);
|
||||
|
||||
(void) print_image_hostname(bus, i->name);
|
||||
(void) print_image_machine_id(bus, i->name);
|
||||
(void) print_image_machine_info(bus, i->name);
|
||||
|
||||
print_os_release(bus, "GetImageOSRelease", i->name, "\t OS: ");
|
||||
|
||||
printf("\t RO: %s%s%s\n",
|
||||
|
@ -846,6 +846,78 @@ static int method_mark_image_read_only(sd_bus_message *message, void *userdata,
|
||||
return bus_image_method_mark_read_only(message, i, error);
|
||||
}
|
||||
|
||||
static int method_get_image_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(image_unrefp) Image *i = NULL;
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
|
||||
r = sd_bus_message_read(message, "s", &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!image_name_is_valid(name))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
|
||||
|
||||
r = image_find(name, &i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
|
||||
|
||||
i->userdata = userdata;
|
||||
return bus_image_method_get_hostname(message, i, error);
|
||||
}
|
||||
|
||||
static int method_get_image_machine_id(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(image_unrefp) Image *i = NULL;
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
|
||||
r = sd_bus_message_read(message, "s", &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!image_name_is_valid(name))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
|
||||
|
||||
r = image_find(name, &i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
|
||||
|
||||
i->userdata = userdata;
|
||||
return bus_image_method_get_machine_id(message, i, error);
|
||||
}
|
||||
|
||||
static int method_get_image_machine_info(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(image_unrefp) Image *i = NULL;
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
|
||||
r = sd_bus_message_read(message, "s", &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!image_name_is_valid(name))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
|
||||
|
||||
r = image_find(name, &i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
|
||||
|
||||
i->userdata = userdata;
|
||||
return bus_image_method_get_machine_info(message, i, error);
|
||||
}
|
||||
|
||||
static int method_get_image_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(image_unrefp) Image *i = NULL;
|
||||
const char *name;
|
||||
@ -1442,6 +1514,9 @@ const sd_bus_vtable manager_vtable[] = {
|
||||
SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetImageHostname", "s", "s", method_get_image_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetImageMachineID", "s", "ay", method_get_image_machine_id, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetImageMachineInfo", "s", "a{ss}", method_get_image_machine_info, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetImageOSRelease", "s", "a{ss}", method_get_image_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
@ -120,6 +120,18 @@
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="SetImageLimit"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="GetImageHostname"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="GetImageMachineID"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="GetImageMachineInfo"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="GetImageOSRelease"/>
|
||||
@ -204,6 +216,18 @@
|
||||
send_interface="org.freedesktop.machine1.Image"
|
||||
send_member="MarkReadOnly"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Image"
|
||||
send_member="GetHostname"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Image"
|
||||
send_member="GetMachineID"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Image"
|
||||
send_member="GetMachineInfo"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Image"
|
||||
send_member="GetOSRelease"/>
|
||||
|
@ -25,19 +25,28 @@
|
||||
#endif
|
||||
#endif
|
||||
#include <sys/mount.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "architecture.h"
|
||||
#include "ask-password-api.h"
|
||||
#include "blkid-util.h"
|
||||
#include "copy.h"
|
||||
#include "def.h"
|
||||
#include "dissect-image.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "gpt.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "hostname-util.h"
|
||||
#include "id128-util.h"
|
||||
#include "linux-3.13/dm-ioctl.h"
|
||||
#include "mount-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "raw-clone.h"
|
||||
#include "signal-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-table.h"
|
||||
@ -635,6 +644,10 @@ DissectedImage* dissected_image_unref(DissectedImage *m) {
|
||||
free(m->partitions[i].decrypted_node);
|
||||
}
|
||||
|
||||
free(m->hostname);
|
||||
strv_free(m->machine_info);
|
||||
strv_free(m->os_release);
|
||||
|
||||
free(m);
|
||||
return NULL;
|
||||
}
|
||||
@ -1193,6 +1206,174 @@ int root_hash_load(const char *image, void **ret, size_t *ret_size) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dissected_image_acquire_metadata(DissectedImage *m) {
|
||||
|
||||
enum {
|
||||
META_HOSTNAME,
|
||||
META_MACHINE_ID,
|
||||
META_MACHINE_INFO,
|
||||
META_OS_RELEASE,
|
||||
_META_MAX,
|
||||
};
|
||||
|
||||
static const char *const paths[_META_MAX] = {
|
||||
[META_HOSTNAME] = "/etc/hostname\0",
|
||||
[META_MACHINE_ID] = "/etc/machine-id\0",
|
||||
[META_MACHINE_INFO] = "/etc/machine-info\0",
|
||||
[META_OS_RELEASE] = "/etc/os-release\0/usr/lib/os-release\0",
|
||||
};
|
||||
|
||||
_cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;
|
||||
_cleanup_(rmdir_and_freep) char *t = NULL;
|
||||
_cleanup_(sigkill_waitp) pid_t child = 0;
|
||||
sd_id128_t machine_id = SD_ID128_NULL;
|
||||
_cleanup_free_ char *hostname = NULL;
|
||||
unsigned n_meta_initialized = 0, k;
|
||||
int fds[2 * _META_MAX], r;
|
||||
siginfo_t si;
|
||||
|
||||
BLOCK_SIGNALS(SIGCHLD);
|
||||
|
||||
assert(m);
|
||||
|
||||
for (; n_meta_initialized < _META_MAX; n_meta_initialized ++)
|
||||
if (pipe2(fds + 2*n_meta_initialized, O_CLOEXEC) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = mkdtemp_malloc("/tmp/dissect-XXXXXX", &t);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
child = raw_clone(SIGCHLD|CLONE_NEWNS);
|
||||
if (child < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
/* Make sure we never propagate to the host */
|
||||
if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
r = dissected_image_mount(m, t, DISSECT_IMAGE_READ_ONLY);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
for (k = 0; k < _META_MAX; k++) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
const char *p;
|
||||
|
||||
fds[2*k] = safe_close(fds[2*k]);
|
||||
|
||||
NULSTR_FOREACH(p, paths[k]) {
|
||||
_cleanup_free_ char *q = NULL;
|
||||
|
||||
r = chase_symlinks(p, t, CHASE_PREFIX_ROOT, &q);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
fd = open(q, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd >= 0)
|
||||
break;
|
||||
}
|
||||
if (fd < 0)
|
||||
continue;
|
||||
|
||||
r = copy_bytes(fd, fds[2*k+1], (uint64_t) -1, 0);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
fds[2*k+1] = safe_close(fds[2*k+1]);
|
||||
}
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
for (k = 0; k < _META_MAX; k++) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
fds[2*k+1] = safe_close(fds[2*k+1]);
|
||||
|
||||
f = fdopen(fds[2*k], "re");
|
||||
if (!f) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fds[2*k] = -1;
|
||||
|
||||
switch (k) {
|
||||
|
||||
case META_HOSTNAME:
|
||||
r = read_etc_hostname_stream(f, &hostname);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to read /etc/hostname: %m");
|
||||
|
||||
break;
|
||||
|
||||
case META_MACHINE_ID: {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to read /etc/machine-id: %m");
|
||||
else if (r == 33) {
|
||||
r = sd_id128_from_string(line, &machine_id);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Image contains invalid /etc/machine-id: %s", line);
|
||||
} else if (r == 0)
|
||||
log_debug("/etc/machine-id file is empty.");
|
||||
else
|
||||
log_debug("/etc/machine-id has unexpected length %i.", r);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case META_MACHINE_INFO:
|
||||
r = load_env_file_pairs(f, "machine-info", NULL, &machine_info);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to read /etc/machine-info: %m");
|
||||
|
||||
break;
|
||||
|
||||
case META_OS_RELEASE:
|
||||
r = load_env_file_pairs(f, "os-release", NULL, &os_release);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to read OS release file: %m");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
r = wait_for_terminate(child, &si);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
child = 0;
|
||||
|
||||
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) {
|
||||
r = -EPROTO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
free_and_replace(m->hostname, hostname);
|
||||
m->machine_id = machine_id;
|
||||
strv_free_and_replace(m->machine_info, machine_info);
|
||||
strv_free_and_replace(m->os_release, os_release);
|
||||
|
||||
finish:
|
||||
for (k = 0; k < n_meta_initialized; k++)
|
||||
safe_close_pair(fds + 2*k);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const char *const partition_designator_table[] = {
|
||||
[PARTITION_ROOT] = "root",
|
||||
[PARTITION_ROOT_SECONDARY] = "root-secondary",
|
||||
|
@ -77,7 +77,13 @@ struct DissectedImage {
|
||||
bool encrypted:1;
|
||||
bool verity:1; /* verity available and usable */
|
||||
bool can_verity:1; /* verity available, but not necessarily used */
|
||||
|
||||
DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX];
|
||||
|
||||
char *hostname;
|
||||
sd_id128_t machine_id;
|
||||
char **machine_info;
|
||||
char **os_release;
|
||||
};
|
||||
|
||||
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret);
|
||||
@ -89,6 +95,8 @@ int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const voi
|
||||
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret);
|
||||
int dissected_image_mount(DissectedImage *m, const char *dest, DissectImageFlags flags);
|
||||
|
||||
int dissected_image_acquire_metadata(DissectedImage *m);
|
||||
|
||||
DecryptedImage* decrypted_image_unref(DecryptedImage *p);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DecryptedImage*, decrypted_image_unref);
|
||||
int decrypted_image_relinquish(DecryptedImage *d);
|
||||
|
@ -34,12 +34,17 @@
|
||||
#include "chattr-util.h"
|
||||
#include "copy.h"
|
||||
#include "dirent-util.h"
|
||||
#include "dissect-image.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "hostname-util.h"
|
||||
#include "id128-util.h"
|
||||
#include "lockfile-util.h"
|
||||
#include "log.h"
|
||||
#include "loop-util.h"
|
||||
#include "machine-image.h"
|
||||
#include "macro.h"
|
||||
#include "mkdir.h"
|
||||
@ -65,6 +70,11 @@ Image *image_unref(Image *i) {
|
||||
|
||||
free(i->name);
|
||||
free(i->path);
|
||||
|
||||
free(i->hostname);
|
||||
strv_free(i->machine_info);
|
||||
strv_free(i->os_release);
|
||||
|
||||
return mfree(i);
|
||||
}
|
||||
|
||||
@ -761,6 +771,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
|
||||
int image_read_only(Image *i, bool b) {
|
||||
_cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
|
||||
if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
|
||||
@ -924,6 +935,118 @@ int image_set_limit(Image *i, uint64_t referenced_max) {
|
||||
return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max);
|
||||
}
|
||||
|
||||
int image_read_metadata(Image *i) {
|
||||
_cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
|
||||
r = image_path_lock(i->path, LOCK_SH|LOCK_NB, &global_lock, &local_lock);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
switch (i->type) {
|
||||
|
||||
case IMAGE_SUBVOLUME:
|
||||
case IMAGE_DIRECTORY: {
|
||||
_cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;
|
||||
sd_id128_t machine_id = SD_ID128_NULL;
|
||||
_cleanup_free_ char *hostname = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
|
||||
r = chase_symlinks("/etc/hostname", i->path, CHASE_PREFIX_ROOT, &path);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to chase /etc/hostname in image %s: %m", i->name);
|
||||
else if (r >= 0) {
|
||||
r = read_etc_hostname(path, &hostname);
|
||||
if (r < 0)
|
||||
log_debug_errno(errno, "Failed to read /etc/hostname of image %s: %m", i->name);
|
||||
}
|
||||
|
||||
path = mfree(path);
|
||||
|
||||
r = chase_symlinks("/etc/machine-id", i->path, CHASE_PREFIX_ROOT, &path);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to chase /etc/machine-id in image %s: %m", i->name);
|
||||
else if (r >= 0) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
log_debug_errno(errno, "Failed to open %s: %m", path);
|
||||
else {
|
||||
r = id128_read_fd(fd, ID128_PLAIN, &machine_id);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Image %s contains invalid machine ID.", i->name);
|
||||
}
|
||||
}
|
||||
|
||||
path = mfree(path);
|
||||
|
||||
r = chase_symlinks("/etc/machine-info", i->path, CHASE_PREFIX_ROOT, &path);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to chase /etc/machine-info in image %s: %m", i->name);
|
||||
else if (r >= 0) {
|
||||
r = load_env_file_pairs(NULL, path, NULL, &machine_info);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to parse machine-info data of %s: %m", i->name);
|
||||
}
|
||||
|
||||
path = mfree(path);
|
||||
|
||||
r = chase_symlinks("/etc/os-release", i->path, CHASE_PREFIX_ROOT, &path);
|
||||
if (r == -ENOENT)
|
||||
r = chase_symlinks("/usr/lib/os-release", i->path, CHASE_PREFIX_ROOT, &path);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to chase os-release in image: %m");
|
||||
else if (r >= 0) {
|
||||
r = load_env_file_pairs(NULL, path, NULL, &os_release);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to parse os-release data of %s: %m", i->name);
|
||||
}
|
||||
|
||||
free_and_replace(i->hostname, hostname);
|
||||
i->machine_id = machine_id;
|
||||
strv_free_and_replace(i->machine_info, machine_info);
|
||||
strv_free_and_replace(i->os_release, os_release);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IMAGE_RAW:
|
||||
case IMAGE_BLOCK: {
|
||||
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
|
||||
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
|
||||
|
||||
r = loop_device_make_by_path(i->path, O_RDONLY, &d);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_acquire_metadata(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
free_and_replace(i->hostname, m->hostname);
|
||||
i->machine_id = m->machine_id;
|
||||
strv_free_and_replace(i->machine_info, m->machine_info);
|
||||
strv_free_and_replace(i->os_release, m->os_release);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
i->metadata_valid = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int image_name_lock(const char *name, int operation, LockFile *ret) {
|
||||
const char *p;
|
||||
|
||||
|
@ -53,6 +53,13 @@ typedef struct Image {
|
||||
uint64_t limit;
|
||||
uint64_t limit_exclusive;
|
||||
|
||||
char *hostname;
|
||||
sd_id128_t machine_id;
|
||||
char **machine_info;
|
||||
char **os_release;
|
||||
|
||||
bool metadata_valid;
|
||||
|
||||
void *userdata;
|
||||
} Image;
|
||||
|
||||
@ -80,6 +87,8 @@ int image_name_lock(const char *name, int operation, LockFile *ret);
|
||||
|
||||
int image_set_limit(Image *i, uint64_t referenced_max);
|
||||
|
||||
int image_read_metadata(Image *i);
|
||||
|
||||
static inline bool IMAGE_IS_HIDDEN(const struct Image *i) {
|
||||
assert(i);
|
||||
|
||||
|
@ -100,7 +100,7 @@ static void test_hostname_cleanup(void) {
|
||||
assert_se(streq(hostname_cleanup(s), "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
|
||||
}
|
||||
|
||||
static void test_read_hostname_config(void) {
|
||||
static void test_read_etc_hostname(void) {
|
||||
char path[] = "/tmp/hostname.XXXXXX";
|
||||
char *hostname;
|
||||
int fd;
|
||||
@ -111,27 +111,27 @@ static void test_read_hostname_config(void) {
|
||||
|
||||
/* simple hostname */
|
||||
write_string_file(path, "foo", WRITE_STRING_FILE_CREATE);
|
||||
assert_se(read_hostname_config(path, &hostname) == 0);
|
||||
assert_se(read_etc_hostname(path, &hostname) == 0);
|
||||
assert_se(streq(hostname, "foo"));
|
||||
hostname = mfree(hostname);
|
||||
|
||||
/* with comment */
|
||||
write_string_file(path, "# comment\nfoo", WRITE_STRING_FILE_CREATE);
|
||||
assert_se(read_hostname_config(path, &hostname) == 0);
|
||||
assert_se(read_etc_hostname(path, &hostname) == 0);
|
||||
assert_se(hostname);
|
||||
assert_se(streq(hostname, "foo"));
|
||||
hostname = mfree(hostname);
|
||||
|
||||
/* with comment and extra whitespace */
|
||||
write_string_file(path, "# comment\n\n foo ", WRITE_STRING_FILE_CREATE);
|
||||
assert_se(read_hostname_config(path, &hostname) == 0);
|
||||
assert_se(read_etc_hostname(path, &hostname) == 0);
|
||||
assert_se(hostname);
|
||||
assert_se(streq(hostname, "foo"));
|
||||
hostname = mfree(hostname);
|
||||
|
||||
/* cleans up name */
|
||||
write_string_file(path, "!foo/bar.com", WRITE_STRING_FILE_CREATE);
|
||||
assert_se(read_hostname_config(path, &hostname) == 0);
|
||||
assert_se(read_etc_hostname(path, &hostname) == 0);
|
||||
assert_se(hostname);
|
||||
assert_se(streq(hostname, "foobar.com"));
|
||||
hostname = mfree(hostname);
|
||||
@ -139,11 +139,11 @@ static void test_read_hostname_config(void) {
|
||||
/* no value set */
|
||||
hostname = (char*) 0x1234;
|
||||
write_string_file(path, "# nothing here\n", WRITE_STRING_FILE_CREATE);
|
||||
assert_se(read_hostname_config(path, &hostname) == -ENOENT);
|
||||
assert_se(read_etc_hostname(path, &hostname) == -ENOENT);
|
||||
assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */
|
||||
|
||||
/* nonexisting file */
|
||||
assert_se(read_hostname_config("/non/existing", &hostname) == -ENOENT);
|
||||
assert_se(read_etc_hostname("/non/existing", &hostname) == -ENOENT);
|
||||
assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */
|
||||
|
||||
unlink(path);
|
||||
@ -155,7 +155,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
test_hostname_is_valid();
|
||||
test_hostname_cleanup();
|
||||
test_read_hostname_config();
|
||||
test_read_etc_hostname();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user