X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Fpath-lookup.c;h=8f75a8e83290db85540d544d82af45c4343e2852;hb=086821244b5113f00a0ef993b78dc56aae2a8f6c;hp=1d95f7d1f83f5b4c64305e108366d7c430f8f45a;hpb=f33d3ec1d7521c91da8b30ad5cb345d6416bb07d;p=elogind.git diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 1d95f7d1f..8f75a8e83 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -22,30 +22,38 @@ #include #include #include +#include #include #include #include "util.h" #include "mkdir.h" #include "strv.h" - +#include "path-util.h" #include "path-lookup.h" int user_config_home(char **config_home) { const char *e; + char *r; - if ((e = getenv("XDG_CONFIG_HOME"))) { - if (asprintf(config_home, "%s/systemd/user", e) < 0) + e = getenv("XDG_CONFIG_HOME"); + if (e) { + r = strappend(e, "/systemd/user"); + if (!r) return -ENOMEM; + *config_home = r; return 1; } else { const char *home; - if ((home = getenv("HOME"))) { - if (asprintf(config_home, "%s/.config/systemd/user", home) < 0) + home = getenv("HOME"); + if (home) { + r = strappend(home, "/.config/systemd/user"); + if (!r) return -ENOMEM; + *config_home = r; return 1; } } @@ -53,14 +61,36 @@ int user_config_home(char **config_home) { return 0; } -static char** user_dirs(void) { +int user_runtime_dir(char **runtime_dir) { + const char *e; + char *r; + + e = getenv("XDG_RUNTIME_DIR"); + if (e) { + r = strappend(e, "/systemd/user"); + if (!r) + return -ENOMEM; + + *runtime_dir = r; + return 1; + } + + return 0; +} + +static char** user_dirs( + const char *generator, + const char *generator_early, + const char *generator_late) { + const char * const config_unit_paths[] = { USER_CONFIG_UNIT_PATH, "/etc/systemd/user", - "/run/systemd/user", NULL }; + const char * const runtime_unit_path = "/run/systemd/user"; + const char * const data_unit_paths[] = { "/usr/local/lib/systemd/user", "/usr/local/share/systemd/user", @@ -71,9 +101,9 @@ static char** user_dirs(void) { }; const char *home, *e; - char *config_home = NULL, *data_home = NULL; - char **config_dirs = NULL, **data_dirs = NULL; - char **r = NULL, **t; + _cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL; + _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL; + char **r = NULL; /* Implement the mechanisms defined in * @@ -87,227 +117,249 @@ static char** user_dirs(void) { if (user_config_home(&config_home) < 0) goto fail; + if (user_runtime_dir(&runtime_dir) < 0) + goto fail; + home = getenv("HOME"); - if ((e = getenv("XDG_CONFIG_DIRS"))) - if (!(config_dirs = strv_split(e, ":"))) + e = getenv("XDG_CONFIG_DIRS"); + if (e) { + config_dirs = strv_split(e, ":"); + if (!config_dirs) goto fail; + } /* We don't treat /etc/xdg/systemd here as the spec * suggests because we assume that that is a link to * /etc/systemd/ anyway. */ - if ((e = getenv("XDG_DATA_HOME"))) { + e = getenv("XDG_DATA_HOME"); + if (e) { if (asprintf(&data_home, "%s/systemd/user", e) < 0) goto fail; } else if (home) { if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0) goto fail; - - /* There is really no need for two unit dirs in $HOME, - * except to be fully compliant with the XDG spec. We - * now try to link the two dirs, so that we can - * minimize disk seeks a little. Further down we'll - * then filter out this link, if it is actually is - * one. */ - - mkdir_parents(data_home, 0777); - (void) symlink("../../../.config/systemd/user", data_home); } - if ((e = getenv("XDG_DATA_DIRS"))) + e = getenv("XDG_DATA_DIRS"); + if (e) data_dirs = strv_split(e, ":"); else data_dirs = strv_new("/usr/local/share", "/usr/share", NULL); - if (!data_dirs) goto fail; /* Now merge everything we found. */ - if (config_home) { - if (!(t = strv_append(r, config_home))) + if (generator_early) + if (strv_extend(&r, generator_early) < 0) goto fail; - strv_free(r); - r = t; - } - if (!strv_isempty(config_dirs)) { - if (!(t = strv_merge_concat(r, config_dirs, "/systemd/user"))) - goto finish; - strv_free(r); - r = t; - } + if (config_home) + if (strv_extend(&r, config_home) < 0) + goto fail; + + if (!strv_isempty(config_dirs)) + if (strv_extend_strv_concat(&r, config_dirs, "/systemd/user") < 0) + goto fail; - if (!(t = strv_merge(r, (char**) config_unit_paths))) + if (strv_extend_strv(&r, (char**) config_unit_paths) < 0) goto fail; - strv_free(r); - r = t; - if (data_home) { - if (!(t = strv_append(r, data_home))) + if (runtime_dir) + if (strv_extend(&r, runtime_dir) < 0) goto fail; - strv_free(r); - r = t; - } - if (!strv_isempty(data_dirs)) { - if (!(t = strv_merge_concat(r, data_dirs, "/systemd/user"))) + if (strv_extend(&r, runtime_unit_path) < 0) + goto fail; + + if (generator) + if (strv_extend(&r, generator) < 0) + goto fail; + + if (data_home) + if (strv_extend(&r, data_home) < 0) goto fail; - strv_free(r); - r = t; - } - if (!(t = strv_merge(r, (char**) data_unit_paths))) + if (!strv_isempty(data_dirs)) + if (strv_extend_strv_concat(&r, data_dirs, "/systemd/user") < 0) + goto fail; + + if (strv_extend_strv(&r, (char**) data_unit_paths) < 0) goto fail; - strv_free(r); - r = t; - if (!strv_path_make_absolute_cwd(r)) - goto fail; + if (generator_late) + if (strv_extend(&r, generator_late) < 0) + goto fail; -finish: - free(config_home); - strv_free(config_dirs); - free(data_home); - strv_free(data_dirs); + if (!path_strv_make_absolute_cwd(r)) + goto fail; return r; fail: strv_free(r); - r = NULL; - goto finish; + return NULL; } -int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal) { +int lookup_paths_init( + LookupPaths *p, + SystemdRunningAs running_as, + bool personal, + const char *root_dir, + const char *generator, + const char *generator_early, + const char *generator_late) { + const char *e; - char *t; + bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ assert(p); /* First priority is whatever has been passed to us via env * vars */ - if ((e = getenv("SYSTEMD_UNIT_PATH"))) - if (!(p->unit_path = split_path_and_make_absolute(e))) + e = getenv("SYSTEMD_UNIT_PATH"); + if (e) { + if (endswith(e, ":")) { + e = strndupa(e, strlen(e) - 1); + append = true; + } + + /* FIXME: empty components in other places should be + * rejected. */ + + p->unit_path = path_split_and_make_absolute(e); + if (!p->unit_path) return -ENOMEM; + } else + p->unit_path = NULL; - if (strv_isempty(p->unit_path)) { + if (!p->unit_path || append) { + /* Let's figure something out. */ - /* Nothing is set, so let's figure something out. */ - strv_free(p->unit_path); + _cleanup_strv_free_ char **unit_path; + int r; - if (running_as == MANAGER_USER) { + /* For the user units we include share/ in the search + * path in order to comply with the XDG basedir spec. + * For the system stuff we avoid such nonsense. OTOH + * we include /lib in the search path for the system + * stuff but avoid it for user stuff. */ + if (running_as == SYSTEMD_USER) { if (personal) - p->unit_path = user_dirs(); + unit_path = user_dirs(generator, generator_early, generator_late); else - p->unit_path = strv_new( - /* If you modify this you also want to modify - * systemduserunitpath= in systemd.pc.in, and - * the arrays in user_dirs() above! */ - USER_CONFIG_UNIT_PATH, - "/etc/systemd/user", - "/run/systemd/user", - "/usr/local/lib/systemd/user", - "/usr/local/share/systemd/user", - USER_DATA_UNIT_PATH, - "/usr/lib/systemd/user", - "/usr/share/systemd/user", - NULL); - - if (!p->unit_path) - return -ENOMEM; - + unit_path = strv_new( + /* If you modify this you also want to modify + * systemduserunitpath= in systemd.pc.in, and + * the arrays in user_dirs() above! */ + STRV_IFNOTNULL(generator_early), + USER_CONFIG_UNIT_PATH, + "/etc/systemd/user", + "/run/systemd/user", + STRV_IFNOTNULL(generator), + "/usr/local/lib/systemd/user", + "/usr/local/share/systemd/user", + USER_DATA_UNIT_PATH, + "/usr/lib/systemd/user", + "/usr/share/systemd/user", + STRV_IFNOTNULL(generator_late), + NULL); } else - if (!(p->unit_path = strv_new( - /* If you modify this you also want to modify - * systemdsystemunitpath= in systemd.pc.in! */ - SYSTEM_CONFIG_UNIT_PATH, - "/etc/systemd/system", - "/run/systemd/system", - "/usr/local/lib/systemd/system", - SYSTEM_DATA_UNIT_PATH, - "/usr/lib/systemd/system", + unit_path = strv_new( + /* If you modify this you also want to modify + * systemdsystemunitpath= in systemd.pc.in! */ + STRV_IFNOTNULL(generator_early), + SYSTEM_CONFIG_UNIT_PATH, + "/etc/systemd/system", + "/run/systemd/system", + STRV_IFNOTNULL(generator), + "/usr/local/lib/systemd/system", + SYSTEM_DATA_UNIT_PATH, + "/usr/lib/systemd/system", #ifdef HAVE_SPLIT_USR - "/lib/systemd/system", + "/lib/systemd/system", #endif - NULL))) - return -ENOMEM; - } + STRV_IFNOTNULL(generator_late), + NULL); - if (p->unit_path) - if (!strv_path_canonicalize(p->unit_path)) + if (!unit_path) return -ENOMEM; - strv_uniq(p->unit_path); - strv_path_remove_empty(p->unit_path); + r = strv_extend_strv(&p->unit_path, unit_path); + if (r < 0) + return r; + } - if (!strv_isempty(p->unit_path)) { + if (!path_strv_resolve_uniq(p->unit_path, root_dir)) + return -ENOMEM; - if (!(t = strv_join(p->unit_path, "\n\t"))) + if (!strv_isempty(p->unit_path)) { + _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t"); + if (!t) return -ENOMEM; - log_debug("Looking for unit files in:\n\t%s", t); - free(t); + log_debug("Looking for unit files in (higher priority first):\n\t%s", t); } else { log_debug("Ignoring unit files."); strv_free(p->unit_path); p->unit_path = NULL; } - if (running_as == MANAGER_SYSTEM) { + if (running_as == SYSTEMD_SYSTEM) { #ifdef HAVE_SYSV_COMPAT /* /etc/init.d/ compatibility does not matter to users */ - if ((e = getenv("SYSTEMD_SYSVINIT_PATH"))) - if (!(p->sysvinit_path = split_path_and_make_absolute(e))) + e = getenv("SYSTEMD_SYSVINIT_PATH"); + if (e) { + p->sysvinit_path = path_split_and_make_absolute(e); + if (!p->sysvinit_path) return -ENOMEM; + } else + p->sysvinit_path = NULL; if (strv_isempty(p->sysvinit_path)) { strv_free(p->sysvinit_path); - if (!(p->sysvinit_path = strv_new( - SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */ - NULL))) + p->sysvinit_path = strv_new( + SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */ + NULL); + if (!p->sysvinit_path) return -ENOMEM; } - if ((e = getenv("SYSTEMD_SYSVRCND_PATH"))) - if (!(p->sysvrcnd_path = split_path_and_make_absolute(e))) + e = getenv("SYSTEMD_SYSVRCND_PATH"); + if (e) { + p->sysvrcnd_path = path_split_and_make_absolute(e); + if (!p->sysvrcnd_path) return -ENOMEM; + } else + p->sysvrcnd_path = NULL; if (strv_isempty(p->sysvrcnd_path)) { strv_free(p->sysvrcnd_path); - if (!(p->sysvrcnd_path = strv_new( - SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */ - NULL))) + p->sysvrcnd_path = strv_new( + SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */ + NULL); + if (!p->sysvrcnd_path) return -ENOMEM; } - if (p->sysvinit_path) - if (!strv_path_canonicalize(p->sysvinit_path)) - return -ENOMEM; - - if (p->sysvrcnd_path) - if (!strv_path_canonicalize(p->sysvrcnd_path)) - return -ENOMEM; - - strv_uniq(p->sysvinit_path); - strv_uniq(p->sysvrcnd_path); + if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir)) + return -ENOMEM; - strv_path_remove_empty(p->sysvinit_path); - strv_path_remove_empty(p->sysvrcnd_path); + if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir)) + return -ENOMEM; if (!strv_isempty(p->sysvinit_path)) { - - if (!(t = strv_join(p->sysvinit_path, "\n\t"))) + _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t"); + if (!t) return -ENOMEM; - log_debug("Looking for SysV init scripts in:\n\t%s", t); - free(t); } else { log_debug("Ignoring SysV init scripts."); strv_free(p->sysvinit_path); @@ -315,19 +367,19 @@ int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal } if (!strv_isempty(p->sysvrcnd_path)) { - - if (!(t = strv_join(p->sysvrcnd_path, "\n\t"))) + _cleanup_free_ char *t = + strv_join(p->sysvrcnd_path, "\n\t"); + if (!t) return -ENOMEM; log_debug("Looking for SysV rcN.d links in:\n\t%s", t); - free(t); } else { log_debug("Ignoring SysV rcN.d links."); strv_free(p->sysvrcnd_path); p->sysvrcnd_path = NULL; } #else - log_debug("Disabled SysV init scripts and rcN.d links support"); + log_debug("SysV init scripts and rcN.d links support disabled"); #endif }