mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
Merge pull request #22649 from keszybz/symlink-enablement-yet-again-punish-me-harder
Fixups to the unit enablement logic
This commit is contained in:
commit
53877d0385
@ -43,6 +43,11 @@ All tools:
|
||||
debugging, in order to test generators and other code against specific kernel
|
||||
command lines.
|
||||
|
||||
* `$SYSTEMD_OS_RELEASE` — if set, use this path instead of `/etc/os-release` or
|
||||
`/usr/lib/os-release`. When operating under some root (e.g. `systemctl
|
||||
--root=…`), the path is taken relative to the outside root. Only useful for
|
||||
debugging.
|
||||
|
||||
* `$SYSTEMD_FSTAB` — if set, use this path instead of `/etc/fstab`. Only useful
|
||||
for debugging.
|
||||
|
||||
|
@ -75,6 +75,10 @@
|
||||
from earliest boot on, and hence must be located on the root file
|
||||
system.</para>
|
||||
|
||||
<para><filename>os-release</filename> must not contain repeating keys. Nevertheless, readers should pick
|
||||
the entries later in the file in case of repeats, similarly to how a shell sourcing the file would. A
|
||||
reader may warn about repeating entries.</para>
|
||||
|
||||
<para>For a longer rationale for <filename>os-release</filename>
|
||||
please refer to the <ulink
|
||||
url="http://0pointer.de/blog/projects/os-release">Announcement of <filename>/etc/os-release</filename></ulink>.</para>
|
||||
|
@ -138,7 +138,7 @@
|
||||
a symlink, so when <command>systemd</command> is asked through D-Bus to load
|
||||
<filename>dbus-org.freedesktop.network1.service</filename>, it'll load
|
||||
<filename>systemd-networkd.service</filename>. As another example, <filename>default.target</filename> —
|
||||
the default system target started at boot — is commonly symlinked (aliased) to either
|
||||
the default system target started at boot — is commonly aliased to either
|
||||
<filename>multi-user.target</filename> or <filename>graphical.target</filename> to select what is started
|
||||
by default. Alias names may be used in commands like <command>disable</command>,
|
||||
<command>start</command>, <command>stop</command>, <command>status</command>, and similar, and in all
|
||||
@ -154,8 +154,12 @@
|
||||
template instance (e.g. <literal>alias@inst.service</literal>) may be a symlink to different template
|
||||
(e.g. <literal>template@inst.service</literal>). In that case, just this specific instance is aliased,
|
||||
while other instances of the template (e.g. <literal>alias@foo.service</literal>,
|
||||
<literal>alias@bar.service</literal>) are not aliased. Those rule preserve the requirement that the
|
||||
instance (if any) is always uniquely defined for a given unit and all its aliases.</para>
|
||||
<literal>alias@bar.service</literal>) are not aliased. Those rules preserve the requirement that the
|
||||
instance (if any) is always uniquely defined for a given unit and all its aliases. The target of alias
|
||||
symlink must point to a valid unit file location, i.e. the symlink target name must match the symlink
|
||||
source name as described, and the destination path must be in one of the unit search paths, see UNIT FILE
|
||||
LOAD PATH section below for more details. Note that the target file may not exist, i.e. the symlink may
|
||||
be dangling.</para>
|
||||
|
||||
<para>Unit files may specify aliases through the <varname>Alias=</varname> directive in the [Install]
|
||||
section. When the unit is enabled, symlinks will be created for those names, and removed when the unit is
|
||||
@ -175,11 +179,18 @@
|
||||
exists for <varname>Requires=</varname> type dependencies as well, the directory suffix is
|
||||
<filename>.requires/</filename> in this case. This functionality is useful to hook units into the
|
||||
start-up of other units, without having to modify their unit files. For details about the semantics of
|
||||
<varname>Wants=</varname>, see below. The preferred way to create symlinks in the
|
||||
<filename>.wants/</filename> or <filename>.requires/</filename> directory of a unit file is by embedding
|
||||
the dependency in [Install] section of the target unit, and creating the symlink in the file system with
|
||||
the <command>enable</command> or <command>preset</command> commands of
|
||||
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
|
||||
<varname>Wants=</varname> and <varname>Requires=</varname>, see below. The preferred way to create
|
||||
symlinks in the <filename>.wants/</filename> or <filename>.requires/</filename> directories is by
|
||||
specifying the dependency in [Install] section of the target unit, and creating the symlink in the file
|
||||
system with the <command>enable</command> or <command>preset</command> commands of
|
||||
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. The
|
||||
target can be a normal unit (either plain or a specific instance of a template unit). In case when the
|
||||
source unit is a template, the target can also be a template, in which case the instance will be
|
||||
"propagated" to the target unit to form a valid unit instance. The target of symlinks in
|
||||
<filename>.wants/</filename> or <filename>.requires/</filename> must thus point to a valid unit file
|
||||
location, i.e. the symlink target name must satisfy the described requirements, and the destination path
|
||||
must be in one of the unit search paths, see UNIT FILE LOAD PATH section below for more details. Note
|
||||
that the target file may not exist, i.e. the symlink may be dangling.</para>
|
||||
|
||||
<para>Along with a unit file <filename>foo.service</filename>, a "drop-in" directory
|
||||
<filename>foo.service.d/</filename> may exist. All files with the suffix
|
||||
@ -501,13 +512,30 @@
|
||||
<programlisting>systemd-analyze --user unit-paths</programlisting>
|
||||
</para>
|
||||
|
||||
<para>Moreover, additional units might be loaded into systemd from
|
||||
directories not on the unit load path by creating a symlink pointing to a
|
||||
unit file in the directories. You can use <command>systemctl link</command>
|
||||
for this operation. See
|
||||
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
for its usage and precaution.
|
||||
</para>
|
||||
<para>Moreover, additional units might be loaded into systemd from directories not on the unit load path
|
||||
by creating a symlink pointing to a unit file in the directories. You can use <command>systemctl
|
||||
link</command> for this; see
|
||||
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. The file
|
||||
system where the linked unit files are located must be accessible when systemd is started (e.g. anything
|
||||
underneath <filename>/home/</filename> or <filename>/var/</filename> is not allowed, unless those
|
||||
directories are located on the root file system).</para>
|
||||
|
||||
<para>It is important to distinguish "linked unit files" from "unit file aliases": any symlink where the
|
||||
symlink <emphasis>target</emphasis> is within the unit load path becomes an alias: the source name and
|
||||
the target file name must satisfy specific constraints listed above in the discussion of aliases, but the
|
||||
symlink target doesn't have to exist, and in fact the symlink target path is not used, except to check
|
||||
whether the target is within the unit load path. In constrast, a symlink which goes outside of the unit
|
||||
load path signifies a linked unit file. The symlink is followed when loading the file, but the
|
||||
destination name is otherwise unused (and may even not be a valid unit file name). For example, symlinks
|
||||
<filename index='false'>/etc/systemd/system/alias1.service</filename> → <filename index='false'>service1.service</filename>,
|
||||
<filename index='false'>/etc/systemd/system/alias2.service</filename> → <filename index='false'>/usr/lib/systemd/service1.service</filename>,
|
||||
<filename index='false'>/etc/systemd/system/alias3.service</filename> → <filename index='false'>/etc/systemd/system/service1.service</filename>
|
||||
are all valid aliases and <filename index='false'>service1.service</filename> will have
|
||||
four names, even if the unit file is located at
|
||||
<filename index='false'>/run/systemd/system/service1.service</filename>. In contrast,
|
||||
a symlink <filename index='false'>/etc/systemd/system/link1.service</filename> → <filename index='false'>../link1_service_file</filename>
|
||||
means that <filename index='false'>link1.service</filename> is a "linked unit" and the contents of
|
||||
<filename index='false'>/etc/systemd/link1_service_file</filename> provide its configuration.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@ -1876,34 +1904,31 @@
|
||||
<term><varname>WantedBy=</varname></term>
|
||||
<term><varname>RequiredBy=</varname></term>
|
||||
|
||||
<listitem><para>This option may be used more than once, or a
|
||||
space-separated list of unit names may be given. A symbolic
|
||||
link is created in the <filename>.wants/</filename> or
|
||||
<filename>.requires/</filename> directory of each of the
|
||||
listed units when this unit is installed by <command>systemctl
|
||||
enable</command>. This has the effect that a dependency of
|
||||
type <varname>Wants=</varname> or <varname>Requires=</varname>
|
||||
is added from the listed unit to the current unit. The primary
|
||||
result is that the current unit will be started when the
|
||||
listed unit is started. See the description of
|
||||
<varname>Wants=</varname> and <varname>Requires=</varname> in
|
||||
the [Unit] section for details.</para>
|
||||
<listitem><para>This option may be used more than once, or a space-separated list of unit names may
|
||||
be given. A symbolic link is created in the <filename>.wants/</filename> or
|
||||
<filename>.requires/</filename> directory of each of the listed units when this unit is installed by
|
||||
<command>systemctl enable</command>. This has the effect of a dependency of type
|
||||
<varname>Wants=</varname> or <varname>Requires=</varname> being added from the listed unit to the
|
||||
current unit. The primary result is that the current unit will be started when the listed unit is
|
||||
started, see the description of <varname>Wants=</varname> and <varname>Requires=</varname> in the
|
||||
[Unit] section for details.</para>
|
||||
|
||||
<para><command>WantedBy=foo.service</command> in a service
|
||||
<filename>bar.service</filename> is mostly equivalent to
|
||||
<command>Alias=foo.service.wants/bar.service</command> in the
|
||||
same file. In case of template units listing non template units,
|
||||
<command>systemctl enable</command> must be called with an
|
||||
instance name, and this instance will be added to the
|
||||
<filename>.wants/</filename> or
|
||||
<filename>.requires/</filename> list of the listed unit. E.g.
|
||||
<command>WantedBy=getty.target</command> in a service
|
||||
<filename>getty@.service</filename> will result in
|
||||
<command>systemctl enable getty@tty2.service</command>
|
||||
creating a
|
||||
<filename>getty.target.wants/getty@tty2.service</filename>
|
||||
link to <filename>getty@.service</filename>.
|
||||
</para></listitem>
|
||||
<para>In case of template units listing non template units, the listing unit must have
|
||||
<varname>DefaultInstance=</varname> set, or <command>systemctl enable</command> must be called with
|
||||
an instance name. The instance (default or specified) will be added to the
|
||||
<filename>.wants/</filename> or <filename>.requires/</filename> list of the listed unit. For example,
|
||||
<command>WantedBy=getty.target</command> in a service <filename>getty@.service</filename> will result
|
||||
in <command>systemctl enable getty@tty2.service</command> creating a
|
||||
<filename>getty.target.wants/getty@tty2.service</filename> link to
|
||||
<filename>getty@.service</filename>. This also applies to listing specific instances of templated
|
||||
units: this specific instance will gain the dependency. A template unit may also list a template
|
||||
unit, in which case a generic dependency will be added where each instance of the listing unit will
|
||||
have a dependency on an instance of the listed template with the same instance value. For example,
|
||||
<command>WantedBy=container@.target</command> in a service <filename>monitor@.service</filename> will
|
||||
result in <command>systemctl enable monitor@.service</command> creating a
|
||||
<filename>container@.target.wants/monitor@.service</filename> link to
|
||||
<filename>monitor@.service</filename>, which applies to all instances of
|
||||
<filename>container@.target</filename>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
14
meson.build
14
meson.build
@ -2450,7 +2450,7 @@ public_programs += executable(
|
||||
install_rpath : rootlibexecdir,
|
||||
install : true)
|
||||
|
||||
public_programs += executable(
|
||||
systemctl = executable(
|
||||
'systemctl',
|
||||
systemctl_sources,
|
||||
include_directories : includes,
|
||||
@ -2464,6 +2464,7 @@ public_programs += executable(
|
||||
install_rpath : rootlibexecdir,
|
||||
install : true,
|
||||
install_dir : rootbindir)
|
||||
public_programs += systemctl
|
||||
|
||||
if conf.get('ENABLE_PORTABLED') == 1
|
||||
dbus_programs += executable(
|
||||
@ -3282,13 +3283,22 @@ executable(
|
||||
install : true,
|
||||
install_dir : rootlibexecdir)
|
||||
|
||||
public_programs += executable(
|
||||
systemd_id128 = executable(
|
||||
'systemd-id128',
|
||||
'src/id128/id128.c',
|
||||
include_directories : includes,
|
||||
link_with : [libshared],
|
||||
install_rpath : rootlibexecdir,
|
||||
install : true)
|
||||
public_programs += systemd_id128
|
||||
|
||||
if want_tests != 'false'
|
||||
test('test-systemctl-enable',
|
||||
test_systemctl_enable_sh,
|
||||
# https://github.com/mesonbuild/meson/issues/2681
|
||||
args : [systemctl.full_path(),
|
||||
systemd_id128.full_path()])
|
||||
endif
|
||||
|
||||
public_programs += executable(
|
||||
'systemd-path',
|
||||
|
@ -74,7 +74,7 @@ static int log_helper(void *userdata, int level, int error, const char *file, in
|
||||
return r;
|
||||
}
|
||||
|
||||
static int verify_conditions(char **lines, UnitFileScope scope, const char *unit, const char *root) {
|
||||
static int verify_conditions(char **lines, LookupScope scope, const char *unit, const char *root) {
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
Unit *u;
|
||||
int r, q = 1;
|
||||
|
@ -78,7 +78,7 @@ static int acquire_host_info(sd_bus *bus, HostInfo **hi) {
|
||||
if (!host)
|
||||
return log_oom();
|
||||
|
||||
if (arg_scope != UNIT_FILE_SYSTEM) {
|
||||
if (arg_scope != LOOKUP_SCOPE_SYSTEM) {
|
||||
r = bus_connect_transport(arg_transport, arg_host, false, &system_bus);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to connect to system bus, ignoring: %m");
|
||||
@ -183,7 +183,7 @@ int verb_plot(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(unit_times_free_arrayp) UnitTimes *times = NULL;
|
||||
_cleanup_free_ char *pretty_times = NULL;
|
||||
bool use_full_bus = arg_scope == UNIT_FILE_SYSTEM;
|
||||
bool use_full_bus = arg_scope == LOOKUP_SCOPE_SYSTEM;
|
||||
BootTimes *boot;
|
||||
UnitTimes *u;
|
||||
int n, m = 1, y = 0, r;
|
||||
@ -201,7 +201,7 @@ int verb_plot(int argc, char *argv[], void *userdata) {
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
if (use_full_bus || arg_scope != UNIT_FILE_SYSTEM) {
|
||||
if (use_full_bus || arg_scope != LOOKUP_SCOPE_SYSTEM) {
|
||||
n = acquire_host_info(bus, &host);
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
@ -2646,7 +2646,7 @@ static int offline_security_check(Unit *u,
|
||||
|
||||
static int offline_security_checks(char **filenames,
|
||||
JsonVariant *policy,
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
bool check_man,
|
||||
bool run_generators,
|
||||
unsigned threshold,
|
||||
@ -2758,7 +2758,7 @@ static int offline_security_checks(char **filenames,
|
||||
static int analyze_security(sd_bus *bus,
|
||||
char **units,
|
||||
JsonVariant *policy,
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
bool check_man,
|
||||
bool run_generators,
|
||||
bool offline,
|
||||
|
@ -67,9 +67,9 @@ int acquire_boot_times(sd_bus *bus, BootTimes **ret) {
|
||||
"Please try again later.\n"
|
||||
"Hint: Use 'systemctl%s list-jobs' to see active jobs",
|
||||
times.finish_time,
|
||||
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
|
||||
arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user");
|
||||
|
||||
if (arg_scope == UNIT_FILE_SYSTEM && times.security_start_time > 0) {
|
||||
if (arg_scope == LOOKUP_SCOPE_SYSTEM && times.security_start_time > 0) {
|
||||
/* security_start_time is set when systemd is not running under container environment. */
|
||||
if (times.initrd_time > 0)
|
||||
times.kernel_done_time = times.initrd_time;
|
||||
|
@ -21,9 +21,9 @@ int verb_unit_files(int argc, char *argv[], void *userdata) {
|
||||
char **v;
|
||||
int r;
|
||||
|
||||
r = lookup_paths_init(&lp, arg_scope, 0, NULL);
|
||||
r = lookup_paths_init_or_warn(&lp, arg_scope, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "lookup_paths_init() failed: %m");
|
||||
return r;
|
||||
|
||||
r = unit_file_build_name_map(&lp, NULL, &unit_ids, &unit_names, NULL);
|
||||
if (r < 0)
|
||||
|
@ -9,9 +9,9 @@ int verb_unit_paths(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(lookup_paths_free) LookupPaths paths = {};
|
||||
int r;
|
||||
|
||||
r = lookup_paths_init(&paths, arg_scope, 0, NULL);
|
||||
r = lookup_paths_init_or_warn(&paths, arg_scope, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "lookup_paths_init() failed: %m");
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(p, paths.search_path)
|
||||
puts(*p);
|
||||
|
@ -242,7 +242,7 @@ static void set_destroy_ignore_pointer_max(Set** s) {
|
||||
set_free_free(*s);
|
||||
}
|
||||
|
||||
int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root) {
|
||||
int verify_units(char **filenames, LookupScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root) {
|
||||
const ManagerTestRunFlags flags =
|
||||
MANAGER_TEST_RUN_MINIMAL |
|
||||
MANAGER_TEST_RUN_ENV_GENERATORS |
|
||||
|
@ -17,7 +17,7 @@ typedef enum RecursiveErrors {
|
||||
int verify_generate_path(char **var, char **filenames);
|
||||
int verify_prepare_filename(const char *filename, char **ret);
|
||||
int verify_executable(Unit *u, const ExecCommand *exec, const char *root);
|
||||
int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root);
|
||||
int verify_units(char **filenames, LookupScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root);
|
||||
|
||||
const char* recursive_errors_to_string(RecursiveErrors i) _const_;
|
||||
RecursiveErrors recursive_errors_from_string(const char *s) _pure_;
|
||||
|
@ -89,7 +89,7 @@ usec_t arg_fuzz = 0;
|
||||
PagerFlags arg_pager_flags = 0;
|
||||
BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
|
||||
const char *arg_host = NULL;
|
||||
UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
|
||||
LookupScope arg_scope = LOOKUP_SCOPE_SYSTEM;
|
||||
RecursiveErrors arg_recursive_errors = RECURSIVE_ERRORS_YES;
|
||||
bool arg_man = true;
|
||||
bool arg_generators = false;
|
||||
@ -114,7 +114,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_unit, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_profile, freep);
|
||||
|
||||
int acquire_bus(sd_bus **bus, bool *use_full_bus) {
|
||||
bool user = arg_scope != UNIT_FILE_SYSTEM;
|
||||
bool user = arg_scope != LOOKUP_SCOPE_SYSTEM;
|
||||
int r;
|
||||
|
||||
if (use_full_bus && *use_full_bus) {
|
||||
@ -351,15 +351,15 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case ARG_SYSTEM:
|
||||
arg_scope = UNIT_FILE_SYSTEM;
|
||||
arg_scope = LOOKUP_SCOPE_SYSTEM;
|
||||
break;
|
||||
|
||||
case ARG_USER:
|
||||
arg_scope = UNIT_FILE_USER;
|
||||
arg_scope = LOOKUP_SCOPE_USER;
|
||||
break;
|
||||
|
||||
case ARG_GLOBAL:
|
||||
arg_scope = UNIT_FILE_GLOBAL;
|
||||
arg_scope = LOOKUP_SCOPE_GLOBAL;
|
||||
break;
|
||||
|
||||
case ARG_ORDER:
|
||||
@ -500,12 +500,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --threshold= is only supported for security right now.");
|
||||
|
||||
if (arg_scope == UNIT_FILE_GLOBAL &&
|
||||
if (arg_scope == LOOKUP_SCOPE_GLOBAL &&
|
||||
!STR_IN_SET(argv[optind] ?: "time", "dot", "unit-paths", "verify"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --global only makes sense with verbs dot, unit-paths, verify.");
|
||||
|
||||
if (streq_ptr(argv[optind], "cat-config") && arg_scope == UNIT_FILE_USER)
|
||||
if (streq_ptr(argv[optind], "cat-config") && arg_scope == LOOKUP_SCOPE_USER)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --user is not supported for cat-config right now.");
|
||||
|
||||
|
@ -22,7 +22,7 @@ extern usec_t arg_fuzz;
|
||||
extern PagerFlags arg_pager_flags;
|
||||
extern BusTransport arg_transport;
|
||||
extern const char *arg_host;
|
||||
extern UnitFileScope arg_scope;
|
||||
extern LookupScope arg_scope;
|
||||
extern RecursiveErrors arg_recursive_errors;
|
||||
extern bool arg_man;
|
||||
extern bool arg_generators;
|
||||
|
@ -16,9 +16,8 @@ static int parse_env_file_internal(
|
||||
FILE *f,
|
||||
const char *fname,
|
||||
int (*push) (const char *filename, unsigned line,
|
||||
const char *key, char *value, void *userdata, int *n_pushed),
|
||||
void *userdata,
|
||||
int *n_pushed) {
|
||||
const char *key, char *value, void *userdata),
|
||||
void *userdata) {
|
||||
|
||||
size_t n_key = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX;
|
||||
_cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
|
||||
@ -99,7 +98,7 @@ static int parse_env_file_internal(
|
||||
if (last_key_whitespace != SIZE_MAX)
|
||||
key[last_key_whitespace] = 0;
|
||||
|
||||
r = push(fname, line, key, value, userdata, n_pushed);
|
||||
r = push(fname, line, key, value, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -142,7 +141,7 @@ static int parse_env_file_internal(
|
||||
if (last_key_whitespace != SIZE_MAX)
|
||||
key[last_key_whitespace] = 0;
|
||||
|
||||
r = push(fname, line, key, value, userdata, n_pushed);
|
||||
r = push(fname, line, key, value, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -261,7 +260,7 @@ static int parse_env_file_internal(
|
||||
if (last_key_whitespace != SIZE_MAX)
|
||||
key[last_key_whitespace] = 0;
|
||||
|
||||
r = push(fname, line, key, value, userdata, n_pushed);
|
||||
r = push(fname, line, key, value, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -299,8 +298,7 @@ static int check_utf8ness_and_warn(
|
||||
static int parse_env_file_push(
|
||||
const char *filename, unsigned line,
|
||||
const char *key, char *value,
|
||||
void *userdata,
|
||||
int *n_pushed) {
|
||||
void *userdata) {
|
||||
|
||||
const char *k;
|
||||
va_list aq, *ap = userdata;
|
||||
@ -322,9 +320,6 @@ static int parse_env_file_push(
|
||||
free(*v);
|
||||
*v = value;
|
||||
|
||||
if (n_pushed)
|
||||
(*n_pushed)++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -340,16 +335,13 @@ int parse_env_filev(
|
||||
const char *fname,
|
||||
va_list ap) {
|
||||
|
||||
int r, n_pushed = 0;
|
||||
int r;
|
||||
va_list aq;
|
||||
|
||||
va_copy(aq, ap);
|
||||
r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed);
|
||||
r = parse_env_file_internal(f, fname, parse_env_file_push, &aq);
|
||||
va_end(aq);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return n_pushed;
|
||||
return r;
|
||||
}
|
||||
|
||||
int parse_env_file_sentinel(
|
||||
@ -370,8 +362,7 @@ int parse_env_file_sentinel(
|
||||
static int load_env_file_push(
|
||||
const char *filename, unsigned line,
|
||||
const char *key, char *value,
|
||||
void *userdata,
|
||||
int *n_pushed) {
|
||||
void *userdata) {
|
||||
char ***m = userdata;
|
||||
char *p;
|
||||
int r;
|
||||
@ -388,78 +379,69 @@ static int load_env_file_push(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (n_pushed)
|
||||
(*n_pushed)++;
|
||||
|
||||
free(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_env_file(FILE *f, const char *fname, char ***rl) {
|
||||
char **m = NULL;
|
||||
_cleanup_strv_free_ char **m = NULL;
|
||||
int r;
|
||||
|
||||
r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL);
|
||||
if (r < 0) {
|
||||
strv_free(m);
|
||||
r = parse_env_file_internal(f, fname, load_env_file_push, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*rl = m;
|
||||
*rl = TAKE_PTR(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_env_file_push_pairs(
|
||||
const char *filename, unsigned line,
|
||||
const char *key, char *value,
|
||||
void *userdata,
|
||||
int *n_pushed) {
|
||||
char ***m = userdata;
|
||||
void *userdata) {
|
||||
|
||||
char ***m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
r = check_utf8ness_and_warn(filename, line, key, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Check if the key is present */
|
||||
for (char **t = *m; t && *t; t += 2)
|
||||
if (streq(t[0], key)) {
|
||||
if (value)
|
||||
return free_and_replace(t[1], value);
|
||||
else
|
||||
return free_and_strdup(t+1, "");
|
||||
}
|
||||
|
||||
r = strv_extend(m, key);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
return r;
|
||||
|
||||
if (!value) {
|
||||
r = strv_extend(m, "");
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
r = strv_push(m, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (n_pushed)
|
||||
(*n_pushed)++;
|
||||
|
||||
return 0;
|
||||
if (value)
|
||||
return strv_push(m, value);
|
||||
else
|
||||
return strv_extend(m, "");
|
||||
}
|
||||
|
||||
int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
|
||||
char **m = NULL;
|
||||
_cleanup_strv_free_ char **m = NULL;
|
||||
int r;
|
||||
|
||||
r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL);
|
||||
if (r < 0) {
|
||||
strv_free(m);
|
||||
r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*rl = m;
|
||||
*rl = TAKE_PTR(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int merge_env_file_push(
|
||||
const char *filename, unsigned line,
|
||||
const char *key, char *value,
|
||||
void *userdata,
|
||||
int *n_pushed) {
|
||||
void *userdata) {
|
||||
|
||||
char ***env = userdata;
|
||||
char *expanded_value;
|
||||
@ -488,7 +470,7 @@ static int merge_env_file_push(
|
||||
|
||||
log_debug("%s:%u: setting %s=%s", filename, line, key, value);
|
||||
|
||||
return load_env_file_push(filename, line, key, value, env, n_pushed);
|
||||
return load_env_file_push(filename, line, key, value, env);
|
||||
}
|
||||
|
||||
int merge_env_file(
|
||||
@ -500,7 +482,7 @@ int merge_env_file(
|
||||
* plus "extended" substitutions, unlike other exported parsing functions.
|
||||
*/
|
||||
|
||||
return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL);
|
||||
return parse_env_file_internal(f, fname, merge_env_file_push, env);
|
||||
}
|
||||
|
||||
static void write_env_var(FILE *f, const char *v) {
|
||||
|
@ -170,13 +170,19 @@ int open_extension_release(const char *root, const char *extension, char **ret_p
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") {
|
||||
r = chase_symlinks(p, root, CHASE_PREFIX_ROOT,
|
||||
const char *var = secure_getenv("SYSTEMD_OS_RELEASE");
|
||||
if (var)
|
||||
r = chase_symlinks(var, root, 0,
|
||||
ret_path ? &q : NULL,
|
||||
ret_fd ? &fd : NULL);
|
||||
if (r != -ENOENT)
|
||||
break;
|
||||
}
|
||||
else
|
||||
FOREACH_STRING(path, "/etc/os-release", "/usr/lib/os-release") {
|
||||
r = chase_symlinks(path, root, CHASE_PREFIX_ROOT,
|
||||
ret_path ? &q : NULL,
|
||||
ret_fd ? &fd : NULL);
|
||||
if (r != -ENOENT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -232,7 +232,7 @@ bool path_is_user_config_dir(const char *path) {
|
||||
}
|
||||
|
||||
static int acquire_generator_dirs(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
const char *tempdir,
|
||||
char **generator,
|
||||
char **generator_early,
|
||||
@ -244,17 +244,17 @@ static int acquire_generator_dirs(
|
||||
assert(generator);
|
||||
assert(generator_early);
|
||||
assert(generator_late);
|
||||
assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
|
||||
assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER, LOOKUP_SCOPE_GLOBAL));
|
||||
|
||||
if (scope == UNIT_FILE_GLOBAL)
|
||||
if (scope == LOOKUP_SCOPE_GLOBAL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (tempdir)
|
||||
prefix = tempdir;
|
||||
else if (scope == UNIT_FILE_SYSTEM)
|
||||
else if (scope == LOOKUP_SCOPE_SYSTEM)
|
||||
prefix = "/run/systemd";
|
||||
else {
|
||||
/* UNIT_FILE_USER */
|
||||
/* LOOKUP_SCOPE_USER */
|
||||
const char *e;
|
||||
|
||||
e = getenv("XDG_RUNTIME_DIR");
|
||||
@ -288,21 +288,21 @@ static int acquire_generator_dirs(
|
||||
}
|
||||
|
||||
static int acquire_transient_dir(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
const char *tempdir,
|
||||
char **ret) {
|
||||
|
||||
char *transient;
|
||||
|
||||
assert(ret);
|
||||
assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
|
||||
assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER, LOOKUP_SCOPE_GLOBAL));
|
||||
|
||||
if (scope == UNIT_FILE_GLOBAL)
|
||||
if (scope == LOOKUP_SCOPE_GLOBAL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (tempdir)
|
||||
transient = path_join(tempdir, "transient");
|
||||
else if (scope == UNIT_FILE_SYSTEM)
|
||||
else if (scope == LOOKUP_SCOPE_SYSTEM)
|
||||
transient = strdup("/run/systemd/transient");
|
||||
else
|
||||
return xdg_user_runtime_dir(ret, "/systemd/transient");
|
||||
@ -313,7 +313,7 @@ static int acquire_transient_dir(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
|
||||
static int acquire_config_dirs(LookupScope scope, char **persistent, char **runtime) {
|
||||
_cleanup_free_ char *a = NULL, *b = NULL;
|
||||
int r;
|
||||
|
||||
@ -322,17 +322,17 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru
|
||||
|
||||
switch (scope) {
|
||||
|
||||
case UNIT_FILE_SYSTEM:
|
||||
case LOOKUP_SCOPE_SYSTEM:
|
||||
a = strdup(SYSTEM_CONFIG_UNIT_DIR);
|
||||
b = strdup("/run/systemd/system");
|
||||
break;
|
||||
|
||||
case UNIT_FILE_GLOBAL:
|
||||
case LOOKUP_SCOPE_GLOBAL:
|
||||
a = strdup(USER_CONFIG_UNIT_DIR);
|
||||
b = strdup("/run/systemd/user");
|
||||
break;
|
||||
|
||||
case UNIT_FILE_USER:
|
||||
case LOOKUP_SCOPE_USER:
|
||||
r = xdg_user_config_dir(&a, "/systemd/user");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
return r;
|
||||
@ -364,7 +364,7 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
|
||||
static int acquire_control_dirs(LookupScope scope, char **persistent, char **runtime) {
|
||||
_cleanup_free_ char *a = NULL;
|
||||
int r;
|
||||
|
||||
@ -373,7 +373,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r
|
||||
|
||||
switch (scope) {
|
||||
|
||||
case UNIT_FILE_SYSTEM: {
|
||||
case LOOKUP_SCOPE_SYSTEM: {
|
||||
_cleanup_free_ char *b = NULL;
|
||||
|
||||
a = strdup("/etc/systemd/system.control");
|
||||
@ -389,7 +389,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r
|
||||
break;
|
||||
}
|
||||
|
||||
case UNIT_FILE_USER:
|
||||
case LOOKUP_SCOPE_USER:
|
||||
r = xdg_user_config_dir(&a, "/systemd/user.control");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
return r;
|
||||
@ -406,7 +406,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r
|
||||
|
||||
break;
|
||||
|
||||
case UNIT_FILE_GLOBAL:
|
||||
case LOOKUP_SCOPE_GLOBAL:
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
default:
|
||||
@ -419,7 +419,7 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r
|
||||
}
|
||||
|
||||
static int acquire_attached_dirs(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
char **ret_persistent,
|
||||
char **ret_runtime) {
|
||||
|
||||
@ -429,7 +429,7 @@ static int acquire_attached_dirs(
|
||||
assert(ret_runtime);
|
||||
|
||||
/* Portable services are not available to regular users for now. */
|
||||
if (scope != UNIT_FILE_SYSTEM)
|
||||
if (scope != LOOKUP_SCOPE_SYSTEM)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
a = strdup("/etc/systemd/system.attached");
|
||||
@ -508,8 +508,8 @@ static int get_paths_from_environ(const char *var, char ***paths, bool *append)
|
||||
}
|
||||
|
||||
int lookup_paths_init(
|
||||
LookupPaths *p,
|
||||
UnitFileScope scope,
|
||||
LookupPaths *lp,
|
||||
LookupScope scope,
|
||||
LookupPathsFlags flags,
|
||||
const char *root_dir) {
|
||||
|
||||
@ -526,16 +526,16 @@ int lookup_paths_init(
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(lp);
|
||||
assert(scope >= 0);
|
||||
assert(scope < _UNIT_FILE_SCOPE_MAX);
|
||||
assert(scope < _LOOKUP_SCOPE_MAX);
|
||||
|
||||
#if HAVE_SPLIT_USR
|
||||
flags |= LOOKUP_PATHS_SPLIT_USR;
|
||||
#endif
|
||||
|
||||
if (!empty_or_root(root_dir)) {
|
||||
if (scope == UNIT_FILE_USER)
|
||||
if (scope == LOOKUP_SCOPE_USER)
|
||||
return -EINVAL;
|
||||
|
||||
r = is_dir(root_dir, true);
|
||||
@ -560,8 +560,8 @@ int lookup_paths_init(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (scope == UNIT_FILE_USER) {
|
||||
r = acquire_config_dirs(UNIT_FILE_GLOBAL, &global_persistent_config, &global_runtime_config);
|
||||
if (scope == LOOKUP_SCOPE_USER) {
|
||||
r = acquire_config_dirs(LOOKUP_SCOPE_GLOBAL, &global_persistent_config, &global_runtime_config);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -606,7 +606,7 @@ int lookup_paths_init(
|
||||
|
||||
switch (scope) {
|
||||
|
||||
case UNIT_FILE_SYSTEM:
|
||||
case LOOKUP_SCOPE_SYSTEM:
|
||||
add = strv_new(
|
||||
/* If you modify this you also want to modify
|
||||
* systemdsystemunitpath= in systemd.pc.in! */
|
||||
@ -629,7 +629,7 @@ int lookup_paths_init(
|
||||
STRV_IFNOTNULL(generator_late));
|
||||
break;
|
||||
|
||||
case UNIT_FILE_GLOBAL:
|
||||
case LOOKUP_SCOPE_GLOBAL:
|
||||
add = strv_new(
|
||||
/* If you modify this you also want to modify
|
||||
* systemduserunitpath= in systemd.pc.in, and
|
||||
@ -652,7 +652,7 @@ int lookup_paths_init(
|
||||
STRV_IFNOTNULL(generator_late));
|
||||
break;
|
||||
|
||||
case UNIT_FILE_USER:
|
||||
case LOOKUP_SCOPE_USER:
|
||||
add = user_dirs(persistent_config, runtime_config,
|
||||
global_persistent_config, global_runtime_config,
|
||||
generator, generator_early, generator_late,
|
||||
@ -716,7 +716,7 @@ int lookup_paths_init(
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
*p = (LookupPaths) {
|
||||
*lp = (LookupPaths) {
|
||||
.search_path = strv_uniq(TAKE_PTR(paths)),
|
||||
|
||||
.persistent_config = TAKE_PTR(persistent_config),
|
||||
@ -741,46 +741,56 @@ int lookup_paths_init(
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lookup_paths_free(LookupPaths *p) {
|
||||
if (!p)
|
||||
return;
|
||||
int lookup_paths_init_or_warn(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir) {
|
||||
int r;
|
||||
|
||||
p->search_path = strv_free(p->search_path);
|
||||
|
||||
p->persistent_config = mfree(p->persistent_config);
|
||||
p->runtime_config = mfree(p->runtime_config);
|
||||
|
||||
p->persistent_attached = mfree(p->persistent_attached);
|
||||
p->runtime_attached = mfree(p->runtime_attached);
|
||||
|
||||
p->generator = mfree(p->generator);
|
||||
p->generator_early = mfree(p->generator_early);
|
||||
p->generator_late = mfree(p->generator_late);
|
||||
|
||||
p->transient = mfree(p->transient);
|
||||
|
||||
p->persistent_control = mfree(p->persistent_control);
|
||||
p->runtime_control = mfree(p->runtime_control);
|
||||
|
||||
p->root_dir = mfree(p->root_dir);
|
||||
p->temporary_dir = mfree(p->temporary_dir);
|
||||
r = lookup_paths_init(lp, scope, flags, root_dir);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to initialize unit search paths%s%s: %m",
|
||||
isempty(root_dir) ? "" : " for root directory ", strempty(root_dir));
|
||||
return r;
|
||||
}
|
||||
|
||||
void lookup_paths_log(LookupPaths *p) {
|
||||
assert(p);
|
||||
void lookup_paths_free(LookupPaths *lp) {
|
||||
if (!lp)
|
||||
return;
|
||||
|
||||
if (strv_isempty(p->search_path)) {
|
||||
lp->search_path = strv_free(lp->search_path);
|
||||
|
||||
lp->persistent_config = mfree(lp->persistent_config);
|
||||
lp->runtime_config = mfree(lp->runtime_config);
|
||||
|
||||
lp->persistent_attached = mfree(lp->persistent_attached);
|
||||
lp->runtime_attached = mfree(lp->runtime_attached);
|
||||
|
||||
lp->generator = mfree(lp->generator);
|
||||
lp->generator_early = mfree(lp->generator_early);
|
||||
lp->generator_late = mfree(lp->generator_late);
|
||||
|
||||
lp->transient = mfree(lp->transient);
|
||||
|
||||
lp->persistent_control = mfree(lp->persistent_control);
|
||||
lp->runtime_control = mfree(lp->runtime_control);
|
||||
|
||||
lp->root_dir = mfree(lp->root_dir);
|
||||
lp->temporary_dir = mfree(lp->temporary_dir);
|
||||
}
|
||||
|
||||
void lookup_paths_log(LookupPaths *lp) {
|
||||
assert(lp);
|
||||
|
||||
if (strv_isempty(lp->search_path)) {
|
||||
log_debug("Ignoring unit files.");
|
||||
p->search_path = strv_free(p->search_path);
|
||||
lp->search_path = strv_free(lp->search_path);
|
||||
} else {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
t = strv_join(p->search_path, "\n\t");
|
||||
t = strv_join(lp->search_path, "\n\t");
|
||||
log_debug("Looking for unit files in (higher priority first):\n\t%s", strna(t));
|
||||
}
|
||||
}
|
||||
|
||||
char **generator_binary_paths(UnitFileScope scope) {
|
||||
char **generator_binary_paths(LookupScope scope) {
|
||||
bool append = false; /* Add items from SYSTEMD_GENERATOR_PATH before normal directories */
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
int r;
|
||||
@ -795,15 +805,15 @@ char **generator_binary_paths(UnitFileScope scope) {
|
||||
|
||||
switch (scope) {
|
||||
|
||||
case UNIT_FILE_SYSTEM:
|
||||
case LOOKUP_SCOPE_SYSTEM:
|
||||
add = strv_new("/run/systemd/system-generators",
|
||||
"/etc/systemd/system-generators",
|
||||
"/usr/local/lib/systemd/system-generators",
|
||||
SYSTEM_GENERATOR_DIR);
|
||||
break;
|
||||
|
||||
case UNIT_FILE_GLOBAL:
|
||||
case UNIT_FILE_USER:
|
||||
case LOOKUP_SCOPE_GLOBAL:
|
||||
case LOOKUP_SCOPE_USER:
|
||||
add = strv_new("/run/systemd/user-generators",
|
||||
"/etc/systemd/user-generators",
|
||||
"/usr/local/lib/systemd/user-generators",
|
||||
|
@ -3,10 +3,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct LookupPaths LookupPaths;
|
||||
|
||||
#include "def.h"
|
||||
#include "unit-file.h"
|
||||
#include "macro.h"
|
||||
|
||||
typedef enum LookupPathsFlags {
|
||||
@ -15,7 +12,15 @@ typedef enum LookupPathsFlags {
|
||||
LOOKUP_PATHS_SPLIT_USR = 1 << 2,
|
||||
} LookupPathsFlags;
|
||||
|
||||
struct LookupPaths {
|
||||
typedef enum LookupScope {
|
||||
LOOKUP_SCOPE_SYSTEM,
|
||||
LOOKUP_SCOPE_GLOBAL,
|
||||
LOOKUP_SCOPE_USER,
|
||||
_LOOKUP_SCOPE_MAX,
|
||||
_LOOKUP_SCOPE_INVALID = -EINVAL,
|
||||
} LookupScope;
|
||||
|
||||
typedef struct LookupPaths {
|
||||
/* Where we look for unit files. This includes the individual special paths below, but also any vendor
|
||||
* supplied, static unit file paths. */
|
||||
char **search_path;
|
||||
@ -52,9 +57,10 @@ struct LookupPaths {
|
||||
|
||||
/* A temporary directory when running in test mode, to be nuked */
|
||||
char *temporary_dir;
|
||||
};
|
||||
} LookupPaths;
|
||||
|
||||
int lookup_paths_init(LookupPaths *p, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir);
|
||||
int lookup_paths_init(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir);
|
||||
int lookup_paths_init_or_warn(LookupPaths *lp, LookupScope scope, LookupPathsFlags flags, const char *root_dir);
|
||||
|
||||
int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs);
|
||||
int xdg_user_runtime_dir(char **ret, const char *suffix);
|
||||
@ -67,7 +73,7 @@ bool path_is_user_config_dir(const char *path);
|
||||
void lookup_paths_log(LookupPaths *p);
|
||||
void lookup_paths_free(LookupPaths *p);
|
||||
|
||||
char **generator_binary_paths(UnitFileScope scope);
|
||||
char **generator_binary_paths(LookupScope scope);
|
||||
char **env_generator_binary_paths(bool is_system);
|
||||
|
||||
#define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network"))
|
||||
|
@ -127,17 +127,22 @@ bool null_or_empty(struct stat *st) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int null_or_empty_path(const char *fn) {
|
||||
int null_or_empty_path_with_root(const char *fn, const char *root) {
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
assert(fn);
|
||||
|
||||
/* If we have the path, let's do an easy text comparison first. */
|
||||
if (path_equal(fn, "/dev/null"))
|
||||
/* A symlink to /dev/null or an empty file?
|
||||
* When looking under root_dir, we can't expect /dev/ to be mounted,
|
||||
* so let's see if the path is a (possibly dangling) symlink to /dev/null. */
|
||||
|
||||
if (path_equal_ptr(path_startswith(fn, root ?: "/"), "dev/null"))
|
||||
return true;
|
||||
|
||||
if (stat(fn, &st) < 0)
|
||||
return -errno;
|
||||
r = chase_symlinks_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return null_or_empty(&st);
|
||||
}
|
||||
|
@ -31,9 +31,13 @@ static inline int dir_is_populated(const char *path) {
|
||||
}
|
||||
|
||||
bool null_or_empty(struct stat *st) _pure_;
|
||||
int null_or_empty_path(const char *fn);
|
||||
int null_or_empty_path_with_root(const char *fn, const char *root);
|
||||
int null_or_empty_fd(int fd);
|
||||
|
||||
static inline int null_or_empty_path(const char *fn) {
|
||||
return null_or_empty_path_with_root(fn, NULL);
|
||||
}
|
||||
|
||||
int path_is_read_only_fs(const char *path);
|
||||
|
||||
int files_same(const char *filea, const char *fileb, int flags);
|
||||
|
@ -69,7 +69,7 @@ int unit_symlink_name_compatible(const char *symlink, const char *target, bool i
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_validate_alias_symlink_and_warn(const char *filename, const char *target) {
|
||||
int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, const char *target) {
|
||||
const char *src, *dst;
|
||||
_cleanup_free_ char *src_instance = NULL, *dst_instance = NULL;
|
||||
UnitType src_unit_type, dst_unit_type;
|
||||
@ -82,7 +82,8 @@ int unit_validate_alias_symlink_and_warn(const char *filename, const char *targe
|
||||
*
|
||||
* -EINVAL is returned if the something is wrong with the source filename or the source unit type is
|
||||
* not allowed to symlink,
|
||||
* -EXDEV if the target filename is not a valid unit name or doesn't match the source.
|
||||
* -EXDEV if the target filename is not a valid unit name or doesn't match the source,
|
||||
* -ELOOP for an alias to self.
|
||||
*/
|
||||
|
||||
src = basename(filename);
|
||||
@ -92,51 +93,56 @@ int unit_validate_alias_symlink_and_warn(const char *filename, const char *targe
|
||||
|
||||
src_name_type = unit_name_to_instance(src, &src_instance);
|
||||
if (src_name_type < 0)
|
||||
return log_notice_errno(src_name_type,
|
||||
"%s: not a valid unit name \"%s\": %m", filename, src);
|
||||
return log_full_errno(log_level, src_name_type,
|
||||
"%s: not a valid unit name \"%s\": %m", filename, src);
|
||||
|
||||
src_unit_type = unit_name_to_type(src);
|
||||
assert(src_unit_type >= 0); /* unit_name_to_instance() checked the suffix already */
|
||||
|
||||
if (!unit_type_may_alias(src_unit_type))
|
||||
return log_notice_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: symlinks are not allowed for units of this type, rejecting.",
|
||||
filename);
|
||||
return log_full_errno(log_level, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: symlinks are not allowed for units of this type, rejecting.",
|
||||
filename);
|
||||
|
||||
if (src_name_type != UNIT_NAME_PLAIN &&
|
||||
!unit_type_may_template(src_unit_type))
|
||||
return log_notice_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: templates not allowed for %s units, rejecting.",
|
||||
filename, unit_type_to_string(src_unit_type));
|
||||
return log_full_errno(log_level, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: templates not allowed for %s units, rejecting.",
|
||||
filename, unit_type_to_string(src_unit_type));
|
||||
|
||||
/* dst checks */
|
||||
|
||||
if (streq(src, dst))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ELOOP),
|
||||
"%s: unit self-alias: %s → %s, ignoring.",
|
||||
filename, src, dst);
|
||||
|
||||
dst_name_type = unit_name_to_instance(dst, &dst_instance);
|
||||
if (dst_name_type < 0)
|
||||
return log_notice_errno(dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type,
|
||||
"%s points to \"%s\" which is not a valid unit name: %m",
|
||||
filename, dst);
|
||||
return log_full_errno(log_level, dst_name_type == -EINVAL ? SYNTHETIC_ERRNO(EXDEV) : dst_name_type,
|
||||
"%s points to \"%s\" which is not a valid unit name: %m",
|
||||
filename, dst);
|
||||
|
||||
if (!(dst_name_type == src_name_type ||
|
||||
(src_name_type == UNIT_NAME_INSTANCE && dst_name_type == UNIT_NAME_TEMPLATE)))
|
||||
return log_notice_errno(SYNTHETIC_ERRNO(EXDEV),
|
||||
"%s: symlink target name type \"%s\" does not match source, rejecting.",
|
||||
filename, dst);
|
||||
return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV),
|
||||
"%s: symlink target name type \"%s\" does not match source, rejecting.",
|
||||
filename, dst);
|
||||
|
||||
if (dst_name_type == UNIT_NAME_INSTANCE) {
|
||||
assert(src_instance);
|
||||
assert(dst_instance);
|
||||
if (!streq(src_instance, dst_instance))
|
||||
return log_notice_errno(SYNTHETIC_ERRNO(EXDEV),
|
||||
"%s: unit symlink target \"%s\" instance name doesn't match, rejecting.",
|
||||
filename, dst);
|
||||
return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV),
|
||||
"%s: unit symlink target \"%s\" instance name doesn't match, rejecting.",
|
||||
filename, dst);
|
||||
}
|
||||
|
||||
dst_unit_type = unit_name_to_type(dst);
|
||||
if (dst_unit_type != src_unit_type)
|
||||
return log_notice_errno(SYNTHETIC_ERRNO(EXDEV),
|
||||
"%s: symlink target \"%s\" has incompatible suffix, rejecting.",
|
||||
filename, dst);
|
||||
return log_full_errno(log_level, SYNTHETIC_ERRNO(EXDEV),
|
||||
"%s: symlink target \"%s\" has incompatible suffix, rejecting.",
|
||||
filename, dst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -259,6 +265,110 @@ static int directory_name_is_valid(const char *name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int unit_file_resolve_symlink(
|
||||
const char *root_dir,
|
||||
char **search_path,
|
||||
const char *dir,
|
||||
int dirfd,
|
||||
const char *filename,
|
||||
bool resolve_destination_target,
|
||||
char **ret_destination) {
|
||||
|
||||
_cleanup_free_ char *target = NULL, *simplified = NULL, *dst = NULL, *_dir = NULL, *_filename = NULL;
|
||||
int r;
|
||||
|
||||
/* This can be called with either dir+dirfd valid and filename just a name,
|
||||
* or !dir && dirfd==AT_FDCWD, and filename being a full path.
|
||||
*
|
||||
* If resolve_destination_target is true, an absolute path will be returned.
|
||||
* If not, an absolute path is returned for linked unit files, and a relative
|
||||
* path otherwise.
|
||||
*
|
||||
* Returns an error, false if this is an alias, true if it's a linked unit file. */
|
||||
|
||||
assert(filename);
|
||||
assert(ret_destination);
|
||||
assert(dir || path_is_absolute(filename));
|
||||
assert(dirfd >= 0 || dirfd == AT_FDCWD);
|
||||
|
||||
r = readlinkat_malloc(dirfd, filename, &target);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to read symlink %s%s%s: %m",
|
||||
dir, dir ? "/" : "", filename);
|
||||
|
||||
if (!dir) {
|
||||
r = path_extract_directory(filename, &_dir);
|
||||
if (r < 0)
|
||||
return r;
|
||||
dir = _dir;
|
||||
|
||||
r = path_extract_filename(filename, &_filename);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == O_DIRECTORY)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EISDIR),
|
||||
"Unexpected path to a directory \"%s\", refusing.", filename);
|
||||
filename = _filename;
|
||||
}
|
||||
|
||||
bool is_abs = path_is_absolute(target);
|
||||
if (root_dir || !is_abs) {
|
||||
char *target_abs = path_join(is_abs ? root_dir : dir, target);
|
||||
if (!target_abs)
|
||||
return log_oom();
|
||||
|
||||
free_and_replace(target, target_abs);
|
||||
}
|
||||
|
||||
/* Get rid of "." and ".." components in target path */
|
||||
r = chase_symlinks(target, root_dir, CHASE_NOFOLLOW | CHASE_NONEXISTENT, &simplified, NULL);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to resolve symlink %s/%s pointing to %s: %m",
|
||||
dir, filename, target);
|
||||
|
||||
assert(path_is_absolute(simplified));
|
||||
|
||||
/* Check if the symlink remain inside of of our search path.
|
||||
* If yes, it is an alias. Verify that it is valid.
|
||||
*
|
||||
* If no, then this is a linked unit file or mask, and we don't care about the target name
|
||||
* when loading units, and we return the link *source* (resolve_destination_target == false);
|
||||
* When this is called for installation purposes, we want the final destination,
|
||||
* so we return the *target*.
|
||||
*/
|
||||
const char *tail = path_startswith_strv(simplified, search_path);
|
||||
if (tail) { /* An alias */
|
||||
_cleanup_free_ char *target_name = NULL;
|
||||
|
||||
r = path_extract_filename(simplified, &target_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = unit_validate_alias_symlink_or_warn(LOG_NOTICE, filename, simplified);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (is_path(tail))
|
||||
log_warning("Suspicious symlink %s/%s→%s, treating as alias.",
|
||||
dir, filename, simplified);
|
||||
|
||||
dst = resolve_destination_target ? TAKE_PTR(simplified) : TAKE_PTR(target_name);
|
||||
|
||||
} else {
|
||||
log_debug("Linked unit file: %s/%s → %s", dir, filename, simplified);
|
||||
|
||||
if (resolve_destination_target)
|
||||
dst = TAKE_PTR(simplified);
|
||||
else {
|
||||
dst = path_join(dir, filename);
|
||||
if (!dst)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
*ret_destination = TAKE_PTR(dst);
|
||||
return !tail; /* true if linked unit file */
|
||||
}
|
||||
|
||||
int unit_file_build_name_map(
|
||||
const LookupPaths *lp,
|
||||
uint64_t *cache_timestamp_hash,
|
||||
@ -308,10 +418,9 @@ int unit_file_build_name_map(
|
||||
|
||||
FOREACH_DIRENT_ALL(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) {
|
||||
_unused_ _cleanup_free_ char *_filename_free = NULL;
|
||||
_cleanup_free_ char *simplified = NULL;
|
||||
bool symlink_to_dir = false;
|
||||
const char *dst = NULL;
|
||||
char *filename;
|
||||
_cleanup_free_ char *dst = NULL;
|
||||
bool symlink_to_dir = false;
|
||||
|
||||
/* We only care about valid units and dirs with certain suffixes, let's ignore the
|
||||
* rest. */
|
||||
@ -395,77 +504,35 @@ int unit_file_build_name_map(
|
||||
/* We don't explicitly check for alias loops here. unit_ids_map_get() which
|
||||
* limits the number of hops should be used to access the map. */
|
||||
|
||||
_cleanup_free_ char *target = NULL;
|
||||
|
||||
r = readlinkat_malloc(dirfd(d), de->d_name, &target);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to read symlink %s/%s, ignoring: %m",
|
||||
*dir, de->d_name);
|
||||
r = unit_file_resolve_symlink(lp->root_dir, lp->search_path,
|
||||
*dir, dirfd(d), de->d_name,
|
||||
/* resolve_destination_target= */ false,
|
||||
&dst);
|
||||
if (r == -ENOMEM)
|
||||
return r;
|
||||
if (r < 0) /* we ignore other errors here */
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool is_abs = path_is_absolute(target);
|
||||
if (lp->root_dir || !is_abs) {
|
||||
char *target_abs = path_join(is_abs ? lp->root_dir : *dir, target);
|
||||
if (!target_abs)
|
||||
return log_oom();
|
||||
|
||||
free_and_replace(target, target_abs);
|
||||
}
|
||||
|
||||
/* Get rid of "." and ".." components in target path */
|
||||
r = chase_symlinks(target, lp->root_dir, CHASE_NOFOLLOW | CHASE_NONEXISTENT, &simplified, NULL);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to resolve symlink %s pointing to %s, ignoring: %m",
|
||||
filename, target);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if the symlink goes outside of our search path.
|
||||
* If yes, it's a linked unit file or mask, and we don't care about the target name.
|
||||
* Let's just store the link source directly.
|
||||
* If not, let's verify that it's a good symlink. */
|
||||
char *tail = path_startswith_strv(simplified, lp->search_path);
|
||||
if (!tail) {
|
||||
log_debug("%s: linked unit file: %s → %s",
|
||||
__func__, filename, simplified);
|
||||
|
||||
dst = filename;
|
||||
} else {
|
||||
|
||||
bool self_alias;
|
||||
|
||||
dst = basename(simplified);
|
||||
self_alias = streq(dst, de->d_name);
|
||||
|
||||
if (is_path(tail))
|
||||
log_full(self_alias ? LOG_DEBUG : LOG_WARNING,
|
||||
"Suspicious symlink %s→%s, treating as alias.",
|
||||
filename, simplified);
|
||||
|
||||
r = unit_validate_alias_symlink_and_warn(filename, simplified);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
if (self_alias) {
|
||||
/* A self-alias that has no effect */
|
||||
log_debug("%s: self-alias: %s/%s → %s, ignoring.",
|
||||
__func__, *dir, de->d_name, dst);
|
||||
continue;
|
||||
}
|
||||
|
||||
log_debug("%s: alias: %s/%s → %s", __func__, *dir, de->d_name, dst);
|
||||
}
|
||||
|
||||
} else {
|
||||
dst = filename;
|
||||
dst = TAKE_PTR(_filename_free); /* Grab the copy we made previously, if available. */
|
||||
if (!dst) {
|
||||
dst = strdup(filename);
|
||||
if (!dst)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
log_debug("%s: normal unit file: %s", __func__, dst);
|
||||
}
|
||||
|
||||
r = hashmap_put_strdup(&ids, de->d_name, dst);
|
||||
_cleanup_free_ char *key = strdup(de->d_name);
|
||||
if (!key)
|
||||
return log_oom();
|
||||
|
||||
r = hashmap_ensure_put(&ids, &string_hash_ops_free_free, key, dst);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to add entry to hashmap (%s→%s): %m",
|
||||
de->d_name, dst);
|
||||
key = dst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,11 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "path-lookup.h"
|
||||
#include "time-util.h"
|
||||
#include "unit-name.h"
|
||||
|
||||
typedef enum UnitFileState UnitFileState;
|
||||
typedef enum UnitFileScope UnitFileScope;
|
||||
typedef struct LookupPaths LookupPaths;
|
||||
|
||||
enum UnitFileState {
|
||||
UNIT_FILE_ENABLED,
|
||||
@ -29,21 +28,23 @@ enum UnitFileState {
|
||||
_UNIT_FILE_STATE_INVALID = -EINVAL,
|
||||
};
|
||||
|
||||
enum UnitFileScope {
|
||||
UNIT_FILE_SYSTEM,
|
||||
UNIT_FILE_GLOBAL,
|
||||
UNIT_FILE_USER,
|
||||
_UNIT_FILE_SCOPE_MAX,
|
||||
_UNIT_FILE_SCOPE_INVALID = -EINVAL,
|
||||
};
|
||||
|
||||
bool unit_type_may_alias(UnitType type) _const_;
|
||||
bool unit_type_may_template(UnitType type) _const_;
|
||||
|
||||
int unit_symlink_name_compatible(const char *symlink, const char *target, bool instance_propagation);
|
||||
int unit_validate_alias_symlink_and_warn(const char *filename, const char *target);
|
||||
int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, const char *target);
|
||||
|
||||
bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_hash, uint64_t *ret_new);
|
||||
|
||||
int unit_file_resolve_symlink(
|
||||
const char *root_dir,
|
||||
char **search_path,
|
||||
const char *dir,
|
||||
int dirfd,
|
||||
const char *filename,
|
||||
bool resolve_destination_target,
|
||||
char **ret_destination);
|
||||
|
||||
int unit_file_build_name_map(
|
||||
const LookupPaths *lp,
|
||||
uint64_t *cache_timestamp_hash,
|
||||
|
@ -2288,7 +2288,7 @@ fail:
|
||||
static int method_enable_unit_files_generic(
|
||||
sd_bus_message *message,
|
||||
Manager *m,
|
||||
int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes),
|
||||
int (*call)(LookupScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes),
|
||||
bool carries_install_info,
|
||||
sd_bus_error *error) {
|
||||
|
||||
@ -2352,7 +2352,7 @@ static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bu
|
||||
return method_enable_unit_files_generic(message, userdata, unit_file_link, false, error);
|
||||
}
|
||||
|
||||
static int unit_file_preset_without_mode(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes) {
|
||||
static int unit_file_preset_without_mode(LookupScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, size_t *n_changes) {
|
||||
return unit_file_preset(scope, flags, root_dir, files, UNIT_FILE_PRESET_FULL, changes, n_changes);
|
||||
}
|
||||
|
||||
@ -2412,7 +2412,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
|
||||
static int method_disable_unit_files_generic(
|
||||
sd_bus_message *message,
|
||||
Manager *m,
|
||||
int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes),
|
||||
int (*call)(LookupScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, size_t *n_changes),
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
@ -2638,7 +2638,7 @@ static int method_get_unit_file_links(sd_bus_message *message, void *userdata, s
|
||||
flags = UNIT_FILE_DRY_RUN |
|
||||
(runtime ? UNIT_FILE_RUNTIME : 0);
|
||||
|
||||
r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes);
|
||||
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, flags, NULL, p, &changes, &n_changes);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get file links for %s: %m", name);
|
||||
|
||||
|
@ -62,7 +62,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (!getenv("SYSTEMD_LOG_LEVEL"))
|
||||
log_set_max_level(LOG_CRIT);
|
||||
|
||||
assert_se(manager_new(UNIT_FILE_SYSTEM, MANAGER_TEST_RUN_MINIMAL, &m) >= 0);
|
||||
assert_se(manager_new(LOOKUP_SCOPE_SYSTEM, MANAGER_TEST_RUN_MINIMAL, &m) >= 0);
|
||||
|
||||
name = strjoina("a.", unit_type_to_string(t));
|
||||
assert_se(unit_new_for_name(m, unit_vtable[t]->object_size, name, &u) >= 0);
|
||||
|
@ -2885,7 +2885,7 @@ int main(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = manager_new(arg_system ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
|
||||
r = manager_new(arg_system ? LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER,
|
||||
arg_action == ACTION_TEST ? MANAGER_TEST_FULL : 0,
|
||||
&m);
|
||||
if (r < 0) {
|
||||
|
@ -775,13 +775,13 @@ static int manager_setup_sigchld_event_source(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) {
|
||||
int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) {
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
assert(_m);
|
||||
assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER));
|
||||
assert(IN_SET(scope, LOOKUP_SCOPE_SYSTEM, LOOKUP_SCOPE_USER));
|
||||
|
||||
m = new(Manager, 1);
|
||||
if (!m)
|
||||
@ -1700,7 +1700,7 @@ static void manager_preset_all(Manager *m) {
|
||||
return;
|
||||
|
||||
/* If this is the first boot, and we are in the host system, then preset everything */
|
||||
r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
|
||||
r = unit_file_preset_all(LOOKUP_SCOPE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
|
||||
if (r < 0)
|
||||
log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r,
|
||||
"Failed to populate /etc with preset unit settings, ignoring: %m");
|
||||
@ -1751,11 +1751,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *roo
|
||||
|
||||
/* If we are running in test mode, we still want to run the generators,
|
||||
* but we should not touch the real generator directories. */
|
||||
r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope,
|
||||
MANAGER_IS_TEST_RUN(m) ? LOOKUP_PATHS_TEMPORARY_GENERATED : 0,
|
||||
root);
|
||||
r = lookup_paths_init_or_warn(&m->lookup_paths, m->unit_file_scope,
|
||||
MANAGER_IS_TEST_RUN(m) ? LOOKUP_PATHS_TEMPORARY_GENERATED : 0,
|
||||
root);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to initialize path lookup table: %m");
|
||||
return r;
|
||||
|
||||
dual_timestamp_get(m->timestamps + manager_timestamp_initrd_mangle(MANAGER_TIMESTAMP_GENERATORS_START));
|
||||
r = manager_run_environment_generators(m);
|
||||
@ -3343,9 +3343,9 @@ int manager_reload(Manager *m) {
|
||||
m->uid_refs = hashmap_free(m->uid_refs);
|
||||
m->gid_refs = hashmap_free(m->gid_refs);
|
||||
|
||||
r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
|
||||
r = lookup_paths_init_or_warn(&m->lookup_paths, m->unit_file_scope, 0, NULL);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to initialize path lookup table, ignoring: %m");
|
||||
return r;
|
||||
|
||||
(void) manager_run_environment_generators(m);
|
||||
(void) manager_run_generators(m);
|
||||
|
@ -235,7 +235,7 @@ struct Manager {
|
||||
int user_lookup_fds[2];
|
||||
sd_event_source *user_lookup_event_source;
|
||||
|
||||
UnitFileScope unit_file_scope;
|
||||
LookupScope unit_file_scope;
|
||||
LookupPaths lookup_paths;
|
||||
Hashmap *unit_id_map;
|
||||
Hashmap *unit_name_map;
|
||||
@ -463,8 +463,8 @@ static inline usec_t manager_default_timeout_abort_usec(Manager *m) {
|
||||
return m->default_timeout_abort_set ? m->default_timeout_abort_usec : m->default_timeout_stop_usec;
|
||||
}
|
||||
|
||||
#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM)
|
||||
#define MANAGER_IS_USER(m) ((m)->unit_file_scope != UNIT_FILE_SYSTEM)
|
||||
#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == LOOKUP_SCOPE_SYSTEM)
|
||||
#define MANAGER_IS_USER(m) ((m)->unit_file_scope != LOOKUP_SCOPE_SYSTEM)
|
||||
|
||||
#define MANAGER_IS_RELOADING(m) ((m)->n_reloading > 0)
|
||||
|
||||
@ -475,7 +475,7 @@ static inline usec_t manager_default_timeout_abort_usec(Manager *m) {
|
||||
|
||||
#define MANAGER_IS_TEST_RUN(m) ((m)->test_run_flags != 0)
|
||||
|
||||
int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager **m);
|
||||
int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **m);
|
||||
Manager* manager_free(Manager *m);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
|
||||
|
||||
|
@ -183,7 +183,7 @@ int unit_name_printf(const Unit *u, const char* format, char **ret) {
|
||||
|
||||
COMMON_SYSTEM_SPECIFIERS,
|
||||
|
||||
COMMON_CREDS_SPECIFIERS,
|
||||
COMMON_CREDS_SPECIFIERS(u->manager->unit_file_scope),
|
||||
{}
|
||||
};
|
||||
|
||||
@ -253,7 +253,7 @@ int unit_full_printf_full(const Unit *u, const char *format, size_t max_length,
|
||||
|
||||
COMMON_SYSTEM_SPECIFIERS,
|
||||
|
||||
COMMON_CREDS_SPECIFIERS,
|
||||
COMMON_CREDS_SPECIFIERS(u->manager->unit_file_scope),
|
||||
|
||||
COMMON_TMP_SPECIFIERS,
|
||||
{}
|
||||
|
@ -601,8 +601,8 @@ static int get_search(uint64_t type, char ***list) {
|
||||
case SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT:
|
||||
case SD_PATH_SYSTEMD_SEARCH_USER_UNIT: {
|
||||
_cleanup_(lookup_paths_free) LookupPaths lp = {};
|
||||
const UnitFileScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT ?
|
||||
UNIT_FILE_SYSTEM : UNIT_FILE_USER;
|
||||
const LookupScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT ?
|
||||
LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER;
|
||||
|
||||
r = lookup_paths_init(&lp, scope, 0, NULL);
|
||||
if (r < 0)
|
||||
@ -615,8 +615,8 @@ static int get_search(uint64_t type, char ***list) {
|
||||
case SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR:
|
||||
case SD_PATH_SYSTEMD_SEARCH_USER_GENERATOR: {
|
||||
char **t;
|
||||
const UnitFileScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR ?
|
||||
UNIT_FILE_SYSTEM : UNIT_FILE_USER;
|
||||
const LookupScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR ?
|
||||
LOOKUP_SCOPE_SYSTEM : LOOKUP_SCOPE_USER;
|
||||
|
||||
t = generator_binary_paths(scope);
|
||||
if (!t)
|
||||
|
@ -231,7 +231,7 @@ static int extract_now(
|
||||
/* Then, send unit file data to the parent (or/and add it to the hashmap). For that we use our usual unit
|
||||
* discovery logic. Note that we force looking inside of /lib/systemd/system/ for units too, as we mightbe
|
||||
* compiled for a split-usr system but the image might be a legacy-usr one. */
|
||||
r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where);
|
||||
r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to acquire lookup paths: %m");
|
||||
|
||||
@ -1340,12 +1340,12 @@ int portable_attach(
|
||||
strempty(extensions_joined));
|
||||
}
|
||||
|
||||
r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
|
||||
r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
HASHMAP_FOREACH(item, unit_files) {
|
||||
r = unit_file_exists(UNIT_FILE_SYSTEM, &paths, item->name);
|
||||
r = unit_file_exists(LOOKUP_SCOPE_SYSTEM, &paths, item->name);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name);
|
||||
if (!FLAGS_SET(flags, PORTABLE_REATTACH) && r > 0)
|
||||
@ -1539,7 +1539,7 @@ int portable_detach(
|
||||
|
||||
assert(name_or_path);
|
||||
|
||||
r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
|
||||
r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1573,7 +1573,7 @@ int portable_detach(
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
r = unit_file_lookup_state(UNIT_FILE_SYSTEM, &paths, de->d_name, &state);
|
||||
r = unit_file_lookup_state(LOOKUP_SCOPE_SYSTEM, &paths, de->d_name, &state);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name);
|
||||
if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_RUNTIME, UNIT_FILE_LINKED_RUNTIME))
|
||||
@ -1717,7 +1717,7 @@ static int portable_get_state_internal(
|
||||
assert(name_or_path);
|
||||
assert(ret);
|
||||
|
||||
r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
|
||||
r = lookup_paths_init(&paths, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1753,7 +1753,7 @@ static int portable_get_state_internal(
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
r = unit_file_lookup_state(UNIT_FILE_SYSTEM, &paths, de->d_name, &state);
|
||||
r = unit_file_lookup_state(LOOKUP_SCOPE_SYSTEM, &paths, de->d_name, &state);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name);
|
||||
if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_LINKED_RUNTIME))
|
||||
|
@ -785,7 +785,8 @@ static int condition_test_needs_update(Condition *c, char **env) {
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p);
|
||||
return true;
|
||||
} else if (r == 0) {
|
||||
}
|
||||
if (isempty(timestamp_str)) {
|
||||
log_debug("No data in timestamp file '%s', using mtime.", p);
|
||||
return true;
|
||||
}
|
||||
|
@ -97,7 +97,11 @@ static int specifier_last_component(char specifier, const void *data, const char
|
||||
return 0;
|
||||
}
|
||||
|
||||
int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) {
|
||||
int install_name_printf(
|
||||
LookupScope scope,
|
||||
const UnitFileInstallInfo *info,
|
||||
const char *format,
|
||||
char **ret) {
|
||||
/* This is similar to unit_name_printf() */
|
||||
|
||||
const Specifier table[] = {
|
||||
@ -109,13 +113,13 @@ int install_name_printf(const UnitFileInstallInfo *i, const char *format, const
|
||||
|
||||
COMMON_SYSTEM_SPECIFIERS,
|
||||
|
||||
COMMON_CREDS_SPECIFIERS,
|
||||
COMMON_CREDS_SPECIFIERS(scope),
|
||||
{}
|
||||
};
|
||||
|
||||
assert(i);
|
||||
assert(info);
|
||||
assert(format);
|
||||
assert(ret);
|
||||
|
||||
return specifier_printf(format, UNIT_NAME_MAX, table, root, i, ret);
|
||||
return specifier_printf(format, UNIT_NAME_MAX, table, info->root, info, ret);
|
||||
}
|
||||
|
@ -4,4 +4,8 @@
|
||||
#include "install.h"
|
||||
#include "unit-name.h"
|
||||
|
||||
int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret);
|
||||
int install_name_printf(
|
||||
LookupScope scope,
|
||||
const UnitFileInstallInfo *info,
|
||||
const char *format,
|
||||
char **ret);
|
||||
|
1106
src/shared/install.c
1106
src/shared/install.c
File diff suppressed because it is too large
Load Diff
@ -15,6 +15,7 @@ typedef struct UnitFileInstallInfo UnitFileInstallInfo;
|
||||
#include "macro.h"
|
||||
#include "path-lookup.h"
|
||||
#include "strv.h"
|
||||
#include "unit-file.h"
|
||||
#include "unit-name.h"
|
||||
|
||||
enum UnitFilePresetMode {
|
||||
@ -70,7 +71,8 @@ struct UnitFileList {
|
||||
|
||||
enum UnitFileType {
|
||||
UNIT_FILE_TYPE_REGULAR,
|
||||
UNIT_FILE_TYPE_SYMLINK,
|
||||
UNIT_FILE_TYPE_LINKED,
|
||||
UNIT_FILE_TYPE_ALIAS,
|
||||
UNIT_FILE_TYPE_MASKED,
|
||||
_UNIT_FILE_TYPE_MAX,
|
||||
_UNIT_FILE_TYPE_INVALID = -EINVAL,
|
||||
@ -94,28 +96,28 @@ struct UnitFileInstallInfo {
|
||||
};
|
||||
|
||||
int unit_file_enable(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
UnitFileFlags flags,
|
||||
const char *root_dir,
|
||||
char **files,
|
||||
UnitFileChange **changes,
|
||||
size_t *n_changes);
|
||||
int unit_file_disable(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
UnitFileFlags flags,
|
||||
const char *root_dir,
|
||||
char **files,
|
||||
UnitFileChange **changes,
|
||||
size_t *n_changes);
|
||||
int unit_file_reenable(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
UnitFileFlags flags,
|
||||
const char *root_dir,
|
||||
char **files,
|
||||
char **names_or_paths,
|
||||
UnitFileChange **changes,
|
||||
size_t *n_changes);
|
||||
int unit_file_preset(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
UnitFileFlags flags,
|
||||
const char *root_dir,
|
||||
char **files,
|
||||
@ -123,52 +125,52 @@ int unit_file_preset(
|
||||
UnitFileChange **changes,
|
||||
size_t *n_changes);
|
||||
int unit_file_preset_all(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
UnitFileFlags flags,
|
||||
const char *root_dir,
|
||||
UnitFilePresetMode mode,
|
||||
UnitFileChange **changes,
|
||||
size_t *n_changes);
|
||||
int unit_file_mask(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
UnitFileFlags flags,
|
||||
const char *root_dir,
|
||||
char **files,
|
||||
UnitFileChange **changes,
|
||||
size_t *n_changes);
|
||||
int unit_file_unmask(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
UnitFileFlags flags,
|
||||
const char *root_dir,
|
||||
char **files,
|
||||
UnitFileChange **changes,
|
||||
size_t *n_changes);
|
||||
int unit_file_link(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
UnitFileFlags flags,
|
||||
const char *root_dir,
|
||||
char **files,
|
||||
UnitFileChange **changes,
|
||||
size_t *n_changes);
|
||||
int unit_file_revert(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
const char *root_dir,
|
||||
char **files,
|
||||
UnitFileChange **changes,
|
||||
size_t *n_changes);
|
||||
int unit_file_set_default(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
UnitFileFlags flags,
|
||||
const char *root_dir,
|
||||
const char *file,
|
||||
UnitFileChange **changes,
|
||||
size_t *n_changes);
|
||||
int unit_file_get_default(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
const char *root_dir,
|
||||
char **name);
|
||||
int unit_file_add_dependency(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
UnitFileFlags flags,
|
||||
const char *root_dir,
|
||||
char **files,
|
||||
@ -178,22 +180,27 @@ int unit_file_add_dependency(
|
||||
size_t *n_changes);
|
||||
|
||||
int unit_file_lookup_state(
|
||||
UnitFileScope scope,
|
||||
LookupScope scope,
|
||||
const LookupPaths *paths,
|
||||
const char *name,
|
||||
UnitFileState *ret);
|
||||
|
||||
int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret);
|
||||
int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name);
|
||||
int unit_file_get_state(LookupScope scope, const char *root_dir, const char *filename, UnitFileState *ret);
|
||||
int unit_file_exists(LookupScope scope, const LookupPaths *paths, const char *name);
|
||||
|
||||
int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns);
|
||||
int unit_file_get_list(LookupScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns);
|
||||
Hashmap* unit_file_list_free(Hashmap *h);
|
||||
|
||||
int unit_file_changes_add(UnitFileChange **changes, size_t *n_changes, int type, const char *path, const char *source);
|
||||
void unit_file_changes_free(UnitFileChange *changes, size_t n_changes);
|
||||
void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, size_t n_changes, bool quiet);
|
||||
|
||||
int unit_file_verify_alias(const UnitFileInstallInfo *i, const char *dst, char **ret_dst);
|
||||
int unit_file_verify_alias(
|
||||
const UnitFileInstallInfo *info,
|
||||
const char *dst,
|
||||
char **ret_dst,
|
||||
UnitFileChange **changes,
|
||||
size_t *n_changes);
|
||||
|
||||
typedef struct UnitFilePresetRule UnitFilePresetRule;
|
||||
|
||||
@ -204,7 +211,7 @@ typedef struct {
|
||||
} UnitFilePresets;
|
||||
|
||||
void unit_file_presets_freep(UnitFilePresets *p);
|
||||
int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name, UnitFilePresets *cached);
|
||||
int unit_file_query_preset(LookupScope scope, const char *root_dir, const char *name, UnitFilePresets *cached);
|
||||
|
||||
const char *unit_file_state_to_string(UnitFileState s) _const_;
|
||||
UnitFileState unit_file_state_from_string(const char *s) _pure_;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "id128-util.h"
|
||||
#include "macro.h"
|
||||
#include "os-util.h"
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
#include "specifier.h"
|
||||
#include "string-util.h"
|
||||
@ -162,7 +163,8 @@ int specifier_machine_id(char specifier, const void *data, const char *root, con
|
||||
|
||||
fd = chase_symlinks_and_open("/etc/machine-id", root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
/* Translate error for missing os-release file to EUNATCH. */
|
||||
return fd == -ENOENT ? -EUNATCH : fd;
|
||||
|
||||
r = id128_read_fd(fd, ID128_PLAIN, &id);
|
||||
} else
|
||||
@ -269,44 +271,54 @@ int specifier_architecture(char specifier, const void *data, const char *root, c
|
||||
}
|
||||
|
||||
/* Note: fields in /etc/os-release might quite possibly be missing, even if everything is entirely valid
|
||||
* otherwise. We'll return an empty value or NULL in that case from the functions below. */
|
||||
* otherwise. We'll return an empty value or NULL in that case from the functions below. But if the
|
||||
* os-release file is missing, we'll return -EUNATCH. This means that something is seriously wrong with the
|
||||
* installation. */
|
||||
|
||||
static int parse_os_release_specifier(const char *root, const char *id, char **ret) {
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
/* Translate error for missing os-release file to EUNATCH. */
|
||||
r = parse_os_release(root, id, ret);
|
||||
return r == -ENOENT ? -EUNATCH : r;
|
||||
}
|
||||
|
||||
int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
assert(ret);
|
||||
return parse_os_release(root, "ID", ret);
|
||||
return parse_os_release_specifier(root, "ID", ret);
|
||||
}
|
||||
|
||||
int specifier_os_version_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
assert(ret);
|
||||
return parse_os_release(root, "VERSION_ID", ret);
|
||||
return parse_os_release_specifier(root, "VERSION_ID", ret);
|
||||
}
|
||||
|
||||
int specifier_os_build_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
assert(ret);
|
||||
return parse_os_release(root, "BUILD_ID", ret);
|
||||
return parse_os_release_specifier(root, "BUILD_ID", ret);
|
||||
}
|
||||
|
||||
int specifier_os_variant_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
assert(ret);
|
||||
return parse_os_release(root, "VARIANT_ID", ret);
|
||||
return parse_os_release_specifier(root, "VARIANT_ID", ret);
|
||||
}
|
||||
|
||||
int specifier_os_image_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
assert(ret);
|
||||
return parse_os_release(root, "IMAGE_ID", ret);
|
||||
return parse_os_release_specifier(root, "IMAGE_ID", ret);
|
||||
}
|
||||
|
||||
int specifier_os_image_version(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
assert(ret);
|
||||
return parse_os_release(root, "IMAGE_VERSION", ret);
|
||||
return parse_os_release_specifier(root, "IMAGE_VERSION", ret);
|
||||
}
|
||||
|
||||
int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
LookupScope scope = PTR_TO_INT(data);
|
||||
char *t;
|
||||
|
||||
assert(ret);
|
||||
|
||||
t = gid_to_name(getgid());
|
||||
if (scope == LOOKUP_SCOPE_GLOBAL)
|
||||
return -EINVAL;
|
||||
|
||||
t = gid_to_name(scope == LOOKUP_SCOPE_USER ? getgid() : 0);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -315,27 +327,42 @@ int specifier_group_name(char specifier, const void *data, const char *root, con
|
||||
}
|
||||
|
||||
int specifier_group_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
LookupScope scope = PTR_TO_INT(data);
|
||||
gid_t gid;
|
||||
|
||||
assert(ret);
|
||||
|
||||
if (asprintf(ret, UID_FMT, getgid()) < 0)
|
||||
if (scope == LOOKUP_SCOPE_GLOBAL)
|
||||
return -EINVAL;
|
||||
|
||||
gid = scope == LOOKUP_SCOPE_USER ? getgid() : 0;
|
||||
|
||||
if (asprintf(ret, UID_FMT, gid) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int specifier_user_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
LookupScope scope = PTR_TO_INT(data);
|
||||
uid_t uid;
|
||||
char *t;
|
||||
|
||||
assert(ret);
|
||||
|
||||
/* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able
|
||||
* to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed.
|
||||
if (scope == LOOKUP_SCOPE_GLOBAL)
|
||||
return -EINVAL;
|
||||
|
||||
* We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with
|
||||
* specifer_user_id() below.
|
||||
uid = scope == LOOKUP_SCOPE_USER ? getuid() : 0;
|
||||
|
||||
/* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want
|
||||
* to be able to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed.
|
||||
|
||||
* We don't use getusername_malloc() here, because we don't want to look at $USER, to remain
|
||||
* consistent with specifer_user_id() below.
|
||||
*/
|
||||
|
||||
t = uid_to_name(getuid());
|
||||
t = uid_to_name(uid);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -344,9 +371,17 @@ int specifier_user_name(char specifier, const void *data, const char *root, cons
|
||||
}
|
||||
|
||||
int specifier_user_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
LookupScope scope = PTR_TO_INT(data);
|
||||
uid_t uid;
|
||||
|
||||
assert(ret);
|
||||
|
||||
if (asprintf(ret, UID_FMT, getuid()) < 0)
|
||||
if (scope == LOOKUP_SCOPE_GLOBAL)
|
||||
return -EINVAL;
|
||||
|
||||
uid = scope == LOOKUP_SCOPE_USER ? getuid() : 0;
|
||||
|
||||
if (asprintf(ret, UID_FMT, uid) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
|
@ -84,11 +84,11 @@ int specifier_var_tmp_dir(char specifier, const void *data, const char *root, co
|
||||
{ 'w', specifier_os_version_id, NULL }, \
|
||||
{ 'W', specifier_os_variant_id, NULL }
|
||||
|
||||
#define COMMON_CREDS_SPECIFIERS \
|
||||
{ 'g', specifier_group_name, NULL }, \
|
||||
{ 'G', specifier_group_id, NULL }, \
|
||||
{ 'u', specifier_user_name, NULL }, \
|
||||
{ 'U', specifier_user_id, NULL }
|
||||
#define COMMON_CREDS_SPECIFIERS(scope) \
|
||||
{ 'g', specifier_group_name, INT_TO_PTR(scope) }, \
|
||||
{ 'G', specifier_group_id, INT_TO_PTR(scope) }, \
|
||||
{ 'u', specifier_user_name, INT_TO_PTR(scope) }, \
|
||||
{ 'U', specifier_user_id, INT_TO_PTR(scope) }
|
||||
|
||||
#define COMMON_TMP_SPECIFIERS \
|
||||
{ 'T', specifier_tmp_dir, NULL }, \
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "cgroup-util.h"
|
||||
#include "env-file.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "log.h"
|
||||
#include "namespace-util.h"
|
||||
@ -33,6 +34,7 @@
|
||||
#include "random-util.h"
|
||||
#include "strv.h"
|
||||
#include "tests.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
char* setup_fake_runtime_dir(void) {
|
||||
char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p;
|
||||
@ -132,6 +134,23 @@ int log_tests_skipped_errno(int r, const char *message) {
|
||||
return EXIT_TEST_SKIP;
|
||||
}
|
||||
|
||||
int write_tmpfile(char *pattern, const char *contents) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
assert(pattern);
|
||||
assert(contents);
|
||||
|
||||
fd = mkostemp_safe(pattern);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
ssize_t l = strlen(contents);
|
||||
errno = 0;
|
||||
if (write(fd, contents, l) != l)
|
||||
return errno_or_else(EIO);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool have_namespaces(void) {
|
||||
siginfo_t si = {};
|
||||
pid_t pid;
|
||||
|
@ -30,6 +30,8 @@ void test_setup_logging(int level);
|
||||
int log_tests_skipped(const char *message);
|
||||
int log_tests_skipped_errno(int r, const char *message);
|
||||
|
||||
int write_tmpfile(char *pattern, const char *contents);
|
||||
|
||||
bool have_namespaces(void);
|
||||
|
||||
/* We use the small but non-trivial limit here */
|
||||
|
@ -37,9 +37,9 @@ int verb_cat(int argc, char *argv[], void *userdata) {
|
||||
if (arg_transport != BUS_TRANSPORT_LOCAL)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot remotely cat units.");
|
||||
|
||||
r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
|
||||
r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine unit paths: %m");
|
||||
return r;
|
||||
|
||||
r = acquire_bus(BUS_MANAGER, &bus);
|
||||
if (r < 0)
|
||||
@ -99,7 +99,7 @@ int verb_cat(int argc, char *argv[], void *userdata) {
|
||||
ansi_highlight_red(),
|
||||
ansi_highlight_red(),
|
||||
ansi_highlight_red(),
|
||||
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
|
||||
arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user",
|
||||
ansi_normal());
|
||||
|
||||
r = cat_files(fragment_path, dropin_paths, 0);
|
||||
@ -406,8 +406,8 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
|
||||
if (!path) {
|
||||
if (!arg_force) {
|
||||
log_info("Run 'systemctl edit%s --force --full %s' to create a new unit.",
|
||||
arg_scope == UNIT_FILE_GLOBAL ? " --global" :
|
||||
arg_scope == UNIT_FILE_USER ? " --user" : "",
|
||||
arg_scope == LOOKUP_SCOPE_GLOBAL ? " --global" :
|
||||
arg_scope == LOOKUP_SCOPE_USER ? " --user" : "",
|
||||
*name);
|
||||
return -ENOENT;
|
||||
}
|
||||
@ -507,9 +507,9 @@ int verb_edit(int argc, char *argv[], void *userdata) {
|
||||
if (arg_transport != BUS_TRANSPORT_LOCAL)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units remotely.");
|
||||
|
||||
r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
|
||||
r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine unit paths: %m");
|
||||
return r;
|
||||
|
||||
r = mac_selinux_init();
|
||||
if (r < 0)
|
||||
|
@ -141,7 +141,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
if (STR_IN_SET(verb, "mask", "unmask")) {
|
||||
_cleanup_(lookup_paths_free) LookupPaths lp = {};
|
||||
|
||||
r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
|
||||
r = lookup_paths_init_or_warn(&lp, arg_scope, 0, arg_root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -18,7 +18,7 @@ static int show_installation_targets_client_side(const char *name) {
|
||||
flags = UNIT_FILE_DRY_RUN |
|
||||
(arg_runtime ? UNIT_FILE_RUNTIME : 0);
|
||||
|
||||
r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes);
|
||||
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, flags, NULL, p, &changes, &n_changes);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get file links for %s: %m", name);
|
||||
|
||||
|
@ -762,7 +762,7 @@ static void print_status_info(
|
||||
getuid(),
|
||||
get_output_flags() | OUTPUT_BEGIN_NEWLINE,
|
||||
SD_JOURNAL_LOCAL_ONLY,
|
||||
arg_scope == UNIT_FILE_SYSTEM,
|
||||
arg_scope == LOOKUP_SCOPE_SYSTEM,
|
||||
ellipsized);
|
||||
|
||||
if (i->need_daemon_reload)
|
||||
|
@ -246,10 +246,10 @@ int verb_start_special(int argc, char *argv[], void *userdata) {
|
||||
int verb_start_system_special(int argc, char *argv[], void *userdata) {
|
||||
/* Like start_special above, but raises an error when running in user mode */
|
||||
|
||||
if (arg_scope != UNIT_FILE_SYSTEM)
|
||||
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Bad action for %s mode.",
|
||||
arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
|
||||
arg_scope == LOOKUP_SCOPE_GLOBAL ? "--global" : "--user");
|
||||
|
||||
return verb_start_special(argc, argv, userdata);
|
||||
}
|
||||
|
@ -168,8 +168,8 @@ fail:
|
||||
BUS_ERROR_UNIT_MASKED,
|
||||
BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
|
||||
log_error("See %s logs and 'systemctl%s status%s %s' for details.",
|
||||
arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
|
||||
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
|
||||
arg_scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user",
|
||||
arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user",
|
||||
name[0] == '-' ? " --" : "",
|
||||
name);
|
||||
|
||||
@ -242,7 +242,7 @@ static const char** make_extra_args(const char *extra_args[static 4]) {
|
||||
|
||||
assert(extra_args);
|
||||
|
||||
if (arg_scope != UNIT_FILE_SYSTEM)
|
||||
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
|
||||
extra_args[n++] = "--user";
|
||||
|
||||
if (arg_transport == BUS_TRANSPORT_REMOTE) {
|
||||
|
@ -116,7 +116,7 @@ int enable_sysv_units(const char *verb, char **args) {
|
||||
|
||||
/* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
|
||||
|
||||
if (arg_scope != UNIT_FILE_SYSTEM)
|
||||
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
|
||||
return 0;
|
||||
|
||||
if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
|
||||
@ -128,7 +128,7 @@ int enable_sysv_units(const char *verb, char **args) {
|
||||
"is-enabled"))
|
||||
return 0;
|
||||
|
||||
r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
|
||||
r = lookup_paths_init_or_warn(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -46,7 +46,7 @@ int acquire_bus(BusFocus focus, sd_bus **ret) {
|
||||
if (!buses[focus]) {
|
||||
bool user;
|
||||
|
||||
user = arg_scope != UNIT_FILE_SYSTEM;
|
||||
user = arg_scope != LOOKUP_SCOPE_SYSTEM;
|
||||
|
||||
if (focus == BUS_MANAGER)
|
||||
r = bus_connect_transport_systemd(arg_transport, arg_host, user, &buses[focus]);
|
||||
@ -73,7 +73,7 @@ void ask_password_agent_open_maybe(void) {
|
||||
if (arg_dry_run)
|
||||
return;
|
||||
|
||||
if (arg_scope != UNIT_FILE_SYSTEM)
|
||||
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
|
||||
return;
|
||||
|
||||
ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
|
||||
@ -82,7 +82,7 @@ void ask_password_agent_open_maybe(void) {
|
||||
void polkit_agent_open_maybe(void) {
|
||||
/* Open the polkit agent as a child process if necessary */
|
||||
|
||||
if (arg_scope != UNIT_FILE_SYSTEM)
|
||||
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
|
||||
return;
|
||||
|
||||
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
||||
@ -380,7 +380,7 @@ void warn_unit_file_changed(const char *unit) {
|
||||
ansi_highlight_red(),
|
||||
ansi_normal(),
|
||||
unit,
|
||||
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
|
||||
arg_scope == LOOKUP_SCOPE_SYSTEM ? "" : " --user");
|
||||
}
|
||||
|
||||
int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) {
|
||||
@ -814,7 +814,7 @@ bool install_client_side(void) {
|
||||
if (!isempty(arg_root))
|
||||
return true;
|
||||
|
||||
if (arg_scope == UNIT_FILE_GLOBAL)
|
||||
if (arg_scope == LOOKUP_SCOPE_GLOBAL)
|
||||
return true;
|
||||
|
||||
/* Unsupported environment variable, mostly for debugging purposes */
|
||||
|
@ -66,7 +66,7 @@ char **arg_properties = NULL;
|
||||
bool arg_all = false;
|
||||
enum dependency arg_dependency = DEPENDENCY_FORWARD;
|
||||
const char *_arg_job_mode = NULL;
|
||||
UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
|
||||
LookupScope arg_scope = LOOKUP_SCOPE_SYSTEM;
|
||||
bool arg_wait = false;
|
||||
bool arg_no_block = false;
|
||||
int arg_legend = -1; /* -1: true, unless --quiet is passed, 1: true */
|
||||
@ -616,15 +616,15 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case ARG_USER:
|
||||
arg_scope = UNIT_FILE_USER;
|
||||
arg_scope = LOOKUP_SCOPE_USER;
|
||||
break;
|
||||
|
||||
case ARG_SYSTEM:
|
||||
arg_scope = UNIT_FILE_SYSTEM;
|
||||
arg_scope = LOOKUP_SCOPE_SYSTEM;
|
||||
break;
|
||||
|
||||
case ARG_GLOBAL:
|
||||
arg_scope = UNIT_FILE_GLOBAL;
|
||||
arg_scope = LOOKUP_SCOPE_GLOBAL;
|
||||
break;
|
||||
|
||||
case ARG_WAIT:
|
||||
@ -924,10 +924,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
|
||||
/* If we are in --user mode, there's no point in talking to PolicyKit or the infra to query system
|
||||
* passwords */
|
||||
if (arg_scope != UNIT_FILE_SYSTEM)
|
||||
if (arg_scope != LOOKUP_SCOPE_SYSTEM)
|
||||
arg_ask_password = false;
|
||||
|
||||
if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != UNIT_FILE_SYSTEM)
|
||||
if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != LOOKUP_SCOPE_SYSTEM)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Cannot access user instance remotely.");
|
||||
|
||||
|
@ -51,7 +51,7 @@ extern char **arg_properties;
|
||||
extern bool arg_all;
|
||||
extern enum dependency arg_dependency;
|
||||
extern const char *_arg_job_mode;
|
||||
extern UnitFileScope arg_scope;
|
||||
extern LookupScope arg_scope;
|
||||
extern bool arg_wait;
|
||||
extern bool arg_no_block;
|
||||
extern int arg_legend;
|
||||
|
@ -747,7 +747,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
|
||||
if (hashmap_contains(all_services, name))
|
||||
continue;
|
||||
|
||||
r = unit_file_exists(UNIT_FILE_SYSTEM, lp, name);
|
||||
r = unit_file_exists(LOOKUP_SCOPE_SYSTEM, lp, name);
|
||||
if (r < 0 && !IN_SET(r, -ELOOP, -ERFKILL, -EADDRNOTAVAIL)) {
|
||||
log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name);
|
||||
continue;
|
||||
@ -891,9 +891,9 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
|
||||
|
||||
assert_se(arg_dest = dest_late);
|
||||
|
||||
r = lookup_paths_init(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL);
|
||||
r = lookup_paths_init_or_warn(&lp, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to find lookup paths: %m");
|
||||
return r;
|
||||
|
||||
all_services = hashmap_new(&string_hash_ops);
|
||||
if (!all_services)
|
||||
|
@ -97,7 +97,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
/* The simple tests succeeded. Now let's try full unit-based use-case. */
|
||||
|
||||
assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
|
||||
assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
|
||||
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
|
||||
|
||||
assert_se(u = unit_new(m, sizeof(Service)));
|
||||
|
@ -301,7 +301,7 @@ int main(int argc, char *argv[]) {
|
||||
assert_se(set_unit_path(unit_dir) >= 0);
|
||||
assert_se(runtime_dir = setup_fake_runtime_dir());
|
||||
|
||||
assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
|
||||
assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
|
||||
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
|
||||
|
||||
assert_se(test_bpf_cgroup_programs(m,
|
||||
|
@ -90,7 +90,7 @@ int main(int argc, char *argv[]) {
|
||||
assert_se(set_unit_path(unit_dir) >= 0);
|
||||
assert_se(runtime_dir = setup_fake_runtime_dir());
|
||||
|
||||
assert_se(manager_new(UNIT_FILE_SYSTEM, MANAGER_TEST_RUN_BASIC, &m) >= 0);
|
||||
assert_se(manager_new(LOOKUP_SCOPE_SYSTEM, MANAGER_TEST_RUN_BASIC, &m) >= 0);
|
||||
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
|
||||
|
||||
/* We need to enable access to the filesystem where the binary is so we
|
||||
|
@ -42,7 +42,7 @@ TEST_RET(cgroup_mask, .sd_booted = true) {
|
||||
assert_se(get_testdata_dir("units", &unit_dir) >= 0);
|
||||
assert_se(set_unit_path(unit_dir) >= 0);
|
||||
assert_se(runtime_dir = setup_fake_runtime_dir());
|
||||
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
|
||||
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m);
|
||||
if (IN_SET(r, -EPERM, -EACCES)) {
|
||||
log_error_errno(r, "manager_new: %m");
|
||||
return log_tests_skipped("cannot create manager");
|
||||
|
@ -26,7 +26,7 @@ TEST_RET(default_memory_low, .sd_booted = true) {
|
||||
assert_se(get_testdata_dir("units", &unit_dir) >= 0);
|
||||
assert_se(set_unit_path(unit_dir) >= 0);
|
||||
assert_se(runtime_dir = setup_fake_runtime_dir());
|
||||
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
|
||||
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m);
|
||||
if (IN_SET(r, -EPERM, -EACCES)) {
|
||||
log_error_errno(r, "manager_new: %m");
|
||||
return log_tests_skipped("cannot create manager");
|
||||
|
@ -93,7 +93,7 @@ int main(int argc, char *argv[]) {
|
||||
assert_se(set_unit_path(unit_dir) >= 0);
|
||||
assert_se(runtime_dir = setup_fake_runtime_dir());
|
||||
|
||||
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
|
||||
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m);
|
||||
if (manager_errno_skip_test(r))
|
||||
return log_tests_skipped_errno(r, "manager_new");
|
||||
assert_se(r >= 0);
|
||||
|
@ -9,7 +9,12 @@
|
||||
#include "tests.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
/* In case of repeating keys, later entries win. */
|
||||
|
||||
#define env_file_1 \
|
||||
"a=a\n" \
|
||||
"a=b\n" \
|
||||
"a=b\n" \
|
||||
"a=a\n" \
|
||||
"b=b\\\n" \
|
||||
"c\n" \
|
||||
@ -55,18 +60,11 @@
|
||||
|
||||
|
||||
TEST(load_env_file_1) {
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
int r;
|
||||
|
||||
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
|
||||
_cleanup_close_ int fd;
|
||||
assert_se(write_tmpfile(name, env_file_1) == 0);
|
||||
|
||||
fd = mkostemp_safe(name);
|
||||
assert_se(fd >= 0);
|
||||
assert_se(write(fd, env_file_1, strlen(env_file_1)) == strlen(env_file_1));
|
||||
|
||||
r = load_env_file(NULL, name, &data);
|
||||
assert_se(r == 0);
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
assert_se(load_env_file(NULL, name, &data) == 0);
|
||||
assert_se(streq(data[0], "a=a"));
|
||||
assert_se(streq(data[1], "b=bc"));
|
||||
assert_se(streq(data[2], "d=de f"));
|
||||
@ -77,50 +75,30 @@ TEST(load_env_file_1) {
|
||||
}
|
||||
|
||||
TEST(load_env_file_2) {
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
int r;
|
||||
|
||||
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
|
||||
_cleanup_close_ int fd;
|
||||
assert_se(write_tmpfile(name, env_file_2) == 0);
|
||||
|
||||
fd = mkostemp_safe(name);
|
||||
assert_se(fd >= 0);
|
||||
assert_se(write(fd, env_file_2, strlen(env_file_2)) == strlen(env_file_2));
|
||||
|
||||
r = load_env_file(NULL, name, &data);
|
||||
assert_se(r == 0);
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
assert_se(load_env_file(NULL, name, &data) == 0);
|
||||
assert_se(streq(data[0], "a=a"));
|
||||
assert_se(data[1] == NULL);
|
||||
}
|
||||
|
||||
TEST(load_env_file_3) {
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
int r;
|
||||
|
||||
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
|
||||
_cleanup_close_ int fd;
|
||||
assert_se(write_tmpfile(name, env_file_3) == 0);
|
||||
|
||||
fd = mkostemp_safe(name);
|
||||
assert_se(fd >= 0);
|
||||
assert_se(write(fd, env_file_3, strlen(env_file_3)) == strlen(env_file_3));
|
||||
|
||||
r = load_env_file(NULL, name, &data);
|
||||
assert_se(r == 0);
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
assert_se(load_env_file(NULL, name, &data) == 0);
|
||||
assert_se(data == NULL);
|
||||
}
|
||||
|
||||
TEST(load_env_file_4) {
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
|
||||
_cleanup_close_ int fd;
|
||||
int r;
|
||||
assert_se(write_tmpfile(name, env_file_4) == 0);
|
||||
|
||||
fd = mkostemp_safe(name);
|
||||
assert_se(fd >= 0);
|
||||
assert_se(write(fd, env_file_4, strlen(env_file_4)) == strlen(env_file_4));
|
||||
|
||||
r = load_env_file(NULL, name, &data);
|
||||
assert_se(r == 0);
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
assert_se(load_env_file(NULL, name, &data) == 0);
|
||||
assert_se(streq(data[0], "HWMON_MODULES=coretemp f71882fg"));
|
||||
assert_se(streq(data[1], "MODULE_0=coretemp"));
|
||||
assert_se(streq(data[2], "MODULE_1=f71882fg"));
|
||||
@ -128,36 +106,22 @@ TEST(load_env_file_4) {
|
||||
}
|
||||
|
||||
TEST(load_env_file_5) {
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
int r;
|
||||
|
||||
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
|
||||
_cleanup_close_ int fd;
|
||||
assert_se(write_tmpfile(name, env_file_5) == 0);
|
||||
|
||||
fd = mkostemp_safe(name);
|
||||
assert_se(fd >= 0);
|
||||
assert_se(write(fd, env_file_5, strlen(env_file_5)) == strlen(env_file_5));
|
||||
|
||||
r = load_env_file(NULL, name, &data);
|
||||
assert_se(r == 0);
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
assert_se(load_env_file(NULL, name, &data) == 0);
|
||||
assert_se(streq(data[0], "a="));
|
||||
assert_se(streq(data[1], "b="));
|
||||
assert_se(data[2] == NULL);
|
||||
}
|
||||
|
||||
TEST(load_env_file_6) {
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
int r;
|
||||
|
||||
_cleanup_(unlink_tempfilep) char name[] = "/tmp/test-load-env-file.XXXXXX";
|
||||
_cleanup_close_ int fd;
|
||||
assert_se(write_tmpfile(name, env_file_6) == 0);
|
||||
|
||||
fd = mkostemp_safe(name);
|
||||
assert_se(fd >= 0);
|
||||
assert_se(write(fd, env_file_6, strlen(env_file_6)) == strlen(env_file_6));
|
||||
|
||||
r = load_env_file(NULL, name, &data);
|
||||
assert_se(r == 0);
|
||||
_cleanup_strv_free_ char **data = NULL;
|
||||
assert_se(load_env_file(NULL, name, &data) == 0);
|
||||
assert_se(streq(data[0], "a= n t x y '"));
|
||||
assert_se(streq(data[1], "b=$'"));
|
||||
assert_se(streq(data[2], "c= \\n\\t\\$\\`\\\\\n"));
|
||||
|
@ -1117,7 +1117,7 @@ typedef struct test_entry {
|
||||
|
||||
#define entry(x) {x, #x}
|
||||
|
||||
static int run_tests(UnitFileScope scope, const test_entry tests[], char **patterns) {
|
||||
static int run_tests(LookupScope scope, const test_entry tests[], char **patterns) {
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
int r;
|
||||
|
||||
@ -1239,11 +1239,11 @@ int main(int argc, char *argv[]) {
|
||||
assert_se(unsetenv("VAR2") == 0);
|
||||
assert_se(unsetenv("VAR3") == 0);
|
||||
|
||||
r = run_tests(UNIT_FILE_USER, user_tests, argv + 1);
|
||||
r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1);
|
||||
r = run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
@ -1265,11 +1265,11 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
can_unshare = false;
|
||||
|
||||
r = run_tests(UNIT_FILE_USER, user_tests, argv + 1);
|
||||
r = run_tests(LOOKUP_SCOPE_USER, user_tests, argv + 1);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
return run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1);
|
||||
return run_tests(LOOKUP_SCOPE_SYSTEM, system_tests, argv + 1);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -109,8 +109,7 @@ TEST(parse_env_file) {
|
||||
"eleven", &eleven,
|
||||
"twelve", &twelve,
|
||||
"thirteen", &thirteen);
|
||||
|
||||
assert_se(r >= 0);
|
||||
assert_se(r == 0);
|
||||
|
||||
log_info("one=[%s]", strna(one));
|
||||
log_info("two=[%s]", strna(two));
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,13 +32,13 @@ int main(int argc, char* argv[]) {
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
h = hashmap_new(&string_hash_ops);
|
||||
r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
|
||||
r = unit_file_get_list(LOOKUP_SCOPE_SYSTEM, NULL, h, NULL, NULL);
|
||||
assert_se(r == 0);
|
||||
|
||||
HASHMAP_FOREACH(p, h) {
|
||||
UnitFileState s = _UNIT_FILE_STATE_INVALID;
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path), &s);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(p->path), &s);
|
||||
|
||||
assert_se((r < 0 && p->state == UNIT_FILE_BAD) ||
|
||||
(p->state == s));
|
||||
@ -52,18 +52,18 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
log_info("/*** enable **/");
|
||||
|
||||
r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
log_info("/*** enable2 **/");
|
||||
|
||||
r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_ENABLED);
|
||||
|
||||
@ -71,13 +71,13 @@ int main(int argc, char* argv[]) {
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_DISABLED);
|
||||
|
||||
@ -85,16 +85,16 @@ int main(int argc, char* argv[]) {
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
log_info("/*** mask2 ***/");
|
||||
r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_MASKED);
|
||||
|
||||
@ -102,16 +102,16 @@ int main(int argc, char* argv[]) {
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
log_info("/*** unmask2 ***/");
|
||||
r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_DISABLED);
|
||||
|
||||
@ -119,13 +119,13 @@ int main(int argc, char* argv[]) {
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
r = unit_file_mask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_MASKED);
|
||||
|
||||
@ -133,16 +133,16 @@ int main(int argc, char* argv[]) {
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
log_info("/*** disable2 ***/");
|
||||
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_MASKED);
|
||||
|
||||
@ -150,13 +150,13 @@ int main(int argc, char* argv[]) {
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
r = unit_file_unmask(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, files[0], &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_DISABLED);
|
||||
|
||||
@ -164,13 +164,13 @@ int main(int argc, char* argv[]) {
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
|
||||
r = unit_file_enable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_ENABLED);
|
||||
|
||||
@ -178,26 +178,26 @@ int main(int argc, char* argv[]) {
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
|
||||
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
assert_se(r < 0);
|
||||
|
||||
log_info("/*** link files2 ***/");
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
|
||||
r = unit_file_link(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_LINKED);
|
||||
|
||||
@ -205,26 +205,26 @@ int main(int argc, char* argv[]) {
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
|
||||
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
assert_se(r < 0);
|
||||
|
||||
log_info("/*** link files2 ***/");
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
|
||||
r = unit_file_link(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_LINKED);
|
||||
|
||||
@ -232,13 +232,13 @@ int main(int argc, char* argv[]) {
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_reenable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
|
||||
r = unit_file_reenable(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_ENABLED);
|
||||
|
||||
@ -246,25 +246,25 @@ int main(int argc, char* argv[]) {
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
|
||||
r = unit_file_disable(LOOKUP_SCOPE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files2[0]), &state);
|
||||
assert_se(r < 0);
|
||||
log_info("/*** preset files ***/");
|
||||
changes = NULL;
|
||||
n_changes = 0;
|
||||
|
||||
r = unit_file_preset(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, UNIT_FILE_PRESET_FULL, &changes, &n_changes);
|
||||
r = unit_file_preset(LOOKUP_SCOPE_SYSTEM, 0, NULL, (char**) files, UNIT_FILE_PRESET_FULL, &changes, &n_changes);
|
||||
assert_se(r >= 0);
|
||||
|
||||
dump_changes(changes, n_changes);
|
||||
unit_file_changes_free(changes, n_changes);
|
||||
|
||||
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0]), &state);
|
||||
r = unit_file_get_state(LOOKUP_SCOPE_SYSTEM, NULL, basename(files[0]), &state);
|
||||
assert_se(r >= 0);
|
||||
assert_se(state == UNIT_FILE_ENABLED);
|
||||
|
||||
|
@ -42,7 +42,7 @@ TEST_RET(unit_file_get_set) {
|
||||
h = hashmap_new(&string_hash_ops);
|
||||
assert_se(h);
|
||||
|
||||
r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
|
||||
r = unit_file_get_list(LOOKUP_SCOPE_SYSTEM, NULL, h, NULL, NULL);
|
||||
if (IN_SET(r, -EPERM, -EACCES))
|
||||
return log_tests_skipped_errno(r, "unit_file_get_list");
|
||||
|
||||
@ -101,7 +101,7 @@ TEST(config_parse_exec) {
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
_cleanup_(unit_freep) Unit *u = NULL;
|
||||
|
||||
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
if (manager_errno_skip_test(r)) {
|
||||
log_notice_errno(r, "Skipping test: manager_new: %m");
|
||||
return;
|
||||
@ -445,7 +445,7 @@ TEST(config_parse_log_extra_fields) {
|
||||
_cleanup_(unit_freep) Unit *u = NULL;
|
||||
ExecContext c = {};
|
||||
|
||||
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
if (manager_errno_skip_test(r)) {
|
||||
log_notice_errno(r, "Skipping test: manager_new: %m");
|
||||
return;
|
||||
@ -510,59 +510,74 @@ TEST(install_printf, .sd_booted = true) {
|
||||
assert_se(user = uid_to_name(getuid()));
|
||||
assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0);
|
||||
|
||||
#define expect(src, pattern, result) \
|
||||
#define expect(scope, src, pattern, result) \
|
||||
do { \
|
||||
_cleanup_free_ char *t = NULL; \
|
||||
_cleanup_free_ char \
|
||||
*d1 = strdup(i.name), \
|
||||
*d2 = strdup(i.path); \
|
||||
assert_se(install_name_printf(&src, pattern, NULL, &t) >= 0 || !result); \
|
||||
_cleanup_free_ char *t = NULL, \
|
||||
*d1 = ASSERT_PTR(strdup(i.name)), \
|
||||
*d2 = ASSERT_PTR(strdup(i.path)); \
|
||||
int r = install_name_printf(scope, &src, pattern, &t); \
|
||||
assert_se(result ? r >= 0 : r < 0); \
|
||||
memzero(i.name, strlen(i.name)); \
|
||||
memzero(i.path, strlen(i.path)); \
|
||||
assert_se(d1 && d2); \
|
||||
if (result) { \
|
||||
printf("%s\n", t); \
|
||||
assert_se(streq(t, result)); \
|
||||
} else assert_se(t == NULL); \
|
||||
} else \
|
||||
assert_se(!t); \
|
||||
strcpy(i.name, d1); \
|
||||
strcpy(i.path, d2); \
|
||||
} while (false)
|
||||
|
||||
expect(i, "%n", "name.service");
|
||||
expect(i, "%N", "name");
|
||||
expect(i, "%p", "name");
|
||||
expect(i, "%i", "");
|
||||
expect(i, "%j", "name");
|
||||
expect(i, "%g", group);
|
||||
expect(i, "%G", gid);
|
||||
expect(i, "%u", user);
|
||||
expect(i, "%U", uid);
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%n", "name.service");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%N", "name");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%p", "name");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%i", "");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%j", "name");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%g", "root");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%G", "0");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%u", "root");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%U", "0");
|
||||
|
||||
expect(i, "%m", mid);
|
||||
expect(i, "%b", bid);
|
||||
expect(i, "%H", host);
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%m", mid);
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%b", bid);
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i, "%H", host);
|
||||
|
||||
expect(i2, "%g", group);
|
||||
expect(i2, "%G", gid);
|
||||
expect(i2, "%u", user);
|
||||
expect(i2, "%U", uid);
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i2, "%g", "root");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i2, "%G", "0");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i2, "%u", "root");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i2, "%U", "0");
|
||||
|
||||
expect(i3, "%n", "name@inst.service");
|
||||
expect(i3, "%N", "name@inst");
|
||||
expect(i3, "%p", "name");
|
||||
expect(i3, "%g", group);
|
||||
expect(i3, "%G", gid);
|
||||
expect(i3, "%u", user);
|
||||
expect(i3, "%U", uid);
|
||||
expect(LOOKUP_SCOPE_USER, i2, "%g", group);
|
||||
expect(LOOKUP_SCOPE_USER, i2, "%G", gid);
|
||||
expect(LOOKUP_SCOPE_USER, i2, "%u", user);
|
||||
expect(LOOKUP_SCOPE_USER, i2, "%U", uid);
|
||||
|
||||
expect(i3, "%m", mid);
|
||||
expect(i3, "%b", bid);
|
||||
expect(i3, "%H", host);
|
||||
/* gcc-12.0.1-0.9.fc36.x86_64 insist that streq(…, NULL) is called,
|
||||
* even though the call is inside of a conditional where the pointer is checked. :( */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wnonnull"
|
||||
expect(LOOKUP_SCOPE_GLOBAL, i2, "%g", NULL);
|
||||
expect(LOOKUP_SCOPE_GLOBAL, i2, "%G", NULL);
|
||||
expect(LOOKUP_SCOPE_GLOBAL, i2, "%u", NULL);
|
||||
expect(LOOKUP_SCOPE_GLOBAL, i2, "%U", NULL);
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
expect(i4, "%g", group);
|
||||
expect(i4, "%G", gid);
|
||||
expect(i4, "%u", user);
|
||||
expect(i4, "%U", uid);
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i3, "%n", "name@inst.service");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i3, "%N", "name@inst");
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i3, "%p", "name");
|
||||
expect(LOOKUP_SCOPE_USER, i3, "%g", group);
|
||||
expect(LOOKUP_SCOPE_USER, i3, "%G", gid);
|
||||
expect(LOOKUP_SCOPE_USER, i3, "%u", user);
|
||||
expect(LOOKUP_SCOPE_USER, i3, "%U", uid);
|
||||
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i3, "%m", mid);
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i3, "%b", bid);
|
||||
expect(LOOKUP_SCOPE_SYSTEM, i3, "%H", host);
|
||||
|
||||
expect(LOOKUP_SCOPE_USER, i4, "%g", group);
|
||||
expect(LOOKUP_SCOPE_USER, i4, "%G", gid);
|
||||
expect(LOOKUP_SCOPE_USER, i4, "%u", user);
|
||||
expect(LOOKUP_SCOPE_USER, i4, "%U", uid);
|
||||
}
|
||||
|
||||
static uint64_t make_cap(int cap) {
|
||||
@ -791,7 +806,7 @@ TEST(config_parse_unit_env_file) {
|
||||
_cleanup_strv_free_ char **files = NULL;
|
||||
int r;
|
||||
|
||||
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
if (manager_errno_skip_test(r)) {
|
||||
log_notice_errno(r, "Skipping test: manager_new: %m");
|
||||
return;
|
||||
@ -924,7 +939,7 @@ TEST(unit_is_recursive_template_dependency) {
|
||||
Unit *u;
|
||||
int r;
|
||||
|
||||
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
if (manager_errno_skip_test(r)) {
|
||||
log_notice_errno(r, "Skipping test: manager_new: %m");
|
||||
return;
|
||||
|
@ -2,8 +2,11 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "fs-util.h"
|
||||
#include "log.h"
|
||||
#include "os-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tests.h"
|
||||
|
||||
TEST(path_is_os_tree) {
|
||||
@ -12,4 +15,61 @@ TEST(path_is_os_tree) {
|
||||
assert_se(path_is_os_tree("/idontexist") == -ENOENT);
|
||||
}
|
||||
|
||||
TEST(parse_os_release) {
|
||||
/* Let's assume that we're running in a valid system, so os-release is available */
|
||||
_cleanup_free_ char *id = NULL, *id2 = NULL, *name = NULL, *foobar = NULL;
|
||||
assert_se(parse_os_release(NULL, "ID", &id) == 0);
|
||||
log_info("ID: %s", id);
|
||||
|
||||
assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0);
|
||||
assert_se(parse_os_release(NULL, "ID", &id2) == 0);
|
||||
log_info("ID: %s", strnull(id2));
|
||||
|
||||
_cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX";
|
||||
assert_se(write_tmpfile(tmpfile,
|
||||
"ID=the-id \n"
|
||||
"NAME=the-name") == 0);
|
||||
|
||||
assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0);
|
||||
assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0);
|
||||
log_info("ID: %s NAME: %s", id, name);
|
||||
assert_se(streq(id, "the-id"));
|
||||
assert_se(streq(name, "the-name"));
|
||||
|
||||
_cleanup_(unlink_tempfilep) char tmpfile2[] = "/tmp/test-os-util.XXXXXX";
|
||||
assert_se(write_tmpfile(tmpfile2,
|
||||
"ID=\"ignored\" \n"
|
||||
"ID=\"the-id\" \n"
|
||||
"NAME='the-name'") == 0);
|
||||
|
||||
assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile2, 1) == 0);
|
||||
assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0);
|
||||
log_info("ID: %s NAME: %s", id, name);
|
||||
assert_se(streq(id, "the-id"));
|
||||
assert_se(streq(name, "the-name"));
|
||||
|
||||
assert_se(parse_os_release(NULL, "FOOBAR", &foobar) == 0);
|
||||
log_info("FOOBAR: %s", strnull(foobar));
|
||||
assert_se(foobar == NULL);
|
||||
|
||||
assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
|
||||
}
|
||||
|
||||
TEST(load_os_release_pairs) {
|
||||
_cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX";
|
||||
assert_se(write_tmpfile(tmpfile,
|
||||
"ID=\"ignored\" \n"
|
||||
"ID=\"the-id\" \n"
|
||||
"NAME='the-name'") == 0);
|
||||
|
||||
assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0);
|
||||
|
||||
_cleanup_strv_free_ char **pairs = NULL;
|
||||
assert_se(load_os_release_pairs(NULL, &pairs) == 0);
|
||||
assert_se(strv_equal(pairs, STRV_MAKE("ID", "the-id",
|
||||
"NAME", "the-name")));
|
||||
|
||||
assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "tests.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
static void test_paths_one(UnitFileScope scope) {
|
||||
static void test_paths_one(LookupScope scope) {
|
||||
_cleanup_(rm_rf_physical_and_freep) char *tmp = NULL;
|
||||
_cleanup_(lookup_paths_free) LookupPaths lp_without_env = {};
|
||||
_cleanup_(lookup_paths_free) LookupPaths lp_with_env = {};
|
||||
@ -34,9 +34,9 @@ static void test_paths_one(UnitFileScope scope) {
|
||||
}
|
||||
|
||||
TEST(paths) {
|
||||
test_paths_one(UNIT_FILE_SYSTEM);
|
||||
test_paths_one(UNIT_FILE_USER);
|
||||
test_paths_one(UNIT_FILE_GLOBAL);
|
||||
test_paths_one(LOOKUP_SCOPE_SYSTEM);
|
||||
test_paths_one(LOOKUP_SCOPE_USER);
|
||||
test_paths_one(LOOKUP_SCOPE_GLOBAL);
|
||||
}
|
||||
|
||||
TEST(user_and_global_paths) {
|
||||
@ -48,8 +48,8 @@ TEST(user_and_global_paths) {
|
||||
assert_se(unsetenv("XDG_DATA_DIRS") == 0);
|
||||
assert_se(unsetenv("XDG_CONFIG_DIRS") == 0);
|
||||
|
||||
assert_se(lookup_paths_init(&lp_global, UNIT_FILE_GLOBAL, 0, NULL) == 0);
|
||||
assert_se(lookup_paths_init(&lp_user, UNIT_FILE_USER, 0, NULL) == 0);
|
||||
assert_se(lookup_paths_init(&lp_global, LOOKUP_SCOPE_GLOBAL, 0, NULL) == 0);
|
||||
assert_se(lookup_paths_init(&lp_user, LOOKUP_SCOPE_USER, 0, NULL) == 0);
|
||||
g = lp_global.search_path;
|
||||
u = lp_user.search_path;
|
||||
|
||||
@ -70,7 +70,7 @@ TEST(user_and_global_paths) {
|
||||
log_info("+ %s", *p);
|
||||
}
|
||||
|
||||
static void test_generator_binary_paths_one(UnitFileScope scope) {
|
||||
static void test_generator_binary_paths_one(LookupScope scope) {
|
||||
_cleanup_(rm_rf_physical_and_freep) char *tmp = NULL;
|
||||
_cleanup_strv_free_ char **gp_without_env = NULL;
|
||||
_cleanup_strv_free_ char **env_gp_without_env = NULL;
|
||||
@ -85,13 +85,13 @@ static void test_generator_binary_paths_one(UnitFileScope scope) {
|
||||
assert_se(unsetenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH") == 0);
|
||||
|
||||
gp_without_env = generator_binary_paths(scope);
|
||||
env_gp_without_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false);
|
||||
env_gp_without_env = env_generator_binary_paths(scope == LOOKUP_SCOPE_SYSTEM ? true : false);
|
||||
|
||||
log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
|
||||
log_info("Generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user");
|
||||
STRV_FOREACH(dir, gp_without_env)
|
||||
log_info(" %s", *dir);
|
||||
|
||||
log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
|
||||
log_info("Environment generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user");
|
||||
STRV_FOREACH(dir, env_gp_without_env)
|
||||
log_info(" %s", *dir);
|
||||
|
||||
@ -104,13 +104,13 @@ static void test_generator_binary_paths_one(UnitFileScope scope) {
|
||||
assert_se(setenv("SYSTEMD_ENVIRONMENT_GENERATOR_PATH", systemd_env_generator_path, 1) == 0);
|
||||
|
||||
gp_with_env = generator_binary_paths(scope);
|
||||
env_gp_with_env = env_generator_binary_paths(scope == UNIT_FILE_SYSTEM ? true : false);
|
||||
env_gp_with_env = env_generator_binary_paths(scope == LOOKUP_SCOPE_SYSTEM ? true : false);
|
||||
|
||||
log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
|
||||
log_info("Generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user");
|
||||
STRV_FOREACH(dir, gp_with_env)
|
||||
log_info(" %s", *dir);
|
||||
|
||||
log_info("Environment generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
|
||||
log_info("Environment generators dirs (%s):", scope == LOOKUP_SCOPE_SYSTEM ? "system" : "user");
|
||||
STRV_FOREACH(dir, env_gp_with_env)
|
||||
log_info(" %s", *dir);
|
||||
|
||||
@ -119,8 +119,8 @@ static void test_generator_binary_paths_one(UnitFileScope scope) {
|
||||
}
|
||||
|
||||
TEST(generator_binary_paths) {
|
||||
test_generator_binary_paths_one(UNIT_FILE_SYSTEM);
|
||||
test_generator_binary_paths_one(UNIT_FILE_USER);
|
||||
test_generator_binary_paths_one(LOOKUP_SCOPE_SYSTEM);
|
||||
test_generator_binary_paths_one(LOOKUP_SCOPE_USER);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
@ -33,7 +33,7 @@ static int setup_test(Manager **m) {
|
||||
if (r == -ENOMEDIUM)
|
||||
return log_tests_skipped("cgroupfs not available");
|
||||
|
||||
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &tmp);
|
||||
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &tmp);
|
||||
if (manager_errno_skip_test(r))
|
||||
return log_tests_skipped_errno(r, "manager_new");
|
||||
assert_se(r >= 0);
|
||||
|
@ -30,7 +30,7 @@ int main(int argc, char *argv[]) {
|
||||
assert_se(set_unit_path(unit_dir) >= 0);
|
||||
assert_se(runtime_dir = setup_fake_runtime_dir());
|
||||
|
||||
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
|
||||
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m);
|
||||
if (manager_errno_skip_test(r))
|
||||
return log_tests_skipped_errno(r, "manager_new");
|
||||
assert_se(r >= 0);
|
||||
|
@ -135,7 +135,7 @@ int main(int argc, char *argv[]) {
|
||||
assert_se(set_unit_path(unit_dir) >= 0);
|
||||
assert_se(runtime_dir = setup_fake_runtime_dir());
|
||||
|
||||
assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
|
||||
assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
|
||||
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
|
||||
|
||||
assert_se(test_socket_bind(m, "socket_bind_test.service", netcat_path, "2000", STRV_MAKE("2000"), STRV_MAKE("any")) >= 0);
|
||||
|
@ -228,17 +228,12 @@ TEST(passfd_read) {
|
||||
|
||||
if (r == 0) {
|
||||
/* Child */
|
||||
char tmpfile[] = "/tmp/test-socket-util-passfd-read-XXXXXX";
|
||||
_cleanup_close_ int tmpfd = -1;
|
||||
|
||||
pair[0] = safe_close(pair[0]);
|
||||
|
||||
tmpfd = mkostemp_safe(tmpfile);
|
||||
assert_se(tmpfd >= 0);
|
||||
assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents));
|
||||
tmpfd = safe_close(tmpfd);
|
||||
char tmpfile[] = "/tmp/test-socket-util-passfd-read-XXXXXX";
|
||||
assert_se(write_tmpfile(tmpfile, file_contents) == 0);
|
||||
|
||||
tmpfd = open(tmpfile, O_RDONLY);
|
||||
_cleanup_close_ int tmpfd = open(tmpfile, O_RDONLY);
|
||||
assert_se(tmpfd >= 0);
|
||||
assert_se(unlink(tmpfile) == 0);
|
||||
|
||||
@ -277,16 +272,12 @@ TEST(passfd_contents_read) {
|
||||
/* Child */
|
||||
struct iovec iov = IOVEC_INIT_STRING(wire_contents);
|
||||
char tmpfile[] = "/tmp/test-socket-util-passfd-contents-read-XXXXXX";
|
||||
_cleanup_close_ int tmpfd = -1;
|
||||
|
||||
pair[0] = safe_close(pair[0]);
|
||||
|
||||
tmpfd = mkostemp_safe(tmpfile);
|
||||
assert_se(tmpfd >= 0);
|
||||
assert_se(write(tmpfd, file_contents, strlen(file_contents)) == (ssize_t) strlen(file_contents));
|
||||
tmpfd = safe_close(tmpfd);
|
||||
assert_se(write_tmpfile(tmpfile, file_contents) == 0);
|
||||
|
||||
tmpfd = open(tmpfile, O_RDONLY);
|
||||
_cleanup_close_ int tmpfd = open(tmpfile, O_RDONLY);
|
||||
assert_se(tmpfd >= 0);
|
||||
assert_se(unlink(tmpfile) == 0);
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tests.h"
|
||||
#include "unit-file.h"
|
||||
|
||||
static void test_specifier_escape_one(const char *a, const char *b) {
|
||||
_cleanup_free_ char *x = NULL;
|
||||
@ -46,7 +47,7 @@ TEST(specifier_escape_strv) {
|
||||
static const Specifier specifier_table[] = {
|
||||
COMMON_SYSTEM_SPECIFIERS,
|
||||
|
||||
COMMON_CREDS_SPECIFIERS,
|
||||
COMMON_CREDS_SPECIFIERS(LOOKUP_SCOPE_USER),
|
||||
{ 'h', specifier_user_home, NULL },
|
||||
|
||||
COMMON_TMP_SPECIFIERS,
|
||||
@ -138,4 +139,18 @@ TEST(specifiers) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(specifiers_missing_data_ok) {
|
||||
_cleanup_free_ char *resolved = NULL;
|
||||
|
||||
assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0);
|
||||
assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) >= 0);
|
||||
assert_se(streq(resolved, "-----"));
|
||||
|
||||
assert_se(setenv("SYSTEMD_OS_RELEASE", "/nosuchfileordirectory", 1) == 0);
|
||||
assert_se(specifier_printf("%A-%B-%M-%o-%w-%W", SIZE_MAX, specifier_table, NULL, NULL, &resolved) == -EUNATCH);
|
||||
assert_se(streq(resolved, "-----"));
|
||||
|
||||
assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
@ -18,6 +18,30 @@
|
||||
#include "tests.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
TEST(null_or_empty_path) {
|
||||
assert_se(null_or_empty_path("/dev/null") == 1);
|
||||
assert_se(null_or_empty_path("/dev/tty") == 1); /* We assume that any character device is "empty", bleh. */
|
||||
assert_se(null_or_empty_path("../../../../../../../../../../../../../../../../../../../../dev/null") == 1);
|
||||
assert_se(null_or_empty_path("/proc/self/exe") == 0);
|
||||
assert_se(null_or_empty_path("/nosuchfileordir") == -ENOENT);
|
||||
}
|
||||
|
||||
TEST(null_or_empty_path_with_root) {
|
||||
assert_se(null_or_empty_path_with_root("/dev/null", NULL) == 1);
|
||||
assert_se(null_or_empty_path_with_root("/dev/null", "/") == 1);
|
||||
assert_se(null_or_empty_path_with_root("/dev/null", "/.././../") == 1);
|
||||
assert_se(null_or_empty_path_with_root("/dev/null", "/.././..") == 1);
|
||||
assert_se(null_or_empty_path_with_root("../../../../../../../../../../../../../../../../../../../../dev/null", NULL) == 1);
|
||||
assert_se(null_or_empty_path_with_root("../../../../../../../../../../../../../../../../../../../../dev/null", "/") == 1);
|
||||
assert_se(null_or_empty_path_with_root("/proc/self/exe", NULL) == 0);
|
||||
assert_se(null_or_empty_path_with_root("/proc/self/exe", "/") == 0);
|
||||
assert_se(null_or_empty_path_with_root("/nosuchfileordir", NULL) == -ENOENT);
|
||||
assert_se(null_or_empty_path_with_root("/nosuchfileordir", "/.././../") == -ENOENT);
|
||||
assert_se(null_or_empty_path_with_root("/nosuchfileordir", "/.././..") == -ENOENT);
|
||||
assert_se(null_or_empty_path_with_root("/foobar/barbar/dev/null", "/foobar/barbar") == 1);
|
||||
assert_se(null_or_empty_path_with_root("/foobar/barbar/dev/null", "/foobar/barbar/") == 1);
|
||||
}
|
||||
|
||||
TEST(files_same) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
char name[] = "/tmp/test-files_same.XXXXXX";
|
||||
|
@ -8,20 +8,20 @@
|
||||
#include "unit-file.h"
|
||||
|
||||
TEST(unit_validate_alias_symlink_and_warn) {
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.service") == 0);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.socket") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b.foobar") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.service") == 0);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@.socket") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.service") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@YYY.socket") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b@YYY.service") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@XXX.service") == 0);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a@XXX.service", "/other/b@.service") == 0);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a@.service", "/other/b.service") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a.service", "/other/b@.service") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a@.slice", "/other/b.slice") == -EINVAL);
|
||||
assert_se(unit_validate_alias_symlink_and_warn("/path/a.slice", "/other/b.slice") == -EINVAL);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.service") == 0);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.socket") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b.foobar") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@.service") == 0);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@.socket") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@YYY.service") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@YYY.socket") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b@YYY.service") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@XXX.service") == 0);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@XXX.service", "/other/b@.service") == 0);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.service", "/other/b.service") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.service", "/other/b@.service") == -EXDEV);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a@.slice", "/other/b.slice") == -EINVAL);
|
||||
assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO, "/path/a.slice", "/other/b.slice") == -EINVAL);
|
||||
}
|
||||
|
||||
TEST(unit_file_build_name_map) {
|
||||
@ -35,7 +35,7 @@ TEST(unit_file_build_name_map) {
|
||||
|
||||
ids = strv_skip(saved_argv, 1);
|
||||
|
||||
assert_se(lookup_paths_init(&lp, UNIT_FILE_SYSTEM, 0, NULL) >= 0);
|
||||
assert_se(lookup_paths_init(&lp, LOOKUP_SCOPE_SYSTEM, 0, NULL) >= 0);
|
||||
|
||||
assert_se(unit_file_build_name_map(&lp, &mtime, &unit_ids, &unit_names, NULL) == 1);
|
||||
|
||||
|
@ -228,7 +228,7 @@ TEST_RET(unit_printf, .sd_booted = true) {
|
||||
assert_se(get_home_dir(&home) >= 0);
|
||||
assert_se(get_shell(&shell) >= 0);
|
||||
|
||||
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
if (manager_errno_skip_test(r))
|
||||
return log_tests_skipped_errno(r, "manager_new");
|
||||
assert_se(r == 0);
|
||||
|
@ -31,7 +31,7 @@ TEST(deserialize_exec_command) {
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
int r;
|
||||
|
||||
r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
r = manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
|
||||
if (manager_errno_skip_test(r)) {
|
||||
log_notice_errno(r, "Skipping test: manager_new: %m");
|
||||
return;
|
||||
|
@ -26,7 +26,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
assert_se(runtime_dir = setup_fake_runtime_dir());
|
||||
|
||||
assert_se(manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
|
||||
assert_se(manager_new(LOOKUP_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m) >= 0);
|
||||
assert_se(manager_startup(m, NULL, NULL, NULL) >= 0);
|
||||
|
||||
assert_se(a = unit_new(m, sizeof(Service)));
|
||||
|
@ -204,31 +204,6 @@ STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
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 },
|
||||
{ 'b', specifier_boot_id, NULL },
|
||||
{ 'B', specifier_os_build_id, NULL },
|
||||
{ 'H', specifier_host_name, NULL },
|
||||
{ 'l', specifier_short_host_name, NULL },
|
||||
{ 'm', specifier_machine_id_safe, NULL },
|
||||
{ 'o', specifier_os_id, NULL },
|
||||
{ 'v', specifier_kernel_release, NULL },
|
||||
{ 'w', specifier_os_version_id, NULL },
|
||||
{ 'W', specifier_os_variant_id, NULL },
|
||||
|
||||
{ 'h', specifier_user_home, NULL },
|
||||
|
||||
{ 'C', specifier_directory, UINT_TO_PTR(DIRECTORY_CACHE) },
|
||||
{ 'L', specifier_directory, UINT_TO_PTR(DIRECTORY_LOGS) },
|
||||
{ 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) },
|
||||
{ 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) },
|
||||
|
||||
COMMON_CREDS_SPECIFIERS,
|
||||
|
||||
COMMON_TMP_SPECIFIERS,
|
||||
{}
|
||||
};
|
||||
|
||||
static int specifier_machine_id_safe(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
int r;
|
||||
|
||||
@ -2737,7 +2712,7 @@ static bool should_include_path(const char *path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static int specifier_expansion_from_arg(Item *i) {
|
||||
static int specifier_expansion_from_arg(const Specifier *specifier_table, Item *i) {
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
@ -2944,6 +2919,30 @@ static int parse_line(
|
||||
assert(line >= 1);
|
||||
assert(buffer);
|
||||
|
||||
const Specifier specifier_table[] = {
|
||||
{ 'a', specifier_architecture, NULL },
|
||||
{ 'b', specifier_boot_id, NULL },
|
||||
{ 'B', specifier_os_build_id, NULL },
|
||||
{ 'H', specifier_host_name, NULL },
|
||||
{ 'l', specifier_short_host_name, NULL },
|
||||
{ 'm', specifier_machine_id_safe, NULL },
|
||||
{ 'o', specifier_os_id, NULL },
|
||||
{ 'v', specifier_kernel_release, NULL },
|
||||
{ 'w', specifier_os_version_id, NULL },
|
||||
{ 'W', specifier_os_variant_id, NULL },
|
||||
|
||||
{ 'h', specifier_user_home, NULL },
|
||||
|
||||
{ 'C', specifier_directory, UINT_TO_PTR(DIRECTORY_CACHE) },
|
||||
{ 'L', specifier_directory, UINT_TO_PTR(DIRECTORY_LOGS) },
|
||||
{ 'S', specifier_directory, UINT_TO_PTR(DIRECTORY_STATE) },
|
||||
{ 't', specifier_directory, UINT_TO_PTR(DIRECTORY_RUNTIME) },
|
||||
|
||||
COMMON_CREDS_SPECIFIERS(arg_user ? LOOKUP_SCOPE_USER : LOOKUP_SCOPE_SYSTEM),
|
||||
COMMON_TMP_SPECIFIERS,
|
||||
{}
|
||||
};
|
||||
|
||||
r = extract_many_words(
|
||||
&buffer,
|
||||
NULL,
|
||||
@ -3148,7 +3147,7 @@ static int parse_line(
|
||||
if (!should_include_path(i.path))
|
||||
return 0;
|
||||
|
||||
r = specifier_expansion_from_arg(&i);
|
||||
r = specifier_expansion_from_arg(specifier_table, &i);
|
||||
if (r == -ENXIO)
|
||||
return log_unresolvable_specifier(fname, line);
|
||||
if (r < 0) {
|
||||
|
@ -88,6 +88,7 @@ endif
|
||||
|
||||
test_fstab_generator_sh = find_program('test-fstab-generator.sh')
|
||||
test_network_generator_conversion_sh = find_program('test-network-generator-conversion.sh')
|
||||
test_systemctl_enable_sh = find_program('test-systemctl-enable.sh')
|
||||
test_systemd_tmpfiles_py = find_program('test-systemd-tmpfiles.py')
|
||||
hwdb_test_sh = find_program('hwdb-test.sh')
|
||||
|
||||
|
693
test/test-systemctl-enable.sh
Normal file
693
test/test-systemctl-enable.sh
Normal file
@ -0,0 +1,693 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
set -ex
|
||||
|
||||
# Silence warning from running_in_chroot_or_offline()
|
||||
export SYSTEMD_IGNORE_CHROOT=1
|
||||
|
||||
systemctl=${1:-systemctl}
|
||||
systemd_id128=${2:-systemd-id128}
|
||||
|
||||
unset root
|
||||
cleanup() {
|
||||
[ -n "$root" ] && rm -rf "$root"
|
||||
}
|
||||
trap cleanup exit
|
||||
root=$(mktemp -d --tmpdir systemctl-test.XXXXXX)
|
||||
|
||||
islink() {
|
||||
test -h "$1" || return 1
|
||||
test "$(readlink "$1")" = "$2" || return 2
|
||||
}
|
||||
|
||||
: '------enable nonexistent------------------------------------'
|
||||
( ! "$systemctl" --root="$root" enable test1.service )
|
||||
|
||||
: '------basic enablement--------------------------------------'
|
||||
mkdir -p "$root/etc/systemd/system"
|
||||
cat >"$root/etc/systemd/system/test1.service" <<EOF
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
RequiredBy=special.target
|
||||
EOF
|
||||
|
||||
"$systemctl" --root="$root" enable test1.service
|
||||
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
|
||||
"$systemctl" --root="$root" reenable test1.service
|
||||
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
|
||||
"$systemctl" --root="$root" disable test1.service
|
||||
test ! -h "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
test ! -h "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
|
||||
: '------enable when link already exists-----------------------'
|
||||
# We don't read the symlink target, so it's OK for the symlink to point
|
||||
# to something else. We should just silently accept this.
|
||||
|
||||
mkdir -p "$root/etc/systemd/system/default.target.wants"
|
||||
mkdir -p "$root/etc/systemd/system/special.target.requires"
|
||||
ln -s /usr/lib/systemd/system/test1.service "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
ln -s /usr/lib/systemd/system/test1.service "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
|
||||
"$systemctl" --root="$root" enable test1.service
|
||||
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
|
||||
"$systemctl" --root="$root" reenable test1.service
|
||||
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
|
||||
"$systemctl" --root="$root" disable test1.service
|
||||
test ! -h "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
test ! -h "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
|
||||
: '------suffix guessing---------------------------------------'
|
||||
"$systemctl" --root="$root" enable test1
|
||||
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
|
||||
"$systemctl" --root="$root" reenable test1
|
||||
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
|
||||
"$systemctl" --root="$root" disable test1
|
||||
test ! -e "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
test ! -e "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
|
||||
: '-------aliases----------------------------------------------'
|
||||
cat >>"$root/etc/systemd/system/test1.service" <<EOF
|
||||
Alias=test1-goodalias.service
|
||||
Alias=test1@badalias.service
|
||||
Alias=test1-badalias.target
|
||||
Alias=test1-badalias.socket
|
||||
# we have a series of good, bad, and then good again
|
||||
Alias=test1-goodalias2.service
|
||||
EOF
|
||||
|
||||
( ! "$systemctl" --root="$root" enable test1 )
|
||||
test -h "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
test -h "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
test -e "$root/etc/systemd/system/test1-goodalias.service"
|
||||
test -h "$root/etc/systemd/system/test1-goodalias.service"
|
||||
test ! -h "$root/etc/systemd/system/test1@badalias.service"
|
||||
test ! -h "$root/etc/systemd/system/test1-badalias.target"
|
||||
test ! -h "$root/etc/systemd/system/test1-badalias.socket"
|
||||
test -e "$root/etc/systemd/system/test1-goodalias2.service"
|
||||
test -h "$root/etc/systemd/system/test1-goodalias2.service"
|
||||
|
||||
: '-------aliases in reeanble----------------------------------'
|
||||
( ! "$systemctl" --root="$root" reenable test1 )
|
||||
islink "$root/etc/systemd/system/default.target.wants/test1.service" "../test1.service"
|
||||
islink "$root/etc/systemd/system/test1-goodalias.service" "test1.service"
|
||||
|
||||
test ! -h "$root/etc/systemd/system/test1@badalias.service"
|
||||
test ! -h "$root/etc/systemd/system/test1-badalias.target"
|
||||
test ! -h "$root/etc/systemd/system/test1-badalias.socket"
|
||||
|
||||
"$systemctl" --root="$root" disable test1
|
||||
test ! -h "$root/etc/systemd/system/default.target.wants/test1.service"
|
||||
test ! -h "$root/etc/systemd/system/special.target.requires/test1.service"
|
||||
test ! -h "$root/etc/systemd/system/test1-goodalias.service"
|
||||
|
||||
: '-------aliases when link already exists---------------------'
|
||||
cat >"$root/etc/systemd/system/test1a.service" <<EOF
|
||||
[Install]
|
||||
Alias=test1a-alias.service
|
||||
EOF
|
||||
|
||||
ln -s /usr/lib/systemd/system/test1a.service "$root/etc/systemd/system/test1a-alias.service"
|
||||
|
||||
"$systemctl" --root="$root" enable test1a.service
|
||||
test -h "$root/etc/systemd/system/test1a-alias.service"
|
||||
|
||||
"$systemctl" --root="$root" disable test1a.service
|
||||
test ! -h "$root/etc/systemd/system/test1a-alias.service"
|
||||
|
||||
: '-------also units-------------------------------------------'
|
||||
cat >"$root/etc/systemd/system/test2.socket" <<EOF
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
Also=test2.service
|
||||
EOF
|
||||
|
||||
cat >"$root/etc/systemd/system/test2.service" <<EOF
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
Also=test2.socket
|
||||
EOF
|
||||
|
||||
"$systemctl" --root="$root" reenable test2.service
|
||||
test -h "$root/etc/systemd/system/default.target.wants/test2.service"
|
||||
test -h "$root/etc/systemd/system/sockets.target.wants/test2.socket"
|
||||
|
||||
"$systemctl" --root="$root" reenable test2.socket
|
||||
test -h "$root/etc/systemd/system/default.target.wants/test2.service"
|
||||
test -h "$root/etc/systemd/system/sockets.target.wants/test2.socket"
|
||||
|
||||
"$systemctl" --root="$root" disable test2.socket
|
||||
test ! -e "$root/etc/systemd/system/default.target.wants/test2.service"
|
||||
test ! -e "$root/etc/systemd/system/sockets.target.wants/test2.socket"
|
||||
|
||||
|
||||
: '-------link-------------------------------------------------'
|
||||
# File doesn't exist yet
|
||||
test ! -e "$root/link1.path"
|
||||
( ! "$systemctl" --root="$root" link '/link1.path' )
|
||||
test ! -e "$root/etc/systemd/system/link1.path"
|
||||
|
||||
cat >"$root/link1.path" <<EOF
|
||||
[Install]
|
||||
WantedBy=paths.target
|
||||
EOF
|
||||
|
||||
"$systemctl" --root="$root" link '/link1.path'
|
||||
islink "$root/etc/systemd/system/link1.path" "/link1.path"
|
||||
|
||||
: '-------link already linked same path------------------------'
|
||||
SYSTEMD_LOG_LEVEL=debug "$systemctl" --root="$root" link '/link1.path' # this passes
|
||||
islink "$root/etc/systemd/system/link1.path" "/link1.path"
|
||||
|
||||
: '-------link already linked different path-------------------'
|
||||
mkdir "$root/subdir"
|
||||
cp "$root/link1.path" "$root/subdir/"
|
||||
( ! "$systemctl" --root="$root" link '/subdir/link1.path' )
|
||||
islink "$root/etc/systemd/system/link1.path" "/link1.path"
|
||||
|
||||
: '-------link bad suffix--------------------------------------'
|
||||
cp "$root/link1.path" "$root/subdir/link1.suffix"
|
||||
( ! "$systemctl" --root="$root" link '/subdir/link1.suffix' )
|
||||
test ! -e "$root/etc/systemd/system/link1.suffix"
|
||||
|
||||
: '-------unlink by unit name----------------------------------'
|
||||
"$systemctl" --root="$root" disable 'link1.path'
|
||||
test ! -e "$root/etc/systemd/system/link1.path"
|
||||
|
||||
: '-------unlink by path---------------------------------------'
|
||||
"$systemctl" --root="$root" link '/link1.path'
|
||||
test -h "$root/etc/systemd/system/link1.path"
|
||||
"$systemctl" --root="$root" disable '/link1.path'
|
||||
test ! -e "$root/etc/systemd/system/link1.path"
|
||||
|
||||
: '-------unlink by wrong path---------------------------------'
|
||||
"$systemctl" --root="$root" link '/link1.path'
|
||||
test -h "$root/etc/systemd/system/link1.path"
|
||||
"$systemctl" --root="$root" disable '/subdir/link1.path' # we only care about the name
|
||||
test ! -e "$root/etc/systemd/system/link1.path"
|
||||
|
||||
|
||||
: '-------link and enable--------------------------------------'
|
||||
"$systemctl" --root="$root" enable '/link1.path'
|
||||
islink "$root/etc/systemd/system/link1.path" "/link1.path"
|
||||
islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
|
||||
|
||||
: '-------enable already linked same path----------------------'
|
||||
"$systemctl" --root="$root" enable '/link1.path'
|
||||
islink "$root/etc/systemd/system/link1.path" "/link1.path"
|
||||
islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
|
||||
|
||||
: '-------enable already linked different path-----------------'
|
||||
( ! "$systemctl" --root="$root" enable '/subdir/link1.path' )
|
||||
islink "$root/etc/systemd/system/link1.path" "/link1.path"
|
||||
islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
|
||||
|
||||
: '-------enable bad suffix------------------------------------'
|
||||
cp "$root/link1.path" "$root/subdir/link1.suffix"
|
||||
( ! "$systemctl" --root="$root" enable '/subdir/link1.suffix' )
|
||||
test ! -e "$root/etc/systemd/system/link1.suffix"
|
||||
test ! -e "$root/etc/systemd/system/paths.target.wants/link1.suffix"
|
||||
|
||||
: '-------disable by unit name---------------------------------'
|
||||
"$systemctl" --root="$root" disable 'link1.path'
|
||||
test ! -e "$root/etc/systemd/system/link1.path"
|
||||
test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path"
|
||||
|
||||
: '-------disable by path--------------------------------------'
|
||||
"$systemctl" --root="$root" enable '/link1.path'
|
||||
test -h "$root/etc/systemd/system/link1.path"
|
||||
test -h "$root/etc/systemd/system/paths.target.wants/link1.path"
|
||||
"$systemctl" --root="$root" disable '/link1.path'
|
||||
test ! -e "$root/etc/systemd/system/link1.path"
|
||||
test ! -e "$root/etc/systemd/system/paths.target.wants/link1.path"
|
||||
|
||||
|
||||
: '-------link and enable-------------------------------------'
|
||||
"$systemctl" --root="$root" link '/link1.path'
|
||||
islink "$root/etc/systemd/system/link1.path" "/link1.path"
|
||||
test ! -h "$root/etc/systemd/system/paths.target.wants/link1.path"
|
||||
|
||||
"$systemctl" --root="$root" enable 'link1.path'
|
||||
islink "$root/etc/systemd/system/link1.path" "/link1.path"
|
||||
islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
|
||||
|
||||
"$systemctl" --root="$root" reenable 'link1.path'
|
||||
islink "$root/etc/systemd/system/link1.path" "/link1.path"
|
||||
islink "$root/etc/systemd/system/paths.target.wants/link1.path" "../link1.path"
|
||||
|
||||
: '-------manual link------------------------------------------'
|
||||
cat >"$root/link3.suffix" <<EOF
|
||||
[Install]
|
||||
WantedBy=services.target
|
||||
EOF
|
||||
|
||||
# We wouldn't create such a link ourselves, but it should accept it when present.
|
||||
ln -s "/link3.suffix" "$root/etc/systemd/system/link3.service"
|
||||
|
||||
SYSTEMD_LOG_LEVEL=debug SYSTEMD_LOG_LOCATION=1 "$systemctl" --root="$root" enable 'link3.service'
|
||||
islink "$root/etc/systemd/system/link3.service" "/link3.suffix"
|
||||
islink "$root/etc/systemd/system/services.target.wants/link3.service" "../link3.service"
|
||||
|
||||
SYSTEMD_LOG_LEVEL=debug SYSTEMD_LOG_LOCATION=1 "$systemctl" --root="$root" disable 'link3.service'
|
||||
test ! -h "$root/etc/systemd/system/link3.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/link3.service"
|
||||
|
||||
: '-------enable on masked-------------------------------------'
|
||||
ln -s "/dev/null" "$root/etc/systemd/system/masked.service"
|
||||
( ! "$systemctl" --root="$root" enable 'masked.service' )
|
||||
( ! "$systemctl" --root="$root" enable '/etc/systemd/system/masked.service' )
|
||||
|
||||
: '-------enable on masked alias-------------------------------'
|
||||
test -h "$root/etc/systemd/system/masked.service"
|
||||
ln -s "masked.service" "$root/etc/systemd/system/masked-alias.service"
|
||||
( ! "$systemctl" --root="$root" enable 'masked-alias.service' )
|
||||
( ! "$systemctl" --root="$root" enable '/etc/systemd/system/masked-alias.service' )
|
||||
|
||||
: '-------issue 22000: link in subdirectory--------------------'
|
||||
mkdir -p "$root/etc/systemd/system/myown.d"
|
||||
cat >"$root/etc/systemd/system/link5-also.service" <<EOF
|
||||
[Install]
|
||||
WantedBy=services.target
|
||||
Also=link5.service
|
||||
EOF
|
||||
cat >"$root/etc/systemd/system/myown.d/link5.service" <<EOF
|
||||
[Install]
|
||||
WantedBy=services.target
|
||||
Also=link5-also.service
|
||||
EOF
|
||||
|
||||
( ! "$systemctl" --root="$root" enable 'link5.service' )
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/link5.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/link5-also.service"
|
||||
|
||||
"$systemctl" --root="$root" enable 'link5-also.service'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/link5.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/link5-also.service" "../link5-also.service"
|
||||
|
||||
: '-------template enablement----------------------------------'
|
||||
cat >"$root/etc/systemd/system/templ1@.service" <<EOF
|
||||
[Install]
|
||||
WantedBy=services.target
|
||||
EOF
|
||||
|
||||
# No instance here — this can't succeed.
|
||||
( ! "$systemctl" --root="$root" enable 'templ1@.service' )
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
|
||||
|
||||
"$systemctl" --root="$root" enable 'templ1@one.service'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
|
||||
|
||||
"$systemctl" --root="$root" enable 'templ1@two.service'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
|
||||
|
||||
"$systemctl" --root="$root" disable 'templ1@one.service'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
|
||||
|
||||
"$systemctl" --root="$root" disable 'templ1@two.service'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service"
|
||||
|
||||
: '-------template enablement w/ default instance--------------'
|
||||
cat >"$root/etc/systemd/system/templ1@.service" <<EOF
|
||||
[Install]
|
||||
# check enablement with
|
||||
WantedBy=services.target services.target
|
||||
RequiredBy=other@templ1.target other@%p.target
|
||||
DefaultInstance=333
|
||||
EOF
|
||||
|
||||
"$systemctl" --root="$root" enable 'templ1@.service'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
|
||||
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
|
||||
|
||||
"$systemctl" --root="$root" enable 'templ1@one.service'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
|
||||
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
|
||||
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service" "../templ1@one.service"
|
||||
|
||||
"$systemctl" --root="$root" enable 'templ1@two.service'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
|
||||
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@one.service" "../templ1@one.service"
|
||||
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service" "../templ1@one.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
|
||||
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service" "../templ1@two.service"
|
||||
|
||||
"$systemctl" --root="$root" disable 'templ1@one.service'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@333.service" "../templ1@.service"
|
||||
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service" "../templ1@.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
|
||||
test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service"
|
||||
islink "$root/etc/systemd/system/services.target.wants/templ1@two.service" "../templ1@two.service"
|
||||
islink "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service" "../templ1@two.service"
|
||||
|
||||
# disable remaining links here
|
||||
"$systemctl" --root="$root" disable 'templ1@.service'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@333.service"
|
||||
test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@333.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
|
||||
test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@one.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service"
|
||||
test ! -h "$root/etc/systemd/system/other@templ1.target.requires/templ1@two.service"
|
||||
|
||||
: '-------removal of relative enablement symlinks--------------'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@.service"
|
||||
ln -s '../templ1@one.service' "$root/etc/systemd/system/services.target.wants/templ1@one.service"
|
||||
ln -s 'templ1@two.service' "$root/etc/systemd/system/services.target.wants/templ1@two.service"
|
||||
ln -s '../templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@three.service"
|
||||
ln -s 'templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@four.service"
|
||||
ln -s '/usr/lib/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@five.service"
|
||||
ln -s '/etc/systemd/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@six.service"
|
||||
ln -s '/run/system/templ1@.service' "$root/etc/systemd/system/services.target.wants/templ1@seven.service"
|
||||
|
||||
# this should remove all links
|
||||
"$systemctl" --root="$root" disable 'templ1@.service'
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@one.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@two.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@three.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@four.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@five.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@six.service"
|
||||
test ! -h "$root/etc/systemd/system/services.target.wants/templ1@seven.service"
|
||||
|
||||
: '-------template enablement for another template-------------'
|
||||
cat >"$root/etc/systemd/system/templ2@.service" <<EOF
|
||||
[Install]
|
||||
RequiredBy=another-template@.target
|
||||
EOF
|
||||
|
||||
"$systemctl" --root="$root" enable 'templ2@.service'
|
||||
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
|
||||
|
||||
"$systemctl" --root="$root" enable 'templ2@two.service'
|
||||
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
|
||||
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service" "../templ2@two.service"
|
||||
|
||||
"$systemctl" --root="$root" disable 'templ2@other.service'
|
||||
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
|
||||
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service" "../templ2@two.service"
|
||||
|
||||
"$systemctl" --root="$root" disable 'templ2@two.service'
|
||||
islink "$root/etc/systemd/system/another-template@.target.requires/templ2@.service" "../templ2@.service"
|
||||
test ! -h "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service"
|
||||
|
||||
"$systemctl" --root="$root" disable 'templ2@.service'
|
||||
test ! -h "$root/etc/systemd/system/another-template@.target.requires/templ2@.service"
|
||||
test ! -h "$root/etc/systemd/system/another-template@.target.requires/templ2@two.service"
|
||||
|
||||
: '-------aliases w/ and w/o instance--------------------------'
|
||||
test ! -e "$root/etc/systemd/system/link4.service"
|
||||
cat >"$root/etc/systemd/system/link4.service" <<EOF
|
||||
[Install]
|
||||
Alias=link4.service
|
||||
Alias=link4@.service
|
||||
Alias=link4@inst.service
|
||||
Alias=link4alias.service
|
||||
Alias=link4alias2.service
|
||||
EOF
|
||||
|
||||
( ! "$systemctl" --root="$root" enable 'link4.service' )
|
||||
test ! -h "$root/etc/systemd/system/link4.service" # this is our file
|
||||
test ! -h "$root/etc/systemd/system/link4@.service"
|
||||
test ! -h "$root/etc/systemd/system/link4@inst.service"
|
||||
islink "$root/etc/systemd/system/link4alias.service" "link4.service"
|
||||
islink "$root/etc/systemd/system/link4alias2.service" "link4.service"
|
||||
|
||||
"$systemctl" --root="$root" disable 'link4.service'
|
||||
test ! -h "$root/etc/systemd/system/link4.service"
|
||||
test ! -h "$root/etc/systemd/system/link4@.service"
|
||||
test ! -h "$root/etc/systemd/system/link4@inst.service"
|
||||
test ! -h "$root/etc/systemd/system/link4alias.service"
|
||||
test ! -h "$root/etc/systemd/system/link4alias2.service"
|
||||
|
||||
: '-------systemctl enable on path to unit file----------------'
|
||||
cat >"$root/etc/systemd/system/link4.service" <<EOF
|
||||
[Install]
|
||||
Alias=link4alias.service
|
||||
Alias=link4alias2.service
|
||||
EOF
|
||||
|
||||
# Apparently this works. I'm not sure what to think.
|
||||
"$systemctl" --root="$root" enable '/etc/systemd/system/link4.service'
|
||||
test ! -h "$root/etc/systemd/system/link4.service" # this is our file
|
||||
islink "$root/etc/systemd/system/link4alias.service" "link4.service"
|
||||
islink "$root/etc/systemd/system/link4alias2.service" "link4.service"
|
||||
|
||||
"$systemctl" --root="$root" disable '/etc/systemd/system/link4.service'
|
||||
test ! -h "$root/etc/systemd/system/link4.service"
|
||||
test ! -h "$root/etc/systemd/system/link4alias.service"
|
||||
test ! -h "$root/etc/systemd/system/link4alias2.service"
|
||||
|
||||
: '-------issue 661: enable on unit file--------------'
|
||||
test ! -e "$root/etc/systemd/system/link5.service"
|
||||
cat >"$root/etc/systemd/system/link5.service" <<EOF
|
||||
[Install]
|
||||
Alias=link5.service
|
||||
Alias=link5alias.service
|
||||
Alias=link5alias2.service
|
||||
EOF
|
||||
|
||||
"$systemctl" --root="$root" enable 'link5.service'
|
||||
test ! -h "$root/etc/systemd/system/link5.service" # this is our file
|
||||
islink "$root/etc/systemd/system/link5alias.service" "link5.service"
|
||||
islink "$root/etc/systemd/system/link5alias2.service" "link5.service"
|
||||
|
||||
"$systemctl" --root="$root" disable 'link5.service'
|
||||
test ! -h "$root/etc/systemd/system/link5alias.service"
|
||||
test ! -h "$root/etc/systemd/system/link5alias2.service"
|
||||
|
||||
: '-------issue 661: link and enable on unit file--------------'
|
||||
test ! -e "$root/etc/systemd/system/link5copy.service"
|
||||
cat >"$root/link5copy.service" <<EOF
|
||||
[Install]
|
||||
Alias=link5copy.service
|
||||
Alias=link5alias.service
|
||||
Alias=link5alias2.service
|
||||
EOF
|
||||
|
||||
test ! -e "$root/etc/systemd/system/link5copy.service"
|
||||
|
||||
"$systemctl" --root="$root" link '/link5copy.service'
|
||||
islink "$root/etc/systemd/system/link5copy.service" '/link5copy.service'
|
||||
test ! -h "$root/etc/systemd/system/link5alias.service"
|
||||
test ! -h "$root/etc/systemd/system/link5alias2.service"
|
||||
|
||||
"$systemctl" --root="$root" disable 'link5copy.service'
|
||||
test ! -h "$root/etc/systemd/system/link5copy.service"
|
||||
test ! -h "$root/etc/systemd/system/link5alias.service"
|
||||
test ! -h "$root/etc/systemd/system/link5alias2.service"
|
||||
|
||||
"$systemctl" --root="$root" enable '/link5copy.service'
|
||||
islink "$root/etc/systemd/system/link5copy.service" '/link5copy.service'
|
||||
islink "$root/etc/systemd/system/link5alias.service" 'link5copy.service'
|
||||
islink "$root/etc/systemd/system/link5alias2.service" 'link5copy.service'
|
||||
|
||||
"$systemctl" --root="$root" disable 'link5copy.service'
|
||||
test ! -h "$root/etc/systemd/system/link5copy.service"
|
||||
test ! -h "$root/etc/systemd/system/link5alias.service"
|
||||
test ! -h "$root/etc/systemd/system/link5alias2.service"
|
||||
|
||||
: '----issue 19437: plain templates in .wants/ or .requires/---'
|
||||
test ! -e "$root/etc/systemd/system/link5@.path"
|
||||
cat >"$root/etc/systemd/system/link5@.path" <<EOF
|
||||
[Install]
|
||||
WantedBy=target5@.target
|
||||
RequiredBy=target5@.target
|
||||
WantedBy=target5@inst.target
|
||||
RequiredBy=target5@inst.target
|
||||
EOF
|
||||
|
||||
"$systemctl" --root="$root" enable 'link5@.path'
|
||||
test ! -h "$root/etc/systemd/system/link5@.path" # this is our file
|
||||
islink "$root/etc/systemd/system/target5@.target.wants/link5@.path" "../link5@.path"
|
||||
islink "$root/etc/systemd/system/target5@.target.requires/link5@.path" "../link5@.path"
|
||||
islink "$root/etc/systemd/system/target5@inst.target.wants/link5@.path" "../link5@.path"
|
||||
islink "$root/etc/systemd/system/target5@inst.target.requires/link5@.path" "../link5@.path"
|
||||
|
||||
"$systemctl" --root="$root" disable 'link5@.path'
|
||||
test ! -h "$root/etc/systemd/system/link5@.path" # this is our file
|
||||
test ! -h "$root/etc/systemd/system/target5@.target.wants/link5@.path"
|
||||
test ! -h "$root/etc/systemd/system/target5@.target.requires/link5@.path"
|
||||
test ! -h "$root/etc/systemd/system/target5@inst.target.wants/link5@.path"
|
||||
test ! -h "$root/etc/systemd/system/target5@inst.target.requires/link5@.path"
|
||||
|
||||
: '-------removal of symlinks not listed in [Install]----------'
|
||||
# c.f. 66a19d85a533b15ed32f4066ec880b5a8c06babd
|
||||
test ! -e "$root/etc/systemd/system/multilink.mount"
|
||||
cat >"$root/etc/systemd/system/multilink.mount" <<EOF
|
||||
[Install]
|
||||
WantedBy=multilink.target
|
||||
EOF
|
||||
|
||||
mkdir -p "$root/etc/systemd/system/default.target.wants"
|
||||
ln -s ../multilink.mount "$root/etc/systemd/system/default.target.wants/"
|
||||
ln -s ../multilink.mount "$root/etc/systemd/system/multilink-alias.mount"
|
||||
ln -s ../multilink.mount "$root/etc/systemd/system/multilink-badalias.service"
|
||||
|
||||
"$systemctl" --root="$root" disable 'multilink.mount'
|
||||
test -e "$root/etc/systemd/system/multilink.mount" # this is our file
|
||||
test ! -h "$root/etc/systemd/system/default.target.wants/"
|
||||
test ! -h "$root/etc/systemd/system/multilink-alias.mount"
|
||||
test ! -h "$root/etc/systemd/system/multilink-badalias.service"
|
||||
|
||||
: '-------merge 20017: specifiers in the unit file-------------'
|
||||
test ! -e "$root/etc/systemd/system/some-some-link6@.socket"
|
||||
# c.f. de61a04b188f81a85cdb5c64ddb4987dcd9d30d3
|
||||
|
||||
check_alias() {
|
||||
: "------------------ %$1 -------------------------------------"
|
||||
cat >"$root/etc/systemd/system/some-some-link6@.socket" <<EOF
|
||||
[Install]
|
||||
Alias=target@$1:%$1.socket
|
||||
EOF
|
||||
SYSTEMD_LOG_LEVEL=debug "$systemctl" --root="$root" enable 'some-some-link6@.socket' || return 1
|
||||
islink "$root/etc/systemd/system/target@$1:$2.socket" "some-some-link6@.socket" || return 2
|
||||
}
|
||||
|
||||
# TODO: our architecture names are different than what uname -m returns.
|
||||
# Add something like 'systemd-detect-virt --print-architecture' and use it here.
|
||||
check_alias a "$(uname -m | tr '_' '-')" || :
|
||||
|
||||
test ! -e "$root/etc/os-release"
|
||||
test ! -e "$root/usr/lib/os-release"
|
||||
|
||||
( ! check_alias A '' )
|
||||
( ! check_alias B '' )
|
||||
( ! check_alias M '' )
|
||||
( ! check_alias o '' )
|
||||
( ! check_alias w '' )
|
||||
( ! check_alias W '' )
|
||||
|
||||
cat >"$root/etc/os-release" <<EOF
|
||||
# empty
|
||||
EOF
|
||||
|
||||
check_alias A ''
|
||||
check_alias B ''
|
||||
check_alias M ''
|
||||
check_alias o ''
|
||||
check_alias w ''
|
||||
check_alias W ''
|
||||
|
||||
cat >"$root/etc/os-release" <<EOF
|
||||
ID='the-id'
|
||||
VERSION_ID=39a
|
||||
BUILD_ID=build-id
|
||||
VARIANT_ID=wrong
|
||||
VARIANT_ID=right
|
||||
IMAGE_ID="foobar"
|
||||
IMAGE_VERSION='1-2-3'
|
||||
EOF
|
||||
|
||||
check_alias A '1-2-3'
|
||||
check_alias B 'build-id'
|
||||
check_alias M 'foobar'
|
||||
check_alias o 'the-id'
|
||||
check_alias w '39a'
|
||||
check_alias W 'right'
|
||||
|
||||
check_alias b "$("$systemd_id128" boot-id)"
|
||||
|
||||
# Specifiers not available for [Install]
|
||||
( ! check_alias C '' )
|
||||
( ! check_alias E '' )
|
||||
( ! check_alias f '' )
|
||||
( ! check_alias h '' )
|
||||
( ! check_alias I '' )
|
||||
( ! check_alias J '' )
|
||||
( ! check_alias L '' )
|
||||
( ! check_alias P '' )
|
||||
( ! check_alias s '' )
|
||||
( ! check_alias S '' )
|
||||
( ! check_alias t '' )
|
||||
( ! check_alias T '' )
|
||||
( ! check_alias V '' )
|
||||
|
||||
check_alias g root
|
||||
check_alias G 0
|
||||
check_alias u root
|
||||
check_alias U 0
|
||||
|
||||
check_alias i ""
|
||||
|
||||
check_alias j 'link6'
|
||||
|
||||
check_alias l "$(uname -n | sed 's/\..*//')"
|
||||
|
||||
test ! -e "$root/etc/machine-id"
|
||||
( ! check_alias m '' )
|
||||
|
||||
"$systemd_id128" new >"$root/etc/machine-id"
|
||||
check_alias m "$(cat "$root/etc/machine-id")"
|
||||
|
||||
check_alias n 'some-some-link6@.socket'
|
||||
check_alias N 'some-some-link6@'
|
||||
|
||||
check_alias p 'some-some-link6'
|
||||
|
||||
check_alias v "$(uname -r)"
|
||||
|
||||
# % is not legal in unit name
|
||||
( ! check_alias % '%' )
|
||||
|
||||
# %z is not defined
|
||||
( ! check_alias z 'z' )
|
||||
|
||||
: '-------specifiers in WantedBy-------------------------------'
|
||||
# We don't need to repeat all the tests. Let's do a basic check that specifier
|
||||
# expansion is performed.
|
||||
|
||||
cat >"$root/etc/systemd/system/some-some-link7.socket" <<EOF
|
||||
[Install]
|
||||
WantedBy=target@%p.target
|
||||
WantedBy=another-target@.target
|
||||
RequiredBy=target2@%p.target
|
||||
RequiredBy=another-target2@.target
|
||||
EOF
|
||||
|
||||
"$systemctl" --root="$root" enable 'some-some-link7.socket'
|
||||
islink "$root/etc/systemd/system/target@some-some-link7.target.wants/some-some-link7.socket" "../some-some-link7.socket"
|
||||
islink "$root/etc/systemd/system/another-target@.target.wants/some-some-link7.socket" "../some-some-link7.socket"
|
||||
islink "$root/etc/systemd/system/target2@some-some-link7.target.requires/some-some-link7.socket" "../some-some-link7.socket"
|
||||
islink "$root/etc/systemd/system/another-target2@.target.requires/some-some-link7.socket" "../some-some-link7.socket"
|
||||
|
||||
"$systemctl" --root="$root" disable 'some-some-link7.socket'
|
||||
test ! -h "$root/etc/systemd/system/target@some-some-link7.target.wants/some-some-link7.socket"
|
||||
test ! -h "$root/etc/systemd/system/another-target@.target.wants/some-some-link7.socket"
|
||||
test ! -h "$root/etc/systemd/system/target2@some-some-link7.target.requires/some-some-link7.socket"
|
||||
test ! -h "$root/etc/systemd/system/another-target2@.target.requires/some-some-link7.socket"
|
||||
|
||||
# TODO: repeat the tests above for presets
|
||||
|
||||
: '-------SYSTEMD_OS_RELEASE relative to root-------------------'
|
||||
# check that os-release overwriting works as expected with root
|
||||
test -e "$root/etc/os-release"
|
||||
|
||||
cat >"$root/etc/os-release2" <<EOF
|
||||
ID='the-id2'
|
||||
EOF
|
||||
|
||||
SYSTEMD_OS_RELEASE="$root/etc/os-release2" check_alias o 'the-id2'
|
@ -98,13 +98,13 @@ def test_valid_specifiers(*, user):
|
||||
test_content('f {} - - - - %b', '{}'.format(id128.get_boot().hex), user=user)
|
||||
test_content('f {} - - - - %H', '{}'.format(socket.gethostname()), user=user)
|
||||
test_content('f {} - - - - %v', '{}'.format(os.uname().release), user=user)
|
||||
test_content('f {} - - - - %U', '{}'.format(os.getuid()), user=user)
|
||||
test_content('f {} - - - - %G', '{}'.format(os.getgid()), user=user)
|
||||
test_content('f {} - - - - %U', '{}'.format(os.getuid() if user else 0), user=user)
|
||||
test_content('f {} - - - - %G', '{}'.format(os.getgid() if user else 0), user=user)
|
||||
|
||||
puser = pwd.getpwuid(os.getuid())
|
||||
puser = pwd.getpwuid(os.getuid() if user else 0)
|
||||
test_content('f {} - - - - %u', '{}'.format(puser.pw_name), user=user)
|
||||
|
||||
pgroup = grp.getgrgid(os.getgid())
|
||||
pgroup = grp.getgrgid(os.getgid() if user else 0)
|
||||
test_content('f {} - - - - %g', '{}'.format(pgroup.gr_name), user=user)
|
||||
|
||||
# Note that %h is the only specifier in which we look the environment,
|
||||
|
Loading…
Reference in New Issue
Block a user