summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-07-02 12:23:36 +0200
committerLennart Poettering <lennart@poettering.net>2014-07-02 12:23:36 +0200
commit9a00f57a5ba7ed431e6bac8d8b36518708503b4e (patch)
treee548891199d5ff830aa74f40cd23e63660dec41a /src
parentcd4ba18a849dc82735b3787cf99bd3fdc404d5ae (diff)
path: add new "systemd-path" utility for querying paths described in file-hierarchy(7)
This new tool is based on "sd-path", a new (so far unexported) API for libsystemd, that can hopefully grow into a workable API covering /opt and more one day.
Diffstat (limited to 'src')
l---------src/libsystemd/sd-path/Makefile1
-rw-r--r--src/libsystemd/sd-path/sd-path.c626
l---------src/path/Makefile1
-rw-r--r--src/path/path.c208
-rw-r--r--src/shared/architecture.h51
-rw-r--r--src/shared/strv.c34
-rw-r--r--src/shared/strv.h2
-rw-r--r--src/shared/util.c4
-rw-r--r--src/systemd/sd-path.h87
9 files changed, 1010 insertions, 4 deletions
diff --git a/src/libsystemd/sd-path/Makefile b/src/libsystemd/sd-path/Makefile
new file mode 120000
index 0000000000..d0b0e8e008
--- /dev/null
+++ b/src/libsystemd/sd-path/Makefile
@@ -0,0 +1 @@
+../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c
new file mode 100644
index 0000000000..44c1b8bd70
--- /dev/null
+++ b/src/libsystemd/sd-path/sd-path.c
@@ -0,0 +1,626 @@
+/***
+ 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/>.
+***/
+
+#include "util.h"
+#include "architecture.h"
+#include "path-util.h"
+#include "strv.h"
+#include "sd-path.h"
+
+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
+ cc = strjoin(h, "/", suffix, NULL);
+ 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;
+ const char *fn = NULL;
+ char line[LINE_MAX];
+ size_t n;
+ int r;
+
+ assert(field);
+ assert(buffer);
+ assert(ret);
+
+ r = from_home_dir(NULL, ".config/user-dirs.dirs", &b, &fn);
+ if (r < 0)
+ return r;
+
+ 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:
+ return from_environment("TMPDIR", "/tmp", ret);
+
+ case SD_PATH_TEMPORARY_LARGE:
+ return from_environment("TMPDIR", "/var/tmp", ret);
+
+ 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:
+ return from_home_dir(NULL, ".local/lib/" ARCH_TUPLE, buffer, ret);
+
+ 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);
+ }
+
+ return -ENOTSUP;
+}
+
+int sd_path_home(uint64_t type, const char *suffix, char **path) {
+ 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
+ cc = strjoin(ret, "/", suffix, NULL);
+
+ 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
+ h = strjoin(e, "/", home_suffix, NULL);
+
+ 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",
+#ifdef HAVE_SPLIT_USR
+ "/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",
+#ifdef HAVE_SPLIT_USR
+ "/lib",
+#endif
+ NULL);
+
+ case SD_PATH_SEARCH_LIBRARY_ARCH:
+ return search_from_environment(list,
+ NULL,
+ ".local/lib/" ARCH_TUPLE,
+ "LD_LIBRARY_PATH",
+ true,
+ LIBDIR,
+#ifdef HAVE_SPLIT_USR
+ 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);
+ }
+
+ return -ENOTSUP;
+}
+
+int sd_path_search(uint64_t type, const char *suffix, char ***paths) {
+ 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
+ *j = strjoin(*i, "/", suffix, NULL);
+
+ if (!*j) {
+ strv_free(l);
+ strv_free(n);
+ return -ENOMEM;
+ }
+
+ j++;
+ }
+
+ *j = NULL;
+ *paths = n;
+ return 0;
+}
diff --git a/src/path/Makefile b/src/path/Makefile
new file mode 120000
index 0000000000..d0b0e8e008
--- /dev/null
+++ b/src/path/Makefile
@@ -0,0 +1 @@
+../Makefile \ No newline at end of file
diff --git a/src/path/path.c b/src/path/path.c
new file mode 100644
index 0000000000..c2936e0bca
--- /dev/null
+++ b/src/path/path.c
@@ -0,0 +1,208 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ 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/>.
+***/
+
+#include <stdio.h>
+#include <getopt.h>
+#include <error.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sd-path.h"
+#include "build.h"
+#include "macro.h"
+#include "util.h"
+#include "log.h"
+
+static const char *arg_suffix = NULL;
+
+static const char* const path_table[_SD_PATH_MAX] = {
+ [SD_PATH_TEMPORARY] = "temporary",
+ [SD_PATH_TEMPORARY_LARGE] = "temporary-large",
+ [SD_PATH_SYSTEM_BINARIES] = "system-binaries",
+ [SD_PATH_SYSTEM_INCLUDE] = "system-include",
+ [SD_PATH_SYSTEM_LIBRARY_PRIVATE] = "system-library-private",
+ [SD_PATH_SYSTEM_LIBRARY_ARCH] = "system-library-arch",
+ [SD_PATH_SYSTEM_SHARED] = "system-shared",
+ [SD_PATH_SYSTEM_CONFIGURATION_FACTORY] = "system-configuration-factory",
+ [SD_PATH_SYSTEM_STATE_FACTORY] = "system-state-factory",
+ [SD_PATH_SYSTEM_CONFIGURATION] = "system-configuration",
+ [SD_PATH_SYSTEM_RUNTIME] = "system-runtime",
+ [SD_PATH_SYSTEM_RUNTIME_LOGS] = "system-runtime-logs",
+ [SD_PATH_SYSTEM_STATE_PRIVATE] = "system-state-private",
+ [SD_PATH_SYSTEM_STATE_LOGS] = "system-state-logs",
+ [SD_PATH_SYSTEM_STATE_CACHE] = "system-state-cache",
+ [SD_PATH_SYSTEM_STATE_SPOOL] = "system-state-spool",
+ [SD_PATH_USER_BINARIES] = "user-binaries",
+ [SD_PATH_USER_LIBRARY_PRIVATE] = "user-library-private",
+ [SD_PATH_USER_LIBRARY_ARCH] = "user-library-arch",
+ [SD_PATH_USER_SHARED] = "user-shared",
+ [SD_PATH_USER_CONFIGURATION] = "user-configuration",
+ [SD_PATH_USER_RUNTIME] = "user-runtime",
+ [SD_PATH_USER_STATE_CACHE] = "user-state-cache",
+ [SD_PATH_USER] = "user",
+ [SD_PATH_USER_DOCUMENTS] = "user-documents",
+ [SD_PATH_USER_MUSIC] = "user-music",
+ [SD_PATH_USER_PICTURES] = "user-pictures",
+ [SD_PATH_USER_VIDEOS] = "user-videos",
+ [SD_PATH_USER_DOWNLOAD] = "user-download",
+ [SD_PATH_USER_PUBLIC] = "user-public",
+ [SD_PATH_USER_TEMPLATES] = "user-templates",
+ [SD_PATH_USER_DESKTOP] = "user-desktop",
+ [SD_PATH_SEARCH_BINARIES] = "search-binaries",
+ [SD_PATH_SEARCH_LIBRARY_PRIVATE] = "search-library-private",
+ [SD_PATH_SEARCH_LIBRARY_ARCH] = "search-library-arch",
+ [SD_PATH_SEARCH_SHARED] = "search-shared",
+ [SD_PATH_SEARCH_CONFIGURATION_FACTORY] = "search-configuration-factory",
+ [SD_PATH_SEARCH_STATE_FACTORY] = "search-state-factory",
+ [SD_PATH_SEARCH_CONFIGURATION] = "search-configuration",
+};
+
+static int help(void) {
+
+ printf("%s [OPTIONS...] [NAME...]\n\n"
+ "Show system and user paths.\n\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --suffix=SUFFIX Suffix to append to paths\n",
+ program_invocation_short_name);
+
+ return 0;
+}
+
+static int list_homes(void) {
+ uint64_t i = 0;
+ int r = 0;
+
+ for (i = 0; i < ELEMENTSOF(path_table); i++) {
+ _cleanup_free_ char *p = NULL;
+ int q;
+
+ q = sd_path_home(i, arg_suffix, &p);
+ if (q == -ENXIO)
+ continue;
+ if (q < 0) {
+ log_error("Failed to query %s: %s", path_table[i], strerror(-r));
+ r = q;
+ continue;
+ }
+
+ printf("%s: %s\n", path_table[i], p);
+ }
+
+ return r;
+}
+
+static int print_home(const char *n) {
+ uint64_t i = 0;
+ int r;
+
+ for (i = 0; i < ELEMENTSOF(path_table); i++) {
+ if (streq(path_table[i], n)) {
+ _cleanup_free_ char *p = NULL;
+
+ r = sd_path_home(i, arg_suffix, &p);
+ if (r < 0) {
+ log_error("Failed to query %s: %s", n, strerror(-r));
+ return r;
+ }
+
+ printf("%s\n", p);
+ return 0;
+ }
+ }
+
+ log_error("Path %s not known.", n);
+ return -ENOTSUP;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+ enum {
+ ARG_VERSION = 0x100,
+ ARG_SUFFIX,
+ };
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "suffix", required_argument, NULL, ARG_SUFFIX },
+ {}
+ };
+
+ int c;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+
+ switch (c) {
+
+ case 'h':
+ return help();
+
+ case ARG_VERSION:
+ puts(PACKAGE_STRING);
+ puts(SYSTEMD_FEATURES);
+ return 0;
+
+ case ARG_SUFFIX:
+ arg_suffix = optarg;
+ break;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ assert_not_reached("Unhandled option");
+ }
+ }
+
+ return 1;
+}
+
+int main(int argc, char* argv[]) {
+ int r;
+
+ log_parse_environment();
+ log_open();
+
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ goto finish;
+
+ if (argc > optind) {
+ int i, q;
+
+ for (i = optind; i < argc; i++) {
+ q = print_home(argv[i]);
+ if (q < 0)
+ r = q;
+ }
+ } else
+ r = list_homes();
+
+
+finish:
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/shared/architecture.h b/src/shared/architecture.h
index 20e848bd8f..08079244dc 100644
--- a/src/shared/architecture.h
+++ b/src/shared/architecture.h
@@ -23,6 +23,8 @@
#include "util.h"
+/* A cleaned up architecture definition */
+
typedef enum Architecture {
ARCHITECTURE_X86 = 0,
ARCHITECTURE_X86_64,
@@ -38,7 +40,9 @@ typedef enum Architecture {
ARCHITECTURE_SPARC,
ARCHITECTURE_SPARC64,
ARCHITECTURE_MIPS,
+ ARCHITECTURE_MIPS_LE,
ARCHITECTURE_MIPS64,
+ ARCHITECTURE_MIPS64_LE,
ARCHITECTURE_ALPHA,
ARCHITECTURE_ARM,
ARCHITECTURE_ARM_BE,
@@ -55,64 +59,107 @@ typedef enum Architecture {
Architecture uname_architecture(void);
+/*
+ * ARCH_TUPLE should resolve to the local architecture systemd is
+ * built for, according to the Debian tuple list:
+ *
+ * https://wiki.debian.org/Multiarch/Tuples
+ *
+ */
+
#if defined(__x86_64__)
# define native_architecture() ARCHITECTURE_X86_64
+# define ARCH_TUPLE "x86_64-linux-gnu"
#elif defined(__i386__)
# define native_architecture() ARCHITECTURE_X86
+# define ARCH_TUPLE "i386-linux-gnu"
#elif defined(__powerpc64__)
# if defined(WORDS_BIGENDIAN)
# define native_architecture() ARCHITECTURE_PPC64
+# define ARCH_TUPLE "ppc64-linux-gnu"
# else
# define native_architecture() ARCHITECTURE_PPC64_LE
+# error "Missing ARCH_TUPLE for PPC64LE"
# endif
#elif defined(__powerpc__)
# if defined(WORDS_BIGENDIAN)
# define native_architecture() ARCHITECTURE_PPC
+# define ARCH_TUPLE "powerpc-linux-gnu"
# else
# define native_architecture() ARCHITECTURE_PPC_LE
+# error "Missing ARCH_TUPLE for PPCLE"
# endif
#elif defined(__ia64__)
# define native_architecture() ARCHITECTURE_IA64
+# define ARCH_TUPLE "ia64-linux-gnu"
#elif defined(__hppa64__)
# define native_architecture() ARCHITECTURE_PARISC64
+# error "Missing ARCH_TUPLE for HPPA64"
#elif defined(__hppa__)
# define native_architecture() ARCHITECTURE_PARISC
+# define ARCH_TUPLE "hppa‑linux‑gnu"
#elif defined(__s390x__)
# define native_architecture() ARCHITECTURE_S390X
+# define ARCH_TUPLE "s390x-linux-gnu"
#elif defined(__s390__)
# define native_architecture() ARCHITECTURE_S390
+# define ARCH_TUPLE "s390-linux-gnu"
#elif defined(__sparc64__)
# define native_architecture() ARCHITECTURE_SPARC64
+# define ARCH_TUPLE "sparc64-linux-gnu"
#elif defined(__sparc__)
# define native_architecture() ARCHITECTURE_SPARC
+# define ARCH_TUPLE "sparc-linux-gnu"
#elif defined(__mips64__)
-# define native_architecture() ARCHITECTURE_MIPS64
+# if defined(WORDS_BIGENDIAN)
+# define native_architecture() ARCHITECTURE_MIPS64
+# error "Missing ARCH_TUPLE for MIPS64"
+# else
+# define native_architecture() ARCHITECTURE_MIPS64_LE
+# error "Missing ARCH_TUPLE for MIPS64_LE"
+# endif
#elif defined(__mips__)
-# define native_architecture() ARCHITECTURE_MIPS
+# if defined(WORDS_BIGENDIAN)
+# define native_architecture() ARCHITECTURE_MIPS
+# define ARCH_TUPLE "mips-linux-gnu"
+# else
+# define native_architecture() ARCHITECTURE_MIPS_LE
+# define ARCH_TUPLE "mipsel-linux-gnu"
+#endif
#elif defined(__alpha__)
# define native_architecture() ARCHITECTURE_ALPHA
+# define ARCH_TUPLE "alpha-linux-gnu"
#elif defined(__aarch64__)
# if defined(WORDS_BIGENDIAN)
# define native_architecture() ARCHITECTURE_ARM64_BE
+# define ARCH_TUPLE "aarch64_be-linux-gnu"
# else
# define native_architecture() ARCHITECTURE_ARM64
+# define ARCH_TUPLE "aarch64-linux-gnu"
# endif
#elif defined(__arm__)
# if defined(WORDS_BIGENDIAN)
# define native_architecture() ARCHITECTURE_ARM_BE
+# error "Missing ARCH_TUPLE for ARM_BE"
# else
# define native_architecture() ARCHITECTURE_ARM
+# error "Missing ARCH_TUPLE for ARM"
# endif
#elif defined(__sh64__)
# define native_architecture() ARCHITECTURE_SH64
+# error "Missing ARCH_TUPLE for SH64"
#elif defined(__sh__)
# define native_architecture() ARCHITECTURE_SH
+# define ARCH_TUPLE "sh4-linux-gnu"
#elif defined(__m68k__)
# define native_architecture() ARCHITECTURE_M68K
+# define ARCH_TUPLE "m68k-linux-gnu"
#elif defined(__tilegx__)
# define native_architecture() ARCHITECTURE_TILEGX
+# error "Missing ARCH_TUPLE for TILEGX"
#elif defined(__cris__)
# define native_architecture() ARCHITECTURE_CRIS
+# error "Missing ARCH_TUPLE for CRIS"
#else
#error "Please register your architecture here!"
#endif
diff --git a/src/shared/strv.c b/src/shared/strv.c
index 1ef0b26a25..b4c476eff2 100644
--- a/src/shared/strv.c
+++ b/src/shared/strv.c
@@ -378,6 +378,30 @@ int strv_push(char ***l, char *value) {
return 0;
}
+int strv_push_prepend(char ***l, char *value) {
+ char **c;
+ unsigned n, i;
+
+ if (!value)
+ return 0;
+
+ n = strv_length(*l);
+ c = new(char*, n + 2);
+ if (!c)
+ return -ENOMEM;
+
+ for (i = 0; i < n; i++)
+ c[i+1] = (*l)[i];
+
+ c[0] = value;
+ c[n+1] = NULL;
+
+ free(*l);
+ *l = c;
+
+ return 0;
+}
+
int strv_consume(char ***l, char *value) {
int r;
@@ -388,6 +412,16 @@ int strv_consume(char ***l, char *value) {
return r;
}
+int strv_consume_prepend(char ***l, char *value) {
+ int r;
+
+ r = strv_push_prepend(l, value);
+ if (r < 0)
+ free(value);
+
+ return r;
+}
+
int strv_extend(char ***l, const char *value) {
char *v;
diff --git a/src/shared/strv.h b/src/shared/strv.h
index e26ab828d2..3034073d32 100644
--- a/src/shared/strv.h
+++ b/src/shared/strv.h
@@ -41,7 +41,9 @@ int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
int strv_extend(char ***l, const char *value);
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
int strv_push(char ***l, char *value);
+int strv_push_prepend(char ***l, char *value);
int strv_consume(char ***l, char *value);
+int strv_consume_prepend(char ***l, char *value);
char **strv_remove(char **l, const char *s);
char **strv_uniq(char **l);
diff --git a/src/shared/util.c b/src/shared/util.c
index 9b5a47ab6f..a1c8baf237 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -5226,8 +5226,8 @@ int get_home_dir(char **_h) {
assert(_h);
/* Take the user specified one */
- e = getenv("HOME");
- if (e) {
+ e = secure_getenv("HOME");
+ if (e && path_is_absolute(e)) {
h = strdup(e);
if (!h)
return -ENOMEM;
diff --git a/src/systemd/sd-path.h b/src/systemd/sd-path.h
new file mode 100644
index 0000000000..e238c0ce20
--- /dev/null
+++ b/src/systemd/sd-path.h
@@ -0,0 +1,87 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foosdpathhfoo
+#define foosdpathhfoo
+
+/***
+ 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/>.
+***/
+
+#include <inttypes.h>
+
+enum {
+ /* Temporary files */
+ SD_PATH_TEMPORARY = 0x0ULL,
+ SD_PATH_TEMPORARY_LARGE,
+
+ /* Vendor supplied data */
+ SD_PATH_SYSTEM_BINARIES,
+ SD_PATH_SYSTEM_INCLUDE,
+ SD_PATH_SYSTEM_LIBRARY_PRIVATE,
+ SD_PATH_SYSTEM_LIBRARY_ARCH,
+ SD_PATH_SYSTEM_SHARED,
+ SD_PATH_SYSTEM_CONFIGURATION_FACTORY,
+ SD_PATH_SYSTEM_STATE_FACTORY,
+
+ /* System configuration, runtime, state, ... */
+ SD_PATH_SYSTEM_CONFIGURATION,
+ SD_PATH_SYSTEM_RUNTIME,
+ SD_PATH_SYSTEM_RUNTIME_LOGS,
+ SD_PATH_SYSTEM_STATE_PRIVATE,
+ SD_PATH_SYSTEM_STATE_LOGS,
+ SD_PATH_SYSTEM_STATE_CACHE,
+ SD_PATH_SYSTEM_STATE_SPOOL,
+
+ /* Vendor supplied data */
+ SD_PATH_USER_BINARIES,
+ SD_PATH_USER_LIBRARY_PRIVATE,
+ SD_PATH_USER_LIBRARY_ARCH,
+ SD_PATH_USER_SHARED,
+
+ /* User configuration, state, runtime ... */
+ SD_PATH_USER_CONFIGURATION, /* takes both actual configuration (like /etc) and state (like /var/lib) */
+ SD_PATH_USER_RUNTIME,
+ SD_PATH_USER_STATE_CACHE,
+
+ /* User resources */
+ SD_PATH_USER, /* $HOME itself */
+ SD_PATH_USER_DOCUMENTS,
+ SD_PATH_USER_MUSIC,
+ SD_PATH_USER_PICTURES,
+ SD_PATH_USER_VIDEOS,
+ SD_PATH_USER_DOWNLOAD,
+ SD_PATH_USER_PUBLIC,
+ SD_PATH_USER_TEMPLATES,
+ SD_PATH_USER_DESKTOP,
+
+ /* Search paths */
+ 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,
+
+ _SD_PATH_MAX,
+};
+
+int sd_path_home(uint64_t type, const char *suffix, char **path);
+int sd_path_search(uint64_t type, const char *suffix, char ***paths);
+
+#endif