2014-07-02 12:23:36 +02:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2014 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/>.
|
|
|
|
***/
|
|
|
|
|
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"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "missing.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;
|
|
|
|
|
|
|
|
if (endswith(h, "/"))
|
|
|
|
cc = strappend(h, suffix);
|
|
|
|
else
|
2016-10-23 17:43:27 +02:00
|
|
|
cc = strjoin(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
|
|
|
char line[LINE_MAX];
|
|
|
|
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;
|
|
|
|
|
2016-03-15 02:00:34 +01:00
|
|
|
fn = strappend(c, "/user-dirs.dirs");
|
|
|
|
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);
|
|
|
|
FOREACH_LINE(line, f, return -errno) {
|
|
|
|
char *l, *p, *e;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
cc = strappend(h, p+5);
|
|
|
|
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;
|
|
|
|
|
|
|
|
cc = strappend(h, "/Desktop");
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-03-13 14:08:00 +01:00
|
|
|
return -EOPNOTSUPP;
|
2014-07-02 12:23:36 +02:00
|
|
|
}
|
|
|
|
|
2014-07-11 03:13:24 +02:00
|
|
|
_public_ int sd_path_home(uint64_t type, const char *suffix, char **path) {
|
2014-07-02 12:23:36 +02:00
|
|
|
char *buffer = NULL, *cc;
|
|
|
|
const char *ret;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(path, -EINVAL);
|
|
|
|
|
|
|
|
if (IN_SET(type,
|
|
|
|
SD_PATH_SEARCH_BINARIES,
|
|
|
|
SD_PATH_SEARCH_LIBRARY_PRIVATE,
|
|
|
|
SD_PATH_SEARCH_LIBRARY_ARCH,
|
|
|
|
SD_PATH_SEARCH_SHARED,
|
|
|
|
SD_PATH_SEARCH_CONFIGURATION_FACTORY,
|
|
|
|
SD_PATH_SEARCH_STATE_FACTORY,
|
|
|
|
SD_PATH_SEARCH_CONFIGURATION)) {
|
|
|
|
|
|
|
|
_cleanup_strv_free_ char **l = NULL;
|
|
|
|
|
|
|
|
r = sd_path_search(type, suffix, &l);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
buffer = strv_join(l, ":");
|
|
|
|
if (!buffer)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*path = buffer;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = get_path(type, &buffer, &ret);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (!suffix) {
|
|
|
|
if (!buffer) {
|
|
|
|
buffer = strdup(ret);
|
|
|
|
if (!buffer)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
*path = buffer;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
suffix += strspn(suffix, "/");
|
|
|
|
|
|
|
|
if (endswith(ret, "/"))
|
|
|
|
cc = strappend(ret, suffix);
|
|
|
|
else
|
2016-10-23 17:43:27 +02:00
|
|
|
cc = strjoin(ret, "/", suffix);
|
2014-07-02 12:23:36 +02:00
|
|
|
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
if (!cc)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*path = cc;
|
|
|
|
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, ...) {
|
|
|
|
|
|
|
|
const char *e;
|
|
|
|
char *h = NULL;
|
|
|
|
char **l = 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) {
|
|
|
|
*list = l;
|
|
|
|
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);
|
|
|
|
if (!h) {
|
|
|
|
strv_free(l);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!h && home_suffix) {
|
|
|
|
e = secure_getenv("HOME");
|
|
|
|
if (e && path_is_absolute(e)) {
|
|
|
|
if (endswith(e, "/"))
|
|
|
|
h = strappend(e, home_suffix);
|
|
|
|
else
|
2016-10-23 17:43:27 +02:00
|
|
|
h = strjoin(e, "/", home_suffix);
|
2014-07-02 12:23:36 +02:00
|
|
|
|
|
|
|
if (!h) {
|
|
|
|
strv_free(l);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (h) {
|
|
|
|
r = strv_consume_prepend(&l, h);
|
|
|
|
if (r < 0) {
|
|
|
|
strv_free(l);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*list = l;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_search(uint64_t type, char ***list) {
|
|
|
|
|
|
|
|
assert(list);
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
|
|
|
|
case SD_PATH_SEARCH_BINARIES:
|
|
|
|
return search_from_environment(list,
|
|
|
|
NULL,
|
|
|
|
".local/bin",
|
|
|
|
"PATH",
|
|
|
|
true,
|
|
|
|
"/usr/local/sbin",
|
|
|
|
"/usr/local/bin",
|
|
|
|
"/usr/sbin",
|
|
|
|
"/usr/bin",
|
2017-10-03 10:41:51 +02:00
|
|
|
#if HAVE_SPLIT_USR
|
2014-07-02 12:23:36 +02:00
|
|
|
"/sbin",
|
|
|
|
"/bin",
|
|
|
|
#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);
|
|
|
|
}
|
|
|
|
|
2015-03-13 14:08:00 +01:00
|
|
|
return -EOPNOTSUPP;
|
2014-07-02 12:23:36 +02:00
|
|
|
}
|
|
|
|
|
2014-07-11 03:13:24 +02:00
|
|
|
_public_ int sd_path_search(uint64_t type, const char *suffix, char ***paths) {
|
2014-07-02 12:23:36 +02:00
|
|
|
char **l, **i, **j, **n;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return(paths, -EINVAL);
|
|
|
|
|
|
|
|
if (!IN_SET(type,
|
|
|
|
SD_PATH_SEARCH_BINARIES,
|
|
|
|
SD_PATH_SEARCH_LIBRARY_PRIVATE,
|
|
|
|
SD_PATH_SEARCH_LIBRARY_ARCH,
|
|
|
|
SD_PATH_SEARCH_SHARED,
|
|
|
|
SD_PATH_SEARCH_CONFIGURATION_FACTORY,
|
|
|
|
SD_PATH_SEARCH_STATE_FACTORY,
|
|
|
|
SD_PATH_SEARCH_CONFIGURATION)) {
|
|
|
|
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
r = sd_path_home(type, suffix, &p);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
l = new(char*, 2);
|
|
|
|
if (!l) {
|
|
|
|
free(p);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
l[0] = p;
|
|
|
|
l[1] = NULL;
|
|
|
|
|
|
|
|
*paths = l;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = get_search(type, &l);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (!suffix) {
|
|
|
|
*paths = l;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = new(char*, strv_length(l)+1);
|
|
|
|
if (!n) {
|
|
|
|
strv_free(l);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
j = n;
|
|
|
|
STRV_FOREACH(i, l) {
|
|
|
|
|
|
|
|
if (endswith(*i, "/"))
|
|
|
|
*j = strappend(*i, suffix);
|
|
|
|
else
|
2016-10-23 17:43:27 +02:00
|
|
|
*j = strjoin(*i, "/", suffix);
|
2014-07-02 12:23:36 +02:00
|
|
|
|
|
|
|
if (!*j) {
|
|
|
|
strv_free(l);
|
|
|
|
strv_free(n);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*j = NULL;
|
|
|
|
*paths = n;
|
|
|
|
return 0;
|
|
|
|
}
|