From: Lennart Poettering Date: Thu, 24 Jun 2021 16:06:02 +0000 (+0200) Subject: tree-wide: make specifier expansion --root= aware X-Git-Tag: v249-rc2~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=de61a04b188f81a85cdb5c64ddb4987dcd9d30d3;p=thirdparty%2Fsystemd.git tree-wide: make specifier expansion --root= aware This fixes repart's, systemctl's, sysusers' and tmpfiles' specifier expansion to honour the root dir specified with --root=. This is relevant for specifiers such as %m, %o, … which are directly sourced from files on disk. This doesn't try to be overly smart: specifiers referring to runtime concepts (i.e. boot ID, architecture, hostname) rather than files on the medium are left as is. There's certainly a point to be made that they should fail in case --root= is specified, but I am not entirely convinced about that, and it's certainly something we can look into later if there's reason to. I wondered for a while how to hook this up best, but given that quite a large number of specifiers resolve to data from files on disks, and most of our tools needs this, I ultimately decided to make the root dir a first class parameter to specifier_printf(). Replaces: #16187 Fixes: #16183 --- diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index b18f3b34d16..b0f24695409 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2660,7 +2660,7 @@ int config_parse_environ( if (u) r = unit_env_printf(u, word, &resolved); else - r = specifier_printf(word, sc_arg_max(), system_and_tmp_specifier_table, NULL, &resolved); + r = specifier_printf(word, sc_arg_max(), system_and_tmp_specifier_table, NULL, NULL, &resolved); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve specifiers in %s, ignoring: %m", word); diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index 113dd1cc8a5..46c383b8419 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -12,7 +12,7 @@ #include "unit.h" #include "user-util.h" -static int specifier_prefix_and_instance(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_prefix_and_instance(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const Unit *u = userdata; assert(u); @@ -20,7 +20,7 @@ static int specifier_prefix_and_instance(char specifier, const void *data, const return unit_name_to_prefix_and_instance(u->id, ret); } -static int specifier_prefix(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_prefix(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const Unit *u = userdata; assert(u); @@ -28,7 +28,7 @@ static int specifier_prefix(char specifier, const void *data, const void *userda return unit_name_to_prefix(u->id, ret); } -static int specifier_prefix_unescaped(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_prefix_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) { _cleanup_free_ char *p = NULL; const Unit *u = userdata; int r; @@ -42,7 +42,7 @@ static int specifier_prefix_unescaped(char specifier, const void *data, const vo return unit_name_unescape(p, ret); } -static int specifier_instance_unescaped(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_instance_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const Unit *u = userdata; assert(u); @@ -50,7 +50,7 @@ static int specifier_instance_unescaped(char specifier, const void *data, const return unit_name_unescape(strempty(u->instance), ret); } -static int specifier_last_component(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_last_component(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const Unit *u = userdata; _cleanup_free_ char *prefix = NULL; char *dash; @@ -64,24 +64,24 @@ static int specifier_last_component(char specifier, const void *data, const void dash = strrchr(prefix, '-'); if (dash) - return specifier_string(specifier, dash + 1, userdata, ret); + return specifier_string(specifier, dash + 1, root, userdata, ret); *ret = TAKE_PTR(prefix); return 0; } -static int specifier_last_component_unescaped(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_last_component_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) { _cleanup_free_ char *p = NULL; int r; - r = specifier_last_component(specifier, data, userdata, &p); + r = specifier_last_component(specifier, data, root, userdata, &p); if (r < 0) return r; return unit_name_unescape(p, ret); } -static int specifier_filename(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_filename(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const Unit *u = userdata; assert(u); @@ -96,7 +96,7 @@ static void bad_specifier(const Unit *u, char specifier) { log_unit_warning(u, "Specifier '%%%c' used in unit configuration, which is deprecated. Please update your unit file, as it does not work as intended.", specifier); } -static int specifier_cgroup(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_cgroup(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const Unit *u = userdata; char *n; @@ -115,7 +115,7 @@ static int specifier_cgroup(char specifier, const void *data, const void *userda return 0; } -static int specifier_cgroup_root(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_cgroup_root(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const Unit *u = userdata; char *n; @@ -131,7 +131,7 @@ static int specifier_cgroup_root(char specifier, const void *data, const void *u return 0; } -static int specifier_cgroup_slice(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_cgroup_slice(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const Unit *u = userdata, *slice; char *n; @@ -154,7 +154,7 @@ static int specifier_cgroup_slice(char specifier, const void *data, const void * return 0; } -static int specifier_special_directory(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_special_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const Unit *u = userdata; char *n = NULL; @@ -198,7 +198,7 @@ int unit_name_printf(const Unit *u, const char* format, char **ret) { assert(format); assert(ret); - return specifier_printf(format, UNIT_NAME_MAX, table, u, ret); + return specifier_printf(format, UNIT_NAME_MAX, table, NULL, u, ret); } int unit_full_printf_full(const Unit *u, const char *format, size_t max_length, char **ret) { @@ -262,5 +262,5 @@ int unit_full_printf_full(const Unit *u, const char *format, size_t max_length, {} }; - return specifier_printf(format, max_length, table, u, ret); + return specifier_printf(format, max_length, table, NULL, u, ret); } diff --git a/src/partition/repart.c b/src/partition/repart.c index 1e4a10d37fb..d0ee02067b3 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -973,7 +973,7 @@ static int config_parse_label( /* Nota bene: the empty label is a totally valid one. Let's hence not follow our usual rule of * assigning the empty string to reset to default here, but really accept it as label to set. */ - r = specifier_printf(rvalue, GPT_LABEL_MAX, system_and_tmp_specifier_table, NULL, &resolved); + r = specifier_printf(rvalue, GPT_LABEL_MAX, system_and_tmp_specifier_table, arg_root, NULL, &resolved); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in Label=, ignoring: %s", rvalue); @@ -1138,7 +1138,7 @@ static int config_parse_copy_files( if (!isempty(p)) return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Too many arguments: %s", rvalue); - r = specifier_printf(source, PATH_MAX-1, system_and_tmp_specifier_table, NULL, &resolved_source); + r = specifier_printf(source, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_source); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in CopyFiles= source, ignoring: %s", rvalue); @@ -1149,7 +1149,7 @@ static int config_parse_copy_files( if (r < 0) return 0; - r = specifier_printf(target, PATH_MAX-1, system_and_tmp_specifier_table, NULL, &resolved_target); + r = specifier_printf(target, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_target); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in CopyFiles= target, ignoring: %s", resolved_target); @@ -1198,7 +1198,7 @@ static int config_parse_copy_blocks( return 0; } - r = specifier_printf(rvalue, PATH_MAX-1, system_and_tmp_specifier_table, NULL, &d); + r = specifier_printf(rvalue, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &d); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in CopyBlocks= source path, ignoring: %s", rvalue); @@ -1246,7 +1246,7 @@ static int config_parse_make_dirs( if (r == 0) return 0; - r = specifier_printf(word, PATH_MAX-1, system_and_tmp_specifier_table, NULL, &d); + r = specifier_printf(word, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &d); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in MakeDirectories= parameter, ignoring: %s", word); diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 9b7f7f9ba20..283c06345c5 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -255,7 +255,7 @@ int config_parse_dnssd_service_name( return 0; } - r = specifier_printf(rvalue, DNS_LABEL_MAX, specifier_table, NULL, &name); + r = specifier_printf(rvalue, DNS_LABEL_MAX, specifier_table, NULL, NULL, &name); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid service instance name template '%s', ignoring assignment: %m", rvalue); diff --git a/src/resolve/resolved-dnssd.c b/src/resolve/resolved-dnssd.c index 1c7f16c4d2a..ab2773e4e4b 100644 --- a/src/resolve/resolved-dnssd.c +++ b/src/resolve/resolved-dnssd.c @@ -135,7 +135,7 @@ static int dnssd_service_load(Manager *manager, const char *filename) { return 0; } -static int specifier_dnssd_host_name(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_dnssd_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { DnssdService *s = (DnssdService *) userdata; char *n; @@ -170,7 +170,7 @@ int dnssd_render_instance_name(DnssdService *s, char **ret_name) { assert(s); assert(s->name_template); - r = specifier_printf(s->name_template, DNS_LABEL_MAX, specifier_table, s, &name); + r = specifier_printf(s->name_template, DNS_LABEL_MAX, specifier_table, NULL, s, &name); if (r < 0) return log_debug_errno(r, "Failed to replace specifiers: %m"); diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c index a697b5c4e7b..403d6013c1f 100644 --- a/src/shared/install-printf.c +++ b/src/shared/install-printf.c @@ -13,7 +13,7 @@ #include "unit-name.h" #include "user-util.h" -static int specifier_prefix_and_instance(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_prefix_and_instance(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const UnitFileInstallInfo *i = userdata; _cleanup_free_ char *prefix = NULL; int r; @@ -37,7 +37,7 @@ static int specifier_prefix_and_instance(char specifier, const void *data, const return 0; } -static int specifier_name(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const UnitFileInstallInfo *i = userdata; char *ans; @@ -53,7 +53,7 @@ static int specifier_name(char specifier, const void *data, const void *userdata return 0; } -static int specifier_prefix(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_prefix(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const UnitFileInstallInfo *i = userdata; assert(i); @@ -61,7 +61,7 @@ static int specifier_prefix(char specifier, const void *data, const void *userda return unit_name_to_prefix(i->name, ret); } -static int specifier_instance(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_instance(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const UnitFileInstallInfo *i = userdata; char *instance; int r; @@ -82,12 +82,12 @@ static int specifier_instance(char specifier, const void *data, const void *user return 0; } -static int specifier_last_component(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_last_component(char specifier, const void *data, const char *root, const void *userdata, char **ret) { _cleanup_free_ char *prefix = NULL; char *dash; int r; - r = specifier_prefix(specifier, data, userdata, &prefix); + r = specifier_prefix(specifier, data, root, userdata, &prefix); if (r < 0) return r; @@ -103,7 +103,7 @@ static int specifier_last_component(char specifier, const void *data, const void return 0; } -int install_full_printf_internal(const UnitFileInstallInfo *i, const char *format, size_t max_length, char **ret) { +int install_full_printf_internal(const UnitFileInstallInfo *i, const char *format, size_t max_length, const char *root, char **ret) { /* This is similar to unit_name_printf() */ const Specifier table[] = { @@ -123,5 +123,5 @@ int install_full_printf_internal(const UnitFileInstallInfo *i, const char *forma assert(format); assert(ret); - return specifier_printf(format, max_length, table, i, ret); + return specifier_printf(format, max_length, table, root, i, ret); } diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h index 13a39829e97..af32acc2cad 100644 --- a/src/shared/install-printf.h +++ b/src/shared/install-printf.h @@ -4,10 +4,11 @@ #include "install.h" #include "unit-name.h" -int install_full_printf_internal(const UnitFileInstallInfo *i, const char *format, size_t max_length, char **ret); -static inline int install_name_printf(const UnitFileInstallInfo *i, const char *format, char **ret) { - return install_full_printf_internal(i, format, UNIT_NAME_MAX, ret); +int install_full_printf_internal(const UnitFileInstallInfo *i, const char *format, size_t max_length, const char *root, char **ret); + +static inline int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) { + return install_full_printf_internal(i, format, UNIT_NAME_MAX, root, ret); } -static inline int install_path_printf(const UnitFileInstallInfo *i, const char *format, char **ret) { - return install_full_printf_internal(i, format, PATH_MAX-1, ret); +static inline int install_path_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) { + return install_full_printf_internal(i, format, PATH_MAX-1, root, ret); } diff --git a/src/shared/install.c b/src/shared/install.c index 5a1427ee023..4bf868f8e9e 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -963,6 +963,7 @@ static void install_info_free(UnitFileInstallInfo *i) { free(i->name); free(i->path); + free(i->root); strv_free(i->aliases); strv_free(i->wanted_by); strv_free(i->required_by); @@ -1023,6 +1024,7 @@ static int install_info_add( InstallContext *c, const char *name, const char *path, + const char *root, bool auxiliary, UnitFileInstallInfo **ret) { @@ -1066,6 +1068,14 @@ static int install_info_add( goto fail; } + if (root) { + i->root = strdup(root); + if (!i->root) { + r = -ENOMEM; + goto fail; + } + } + if (path) { i->path = strdup(path); if (!i->path) { @@ -1147,11 +1157,11 @@ static int config_parse_also( if (r == 0) break; - r = install_name_printf(info, word, &printed); + r = install_name_printf(info, word, info->root, &printed); if (r < 0) return r; - r = install_info_add(c, printed, NULL, true, NULL); + r = install_info_add(c, printed, NULL, info->root, /* auxiliary= */ true, NULL); if (r < 0) return r; @@ -1194,7 +1204,7 @@ static int config_parse_default_instance( return log_syntax(unit, LOG_WARNING, filename, line, 0, "DefaultInstance= only makes sense for template units, ignoring."); - r = install_name_printf(i, rvalue, &printed); + r = install_name_printf(i, rvalue, i->root, &printed); if (r < 0) return r; @@ -1637,7 +1647,7 @@ static int install_info_traverse( bn = buffer; } - r = install_info_add(c, bn, NULL, false, &i); + r = install_info_add(c, bn, NULL, paths->root_dir, /* auxiliary= */ false, &i); if (r < 0) return r; @@ -1676,9 +1686,9 @@ static int install_info_add_auto( pp = prefix_roota(paths->root_dir, name_or_path); - return install_info_add(c, NULL, pp, false, ret); + return install_info_add(c, NULL, pp, paths->root_dir, /* auxiliary= */ false, ret); } else - return install_info_add(c, name_or_path, NULL, false, ret); + return install_info_add(c, name_or_path, NULL, paths->root_dir, /* auxiliary= */ false, ret); } static int install_info_discover( @@ -1820,7 +1830,7 @@ static int install_info_symlink_alias( STRV_FOREACH(s, i->aliases) { _cleanup_free_ char *alias_path = NULL, *dst = NULL, *dst_updated = NULL; - q = install_path_printf(i, *s, &dst); + q = install_path_printf(i, *s, i->root, &dst); if (q < 0) return q; @@ -1905,7 +1915,7 @@ static int install_info_symlink_wants( STRV_FOREACH(s, list) { _cleanup_free_ char *path = NULL, *dst = NULL; - q = install_name_printf(i, *s, &dst); + q = install_name_printf(i, *s, i->root, &dst); if (q < 0) return q; @@ -2687,7 +2697,7 @@ int unit_file_disable( if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) return -EINVAL; - r = install_info_add(&c, *i, NULL, false, NULL); + r = install_info_add(&c, *i, NULL, paths.root_dir, /* auxiliary= */ false, NULL); if (r < 0) return r; } diff --git a/src/shared/install.h b/src/shared/install.h index c3a0249f5f7..cdc54350356 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -79,6 +79,7 @@ enum UnitFileType { struct UnitFileInstallInfo { char *name; char *path; + char *root; char **aliases; char **wanted_by; diff --git a/src/shared/specifier.c b/src/shared/specifier.c index 1712c1c295f..cb4d6daf6a9 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -10,9 +10,11 @@ #include "alloc-util.h" #include "architecture.h" +#include "fd-util.h" #include "format-util.h" #include "fs-util.h" #include "hostname-util.h" +#include "id128-util.h" #include "macro.h" #include "os-util.h" #include "specifier.h" @@ -29,7 +31,7 @@ * and "%" used for escaping. */ #define POSSIBLE_SPECIFIERS ALPHANUMERICAL "%" -int specifier_printf(const char *text, size_t max_length, const Specifier table[], const void *userdata, char **ret) { +int specifier_printf(const char *text, size_t max_length, const Specifier table[], const char *root, const void *userdata, char **ret) { _cleanup_free_ char *result = NULL; bool percent = false; const char *f; @@ -60,7 +62,7 @@ int specifier_printf(const char *text, size_t max_length, const Specifier table[ _cleanup_free_ char *w = NULL; size_t k, j; - r = i->lookup(i->specifier, i->data, userdata, &w); + r = i->lookup(i->specifier, i->data, root, userdata, &w); if (r < 0) return r; @@ -104,7 +106,7 @@ int specifier_printf(const char *text, size_t max_length, const Specifier table[ /* Generic handler for simple string replacements */ -int specifier_string(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_string(char specifier, const void *data, const char *root, const void *userdata, char **ret) { char *n; n = strdup(strempty(data)); @@ -115,12 +117,21 @@ int specifier_string(char specifier, const void *data, const void *userdata, cha return 0; } -int specifier_machine_id(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_machine_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { sd_id128_t id; char *n; int r; - r = sd_id128_get_machine(&id); + if (root) { + _cleanup_close_ int fd = -1; + + fd = chase_symlinks_and_open("/etc/machine-id", root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL); + if (fd < 0) + return fd; + + r = id128_read_fd(fd, ID128_PLAIN, &id); + } else + r = sd_id128_get_machine(&id); if (r < 0) return r; @@ -132,7 +143,7 @@ int specifier_machine_id(char specifier, const void *data, const void *userdata, return 0; } -int specifier_boot_id(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_boot_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { sd_id128_t id; char *n; int r; @@ -149,7 +160,7 @@ int specifier_boot_id(char specifier, const void *data, const void *userdata, ch return 0; } -int specifier_host_name(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { char *n; n = gethostname_malloc(); @@ -160,7 +171,7 @@ int specifier_host_name(char specifier, const void *data, const void *userdata, return 0; } -int specifier_short_host_name(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_short_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { char *n; n = gethostname_short_malloc(); @@ -171,7 +182,7 @@ int specifier_short_host_name(char specifier, const void *data, const void *user return 0; } -int specifier_kernel_release(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_kernel_release(char specifier, const void *data, const char *root, const void *userdata, char **ret) { struct utsname uts; char *n; int r; @@ -188,7 +199,7 @@ int specifier_kernel_release(char specifier, const void *data, const void *userd return 0; } -int specifier_architecture(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_architecture(char specifier, const void *data, const char *root, const void *userdata, char **ret) { char *t; t = strdup(architecture_to_string(uname_architecture())); @@ -199,11 +210,11 @@ int specifier_architecture(char specifier, const void *data, const void *userdat return 0; } -static int specifier_os_release_common(const char *field, char **ret) { +static int specifier_os_release_common(const char *field, const char *root, char **ret) { char *t = NULL; int r; - r = parse_os_release(NULL, field, &t); + r = parse_os_release(root, field, &t); if (r < 0) return r; if (!t) { @@ -218,31 +229,31 @@ static int specifier_os_release_common(const char *field, char **ret) { return 0; } -int specifier_os_id(char specifier, const void *data, const void *userdata, char **ret) { - return specifier_os_release_common("ID", ret); +int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + return specifier_os_release_common("ID", root, ret); } -int specifier_os_version_id(char specifier, const void *data, const void *userdata, char **ret) { - return specifier_os_release_common("VERSION_ID", ret); +int specifier_os_version_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + return specifier_os_release_common("VERSION_ID", root, ret); } -int specifier_os_build_id(char specifier, const void *data, const void *userdata, char **ret) { - return specifier_os_release_common("BUILD_ID", ret); +int specifier_os_build_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + return specifier_os_release_common("BUILD_ID", root, ret); } -int specifier_os_variant_id(char specifier, const void *data, const void *userdata, char **ret) { - return specifier_os_release_common("VARIANT_ID", ret); +int specifier_os_variant_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + return specifier_os_release_common("VARIANT_ID", root, ret); } -int specifier_os_image_id(char specifier, const void *data, const void *userdata, char **ret) { - return specifier_os_release_common("IMAGE_ID", ret); +int specifier_os_image_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + return specifier_os_release_common("IMAGE_ID", root, ret); } -int specifier_os_image_version(char specifier, const void *data, const void *userdata, char **ret) { - return specifier_os_release_common("IMAGE_VERSION", ret); +int specifier_os_image_version(char specifier, const void *data, const char *root, const void *userdata, char **ret) { + return specifier_os_release_common("IMAGE_VERSION", root, ret); } -int specifier_group_name(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { char *t; t = gid_to_name(getgid()); @@ -253,14 +264,14 @@ int specifier_group_name(char specifier, const void *data, const void *userdata, return 0; } -int specifier_group_id(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_group_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { if (asprintf(ret, UID_FMT, getgid()) < 0) return -ENOMEM; return 0; } -int specifier_user_name(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_user_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) { char *t; /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able @@ -278,7 +289,7 @@ int specifier_user_name(char specifier, const void *data, const void *userdata, return 0; } -int specifier_user_id(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_user_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) { if (asprintf(ret, UID_FMT, getuid()) < 0) return -ENOMEM; @@ -286,7 +297,7 @@ int specifier_user_id(char specifier, const void *data, const void *userdata, ch return 0; } -int specifier_user_home(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_user_home(char specifier, const void *data, const char *root, const void *userdata, char **ret) { /* On PID 1 (which runs as root) this will not result in NSS, * which is good. See above */ @@ -294,7 +305,7 @@ int specifier_user_home(char specifier, const void *data, const void *userdata, return get_home_dir(ret); } -int specifier_user_shell(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_user_shell(char specifier, const void *data, const char *root, const void *userdata, char **ret) { /* On PID 1 (which runs as root) this will not result in NSS, * which is good. See above */ @@ -302,15 +313,18 @@ int specifier_user_shell(char specifier, const void *data, const void *userdata, return get_shell(ret); } -int specifier_tmp_dir(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_tmp_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const char *p; char *copy; int r; - r = tmp_dir(&p); - if (r < 0) - return r; - + if (root) /* If root dir is set, don't honour $TMP or similar */ + p = "/tmp"; + else { + r = tmp_dir(&p); + if (r < 0) + return r; + } copy = strdup(p); if (!copy) return -ENOMEM; @@ -319,15 +333,18 @@ int specifier_tmp_dir(char specifier, const void *data, const void *userdata, ch return 0; } -int specifier_var_tmp_dir(char specifier, const void *data, const void *userdata, char **ret) { +int specifier_var_tmp_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) { const char *p; char *copy; int r; - r = var_tmp_dir(&p); - if (r < 0) - return r; - + if (root) + p = "/var/tmp"; + else { + r = var_tmp_dir(&p); + if (r < 0) + return r; + } copy = strdup(p); if (!copy) return -ENOMEM; diff --git a/src/shared/specifier.h b/src/shared/specifier.h index 839515da427..c433ee2d63e 100644 --- a/src/shared/specifier.h +++ b/src/shared/specifier.h @@ -3,7 +3,7 @@ #include "string-util.h" -typedef int (*SpecifierCallback)(char specifier, const void *data, const void *userdata, char **ret); +typedef int (*SpecifierCallback)(char specifier, const void *data, const char *root, const void *userdata, char **ret); typedef struct Specifier { const char specifier; @@ -11,32 +11,32 @@ typedef struct Specifier { const void *data; } Specifier; -int specifier_printf(const char *text, size_t max_length, const Specifier table[], const void *userdata, char **ret); +int specifier_printf(const char *text, size_t max_length, const Specifier table[], const char *root, const void *userdata, char **ret); -int specifier_string(char specifier, const void *data, const void *userdata, char **ret); +int specifier_string(char specifier, const void *data, const char *root, const void *userdata, char **ret); -int specifier_machine_id(char specifier, const void *data, const void *userdata, char **ret); -int specifier_boot_id(char specifier, const void *data, const void *userdata, char **ret); -int specifier_host_name(char specifier, const void *data, const void *userdata, char **ret); -int specifier_short_host_name(char specifier, const void *data, const void *userdata, char **ret); -int specifier_kernel_release(char specifier, const void *data, const void *userdata, char **ret); -int specifier_architecture(char specifier, const void *data, const void *userdata, char **ret); -int specifier_os_id(char specifier, const void *data, const void *userdata, char **ret); -int specifier_os_version_id(char specifier, const void *data, const void *userdata, char **ret); -int specifier_os_build_id(char specifier, const void *data, const void *userdata, char **ret); -int specifier_os_variant_id(char specifier, const void *data, const void *userdata, char **ret); -int specifier_os_image_id(char specifier, const void *data, const void *userdata, char **ret); -int specifier_os_image_version(char specifier, const void *data, const void *userdata, char **ret); +int specifier_machine_id(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_boot_id(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_short_host_name(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_kernel_release(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_architecture(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_os_version_id(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_os_build_id(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_os_variant_id(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_os_image_id(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_os_image_version(char specifier, const void *data, const char *root, const void *userdata, char **ret); -int specifier_group_name(char specifier, const void *data, const void *userdata, char **ret); -int specifier_group_id(char specifier, const void *data, const void *userdata, char **ret); -int specifier_user_name(char specifier, const void *data, const void *userdata, char **ret); -int specifier_user_id(char specifier, const void *data, const void *userdata, char **ret); -int specifier_user_home(char specifier, const void *data, const void *userdata, char **ret); -int specifier_user_shell(char specifier, const void *data, const void *userdata, char **ret); +int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_group_id(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_user_name(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_user_id(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_user_home(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_user_shell(char specifier, const void *data, const char *root, const void *userdata, char **ret); -int specifier_tmp_dir(char specifier, const void *data, const void *userdata, char **ret); -int specifier_var_tmp_dir(char specifier, const void *data, const void *userdata, char **ret); +int specifier_tmp_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret); +int specifier_var_tmp_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret); /* Typically, in places where one of the above specifier is to be resolved the other similar ones are to be * resolved, too. Hence let's define common macros for the relevant array entries. diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 4131a26c105..6472d73cfee 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1509,7 +1509,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { name = mfree(name); if (name) { - r = specifier_printf(name, NAME_MAX, system_and_tmp_specifier_table, NULL, &resolved_name); + r = specifier_printf(name, NAME_MAX, system_and_tmp_specifier_table, arg_root, NULL, &resolved_name); if (r < 0) return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m", fname, line, name); @@ -1524,7 +1524,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { id = mfree(id); if (id) { - r = specifier_printf(id, PATH_MAX-1, system_and_tmp_specifier_table, NULL, &resolved_id); + r = specifier_printf(id, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_id); if (r < 0) return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m", fname, line, name); @@ -1535,7 +1535,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { description = mfree(description); if (description) { - r = specifier_printf(description, LONG_LINE_MAX, system_and_tmp_specifier_table, NULL, &resolved_description); + r = specifier_printf(description, LONG_LINE_MAX, system_and_tmp_specifier_table, arg_root, NULL, &resolved_description); if (r < 0) return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m", fname, line, description); @@ -1551,7 +1551,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { home = mfree(home); if (home) { - r = specifier_printf(home, PATH_MAX-1, system_and_tmp_specifier_table, NULL, &resolved_home); + r = specifier_printf(home, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_home); if (r < 0) return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m", fname, line, home); @@ -1567,7 +1567,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { shell = mfree(shell); if (shell) { - r = specifier_printf(shell, PATH_MAX-1, system_and_tmp_specifier_table, NULL, &resolved_shell); + r = specifier_printf(shell, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved_shell); if (r < 0) return log_error_errno(r, "[%s:%u] Failed to replace specifiers in '%s': %m", fname, line, shell); diff --git a/src/test/test-load-fragment.c b/src/test/test-load-fragment.c index 50345b7b1e3..b41a8abf7bc 100644 --- a/src/test/test-load-fragment.c +++ b/src/test/test-load-fragment.c @@ -498,8 +498,8 @@ static void test_install_printf(void) { _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *gid = NULL, *group = NULL, *uid = NULL, *user = NULL; - assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); - assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); + assert_se(specifier_machine_id('m', NULL, NULL, NULL, &mid) >= 0 && mid); + assert_se(specifier_boot_id('b', NULL, NULL, NULL, &bid) >= 0 && bid); assert_se(host = gethostname_malloc()); assert_se(group = gid_to_name(getgid())); assert_se(asprintf(&gid, UID_FMT, getgid()) >= 0); @@ -512,7 +512,7 @@ static void test_install_printf(void) { _cleanup_free_ char \ *d1 = strdup(i.name), \ *d2 = strdup(i.path); \ - assert_se(install_name_printf(&src, pattern, &t) >= 0 || !result); \ + assert_se(install_name_printf(&src, pattern, NULL, &t) >= 0 || !result); \ memzero(i.name, strlen(i.name)); \ memzero(i.path, strlen(i.path)); \ assert_se(d1 && d2); \ diff --git a/src/test/test-specifier.c b/src/test/test-specifier.c index e9d501955c5..853943a9960 100644 --- a/src/test/test-specifier.c +++ b/src/test/test-specifier.c @@ -69,7 +69,7 @@ static void test_specifier_printf(void) { log_info("/* %s */", __func__); - r = specifier_printf("xxx a=%X b=%Y yyy", SIZE_MAX, table, NULL, &w); + r = specifier_printf("xxx a=%X b=%Y yyy", SIZE_MAX, table, NULL, NULL, &w); assert_se(r >= 0); assert_se(w); @@ -77,13 +77,13 @@ static void test_specifier_printf(void) { assert_se(streq(w, "xxx a=AAAA b=BBBB yyy")); free(w); - r = specifier_printf("machine=%m, boot=%b, host=%H, version=%v, arch=%a", SIZE_MAX, table, NULL, &w); + r = specifier_printf("machine=%m, boot=%b, host=%H, version=%v, arch=%a", SIZE_MAX, table, NULL, NULL, &w); assert_se(r >= 0); assert_se(w); puts(w); w = mfree(w); - specifier_printf("os=%o, os-version=%w, build=%B, variant=%W", SIZE_MAX, table, NULL, &w); + specifier_printf("os=%o, os-version=%w, build=%B, variant=%W", SIZE_MAX, table, NULL, NULL, &w); if (w) puts(w); } @@ -97,7 +97,7 @@ static void test_specifiers(void) { xsprintf(spec, "%%%c", s->specifier); - assert_se(specifier_printf(spec, SIZE_MAX, specifier_table, NULL, &resolved) >= 0); + assert_se(specifier_printf(spec, SIZE_MAX, specifier_table, NULL, NULL, &resolved) >= 0); log_info("%%%c → %s", s->specifier, resolved); } diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index d7370432207..0077c4c5e3b 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -228,8 +228,8 @@ static int test_unit_printf(void) { log_info("/* %s */", __func__); - assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); - assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); + assert_se(specifier_machine_id('m', NULL, NULL, NULL, &mid) >= 0 && mid); + assert_se(specifier_boot_id('b', NULL, NULL, NULL, &bid) >= 0 && bid); assert_se(host = gethostname_malloc()); assert_se(user = uid_to_name(getuid())); assert_se(group = gid_to_name(getgid())); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 8e8be847285..9ffe7847958 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -200,8 +200,8 @@ STATIC_DESTRUCTOR_REGISTER(arg_exclude_prefixes, freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); -static int specifier_machine_id_safe(char specifier, const void *data, const void *userdata, char **ret); -static int specifier_directory(char specifier, const void *data, const void *userdata, char **ret); +static int specifier_machine_id_safe(char specifier, const void *data, const char *root, const void *userdata, char **ret); +static int specifier_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret); static const Specifier specifier_table[] = { { 'a', specifier_architecture, NULL }, @@ -228,21 +228,20 @@ static const Specifier specifier_table[] = { {} }; -static int specifier_machine_id_safe(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_machine_id_safe(char specifier, const void *data, const char *root, const void *userdata, char **ret) { int r; - /* If /etc/machine_id is missing or empty (e.g. in a chroot environment) - * return a recognizable error so that the caller can skip the rule - * gracefully. */ + /* If /etc/machine_id is missing or empty (e.g. in a chroot environment) return a recognizable error + * so that the caller can skip the rule gracefully. */ - r = specifier_machine_id(specifier, data, userdata, ret); + r = specifier_machine_id(specifier, data, root, userdata, ret); if (IN_SET(r, -ENOENT, -ENOMEDIUM)) return -ENXIO; return r; } -static int specifier_directory(char specifier, const void *data, const void *userdata, char **ret) { +static int specifier_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret) { struct table_entry { uint64_t type; const char *suffix; @@ -262,8 +261,10 @@ static int specifier_directory(char specifier, const void *data, const void *use [DIRECTORY_LOGS] = { SD_PATH_USER_CONFIGURATION, "log" }, }; - unsigned i; const struct table_entry *paths; + _cleanup_free_ char *p = NULL; + unsigned i; + int r; assert_cc(ELEMENTSOF(paths_system) == ELEMENTSOF(paths_user)); paths = arg_user ? paths_user : paths_system; @@ -271,7 +272,22 @@ static int specifier_directory(char specifier, const void *data, const void *use i = PTR_TO_UINT(data); assert(i < ELEMENTSOF(paths_system)); - return sd_path_lookup(paths[i].type, paths[i].suffix, ret); + r = sd_path_lookup(paths[i].type, paths[i].suffix, &p); + if (r < 0) + return r; + + if (arg_root) { + _cleanup_free_ char *j = NULL; + + j = path_join(arg_root, p); + if (!j) + return -ENOMEM; + + *ret = TAKE_PTR(j); + } else + *ret = TAKE_PTR(p); + + return 0; } static int log_unresolvable_specifier(const char *filename, unsigned line) { @@ -2778,7 +2794,7 @@ static int specifier_expansion_from_arg(Item *i) { if (r < 0) return log_error_errno(r, "Failed to unescape parameter to write: %s", i->argument); - r = specifier_printf(unescaped, PATH_MAX-1, specifier_table, NULL, &resolved); + r = specifier_printf(unescaped, PATH_MAX-1, specifier_table, arg_root, NULL, &resolved); if (r < 0) return r; @@ -2788,7 +2804,7 @@ static int specifier_expansion_from_arg(Item *i) { case SET_XATTR: case RECURSIVE_SET_XATTR: STRV_FOREACH(xattr, i->xattrs) { - r = specifier_printf(*xattr, SIZE_MAX, specifier_table, NULL, &resolved); + r = specifier_printf(*xattr, SIZE_MAX, specifier_table, arg_root, NULL, &resolved); if (r < 0) return r; @@ -3021,7 +3037,7 @@ static int parse_line( i.allow_failure = allow_failure; i.try_replace = try_replace; - r = specifier_printf(path, PATH_MAX-1, specifier_table, NULL, &i.path); + r = specifier_printf(path, PATH_MAX-1, specifier_table, arg_root, NULL, &i.path); if (r == -ENXIO) return log_unresolvable_specifier(fname, line); if (r < 0) {