#include "mkdir.h"
#include "hashmap.h"
#include "set.h"
+#include "path-util.h"
#include "path-lookup.h"
#include "strv.h"
#include "unit-name.h"
char **aliases;
char **wanted_by;
+ char **required_by;
} InstallInfo;
typedef struct {
zero(*paths);
return lookup_paths_init(paths,
- scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
- scope == UNIT_FILE_USER);
+ scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_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;
- struct dirent buffer, *de;
assert(remove_symlinks_to);
assert(fd >= 0);
rewinddir(d);
for (;;) {
+ struct dirent *de;
+ union dirent_storage buf;
int k;
- k = readdir_r(d, &buffer, &de);
+ k = readdir_r(d, &buf.de, &de);
if (k != 0) {
r = -errno;
break;
}
/* 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)
found =
set_get(remove_symlinks_to, dest) ||
- set_get(remove_symlinks_to, file_name_from_path(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) {
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);
int r = 0;
DIR *d;
- struct dirent buffer, *de;
assert(name);
assert(fd >= 0);
for (;;) {
int k;
+ struct dirent *de;
+ union dirent_storage buf;
- k = readdir_r(d, &buffer, &de);
+ k = readdir_r(d, &buf.de, &de);
if (k != 0) {
r = -errno;
break;
if (path_is_absolute(name))
found_dest = path_equal(dest, name);
else
- found_dest = streq(file_name_from_path(dest), name);
+ found_dest = streq(path_get_file_name(dest), name);
free(dest);
assert(same_name_link);
fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
- if (fd < 0)
+ if (fd < 0) {
+ if (errno == ENOENT)
+ return 0;
return -errno;
+ }
/* This takes possession of fd and closes it */
return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
UnitFileState *state) {
int r;
- char *path;
+ char _cleanup_free_ *path = NULL;
bool same_name_link_runtime = false, same_name_link = false;
assert(scope >= 0);
return r;
r = find_symlinks(name, path, &same_name_link_runtime);
- free(path);
-
if (r < 0)
return r;
else if (r > 0) {
return r;
r = find_symlinks(name, path, &same_name_link);
- free(path);
-
if (r < 0)
return r;
else if (r > 0) {
UnitFileChange **changes,
unsigned *n_changes) {
- char **i, *prefix;
+ char **i;
+ char _cleanup_free_ *prefix;
int r;
assert(scope >= 0);
return r;
STRV_FOREACH(i, files) {
- char *path;
+ char _cleanup_free_ *path = NULL;
- if (!unit_name_is_valid_no_type(*i, true)) {
+ if (!unit_name_is_valid(*i, true)) {
if (r == 0)
r = -EINVAL;
continue;
if (symlink("/dev/null", path) >= 0) {
add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
- free(path);
continue;
}
if (errno == EEXIST) {
- if (null_or_empty_path(path) > 0) {
- free(path);
+ if (null_or_empty_path(path) > 0)
continue;
- }
if (force) {
unlink(path);
add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
- free(path);
continue;
}
}
if (r == 0)
r = -errno;
}
-
- free(path);
}
- free(prefix);
-
return r;
}
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;
char *path, *fn;
struct stat st;
- fn = file_name_from_path(*i);
+ 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);
}
assert(name || path);
if (!name)
- name = file_name_from_path(path);
+ 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;
}
/* This will return the number of symlink rules that were
supposed to be created, not the ones actually created. This is
- useful to determine whether the passed files hat any
+ useful to determine whether the passed files had any
installation data at all. */
r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
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;
return r;
STRV_FOREACH(i, paths.unit_path) {
- struct dirent buffer, *de;
const char *units_dir;
free(buf);
}
for (;;) {
+ struct dirent *de;
+ union dirent_storage buffer;
UnitFileList *f;
- r = readdir_r(d, &buffer, &de);
+ r = readdir_r(d, &buffer.de, &de);
if (r != 0) {
r = -r;
goto finish;
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, file_name_from_path(f->path), f);
+ r = hashmap_put(h, path_get_file_name(f->path), f);
if (r < 0) {
free(f->path);
free(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);