From 9a00f57a5ba7ed431e6bac8d8b36518708503b4e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 2 Jul 2014 12:23:36 +0200 Subject: [PATCH] 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. --- .gitignore | 1 + Makefile-man.am | 2 + Makefile.am | 20 +- man/file-hierarchy.xml | 20 +- man/systemd-path.xml | 111 ++++++ src/libsystemd/sd-path/Makefile | 1 + src/libsystemd/sd-path/sd-path.c | 626 +++++++++++++++++++++++++++++++ src/path/Makefile | 1 + src/path/path.c | 208 ++++++++++ src/shared/architecture.h | 51 ++- src/shared/strv.c | 34 ++ src/shared/strv.h | 2 + src/shared/util.c | 4 +- src/systemd/sd-path.h | 87 +++++ 14 files changed, 1157 insertions(+), 11 deletions(-) create mode 100644 man/systemd-path.xml create mode 120000 src/libsystemd/sd-path/Makefile create mode 100644 src/libsystemd/sd-path/sd-path.c create mode 120000 src/path/Makefile create mode 100644 src/path/path.c create mode 100644 src/systemd/sd-path.h diff --git a/.gitignore b/.gitignore index fe8c32d42..9523ea027 100644 --- a/.gitignore +++ b/.gitignore @@ -86,6 +86,7 @@ /systemd-networkd-wait-online /systemd-notify /systemd-nspawn +/systemd-path /systemd-quotacheck /systemd-random-seed /systemd-rc-local-generator diff --git a/Makefile-man.am b/Makefile-man.am index 3840bb138..5c289dda2 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -74,6 +74,7 @@ MANPAGES += \ man/systemd-machine-id-setup.1 \ man/systemd-notify.1 \ man/systemd-nspawn.1 \ + man/systemd-path.1 \ man/systemd-remount-fs.service.8 \ man/systemd-run.1 \ man/systemd-shutdownd.service.8 \ @@ -1619,6 +1620,7 @@ EXTRA_DIST += \ man/systemd-networkd.service.xml \ man/systemd-notify.xml \ man/systemd-nspawn.xml \ + man/systemd-path.xml \ man/systemd-quotacheck.service.xml \ man/systemd-random-seed.service.xml \ man/systemd-readahead-replay.service.xml \ diff --git a/Makefile.am b/Makefile.am index 092153b56..d2edf3daa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -187,6 +187,8 @@ AM_CPPFLAGS = \ -DPOLKIT_AGENT_BINARY_PATH=\"$(bindir)/pkttyagent\" \ -DQUOTACHECK=\"$(QUOTACHECK)\" \ -DKEXEC=\"$(KEXEC)\" \ + -DLIBDIR=\"$(libdir)\" \ + -DROOTLIBDIR=\"$(rootlibdir)\" \ -I $(top_srcdir)/src \ -I $(top_builddir)/src/shared \ -I $(top_srcdir)/src/shared \ @@ -344,7 +346,8 @@ bin_PROGRAMS = \ systemd-detect-virt \ systemd-delta \ systemd-analyze \ - systemd-run + systemd-run \ + systemd-path dist_bin_SCRIPTS = \ src/kernel-install/kernel-install @@ -2096,6 +2099,14 @@ systemd_notify_LDADD = \ libsystemd-internal.la \ libsystemd-shared.la +# ------------------------------------------------------------------------------ +systemd_path_SOURCES = \ + src/path/path.c + +systemd_path_LDADD = \ + libsystemd-internal.la \ + libsystemd-shared.la + # ------------------------------------------------------------------------------ systemd_ask_password_SOURCES = \ src/ask-password/ask-password.c @@ -2221,6 +2232,7 @@ libsystemd_internal_la_SOURCES = \ src/systemd/sd-login.h \ src/systemd/sd-id128.h \ src/systemd/sd-daemon.h \ + src/systemd/sd-path.h \ src/libsystemd/sd-bus/sd-bus.c \ src/libsystemd/sd-bus/bus-control.c \ src/libsystemd/sd-bus/bus-control.h \ @@ -2274,7 +2286,8 @@ libsystemd_internal_la_SOURCES = \ src/libsystemd/sd-rtnl/rtnl-util.c \ src/libsystemd/sd-id128/sd-id128.c \ src/libsystemd/sd-daemon/sd-daemon.c \ - src/libsystemd/sd-login/sd-login.c + src/libsystemd/sd-login/sd-login.c \ + src/libsystemd/sd-path/sd-path.c nodist_libsystemd_internal_la_SOURCES = \ src/libsystemd/libsystemd.sym \ @@ -2377,7 +2390,8 @@ pkginclude_HEADERS += \ src/systemd/sd-utf8.h \ src/systemd/sd-event.h \ src/systemd/sd-rtnl.h \ - src/systemd/sd-resolve.h + src/systemd/sd-resolve.h \ + src/systemd/sd-path.h endif lib_LTLIBRARIES += \ diff --git a/man/file-hierarchy.xml b/man/file-hierarchy.xml index 4d542caad..a996bb69d 100644 --- a/man/file-hierarchy.xml +++ b/man/file-hierarchy.xml @@ -62,6 +62,11 @@ subset of these specifications that defines more strictly the suggestions and restrictions systemd makes on the file system hierarchy. + + Many of the paths described here are queriable + with the + systemd-path1 + tool. @@ -296,8 +301,8 @@ /usr/lib/arch-id Location for placing - dynamic libraries, called $libdir. - The architecture identifier to use, is defined on $libdir. + The architecture identifier to use is defined on Multiarch Architecture Specifiers (Tuples) list. Legacy locations of $libdir are /usr/lib, @@ -309,7 +314,10 @@ $libdir for the primary architecture of the system, invoke: - # pkg-config --variable=libdir systemd + # pkg-config --variable=libdir systemd or + # systemd-path system-library-arch + + @@ -621,7 +629,10 @@ of these directories are also standardized (though more weakly) by the XDG - Base Directory Specification. + Base Directory Specification. Additional + locations for high-level user resources are defined by + xdg-user-dirs. @@ -952,6 +963,7 @@ systemd1, hier7, + systemd-path1, systemd-boot-generator8, sysctl.d5, tmpfiles.d5, diff --git a/man/systemd-path.xml b/man/systemd-path.xml new file mode 100644 index 000000000..fc01d5edd --- /dev/null +++ b/man/systemd-path.xml @@ -0,0 +1,111 @@ + + + + + + + + + systemd-path + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-path + 1 + + + + systemd-path + List and query system and user paths + + + + + systemd-path OPTIONS NAME + + + + + Description + + systemd-path may be used to + query system and user paths. The tool makes many of + the paths described in + file-hierarchy7 + queriable. + + When invoked without arguments a list of known + paths and their current values is shown. When at least + one argument is passed the path with this is name is + queried and its value shown. The variables whose name + begins with search- don't refer to + individual paths, but instead a to a list of + colon-separated search paths, in their order of + precedence. + + + + Options + + The following options are understood: + + + + + + The printed paths are + suffixed by the specified + string. + + + + + + + + + + Exit status + + On success, 0 is returned, a non-zero failure + code otherwise. + + + + See Also + + systemd1, + file-hierarchy7 + + + + diff --git a/src/libsystemd/sd-path/Makefile b/src/libsystemd/sd-path/Makefile new file mode 120000 index 000000000..d0b0e8e00 --- /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 000000000..44c1b8bd7 --- /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 . +***/ + +#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 000000000..d0b0e8e00 --- /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 000000000..c2936e0bc --- /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 . +***/ + +#include +#include +#include +#include +#include +#include +#include + +#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 20e848bd8..08079244d 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 1ef0b26a2..b4c476eff 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 e26ab828d..3034073d3 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 9b5a47ab6..a1c8baf23 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 000000000..e238c0ce2 --- /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 . +***/ + +#include + +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 -- 2.30.2