diff --git a/Makefile.am b/Makefile.am index d4e3e9a013..a1bb21e4fc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -575,7 +575,16 @@ dist_userunit_DATA = \ units/user/default.target \ units/user/exit.target \ units/user/graphical-session.target \ - units/user/graphical-session-pre.target + units/user/graphical-session-pre.target \ + units/user/bluetooth.target \ + units/user/busnames.target \ + units/user/paths.target \ + units/user/printer.target \ + units/user/shutdown.target \ + units/user/smartcard.target \ + units/user/sockets.target \ + units/user/sound.target \ + units/user/timers.target nodist_userunit_DATA = \ units/user/systemd-exit.service @@ -634,6 +643,10 @@ EXTRA_DIST += \ units/rc-local.service.in \ units/halt-local.service.in +GENERAL_ALIASES += \ + $(systemunitdir)/reboot.target $(pkgsysconfdir)/system/ctrl-alt-del.target \ + $(systemunitdir)/machines.target $(pkgsysconfdir)/system/multi-user.target.wants/machines.target + # automake is broken and can't handle files with a dash in front # http://debbugs.gnu.org/cgi/bugreport.cgi?bug=14728#8 units-install-hook: @@ -6292,19 +6305,6 @@ SYSTEM_UNIT_ALIASES += \ reboot.target ctrl-alt-del.target \ getty@.service autovt@.service -USER_UNIT_ALIASES += \ - $(systemunitdir)/shutdown.target shutdown.target \ - $(systemunitdir)/sockets.target sockets.target \ - $(systemunitdir)/timers.target timers.target \ - $(systemunitdir)/paths.target paths.target \ - $(systemunitdir)/bluetooth.target bluetooth.target \ - $(systemunitdir)/printer.target printer.target \ - $(systemunitdir)/sound.target sound.target \ - $(systemunitdir)/smartcard.target smartcard.target - -USER_UNIT_ALIASES += \ - $(systemunitdir)/busnames.target busnames.target - GENERAL_ALIASES += \ $(systemunitdir)/remote-fs.target $(pkgsysconfdir)/system/multi-user.target.wants/remote-fs.target \ $(systemunitdir)/getty@.service $(pkgsysconfdir)/system/getty.target.wants/getty@tty1.service \ diff --git a/man/systemctl.xml b/man/systemctl.xml index 9762fd0450..fde4f4f3bb 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1092,7 +1092,8 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service enabled and disabled, or only enabled, or only disabled. If the unit carries no install information, it will be silently ignored - by this command. + by this command. NAME must be the real unit name, + any alias names are ignored silently. For more information on the preset policy format, see systemd.preset5. diff --git a/man/systemd.preset.xml b/man/systemd.preset.xml index b7164014f0..d09167baaf 100644 --- a/man/systemd.preset.xml +++ b/man/systemd.preset.xml @@ -98,6 +98,10 @@ Empty lines and lines whose first non-whitespace character is # or ; are ignored. + Presets must refer to the "real" unit file, and not to any aliases. See + systemd.unit5 + for a description of unit aliasing. + Two different directives are understood: enable may be used to enable units by default, disable to disable units by default. diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 85a7b12d76..f818e772a9 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -144,21 +144,31 @@ and are equivalent. - Time span values encoded in unit files can be written in - various formats. A stand-alone number specifies a time in seconds. - If suffixed with a time unit, the unit is honored. A concatenation - of multiple values with units is supported, in which case the - values are added up. Example: "50" refers to 50 seconds; "2min - 200ms" refers to 2 minutes plus 200 milliseconds, i.e. 120200ms. - The following time units are understood: s, min, h, d, w, ms, us. - For details see + Time span values encoded in unit files can be written in various formats. A stand-alone number specifies a + time in seconds. If suffixed with a time unit, the unit is honored. A concatenation of multiple values with units + is supported, in which case the values are added up. Example: 50 refers to 50 seconds; + 2min 200ms refers to 2 minutes and 200 milliseconds, i.e. 120200 ms. The following time units + are understood: s, min, h, d, + w, ms, us. For details see systemd.time7. - Empty lines and lines starting with # or ; are - ignored. This may be used for commenting. Lines ending - in a backslash are concatenated with the following - line while reading and the backslash is replaced by a - space character. This may be used to wrap long lines. + Empty lines and lines starting with # or ; are ignored. This may be + used for commenting. Lines ending in a backslash are concatenated with the following line while reading and the + backslash is replaced by a space character. This may be used to wrap long lines. + + Units can be aliased (have an alternative name), by creating a symlink from the new name to the existing name + in one of the unit search paths. For example, systemd-networkd.service has the alias + dbus-org.freedesktop.network1.service, created during installation as the symlink + /usr/lib/systemd/system/dbus-org.freedesktop.network1.service. In addition, unit files may + specify aliases through the Alias= directive in the [Install] section; those aliases are only + effective when the unit is enabled. When the unit is enabled, symlinks will be created for those names, and removed + when the unit is disabled. For example, reboot.target specifies + Alias=ctrl-alt-del.target, so when enabled it will be invoked whenever CTRL+ALT+DEL is + pressed. Alias names may be used in commands like enable, disable, + start, stop, status, …, and in unit dependency directives + Wants=, Requires=, Before=, After=, …, + with the limitation that aliases specified through Alias= are only effective when the unit is + enabled. Aliases cannot be used with the preset command. Along with a unit file foo.service, the directory foo.service.wants/ may exist. All diff --git a/src/shared/install.c b/src/shared/install.c index e740ef3910..6a16f8985b 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -393,19 +393,40 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang log_error_errno(r, "Failed to %s: %m.", verb); } +/** + * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem. + * wc should be the full path in the host file system. + */ +static bool chroot_symlinks_same(const char *root, const char *wd, const char *a, const char *b) { + assert(path_is_absolute(wd)); + + /* This will give incorrect results if the paths are relative and go outside + * of the chroot. False negatives are possible. */ + + a = strjoina(path_is_absolute(a) ? root : wd, "/", a); + b = strjoina(path_is_absolute(b) ? root : wd, "/", b); + return path_equal_or_files_same(a, b); +} + static int create_symlink( + const LookupPaths *paths, const char *old_path, const char *new_path, bool force, UnitFileChange **changes, unsigned *n_changes) { - _cleanup_free_ char *dest = NULL; + _cleanup_free_ char *dest = NULL, *dirname = NULL; + const char *rp; int r; assert(old_path); assert(new_path); + rp = skip_root(paths, old_path); + if (rp) + old_path = rp; + /* Actually create a symlink, and remember that we did. Is * smart enough to check if there's already a valid symlink in * place. @@ -436,7 +457,11 @@ static int create_symlink( return r; } - if (path_equal(dest, old_path)) + dirname = dirname_malloc(new_path); + if (!dirname) + return -ENOMEM; + + if (chroot_symlinks_same(paths->root_dir, dirname, dest, old_path)) return 1; if (!force) { @@ -620,7 +645,7 @@ static int remove_marked_symlinks( fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); if (fd < 0) - return -errno; + return errno == ENOENT ? 0 : -errno; do { int q, cfd; @@ -903,6 +928,10 @@ static int install_info_may_process( return 0; } +/** + * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process + * hashmap, or retrieves the existing one if already present. + */ static int install_info_add( InstallContext *c, const char *name, @@ -1334,9 +1363,8 @@ static int install_info_follow( } /** - * Search for the unit file. If the unit name is a symlink, - * follow the symlink to the target, maybe more than once. - * Propagate the instance name if present. + * Search for the unit file. If the unit name is a symlink, follow the symlink to the + * target, maybe more than once. Propagate the instance name if present. */ static int install_info_traverse( UnitFileScope scope, @@ -1421,6 +1449,10 @@ static int install_info_traverse( return 0; } +/** + * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/") + * or the name (otherwise). root_dir is prepended to the path. + */ static int install_info_add_auto( InstallContext *c, const LookupPaths *paths, @@ -1479,7 +1511,6 @@ static int install_info_symlink_alias( STRV_FOREACH(s, i->aliases) { _cleanup_free_ char *alias_path = NULL, *dst = NULL; - const char *rp; q = install_full_printf(i, *s, &dst); if (q < 0) @@ -1489,9 +1520,7 @@ static int install_info_symlink_alias( if (!alias_path) return -ENOMEM; - rp = skip_root(paths, i->path); - - q = create_symlink(rp ?: i->path, alias_path, force, changes, n_changes); + q = create_symlink(paths, i->path, alias_path, force, changes, n_changes); if (r == 0) r = q; } @@ -1535,7 +1564,6 @@ static int install_info_symlink_wants( STRV_FOREACH(s, list) { _cleanup_free_ char *path = NULL, *dst = NULL; - const char *rp; q = install_full_printf(i, *s, &dst); if (q < 0) @@ -1550,9 +1578,7 @@ static int install_info_symlink_wants( if (!path) return -ENOMEM; - rp = skip_root(paths, i->path); - - q = create_symlink(rp ?: i->path, path, true, changes, n_changes); + q = create_symlink(paths, i->path, path, true, changes, n_changes); if (r == 0) r = q; } @@ -1569,7 +1595,6 @@ static int install_info_symlink_link( unsigned *n_changes) { _cleanup_free_ char *path = NULL; - const char *rp; int r; assert(i); @@ -1587,9 +1612,7 @@ static int install_info_symlink_link( if (!path) return -ENOMEM; - rp = skip_root(paths, i->path); - - return create_symlink(rp ?: i->path, path, force, changes, n_changes); + return create_symlink(paths, i->path, path, force, changes, n_changes); } static int install_info_apply( @@ -1663,6 +1686,17 @@ static int install_context_apply( if (r < 0) return r; + /* We can attempt to process a masked unit when a different unit + * that we were processing specifies it in DefaultInstance= or Also=. */ + if (i->type == UNIT_FILE_TYPE_MASKED) { + unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path, NULL); + if (r >= 0) + /* Assume that some *could* have been enabled here, avoid + * "empty [Install] section" warning. */ + r += 1; + continue; + } + if (i->type != UNIT_FILE_TYPE_REGULAR) continue; @@ -1765,7 +1799,7 @@ int unit_file_mask( if (!path) return -ENOMEM; - q = create_symlink("/dev/null", path, force, changes, n_changes); + q = create_symlink(&paths, "/dev/null", path, force, changes, n_changes); if (q < 0 && r >= 0) r = q; } @@ -1925,14 +1959,12 @@ int unit_file_link( r = 0; STRV_FOREACH(i, todo) { _cleanup_free_ char *new_path = NULL; - const char *old_path; - old_path = skip_root(&paths, *i); new_path = path_make_absolute(basename(*i), config_path); if (!new_path) return -ENOMEM; - q = create_symlink(old_path ?: *i, new_path, force, changes, n_changes); + q = create_symlink(&paths, *i, new_path, force, changes, n_changes); if (q < 0 && r >= 0) r = q; } @@ -1967,7 +1999,6 @@ int unit_file_revert( unsigned *n_changes) { _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; - /* _cleanup_(install_context_done) InstallContext c = {}; */ _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_strv_free_ char **todo = NULL; size_t n_todo = 0, n_allocated = 0; @@ -2312,7 +2343,7 @@ int unit_file_set_default( _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_(install_context_done) InstallContext c = {}; UnitFileInstallInfo *i; - const char *new_path, *old_path; + const char *new_path; int r; assert(scope >= 0); @@ -2335,10 +2366,8 @@ int unit_file_set_default( if (r < 0) return r; - old_path = skip_root(&paths, i->path); new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET); - - return create_symlink(old_path ?: i->path, new_path, force, changes, n_changes); + return create_symlink(&paths, i->path, new_path, force, changes, n_changes); } int unit_file_get_default( @@ -2685,19 +2714,26 @@ static int preset_prepare_one( InstallContext *plus, InstallContext *minus, LookupPaths *paths, - UnitFilePresetMode mode, const char *name, Presets presets, UnitFileChange **changes, unsigned *n_changes) { + _cleanup_(install_context_done) InstallContext tmp = {}; UnitFileInstallInfo *i; int r; - if (install_info_find(plus, name) || - install_info_find(minus, name)) + if (install_info_find(plus, name) || install_info_find(minus, name)) return 0; + r = install_info_discover(scope, &tmp, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); + if (r < 0) + return r; + if (!streq(name, i->name)) { + log_debug("Skipping %s because is an alias for %s", name, i->name); + return 0; + } + r = query_presets(name, presets); if (r < 0) return r; @@ -2748,7 +2784,7 @@ int unit_file_preset( return r; STRV_FOREACH(i, files) { - r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, presets, changes, n_changes); + r = preset_prepare_one(scope, &plus, &minus, &paths, *i, presets, changes, n_changes); if (r < 0) return r; } @@ -2809,7 +2845,7 @@ int unit_file_preset_all( continue; /* we don't pass changes[] in, because we want to handle errors on our own */ - r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name, presets, NULL, 0); + r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, presets, NULL, 0); if (r == -ERFKILL) r = unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, de->d_name, NULL); diff --git a/system-preset/90-systemd.preset b/system-preset/90-systemd.preset index ee1b864bcf..0f494b7552 100644 --- a/system-preset/90-systemd.preset +++ b/system-preset/90-systemd.preset @@ -15,6 +15,7 @@ enable getty@.service enable systemd-timesyncd.service enable systemd-networkd.service enable systemd-resolved.service +enable systemd-networkd-wait-online.service disable console-getty.service disable console-shell.service @@ -23,10 +24,12 @@ disable debug-shell.service disable halt.target disable kexec.target disable poweroff.target -disable reboot.target +enable reboot.target disable rescue.target +disable exit.target disable syslog.socket disable systemd-journal-gatewayd.* -disable systemd-networkd-wait-online.service +disable systemd-journal-remote.* +disable systemd-journal-upload.* diff --git a/units/user/bluetooth.target b/units/user/bluetooth.target new file mode 120000 index 0000000000..72e74be0a1 --- /dev/null +++ b/units/user/bluetooth.target @@ -0,0 +1 @@ +../bluetooth.target \ No newline at end of file diff --git a/units/user/busnames.target b/units/user/busnames.target new file mode 120000 index 0000000000..04f4ba1345 --- /dev/null +++ b/units/user/busnames.target @@ -0,0 +1 @@ +../busnames.target \ No newline at end of file diff --git a/units/user/paths.target b/units/user/paths.target new file mode 120000 index 0000000000..33545d24f3 --- /dev/null +++ b/units/user/paths.target @@ -0,0 +1 @@ +../paths.target \ No newline at end of file diff --git a/units/user/printer.target b/units/user/printer.target new file mode 120000 index 0000000000..8b8d5511cd --- /dev/null +++ b/units/user/printer.target @@ -0,0 +1 @@ +../printer.target \ No newline at end of file diff --git a/units/user/shutdown.target b/units/user/shutdown.target new file mode 120000 index 0000000000..a9de83782f --- /dev/null +++ b/units/user/shutdown.target @@ -0,0 +1 @@ +../shutdown.target \ No newline at end of file diff --git a/units/user/smartcard.target b/units/user/smartcard.target new file mode 120000 index 0000000000..f7a23b6b6d --- /dev/null +++ b/units/user/smartcard.target @@ -0,0 +1 @@ +../smartcard.target \ No newline at end of file diff --git a/units/user/sockets.target b/units/user/sockets.target new file mode 120000 index 0000000000..a9e4b97184 --- /dev/null +++ b/units/user/sockets.target @@ -0,0 +1 @@ +../sockets.target \ No newline at end of file diff --git a/units/user/sound.target b/units/user/sound.target new file mode 120000 index 0000000000..17c8e9d6e1 --- /dev/null +++ b/units/user/sound.target @@ -0,0 +1 @@ +../sound.target \ No newline at end of file diff --git a/units/user/timers.target b/units/user/timers.target new file mode 120000 index 0000000000..f98b68a84d --- /dev/null +++ b/units/user/timers.target @@ -0,0 +1 @@ +../timers.target \ No newline at end of file