install: follow unit file symlinks in /usr, but not /etc when looking for [Install] data

Some distributions use alias unit files via symlinks in /usr to cover
for legacy service names. With this change we'll allow "systemctl
enable" on such aliases.

Previously, our rule was that symlinks are user configuration that
"systemctl enable" + "systemctl disable" creates and removes, while unit
files is where the instructions to do so are store. As a result of the
rule we'd never read install information through symlinks, since that
would mix enablement state with installation instructions.

Now, the new rule is that only symlinks inside of /etc are
configuration. Unit files, and symlinks in /usr are now valid for
installation instructions.

This patch is quite a rework of the whole install logic, and makes the
following addional changes:

- Adds a complete test "test-instal-root" that tests the install logic
  pretty comprehensively.

- Never uses canonicalize_file_name(), because that's incompatible with
  operation relative to a specific root directory.

- unit_file_get_state() is reworked to return a proper error, and
  returns the state in a call-by-ref parameter. This cleans up confusion
  between the enum type and errno-like errors.

- The new logic puts a limit on how long to follow unit file symlinks:
  it will do so only for 64 steps at max.

- The InstallContext object's fields are renamed to will_process and
  has_processed (will_install and has_installed) since they are also
  used for deinstallation and all kinds of other operations.

- The root directory is always verified before use.

- install.c is reordered to place the exported functions together.

- Stricter rules are followed when traversing symlinks: the unit suffix
  must say identical, and it's not allowed to link between regular units
  and templated units.

- Various modernizations

- The "invalid" unit file state has been renamed to "bad", in order to
  avoid confusion between UNIT_FILE_INVALID and
  _UNIT_FILE_STATE_INVALID. Given that the state should normally not be
  seen and is not documented this should not be a problematic change.
  The new name is now documented however.

Fixes #1375, #1718, #1706
This commit is contained in:
Lennart Poettering
2015-11-12 17:57:04 +01:00
parent d073dea0a8
commit 0ec0deaa30
12 changed files with 2106 additions and 1074 deletions
+1293 -1029
View File
File diff suppressed because it is too large Load Diff
+34 -6
View File
@@ -25,13 +25,15 @@ typedef enum UnitFileScope UnitFileScope;
typedef enum UnitFileState UnitFileState;
typedef enum UnitFilePresetMode UnitFilePresetMode;
typedef enum UnitFileChangeType UnitFileChangeType;
typedef enum UnitFileType UnitFileType;
typedef struct UnitFileChange UnitFileChange;
typedef struct UnitFileList UnitFileList;
typedef struct UnitFileInstallInfo UnitFileInstallInfo;
#include "hashmap.h"
#include "unit-name.h"
#include "path-lookup.h"
#include "strv.h"
#include "unit-name.h"
enum UnitFileScope {
UNIT_FILE_SYSTEM,
@@ -51,7 +53,7 @@ enum UnitFileState {
UNIT_FILE_STATIC,
UNIT_FILE_DISABLED,
UNIT_FILE_INDIRECT,
UNIT_FILE_INVALID,
UNIT_FILE_BAD,
_UNIT_FILE_STATE_MAX,
_UNIT_FILE_STATE_INVALID = -1
};
@@ -82,6 +84,14 @@ struct UnitFileList {
UnitFileState state;
};
enum UnitFileType {
UNIT_FILE_TYPE_REGULAR,
UNIT_FILE_TYPE_SYMLINK,
UNIT_FILE_TYPE_MASKED,
_UNIT_FILE_TYPE_MAX,
_UNIT_FILE_TYPE_INVALID = -1,
};
struct UnitFileInstallInfo {
char *name;
char *path;
@@ -93,8 +103,26 @@ struct UnitFileInstallInfo {
char **also;
char *default_instance;
UnitFileType type;
char *symlink_target;
};
static inline bool UNIT_FILE_INSTALL_INFO_HAS_RULES(UnitFileInstallInfo *i) {
assert(i);
return !strv_isempty(i->aliases) ||
!strv_isempty(i->wanted_by) ||
!strv_isempty(i->required_by);
}
static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) {
assert(i);
return !strv_isempty(i->also);
}
int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
@@ -105,14 +133,14 @@ int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char
int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name);
int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes);
UnitFileState unit_file_lookup_state(UnitFileScope scope, const char *root_dir,const LookupPaths *paths, const char *name);
UnitFileState unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename);
int unit_file_lookup_state(UnitFileScope scope, const char *root_dir,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_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h);
Hashmap* unit_file_list_free(Hashmap *h);
void unit_file_list_free(Hashmap *h);
int unit_file_changes_add(UnitFileChange **changes, unsigned *n_changes, UnitFileChangeType type, const char *path, const char *source);
void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes);