X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Fpath-lookup.c;h=63af43cdbb0de55542e54e54b88f0321a5d8bb70;hp=41ebc7f5b3e38c7eafe96437d262cb6067df2a65;hb=b5d742138f71e87312541a89aac5657015f50f48;hpb=9eb977db5b89b44f254ab40c1876a76b7d7ea2d0 diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 41ebc7f5b..63af43cdb 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -31,21 +32,35 @@ #include "path-util.h" #include "path-lookup.h" +static const char* const systemd_running_as_table[_SYSTEMD_RUNNING_AS_MAX] = { + [SYSTEMD_SYSTEM] = "system", + [SYSTEMD_USER] = "user" +}; + +DEFINE_STRING_TABLE_LOOKUP(systemd_running_as, SystemdRunningAs); + 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,7 +68,11 @@ int user_config_home(char **config_home) { return 0; } -static char** user_dirs(void) { +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", @@ -71,9 +90,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, *data_home = NULL; + _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL; + char **r = NULL; /* Implement the mechanisms defined in * @@ -89,15 +108,19 @@ static char** user_dirs(void) { 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; @@ -112,202 +135,216 @@ static char** user_dirs(void) { * then filter out this link, if it is actually is * one. */ - mkdir_parents(data_home, 0777); + mkdir_parents_label(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 (!(t = strv_merge(r, (char**) config_unit_paths))) + if (!strv_isempty(config_dirs)) + if (strv_extend_strv_concat(&r, config_dirs, "/systemd/user") < 0) + goto fail; + + 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 (generator) + if (strv_extend(&r, generator) < 0) goto fail; - strv_free(r); - r = t; - } - if (!strv_isempty(data_dirs)) { - if (!(t = strv_merge_concat(r, data_dirs, "/systemd/user"))) + if (data_home) + if (strv_extend(&r, data_home) < 0) + goto fail; + + if (!strv_isempty(data_dirs)) + if (strv_extend_strv_concat(&r, data_dirs, "/systemd/user") < 0) goto fail; - strv_free(r); - r = t; - } - if (!(t = strv_merge(r, (char**) data_unit_paths))) + if (strv_extend_strv(&r, (char**) data_unit_paths) < 0) goto fail; - strv_free(r); - r = t; - if (!path_strv_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 *generator, + const char *generator_early, + const char *generator_late) { + const char *e; - char *t; assert(p); /* First priority is whatever has been passed to us via env * vars */ - if ((e = getenv("SYSTEMD_UNIT_PATH"))) - if (!(p->unit_path = path_split_and_make_absolute(e))) + e = getenv("SYSTEMD_UNIT_PATH"); + if (e) { + 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)) { - /* Nothing is set, so let's figure something out. */ strv_free(p->unit_path); - 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(); + p->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! */ + 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); if (!p->unit_path) return -ENOMEM; - } 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", + } else { + p->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))) + STRV_IFNOTNULL(generator_late), + NULL); + + if (!p->unit_path) return -ENOMEM; + } } - if (p->unit_path) - if (!path_strv_canonicalize(p->unit_path)) - return -ENOMEM; + if (!path_strv_canonicalize_absolute(p->unit_path, NULL)) + return -ENOMEM; strv_uniq(p->unit_path); - path_strv_remove_empty(p->unit_path); if (!strv_isempty(p->unit_path)) { - - if (!(t = strv_join(p->unit_path, "\n\t"))) + _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 = path_split_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 = path_split_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 (!path_strv_canonicalize(p->sysvinit_path)) - return -ENOMEM; + if (!path_strv_canonicalize_absolute(p->sysvinit_path, NULL)) + return -ENOMEM; - if (p->sysvrcnd_path) - if (!path_strv_canonicalize(p->sysvrcnd_path)) - return -ENOMEM; + if (!path_strv_canonicalize_absolute(p->sysvrcnd_path, NULL)) + return -ENOMEM; strv_uniq(p->sysvinit_path); strv_uniq(p->sysvrcnd_path); - path_strv_remove_empty(p->sysvinit_path); - path_strv_remove_empty(p->sysvrcnd_path); - 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 +352,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 }