/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "alloc-util.h"
-#include "fileio.h"
#include "fs-util.h"
#include "install.h"
#include "log.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
+#include "tmpfile-util.h"
#include "user-util.h"
#include "util.h"
data_dirs = strv_split(e, ":");
else
data_dirs = strv_new("/usr/local/share",
- "/usr/share",
- NULL);
+ "/usr/share");
if (!data_dirs)
return -ENOMEM;
- *ret_config_dirs = config_dirs;
- *ret_data_dirs = data_dirs;
- config_dirs = data_dirs = NULL;
+ *ret_config_dirs = TAKE_PTR(config_dirs);
+ *ret_data_dirs = TAKE_PTR(data_dirs);
+
return 0;
}
_cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
_cleanup_free_ char *data_home = NULL;
_cleanup_strv_free_ char **res = NULL;
- char **tmp;
int r;
r = xdg_user_dirs(&config_dirs, &data_dirs);
if (path_strv_make_absolute_cwd(res) < 0)
return NULL;
- tmp = res;
- res = NULL;
-
- return tmp;
+ return TAKE_PTR(res);
}
bool path_is_user_data_dir(const char *path) {
if (tempdir)
prefix = tempdir;
-
else if (scope == UNIT_FILE_SYSTEM)
prefix = "/run/systemd";
-
- else if (scope == UNIT_FILE_USER) {
+ else {
+ /* UNIT_FILE_USER */
const char *e;
e = getenv("XDG_RUNTIME_DIR");
if (!z)
return -ENOMEM;
- *generator = x;
- *generator_early = y;
- *generator_late = z;
+ *generator = TAKE_PTR(x);
+ *generator_early = TAKE_PTR(y);
+ *generator_late = TAKE_PTR(z);
- x = y = z = NULL;
return 0;
}
*runtime = NULL;
}
- *persistent = a;
- a = NULL;
+ *persistent = TAKE_PTR(a);
return 0;
if (!a || !b)
return -ENOMEM;
- *persistent = a;
- *runtime = b;
- a = b = NULL;
+ *persistent = TAKE_PTR(a);
+ *runtime = TAKE_PTR(b);
return 0;
}
if (!b)
return -ENOMEM;
- *runtime = b;
- b = NULL;
+ *runtime = TAKE_PTR(b);
break;
}
assert_not_reached("Hmm, unexpected scope value.");
}
- *persistent = a;
- a = NULL;
+ *persistent = TAKE_PTR(a);
+
+ return 0;
+}
+
+static int acquire_attached_dirs(
+ UnitFileScope scope,
+ char **ret_persistent,
+ char **ret_runtime) {
+
+ _cleanup_free_ char *a = NULL, *b = NULL;
+
+ assert(ret_persistent);
+ assert(ret_runtime);
+
+ /* Portable services are not available to regular users for now. */
+ if (scope != UNIT_FILE_SYSTEM)
+ return -EOPNOTSUPP;
+
+ a = strdup("/etc/systemd/system.attached");
+ if (!a)
+ return -ENOMEM;
+
+ b = strdup("/run/systemd/system.attached");
+ if (!b)
+ return -ENOMEM;
+
+ *ret_persistent = TAKE_PTR(a);
+ *ret_runtime = TAKE_PTR(b);
return 0;
}
*global_persistent_config = NULL, *global_runtime_config = NULL,
*generator = NULL, *generator_early = NULL, *generator_late = NULL,
*transient = NULL,
- *persistent_control = NULL, *runtime_control = NULL;
+ *persistent_control = NULL, *runtime_control = NULL,
+ *persistent_attached = NULL, *runtime_attached = NULL;
bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
_cleanup_strv_free_ char **paths = NULL;
const char *e;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- if (!isempty(root_dir) && !path_equal(root_dir, "/")) {
+#if HAVE_SPLIT_USR
+ flags |= LOOKUP_PATHS_SPLIT_USR;
+#endif
+
+ if (!empty_or_root(root_dir)) {
if (scope == UNIT_FILE_USER)
return -EINVAL;
if (flags & LOOKUP_PATHS_TEMPORARY_GENERATED) {
r = mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir);
if (r < 0)
- return log_error_errno(r, "Failed to create temporary directory: %m");
+ return log_debug_errno(r, "Failed to create temporary directory: %m");
}
/* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
if (r < 0 && r != -EOPNOTSUPP)
return r;
+ r = acquire_attached_dirs(scope, &persistent_attached, &runtime_attached);
+ if (r < 0 && r != -EOPNOTSUPP)
+ return r;
+
/* First priority is whatever has been passed to us via env vars */
e = getenv("SYSTEMD_UNIT_PATH");
if (e) {
persistent_config,
SYSTEM_CONFIG_UNIT_PATH,
"/etc/systemd/system",
+ STRV_IFNOTNULL(persistent_attached),
runtime_config,
"/run/systemd/system",
+ STRV_IFNOTNULL(runtime_attached),
STRV_IFNOTNULL(generator),
"/usr/local/lib/systemd/system",
SYSTEM_DATA_UNIT_PATH,
"/usr/lib/systemd/system",
-#if HAVE_SPLIT_USR
- "/lib/systemd/system",
-#endif
- STRV_IFNOTNULL(generator_late),
- NULL);
+ STRV_IFNOTNULL(flags & LOOKUP_PATHS_SPLIT_USR ? "/lib/systemd/system" : NULL),
+ STRV_IFNOTNULL(generator_late));
break;
case UNIT_FILE_GLOBAL:
"/usr/local/lib/systemd/user",
USER_DATA_UNIT_PATH,
"/usr/lib/systemd/user",
- STRV_IFNOTNULL(generator_late),
- NULL);
+ STRV_IFNOTNULL(generator_late));
break;
case UNIT_FILE_USER:
r = strv_extend_strv(&paths, add, true);
if (r < 0)
return r;
- } else {
+ } else
/* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
* and don't have to copy anything */
- paths = add;
- add = NULL;
- }
+ paths = TAKE_PTR(add);
}
r = patch_root_prefix(&persistent_config, root);
r = patch_root_prefix(&persistent_control, root);
if (r < 0)
return r;
-
r = patch_root_prefix(&runtime_control, root);
if (r < 0)
return r;
+ r = patch_root_prefix(&persistent_attached, root);
+ if (r < 0)
+ return r;
+ r = patch_root_prefix(&runtime_attached, root);
+ if (r < 0)
+ return r;
+
r = patch_root_prefix_strv(paths, root);
if (r < 0)
return -ENOMEM;
- p->search_path = strv_uniq(paths);
- paths = NULL;
+ *p = (LookupPaths) {
+ .search_path = strv_uniq(paths),
- p->persistent_config = persistent_config;
- p->runtime_config = runtime_config;
- persistent_config = runtime_config = NULL;
+ .persistent_config = TAKE_PTR(persistent_config),
+ .runtime_config = TAKE_PTR(runtime_config),
- p->generator = generator;
- p->generator_early = generator_early;
- p->generator_late = generator_late;
- generator = generator_early = generator_late = NULL;
+ .generator = TAKE_PTR(generator),
+ .generator_early = TAKE_PTR(generator_early),
+ .generator_late = TAKE_PTR(generator_late),
- p->transient = transient;
- transient = NULL;
+ .transient = TAKE_PTR(transient),
- p->persistent_control = persistent_control;
- p->runtime_control = runtime_control;
- persistent_control = runtime_control = NULL;
+ .persistent_control = TAKE_PTR(persistent_control),
+ .runtime_control = TAKE_PTR(runtime_control),
- p->root_dir = root;
- root = NULL;
+ .persistent_attached = TAKE_PTR(persistent_attached),
+ .runtime_attached = TAKE_PTR(runtime_attached),
- p->temporary_dir = tempdir;
- tempdir = NULL;
+ .root_dir = TAKE_PTR(root),
+ .temporary_dir = TAKE_PTR(tempdir),
+ };
+ paths = NULL;
return 0;
}
p->persistent_config = mfree(p->persistent_config);
p->runtime_config = mfree(p->runtime_config);
+ p->persistent_attached = mfree(p->persistent_attached);
+ p->runtime_attached = mfree(p->runtime_attached);
+
p->generator = mfree(p->generator);
p->generator_early = mfree(p->generator_early);
p->generator_late = mfree(p->generator_late);
int lookup_paths_reduce(LookupPaths *p) {
_cleanup_free_ struct stat *stats = NULL;
size_t n_stats = 0, allocated = 0;
- unsigned c = 0;
+ size_t c = 0;
int r;
assert(p);
/* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
- * the same by comparing their device and inode numbers. Note one special tweak: when we have a root path set,
- * we do not follow symlinks when retrieving them, because the kernel wouldn't take the root prefix into
- * account when following symlinks. When we have no root path set this restriction does not apply however. */
+ * the same by comparing their device and inode numbers. */
if (!p->search_path)
return 0;
while (p->search_path[c]) {
struct stat st;
- unsigned k;
+ size_t k;
/* Never strip the transient and control directories from the path */
if (path_equal_ptr(p->search_path[c], p->transient) ||
continue;
}
- if (p->root_dir)
- r = lstat(p->search_path[c], &st);
- else
- r = stat(p->search_path[c], &st);
+ r = chase_symlinks_and_stat(p->search_path[c], p->root_dir, 0, NULL, &st);
+ if (r == -ENOENT)
+ goto remove_item;
if (r < 0) {
- if (errno == ENOENT)
- goto remove_item;
-
/* If something we don't grok happened, let's better leave it in. */
- log_debug_errno(errno, "Failed to stat %s: %m", p->search_path[c]);
+ log_debug_errno(r, "Failed to chase and stat %s: %m", p->search_path[c]);
c++;
continue;
}
- for (k = 0; k < n_stats; k++) {
+ for (k = 0; k < n_stats; k++)
if (stats[k].st_dev == st.st_dev &&
stats[k].st_ino == st.st_ino)
break;
- }
if (k < n_stats) /* Is there already an entry with the same device/inode? */
goto remove_item;
/* Flush the generated unit files in full */
if (p->generator)
- (void) rm_rf(p->generator, REMOVE_ROOT);
+ (void) rm_rf(p->generator, REMOVE_ROOT|REMOVE_PHYSICAL);
if (p->generator_early)
- (void) rm_rf(p->generator_early, REMOVE_ROOT);
+ (void) rm_rf(p->generator_early, REMOVE_ROOT|REMOVE_PHYSICAL);
if (p->generator_late)
- (void) rm_rf(p->generator_late, REMOVE_ROOT);
+ (void) rm_rf(p->generator_late, REMOVE_ROOT|REMOVE_PHYSICAL);
if (p->temporary_dir)
- (void) rm_rf(p->temporary_dir, REMOVE_ROOT);
+ (void) rm_rf(p->temporary_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
}
char **generator_binary_paths(UnitFileScope scope) {
return strv_new("/run/systemd/system-generators",
"/etc/systemd/system-generators",
"/usr/local/lib/systemd/system-generators",
- SYSTEM_GENERATOR_PATH,
- NULL);
+ SYSTEM_GENERATOR_PATH);
case UNIT_FILE_GLOBAL:
case UNIT_FILE_USER:
return strv_new("/run/systemd/user-generators",
"/etc/systemd/user-generators",
"/usr/local/lib/systemd/user-generators",
- USER_GENERATOR_PATH,
- NULL);
+ USER_GENERATOR_PATH);
default:
assert_not_reached("Hmm, unexpected scope.");