2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2014-07-02 12:23:36 +02:00
|
|
|
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "sd-path.h"
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2014-07-02 12:23:36 +02:00
|
|
|
#include "architecture.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2015-10-26 18:05:03 +01:00
|
|
|
#include "fileio.h"
|
2017-07-20 14:19:57 +02:00
|
|
|
#include "fs-util.h"
|
path: show various systemd directories and search paths too
So far we had various ad hoc APIs to query search paths:
systemd-analyze unit-paths, lookup_paths_log(), the pkgconfig file,
debug logs emitted by systemd-analyze cat-config.
But answering a simple question "what is the search path for tmpfiles,
sysusers, .network files, ..." is surprisingly hard.
I think we should have an api that makes it easy to query this. Pkgconfig is
not bad, but it is primarily a development tool, so it's not available in many
context. Also it can't provide support for paths which are influenced by
environment variables, and I'd like to be able to answer the question "what is
the search path for ..., assuming that VAR_FOO=... is set?".
Extending sd-path to support more of our internal paths seems to be most
flexible solution. We already have systemd-path which provides a nice
way to query, and we can add stuff like optional descriptions later on.
We we essentially get a nice programmatic and commmandline apis for the price
of one.
2020-03-24 16:04:50 +01:00
|
|
|
#include "path-lookup.h"
|
2014-07-02 12:23:36 +02:00
|
|
|
#include "path-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2014-07-02 12:23:36 +02:00
|
|
|
#include "strv.h"
|
2015-10-25 22:32:30 +01:00
|
|
|
#include "user-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "util.h"
|
2014-07-02 12:23:36 +02:00
|
|
|
|
|
|
|
static int from_environment(const char *envname, const char *fallback, const char **ret) {
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
if (envname) {
|
|
|
|
const char *e;
|
|
|
|
|
|
|
|
e = secure_getenv(envname);
|
|
|
|
if (e && path_is_absolute(e)) {
|
|
|
|
*ret = e;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fallback) {
|
|
|
|
*ret = fallback;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENXIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int from_home_dir(const char *envname, const char *suffix, char **buffer, const char **ret) {
|
|
|
|
_cleanup_free_ char *h = NULL;
|
|
|
|
char *cc = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(suffix);
|
|
|
|
assert(buffer);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
if (envname) {
|
|
|
|
const char *e = NULL;
|
|
|
|
|
|
|
|
e = secure_getenv(envname);
|
|
|
|
if (e && path_is_absolute(e)) {
|
|
|
|
*ret = e;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = get_home_dir(&h);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-06-20 20:07:01 +02:00
|
|
|
cc = path_join(h, suffix);
|
2014-07-02 12:23:36 +02:00
|
|
|
if (!cc)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*buffer = cc;
|
|
|
|
*ret = cc;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int from_user_dir(const char *field, char **buffer, const char **ret) {
|
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
_cleanup_free_ char *b = NULL;
|
2016-03-15 02:00:34 +01:00
|
|
|
_cleanup_free_ const char *fn = NULL;
|
|
|
|
const char *c = NULL;
|
2014-07-02 12:23:36 +02:00
|
|
|
size_t n;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(field);
|
|
|
|
assert(buffer);
|
|
|
|
assert(ret);
|
|
|
|
|
2016-03-15 02:00:34 +01:00
|
|
|
r = from_home_dir("XDG_CONFIG_HOME", ".config", &b, &c);
|
2014-07-02 12:23:36 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-07-11 19:14:16 +02:00
|
|
|
fn = path_join(c, "user-dirs.dirs");
|
2016-03-15 02:00:34 +01:00
|
|
|
if (!fn)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2014-07-02 12:23:36 +02:00
|
|
|
f = fopen(fn, "re");
|
|
|
|
if (!f) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
goto fallback;
|
|
|
|
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This is an awful parse, but it follows closely what
|
|
|
|
* xdg-user-dirs does upstream */
|
|
|
|
|
|
|
|
n = strlen(field);
|
2018-10-18 16:15:18 +02:00
|
|
|
for (;;) {
|
|
|
|
_cleanup_free_ char *line = NULL;
|
2014-07-02 12:23:36 +02:00
|
|
|
char *l, *p, *e;
|
|
|
|
|
2018-10-18 16:15:18 +02:00
|
|
|
r = read_line(f, LONG_LINE_MAX, &line);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
|
|
|
|
2014-07-02 12:23:36 +02:00
|
|
|
l = strstrip(line);
|
|
|
|
|
|
|
|
if (!strneq(l, field, n))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
p = l + n;
|
|
|
|
p += strspn(p, WHITESPACE);
|
|
|
|
|
|
|
|
if (*p != '=')
|
|
|
|
continue;
|
|
|
|
p++;
|
|
|
|
|
|
|
|
p += strspn(p, WHITESPACE);
|
|
|
|
|
|
|
|
if (*p != '"')
|
|
|
|
continue;
|
|
|
|
p++;
|
|
|
|
|
|
|
|
e = strrchr(p, '"');
|
|
|
|
if (!e)
|
|
|
|
continue;
|
|
|
|
*e = 0;
|
|
|
|
|
|
|
|
/* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
|
|
|
|
if (startswith(p, "$HOME/")) {
|
|
|
|
_cleanup_free_ char *h = NULL;
|
|
|
|
char *cc;
|
|
|
|
|
|
|
|
r = get_home_dir(&h);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-07-11 19:14:16 +02:00
|
|
|
cc = path_join(h, p+5);
|
2014-07-02 12:23:36 +02:00
|
|
|
if (!cc)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*buffer = cc;
|
|
|
|
*ret = cc;
|
|
|
|
return 0;
|
|
|
|
} else if (streq(p, "$HOME")) {
|
|
|
|
|
|
|
|
r = get_home_dir(buffer);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret = *buffer;
|
|
|
|
return 0;
|
|
|
|
} else if (path_is_absolute(p)) {
|
|
|
|
char *copy;
|
|
|
|
|
|
|
|
copy = strdup(p);
|
|
|
|
if (!copy)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*buffer = copy;
|
|
|
|
*ret = copy;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fallback:
|
|
|
|
/* The desktop directory defaults to $HOME/Desktop, the others to $HOME */
|
|
|
|
if (streq(field, "XDG_DESKTOP_DIR")) {
|
|
|
|
_cleanup_free_ char *h = NULL;
|
|
|
|
char *cc;
|
|
|
|
|
|
|
|
r = get_home_dir(&h);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-07-11 19:14:16 +02:00
|
|
|
cc = path_join(h, "Desktop");
|
2014-07-02 12:23:36 +02:00
|
|
|
if (!cc)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*buffer = cc;
|
|
|
|
*ret = cc;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
r = get_home_dir(buffer);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret = *buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_path(uint64_t type, char **buffer, const char **ret) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(buffer);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
|
|
|
case SD_PATH_TEMPORARY:
|
2017-07-20 14:19:57 +02:00
|
|
|
return tmp_dir(ret);
|
2014-07-02 12:23:36 +02:00
|
|
|
|
|
|
|
case SD_PATH_TEMPORARY_LARGE:
|
2017-07-20 14:19:57 +02:00
|
|
|
return var_tmp_dir(ret);
|
2014-07-02 12:23:36 +02:00
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_BINARIES:
|
|
|
|
*ret = "/usr/bin";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_INCLUDE:
|
|
|
|
*ret = "/usr/include";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_LIBRARY_PRIVATE:
|
|
|
|
*ret = "/usr/lib";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_LIBRARY_ARCH:
|
|
|
|
*ret = LIBDIR;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_SHARED:
|
|
|
|
*ret = "/usr/share";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_CONFIGURATION_FACTORY:
|
|
|
|
*ret = "/usr/share/factory/etc";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_STATE_FACTORY:
|
|
|
|
*ret = "/usr/share/factory/var";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_CONFIGURATION:
|
|
|
|
*ret = "/etc";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_RUNTIME:
|
|
|
|
*ret = "/run";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_RUNTIME_LOGS:
|
|
|
|
*ret = "/run/log";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_STATE_PRIVATE:
|
|
|
|
*ret = "/var/lib";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_STATE_LOGS:
|
|
|
|
*ret = "/var/log";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_STATE_CACHE:
|
|
|
|
*ret = "/var/cache";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEM_STATE_SPOOL:
|
|
|
|
*ret = "/var/spool";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_USER_BINARIES:
|
|
|
|
return from_home_dir(NULL, ".local/bin", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_LIBRARY_PRIVATE:
|
|
|
|
return from_home_dir(NULL, ".local/lib", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_LIBRARY_ARCH:
|
2014-07-03 15:40:14 +02:00
|
|
|
return from_home_dir(NULL, ".local/lib/" LIB_ARCH_TUPLE, buffer, ret);
|
2014-07-02 12:23:36 +02:00
|
|
|
|
|
|
|
case SD_PATH_USER_SHARED:
|
|
|
|
return from_home_dir("XDG_DATA_HOME", ".local/share", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_CONFIGURATION:
|
|
|
|
return from_home_dir("XDG_CONFIG_HOME", ".config", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_RUNTIME:
|
|
|
|
return from_environment("XDG_RUNTIME_DIR", NULL, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_STATE_CACHE:
|
|
|
|
return from_home_dir("XDG_CACHE_HOME", ".cache", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER:
|
|
|
|
r = get_home_dir(buffer);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
*ret = *buffer;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_USER_DOCUMENTS:
|
|
|
|
return from_user_dir("XDG_DOCUMENTS_DIR", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_MUSIC:
|
|
|
|
return from_user_dir("XDG_MUSIC_DIR", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_PICTURES:
|
|
|
|
return from_user_dir("XDG_PICTURES_DIR", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_VIDEOS:
|
|
|
|
return from_user_dir("XDG_VIDEOS_DIR", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_DOWNLOAD:
|
|
|
|
return from_user_dir("XDG_DOWNLOAD_DIR", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_PUBLIC:
|
|
|
|
return from_user_dir("XDG_PUBLICSHARE_DIR", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_TEMPLATES:
|
|
|
|
return from_user_dir("XDG_TEMPLATES_DIR", buffer, ret);
|
|
|
|
|
|
|
|
case SD_PATH_USER_DESKTOP:
|
|
|
|
return from_user_dir("XDG_DESKTOP_DIR", buffer, ret);
|
path: show various systemd directories and search paths too
So far we had various ad hoc APIs to query search paths:
systemd-analyze unit-paths, lookup_paths_log(), the pkgconfig file,
debug logs emitted by systemd-analyze cat-config.
But answering a simple question "what is the search path for tmpfiles,
sysusers, .network files, ..." is surprisingly hard.
I think we should have an api that makes it easy to query this. Pkgconfig is
not bad, but it is primarily a development tool, so it's not available in many
context. Also it can't provide support for paths which are influenced by
environment variables, and I'd like to be able to answer the question "what is
the search path for ..., assuming that VAR_FOO=... is set?".
Extending sd-path to support more of our internal paths seems to be most
flexible solution. We already have systemd-path which provides a nice
way to query, and we can add stuff like optional descriptions later on.
We we essentially get a nice programmatic and commmandline apis for the price
of one.
2020-03-24 16:04:50 +01:00
|
|
|
|
|
|
|
case SD_PATH_SYSTEMD_UTIL_DIR:
|
|
|
|
*ret = ROOTPREFIX "lib/systemd";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEMD_SYSTEM_UNIT_DIR:
|
|
|
|
*ret = SYSTEM_DATA_UNIT_PATH;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEMD_SYSTEM_PRESET_DIR:
|
|
|
|
*ret = ROOTPREFIX "lib/systemd/system-preset";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEMD_USER_UNIT_DIR:
|
|
|
|
*ret = USER_DATA_UNIT_PATH;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEMD_USER_PRESET_DIR:
|
|
|
|
*ret = ROOTPREFIX "lib/systemd/user-preset";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEMD_SYSTEM_CONF_DIR:
|
|
|
|
*ret = SYSTEM_CONFIG_UNIT_PATH; // FIXME: _DIR vs. _PATH
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEMD_USER_CONF_DIR:
|
|
|
|
*ret = USER_CONFIG_UNIT_PATH; // FIXME: _DIR vs. _PATH
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEMD_SYSTEM_GENERATOR_DIR:
|
|
|
|
*ret = SYSTEM_GENERATOR_PATH; // FIXME: _DIR vs. _PATH
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEMD_USER_GENERATOR_DIR:
|
|
|
|
*ret = USER_GENERATOR_PATH; // FIXME: _DIR vs. _PATH
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEMD_SLEEP_DIR:
|
|
|
|
*ret = ROOTPREFIX "lib/systemd/system-sleep";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSTEMD_SHUTDOWN_DIR:
|
|
|
|
*ret = ROOTPREFIX "lib/systemd/system-shutdown";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* FIXME: systemd.pc uses ${prefix}, but CONF_PATHS_NULSTR doesn't.
|
|
|
|
* Should ${prefix} use in systemd.pc be removed? */
|
|
|
|
case SD_PATH_TMPFILES_DIR:
|
|
|
|
*ret = "/usr/lib/tmpfiles.d";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSUSERS_DIR:
|
|
|
|
*ret = "/usr/lib/sysusers.d";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_SYSCTL_DIR:
|
|
|
|
*ret = "/usr/lib/sysctl.d";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_BINFMT_DIR:
|
|
|
|
*ret = "/usr/lib/binfmt.d";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_MODULES_LOAD_DIR:
|
|
|
|
*ret = "/usr/lib/modules-load.d";
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case SD_PATH_CATALOG_DIR:
|
|
|
|
*ret = "/usr/lib/systemd/catalog";
|
|
|
|
return 0;
|
2014-07-02 12:23:36 +02:00
|
|
|
}
|
|
|
|
|
2015-03-13 14:08:00 +01:00
|
|
|
return -EOPNOTSUPP;
|
2014-07-02 12:23:36 +02:00
|
|
|
}
|
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
static int get_path_alloc(uint64_t type, const char *suffix, char **path) {
|
2019-06-20 20:14:05 +02:00
|
|
|
_cleanup_free_ char *buffer = NULL;
|
2020-03-24 15:18:20 +01:00
|
|
|
char *buffer2 = NULL;
|
2014-07-02 12:23:36 +02:00
|
|
|
const char *ret;
|
|
|
|
int r;
|
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
assert(path);
|
2014-07-02 12:23:36 +02:00
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
r = get_path(type, &buffer, &ret);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-07-02 12:23:36 +02:00
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
if (suffix) {
|
|
|
|
suffix += strspn(suffix, "/");
|
|
|
|
buffer2 = path_join(ret, suffix);
|
|
|
|
if (!buffer2)
|
|
|
|
return -ENOMEM;
|
|
|
|
} else if (!buffer) {
|
|
|
|
buffer = strdup(ret);
|
2014-07-02 12:23:36 +02:00
|
|
|
if (!buffer)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
*path = buffer2 ?: TAKE_PTR(buffer);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ int sd_path_lookup(uint64_t type, const char *suffix, char **path) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(path, -EINVAL);
|
|
|
|
|
|
|
|
r = get_path_alloc(type, suffix, path);
|
|
|
|
if (r != -EOPNOTSUPP)
|
2014-07-02 12:23:36 +02:00
|
|
|
return r;
|
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
/* Fall back to sd_path_lookup_strv */
|
|
|
|
_cleanup_strv_free_ char **l = NULL;
|
|
|
|
char *buffer;
|
2014-07-02 12:23:36 +02:00
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
r = sd_path_lookup_strv(type, suffix, &l);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-07-02 12:23:36 +02:00
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
buffer = strv_join(l, ":");
|
|
|
|
if (!buffer)
|
2014-07-02 12:23:36 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
*path = buffer;
|
2014-07-02 12:23:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int search_from_environment(
|
|
|
|
char ***list,
|
|
|
|
const char *env_home,
|
|
|
|
const char *home_suffix,
|
|
|
|
const char *env_search,
|
|
|
|
bool env_search_sufficient,
|
|
|
|
const char *first, ...) {
|
|
|
|
|
2019-06-24 07:57:50 +02:00
|
|
|
_cleanup_strv_free_ char **l = NULL;
|
2014-07-02 12:23:36 +02:00
|
|
|
const char *e;
|
|
|
|
char *h = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(list);
|
|
|
|
|
|
|
|
if (env_search) {
|
|
|
|
e = secure_getenv(env_search);
|
|
|
|
if (e) {
|
|
|
|
l = strv_split(e, ":");
|
|
|
|
if (!l)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (env_search_sufficient) {
|
2019-06-24 07:57:50 +02:00
|
|
|
*list = TAKE_PTR(l);
|
2014-07-02 12:23:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!l && first) {
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, first);
|
|
|
|
l = strv_new_ap(first, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
if (!l)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (env_home) {
|
|
|
|
e = secure_getenv(env_home);
|
|
|
|
if (e && path_is_absolute(e)) {
|
|
|
|
h = strdup(e);
|
2019-06-24 07:57:50 +02:00
|
|
|
if (!h)
|
2014-07-02 12:23:36 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!h && home_suffix) {
|
|
|
|
e = secure_getenv("HOME");
|
|
|
|
if (e && path_is_absolute(e)) {
|
2019-06-20 20:07:01 +02:00
|
|
|
h = path_join(e, home_suffix);
|
2019-06-24 07:57:50 +02:00
|
|
|
if (!h)
|
2014-07-02 12:23:36 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (h) {
|
|
|
|
r = strv_consume_prepend(&l, h);
|
2019-06-24 07:57:50 +02:00
|
|
|
if (r < 0)
|
2014-07-02 12:23:36 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2019-06-24 07:57:50 +02:00
|
|
|
*list = TAKE_PTR(l);
|
2014-07-02 12:23:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-01 21:48:36 +01:00
|
|
|
#if HAVE_SPLIT_BIN
|
|
|
|
# define ARRAY_SBIN_BIN(x) x "sbin", x "bin"
|
|
|
|
#else
|
|
|
|
# define ARRAY_SBIN_BIN(x) x "bin"
|
|
|
|
#endif
|
|
|
|
|
2014-07-02 12:23:36 +02:00
|
|
|
static int get_search(uint64_t type, char ***list) {
|
path: show various systemd directories and search paths too
So far we had various ad hoc APIs to query search paths:
systemd-analyze unit-paths, lookup_paths_log(), the pkgconfig file,
debug logs emitted by systemd-analyze cat-config.
But answering a simple question "what is the search path for tmpfiles,
sysusers, .network files, ..." is surprisingly hard.
I think we should have an api that makes it easy to query this. Pkgconfig is
not bad, but it is primarily a development tool, so it's not available in many
context. Also it can't provide support for paths which are influenced by
environment variables, and I'd like to be able to answer the question "what is
the search path for ..., assuming that VAR_FOO=... is set?".
Extending sd-path to support more of our internal paths seems to be most
flexible solution. We already have systemd-path which provides a nice
way to query, and we can add stuff like optional descriptions later on.
We we essentially get a nice programmatic and commmandline apis for the price
of one.
2020-03-24 16:04:50 +01:00
|
|
|
int r;
|
2014-07-02 12:23:36 +02:00
|
|
|
|
|
|
|
assert(list);
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
|
|
|
|
case SD_PATH_SEARCH_BINARIES:
|
|
|
|
return search_from_environment(list,
|
|
|
|
NULL,
|
|
|
|
".local/bin",
|
|
|
|
"PATH",
|
|
|
|
true,
|
2018-03-01 21:48:36 +01:00
|
|
|
ARRAY_SBIN_BIN("/usr/local/"),
|
|
|
|
ARRAY_SBIN_BIN("/usr/"),
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_SPLIT_USR
|
2018-03-01 21:48:36 +01:00
|
|
|
ARRAY_SBIN_BIN("/"),
|
2014-07-02 12:23:36 +02:00
|
|
|
#endif
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
case SD_PATH_SEARCH_LIBRARY_PRIVATE:
|
|
|
|
return search_from_environment(list,
|
|
|
|
NULL,
|
|
|
|
".local/lib",
|
|
|
|
NULL,
|
|
|
|
false,
|
|
|
|
"/usr/local/lib",
|
|
|
|
"/usr/lib",
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_SPLIT_USR
|
2014-07-02 12:23:36 +02:00
|
|
|
"/lib",
|
|
|
|
#endif
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
case SD_PATH_SEARCH_LIBRARY_ARCH:
|
|
|
|
return search_from_environment(list,
|
|
|
|
NULL,
|
2014-07-03 15:40:14 +02:00
|
|
|
".local/lib/" LIB_ARCH_TUPLE,
|
2014-07-02 12:23:36 +02:00
|
|
|
"LD_LIBRARY_PATH",
|
|
|
|
true,
|
|
|
|
LIBDIR,
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_SPLIT_USR
|
2014-07-02 12:23:36 +02:00
|
|
|
ROOTLIBDIR,
|
|
|
|
#endif
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
case SD_PATH_SEARCH_SHARED:
|
|
|
|
return search_from_environment(list,
|
|
|
|
"XDG_DATA_HOME",
|
|
|
|
".local/share",
|
|
|
|
"XDG_DATA_DIRS",
|
|
|
|
false,
|
|
|
|
"/usr/local/share",
|
|
|
|
"/usr/share",
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
case SD_PATH_SEARCH_CONFIGURATION_FACTORY:
|
|
|
|
return search_from_environment(list,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
false,
|
|
|
|
"/usr/local/share/factory/etc",
|
|
|
|
"/usr/share/factory/etc",
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
case SD_PATH_SEARCH_STATE_FACTORY:
|
|
|
|
return search_from_environment(list,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
false,
|
|
|
|
"/usr/local/share/factory/var",
|
|
|
|
"/usr/share/factory/var",
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
case SD_PATH_SEARCH_CONFIGURATION:
|
|
|
|
return search_from_environment(list,
|
|
|
|
"XDG_CONFIG_HOME",
|
|
|
|
".config",
|
|
|
|
"XDG_CONFIG_DIRS",
|
|
|
|
false,
|
|
|
|
"/etc",
|
|
|
|
NULL);
|
2018-03-26 09:51:12 +02:00
|
|
|
|
2020-03-24 11:28:25 +01:00
|
|
|
case SD_PATH_SEARCH_BINARIES_DEFAULT:
|
|
|
|
return strv_from_nulstr(list, DEFAULT_PATH_NULSTR);
|
2018-03-26 09:51:12 +02:00
|
|
|
|
path: show various systemd directories and search paths too
So far we had various ad hoc APIs to query search paths:
systemd-analyze unit-paths, lookup_paths_log(), the pkgconfig file,
debug logs emitted by systemd-analyze cat-config.
But answering a simple question "what is the search path for tmpfiles,
sysusers, .network files, ..." is surprisingly hard.
I think we should have an api that makes it easy to query this. Pkgconfig is
not bad, but it is primarily a development tool, so it's not available in many
context. Also it can't provide support for paths which are influenced by
environment variables, and I'd like to be able to answer the question "what is
the search path for ..., assuming that VAR_FOO=... is set?".
Extending sd-path to support more of our internal paths seems to be most
flexible solution. We already have systemd-path which provides a nice
way to query, and we can add stuff like optional descriptions later on.
We we essentially get a nice programmatic and commmandline apis for the price
of one.
2020-03-24 16:04:50 +01:00
|
|
|
case SD_PATH_SYSTEMD_SYSTEM_UNIT_PATH:
|
|
|
|
case SD_PATH_SYSTEMD_USER_UNIT_PATH: {
|
|
|
|
_cleanup_(lookup_paths_free) LookupPaths lp = {};
|
|
|
|
const UnitFileScope scope = type == SD_PATH_SYSTEMD_SYSTEM_UNIT_PATH ?
|
|
|
|
UNIT_FILE_SYSTEM : UNIT_FILE_USER;
|
|
|
|
|
|
|
|
r = lookup_paths_init(&lp, scope, 0, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2018-03-26 09:51:12 +02:00
|
|
|
|
path: show various systemd directories and search paths too
So far we had various ad hoc APIs to query search paths:
systemd-analyze unit-paths, lookup_paths_log(), the pkgconfig file,
debug logs emitted by systemd-analyze cat-config.
But answering a simple question "what is the search path for tmpfiles,
sysusers, .network files, ..." is surprisingly hard.
I think we should have an api that makes it easy to query this. Pkgconfig is
not bad, but it is primarily a development tool, so it's not available in many
context. Also it can't provide support for paths which are influenced by
environment variables, and I'd like to be able to answer the question "what is
the search path for ..., assuming that VAR_FOO=... is set?".
Extending sd-path to support more of our internal paths seems to be most
flexible solution. We already have systemd-path which provides a nice
way to query, and we can add stuff like optional descriptions later on.
We we essentially get a nice programmatic and commmandline apis for the price
of one.
2020-03-24 16:04:50 +01:00
|
|
|
*list = TAKE_PTR(lp.search_path);
|
|
|
|
return 0;
|
2020-03-24 11:28:25 +01:00
|
|
|
}
|
2014-07-02 12:23:36 +02:00
|
|
|
|
path: show various systemd directories and search paths too
So far we had various ad hoc APIs to query search paths:
systemd-analyze unit-paths, lookup_paths_log(), the pkgconfig file,
debug logs emitted by systemd-analyze cat-config.
But answering a simple question "what is the search path for tmpfiles,
sysusers, .network files, ..." is surprisingly hard.
I think we should have an api that makes it easy to query this. Pkgconfig is
not bad, but it is primarily a development tool, so it's not available in many
context. Also it can't provide support for paths which are influenced by
environment variables, and I'd like to be able to answer the question "what is
the search path for ..., assuming that VAR_FOO=... is set?".
Extending sd-path to support more of our internal paths seems to be most
flexible solution. We already have systemd-path which provides a nice
way to query, and we can add stuff like optional descriptions later on.
We we essentially get a nice programmatic and commmandline apis for the price
of one.
2020-03-24 16:04:50 +01:00
|
|
|
case SD_PATH_SYSTEMD_SYSTEM_GENERATOR_PATH:
|
|
|
|
case SD_PATH_SYSTEMD_USER_GENERATOR_PATH: {
|
|
|
|
char **t;
|
|
|
|
const UnitFileScope scope = type == SD_PATH_SYSTEMD_SYSTEM_UNIT_PATH ?
|
|
|
|
UNIT_FILE_SYSTEM : UNIT_FILE_USER;
|
|
|
|
|
|
|
|
t = generator_binary_paths(scope);
|
|
|
|
if (!t)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*list = t;
|
|
|
|
return 0;
|
|
|
|
}}
|
|
|
|
|
2015-03-13 14:08:00 +01:00
|
|
|
return -EOPNOTSUPP;
|
2014-07-02 12:23:36 +02:00
|
|
|
}
|
|
|
|
|
2020-03-23 19:50:59 +01:00
|
|
|
_public_ int sd_path_lookup_strv(uint64_t type, const char *suffix, char ***paths) {
|
2018-05-02 08:47:04 +02:00
|
|
|
_cleanup_strv_free_ char **l = NULL, **n = NULL;
|
2014-07-02 12:23:36 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(paths, -EINVAL);
|
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
r = get_search(type, &l);
|
|
|
|
if (r == -EOPNOTSUPP) {
|
|
|
|
_cleanup_free_ char *t = NULL;
|
2014-07-02 12:23:36 +02:00
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
r = get_path_alloc(type, suffix, &t);
|
2014-07-02 12:23:36 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
l = new(char*, 2);
|
2020-03-24 15:18:20 +01:00
|
|
|
if (!l)
|
2014-07-02 12:23:36 +02:00
|
|
|
return -ENOMEM;
|
2020-03-24 15:18:20 +01:00
|
|
|
l[0] = TAKE_PTR(t);
|
2014-07-02 12:23:36 +02:00
|
|
|
l[1] = NULL;
|
|
|
|
|
2018-05-02 08:47:04 +02:00
|
|
|
*paths = TAKE_PTR(l);
|
2014-07-02 12:23:36 +02:00
|
|
|
return 0;
|
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
} else if (r < 0)
|
2014-07-02 12:23:36 +02:00
|
|
|
return r;
|
|
|
|
|
|
|
|
if (!suffix) {
|
2018-05-02 08:47:04 +02:00
|
|
|
*paths = TAKE_PTR(l);
|
2014-07-02 12:23:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = new(char*, strv_length(l)+1);
|
2018-05-02 08:47:04 +02:00
|
|
|
if (!n)
|
2014-07-02 12:23:36 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2020-03-24 15:18:20 +01:00
|
|
|
char **i, **j = n;
|
2014-07-02 12:23:36 +02:00
|
|
|
STRV_FOREACH(i, l) {
|
2019-06-20 20:07:01 +02:00
|
|
|
*j = path_join(*i, suffix);
|
2018-05-02 08:47:04 +02:00
|
|
|
if (!*j)
|
2014-07-02 12:23:36 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
*j = NULL;
|
2020-03-24 15:18:20 +01:00
|
|
|
|
2018-05-02 08:47:04 +02:00
|
|
|
*paths = TAKE_PTR(n);
|
2014-07-02 12:23:36 +02:00
|
|
|
return 0;
|
|
|
|
}
|