#include "install.h"
#include "conf-parser.h"
#include "conf-files.h"
-
-typedef struct {
- char *name;
- char *path;
-
- char **aliases;
- char **wanted_by;
- char **required_by;
-} InstallInfo;
+#include "specifier.h"
+#include "install-printf.h"
+#include "special.h"
typedef struct {
Hashmap *will_install;
Hashmap *have_installed;
} InstallContext;
-static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
+#define _cleanup_install_context_done_ _cleanup_(install_context_done)
+
+static int lookup_paths_init_from_scope(LookupPaths *paths,
+ UnitFileScope scope,
+ const char *root_dir) {
assert(paths);
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
return lookup_paths_init(paths,
scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
scope == UNIT_FILE_USER,
+ root_dir,
NULL, NULL, NULL);
}
path_kill_slashes(n);
- r = set_put(*remove_symlinks_to, n);
- if (r < 0) {
- free(n);
+ r = set_consume(*remove_symlinks_to, n);
+ if (r < 0)
return r == -EEXIST ? 0 : r;
- }
return 0;
}
char** files) {
int r = 0;
- DIR *d;
+ _cleanup_closedir_ DIR *d = NULL;
assert(remove_symlinks_to);
assert(fd >= 0);
d = fdopendir(fd);
if (!d) {
- close_nointr_nofail(fd);
+ safe_close(fd);
return -errno;
}
for (;;) {
struct dirent *de;
- union dirent_storage buf;
- int k;
- k = readdir_r(d, &buf.de, &de);
- if (k != 0) {
+ errno = 0;
+ de = readdir(d);
+ if (!de && errno != 0) {
r = -errno;
break;
}
if (de->d_type == DT_DIR) {
int nfd, q;
- char *p;
+ _cleanup_free_ char *p = NULL;
nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
if (nfd < 0) {
p = path_make_absolute(de->d_name, path);
if (!p) {
- close_nointr_nofail(nfd);
- r = -ENOMEM;
- break;
+ safe_close(nfd);
+ return -ENOMEM;
}
/* 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, files);
- free(p);
if (r == 0)
r = q;
} else if (de->d_type == DT_LNK) {
- char *p, *dest;
+ _cleanup_free_ char *p = NULL, *dest = NULL;
int q;
bool found;
p = path_make_absolute(de->d_name, path);
- if (!p) {
- r = -ENOMEM;
- break;
- }
+ if (!p)
+ return -ENOMEM;
q = readlink_and_canonicalize(p, &dest);
if (q < 0) {
- free(p);
-
if (q == -ENOENT)
continue;
found =
set_get(remove_symlinks_to, dest) ||
- set_get(remove_symlinks_to, path_get_file_name(dest));
+ set_get(remove_symlinks_to, basename(dest));
if (unit_name_is_instance(p))
- found = found && strv_contains(files, path_get_file_name(p));
+ found = found && strv_contains(files, basename(p));
if (found) {
}
}
}
-
- free(p);
- free(dest);
}
}
- closedir(d);
-
return r;
}
int q, cfd;
deleted = false;
- cfd = dup(fd);
+ cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (cfd < 0) {
r = -errno;
break;
r = q;
} while (deleted);
- close_nointr_nofail(fd);
+ safe_close(fd);
return r;
}
bool *same_name_link) {
int r = 0;
- DIR *d;
+ _cleanup_closedir_ DIR *d = NULL;
assert(name);
assert(fd >= 0);
d = fdopendir(fd);
if (!d) {
- close_nointr_nofail(fd);
+ safe_close(fd);
return -errno;
}
for (;;) {
- int k;
struct dirent *de;
- union dirent_storage buf;
- k = readdir_r(d, &buf.de, &de);
- if (k != 0) {
- r = -errno;
- break;
- }
+ errno = 0;
+ de = readdir(d);
+ if (!de && errno != 0)
+ return -errno;
if (!de)
- break;
+ return r;
if (ignore_file(de->d_name))
continue;
if (de->d_type == DT_DIR) {
int nfd, q;
- char *p;
+ _cleanup_free_ char *p = NULL;
nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
if (nfd < 0) {
p = path_make_absolute(de->d_name, path);
if (!p) {
- close_nointr_nofail(nfd);
- r = -ENOMEM;
- break;
+ safe_close(nfd);
+ return -ENOMEM;
}
/* This will close nfd, regardless whether it succeeds or not */
q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
- free(p);
- if (q > 0) {
- r = 1;
- break;
- }
+ if (q > 0)
+ return 1;
if (r == 0)
r = q;
} else if (de->d_type == DT_LNK) {
- char *p, *dest;
+ _cleanup_free_ char *p = NULL, *dest = NULL;
bool found_path, found_dest, b = false;
int q;
/* Acquire symlink name */
p = path_make_absolute(de->d_name, path);
- if (!p) {
- r = -ENOMEM;
- break;
- }
+ if (!p)
+ return -ENOMEM;
/* Acquire symlink destination */
q = readlink_and_canonicalize(p, &dest);
if (q < 0) {
- free(p);
-
if (q == -ENOENT)
continue;
if (path_is_absolute(name))
found_dest = path_equal(dest, name);
else
- found_dest = streq(path_get_file_name(dest), name);
-
- free(dest);
+ found_dest = streq(basename(dest), name);
if (found_path && found_dest) {
- char *t;
+ _cleanup_free_ char *t = NULL;
/* Filter out same name links in the main
* config path */
t = path_make_absolute(name, config_path);
- if (!t) {
- free(p);
- r = -ENOMEM;
- break;
- }
+ if (!t)
+ return -ENOMEM;
b = path_equal(t, p);
- free(t);
}
- free(p);
-
if (b)
*same_name_link = true;
- else if (found_path || found_dest) {
- r = 1;
- break;
- }
+ else if (found_path || found_dest)
+ return 1;
}
}
-
- closedir(d);
-
- return r;
}
static int find_symlinks(
UnitFileState *state) {
int r;
- char _cleanup_free_ *path = NULL;
+ _cleanup_free_ char *path2 = NULL;
bool same_name_link_runtime = false, same_name_link = false;
assert(scope >= 0);
assert(name);
if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
+ _cleanup_free_ char *path = NULL;
/* First look in runtime config path */
r = get_config_path(scope, true, root_dir, &path);
}
/* Then look in the normal config path */
- r = get_config_path(scope, false, root_dir, &path);
+ r = get_config_path(scope, false, root_dir, &path2);
if (r < 0)
return r;
- r = find_symlinks(name, path, &same_name_link);
+ r = find_symlinks(name, path2, &same_name_link);
if (r < 0)
return r;
else if (r > 0) {
UnitFileScope scope,
bool runtime,
const char *root_dir,
- char *files[],
+ char **files,
bool force,
UnitFileChange **changes,
unsigned *n_changes) {
char **i;
- char _cleanup_free_ *prefix;
+ _cleanup_free_ char *prefix;
int r;
assert(scope >= 0);
return r;
STRV_FOREACH(i, files) {
- char _cleanup_free_ *path = NULL;
+ _cleanup_free_ char *path = NULL;
- if (!unit_name_is_valid(*i, true)) {
+ if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
if (r == 0)
r = -EINVAL;
continue;
UnitFileScope scope,
bool runtime,
const char *root_dir,
- char *files[],
+ char **files,
UnitFileChange **changes,
unsigned *n_changes) {
STRV_FOREACH(i, files) {
char *path;
- if (!unit_name_is_valid(*i, true)) {
+ if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
if (r == 0)
r = -EINVAL;
continue;
UnitFileScope scope,
bool runtime,
const char *root_dir,
- char *files[],
+ char **files,
bool force,
UnitFileChange **changes,
unsigned *n_changes) {
- LookupPaths paths;
- char **i, *config_path = NULL;
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ char **i;
+ _cleanup_free_ char *config_path = NULL;
int r, q;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- zero(paths);
-
- r = lookup_paths_init_from_scope(&paths, scope);
+ r = lookup_paths_init_from_scope(&paths, scope, root_dir);
if (r < 0)
return r;
r = get_config_path(scope, runtime, root_dir, &config_path);
if (r < 0)
- goto finish;
+ return r;
STRV_FOREACH(i, files) {
- char *path, *fn;
+ _cleanup_free_ char *path = NULL;
+ char *fn;
struct stat st;
- fn = path_get_file_name(*i);
+ fn = basename(*i);
if (!path_is_absolute(*i) ||
- !unit_name_is_valid(fn, true)) {
+ !unit_name_is_valid(fn, TEMPLATE_VALID)) {
if (r == 0)
r = -EINVAL;
continue;
}
q = in_search_path(*i, paths.unit_path);
- if (q < 0) {
- r = q;
- break;
- }
+ if (q < 0)
+ return q;
if (q > 0)
continue;
path = path_make_absolute(fn, config_path);
- if (!path) {
- r = -ENOMEM;
- break;
- }
+ if (!path)
+ return -ENOMEM;
if (symlink(*i, path) >= 0) {
add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
-
- free(path);
continue;
}
if (errno == EEXIST) {
- char *dest = NULL;
+ _cleanup_free_ char *dest = NULL;
q = readlink_and_make_absolute(path, &dest);
if (q < 0 && errno != ENOENT) {
- free(path);
-
if (r == 0)
r = q;
-
continue;
}
- if (q >= 0 && path_equal(dest, *i)) {
- free(dest);
- free(path);
+ if (q >= 0 && path_equal(dest, *i))
continue;
- }
-
- free(dest);
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, *i);
- free(path);
continue;
}
}
if (r == 0)
r = -errno;
}
-
- free(path);
}
- finish:
- lookup_paths_free(&paths);
- free(config_path);
-
return r;
}
assert(name || path);
if (!name)
- name = path_get_file_name(path);
+ name = basename(path);
- if (!unit_name_is_valid(name, true))
+ if (!unit_name_is_valid(name, TEMPLATE_VALID))
return -EINVAL;
if (hashmap_get(c->have_installed, name) ||
return install_info_add(c, name_or_path, NULL);
}
-static int config_parse_also(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+static int config_parse_also(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
char *w;
size_t l;
assert(rvalue);
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- char *n;
+ _cleanup_free_ char *n;
int r;
n = strndup(w, l);
return -ENOMEM;
r = install_info_add(c, n, NULL);
- if (r < 0) {
- free(n);
+ if (r < 0)
return r;
- }
-
- free(n);
}
return 0;
}
+static int config_parse_user(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ InstallInfo *i = data;
+ char* printed;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = install_full_printf(i, rvalue, &printed);
+ if (r < 0)
+ return r;
+
+ free(i->user);
+ i->user = printed;
+
+ return 0;
+}
+
static int unit_file_load(
InstallContext *c,
InstallInfo *info,
{ "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 },
+ { "Exec", "User", config_parse_user, 0, info },
{ NULL, NULL, NULL, 0, NULL }
};
int fd;
- FILE *f;
+ _cleanup_fclose_ FILE *f = NULL;
int r;
assert(c);
f = fdopen(fd, "re");
if (!f) {
- close_nointr_nofail(fd);
+ safe_close(fd);
return -ENOMEM;
}
- r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
- fclose(f);
+ r = config_parse(NULL, path, f, NULL,
+ config_item_table_lookup, (void*) items, true, true, info);
if (r < 0)
return r;
return
- strv_length(info->aliases) +
- strv_length(info->wanted_by) +
- strv_length(info->required_by);
+ (int) strv_length(info->aliases) +
+ (int) strv_length(info->wanted_by) +
+ (int) strv_length(info->required_by);
}
static int unit_file_search(
assert(info);
assert(paths);
- if (info->path)
- return unit_file_load(c, info, info->path, allow_symlink);
+ if (info->path) {
+ char *full_path = NULL;
+
+ if (!isempty(root_dir))
+ full_path = strappenda(root_dir, info->path);
+
+ return unit_file_load(c, info, full_path ?: info->path, allow_symlink);
+ }
assert(info->name);
STRV_FOREACH(p, paths->unit_path) {
- char *path = NULL;
-
- if (isempty(root_dir))
- asprintf(&path, "%s/%s", *p, info->name);
- else
- asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
+ _cleanup_free_ char *path = NULL, *full_path = NULL;
+ path = strjoin(*p, "/", info->name, NULL);
if (!path)
return -ENOMEM;
- r = unit_file_load(c, info, path, allow_symlink);
+ if (!isempty(root_dir)) {
+ full_path = strappend(root_dir, path);
+ if (!full_path)
+ return -ENOMEM;
+ }
- if (r >= 0)
+ r = unit_file_load(c, info, full_path ?: path, allow_symlink);
+ if (r >= 0) {
info->path = path;
- 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);
+ path = NULL;
+ } else if (r == -ENOENT && unit_name_is_instance(info->name)) {
+ /* Unit file doesn't exist, however instance enablement was requested.
+ * We will check if it is possible to load template unit file. */
+ _cleanup_free_ char *template = NULL, *template_dir = NULL;
+
+ template = unit_name_template(info->name);
+ if (!template)
+ return -ENOMEM;
+
+ /* We will reuse path variable since we don't need it anymore. */
+ template_dir = path;
+ *(strrchr(template_dir, '/') + 1) = '\0';
+
+ path = strappend(template_dir, template);
+ if (!path)
+ return -ENOMEM;
+
+ if (!isempty(root_dir)) {
+ free(full_path);
+ full_path = strappend(root_dir, path);
+ if (!full_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);
+ /* Let's try to load template unit. */
+ r = unit_file_load(c, info, full_path ?: path, allow_symlink);
+ if (r >= 0) {
+ info->path = path;
+ path = NULL;
}
- free(path);
}
if (r != -ENOENT && r != -ELOOP)
const char *name,
bool allow_symlink) {
- InstallContext c;
+ _cleanup_install_context_done_ InstallContext c = {};
InstallInfo *i;
int r;
assert(paths);
assert(name);
- zero(c);
-
r = install_info_add_auto(&c, name);
if (r < 0)
return r;
if (r >= 0)
r =
- strv_length(i->aliases) +
- strv_length(i->wanted_by) +
- strv_length(i->required_by);
-
- install_context_done(&c);
+ (int) strv_length(i->aliases) +
+ (int) strv_length(i->wanted_by) +
+ (int) strv_length(i->required_by);
return r;
}
UnitFileChange **changes,
unsigned *n_changes) {
- char *dest;
+ _cleanup_free_ char *dest = NULL;
int r;
assert(old_path);
if (r < 0)
return r;
- if (path_equal(dest, old_path)) {
- free(dest);
+ if (path_equal(dest, old_path))
return 0;
- }
-
- free(dest);
if (!force)
return -EEXIST;
- unlink(new_path);
+ r = unlink(new_path);
+ if (r < 0 && errno != ENOENT)
+ return -errno;
if (symlink(old_path, new_path) >= 0) {
add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
assert(config_path);
STRV_FOREACH(s, i->aliases) {
- char *alias_path;
+ _cleanup_free_ char *alias_path = NULL, *dst = NULL;
- alias_path = path_make_absolute(*s, config_path);
+ q = install_full_printf(i, *s, &dst);
+ if (q < 0)
+ return q;
+ alias_path = path_make_absolute(dst, config_path);
if (!alias_path)
return -ENOMEM;
q = create_symlink(i->path, alias_path, force, changes, n_changes);
- free(alias_path);
-
if (r == 0)
r = q;
}
assert(config_path);
STRV_FOREACH(s, i->wanted_by) {
- char *path;
+ _cleanup_free_ char *path = NULL, *dst = NULL;
- if (!unit_name_is_valid(*s, true)) {
+ q = install_full_printf(i, *s, &dst);
+ if (q < 0)
+ return q;
+
+ if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
r = -EINVAL;
continue;
}
- if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0)
+ if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0)
return -ENOMEM;
q = create_symlink(i->path, path, force, changes, n_changes);
- free(path);
if (r == 0)
r = q;
assert(config_path);
STRV_FOREACH(s, i->required_by) {
- char *path;
+ _cleanup_free_ char *path = NULL, *dst = NULL;
- if (!unit_name_is_valid(*s, true)) {
+ q = install_full_printf(i, *s, &dst);
+ if (q < 0)
+ return q;
+
+ if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
r = -EINVAL;
continue;
}
- if (asprintf(&path, "%s/%s.requires/%s", config_path, *s, i->name) < 0)
+ if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0)
return -ENOMEM;
q = create_symlink(i->path, path, force, changes, n_changes);
- free(path);
if (r == 0)
r = q;
unsigned *n_changes) {
int r;
- char *path;
+ _cleanup_free_ char *path = NULL;
assert(i);
assert(paths);
return -ENOMEM;
r = create_symlink(i->path, path, force, changes, n_changes);
- free(path);
-
return r;
}
assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
q = unit_file_search(c, i, paths, root_dir, false);
- if (q < 0) {
+ if (q == -ENOENT) {
+ /* do nothing */
+ } else if (q < 0) {
if (r >= 0)
r = q;
r += q;
if (unit_name_is_instance(i->name)) {
- char *unit_file = NULL;
+ char *unit_file;
+
+ if (i->path) {
+ unit_file = basename(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 {
+ /* If i->path is not set, it means that we didn't actually find
+ * the unit file. But we can still remove symlinks to the
+ * nonexistent template. */
+ unit_file = unit_name_template(i->name);
+ if (!unit_file)
+ return log_oom();
- 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);
+ free(unit_file);
+ }
} else
q = mark_symlink_for_removal(remove_symlinks_to, i->name);
UnitFileScope scope,
bool runtime,
const char *root_dir,
- char *files[],
+ char **files,
bool force,
UnitFileChange **changes,
unsigned *n_changes) {
- LookupPaths paths;
- InstallContext c;
- char **i, *config_path = NULL;
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ _cleanup_install_context_done_ InstallContext c = {};
+ char **i;
+ _cleanup_free_ char *config_path = NULL;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- zero(paths);
- zero(c);
-
- r = lookup_paths_init_from_scope(&paths, scope);
+ r = lookup_paths_init_from_scope(&paths, scope, root_dir);
if (r < 0)
return r;
r = get_config_path(scope, runtime, root_dir, &config_path);
if (r < 0)
- goto finish;
+ return r;
STRV_FOREACH(i, files) {
r = install_info_add_auto(&c, *i);
if (r < 0)
- goto finish;
+ return r;
}
/* 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 had any
installation data at all. */
- r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
-
-finish:
- install_context_done(&c);
- lookup_paths_free(&paths);
- free(config_path);
- return r;
+ return install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
}
int unit_file_disable(
UnitFileScope scope,
bool runtime,
const char *root_dir,
- char *files[],
+ char **files,
UnitFileChange **changes,
unsigned *n_changes) {
- LookupPaths paths;
- InstallContext c;
- char **i, *config_path = NULL;
- Set *remove_symlinks_to = NULL;
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ _cleanup_install_context_done_ InstallContext c = {};
+ char **i;
+ _cleanup_free_ char *config_path = NULL;
+ _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
int r, q;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- zero(paths);
- zero(c);
-
- r = lookup_paths_init_from_scope(&paths, scope);
+ r = lookup_paths_init_from_scope(&paths, scope, root_dir);
if (r < 0)
return r;
r = get_config_path(scope, runtime, root_dir, &config_path);
if (r < 0)
- goto finish;
+ return r;
STRV_FOREACH(i, files) {
r = install_info_add_auto(&c, *i);
if (r < 0)
- goto finish;
+ return r;
}
r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
if (r == 0)
r = q;
-finish:
- install_context_done(&c);
- lookup_paths_free(&paths);
- set_free_free(remove_symlinks_to);
- free(config_path);
-
return r;
}
UnitFileScope scope,
bool runtime,
const char *root_dir,
- char *files[],
+ char **files,
bool force,
UnitFileChange **changes,
unsigned *n_changes) {
+ int r;
- LookupPaths paths;
- InstallContext c;
- char **i, *config_path = NULL;
- Set *remove_symlinks_to = NULL;
- int r, q;
+ r = unit_file_disable(scope, runtime, root_dir, files,
+ changes, n_changes);
+ if (r < 0)
+ return r;
+
+ return unit_file_enable(scope, runtime, root_dir, files, force,
+ changes, n_changes);
+}
+
+int unit_file_set_default(
+ UnitFileScope scope,
+ const char *root_dir,
+ const char *file,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes) {
+
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ _cleanup_install_context_done_ InstallContext c = {};
+ _cleanup_free_ char *config_path = NULL;
+ char *path;
+ int r;
+ InstallInfo *i = NULL;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(file);
- zero(paths);
- zero(c);
+ if (unit_name_to_type(file) != UNIT_TARGET)
+ return -EINVAL;
- r = lookup_paths_init_from_scope(&paths, scope);
+ r = lookup_paths_init_from_scope(&paths, scope, root_dir);
if (r < 0)
return r;
- r = get_config_path(scope, runtime, root_dir, &config_path);
+ r = get_config_path(scope, false, root_dir, &config_path);
if (r < 0)
- goto finish;
+ return r;
- STRV_FOREACH(i, files) {
- r = mark_symlink_for_removal(&remove_symlinks_to, *i);
- if (r < 0)
- goto finish;
+ r = install_info_add_auto(&c, file);
+ if (r < 0)
+ return r;
- r = install_info_add_auto(&c, *i);
- if (r < 0)
- goto finish;
- }
+ assert_se(i = hashmap_first(c.will_install));
- r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
+ r = unit_file_search(&c, i, &paths, root_dir, false);
+ if (r < 0)
+ return r;
- /* 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 (r == 0)
- r = q;
+ path = strappenda(config_path, "/" SPECIAL_DEFAULT_TARGET);
-finish:
- lookup_paths_free(&paths);
- install_context_done(&c);
- set_free_free(remove_symlinks_to);
- free(config_path);
+ r = create_symlink(i->path, path, force, changes, n_changes);
+ if (r < 0)
+ return r;
- return r;
+ return 0;
+}
+
+int unit_file_get_default(
+ UnitFileScope scope,
+ const char *root_dir,
+ char **name) {
+
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ char **p;
+ int r;
+
+ assert(scope >= 0);
+ assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(name);
+
+ r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, paths.unit_path) {
+ _cleanup_free_ char *path = NULL, *tmp = NULL;
+ char *n;
+
+ if (isempty(root_dir))
+ path = strappend(*p, "/" SPECIAL_DEFAULT_TARGET);
+ else
+ path = strjoin(root_dir, "/", *p, "/" SPECIAL_DEFAULT_TARGET, NULL);
+
+ if (!path)
+ return -ENOMEM;
+
+ r = readlink_malloc(path, &tmp);
+ if (r == -ENOENT)
+ continue;
+ else if (r == -EINVAL)
+ /* not a symlink */
+ n = strdup(SPECIAL_DEFAULT_TARGET);
+ else if (r < 0)
+ return r;
+ else
+ n = strdup(basename(tmp));
+
+ if (!n)
+ return -ENOMEM;
+
+ *name = n;
+ return 0;
+ }
+
+ return -ENOENT;
}
UnitFileState unit_file_get_state(
const char *root_dir,
const char *name) {
- LookupPaths paths;
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
UnitFileState state = _UNIT_FILE_STATE_INVALID;
- char **i, *path = NULL;
+ char **i;
+ _cleanup_free_ char *path = NULL;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(name);
- zero(paths);
-
if (root_dir && scope != UNIT_FILE_SYSTEM)
return -EINVAL;
- if (!unit_name_is_valid(name, true))
+ if (!unit_name_is_valid(name, TEMPLATE_VALID))
return -EINVAL;
- r = lookup_paths_init_from_scope(&paths, scope);
+ r = lookup_paths_init_from_scope(&paths, scope, root_dir);
if (r < 0)
return r;
STRV_FOREACH(i, paths.unit_path) {
struct stat st;
+ char *partial;
free(path);
path = NULL;
asprintf(&path, "%s/%s/%s", root_dir, *i, name);
else
asprintf(&path, "%s/%s", *i, name);
+ if (!path)
+ return -ENOMEM;
- if (!path) {
- r = -ENOMEM;
- goto finish;
- }
+ if (root_dir)
+ partial = path + strlen(root_dir) + 1;
+ else
+ partial = path;
+ /*
+ * Search for a unit file in our default paths, to
+ * be sure, that there are no broken symlinks.
+ */
if (lstat(path, &st) < 0) {
r = -errno;
- if (errno == ENOENT)
- continue;
+ if (errno != ENOENT)
+ return r;
- goto finish;
- }
-
- if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
- r = -ENOENT;
- goto finish;
- }
-
- r = null_or_empty_path(path);
- if (r < 0 && r != -ENOENT)
- goto finish;
- else if (r > 0) {
- state = path_startswith(*i, "/run") ?
- UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
- r = 0;
- goto finish;
+ if (!unit_name_is_instance(name))
+ continue;
+ } else {
+ if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
+ return -ENOENT;
+
+ r = null_or_empty_path(path);
+ if (r < 0 && r != -ENOENT)
+ return r;
+ else if (r > 0) {
+ state = path_startswith(*i, "/run") ?
+ UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
+ return state;
+ }
}
r = find_symlinks_in_scope(scope, root_dir, name, &state);
- if (r < 0) {
- goto finish;
- } else if (r > 0) {
- r = 0;
- goto finish;
- }
+ if (r < 0)
+ return r;
+ else if (r > 0)
+ return state;
- r = unit_file_can_install(&paths, root_dir, path, true);
- if (r < 0 && errno != -ENOENT)
- goto finish;
- else if (r > 0) {
- state = UNIT_FILE_DISABLED;
- r = 0;
- goto finish;
- } else if (r == 0) {
- state = UNIT_FILE_STATIC;
- r = 0;
- goto finish;
- }
+ r = unit_file_can_install(&paths, root_dir, partial, true);
+ if (r < 0 && errno != ENOENT)
+ return r;
+ else if (r > 0)
+ return UNIT_FILE_DISABLED;
+ else if (r == 0)
+ return UNIT_FILE_STATIC;
}
-finish:
- lookup_paths_free(&paths);
- free(path);
-
return r < 0 ? r : state;
}
int unit_file_query_preset(UnitFileScope scope, const char *name) {
- char **files, **i;
+ _cleanup_strv_free_ char **files = NULL;
+ char **i;
int r;
assert(scope >= 0);
assert(name);
if (scope == UNIT_FILE_SYSTEM)
- r = conf_files_list(&files, ".preset",
+ r = conf_files_list(&files, ".preset", NULL,
"/etc/systemd/system-preset",
"/usr/local/lib/systemd/system-preset",
"/usr/lib/systemd/system-preset",
#endif
NULL);
else if (scope == UNIT_FILE_GLOBAL)
- r = conf_files_list(&files, ".preset",
+ r = conf_files_list(&files, ".preset", NULL,
"/etc/systemd/user-preset",
"/usr/local/lib/systemd/user-preset",
"/usr/lib/systemd/user-preset",
return r;
STRV_FOREACH(i, files) {
- FILE *f;
+ _cleanup_fclose_ FILE *f;
f = fopen(*i, "re");
if (!f) {
if (errno == ENOENT)
continue;
- r = -errno;
- goto finish;
+ return -errno;
}
for (;;) {
if (!*l)
continue;
- if (strchr(COMMENTS, *l))
+ if (strchr(COMMENTS "\n", *l))
continue;
if (first_word(l, "enable")) {
l += 6;
l += strspn(l, WHITESPACE);
- if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
- r = 1;
- fclose(f);
- goto finish;
- }
+ if (fnmatch(l, name, FNM_NOESCAPE) == 0)
+ return 1;
+
} else if (first_word(l, "disable")) {
l += 7;
l += strspn(l, WHITESPACE);
- if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
- r = 0;
- fclose(f);
- goto finish;
- }
+ if (fnmatch(l, name, FNM_NOESCAPE) == 0)
+ return 0;
+
} else
log_debug("Couldn't parse line '%s'", l);
}
-
- fclose(f);
}
/* Default is "enable" */
- r = 1;
-
-finish:
- strv_free(files);
-
- return r;
+ return 1;
}
int unit_file_preset(
UnitFileScope scope,
bool runtime,
const char *root_dir,
- char *files[],
+ char **files,
bool force,
UnitFileChange **changes,
unsigned *n_changes) {
- LookupPaths paths;
- InstallContext plus, minus;
- char **i, *config_path = NULL;
- Set *remove_symlinks_to = NULL;
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ _cleanup_install_context_done_ InstallContext plus = {}, minus = {};
+ char **i;
+ _cleanup_free_ char *config_path = NULL;
+ _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
int r, q;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- zero(paths);
- zero(plus);
- zero(minus);
-
- r = lookup_paths_init_from_scope(&paths, scope);
+ r = lookup_paths_init_from_scope(&paths, scope, root_dir);
if (r < 0)
return r;
r = get_config_path(scope, runtime, root_dir, &config_path);
if (r < 0)
- goto finish;
+ return r;
STRV_FOREACH(i, files) {
- if (!unit_name_is_valid(*i, true)) {
- r = -EINVAL;
- goto finish;
- }
+ if (!unit_name_is_valid(*i, TEMPLATE_VALID))
+ return -EINVAL;
r = unit_file_query_preset(scope, *i);
if (r < 0)
- goto finish;
+ return r;
if (r)
r = install_info_add_auto(&plus, *i);
r = install_info_add_auto(&minus, *i);
if (r < 0)
- goto finish;
+ return r;
}
- r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
+ 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, files);
+ q = remove_marked_symlinks(remove_symlinks_to, config_path,
+ changes, n_changes, files);
if (r == 0)
r = q;
/* Returns number of symlinks that where supposed to be installed. */
- q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
+ q = install_context_apply(&plus, &paths, config_path, root_dir, force,
+ changes, n_changes);
if (r == 0)
r = q;
-finish:
- lookup_paths_free(&paths);
- install_context_done(&plus);
- install_context_done(&minus);
- set_free_free(remove_symlinks_to);
- free(config_path);
-
return r;
}
+static void unitfilelist_free(UnitFileList **f) {
+ if (!*f)
+ return;
+
+ free((*f)->path);
+ free(*f);
+}
+#define _cleanup_unitfilelist_free_ _cleanup_(unitfilelist_free)
+
int unit_file_get_list(
UnitFileScope scope,
const char *root_dir,
Hashmap *h) {
- LookupPaths paths;
- char **i, *buf = NULL;
- DIR *d = NULL;
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ char **i;
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_closedir_ DIR *d = NULL;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(h);
- zero(paths);
-
if (root_dir && scope != UNIT_FILE_SYSTEM)
return -EINVAL;
- r = lookup_paths_init_from_scope(&paths, scope);
+ r = lookup_paths_init_from_scope(&paths, scope, root_dir);
if (r < 0)
return r;
buf = NULL;
if (root_dir) {
- if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) {
- r = -ENOMEM;
- goto finish;
- }
+ if (asprintf(&buf, "%s/%s", root_dir, *i) < 0)
+ return -ENOMEM;
+
units_dir = buf;
} else
units_dir = *i;
if (errno == ENOENT)
continue;
- r = -errno;
- goto finish;
+ return -errno;
}
for (;;) {
struct dirent *de;
- union dirent_storage buffer;
- UnitFileList *f;
+ _cleanup_unitfilelist_free_ UnitFileList *f = NULL;
- r = readdir_r(d, &buffer.de, &de);
- if (r != 0) {
- r = -r;
- goto finish;
- }
+ errno = 0;
+ de = readdir(d);
+ if (!de && errno != 0)
+ return -errno;
if (!de)
break;
if (ignore_file(de->d_name))
continue;
- if (!unit_name_is_valid(de->d_name, true))
+ if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID))
continue;
if (hashmap_get(h, de->d_name))
if (r == -ENOENT)
continue;
- goto finish;
+ return r;
}
if (de->d_type != DT_LNK && de->d_type != DT_REG)
continue;
f = new0(UnitFileList, 1);
- if (!f) {
- r = -ENOMEM;
- goto finish;
- }
+ if (!f)
+ return -ENOMEM;
f->path = path_make_absolute(de->d_name, units_dir);
- if (!f->path) {
- free(f);
- r = -ENOMEM;
- goto finish;
- }
+ if (!f->path)
+ return -ENOMEM;
r = null_or_empty_path(f->path);
- if (r < 0 && r != -ENOENT) {
- free(f->path);
- free(f);
- goto finish;
- } else if (r > 0) {
+ if (r < 0 && r != -ENOENT)
+ return r;
+ else if (r > 0) {
f->state =
path_startswith(*i, "/run") ?
UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
}
r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
- if (r < 0) {
- free(f->path);
- free(f);
- goto finish;
- } else if (r > 0) {
+ if (r < 0)
+ return r;
+ else if (r > 0) {
f->state = UNIT_FILE_ENABLED;
goto found;
}
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)
+ return r;
+ else if (r > 0)
f->state = UNIT_FILE_DISABLED;
else
f->state = UNIT_FILE_STATIC;
found:
- r = hashmap_put(h, path_get_file_name(f->path), f);
- if (r < 0) {
- free(f->path);
- free(f);
- goto finish;
- }
+ r = hashmap_put(h, basename(f->path), f);
+ if (r < 0)
+ return r;
+ f = NULL; /* prevent cleanup */
}
}
-finish:
- lookup_paths_free(&paths);
- free(buf);
-
- if (d)
- closedir(d);
-
return r;
}