1
0
mirror of https://github.com/systemd/systemd synced 2026-03-19 11:34:46 +01:00

Compare commits

..

3 Commits

Author SHA1 Message Date
Lennart Poettering
de61a04b18 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
2021-06-24 22:30:14 +02:00
Andrea Pappacoda
0c651d32d4 docs: update autofs Kconfig name 2021-06-24 20:11:03 +02:00
Juergen Hoetzel
274b0d3fc1 docs: EFI separator needs to be backslash-escaped in markdown 2021-06-24 20:09:52 +02:00
18 changed files with 183 additions and 138 deletions

2
README
View File

@ -85,7 +85,7 @@ REQUIREMENTS:
Optional but strongly recommended:
CONFIG_IPV6
CONFIG_AUTOFS4_FS
CONFIG_AUTOFS_FS
CONFIG_TMPFS_XATTR
CONFIG_{TMPFS,EXT4_FS,XFS,BTRFS_FS,...}_POSIX_ACL
CONFIG_SECCOMP

View File

@ -210,7 +210,7 @@ Note that these configurations snippets do not need to be the only configuration
To make this explicitly clear: this specification is designed with "free" operating systems in mind, starting Windows or macOS is out of focus with these configuration snippets, use boot-loader specific solutions for that. In the text above, if we say "OS" we hence imply "free", i.e. primarily Linux (though this could be easily be extended to the BSDs and whatnot).
Note that all paths used in the configuration snippets use a Unix-style "/" as path separator. This needs to be converted to an EFI-style "\" separator in EFI boot loaders.
Note that all paths used in the configuration snippets use a Unix-style "/" as path separator. This needs to be converted to an EFI-style "\\" separator in EFI boot loaders.
## Logic

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -79,6 +79,7 @@ enum UnitFileType {
struct UnitFileInstallInfo {
char *name;
char *path;
char *root;
char **aliases;
char **wanted_by;

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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); \

View File

@ -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);
}

View File

@ -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()));

View File

@ -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) {