diff --git a/man/custom-entities.ent.in b/man/custom-entities.ent.in index 4494a1c3ab..beff1529a7 100644 --- a/man/custom-entities.ent.in +++ b/man/custom-entities.ent.in @@ -15,6 +15,7 @@ + diff --git a/man/systemd.special.xml b/man/systemd.special.xml index f6f35b861d..deba4f8e4f 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -1,6 +1,9 @@ + "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ + +%entities; +]> @@ -239,6 +242,13 @@ 3, 5, …; see systemd1. + If default.target is not present on disk and no unit was requested on + the kernel command line, the default set at compile time will be used + (&FALLBACK_DEFAULT_TARGET;). + + If the default unit or one of the fallbacks cannot be started, systemd starts + rescue.target. + For typical unit files please set WantedBy= to a regular target (like multi-user.target or graphical.target), instead of default.target, since such a service will also be run on special diff --git a/meson.build b/meson.build index abdde0040b..423f921834 100644 --- a/meson.build +++ b/meson.build @@ -726,6 +726,9 @@ if fallback_hostname == '' or fallback_hostname[0] == '.' or fallback_hostname[0 endif conf.set_quoted('FALLBACK_HOSTNAME', fallback_hostname) +fallback_default_target = get_option('fallback-default-target') +conf.set_quoted('FALLBACK_DEFAULT_TARGET', fallback_default_target) + extra_net_naming_schemes = [] extra_net_naming_map = [] foreach scheme: get_option('extra-net-naming-schemes').split(',') @@ -2751,6 +2754,7 @@ summary({ 'nobody user name' : nobody_user, 'nobody group name' : nobody_group, 'fallback hostname' : get_option('fallback-hostname'), + 'fallback default target' : fallback_default_target, 'default compression method' : compression, 'default DNSSEC mode' : default_dnssec, 'default DNS-over-TLS mode' : default_dns_over_tls, diff --git a/meson_options.txt b/meson_options.txt index 8df682742d..9c0cda4c38 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -267,6 +267,8 @@ option('clock-valid-range-usec-max', type : 'integer', value : 473364000000000, description : 'maximum value in microseconds for the difference between RTC and epoch, exceeding which is considered an RTC error ["0" disables]') option('default-user-shell', type : 'string', value : '/bin/bash', description : 'default interactive shell') +option('fallback-default-target', type : 'string', value : 'graphical.target', + description : 'unit to activate when default.target is not found on disk') option('system-alloc-uid-min', type : 'integer', value : 0, description : 'minimum system UID used when allocating') diff --git a/src/core/main.c b/src/core/main.c index c476400a93..3dd227f244 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -2768,15 +2768,22 @@ static int do_queue_default_job( log_debug("Activating default unit: %s", unit); r = manager_load_startable_unit_or_warn(m, unit, NULL, &target); - if (r < 0 && in_initrd() && !arg_default_unit) { - /* Fall back to default.target, which we used to always use by default. Only do this if no - * explicit configuration was given. */ + if (r == -ENOENT && !arg_default_unit) { + if (in_initrd()) + /* Fall back to default.target, which we used to always use by default. + * Only do this if no explicit configuration was given. */ + unit = SPECIAL_DEFAULT_TARGET; + else + /* The default.target symlink was not found on disk and the target was not + * explicitly specified. Fall back to the target configured at build time + * via -Ddefault-target=. */ + unit = FALLBACK_DEFAULT_TARGET; - log_info("Falling back to %s.", SPECIAL_DEFAULT_TARGET); - - r = manager_load_startable_unit_or_warn(m, SPECIAL_DEFAULT_TARGET, NULL, &target); + log_info("Falling back to %s.", unit); + r = manager_load_startable_unit_or_warn(m, unit, NULL, &target); } if (r < 0) { + /* We failed. Activate rescue mode. */ log_info("Falling back to %s.", SPECIAL_RESCUE_TARGET); r = manager_load_startable_unit_or_warn(m, SPECIAL_RESCUE_TARGET, NULL, &target); diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index 7f71f5fdc7..c218e015fa 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -88,6 +88,9 @@ TEST(unit_name_is_valid) { test_unit_name_is_valid_one("foo.target.wants/plain.service", UNIT_NAME_ANY, false); test_unit_name_is_valid_one("foo.target.conf/foo.conf", UNIT_NAME_ANY, false); test_unit_name_is_valid_one("foo.target.requires/plain.socket", UNIT_NAME_ANY, false); + + /* The build-time configured fallback for default.target must be a valid plain unit name. */ + test_unit_name_is_valid_one(FALLBACK_DEFAULT_TARGET, UNIT_NAME_PLAIN, true); } static void test_unit_name_replace_instance_one(const char *pattern, const char *repl, const char *expected, int ret) {