char **aliases;
char **wanted_by;
+ char **required_by;
} InstallInfo;
typedef struct {
return lookup_paths_init(paths,
scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
- scope == UNIT_FILE_USER);
+ scope == UNIT_FILE_USER,
+ NULL, NULL, NULL);
}
static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
const char *config_path,
bool *deleted,
UnitFileChange **changes,
- unsigned *n_changes) {
+ unsigned *n_changes,
+ char** files) {
int r = 0;
DIR *d;
}
/* This will close nfd, regardless whether it succeeds or not */
- q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes);
+ q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, files);
free(p);
if (r == 0)
set_get(remove_symlinks_to, dest) ||
set_get(remove_symlinks_to, path_get_file_name(dest));
+ if (unit_name_is_instance(p))
+ found = found && strv_contains(files, path_get_file_name(p));
+
if (found) {
if (unlink(p) < 0 && errno != ENOENT) {
Set *remove_symlinks_to,
const char *config_path,
UnitFileChange **changes,
- unsigned *n_changes) {
+ unsigned *n_changes,
+ char** files) {
int fd, r = 0;
bool deleted;
}
/* This takes possession of cfd and closes it */
- q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes);
+ q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, files);
if (r == 0)
r = q;
} while (deleted);
STRV_FOREACH(i, files) {
char *path;
- if (!unit_name_is_valid_no_type(*i, true)) {
+ if (!unit_name_is_valid(*i, true)) {
if (r == 0)
r = -EINVAL;
continue;
STRV_FOREACH(i, files) {
char *path;
- if (!unit_name_is_valid_no_type(*i, true)) {
+ if (!unit_name_is_valid(*i, true)) {
if (r == 0)
r = -EINVAL;
continue;
finish:
- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+ q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
if (r == 0)
r = q;
fn = path_get_file_name(*i);
if (!path_is_absolute(*i) ||
- !unit_name_is_valid_no_type(fn, true)) {
+ !unit_name_is_valid(fn, true)) {
if (r == 0)
r = -EINVAL;
continue;
free(i->path);
strv_free(i->aliases);
strv_free(i->wanted_by);
+ strv_free(i->required_by);
free(i);
}
if (!name)
name = path_get_file_name(path);
- if (!unit_name_is_valid_no_type(name, true))
+ if (!unit_name_is_valid(name, true))
return -EINVAL;
if (hashmap_get(c->have_installed, name) ||
bool allow_symlink) {
const ConfigTableItem items[] = {
- { "Install", "Alias", config_parse_strv, 0, &info->aliases },
- { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
- { "Install", "Also", config_parse_also, 0, c },
+ { "Install", "Alias", config_parse_strv, 0, &info->aliases },
+ { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
+ { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
+ { "Install", "Also", config_parse_also, 0, c },
{ NULL, NULL, NULL, 0, NULL }
};
if (r < 0)
return r;
- return strv_length(info->aliases) + strv_length(info->wanted_by);
+ return
+ strv_length(info->aliases) +
+ strv_length(info->wanted_by) +
+ strv_length(info->required_by);
}
static int unit_file_search(
if (r >= 0)
info->path = path;
- else
+ else {
+ if (r == -ENOENT && unit_name_is_instance(info->name)) {
+ /* unit file doesn't exist, however instance enablement was request */
+ /* we will check if it is possible to load template unit file */
+ char *template = NULL,
+ *template_path = NULL,
+ *template_dir = NULL;
+
+ template = unit_name_template(info->name);
+ if (!template) {
+ free(path);
+ return -ENOMEM;
+ }
+
+ /* we will reuse path variable since we don't need it anymore */
+ template_dir = path;
+ *(strrchr(path, '/') + 1) = '\0';
+
+ template_path = strjoin(template_dir, template, NULL);
+ if (!template_path) {
+ free(path);
+ free(template);
+ return -ENOMEM;
+ }
+
+ /* let's try to load template unit */
+ r = unit_file_load(c, info, template_path, allow_symlink);
+ if (r >= 0) {
+ info->path = strdup(template_path);
+ if (!info->path) {
+ free(path);
+ free(template);
+ free(template_path);
+ return -ENOMEM;
+ }
+ }
+
+ free(template);
+ free(template_path);
+ }
free(path);
+ }
if (r != -ENOENT && r != -ELOOP)
return r;
r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
if (r >= 0)
- r = strv_length(i->aliases) + strv_length(i->wanted_by);
+ r =
+ strv_length(i->aliases) +
+ strv_length(i->wanted_by) +
+ strv_length(i->required_by);
install_context_done(&c);
assert(old_path);
assert(new_path);
- mkdir_parents(new_path, 0755);
+ mkdir_parents_label(new_path, 0755);
if (symlink(old_path, new_path) >= 0) {
add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
free(dest);
- if (force)
+ if (!force)
return -EEXIST;
unlink(new_path);
STRV_FOREACH(s, i->wanted_by) {
char *path;
- if (!unit_name_is_valid_no_type(*s, true)) {
+ if (!unit_name_is_valid(*s, true)) {
r = -EINVAL;
continue;
}
return r;
}
+static int install_info_symlink_requires(
+ InstallInfo *i,
+ const char *config_path,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes) {
+
+ char **s;
+ int r = 0, q;
+
+ assert(i);
+ assert(config_path);
+
+ STRV_FOREACH(s, i->required_by) {
+ char *path;
+
+ if (!unit_name_is_valid(*s, true)) {
+ r = -EINVAL;
+ continue;
+ }
+
+ if (asprintf(&path, "%s/%s.requires/%s", config_path, *s, i->name) < 0)
+ return -ENOMEM;
+
+ q = create_symlink(i->path, path, force, changes, n_changes);
+ free(path);
+
+ if (r == 0)
+ r = q;
+ }
+
+ return r;
+}
+
static int install_info_symlink_link(
InstallInfo *i,
LookupPaths *paths,
if (r == 0)
r = q;
+ q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
+ if (r == 0)
+ r = q;
+
q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
if (r == 0)
r = q;
} else if (r >= 0)
r += q;
- q = mark_symlink_for_removal(remove_symlinks_to, i->name);
+ if (unit_name_is_instance(i->name)) {
+ char *unit_file = NULL;
+
+ unit_file = path_get_file_name(i->path);
+
+ if (unit_name_is_instance(unit_file))
+ /* unit file named as instance exists, thus all symlinks pointing to it, will be removed */
+ q = mark_symlink_for_removal(remove_symlinks_to, i->name);
+ else
+ /* does not exist, thus we will mark for removal symlinks to template unit file */
+ q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
+ } else
+ q = mark_symlink_for_removal(remove_symlinks_to, i->name);
+
if (r >= 0 && q < 0)
r = q;
}
r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+ q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
if (r == 0)
r = q;
goto finish;
}
- r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+ r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
/* Returns number of symlinks that where supposed to be installed. */
q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
if (root_dir && scope != UNIT_FILE_SYSTEM)
return -EINVAL;
- if (!unit_name_is_valid_no_type(name, true))
+ if (!unit_name_is_valid(name, true))
return -EINVAL;
r = lookup_paths_init_from_scope(&paths, scope);
if (scope == UNIT_FILE_SYSTEM)
r = conf_files_list(&files, ".preset",
- "/etc/systemd/system.preset",
- "/usr/local/lib/systemd/system.preset",
- "/usr/lib/systemd/system.preset",
- "/lib/systemd/system.preset",
+ "/etc/systemd/system-preset",
+ "/usr/local/lib/systemd/system-preset",
+ "/usr/lib/systemd/system-preset",
+#ifdef HAVE_SPLIT_USR
+ "/lib/systemd/system-preset",
+#endif
NULL);
else if (scope == UNIT_FILE_GLOBAL)
r = conf_files_list(&files, ".preset",
- "/etc/systemd/user.preset",
- "/usr/local/lib/systemd/user.preset",
- "/usr/lib/systemd/user.preset",
+ "/etc/systemd/user-preset",
+ "/usr/local/lib/systemd/user-preset",
+ "/usr/lib/systemd/user-preset",
NULL);
else
return 1;
STRV_FOREACH(i, files) {
- if (!unit_name_is_valid_no_type(*i, true)) {
+ if (!unit_name_is_valid(*i, true)) {
r = -EINVAL;
goto finish;
}
r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+ q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
if (r == 0)
r = q;
if (ignore_file(de->d_name))
continue;
- if (!unit_name_is_valid_no_type(de->d_name, true))
+ if (!unit_name_is_valid(de->d_name, true))
continue;
if (hashmap_get(h, de->d_name))
free(f->path);
free(f);
goto finish;
- } else if (r > 0)
+ } else if (r > 0) {
+ f->state = UNIT_FILE_ENABLED;
goto found;
+ }
r = unit_file_can_install(&paths, root_dir, f->path, true);
- if (r < 0) {
+ if (r == -EINVAL || /* Invalid setting? */
+ r == -EBADMSG || /* Invalid format? */
+ r == -ENOENT /* Included file not found? */)
+ f->state = UNIT_FILE_INVALID;
+ else if (r < 0) {
free(f->path);
free(f);
goto finish;
- } else if (r > 0) {
+ } else if (r > 0)
f->state = UNIT_FILE_DISABLED;
- goto found;
- } else {
+ else
f->state = UNIT_FILE_STATIC;
- goto found;
- }
-
- free(f->path);
- free(f);
- continue;
found:
r = hashmap_put(h, path_get_file_name(f->path), f);
[UNIT_FILE_MASKED] = "masked",
[UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
[UNIT_FILE_STATIC] = "static",
- [UNIT_FILE_DISABLED] = "disabled"
+ [UNIT_FILE_DISABLED] = "disabled",
+ [UNIT_FILE_INVALID] = "invalid",
};
DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);