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.c120
-rw-r--r--src/shared/install.h7
3 files changed, 116 insertions, 32 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 1522435f7f..febe33ed7b 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)
@@ -444,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);
@@ -745,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;
}
@@ -1637,8 +1713,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;
}
@@ -1953,7 +2032,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;
@@ -1965,7 +2044,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;
@@ -2018,7 +2097,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;
@@ -2131,7 +2210,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;
@@ -2163,7 +2242,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;
@@ -2425,7 +2504,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;
@@ -2443,7 +2524,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
@@ -2482,7 +2563,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;
}
@@ -2537,7 +2618,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 219b48f428..82c62095d5 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -77,8 +77,12 @@ enum UnitFileChangeType {
_UNIT_FILE_CHANGE_TYPE_INVALID = -1
};
+/* 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;
};
@@ -233,6 +237,7 @@ 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);