2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2015-11-16 22:09:36 +01:00
|
|
|
#include <errno.h>
|
2010-06-15 14:45:15 +02:00
|
|
|
#include <stdio.h>
|
2015-11-16 22:09:36 +01:00
|
|
|
#include <stdlib.h>
|
2012-09-18 17:11:12 +02:00
|
|
|
#include <string.h>
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2017-09-14 19:26:29 +02:00
|
|
|
#include "fs-util.h"
|
2015-03-15 02:46:59 +01:00
|
|
|
#include "install.h"
|
2015-12-03 21:13:37 +01:00
|
|
|
#include "log.h"
|
|
|
|
#include "macro.h"
|
2016-02-25 01:44:30 +01:00
|
|
|
#include "mkdir.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "path-lookup.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "path-util.h"
|
2016-04-06 21:02:36 +02:00
|
|
|
#include "rm-rf.h"
|
2016-02-25 00:16:51 +01:00
|
|
|
#include "stat-util.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "string-util.h"
|
|
|
|
#include "strv.h"
|
2018-11-30 21:05:27 +01:00
|
|
|
#include "tmpfile-util.h"
|
2017-02-10 15:16:11 +01:00
|
|
|
#include "user-util.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "util.h"
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2017-11-23 11:41:28 +01:00
|
|
|
int xdg_user_runtime_dir(char **ret, const char *suffix) {
|
2010-06-16 01:58:50 +02:00
|
|
|
const char *e;
|
2016-02-29 20:41:54 +01:00
|
|
|
char *j;
|
|
|
|
|
|
|
|
assert(ret);
|
2016-04-06 21:02:36 +02:00
|
|
|
assert(suffix);
|
2010-06-16 01:58:50 +02:00
|
|
|
|
2016-04-06 21:02:36 +02:00
|
|
|
e = getenv("XDG_RUNTIME_DIR");
|
|
|
|
if (!e)
|
|
|
|
return -ENXIO;
|
2016-02-29 20:41:54 +01:00
|
|
|
|
2016-04-06 21:02:36 +02:00
|
|
|
j = strappend(e, suffix);
|
|
|
|
if (!j)
|
|
|
|
return -ENOMEM;
|
2010-06-16 01:58:50 +02:00
|
|
|
|
2016-02-29 20:41:54 +01:00
|
|
|
*ret = j;
|
2010-06-16 01:58:50 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-11-23 11:41:28 +01:00
|
|
|
int xdg_user_config_dir(char **ret, const char *suffix) {
|
2014-09-28 23:54:25 +02:00
|
|
|
const char *e;
|
2016-02-29 20:41:54 +01:00
|
|
|
char *j;
|
2017-02-10 15:16:11 +01:00
|
|
|
int r;
|
2016-02-29 20:41:54 +01:00
|
|
|
|
|
|
|
assert(ret);
|
2014-09-28 23:54:25 +02:00
|
|
|
|
2016-04-06 21:02:36 +02:00
|
|
|
e = getenv("XDG_CONFIG_HOME");
|
|
|
|
if (e)
|
|
|
|
j = strappend(e, suffix);
|
|
|
|
else {
|
2017-02-10 15:16:11 +01:00
|
|
|
_cleanup_free_ char *home = NULL;
|
2016-04-06 21:02:36 +02:00
|
|
|
|
2017-02-10 15:16:11 +01:00
|
|
|
r = get_home_dir(&home);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-04-06 21:02:36 +02:00
|
|
|
|
2016-10-23 17:43:27 +02:00
|
|
|
j = strjoin(home, "/.config", suffix);
|
2016-04-06 21:02:36 +02:00
|
|
|
}
|
2014-09-28 23:54:25 +02:00
|
|
|
|
2016-02-29 20:41:54 +01:00
|
|
|
if (!j)
|
|
|
|
return -ENOMEM;
|
2014-09-28 23:54:25 +02:00
|
|
|
|
2016-02-29 20:41:54 +01:00
|
|
|
*ret = j;
|
2014-09-28 23:54:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-11-23 11:41:28 +01:00
|
|
|
int xdg_user_data_dir(char **ret, const char *suffix) {
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
const char *e;
|
2016-02-29 20:41:54 +01:00
|
|
|
char *j;
|
2017-02-10 15:16:11 +01:00
|
|
|
int r;
|
2016-02-29 20:41:54 +01:00
|
|
|
|
|
|
|
assert(ret);
|
2016-02-29 20:56:47 +01:00
|
|
|
assert(suffix);
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
|
|
|
|
/* We don't treat /etc/xdg/systemd here as the spec
|
2016-07-10 14:48:23 +02:00
|
|
|
* suggests because we assume that is a link to
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
* /etc/systemd/ anyway. */
|
|
|
|
|
|
|
|
e = getenv("XDG_DATA_HOME");
|
|
|
|
if (e)
|
2016-02-29 20:41:54 +01:00
|
|
|
j = strappend(e, suffix);
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
else {
|
2017-02-10 15:16:11 +01:00
|
|
|
_cleanup_free_ char *home = NULL;
|
2016-02-29 20:41:54 +01:00
|
|
|
|
2017-02-10 15:16:11 +01:00
|
|
|
r = get_home_dir(&home);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-02-29 20:41:54 +01:00
|
|
|
|
2016-10-23 17:43:27 +02:00
|
|
|
j = strjoin(home, "/.local/share", suffix);
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
}
|
2016-02-29 20:41:54 +01:00
|
|
|
if (!j)
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-02-29 20:41:54 +01:00
|
|
|
*ret = j;
|
2016-02-24 21:24:23 +01:00
|
|
|
return 1;
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
}
|
|
|
|
|
2017-09-22 14:46:09 +02:00
|
|
|
static const char* const user_data_unit_paths[] = {
|
|
|
|
"/usr/local/lib/systemd/user",
|
|
|
|
"/usr/local/share/systemd/user",
|
|
|
|
USER_DATA_UNIT_PATH,
|
|
|
|
"/usr/lib/systemd/user",
|
|
|
|
"/usr/share/systemd/user",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char* const user_config_unit_paths[] = {
|
|
|
|
USER_CONFIG_UNIT_PATH,
|
|
|
|
"/etc/systemd/user",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2017-11-23 11:41:28 +01:00
|
|
|
int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs) {
|
2010-06-15 14:45:15 +02:00
|
|
|
/* Implement the mechanisms defined in
|
|
|
|
*
|
|
|
|
* http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
|
|
|
|
*
|
|
|
|
* We look in both the config and the data dirs because we
|
|
|
|
* want to encourage that distributors ship their unit files
|
|
|
|
* as data, and allow overriding as configuration.
|
|
|
|
*/
|
2017-11-23 11:41:28 +01:00
|
|
|
const char *e;
|
|
|
|
_cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2012-05-23 03:43:29 +02:00
|
|
|
e = getenv("XDG_CONFIG_DIRS");
|
|
|
|
if (e) {
|
|
|
|
config_dirs = strv_split(e, ":");
|
|
|
|
if (!config_dirs)
|
2017-11-23 11:41:28 +01:00
|
|
|
return -ENOMEM;
|
2012-05-23 03:43:29 +02:00
|
|
|
}
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2012-05-23 03:43:29 +02:00
|
|
|
e = getenv("XDG_DATA_DIRS");
|
|
|
|
if (e)
|
2010-06-15 14:45:15 +02:00
|
|
|
data_dirs = strv_split(e, ":");
|
|
|
|
else
|
2011-04-04 19:02:32 +02:00
|
|
|
data_dirs = strv_new("/usr/local/share",
|
2018-10-31 17:03:50 +01:00
|
|
|
"/usr/share");
|
2010-06-15 14:45:15 +02:00
|
|
|
if (!data_dirs)
|
2017-11-23 11:41:28 +01:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-10-08 16:59:31 +02:00
|
|
|
*ret_config_dirs = TAKE_PTR(config_dirs);
|
|
|
|
*ret_data_dirs = TAKE_PTR(data_dirs);
|
|
|
|
|
2017-11-23 11:41:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char** user_dirs(
|
|
|
|
const char *persistent_config,
|
|
|
|
const char *runtime_config,
|
2018-02-08 13:57:05 +01:00
|
|
|
const char *global_persistent_config,
|
|
|
|
const char *global_runtime_config,
|
2017-11-23 11:41:28 +01:00
|
|
|
const char *generator,
|
|
|
|
const char *generator_early,
|
|
|
|
const char *generator_late,
|
|
|
|
const char *transient,
|
|
|
|
const char *persistent_control,
|
|
|
|
const char *runtime_control) {
|
|
|
|
|
|
|
|
_cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
|
|
|
|
_cleanup_free_ char *data_home = NULL;
|
|
|
|
_cleanup_strv_free_ char **res = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = xdg_user_dirs(&config_dirs, &data_dirs);
|
|
|
|
if (r < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
r = xdg_user_data_dir(&data_home, "/systemd/user");
|
|
|
|
if (r < 0 && r != -ENXIO)
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
return NULL;
|
2010-06-15 14:45:15 +02:00
|
|
|
|
|
|
|
/* Now merge everything we found. */
|
2016-04-06 21:02:36 +02:00
|
|
|
if (strv_extend(&res, persistent_control) < 0)
|
|
|
|
return NULL;
|
2016-02-25 01:13:57 +01:00
|
|
|
|
2016-04-06 21:02:36 +02:00
|
|
|
if (strv_extend(&res, runtime_control) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (strv_extend(&res, transient) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (strv_extend(&res, generator_early) < 0)
|
|
|
|
return NULL;
|
2012-05-23 03:43:29 +02:00
|
|
|
|
2017-02-10 15:17:18 +01:00
|
|
|
if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
|
|
|
|
return NULL;
|
2014-09-28 23:54:25 +02:00
|
|
|
|
2016-02-24 17:18:42 +01:00
|
|
|
if (strv_extend(&res, persistent_config) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2018-02-08 13:57:05 +01:00
|
|
|
/* global config has lower priority than the user config of the same type */
|
|
|
|
if (strv_extend(&res, global_persistent_config) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2017-09-22 14:46:09 +02:00
|
|
|
if (strv_extend_strv(&res, (char**) user_config_unit_paths, false) < 0)
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
return NULL;
|
2014-09-28 23:54:25 +02:00
|
|
|
|
2016-02-24 17:18:42 +01:00
|
|
|
if (strv_extend(&res, runtime_config) < 0)
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
return NULL;
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2018-02-08 13:57:05 +01:00
|
|
|
if (strv_extend(&res, global_runtime_config) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
2016-04-06 21:02:36 +02:00
|
|
|
if (strv_extend(&res, generator) < 0)
|
|
|
|
return NULL;
|
2012-05-23 03:43:29 +02:00
|
|
|
|
2016-04-06 21:02:36 +02:00
|
|
|
if (strv_extend(&res, data_home) < 0)
|
|
|
|
return NULL;
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2017-02-10 15:17:18 +01:00
|
|
|
if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
|
|
|
|
return NULL;
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2017-09-22 14:46:09 +02:00
|
|
|
if (strv_extend_strv(&res, (char**) user_data_unit_paths, false) < 0)
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
return NULL;
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2016-04-06 21:02:36 +02:00
|
|
|
if (strv_extend(&res, generator_late) < 0)
|
|
|
|
return NULL;
|
2012-05-23 03:43:29 +02:00
|
|
|
|
2015-10-22 19:28:31 +02:00
|
|
|
if (path_strv_make_absolute_cwd(res) < 0)
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
return NULL;
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2018-03-22 16:53:26 +01:00
|
|
|
return TAKE_PTR(res);
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
}
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2017-09-22 14:46:09 +02:00
|
|
|
bool path_is_user_data_dir(const char *path) {
|
|
|
|
assert(path);
|
|
|
|
|
|
|
|
return strv_contains((char**) user_data_unit_paths, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool path_is_user_config_dir(const char *path) {
|
|
|
|
assert(path);
|
|
|
|
|
|
|
|
return strv_contains((char**) user_config_unit_paths, path);
|
|
|
|
}
|
|
|
|
|
2016-02-24 15:31:33 +01:00
|
|
|
static int acquire_generator_dirs(
|
2016-02-24 21:24:23 +01:00
|
|
|
UnitFileScope scope,
|
2017-09-14 19:26:29 +02:00
|
|
|
const char *tempdir,
|
2016-02-24 15:31:33 +01:00
|
|
|
char **generator,
|
|
|
|
char **generator_early,
|
|
|
|
char **generator_late) {
|
|
|
|
|
|
|
|
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
|
|
|
|
const char *prefix;
|
|
|
|
|
|
|
|
assert(generator);
|
|
|
|
assert(generator_early);
|
|
|
|
assert(generator_late);
|
2017-09-14 19:26:29 +02:00
|
|
|
assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
|
2016-02-24 15:31:33 +01:00
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
if (scope == UNIT_FILE_GLOBAL)
|
|
|
|
return -EOPNOTSUPP;
|
2016-02-24 21:24:23 +01:00
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
if (tempdir)
|
|
|
|
prefix = tempdir;
|
|
|
|
else if (scope == UNIT_FILE_SYSTEM)
|
|
|
|
prefix = "/run/systemd";
|
2018-06-20 08:17:38 +02:00
|
|
|
else {
|
|
|
|
/* UNIT_FILE_USER */
|
2016-02-24 21:24:23 +01:00
|
|
|
const char *e;
|
2016-02-24 15:31:33 +01:00
|
|
|
|
|
|
|
e = getenv("XDG_RUNTIME_DIR");
|
|
|
|
if (!e)
|
2016-02-24 21:24:23 +01:00
|
|
|
return -ENXIO;
|
2016-02-24 15:31:33 +01:00
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
prefix = strjoina(e, "/systemd");
|
2016-02-24 15:31:33 +01:00
|
|
|
}
|
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
x = strappend(prefix, "/generator");
|
2016-02-24 15:31:33 +01:00
|
|
|
if (!x)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
y = strappend(prefix, "/generator.early");
|
2016-02-24 15:31:33 +01:00
|
|
|
if (!y)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
z = strappend(prefix, "/generator.late");
|
2016-02-24 15:31:33 +01:00
|
|
|
if (!z)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*generator = TAKE_PTR(x);
|
|
|
|
*generator_early = TAKE_PTR(y);
|
|
|
|
*generator_late = TAKE_PTR(z);
|
2016-02-24 15:31:33 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
static int acquire_transient_dir(
|
|
|
|
UnitFileScope scope,
|
|
|
|
const char *tempdir,
|
|
|
|
char **ret) {
|
2016-02-25 01:13:57 +01:00
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
char *transient;
|
2016-02-25 01:13:57 +01:00
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
assert(ret);
|
|
|
|
assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
|
2016-02-25 01:13:57 +01:00
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
if (scope == UNIT_FILE_GLOBAL)
|
|
|
|
return -EOPNOTSUPP;
|
2016-02-25 01:13:57 +01:00
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
if (tempdir)
|
|
|
|
transient = strjoin(tempdir, "/transient");
|
|
|
|
else if (scope == UNIT_FILE_SYSTEM)
|
|
|
|
transient = strdup("/run/systemd/transient");
|
|
|
|
else
|
2017-11-23 11:41:28 +01:00
|
|
|
return xdg_user_runtime_dir(ret, "/systemd/transient");
|
2016-02-29 20:56:47 +01:00
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
if (!transient)
|
|
|
|
return -ENOMEM;
|
|
|
|
*ret = transient;
|
|
|
|
return 0;
|
2016-02-25 01:13:57 +01:00
|
|
|
}
|
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
|
2016-02-24 17:18:42 +01:00
|
|
|
_cleanup_free_ char *a = NULL, *b = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(persistent);
|
|
|
|
assert(runtime);
|
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
switch (scope) {
|
|
|
|
|
|
|
|
case UNIT_FILE_SYSTEM:
|
2016-02-24 17:18:42 +01:00
|
|
|
a = strdup(SYSTEM_CONFIG_UNIT_PATH);
|
|
|
|
b = strdup("/run/systemd/system");
|
2016-02-24 21:24:23 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case UNIT_FILE_GLOBAL:
|
|
|
|
a = strdup(USER_CONFIG_UNIT_PATH);
|
|
|
|
b = strdup("/run/systemd/user");
|
|
|
|
break;
|
2016-02-24 17:18:42 +01:00
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
case UNIT_FILE_USER:
|
2017-11-23 11:41:28 +01:00
|
|
|
r = xdg_user_config_dir(&a, "/systemd/user");
|
2017-02-10 15:18:23 +01:00
|
|
|
if (r < 0 && r != -ENXIO)
|
2016-02-24 17:18:42 +01:00
|
|
|
return r;
|
|
|
|
|
2017-11-23 11:41:28 +01:00
|
|
|
r = xdg_user_runtime_dir(runtime, "/systemd/user");
|
2017-02-10 15:18:23 +01:00
|
|
|
if (r < 0) {
|
|
|
|
if (r != -ENXIO)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
/* If XDG_RUNTIME_DIR is not set, don't consider that fatal, simply initialize the runtime
|
|
|
|
* directory to NULL */
|
|
|
|
*runtime = NULL;
|
|
|
|
}
|
2016-02-24 17:18:42 +01:00
|
|
|
|
2018-03-22 16:53:26 +01:00
|
|
|
*persistent = TAKE_PTR(a);
|
2016-02-24 17:18:42 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
default:
|
|
|
|
assert_not_reached("Hmm, unexpected scope value.");
|
2016-02-24 17:18:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!a || !b)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*persistent = TAKE_PTR(a);
|
|
|
|
*runtime = TAKE_PTR(b);
|
2016-02-24 17:18:42 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-06 21:02:36 +02:00
|
|
|
static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
|
|
|
|
_cleanup_free_ char *a = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(persistent);
|
|
|
|
assert(runtime);
|
|
|
|
|
|
|
|
switch (scope) {
|
|
|
|
|
|
|
|
case UNIT_FILE_SYSTEM: {
|
|
|
|
_cleanup_free_ char *b = NULL;
|
|
|
|
|
|
|
|
a = strdup("/etc/systemd/system.control");
|
|
|
|
if (!a)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
b = strdup("/run/systemd/system.control");
|
|
|
|
if (!b)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-03-22 16:53:26 +01:00
|
|
|
*runtime = TAKE_PTR(b);
|
2016-04-06 21:02:36 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case UNIT_FILE_USER:
|
2018-02-08 14:36:17 +01:00
|
|
|
r = xdg_user_config_dir(&a, "/systemd/user.control");
|
2017-02-10 15:18:23 +01:00
|
|
|
if (r < 0 && r != -ENXIO)
|
2016-04-06 21:02:36 +02:00
|
|
|
return r;
|
|
|
|
|
2018-02-08 14:36:17 +01:00
|
|
|
r = xdg_user_runtime_dir(runtime, "/systemd/user.control");
|
2017-02-10 15:18:23 +01:00
|
|
|
if (r < 0) {
|
|
|
|
if (r != -ENXIO)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
/* If XDG_RUNTIME_DIR is not set, don't consider this fatal, simply initialize the directory to
|
|
|
|
* NULL */
|
|
|
|
*runtime = NULL;
|
|
|
|
}
|
2016-04-06 21:02:36 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case UNIT_FILE_GLOBAL:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Hmm, unexpected scope value.");
|
|
|
|
}
|
|
|
|
|
2018-03-22 16:53:26 +01:00
|
|
|
*persistent = TAKE_PTR(a);
|
2016-04-06 21:02:36 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-08 17:22:06 +02:00
|
|
|
static int acquire_attached_dirs(
|
|
|
|
UnitFileScope scope,
|
|
|
|
char **ret_persistent,
|
|
|
|
char **ret_runtime) {
|
|
|
|
|
|
|
|
_cleanup_free_ char *a = NULL, *b = NULL;
|
|
|
|
|
|
|
|
assert(ret_persistent);
|
|
|
|
assert(ret_runtime);
|
|
|
|
|
|
|
|
/* Portable services are not available to regular users for now. */
|
|
|
|
if (scope != UNIT_FILE_SYSTEM)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
a = strdup("/etc/systemd/system.attached");
|
|
|
|
if (!a)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
b = strdup("/run/systemd/system.attached");
|
|
|
|
if (!b)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*ret_persistent = TAKE_PTR(a);
|
|
|
|
*ret_runtime = TAKE_PTR(b);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-24 15:31:33 +01:00
|
|
|
static int patch_root_prefix(char **p, const char *root_dir) {
|
|
|
|
char *c;
|
|
|
|
|
|
|
|
assert(p);
|
|
|
|
|
|
|
|
if (!*p)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
c = prefix_root(root_dir, *p);
|
|
|
|
if (!c)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
free(*p);
|
|
|
|
*p = c;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-25 02:32:19 +01:00
|
|
|
static int patch_root_prefix_strv(char **l, const char *root_dir) {
|
|
|
|
char **i;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!root_dir)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
STRV_FOREACH(i, l) {
|
|
|
|
r = patch_root_prefix(i, root_dir);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-23 03:43:29 +02:00
|
|
|
int lookup_paths_init(
|
|
|
|
LookupPaths *p,
|
2016-02-24 21:24:23 +01:00
|
|
|
UnitFileScope scope,
|
2016-04-07 18:48:01 +02:00
|
|
|
LookupPathsFlags flags,
|
2016-02-24 15:31:33 +01:00
|
|
|
const char *root_dir) {
|
2012-05-23 03:43:29 +02:00
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
_cleanup_(rmdir_and_freep) char *tempdir = NULL;
|
2016-02-25 00:16:51 +01:00
|
|
|
_cleanup_free_ char
|
|
|
|
*root = NULL,
|
2016-02-25 01:13:57 +01:00
|
|
|
*persistent_config = NULL, *runtime_config = NULL,
|
2018-02-08 13:57:05 +01:00
|
|
|
*global_persistent_config = NULL, *global_runtime_config = NULL,
|
2016-02-25 00:16:51 +01:00
|
|
|
*generator = NULL, *generator_early = NULL, *generator_late = NULL,
|
2016-04-06 21:02:36 +02:00
|
|
|
*transient = NULL,
|
2018-10-08 17:22:06 +02:00
|
|
|
*persistent_control = NULL, *runtime_control = NULL,
|
|
|
|
*persistent_attached = NULL, *runtime_attached = NULL;
|
2014-07-20 23:56:57 +02:00
|
|
|
bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
|
2016-04-14 03:10:33 +02:00
|
|
|
_cleanup_strv_free_ char **paths = NULL;
|
2016-02-24 15:31:33 +01:00
|
|
|
const char *e;
|
2015-10-22 19:28:31 +02:00
|
|
|
int r;
|
2010-06-15 14:45:15 +02:00
|
|
|
|
|
|
|
assert(p);
|
2016-02-24 21:24:23 +01:00
|
|
|
assert(scope >= 0);
|
|
|
|
assert(scope < _UNIT_FILE_SCOPE_MAX);
|
2016-02-24 15:31:33 +01:00
|
|
|
|
2018-04-16 12:36:07 +02:00
|
|
|
#if HAVE_SPLIT_USR
|
|
|
|
flags |= LOOKUP_PATHS_SPLIT_USR;
|
|
|
|
#endif
|
|
|
|
|
2018-04-18 14:20:49 +02:00
|
|
|
if (!empty_or_root(root_dir)) {
|
2016-02-25 00:16:51 +01:00
|
|
|
if (scope == UNIT_FILE_USER)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
r = is_dir(root_dir, true);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
return -ENOTDIR;
|
|
|
|
|
|
|
|
root = strdup(root_dir);
|
|
|
|
if (!root)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2017-09-14 19:26:29 +02:00
|
|
|
if (flags & LOOKUP_PATHS_TEMPORARY_GENERATED) {
|
|
|
|
r = mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir);
|
|
|
|
if (r < 0)
|
2018-10-09 16:44:04 +02:00
|
|
|
return log_debug_errno(r, "Failed to create temporary directory: %m");
|
2017-09-14 19:26:29 +02:00
|
|
|
}
|
|
|
|
|
2017-02-10 15:18:23 +01:00
|
|
|
/* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
|
2016-02-24 21:24:23 +01:00
|
|
|
r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
|
2017-02-10 15:18:23 +01:00
|
|
|
if (r < 0)
|
2016-02-24 17:18:42 +01:00
|
|
|
return r;
|
|
|
|
|
2018-02-08 13:57:05 +01:00
|
|
|
if (scope == UNIT_FILE_USER) {
|
|
|
|
r = acquire_config_dirs(UNIT_FILE_GLOBAL, &global_persistent_config, &global_runtime_config);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2016-04-07 18:48:01 +02:00
|
|
|
if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
|
2017-02-10 15:18:23 +01:00
|
|
|
/* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
|
2017-09-14 19:26:29 +02:00
|
|
|
r = acquire_generator_dirs(scope, tempdir,
|
|
|
|
&generator, &generator_early, &generator_late);
|
2017-10-04 16:01:32 +02:00
|
|
|
if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
|
2016-04-07 18:48:01 +02:00
|
|
|
return r;
|
|
|
|
}
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2017-02-10 15:18:23 +01:00
|
|
|
/* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
|
2017-09-14 19:26:29 +02:00
|
|
|
r = acquire_transient_dir(scope, tempdir, &transient);
|
2017-10-04 16:01:32 +02:00
|
|
|
if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
|
2016-02-25 01:13:57 +01:00
|
|
|
return r;
|
|
|
|
|
2017-02-10 15:18:23 +01:00
|
|
|
/* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
|
2016-04-06 21:02:36 +02:00
|
|
|
r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
|
2017-02-10 15:18:23 +01:00
|
|
|
if (r < 0 && r != -EOPNOTSUPP)
|
2016-04-06 21:02:36 +02:00
|
|
|
return r;
|
|
|
|
|
2018-10-08 17:22:06 +02:00
|
|
|
r = acquire_attached_dirs(scope, &persistent_attached, &runtime_attached);
|
|
|
|
if (r < 0 && r != -EOPNOTSUPP)
|
|
|
|
return r;
|
|
|
|
|
2016-02-25 01:44:30 +01:00
|
|
|
/* First priority is whatever has been passed to us via env vars */
|
2012-05-23 03:43:29 +02:00
|
|
|
e = getenv("SYSTEMD_UNIT_PATH");
|
|
|
|
if (e) {
|
2016-02-24 15:31:33 +01:00
|
|
|
const char *k;
|
|
|
|
|
|
|
|
k = endswith(e, ":");
|
|
|
|
if (k) {
|
|
|
|
e = strndupa(e, k - e);
|
2014-07-20 23:56:57 +02:00
|
|
|
append = true;
|
|
|
|
}
|
|
|
|
|
2017-02-11 17:32:17 +01:00
|
|
|
/* FIXME: empty components in other places should be rejected. */
|
2014-07-20 23:56:57 +02:00
|
|
|
|
2016-04-14 03:10:33 +02:00
|
|
|
r = path_split_and_make_absolute(e, &paths);
|
2015-10-22 19:28:31 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-04-14 03:10:33 +02:00
|
|
|
}
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2016-04-14 03:10:33 +02:00
|
|
|
if (!paths || append) {
|
2014-07-20 23:56:57 +02:00
|
|
|
/* Let's figure something out. */
|
|
|
|
|
2016-02-24 15:31:33 +01:00
|
|
|
_cleanup_strv_free_ char **add = NULL;
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2012-05-23 03:43:29 +02:00
|
|
|
/* For the user units we include share/ in the search
|
2014-07-20 23:56:57 +02:00
|
|
|
* 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. */
|
2012-05-23 03:43:29 +02:00
|
|
|
|
2016-02-24 21:24:23 +01:00
|
|
|
switch (scope) {
|
|
|
|
|
|
|
|
case UNIT_FILE_SYSTEM:
|
|
|
|
add = strv_new(
|
|
|
|
/* If you modify this you also want to modify
|
|
|
|
* systemdsystemunitpath= in systemd.pc.in! */
|
2016-04-06 21:02:36 +02:00
|
|
|
STRV_IFNOTNULL(persistent_control),
|
|
|
|
STRV_IFNOTNULL(runtime_control),
|
2016-02-25 01:13:57 +01:00
|
|
|
STRV_IFNOTNULL(transient),
|
2016-02-24 21:24:23 +01:00
|
|
|
STRV_IFNOTNULL(generator_early),
|
|
|
|
persistent_config,
|
2016-02-25 00:54:31 +01:00
|
|
|
SYSTEM_CONFIG_UNIT_PATH,
|
2016-02-24 21:24:23 +01:00
|
|
|
"/etc/systemd/system",
|
2018-10-08 17:22:06 +02:00
|
|
|
STRV_IFNOTNULL(persistent_attached),
|
2016-02-24 21:24:23 +01:00
|
|
|
runtime_config,
|
|
|
|
"/run/systemd/system",
|
2018-10-08 17:22:06 +02:00
|
|
|
STRV_IFNOTNULL(runtime_attached),
|
2016-02-24 21:24:23 +01:00
|
|
|
STRV_IFNOTNULL(generator),
|
|
|
|
"/usr/local/lib/systemd/system",
|
|
|
|
SYSTEM_DATA_UNIT_PATH,
|
|
|
|
"/usr/lib/systemd/system",
|
2018-04-16 12:36:07 +02:00
|
|
|
STRV_IFNOTNULL(flags & LOOKUP_PATHS_SPLIT_USR ? "/lib/systemd/system" : NULL),
|
2018-10-31 17:03:50 +01:00
|
|
|
STRV_IFNOTNULL(generator_late));
|
2016-02-24 21:24:23 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case UNIT_FILE_GLOBAL:
|
|
|
|
add = strv_new(
|
2012-05-23 03:43:29 +02:00
|
|
|
/* If you modify this you also want to modify
|
2014-07-20 23:56:57 +02:00
|
|
|
* systemduserunitpath= in systemd.pc.in, and
|
|
|
|
* the arrays in user_dirs() above! */
|
2016-04-06 21:02:36 +02:00
|
|
|
STRV_IFNOTNULL(persistent_control),
|
|
|
|
STRV_IFNOTNULL(runtime_control),
|
2016-02-25 01:13:57 +01:00
|
|
|
STRV_IFNOTNULL(transient),
|
2016-02-24 21:24:23 +01:00
|
|
|
STRV_IFNOTNULL(generator_early),
|
2016-02-24 17:18:42 +01:00
|
|
|
persistent_config,
|
2016-02-25 00:54:31 +01:00
|
|
|
USER_CONFIG_UNIT_PATH,
|
2014-07-20 23:56:57 +02:00
|
|
|
"/etc/systemd/user",
|
2016-02-24 17:18:42 +01:00
|
|
|
runtime_config,
|
2014-07-20 23:56:57 +02:00
|
|
|
"/run/systemd/user",
|
2016-02-24 21:24:23 +01:00
|
|
|
STRV_IFNOTNULL(generator),
|
2014-07-20 23:56:57 +02:00
|
|
|
"/usr/local/share/systemd/user",
|
2018-02-08 14:12:13 +01:00
|
|
|
"/usr/share/systemd/user",
|
|
|
|
"/usr/local/lib/systemd/user",
|
2014-07-20 23:56:57 +02:00
|
|
|
USER_DATA_UNIT_PATH,
|
|
|
|
"/usr/lib/systemd/user",
|
2018-10-31 17:03:50 +01:00
|
|
|
STRV_IFNOTNULL(generator_late));
|
2016-02-24 21:24:23 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case UNIT_FILE_USER:
|
|
|
|
add = user_dirs(persistent_config, runtime_config,
|
2018-02-08 13:57:05 +01:00
|
|
|
global_persistent_config, global_runtime_config,
|
2016-02-25 01:13:57 +01:00
|
|
|
generator, generator_early, generator_late,
|
2016-04-06 21:02:36 +02:00
|
|
|
transient,
|
2018-02-08 13:54:37 +01:00
|
|
|
persistent_control, runtime_control);
|
2016-02-24 21:24:23 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Hmm, unexpected scope?");
|
|
|
|
}
|
2012-05-23 03:43:29 +02:00
|
|
|
|
2016-02-24 15:31:33 +01:00
|
|
|
if (!add)
|
2014-07-20 23:56:57 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-04-20 18:20:51 +02:00
|
|
|
if (paths) {
|
|
|
|
r = strv_extend_strv(&paths, add, true);
|
|
|
|
if (r < 0)
|
2016-02-24 15:31:33 +01:00
|
|
|
return r;
|
2018-04-05 07:26:26 +02:00
|
|
|
} else
|
2016-04-20 18:20:51 +02:00
|
|
|
/* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
|
|
|
|
* and don't have to copy anything */
|
2018-04-05 07:26:26 +02:00
|
|
|
paths = TAKE_PTR(add);
|
2010-06-15 14:45:15 +02:00
|
|
|
}
|
|
|
|
|
2016-02-25 00:16:51 +01:00
|
|
|
r = patch_root_prefix(&persistent_config, root);
|
2016-02-24 17:18:42 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-02-25 00:16:51 +01:00
|
|
|
r = patch_root_prefix(&runtime_config, root);
|
2016-02-24 17:18:42 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-02-25 00:16:51 +01:00
|
|
|
r = patch_root_prefix(&generator, root);
|
2016-02-24 15:31:33 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-02-25 00:16:51 +01:00
|
|
|
r = patch_root_prefix(&generator_early, root);
|
2016-02-24 15:31:33 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-02-25 00:16:51 +01:00
|
|
|
r = patch_root_prefix(&generator_late, root);
|
2016-02-24 15:31:33 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-02-25 01:13:57 +01:00
|
|
|
r = patch_root_prefix(&transient, root);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-04-06 21:02:36 +02:00
|
|
|
r = patch_root_prefix(&persistent_control, root);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = patch_root_prefix(&runtime_control, root);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2018-10-08 17:22:06 +02:00
|
|
|
r = patch_root_prefix(&persistent_attached, root);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = patch_root_prefix(&runtime_attached, root);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2016-04-14 03:10:33 +02:00
|
|
|
r = patch_root_prefix_strv(paths, root);
|
2016-02-25 02:32:19 +01:00
|
|
|
if (r < 0)
|
2012-05-23 03:43:29 +02:00
|
|
|
return -ENOMEM;
|
2010-09-21 05:23:12 +02:00
|
|
|
|
2018-10-08 17:22:06 +02:00
|
|
|
*p = (LookupPaths) {
|
|
|
|
.search_path = strv_uniq(paths),
|
2016-02-24 15:31:33 +01:00
|
|
|
|
2018-10-08 17:22:06 +02:00
|
|
|
.persistent_config = TAKE_PTR(persistent_config),
|
|
|
|
.runtime_config = TAKE_PTR(runtime_config),
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2018-10-08 17:22:06 +02:00
|
|
|
.generator = TAKE_PTR(generator),
|
|
|
|
.generator_early = TAKE_PTR(generator_early),
|
|
|
|
.generator_late = TAKE_PTR(generator_late),
|
2016-02-25 01:13:57 +01:00
|
|
|
|
2018-10-08 17:22:06 +02:00
|
|
|
.transient = TAKE_PTR(transient),
|
2016-04-06 21:02:36 +02:00
|
|
|
|
2018-10-08 17:22:06 +02:00
|
|
|
.persistent_control = TAKE_PTR(persistent_control),
|
|
|
|
.runtime_control = TAKE_PTR(runtime_control),
|
2016-02-25 00:16:51 +01:00
|
|
|
|
2018-10-08 17:22:06 +02:00
|
|
|
.persistent_attached = TAKE_PTR(persistent_attached),
|
|
|
|
.runtime_attached = TAKE_PTR(runtime_attached),
|
2017-09-14 19:26:29 +02:00
|
|
|
|
2018-10-08 17:22:06 +02:00
|
|
|
.root_dir = TAKE_PTR(root),
|
|
|
|
.temporary_dir = TAKE_PTR(tempdir),
|
|
|
|
};
|
|
|
|
|
|
|
|
paths = NULL;
|
2010-06-15 14:45:15 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lookup_paths_free(LookupPaths *p) {
|
2016-02-24 15:31:33 +01:00
|
|
|
if (!p)
|
|
|
|
return;
|
2010-06-15 14:45:15 +02:00
|
|
|
|
2016-02-24 15:31:33 +01:00
|
|
|
p->search_path = strv_free(p->search_path);
|
2016-02-24 17:18:42 +01:00
|
|
|
|
|
|
|
p->persistent_config = mfree(p->persistent_config);
|
|
|
|
p->runtime_config = mfree(p->runtime_config);
|
|
|
|
|
2018-10-08 17:22:06 +02:00
|
|
|
p->persistent_attached = mfree(p->persistent_attached);
|
|
|
|
p->runtime_attached = mfree(p->runtime_attached);
|
|
|
|
|
2016-02-24 15:31:33 +01:00
|
|
|
p->generator = mfree(p->generator);
|
|
|
|
p->generator_early = mfree(p->generator_early);
|
|
|
|
p->generator_late = mfree(p->generator_late);
|
2016-02-25 00:16:51 +01:00
|
|
|
|
2016-02-25 01:13:57 +01:00
|
|
|
p->transient = mfree(p->transient);
|
|
|
|
|
2016-04-06 21:02:36 +02:00
|
|
|
p->persistent_control = mfree(p->persistent_control);
|
|
|
|
p->runtime_control = mfree(p->runtime_control);
|
|
|
|
|
2016-02-25 00:16:51 +01:00
|
|
|
p->root_dir = mfree(p->root_dir);
|
2017-09-16 11:31:16 +02:00
|
|
|
p->temporary_dir = mfree(p->temporary_dir);
|
2010-06-15 14:45:15 +02:00
|
|
|
}
|
2016-02-25 01:44:30 +01:00
|
|
|
|
2016-02-25 02:32:19 +01:00
|
|
|
int lookup_paths_reduce(LookupPaths *p) {
|
|
|
|
_cleanup_free_ struct stat *stats = NULL;
|
|
|
|
size_t n_stats = 0, allocated = 0;
|
tree-wide: be more careful with the type of array sizes
Previously we were a bit sloppy with the index and size types of arrays,
we'd regularly use unsigned. While I don't think this ever resulted in
real issues I think we should be more careful there and follow a
stricter regime: unless there's a strong reason not to use size_t for
array sizes and indexes, size_t it should be. Any allocations we do
ultimately will use size_t anyway, and converting forth and back between
unsigned and size_t will always be a source of problems.
Note that on 32bit machines "unsigned" and "size_t" are equivalent, and
on 64bit machines our arrays shouldn't grow that large anyway, and if
they do we have a problem, however that kind of overly large allocation
we have protections for usually, but for overflows we do not have that
so much, hence let's add it.
So yeah, it's a story of the current code being already "good enough",
but I think some extra type hygiene is better.
This patch tries to be comprehensive, but it probably isn't and I missed
a few cases. But I guess we can cover that later as we notice it. Among
smaller fixes, this changes:
1. strv_length()' return type becomes size_t
2. the unit file changes array size becomes size_t
3. DNS answer and query array sizes become size_t
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=76745
2018-04-27 14:09:31 +02:00
|
|
|
size_t c = 0;
|
2016-02-25 02:32:19 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(p);
|
|
|
|
|
|
|
|
/* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
|
2018-04-18 16:19:46 +02:00
|
|
|
* the same by comparing their device and inode numbers. */
|
2016-02-25 02:32:19 +01:00
|
|
|
|
|
|
|
if (!p->search_path)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
while (p->search_path[c]) {
|
|
|
|
struct stat st;
|
tree-wide: be more careful with the type of array sizes
Previously we were a bit sloppy with the index and size types of arrays,
we'd regularly use unsigned. While I don't think this ever resulted in
real issues I think we should be more careful there and follow a
stricter regime: unless there's a strong reason not to use size_t for
array sizes and indexes, size_t it should be. Any allocations we do
ultimately will use size_t anyway, and converting forth and back between
unsigned and size_t will always be a source of problems.
Note that on 32bit machines "unsigned" and "size_t" are equivalent, and
on 64bit machines our arrays shouldn't grow that large anyway, and if
they do we have a problem, however that kind of overly large allocation
we have protections for usually, but for overflows we do not have that
so much, hence let's add it.
So yeah, it's a story of the current code being already "good enough",
but I think some extra type hygiene is better.
This patch tries to be comprehensive, but it probably isn't and I missed
a few cases. But I guess we can cover that later as we notice it. Among
smaller fixes, this changes:
1. strv_length()' return type becomes size_t
2. the unit file changes array size becomes size_t
3. DNS answer and query array sizes become size_t
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=76745
2018-04-27 14:09:31 +02:00
|
|
|
size_t k;
|
2016-02-25 02:32:19 +01:00
|
|
|
|
2017-11-23 17:45:58 +01:00
|
|
|
/* Never strip the transient and control directories from the path */
|
|
|
|
if (path_equal_ptr(p->search_path[c], p->transient) ||
|
|
|
|
path_equal_ptr(p->search_path[c], p->persistent_control) ||
|
|
|
|
path_equal_ptr(p->search_path[c], p->runtime_control)) {
|
|
|
|
c++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-04-18 16:19:46 +02:00
|
|
|
r = chase_symlinks_and_stat(p->search_path[c], p->root_dir, 0, NULL, &st);
|
|
|
|
if (r == -ENOENT)
|
|
|
|
goto remove_item;
|
2016-02-25 02:32:19 +01:00
|
|
|
if (r < 0) {
|
|
|
|
/* If something we don't grok happened, let's better leave it in. */
|
2018-04-18 16:19:46 +02:00
|
|
|
log_debug_errno(r, "Failed to chase and stat %s: %m", p->search_path[c]);
|
2016-02-25 02:32:19 +01:00
|
|
|
c++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-04-18 16:19:46 +02:00
|
|
|
for (k = 0; k < n_stats; k++)
|
2016-02-25 02:32:19 +01:00
|
|
|
if (stats[k].st_dev == st.st_dev &&
|
|
|
|
stats[k].st_ino == st.st_ino)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (k < n_stats) /* Is there already an entry with the same device/inode? */
|
|
|
|
goto remove_item;
|
|
|
|
|
|
|
|
if (!GREEDY_REALLOC(stats, allocated, n_stats+1))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
stats[n_stats++] = st;
|
|
|
|
c++;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
remove_item:
|
|
|
|
free(p->search_path[c]);
|
|
|
|
memmove(p->search_path + c,
|
|
|
|
p->search_path + c + 1,
|
|
|
|
(strv_length(p->search_path + c + 1) + 1) * sizeof(char*));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strv_isempty(p->search_path)) {
|
|
|
|
log_debug("Ignoring unit files.");
|
|
|
|
p->search_path = strv_free(p->search_path);
|
|
|
|
} else {
|
|
|
|
_cleanup_free_ char *t;
|
|
|
|
|
|
|
|
t = strv_join(p->search_path, "\n\t");
|
|
|
|
if (!t)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-25 01:44:30 +01:00
|
|
|
int lookup_paths_mkdir_generator(LookupPaths *p) {
|
|
|
|
int r, q;
|
|
|
|
|
|
|
|
assert(p);
|
|
|
|
|
2016-04-07 18:48:01 +02:00
|
|
|
if (!p->generator || !p->generator_early || !p->generator_late)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-02-25 01:44:30 +01:00
|
|
|
r = mkdir_p_label(p->generator, 0755);
|
|
|
|
|
|
|
|
q = mkdir_p_label(p->generator_early, 0755);
|
|
|
|
if (q < 0 && r >= 0)
|
|
|
|
r = q;
|
|
|
|
|
|
|
|
q = mkdir_p_label(p->generator_late, 0755);
|
|
|
|
if (q < 0 && r >= 0)
|
|
|
|
r = q;
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lookup_paths_trim_generator(LookupPaths *p) {
|
|
|
|
assert(p);
|
|
|
|
|
|
|
|
/* Trim empty dirs */
|
|
|
|
|
|
|
|
if (p->generator)
|
|
|
|
(void) rmdir(p->generator);
|
|
|
|
if (p->generator_early)
|
|
|
|
(void) rmdir(p->generator_early);
|
|
|
|
if (p->generator_late)
|
|
|
|
(void) rmdir(p->generator_late);
|
|
|
|
}
|
2016-04-06 20:47:44 +02:00
|
|
|
|
|
|
|
void lookup_paths_flush_generator(LookupPaths *p) {
|
|
|
|
assert(p);
|
|
|
|
|
2016-04-06 21:02:36 +02:00
|
|
|
/* Flush the generated unit files in full */
|
|
|
|
|
2016-04-06 20:47:44 +02:00
|
|
|
if (p->generator)
|
2018-05-22 11:56:31 +02:00
|
|
|
(void) rm_rf(p->generator, REMOVE_ROOT|REMOVE_PHYSICAL);
|
2016-04-06 20:47:44 +02:00
|
|
|
if (p->generator_early)
|
2018-05-22 11:56:31 +02:00
|
|
|
(void) rm_rf(p->generator_early, REMOVE_ROOT|REMOVE_PHYSICAL);
|
2016-04-06 20:47:44 +02:00
|
|
|
if (p->generator_late)
|
2018-05-22 11:56:31 +02:00
|
|
|
(void) rm_rf(p->generator_late, REMOVE_ROOT|REMOVE_PHYSICAL);
|
2017-09-14 19:26:29 +02:00
|
|
|
|
|
|
|
if (p->temporary_dir)
|
2018-05-22 11:56:31 +02:00
|
|
|
(void) rm_rf(p->temporary_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
|
2016-04-06 20:47:44 +02:00
|
|
|
}
|
2016-04-07 17:51:26 +02:00
|
|
|
|
|
|
|
char **generator_binary_paths(UnitFileScope scope) {
|
|
|
|
|
|
|
|
switch (scope) {
|
|
|
|
|
|
|
|
case UNIT_FILE_SYSTEM:
|
|
|
|
return strv_new("/run/systemd/system-generators",
|
|
|
|
"/etc/systemd/system-generators",
|
|
|
|
"/usr/local/lib/systemd/system-generators",
|
2018-10-31 17:03:50 +01:00
|
|
|
SYSTEM_GENERATOR_PATH);
|
2016-04-07 17:51:26 +02:00
|
|
|
|
|
|
|
case UNIT_FILE_GLOBAL:
|
|
|
|
case UNIT_FILE_USER:
|
|
|
|
return strv_new("/run/systemd/user-generators",
|
|
|
|
"/etc/systemd/user-generators",
|
|
|
|
"/usr/local/lib/systemd/user-generators",
|
2018-10-31 17:03:50 +01:00
|
|
|
USER_GENERATOR_PATH);
|
2016-04-07 17:51:26 +02:00
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Hmm, unexpected scope.");
|
|
|
|
}
|
|
|
|
}
|