summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/bus-util.c21
-rw-r--r--src/shared/install.c134
-rw-r--r--src/shared/install.h124
3 files changed, 224 insertions, 55 deletions
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 677970b7f0..6a1877d8aa 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -2200,20 +2200,16 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
- if (!quiet) {
- if (streq(type, "symlink"))
- log_info("Created symlink from %s to %s.", path, source);
- else if (streq(type, "unlink"))
- log_info("Removed symlink %s.", path);
- else if (streq(type, "masked"))
- log_info("Unit %s is masked, ignoring.", path);
- else
- log_notice("Manager reported unknown change type \"%s\" for %s.", type, path);
+ /* We expect only "success" changes to be sent over the bus.
+ Hence, reject anything negative. */
+ UnitFileChangeType ch = unit_file_change_type_from_string(type);
+
+ if (ch < 0) {
+ log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
+ continue;
}
- r = unit_file_changes_add(changes, n_changes,
- unit_file_change_type_from_string(type),
- path, source);
+ r = unit_file_changes_add(changes, n_changes, ch, path, source);
if (r < 0)
return r;
}
@@ -2224,6 +2220,7 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un
if (r < 0)
return bus_log_parse_error(r);
+ unit_file_dump_changes(0, NULL, *changes, *n_changes, false);
return 0;
}
diff --git a/src/shared/install.c b/src/shared/install.c
index 10c724edbd..71012eafb4 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -276,6 +276,70 @@ void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
free(changes);
}
+void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, unsigned n_changes, bool quiet) {
+ unsigned i;
+ bool logged = false;
+
+ assert(changes || n_changes == 0);
+ /* If verb is not specified, errors are not allowed! */
+ assert(verb || r >= 0);
+
+ for (i = 0; i < n_changes; i++) {
+ assert(verb || changes[i].type >= 0);
+
+ switch(changes[i].type) {
+ case UNIT_FILE_SYMLINK:
+ if (!quiet)
+ log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source);
+ break;
+ case UNIT_FILE_UNLINK:
+ if (!quiet)
+ log_info("Removed %s.", changes[i].path);
+ break;
+ case UNIT_FILE_IS_MASKED:
+ if (!quiet)
+ log_info("Unit %s is masked, ignoring.", changes[i].path);
+ break;
+ case -EEXIST:
+ if (changes[i].source)
+ log_error_errno(changes[i].type,
+ "Failed to %s unit, file %s already exists and is a symlink to %s.",
+ verb, changes[i].path, changes[i].source);
+ else
+ log_error_errno(changes[i].type,
+ "Failed to %s unit, file %s already exists.",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ case -ERFKILL:
+ log_error_errno(changes[i].type, "Failed to %s unit, unit %s is masked.",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ case -EADDRNOTAVAIL:
+ log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ case -ELOOP:
+ log_error_errno(changes[i].type, "Failed to %s unit, refusing to operate on linked unit file %s",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ default:
+ assert(changes[i].type < 0);
+ log_error_errno(changes[i].type, "Failed to %s unit, file %s: %m.",
+ verb, changes[i].path);
+ logged = true;
+ }
+ }
+
+ if (r < 0 && !logged)
+ log_error_errno(r, "Failed to %s: %m.", verb);
+}
+
+
+
static int create_symlink(
const char *old_path,
const char *new_path,
@@ -300,8 +364,10 @@ static int create_symlink(
return 1;
}
- if (errno != EEXIST)
+ if (errno != EEXIST) {
+ unit_file_changes_add(changes, n_changes, -errno, new_path, NULL);
return -errno;
+ }
r = readlink_malloc(new_path, &dest);
if (r < 0)
@@ -310,8 +376,10 @@ static int create_symlink(
if (path_equal(dest, old_path))
return 0;
- if (!force)
+ if (!force) {
+ unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest);
return -EEXIST;
+ }
r = symlink_atomic(old_path, new_path);
if (r < 0)
@@ -421,6 +489,7 @@ static int remove_marked_symlinks_fd(
p = path_make_absolute(de->d_name, path);
if (!p)
return -ENOMEM;
+ path_kill_slashes(p);
q = readlink_malloc(p, &dest);
if (q == -ENOENT)
@@ -434,8 +503,7 @@ static int remove_marked_symlinks_fd(
/* We remove all links pointing to a file or path that is marked, as well as all files sharing
* the same name as a file that is marked. */
- found =
- set_contains(remove_symlinks_to, dest) ||
+ found = set_contains(remove_symlinks_to, dest) ||
set_contains(remove_symlinks_to, basename(dest)) ||
set_contains(remove_symlinks_to, de->d_name);
@@ -445,10 +513,10 @@ static int remove_marked_symlinks_fd(
if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) {
if (r == 0)
r = -errno;
+ unit_file_changes_add(changes, n_changes, -errno, p, NULL);
continue;
}
- path_kill_slashes(p);
(void) rmdir_parents(p, config_path);
unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
@@ -746,19 +814,26 @@ static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *nam
return ordered_hashmap_get(c->will_process, name);
}
-static int install_info_may_process(UnitFileInstallInfo *i, const LookupPaths *paths) {
+static int install_info_may_process(
+ UnitFileInstallInfo *i,
+ const LookupPaths *paths,
+ UnitFileChange **changes,
+ unsigned *n_changes) {
assert(i);
assert(paths);
/* Checks whether the loaded unit file is one we should process, or is masked, transient or generated and thus
* not subject to enable/disable operations. */
- if (i->type == UNIT_FILE_TYPE_MASKED)
+ if (i->type == UNIT_FILE_TYPE_MASKED) {
+ unit_file_changes_add(changes, n_changes, -ERFKILL, i->path, NULL);
return -ERFKILL;
- if (path_is_generator(paths, i->path))
- return -EADDRNOTAVAIL;
- if (path_is_transient(paths, i->path))
+ }
+ if (path_is_generator(paths, i->path) ||
+ path_is_transient(paths, i->path)) {
+ unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL, i->path, NULL);
return -EADDRNOTAVAIL;
+ }
return 0;
}
@@ -1391,8 +1466,10 @@ static int install_info_symlink_link(
assert(i->path);
r = in_search_path(paths, i->path);
- if (r != 0)
+ if (r < 0)
return r;
+ if (r > 0)
+ return 0;
path = strjoin(config_path, "/", i->name, NULL);
if (!path)
@@ -1431,7 +1508,8 @@ static int install_info_apply(
r = q;
q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
- if (r == 0)
+ /* Do not count links to the unit file towards the "carries_install_info" count */
+ if (r == 0 && q < 0)
r = q;
return r;
@@ -1481,7 +1559,7 @@ static int install_context_apply(
if (q < 0)
r = q;
else
- r+= q;
+ r += q;
}
}
@@ -1638,8 +1716,11 @@ int unit_file_unmask(
return -ENOMEM;
if (unlink(path) < 0) {
- if (errno != ENOENT && r >= 0)
- r = -errno;
+ if (errno != ENOENT) {
+ if (r >= 0)
+ r = -errno;
+ unit_file_changes_add(changes, n_changes, -errno, path, NULL);
+ }
continue;
}
@@ -1954,7 +2035,7 @@ int unit_file_add_dependency(
r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info);
if (r < 0)
return r;
- r = install_info_may_process(target_info, &paths);
+ r = install_info_may_process(target_info, &paths, changes, n_changes);
if (r < 0)
return r;
@@ -1966,7 +2047,7 @@ int unit_file_add_dependency(
r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
if (r < 0)
return r;
- r = install_info_may_process(i, &paths);
+ r = install_info_may_process(i, &paths, changes, n_changes);
if (r < 0)
return r;
@@ -2019,7 +2100,7 @@ int unit_file_enable(
r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD, &i);
if (r < 0)
return r;
- r = install_info_may_process(i, &paths);
+ r = install_info_may_process(i, &paths, changes, n_changes);
if (r < 0)
return r;
@@ -2132,7 +2213,7 @@ int unit_file_set_default(
r = install_info_discover(scope, &c, &paths, name, 0, &i);
if (r < 0)
return r;
- r = install_info_may_process(i, &paths);
+ r = install_info_may_process(i, &paths, changes, n_changes);
if (r < 0)
return r;
@@ -2164,7 +2245,7 @@ int unit_file_get_default(
r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
if (r < 0)
return r;
- r = install_info_may_process(i, &paths);
+ r = install_info_may_process(i, &paths, NULL, 0);
if (r < 0)
return r;
@@ -2413,7 +2494,7 @@ static int execute_preset(
if (q < 0)
r = q;
else
- r+= q;
+ r += q;
}
}
@@ -2426,7 +2507,9 @@ static int preset_prepare_one(
InstallContext *minus,
LookupPaths *paths,
UnitFilePresetMode mode,
- const char *name) {
+ const char *name,
+ UnitFileChange **changes,
+ unsigned *n_changes) {
UnitFileInstallInfo *i;
int r;
@@ -2444,7 +2527,7 @@ static int preset_prepare_one(
if (r < 0)
return r;
- r = install_info_may_process(i, paths);
+ r = install_info_may_process(i, paths, changes, n_changes);
if (r < 0)
return r;
} else
@@ -2483,7 +2566,7 @@ int unit_file_preset(
if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
return -EINVAL;
- r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i);
+ r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, changes, n_changes);
if (r < 0)
return r;
}
@@ -2538,7 +2621,8 @@ int unit_file_preset_all(
if (!IN_SET(de->d_type, DT_LNK, DT_REG))
continue;
- r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name);
+ /* 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, NULL, 0);
if (r == -ERFKILL)
r = unit_file_changes_add(changes, n_changes,
UNIT_FILE_IS_MASKED, de->d_name, NULL);
diff --git a/src/shared/install.h b/src/shared/install.h
index 6b760def9b..4133faffa2 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -74,19 +74,27 @@ enum UnitFileChangeType {
UNIT_FILE_UNLINK,
UNIT_FILE_IS_MASKED,
_UNIT_FILE_CHANGE_TYPE_MAX,
- _UNIT_FILE_CHANGE_TYPE_INVALID = -1
+ _UNIT_FILE_CHANGE_INVALID = INT_MIN
};
-static inline bool unit_file_change_is_modification(UnitFileChangeType type) {
- return IN_SET(type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK);
-}
-
+/* type can either one of the UnitFileChangeTypes listed above, or a negative error.
+ * If source is specified, it should be the contents of the path symlink.
+ * In case of an error, source should be the existing symlink contents or NULL
+ */
struct UnitFileChange {
- UnitFileChangeType type;
+ int type; /* UnitFileChangeType or bust */
char *path;
char *source;
};
+static inline bool unit_file_changes_have_modification(const UnitFileChange* changes, unsigned n_changes) {
+ unsigned i;
+ for (i = 0; i < n_changes; i++)
+ if (IN_SET(changes[i].type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK))
+ return true;
+ return false;
+}
+
struct UnitFileList {
char *path;
UnitFileState state;
@@ -130,18 +138,96 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *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);
-int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_preset_all(UnitFileScope scope, bool runtime, const char *root_dir, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_revert(UnitFileScope scope, 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, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes);
+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);
+int unit_file_preset(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ UnitFilePresetMode mode,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_preset_all(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ UnitFilePresetMode mode,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_mask(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_unmask(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_link(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_revert(
+ UnitFileScope scope,
+ 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,
+ const char *target,
+ UnitDependency dep,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
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);
@@ -151,11 +237,13 @@ Hashmap* 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);
+void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, unsigned n_changes, bool quiet);
int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name);
const char *unit_file_state_to_string(UnitFileState s) _const_;
UnitFileState unit_file_state_from_string(const char *s) _pure_;
+/* from_string conversion is unreliable because of the overlap between -EPERM and -1 for error. */
const char *unit_file_change_type_to_string(UnitFileChangeType s) _const_;
UnitFileChangeType unit_file_change_type_from_string(const char *s) _pure_;