Compare commits
57 Commits
aaf6cb2914
...
adf5023062
Author | SHA1 | Date |
---|---|---|
Mike Yuan | adf5023062 | |
Yu Watanabe | a3c2a9ee5d | |
Daan De Meyer | 062332f3db | |
Mike Yuan | b3c41c9849 | |
Mike Yuan | 97cdb64101 | |
Mike Yuan | 8606e63208 | |
Mike Yuan | a05de0a7fa | |
Mike Yuan | 77e528bda1 | |
Mike Yuan | dd3672539a | |
Mike Yuan | 1f62c885d7 | |
Mike Yuan | da9ff07fa4 | |
Mike Yuan | 394068f136 | |
Mike Yuan | 79495b0904 | |
Mike Yuan | 727bb81a99 | |
Mike Yuan | 97f00da913 | |
Mike Yuan | 8dd6249e0d | |
Mike Yuan | 3cb72f0fe2 | |
Mike Yuan | b9503dfa80 | |
Mike Yuan | c0e8dcfe1a | |
Mike Yuan | 395f57bbce | |
Mike Yuan | bd8316cb29 | |
Mike Yuan | b7d5b0d33b | |
Daan De Meyer | bc9a9177b2 | |
Daan De Meyer | e5c6dcac87 | |
Daan De Meyer | 34a7ca6db2 | |
Daan De Meyer | 397820961d | |
Yu Watanabe | 3b16e9f419 | |
Yu Watanabe | d5a7f3b7d4 | |
Yu Watanabe | f1c16ca6d6 | |
Yu Watanabe | b094398b0f | |
Yu Watanabe | 1ee6570843 | |
Yu Watanabe | b7f051c91d | |
Yu Watanabe | a13ead6814 | |
Yu Watanabe | f901a7b39f | |
Yu Watanabe | 9b01cf0406 | |
Yu Watanabe | d5aae0713d | |
Daan De Meyer | 1d8a81eb4e | |
Daan De Meyer | 86c1317270 | |
Daan De Meyer | f4faac2073 | |
Yu Watanabe | 2bcc2a89f3 | |
Yu Watanabe | 07e6a111c0 | |
Yu Watanabe | c2648f6e23 | |
Daan De Meyer | 1d5b4317cd | |
Yu Watanabe | 8d6eedd8a3 | |
Yu Watanabe | 91eaa90b81 | |
Yu Watanabe | 3b5c5da73a | |
Yu Watanabe | 1775654e2c | |
Yu Watanabe | 0ea6d55a4b | |
Yu Watanabe | 26d35019de | |
Yu Watanabe | b962338104 | |
Yu Watanabe | fae0b00434 | |
Yu Watanabe | f7923ef318 | |
Yu Watanabe | 36df48d863 | |
Yu Watanabe | 53c638db16 | |
Yu Watanabe | 751a247794 | |
Yu Watanabe | 07dbbda0fc | |
Yu Watanabe | ed4a6c476e |
|
@ -962,7 +962,9 @@ default ignore - -</programlisting>
|
|||
discovered/supported/used, prints <literal>no</literal>. Otherwise prints
|
||||
<literal>partial</literal>. In either of these two cases exits with non-zero exit status. It also shows
|
||||
five lines indicating separately whether firmware, drivers, the system, the kernel and libraries
|
||||
discovered/support/use TPM2.</para>
|
||||
discovered/support/use TPM2. Currently, required libraries are <filename>libtss2-esys.so.0</filename>,
|
||||
<filename>libtss2-rc.so.0</filename>, and <filename>libtss2-mu.so.0</filename>. The requirement may be
|
||||
changed in the future release.</para>
|
||||
|
||||
<para>Note, this checks for TPM 2.0 devices only, and does not consider TPM 1.2 at all.</para>
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-nsresourced</command> is a system service that permits transient delegation of a a
|
||||
<para><command>systemd-nsresourced</command> is a system service that permits transient delegation of a
|
||||
UID/GID range to a user namespace (see <citerefentry
|
||||
project='man-pages'><refentrytitle>user_namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry>)
|
||||
allocated by a client, via a Varlink IPC API.</para>
|
||||
|
|
|
@ -2084,6 +2084,7 @@ libsystemd_includes = [basic_includes, include_directories(
|
|||
'src/libsystemd/sd-json',
|
||||
'src/libsystemd/sd-netlink',
|
||||
'src/libsystemd/sd-network',
|
||||
'src/libsystemd/sd-path',
|
||||
'src/libsystemd/sd-resolve',
|
||||
'src/libsystemd/sd-varlink')]
|
||||
|
||||
|
|
|
@ -3,18 +3,11 @@
|
|||
set -e
|
||||
set -o nounset
|
||||
|
||||
if [[ "$DISTRIBUTION" =~ ubuntu|debian ]]; then
|
||||
SUDO_GROUP=sudo
|
||||
else
|
||||
SUDO_GROUP=wheel
|
||||
fi
|
||||
|
||||
useradd \
|
||||
--uid 4711 \
|
||||
--user-group \
|
||||
--create-home \
|
||||
--password "$(openssl passwd -1 testuser)" \
|
||||
--groups "$SUDO_GROUP",systemd-journal \
|
||||
--shell /bin/bash \
|
||||
testuser
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ _systemd_analyze() {
|
|||
)
|
||||
|
||||
local -A VERBS=(
|
||||
[STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk'
|
||||
[STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk has-tpm2'
|
||||
[CRITICAL_CHAIN]='critical-chain'
|
||||
[DOT]='dot'
|
||||
[DUMP]='dump'
|
||||
|
|
|
@ -73,6 +73,7 @@ JSON or table format'
|
|||
'timespan:Parse a systemd syntax timespan'
|
||||
'security:Analyze security settings of a service'
|
||||
'inspect-elf:Parse and print ELF package metadata'
|
||||
'has-tpm2:Report whether TPM2 support is available'
|
||||
# log-level, log-target, service-watchdogs have been deprecated
|
||||
)
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ int verb_pcrs(int argc, char *argv[], void *userdata) {
|
|||
const char *alg = NULL;
|
||||
int r;
|
||||
|
||||
if (tpm2_support() != TPM2_SUPPORT_FULL)
|
||||
if (!tpm2_is_fully_supported())
|
||||
log_notice("System lacks full TPM2 support, not showing PCR state.");
|
||||
else {
|
||||
r = get_pcr_alg(&alg);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "bus-map-properties.h"
|
||||
#include "bus-unit-util.h"
|
||||
#include "bus-util.h"
|
||||
#include "conf-files.h"
|
||||
#include "copy.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
|
|
|
@ -469,3 +469,30 @@ int conf_file_read(
|
|||
|
||||
return r;
|
||||
}
|
||||
|
||||
int find_portable_profile(const char *name, const char *unit, char **ret_path) {
|
||||
const char *dot;
|
||||
|
||||
assert(name);
|
||||
assert(ret_path);
|
||||
|
||||
assert_se(dot = strrchr(unit, '.'));
|
||||
|
||||
NULSTR_FOREACH(p, PORTABLE_PROFILE_DIRS) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
|
||||
joined = strjoin(p, "/", name, "/", dot + 1, ".conf");
|
||||
if (!joined)
|
||||
return -ENOMEM;
|
||||
|
||||
if (laccess(joined, F_OK) >= 0) {
|
||||
*ret_path = TAKE_PTR(joined);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
|
|
@ -47,3 +47,9 @@ int conf_file_read(
|
|||
void *userdata,
|
||||
bool ignore_enoent,
|
||||
bool *invalid_config);
|
||||
|
||||
#define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network"))
|
||||
#define NETWORK_DIRS_NULSTR CONF_PATHS_NULSTR("systemd/network")
|
||||
|
||||
#define PORTABLE_PROFILE_DIRS CONF_PATHS_NULSTR("systemd/portable/profile")
|
||||
int find_portable_profile(const char *name, const char *unit, char **ret_path);
|
||||
|
|
|
@ -70,7 +70,6 @@ basic_sources = files(
|
|||
'ordered-set.c',
|
||||
'os-util.c',
|
||||
'parse-util.c',
|
||||
'path-lookup.c',
|
||||
'path-util.c',
|
||||
'percent-util.c',
|
||||
'pidref.c',
|
||||
|
@ -106,7 +105,6 @@ basic_sources = files(
|
|||
'uid-classification.c',
|
||||
'uid-range.c',
|
||||
'unit-def.c',
|
||||
'unit-file.c',
|
||||
'unit-name.c',
|
||||
'user-util.c',
|
||||
'utf8.c',
|
||||
|
|
|
@ -1,930 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "user-util.h"
|
||||
|
||||
int xdg_user_runtime_dir(char **ret, const char *suffix) {
|
||||
const char *e;
|
||||
char *j;
|
||||
|
||||
assert(ret);
|
||||
assert(suffix);
|
||||
|
||||
e = getenv("XDG_RUNTIME_DIR");
|
||||
if (!e)
|
||||
return -ENXIO;
|
||||
|
||||
j = path_join(e, suffix);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = j;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xdg_user_config_dir(char **ret, const char *suffix) {
|
||||
_cleanup_free_ char *j = NULL;
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
e = getenv("XDG_CONFIG_HOME");
|
||||
if (e) {
|
||||
j = path_join(e, suffix);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
r = get_home_dir(&j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!path_extend(&j, "/.config", suffix))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(j);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xdg_user_data_dir(char **ret, const char *suffix) {
|
||||
_cleanup_free_ char *j = NULL;
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(suffix);
|
||||
|
||||
/* We don't treat /etc/xdg/systemd here as the spec
|
||||
* suggests because we assume that is a link to
|
||||
* /etc/systemd/ anyway. */
|
||||
|
||||
e = getenv("XDG_DATA_HOME");
|
||||
if (e) {
|
||||
j = path_join(e, suffix);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
r = get_home_dir(&j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!path_extend(&j, "/.local/share", suffix))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(j);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int runtime_directory(char **ret, RuntimeScope scope, const char *suffix) {
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(suffix);
|
||||
assert(IN_SET(scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER, RUNTIME_SCOPE_GLOBAL));
|
||||
|
||||
/* Accept $RUNTIME_DIRECTORY as authoritative
|
||||
* If its missing apply the suffix to /run or $XDG_RUNTIME_DIR
|
||||
* if we are in a user runtime scope.
|
||||
*
|
||||
* Return value indicates whether the suffix was applied or not */
|
||||
|
||||
const char *e = secure_getenv("RUNTIME_DIRECTORY");
|
||||
if (e)
|
||||
return strdup_to(ret, e);
|
||||
|
||||
if (scope == RUNTIME_SCOPE_USER) {
|
||||
r = xdg_user_runtime_dir(ret, suffix);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
char *d = path_join("/run", suffix);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
*ret = d;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char* const user_data_unit_paths[] = {
|
||||
"/usr/local/lib/systemd/user",
|
||||
"/usr/local/share/systemd/user",
|
||||
USER_DATA_UNIT_DIR,
|
||||
"/usr/lib/systemd/user",
|
||||
"/usr/share/systemd/user",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char* const user_config_unit_paths[] = {
|
||||
USER_CONFIG_UNIT_DIR,
|
||||
"/etc/systemd/user",
|
||||
NULL
|
||||
};
|
||||
|
||||
int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs) {
|
||||
/* Implement the mechanisms defined in
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
const char *e;
|
||||
_cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
|
||||
|
||||
e = getenv("XDG_CONFIG_DIRS");
|
||||
if (e)
|
||||
config_dirs = strv_split(e, ":");
|
||||
else
|
||||
config_dirs = strv_new("/etc/xdg");
|
||||
if (!config_dirs)
|
||||
return -ENOMEM;
|
||||
|
||||
e = getenv("XDG_DATA_DIRS");
|
||||
if (e)
|
||||
data_dirs = strv_split(e, ":");
|
||||
else
|
||||
data_dirs = strv_new("/usr/local/share",
|
||||
"/usr/share");
|
||||
if (!data_dirs)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_config_dirs = TAKE_PTR(config_dirs);
|
||||
*ret_data_dirs = TAKE_PTR(data_dirs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char** user_dirs(
|
||||
const char *persistent_config,
|
||||
const char *runtime_config,
|
||||
const char *global_persistent_config,
|
||||
const char *global_runtime_config,
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
/* Now merge everything we found. */
|
||||
if (strv_extend_many(
|
||||
&res,
|
||||
persistent_control,
|
||||
runtime_control,
|
||||
transient,
|
||||
generator_early,
|
||||
persistent_config) < 0)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend_strv_concat(&res, (const char* const*) config_dirs, "/systemd/user") < 0)
|
||||
return NULL;
|
||||
|
||||
/* global config has lower priority than the user config of the same type */
|
||||
if (strv_extend(&res, global_persistent_config) < 0)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend_strv(&res, (char**) user_config_unit_paths, false) < 0)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend_many(
|
||||
&res,
|
||||
runtime_config,
|
||||
global_runtime_config,
|
||||
generator,
|
||||
data_home) < 0)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend_strv_concat(&res, (const char* const*) data_dirs, "/systemd/user") < 0)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend_strv(&res, (char**) user_data_unit_paths, false) < 0)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend(&res, generator_late) < 0)
|
||||
return NULL;
|
||||
|
||||
if (path_strv_make_absolute_cwd(res) < 0)
|
||||
return NULL;
|
||||
|
||||
return TAKE_PTR(res);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int acquire_generator_dirs(
|
||||
RuntimeScope scope,
|
||||
const char *tempdir,
|
||||
char **generator,
|
||||
char **generator_early,
|
||||
char **generator_late) {
|
||||
|
||||
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *p = NULL;
|
||||
const char *prefix;
|
||||
|
||||
assert(generator);
|
||||
assert(generator_early);
|
||||
assert(generator_late);
|
||||
assert(IN_SET(scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER, RUNTIME_SCOPE_GLOBAL));
|
||||
|
||||
if (scope == RUNTIME_SCOPE_GLOBAL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (tempdir)
|
||||
prefix = tempdir;
|
||||
else if (scope == RUNTIME_SCOPE_SYSTEM)
|
||||
prefix = "/run/systemd";
|
||||
else {
|
||||
/* RUNTIME_SCOPE_USER */
|
||||
const char *e;
|
||||
|
||||
e = getenv("XDG_RUNTIME_DIR");
|
||||
if (!e)
|
||||
return -ENXIO;
|
||||
|
||||
p = path_join(e, "/systemd");
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
prefix = p;
|
||||
}
|
||||
|
||||
x = path_join(prefix, "generator");
|
||||
if (!x)
|
||||
return -ENOMEM;
|
||||
|
||||
y = path_join(prefix, "generator.early");
|
||||
if (!y)
|
||||
return -ENOMEM;
|
||||
|
||||
z = path_join(prefix, "generator.late");
|
||||
if (!z)
|
||||
return -ENOMEM;
|
||||
|
||||
*generator = TAKE_PTR(x);
|
||||
*generator_early = TAKE_PTR(y);
|
||||
*generator_late = TAKE_PTR(z);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acquire_transient_dir(
|
||||
RuntimeScope scope,
|
||||
const char *tempdir,
|
||||
char **ret) {
|
||||
|
||||
char *transient;
|
||||
|
||||
assert(ret);
|
||||
assert(IN_SET(scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER, RUNTIME_SCOPE_GLOBAL));
|
||||
|
||||
if (scope == RUNTIME_SCOPE_GLOBAL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (tempdir)
|
||||
transient = path_join(tempdir, "transient");
|
||||
else if (scope == RUNTIME_SCOPE_SYSTEM)
|
||||
transient = strdup("/run/systemd/transient");
|
||||
else
|
||||
return xdg_user_runtime_dir(ret, "/systemd/transient");
|
||||
|
||||
if (!transient)
|
||||
return -ENOMEM;
|
||||
*ret = transient;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acquire_config_dirs(RuntimeScope scope, char **persistent, char **runtime) {
|
||||
_cleanup_free_ char *a = NULL, *b = NULL;
|
||||
int r;
|
||||
|
||||
assert(persistent);
|
||||
assert(runtime);
|
||||
|
||||
switch (scope) {
|
||||
|
||||
case RUNTIME_SCOPE_SYSTEM:
|
||||
a = strdup(SYSTEM_CONFIG_UNIT_DIR);
|
||||
b = strdup("/run/systemd/system");
|
||||
break;
|
||||
|
||||
case RUNTIME_SCOPE_GLOBAL:
|
||||
a = strdup(USER_CONFIG_UNIT_DIR);
|
||||
b = strdup("/run/systemd/user");
|
||||
break;
|
||||
|
||||
case RUNTIME_SCOPE_USER:
|
||||
r = xdg_user_config_dir(&a, "/systemd/user");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
return r;
|
||||
|
||||
r = xdg_user_runtime_dir(runtime, "/systemd/user");
|
||||
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;
|
||||
}
|
||||
|
||||
*persistent = TAKE_PTR(a);
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (!a || !b)
|
||||
return -ENOMEM;
|
||||
|
||||
*persistent = TAKE_PTR(a);
|
||||
*runtime = TAKE_PTR(b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acquire_control_dirs(RuntimeScope scope, char **persistent, char **runtime) {
|
||||
_cleanup_free_ char *a = NULL;
|
||||
int r;
|
||||
|
||||
assert(persistent);
|
||||
assert(runtime);
|
||||
|
||||
switch (scope) {
|
||||
|
||||
case RUNTIME_SCOPE_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;
|
||||
|
||||
*runtime = TAKE_PTR(b);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case RUNTIME_SCOPE_USER:
|
||||
r = xdg_user_config_dir(&a, "/systemd/user.control");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
return r;
|
||||
|
||||
r = xdg_user_runtime_dir(runtime, "/systemd/user.control");
|
||||
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;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RUNTIME_SCOPE_GLOBAL:
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
*persistent = TAKE_PTR(a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acquire_attached_dirs(
|
||||
RuntimeScope 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 != RUNTIME_SCOPE_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;
|
||||
}
|
||||
|
||||
static int patch_root_prefix(char **p, const char *root_dir) {
|
||||
char *c;
|
||||
|
||||
assert(p);
|
||||
|
||||
if (!*p)
|
||||
return 0;
|
||||
|
||||
c = path_join(root_dir, *p);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
free_and_replace(*p, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int patch_root_prefix_strv(char **l, const char *root_dir) {
|
||||
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;
|
||||
}
|
||||
|
||||
static int get_paths_from_environ(const char *var, char ***paths, bool *append) {
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
assert(var);
|
||||
assert(paths);
|
||||
assert(append);
|
||||
|
||||
*append = false;
|
||||
|
||||
e = getenv(var);
|
||||
if (e) {
|
||||
const char *k;
|
||||
|
||||
k = endswith(e, ":");
|
||||
if (k) {
|
||||
e = strndupa_safe(e, k - e);
|
||||
*append = true;
|
||||
}
|
||||
|
||||
/* FIXME: empty components in other places should be rejected. */
|
||||
|
||||
r = path_split_and_make_absolute(e, paths);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_paths_init(
|
||||
LookupPaths *lp,
|
||||
RuntimeScope scope,
|
||||
LookupPathsFlags flags,
|
||||
const char *root_dir) {
|
||||
|
||||
_cleanup_(rmdir_and_freep) char *tempdir = NULL;
|
||||
_cleanup_free_ char
|
||||
*root = NULL,
|
||||
*persistent_config = NULL, *runtime_config = NULL,
|
||||
*global_persistent_config = NULL, *global_runtime_config = NULL,
|
||||
*generator = NULL, *generator_early = NULL, *generator_late = NULL,
|
||||
*transient = NULL,
|
||||
*persistent_control = NULL, *runtime_control = NULL,
|
||||
*persistent_attached = NULL, *runtime_attached = NULL;
|
||||
bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
int r;
|
||||
|
||||
assert(lp);
|
||||
assert(scope >= 0);
|
||||
assert(scope < _RUNTIME_SCOPE_MAX);
|
||||
|
||||
if (!empty_or_root(root_dir)) {
|
||||
if (scope == RUNTIME_SCOPE_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;
|
||||
}
|
||||
|
||||
if (flags & LOOKUP_PATHS_TEMPORARY_GENERATED) {
|
||||
r = mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to create temporary directory: %m");
|
||||
}
|
||||
|
||||
/* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
|
||||
r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (scope == RUNTIME_SCOPE_USER) {
|
||||
r = acquire_config_dirs(RUNTIME_SCOPE_GLOBAL, &global_persistent_config, &global_runtime_config);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
|
||||
/* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
|
||||
r = acquire_generator_dirs(scope, tempdir,
|
||||
&generator, &generator_early, &generator_late);
|
||||
if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
|
||||
r = acquire_transient_dir(scope, tempdir, &transient);
|
||||
if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
|
||||
return r;
|
||||
|
||||
/* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
|
||||
r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
|
||||
if (r < 0 && r != -EOPNOTSUPP)
|
||||
return r;
|
||||
|
||||
r = acquire_attached_dirs(scope, &persistent_attached, &runtime_attached);
|
||||
if (r < 0 && r != -EOPNOTSUPP)
|
||||
return r;
|
||||
|
||||
/* First priority is whatever has been passed to us via env vars */
|
||||
r = get_paths_from_environ("SYSTEMD_UNIT_PATH", &paths, &append);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!paths || append) {
|
||||
/* Let's figure something out. */
|
||||
|
||||
_cleanup_strv_free_ char **add = NULL;
|
||||
|
||||
/* 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. */
|
||||
|
||||
switch (scope) {
|
||||
|
||||
case RUNTIME_SCOPE_SYSTEM:
|
||||
add = strv_new(
|
||||
/* If you modify this you also want to modify
|
||||
* systemdsystemunitpath= in systemd.pc.in! */
|
||||
STRV_IFNOTNULL(persistent_control),
|
||||
STRV_IFNOTNULL(runtime_control),
|
||||
STRV_IFNOTNULL(transient),
|
||||
STRV_IFNOTNULL(generator_early),
|
||||
persistent_config,
|
||||
SYSTEM_CONFIG_UNIT_DIR,
|
||||
"/etc/systemd/system",
|
||||
STRV_IFNOTNULL(persistent_attached),
|
||||
runtime_config,
|
||||
"/run/systemd/system",
|
||||
STRV_IFNOTNULL(runtime_attached),
|
||||
STRV_IFNOTNULL(generator),
|
||||
"/usr/local/lib/systemd/system",
|
||||
SYSTEM_DATA_UNIT_DIR,
|
||||
"/usr/lib/systemd/system",
|
||||
/* To be used ONLY for images which might be legacy split-usr */
|
||||
STRV_IFNOTNULL(flags & LOOKUP_PATHS_SPLIT_USR ? "/lib/systemd/system" : NULL),
|
||||
STRV_IFNOTNULL(generator_late));
|
||||
break;
|
||||
|
||||
case RUNTIME_SCOPE_GLOBAL:
|
||||
add = 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(persistent_control),
|
||||
STRV_IFNOTNULL(runtime_control),
|
||||
STRV_IFNOTNULL(transient),
|
||||
STRV_IFNOTNULL(generator_early),
|
||||
persistent_config,
|
||||
USER_CONFIG_UNIT_DIR,
|
||||
"/etc/systemd/user",
|
||||
runtime_config,
|
||||
"/run/systemd/user",
|
||||
STRV_IFNOTNULL(generator),
|
||||
"/usr/local/share/systemd/user",
|
||||
"/usr/share/systemd/user",
|
||||
"/usr/local/lib/systemd/user",
|
||||
USER_DATA_UNIT_DIR,
|
||||
"/usr/lib/systemd/user",
|
||||
STRV_IFNOTNULL(generator_late));
|
||||
break;
|
||||
|
||||
case RUNTIME_SCOPE_USER:
|
||||
add = user_dirs(persistent_config, runtime_config,
|
||||
global_persistent_config, global_runtime_config,
|
||||
generator, generator_early, generator_late,
|
||||
transient,
|
||||
persistent_control, runtime_control);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (!add)
|
||||
return -ENOMEM;
|
||||
|
||||
if (paths) {
|
||||
r = strv_extend_strv(&paths, add, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
/* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
|
||||
* and don't have to copy anything */
|
||||
paths = TAKE_PTR(add);
|
||||
}
|
||||
|
||||
r = patch_root_prefix(&persistent_config, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = patch_root_prefix(&runtime_config, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = patch_root_prefix(&generator, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = patch_root_prefix(&generator_early, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = patch_root_prefix(&generator_late, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = patch_root_prefix(&transient, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = patch_root_prefix(&persistent_control, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = patch_root_prefix(&runtime_control, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = patch_root_prefix(&persistent_attached, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = patch_root_prefix(&runtime_attached, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = patch_root_prefix_strv(paths, root);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
*lp = (LookupPaths) {
|
||||
.search_path = strv_uniq(TAKE_PTR(paths)),
|
||||
|
||||
.persistent_config = TAKE_PTR(persistent_config),
|
||||
.runtime_config = TAKE_PTR(runtime_config),
|
||||
|
||||
.generator = TAKE_PTR(generator),
|
||||
.generator_early = TAKE_PTR(generator_early),
|
||||
.generator_late = TAKE_PTR(generator_late),
|
||||
|
||||
.transient = TAKE_PTR(transient),
|
||||
|
||||
.persistent_control = TAKE_PTR(persistent_control),
|
||||
.runtime_control = TAKE_PTR(runtime_control),
|
||||
|
||||
.persistent_attached = TAKE_PTR(persistent_attached),
|
||||
.runtime_attached = TAKE_PTR(runtime_attached),
|
||||
|
||||
.root_dir = TAKE_PTR(root),
|
||||
.temporary_dir = TAKE_PTR(tempdir),
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_paths_init_or_warn(LookupPaths *lp, RuntimeScope scope, LookupPathsFlags flags, const char *root_dir) {
|
||||
int r;
|
||||
|
||||
r = lookup_paths_init(lp, scope, flags, root_dir);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to initialize unit search paths%s%s: %m",
|
||||
isempty(root_dir) ? "" : " for root directory ", strempty(root_dir));
|
||||
return r;
|
||||
}
|
||||
|
||||
void lookup_paths_done(LookupPaths *lp) {
|
||||
assert(lp);
|
||||
|
||||
lp->search_path = strv_free(lp->search_path);
|
||||
|
||||
lp->persistent_config = mfree(lp->persistent_config);
|
||||
lp->runtime_config = mfree(lp->runtime_config);
|
||||
|
||||
lp->persistent_attached = mfree(lp->persistent_attached);
|
||||
lp->runtime_attached = mfree(lp->runtime_attached);
|
||||
|
||||
lp->generator = mfree(lp->generator);
|
||||
lp->generator_early = mfree(lp->generator_early);
|
||||
lp->generator_late = mfree(lp->generator_late);
|
||||
|
||||
lp->transient = mfree(lp->transient);
|
||||
|
||||
lp->persistent_control = mfree(lp->persistent_control);
|
||||
lp->runtime_control = mfree(lp->runtime_control);
|
||||
|
||||
lp->root_dir = mfree(lp->root_dir);
|
||||
lp->temporary_dir = mfree(lp->temporary_dir);
|
||||
}
|
||||
|
||||
void lookup_paths_log(LookupPaths *lp) {
|
||||
assert(lp);
|
||||
|
||||
if (strv_isempty(lp->search_path)) {
|
||||
log_debug("Ignoring unit files.");
|
||||
lp->search_path = strv_free(lp->search_path);
|
||||
} else {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
t = strv_join(lp->search_path, "\n\t");
|
||||
log_debug("Looking for unit files in (higher priority first):\n\t%s", strna(t));
|
||||
}
|
||||
}
|
||||
|
||||
char **generator_binary_paths(RuntimeScope scope) {
|
||||
bool append = false; /* Add items from SYSTEMD_GENERATOR_PATH before normal directories */
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
int r;
|
||||
|
||||
/* First priority is whatever has been passed to us via env vars */
|
||||
r = get_paths_from_environ("SYSTEMD_GENERATOR_PATH", &paths, &append);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
if (!paths || append) {
|
||||
_cleanup_strv_free_ char **add = NULL;
|
||||
|
||||
switch (scope) {
|
||||
|
||||
case RUNTIME_SCOPE_SYSTEM:
|
||||
add = strv_new("/run/systemd/system-generators",
|
||||
"/etc/systemd/system-generators",
|
||||
"/usr/local/lib/systemd/system-generators",
|
||||
SYSTEM_GENERATOR_DIR);
|
||||
break;
|
||||
|
||||
case RUNTIME_SCOPE_GLOBAL:
|
||||
case RUNTIME_SCOPE_USER:
|
||||
add = strv_new("/run/systemd/user-generators",
|
||||
"/etc/systemd/user-generators",
|
||||
"/usr/local/lib/systemd/user-generators",
|
||||
USER_GENERATOR_DIR);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
if (!add)
|
||||
return NULL;
|
||||
|
||||
if (paths) {
|
||||
r = strv_extend_strv(&paths, add, true);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
} else
|
||||
/* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
|
||||
* and don't have to copy anything */
|
||||
paths = TAKE_PTR(add);
|
||||
}
|
||||
|
||||
return TAKE_PTR(paths);
|
||||
}
|
||||
|
||||
char **env_generator_binary_paths(RuntimeScope runtime_scope) {
|
||||
_cleanup_strv_free_ char **paths = NULL, **add = NULL;
|
||||
bool append = false; /* Add items from SYSTEMD_ENVIRONMENT_GENERATOR_PATH before normal directories */
|
||||
int r;
|
||||
|
||||
/* First priority is whatever has been passed to us via env vars */
|
||||
r = get_paths_from_environ("SYSTEMD_ENVIRONMENT_GENERATOR_PATH", &paths, &append);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
if (!paths || append) {
|
||||
switch (runtime_scope) {
|
||||
|
||||
case RUNTIME_SCOPE_SYSTEM:
|
||||
add = strv_new("/run/systemd/system-environment-generators",
|
||||
"/etc/systemd/system-environment-generators",
|
||||
"/usr/local/lib/systemd/system-environment-generators",
|
||||
SYSTEM_ENV_GENERATOR_DIR);
|
||||
break;
|
||||
|
||||
case RUNTIME_SCOPE_USER:
|
||||
add = strv_new("/run/systemd/user-environment-generators",
|
||||
"/etc/systemd/user-environment-generators",
|
||||
"/usr/local/lib/systemd/user-environment-generators",
|
||||
USER_ENV_GENERATOR_DIR);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
if (!add)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (paths) {
|
||||
r = strv_extend_strv(&paths, add, true);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
} else
|
||||
/* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
|
||||
* and don't have to copy anything */
|
||||
paths = TAKE_PTR(add);
|
||||
|
||||
return TAKE_PTR(paths);
|
||||
}
|
||||
|
||||
int find_portable_profile(const char *name, const char *unit, char **ret_path) {
|
||||
const char *dot;
|
||||
|
||||
assert(name);
|
||||
assert(ret_path);
|
||||
|
||||
assert_se(dot = strrchr(unit, '.'));
|
||||
|
||||
NULSTR_FOREACH(p, PORTABLE_PROFILE_DIRS) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
|
||||
joined = strjoin(p, "/", name, "/", dot + 1, ".conf");
|
||||
if (!joined)
|
||||
return -ENOMEM;
|
||||
|
||||
if (laccess(joined, F_OK) >= 0) {
|
||||
*ret_path = TAKE_PTR(joined);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
|
@ -411,7 +411,6 @@ int verb_status(int argc, char *argv[], void *userdata) {
|
|||
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL, *stub_path = NULL,
|
||||
*current_entry = NULL, *oneshot_entry = NULL, *default_entry = NULL;
|
||||
uint64_t loader_features = 0, stub_features = 0;
|
||||
Tpm2Support s;
|
||||
int have;
|
||||
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
|
||||
|
@ -440,7 +439,7 @@ int verb_status(int argc, char *argv[], void *userdata) {
|
|||
else
|
||||
printf("\n");
|
||||
|
||||
s = tpm2_support();
|
||||
Tpm2Support s = tpm2_support_full(TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER);
|
||||
printf(" TPM2 Support: %s%s%s\n",
|
||||
FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER) ? ansi_highlight_green() :
|
||||
(s & (TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER)) != 0 ? ansi_highlight_red() : ansi_highlight_yellow(),
|
||||
|
|
|
@ -450,7 +450,7 @@ static size_t pe_section_table_find_profile_length(
|
|||
assert(start >= section_table);
|
||||
assert(start < section_table + n_section_table);
|
||||
|
||||
/* Look for the next .profile (or the end of the table), this is where the the sections for this
|
||||
/* Look for the next .profile (or the end of the table), this is where the sections for this
|
||||
* profile end. The base profile does not start with a .profile, the others do, hence conditionally
|
||||
* skip over the first entry. */
|
||||
const PeSectionHeader *e;
|
||||
|
@ -485,7 +485,7 @@ EFI_STATUS pe_locate_profile_sections(
|
|||
if (!p)
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
/* Look for the next .profile (or the end of the table), this is where the the sections for this
|
||||
/* Look for the next .profile (or the end of the table), this is where the sections for this
|
||||
* profile end. */
|
||||
size_t n = pe_section_table_find_profile_length(section_table, n_section_table, p, profile);
|
||||
|
||||
|
|
|
@ -1005,7 +1005,7 @@ static int validate_stub(void) {
|
|||
bool found = false;
|
||||
int r;
|
||||
|
||||
if (tpm2_support() != TPM2_SUPPORT_FULL)
|
||||
if (!tpm2_is_fully_supported())
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Sorry, system lacks full TPM2 support.");
|
||||
|
||||
r = efi_stub_get_features(&features);
|
||||
|
|
|
@ -181,7 +181,7 @@ static int manager_find_user_config_paths(char ***ret_files, char ***ret_dirs) {
|
|||
_cleanup_strv_free_ char **files = NULL, **dirs = NULL;
|
||||
int r;
|
||||
|
||||
r = xdg_user_config_dir(&base, "/systemd");
|
||||
r = xdg_user_config_dir("/systemd", &base);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -2478,7 +2478,7 @@ static int initialize_runtime(
|
|||
/* Create the runtime directory and place the inaccessible device nodes there, if we run in
|
||||
* user mode. In system mode mount_setup() already did that. */
|
||||
|
||||
r = xdg_user_runtime_dir(&p, "/systemd");
|
||||
r = xdg_user_runtime_dir("/systemd", &p);
|
||||
if (r < 0) {
|
||||
*ret_error_message = "$XDG_RUNTIME_DIR is not set";
|
||||
return log_struct_errno(LOG_EMERG, r,
|
||||
|
|
|
@ -1031,7 +1031,7 @@ int manager_new(RuntimeScope runtime_scope, ManagerTestRunFlags test_run_flags,
|
|||
r = mkdir_label("/run/systemd/units", 0755);
|
||||
else {
|
||||
_cleanup_free_ char *units_path = NULL;
|
||||
r = xdg_user_runtime_dir(&units_path, "/systemd/units");
|
||||
r = xdg_user_runtime_dir("/systemd/units", &units_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -5576,12 +5576,13 @@ static int unit_get_invocation_path(Unit *u, char **ret) {
|
|||
p = strjoin("/run/systemd/units/invocation:", u->id);
|
||||
else {
|
||||
_cleanup_free_ char *user_path = NULL;
|
||||
r = xdg_user_runtime_dir(&user_path, "/systemd/units/invocation:");
|
||||
|
||||
r = xdg_user_runtime_dir("/systemd/units/invocation:", &user_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p = strjoin(user_path, u->id);
|
||||
}
|
||||
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ sd_journal_sources += [audit_type_to_name]
|
|||
|
||||
############################################################
|
||||
|
||||
id128_sources = files(
|
||||
sd_id128_sources = files(
|
||||
'sd-id128/id128-util.c',
|
||||
'sd-id128/sd-id128.c',
|
||||
)
|
||||
|
@ -62,6 +62,41 @@ sd_event_sources = files(
|
|||
|
||||
############################################################
|
||||
|
||||
sd_bus_sources = files(
|
||||
'sd-bus/bus-common-errors.c',
|
||||
'sd-bus/bus-container.c',
|
||||
'sd-bus/bus-control.c',
|
||||
'sd-bus/bus-convenience.c',
|
||||
'sd-bus/bus-creds.c',
|
||||
'sd-bus/bus-dump.c',
|
||||
'sd-bus/bus-error.c',
|
||||
'sd-bus/bus-internal.c',
|
||||
'sd-bus/bus-introspect.c',
|
||||
'sd-bus/bus-kernel.c',
|
||||
'sd-bus/bus-match.c',
|
||||
'sd-bus/bus-message.c',
|
||||
'sd-bus/bus-objects.c',
|
||||
'sd-bus/bus-signature.c',
|
||||
'sd-bus/bus-slot.c',
|
||||
'sd-bus/bus-socket.c',
|
||||
'sd-bus/bus-track.c',
|
||||
'sd-bus/bus-type.c',
|
||||
'sd-bus/sd-bus.c',
|
||||
)
|
||||
|
||||
############################################################
|
||||
|
||||
sd_device_sources = files(
|
||||
'sd-device/device-enumerator.c',
|
||||
'sd-device/device-filter.c',
|
||||
'sd-device/device-monitor.c',
|
||||
'sd-device/device-private.c',
|
||||
'sd-device/device-util.c',
|
||||
'sd-device/sd-device.c',
|
||||
)
|
||||
|
||||
############################################################
|
||||
|
||||
sd_login_sources = files('sd-login/sd-login.c')
|
||||
|
||||
############################################################
|
||||
|
@ -83,33 +118,14 @@ sd_varlink_sources = files(
|
|||
|
||||
############################################################
|
||||
|
||||
libsystemd_sources = files(
|
||||
'sd-bus/bus-common-errors.c',
|
||||
'sd-bus/bus-container.c',
|
||||
'sd-bus/bus-control.c',
|
||||
'sd-bus/bus-convenience.c',
|
||||
'sd-bus/bus-creds.c',
|
||||
'sd-bus/bus-dump.c',
|
||||
'sd-bus/bus-error.c',
|
||||
'sd-bus/bus-internal.c',
|
||||
'sd-bus/bus-introspect.c',
|
||||
'sd-bus/bus-kernel.c',
|
||||
'sd-bus/bus-match.c',
|
||||
'sd-bus/bus-message.c',
|
||||
'sd-bus/bus-objects.c',
|
||||
'sd-bus/bus-signature.c',
|
||||
'sd-bus/bus-slot.c',
|
||||
'sd-bus/bus-socket.c',
|
||||
'sd-bus/bus-track.c',
|
||||
'sd-bus/bus-type.c',
|
||||
'sd-bus/sd-bus.c',
|
||||
'sd-device/device-enumerator.c',
|
||||
'sd-device/device-filter.c',
|
||||
'sd-device/device-monitor.c',
|
||||
'sd-device/device-private.c',
|
||||
'sd-device/device-util.c',
|
||||
'sd-device/sd-device.c',
|
||||
'sd-hwdb/sd-hwdb.c',
|
||||
sd_path_sources = files(
|
||||
'sd-path/path-lookup.c',
|
||||
'sd-path/sd-path.c',
|
||||
)
|
||||
|
||||
############################################################
|
||||
|
||||
sd_netlink_sources = files(
|
||||
'sd-netlink/netlink-genl.c',
|
||||
'sd-netlink/netlink-message-nfnl.c',
|
||||
'sd-netlink/netlink-message-rtnl.c',
|
||||
|
@ -122,11 +138,24 @@ libsystemd_sources = files(
|
|||
'sd-netlink/netlink-types.c',
|
||||
'sd-netlink/netlink-util.c',
|
||||
'sd-netlink/sd-netlink.c',
|
||||
)
|
||||
|
||||
############################################################
|
||||
|
||||
sd_network_sources = files(
|
||||
'sd-network/network-util.c',
|
||||
'sd-network/sd-network.c',
|
||||
'sd-path/sd-path.c',
|
||||
)
|
||||
|
||||
############################################################
|
||||
|
||||
libsystemd_sources = files(
|
||||
'sd-hwdb/sd-hwdb.c',
|
||||
'sd-resolve/sd-resolve.c',
|
||||
) + sd_journal_sources + id128_sources + sd_daemon_sources + sd_event_sources + sd_login_sources + sd_json_sources + sd_varlink_sources
|
||||
) + sd_journal_sources + sd_id128_sources + sd_daemon_sources \
|
||||
+ sd_event_sources + sd_bus_sources + sd_device_sources \
|
||||
+ sd_login_sources + sd_json_sources + sd_varlink_sources \
|
||||
+ sd_path_sources + sd_netlink_sources + sd_network_sources
|
||||
|
||||
libsystemd_c_args = ['-fvisibility=default']
|
||||
|
||||
|
|
|
@ -0,0 +1,734 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "user-util.h"
|
||||
|
||||
int user_search_dirs(const char *suffix, char ***ret_config_dirs, char ***ret_data_dirs) {
|
||||
_cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
|
||||
int r;
|
||||
|
||||
assert(ret_config_dirs);
|
||||
assert(ret_data_dirs);
|
||||
|
||||
r = sd_path_lookup_strv(SD_PATH_SEARCH_CONFIGURATION, suffix, &config_dirs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_path_lookup_strv(SD_PATH_SEARCH_SHARED, suffix, &data_dirs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret_config_dirs = TAKE_PTR(config_dirs);
|
||||
*ret_data_dirs = TAKE_PTR(data_dirs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int runtime_directory(RuntimeScope scope, const char *suffix, char **ret) {
|
||||
int r;
|
||||
|
||||
assert(IN_SET(scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER));
|
||||
assert(suffix);
|
||||
assert(ret);
|
||||
|
||||
/* Accept $RUNTIME_DIRECTORY as authoritative
|
||||
* If its missing apply the suffix to /run/, or $XDG_RUNTIME_DIR if we are in a user runtime scope.
|
||||
*
|
||||
* Return value indicates whether the suffix was applied or not */
|
||||
|
||||
const char *e = secure_getenv("RUNTIME_DIRECTORY");
|
||||
if (e)
|
||||
return strdup_to(ret, e);
|
||||
|
||||
if (scope == RUNTIME_SCOPE_USER) {
|
||||
r = xdg_user_runtime_dir(suffix, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
char *d = path_join("/run", suffix);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
*ret = d;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char* const user_data_unit_paths[] = {
|
||||
"/usr/local/lib/systemd/user",
|
||||
"/usr/local/share/systemd/user",
|
||||
USER_DATA_UNIT_DIR,
|
||||
"/usr/lib/systemd/user",
|
||||
"/usr/share/systemd/user",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char* const user_config_unit_paths[] = {
|
||||
USER_CONFIG_UNIT_DIR,
|
||||
"/etc/systemd/user",
|
||||
NULL
|
||||
};
|
||||
|
||||
bool path_is_user_data_dir(const char *path) {
|
||||
assert(path);
|
||||
|
||||
return path_strv_contains((char* const*) user_data_unit_paths, path);
|
||||
}
|
||||
|
||||
bool path_is_user_config_dir(const char *path) {
|
||||
assert(path);
|
||||
|
||||
return path_strv_contains((char* const*) user_config_unit_paths, path);
|
||||
}
|
||||
|
||||
static int acquire_generator_dirs(
|
||||
RuntimeScope scope,
|
||||
const char *tempdir,
|
||||
char **ret,
|
||||
char **ret_early,
|
||||
char **ret_late) {
|
||||
|
||||
_cleanup_free_ char *prefix_alloc = NULL, *g = NULL, *early = NULL, *late = NULL;
|
||||
const char *prefix;
|
||||
int r;
|
||||
|
||||
assert(IN_SET(scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER, RUNTIME_SCOPE_GLOBAL));
|
||||
assert(ret);
|
||||
assert(ret_early);
|
||||
assert(ret_late);
|
||||
|
||||
if (scope == RUNTIME_SCOPE_GLOBAL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (tempdir)
|
||||
prefix = tempdir;
|
||||
else if (scope == RUNTIME_SCOPE_SYSTEM)
|
||||
prefix = "/run/systemd";
|
||||
else { /* RUNTIME_SCOPE_USER */
|
||||
r = xdg_user_runtime_dir("/systemd", &prefix_alloc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
prefix = prefix_alloc;
|
||||
}
|
||||
|
||||
g = path_join(prefix, "generator");
|
||||
if (!g)
|
||||
return -ENOMEM;
|
||||
|
||||
early = path_join(prefix, "generator.early");
|
||||
if (!early)
|
||||
return -ENOMEM;
|
||||
|
||||
late = path_join(prefix, "generator.late");
|
||||
if (!late)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(g);
|
||||
*ret_early = TAKE_PTR(early);
|
||||
*ret_late = TAKE_PTR(late);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acquire_transient_dir(RuntimeScope scope, const char *tempdir, char **ret) {
|
||||
char *transient;
|
||||
|
||||
assert(IN_SET(scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER, RUNTIME_SCOPE_GLOBAL));
|
||||
assert(ret);
|
||||
|
||||
if (scope == RUNTIME_SCOPE_GLOBAL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (tempdir)
|
||||
transient = path_join(tempdir, "transient");
|
||||
else if (scope == RUNTIME_SCOPE_SYSTEM)
|
||||
transient = strdup("/run/systemd/transient");
|
||||
else /* RUNTIME_SCOPE_USER */
|
||||
return xdg_user_runtime_dir("/systemd/transient", ret);
|
||||
|
||||
if (!transient)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = transient;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef enum LookupDirType {
|
||||
LOOKUP_DIR_CONFIG,
|
||||
LOOKUP_DIR_CONTROL,
|
||||
LOOKUP_DIR_ATTACHED,
|
||||
_LOOKUP_DIR_MAX,
|
||||
_LOOKUP_DIR_INVALID = -EINVAL,
|
||||
} LookupDirType;
|
||||
|
||||
static int acquire_lookup_dirs(
|
||||
LookupDirType type,
|
||||
RuntimeScope scope,
|
||||
char **ret_persistent,
|
||||
char **ret_runtime) {
|
||||
|
||||
/* RUNTIME_SCOPE_USER dirs are relative to XDG_CONFIG_DIR and XDG_RUNTIME_DIR, respectively */
|
||||
static const struct {
|
||||
const char *persistent;
|
||||
const char *runtime;
|
||||
} dirs[_LOOKUP_DIR_MAX][_RUNTIME_SCOPE_MAX] = {
|
||||
[LOOKUP_DIR_CONFIG] = {
|
||||
[RUNTIME_SCOPE_SYSTEM] = { SYSTEM_CONFIG_UNIT_DIR, "/run/systemd/system" },
|
||||
[RUNTIME_SCOPE_GLOBAL] = { USER_CONFIG_UNIT_DIR, "/run/systemd/user" },
|
||||
[RUNTIME_SCOPE_USER] = { "systemd/user", "systemd/user" },
|
||||
},
|
||||
[LOOKUP_DIR_CONTROL] = {
|
||||
[RUNTIME_SCOPE_SYSTEM] = { "/etc/systemd/system.control", "/run/systemd/system.control" },
|
||||
[RUNTIME_SCOPE_USER] = { "systemd/user.control", "systemd/user.control" },
|
||||
},
|
||||
[LOOKUP_DIR_ATTACHED] = {
|
||||
[RUNTIME_SCOPE_SYSTEM] = { "/etc/systemd/system.attached", "/run/systemd/system.attached" },
|
||||
/* Portable services are not available to regular users for now. */
|
||||
},
|
||||
};
|
||||
|
||||
_cleanup_free_ char *a = NULL, *b = NULL;
|
||||
int r;
|
||||
|
||||
assert(type >= 0 && type < _LOOKUP_DIR_MAX);
|
||||
assert(IN_SET(scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER, RUNTIME_SCOPE_GLOBAL));
|
||||
assert(ret_persistent);
|
||||
assert(ret_runtime);
|
||||
|
||||
const char *persistent = dirs[type][scope].persistent;
|
||||
const char *runtime = dirs[type][scope].runtime;
|
||||
assert(!persistent == !runtime);
|
||||
|
||||
if (!persistent)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (scope) {
|
||||
|
||||
case RUNTIME_SCOPE_SYSTEM:
|
||||
case RUNTIME_SCOPE_GLOBAL:
|
||||
a = strdup(persistent);
|
||||
b = strdup(runtime);
|
||||
if (!a || !b)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_persistent = TAKE_PTR(a);
|
||||
*ret_runtime = TAKE_PTR(b);
|
||||
|
||||
return 0;
|
||||
|
||||
case RUNTIME_SCOPE_USER:
|
||||
r = xdg_user_config_dir(persistent, &a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = xdg_user_runtime_dir(runtime, ret_runtime);
|
||||
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 */
|
||||
*ret_runtime = NULL;
|
||||
}
|
||||
|
||||
*ret_persistent = TAKE_PTR(a);
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static int patch_root_prefix(char **p, const char *root_dir) {
|
||||
char *c;
|
||||
|
||||
assert(p);
|
||||
|
||||
if (!root_dir)
|
||||
return 0;
|
||||
|
||||
if (!*p)
|
||||
return 0;
|
||||
|
||||
c = path_join(root_dir, *p);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
free_and_replace(*p, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int patch_root_prefix_strv(char **l, const char *root_dir) {
|
||||
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;
|
||||
}
|
||||
|
||||
static int get_paths_from_environ(const char *var, char ***ret) {
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
assert(var);
|
||||
assert(ret);
|
||||
|
||||
e = getenv(var);
|
||||
if (!e) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool append = endswith(e, ":"); /* Whether to append the normal search paths after what's obtained
|
||||
from envvar */
|
||||
|
||||
/* FIXME: empty components in other places should be rejected. */
|
||||
|
||||
r = path_split_and_make_absolute(e, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return append;
|
||||
}
|
||||
|
||||
static char** user_unit_search_dirs(
|
||||
const char *persistent_config,
|
||||
const char *runtime_config,
|
||||
const char *global_persistent_config,
|
||||
const char *global_runtime_config,
|
||||
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 **paths = NULL, **config_dirs = NULL, **data_dirs = NULL;
|
||||
|
||||
/* The returned strv might contain duplicates, and we expect caller to filter them. */
|
||||
|
||||
assert(persistent_config);
|
||||
assert(global_persistent_config);
|
||||
assert(global_runtime_config);
|
||||
assert(persistent_control);
|
||||
|
||||
if (user_search_dirs("/systemd/user", &config_dirs, &data_dirs) < 0)
|
||||
return NULL;
|
||||
|
||||
paths = strv_new(persistent_control,
|
||||
STRV_IFNOTNULL(runtime_control),
|
||||
STRV_IFNOTNULL(transient),
|
||||
STRV_IFNOTNULL(generator_early),
|
||||
persistent_config);
|
||||
if (!paths)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend_strv(&paths, config_dirs, /* filter_duplicates = */ false) < 0)
|
||||
return NULL;
|
||||
|
||||
/* global config has lower priority than the user config of the same type */
|
||||
if (strv_extend(&paths, global_persistent_config) < 0)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend_strv(&paths, (char* const*) user_config_unit_paths, /* filter_duplicates = */ false) < 0)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend_many(&paths,
|
||||
STRV_IFNOTNULL(runtime_config),
|
||||
global_runtime_config,
|
||||
STRV_IFNOTNULL(generator)) < 0)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend_strv(&paths, data_dirs, /* filter_duplicates = */ false) < 0)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend_strv(&paths, (char* const*) user_data_unit_paths, false) < 0)
|
||||
return NULL;
|
||||
|
||||
if (strv_extend(&paths, generator_late) < 0)
|
||||
return NULL;
|
||||
|
||||
if (path_strv_make_absolute_cwd(paths) < 0)
|
||||
return NULL;
|
||||
|
||||
return TAKE_PTR(paths);
|
||||
}
|
||||
|
||||
int lookup_paths_init(
|
||||
LookupPaths *lp,
|
||||
RuntimeScope scope,
|
||||
LookupPathsFlags flags,
|
||||
const char *root_dir) {
|
||||
|
||||
_cleanup_(rmdir_and_freep) char *tempdir = NULL;
|
||||
_cleanup_free_ char
|
||||
*root = NULL,
|
||||
*persistent_config = NULL, *runtime_config = NULL,
|
||||
*global_persistent_config = NULL, *global_runtime_config = NULL,
|
||||
*generator = NULL, *generator_early = NULL, *generator_late = NULL,
|
||||
*transient = NULL,
|
||||
*persistent_control = NULL, *runtime_control = NULL,
|
||||
*persistent_attached = NULL, *runtime_attached = NULL;
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
int r;
|
||||
|
||||
assert(lp);
|
||||
assert(scope >= 0);
|
||||
assert(scope < _RUNTIME_SCOPE_MAX);
|
||||
|
||||
if (!empty_or_root(root_dir)) {
|
||||
if (scope == RUNTIME_SCOPE_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;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(flags, LOOKUP_PATHS_TEMPORARY_GENERATED)) {
|
||||
r = mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to create temporary directory: %m");
|
||||
}
|
||||
|
||||
/* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
|
||||
r = acquire_lookup_dirs(LOOKUP_DIR_CONFIG, scope, &persistent_config, &runtime_config);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (scope == RUNTIME_SCOPE_USER) {
|
||||
r = acquire_lookup_dirs(LOOKUP_DIR_CONFIG, RUNTIME_SCOPE_GLOBAL, &global_persistent_config, &global_runtime_config);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = acquire_lookup_dirs(LOOKUP_DIR_CONTROL, scope, &persistent_control, &runtime_control);
|
||||
if (r < 0 && r != -EOPNOTSUPP)
|
||||
return r;
|
||||
|
||||
r = acquire_lookup_dirs(LOOKUP_DIR_ATTACHED, scope, &persistent_attached, &runtime_attached);
|
||||
if (r < 0 && r != -EOPNOTSUPP)
|
||||
return r;
|
||||
|
||||
if (!FLAGS_SET(flags, LOOKUP_PATHS_EXCLUDE_GENERATED)) {
|
||||
/* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
|
||||
r = acquire_generator_dirs(scope, tempdir,
|
||||
&generator, &generator_early, &generator_late);
|
||||
if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
|
||||
r = acquire_transient_dir(scope, tempdir, &transient);
|
||||
if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
|
||||
return r;
|
||||
|
||||
/* First priority is whatever has been passed to us via env vars */
|
||||
r = get_paths_from_environ("SYSTEMD_UNIT_PATH", &paths);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!paths || r > 0) {
|
||||
/* Let's figure something out. */
|
||||
|
||||
_cleanup_strv_free_ char **add = NULL;
|
||||
|
||||
/* For the user units we include share/ in the search paths in order to comply with
|
||||
* the XDG basedir spec. For the system stuff we avoid such nonsense. OTOH we include (/usr/)lib/
|
||||
* in the search paths for the system stuff but avoid it for user stuff. */
|
||||
|
||||
assert(persistent_config);
|
||||
|
||||
switch (scope) {
|
||||
|
||||
case RUNTIME_SCOPE_SYSTEM:
|
||||
/* If you modify this you also want to modify systemdsystemunitpath= in systemd.pc.in! */
|
||||
add = strv_new(ASSERT_PTR(persistent_control),
|
||||
ASSERT_PTR(runtime_control),
|
||||
ASSERT_PTR(transient),
|
||||
ASSERT_PTR(generator_early),
|
||||
persistent_config,
|
||||
SYSTEM_CONFIG_UNIT_DIR,
|
||||
"/etc/systemd/system",
|
||||
ASSERT_PTR(persistent_attached),
|
||||
ASSERT_PTR(runtime_config),
|
||||
"/run/systemd/system",
|
||||
ASSERT_PTR(runtime_attached),
|
||||
ASSERT_PTR(generator),
|
||||
"/usr/local/lib/systemd/system",
|
||||
SYSTEM_DATA_UNIT_DIR,
|
||||
"/usr/lib/systemd/system",
|
||||
/* To be used ONLY for images which might be legacy split-usr */
|
||||
FLAGS_SET(flags, LOOKUP_PATHS_SPLIT_USR) ? "/lib/systemd/system" : STRV_IGNORE,
|
||||
ASSERT_PTR(generator_late));
|
||||
break;
|
||||
|
||||
case RUNTIME_SCOPE_GLOBAL:
|
||||
/* If you modify this you also want to modify systemduserunitpath= in systemd.pc.in,
|
||||
* and RUNTIME_SCOPE_USER search paths below! */
|
||||
add = strv_new(STRV_IFNOTNULL(persistent_control),
|
||||
STRV_IFNOTNULL(runtime_control),
|
||||
STRV_IFNOTNULL(transient),
|
||||
STRV_IFNOTNULL(generator_early),
|
||||
persistent_config,
|
||||
USER_CONFIG_UNIT_DIR,
|
||||
"/etc/systemd/user",
|
||||
ASSERT_PTR(runtime_config),
|
||||
"/run/systemd/user",
|
||||
STRV_IFNOTNULL(generator),
|
||||
"/usr/local/share/systemd/user",
|
||||
"/usr/share/systemd/user",
|
||||
"/usr/local/lib/systemd/user",
|
||||
USER_DATA_UNIT_DIR,
|
||||
"/usr/lib/systemd/user",
|
||||
STRV_IFNOTNULL(generator_late));
|
||||
break;
|
||||
|
||||
case RUNTIME_SCOPE_USER:
|
||||
add = user_unit_search_dirs(persistent_config, runtime_config,
|
||||
global_persistent_config, global_runtime_config,
|
||||
generator, generator_early, generator_late,
|
||||
transient,
|
||||
persistent_control, runtime_control);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (!add)
|
||||
return -ENOMEM;
|
||||
|
||||
if (paths) {
|
||||
/* strv_uniq() below would filter all duplicates against the final strv */
|
||||
r = strv_extend_strv(&paths, add, /* filter_duplicates = */ false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
/* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
|
||||
* and don't have to copy anything */
|
||||
paths = TAKE_PTR(add);
|
||||
}
|
||||
|
||||
r = patch_root_prefix(&persistent_config, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = patch_root_prefix(&runtime_config, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = patch_root_prefix(&generator, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = patch_root_prefix(&generator_early, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = patch_root_prefix(&generator_late, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = patch_root_prefix(&transient, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = patch_root_prefix(&persistent_control, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = patch_root_prefix(&runtime_control, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = patch_root_prefix(&persistent_attached, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = patch_root_prefix(&runtime_attached, root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = patch_root_prefix_strv(paths, root);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
*lp = (LookupPaths) {
|
||||
.search_path = strv_uniq(TAKE_PTR(paths)),
|
||||
|
||||
.persistent_config = TAKE_PTR(persistent_config),
|
||||
.runtime_config = TAKE_PTR(runtime_config),
|
||||
|
||||
.generator = TAKE_PTR(generator),
|
||||
.generator_early = TAKE_PTR(generator_early),
|
||||
.generator_late = TAKE_PTR(generator_late),
|
||||
|
||||
.transient = TAKE_PTR(transient),
|
||||
|
||||
.persistent_control = TAKE_PTR(persistent_control),
|
||||
.runtime_control = TAKE_PTR(runtime_control),
|
||||
|
||||
.persistent_attached = TAKE_PTR(persistent_attached),
|
||||
.runtime_attached = TAKE_PTR(runtime_attached),
|
||||
|
||||
.root_dir = TAKE_PTR(root),
|
||||
.temporary_dir = TAKE_PTR(tempdir),
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_paths_init_or_warn(LookupPaths *lp, RuntimeScope scope, LookupPathsFlags flags, const char *root_dir) {
|
||||
int r;
|
||||
|
||||
r = lookup_paths_init(lp, scope, flags, root_dir);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to initialize unit search paths%s%s: %m",
|
||||
isempty(root_dir) ? "" : " for root directory ", strempty(root_dir));
|
||||
return r;
|
||||
}
|
||||
|
||||
void lookup_paths_done(LookupPaths *lp) {
|
||||
assert(lp);
|
||||
|
||||
lp->search_path = strv_free(lp->search_path);
|
||||
|
||||
lp->persistent_config = mfree(lp->persistent_config);
|
||||
lp->runtime_config = mfree(lp->runtime_config);
|
||||
|
||||
lp->persistent_attached = mfree(lp->persistent_attached);
|
||||
lp->runtime_attached = mfree(lp->runtime_attached);
|
||||
|
||||
lp->generator = mfree(lp->generator);
|
||||
lp->generator_early = mfree(lp->generator_early);
|
||||
lp->generator_late = mfree(lp->generator_late);
|
||||
|
||||
lp->transient = mfree(lp->transient);
|
||||
|
||||
lp->persistent_control = mfree(lp->persistent_control);
|
||||
lp->runtime_control = mfree(lp->runtime_control);
|
||||
|
||||
lp->root_dir = mfree(lp->root_dir);
|
||||
lp->temporary_dir = mfree(lp->temporary_dir);
|
||||
}
|
||||
|
||||
void lookup_paths_log(LookupPaths *lp) {
|
||||
assert(lp);
|
||||
|
||||
if (strv_isempty(lp->search_path)) {
|
||||
log_debug("Ignoring unit files.");
|
||||
lp->search_path = strv_free(lp->search_path);
|
||||
} else {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
t = strv_join(lp->search_path, "\n\t");
|
||||
log_debug("Looking for unit files in (higher priority first):\n\t%s", strna(t));
|
||||
}
|
||||
}
|
||||
|
||||
static const char* const system_generator_paths[] = {
|
||||
"/run/systemd/system-generators",
|
||||
"/etc/systemd/system-generators",
|
||||
"/usr/local/lib/systemd/system-generators",
|
||||
SYSTEM_GENERATOR_DIR,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char* const user_generator_paths[] = {
|
||||
"/run/systemd/user-generators",
|
||||
"/etc/systemd/user-generators",
|
||||
"/usr/local/lib/systemd/user-generators",
|
||||
USER_GENERATOR_DIR,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char* const system_env_generator_paths[] = {
|
||||
"/run/systemd/system-environment-generators",
|
||||
"/etc/systemd/system-environment-generators",
|
||||
"/usr/local/lib/systemd/system-environment-generators",
|
||||
SYSTEM_ENV_GENERATOR_DIR,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char* const user_env_generator_paths[] = {
|
||||
"/run/systemd/user-environment-generators",
|
||||
"/etc/systemd/user-environment-generators",
|
||||
"/usr/local/lib/systemd/user-environment-generators",
|
||||
USER_ENV_GENERATOR_DIR,
|
||||
NULL,
|
||||
};
|
||||
|
||||
char** generator_binary_paths_internal(RuntimeScope scope, bool env_generator) {
|
||||
|
||||
static const struct {
|
||||
const char *env_name;
|
||||
const char * const *paths[_RUNTIME_SCOPE_MAX];
|
||||
} unit_generator = {
|
||||
"SYSTEMD_GENERATOR_PATH",
|
||||
{
|
||||
[RUNTIME_SCOPE_SYSTEM] = system_generator_paths,
|
||||
[RUNTIME_SCOPE_USER] = user_generator_paths,
|
||||
}
|
||||
}, environment_generator = {
|
||||
"SYSTEMD_ENVIRONMENT_GENERATOR_PATH",
|
||||
{
|
||||
[RUNTIME_SCOPE_SYSTEM] = system_env_generator_paths,
|
||||
[RUNTIME_SCOPE_USER] = user_env_generator_paths,
|
||||
}
|
||||
};
|
||||
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
int r;
|
||||
|
||||
assert(IN_SET(scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER));
|
||||
|
||||
const char *env_name = ASSERT_PTR((env_generator ? environment_generator : unit_generator).env_name);
|
||||
const char * const *search_paths = ASSERT_PTR((env_generator ? environment_generator : unit_generator).paths[scope]);
|
||||
|
||||
/* First priority is whatever has been passed to us via env vars */
|
||||
r = get_paths_from_environ(env_name, &paths);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
if (!paths || r > 0) {
|
||||
_cleanup_strv_free_ char **add = strv_copy((char* const*) search_paths);
|
||||
if (!add)
|
||||
return NULL;
|
||||
|
||||
if (paths) {
|
||||
r = strv_extend_strv(&paths, add, /* filter_duplicates = */ true);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
} else
|
||||
/* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
|
||||
* and don't have to copy anything */
|
||||
paths = TAKE_PTR(add);
|
||||
}
|
||||
|
||||
return TAKE_PTR(paths);
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "macro.h"
|
||||
#include "sd-path.h"
|
||||
|
||||
#include "runtime-scope.h"
|
||||
|
||||
typedef enum LookupPathsFlags {
|
||||
|
@ -55,11 +55,21 @@ typedef struct LookupPaths {
|
|||
int lookup_paths_init(LookupPaths *lp, RuntimeScope scope, LookupPathsFlags flags, const char *root_dir);
|
||||
int lookup_paths_init_or_warn(LookupPaths *lp, RuntimeScope scope, LookupPathsFlags flags, const char *root_dir);
|
||||
|
||||
int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs);
|
||||
int xdg_user_runtime_dir(char **ret, const char *suffix);
|
||||
int xdg_user_config_dir(char **ret, const char *suffix);
|
||||
int xdg_user_data_dir(char **ret, const char *suffix);
|
||||
int runtime_directory(char **ret, RuntimeScope scope, const char *suffix);
|
||||
int runtime_directory(RuntimeScope scope, const char *suffix, char **ret);
|
||||
|
||||
/* We don't treat /etc/xdg/systemd in these functions as the xdg base dir spec suggests because we assume
|
||||
* that is a link to /etc/systemd/ anyway. */
|
||||
|
||||
int user_search_dirs(const char *suffix, char ***ret_config_dirs, char ***ret_data_dirs);
|
||||
static inline int xdg_user_runtime_dir(const char *suffix, char **ret) {
|
||||
return sd_path_lookup(SD_PATH_USER_RUNTIME, suffix, ret);
|
||||
}
|
||||
static inline int xdg_user_config_dir(const char *suffix, char **ret) {
|
||||
return sd_path_lookup(SD_PATH_USER_CONFIGURATION, suffix, ret);
|
||||
}
|
||||
static inline int xdg_user_data_dir(const char *suffix, char **ret) {
|
||||
return sd_path_lookup(SD_PATH_USER_SHARED, suffix, ret);
|
||||
}
|
||||
|
||||
bool path_is_user_data_dir(const char *path);
|
||||
bool path_is_user_config_dir(const char *path);
|
||||
|
@ -67,11 +77,10 @@ bool path_is_user_config_dir(const char *path);
|
|||
void lookup_paths_log(LookupPaths *p);
|
||||
void lookup_paths_done(LookupPaths *p);
|
||||
|
||||
char **generator_binary_paths(RuntimeScope scope);
|
||||
char **env_generator_binary_paths(RuntimeScope scope);
|
||||
|
||||
#define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network"))
|
||||
#define NETWORK_DIRS_NULSTR CONF_PATHS_NULSTR("systemd/network")
|
||||
|
||||
#define PORTABLE_PROFILE_DIRS CONF_PATHS_NULSTR("systemd/portable/profile")
|
||||
int find_portable_profile(const char *name, const char *unit, char **ret_path);
|
||||
char** generator_binary_paths_internal(RuntimeScope scope, bool env_generator);
|
||||
static inline char** generator_binary_paths(RuntimeScope runtime_scope) {
|
||||
return generator_binary_paths_internal(runtime_scope, false);
|
||||
}
|
||||
static inline char** env_generator_binary_paths(RuntimeScope runtime_scope) {
|
||||
return generator_binary_paths_internal(runtime_scope, true);
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "alloc-util.h"
|
||||
#include "architecture.h"
|
||||
#include "conf-files.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
|
@ -65,26 +66,20 @@ static int from_home_dir(const char *envname, const char *suffix, char **buffer,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int from_user_dir(const char *field, char **buffer, const char **ret) {
|
||||
static int from_xdg_user_dir(const char *field, char **buffer, const char **ret) {
|
||||
_cleanup_free_ char *user_dirs = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *b = NULL;
|
||||
_cleanup_free_ const char *fn = NULL;
|
||||
const char *c = NULL;
|
||||
int r;
|
||||
|
||||
assert(field);
|
||||
assert(buffer);
|
||||
assert(ret);
|
||||
|
||||
r = from_home_dir("XDG_CONFIG_HOME", ".config", &b, &c);
|
||||
r = sd_path_lookup(SD_PATH_USER_CONFIGURATION, "user-dirs.dirs", &user_dirs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fn = path_join(c, "user-dirs.dirs");
|
||||
if (!fn)
|
||||
return -ENOMEM;
|
||||
|
||||
f = fopen(fn, "re");
|
||||
f = fopen(user_dirs, "re");
|
||||
if (!f) {
|
||||
if (errno == ENOENT)
|
||||
goto fallback;
|
||||
|
@ -107,14 +102,12 @@ static int from_user_dir(const char *field, char **buffer, const char **ret) {
|
|||
if (!p)
|
||||
continue;
|
||||
|
||||
p += strspn(p, WHITESPACE);
|
||||
|
||||
p = skip_leading_chars(p, WHITESPACE);
|
||||
if (*p != '=')
|
||||
continue;
|
||||
p++;
|
||||
|
||||
p += strspn(p, WHITESPACE);
|
||||
|
||||
p = skip_leading_chars(p, WHITESPACE);
|
||||
if (*p != '"')
|
||||
continue;
|
||||
p++;
|
||||
|
@ -125,62 +118,34 @@ static int from_user_dir(const char *field, char **buffer, const char **ret) {
|
|||
*e = 0;
|
||||
|
||||
/* Three syntaxes permitted: relative to $HOME, $HOME itself, and absolute path */
|
||||
if (startswith(p, "$HOME/")) {
|
||||
_cleanup_free_ char *h = NULL;
|
||||
if (streq(p, "$HOME"))
|
||||
goto home;
|
||||
|
||||
r = get_home_dir(&h);
|
||||
if (r < 0)
|
||||
return r;
|
||||
const char *s = startswith(p, "$HOME/");
|
||||
if (s)
|
||||
return from_home_dir(/* envname = */ NULL, s, buffer, ret);
|
||||
|
||||
if (!path_extend(&h, p+5))
|
||||
if (path_is_absolute(p)) {
|
||||
char *c = strdup(p);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
*buffer = h;
|
||||
*ret = TAKE_PTR(h);
|
||||
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;
|
||||
*ret = *buffer = c;
|
||||
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;
|
||||
if (streq(field, "XDG_DESKTOP_DIR"))
|
||||
return from_home_dir(/* envname = */ NULL, "Desktop", buffer, ret);
|
||||
|
||||
r = get_home_dir(&h);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!path_extend(&h, "Desktop"))
|
||||
return -ENOMEM;
|
||||
|
||||
*buffer = h;
|
||||
*ret = TAKE_PTR(h);
|
||||
} else {
|
||||
home:
|
||||
r = get_home_dir(buffer);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = *buffer;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -287,28 +252,28 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
|
|||
return 0;
|
||||
|
||||
case SD_PATH_USER_DOCUMENTS:
|
||||
return from_user_dir("XDG_DOCUMENTS_DIR", buffer, ret);
|
||||
return from_xdg_user_dir("XDG_DOCUMENTS_DIR", buffer, ret);
|
||||
|
||||
case SD_PATH_USER_MUSIC:
|
||||
return from_user_dir("XDG_MUSIC_DIR", buffer, ret);
|
||||
return from_xdg_user_dir("XDG_MUSIC_DIR", buffer, ret);
|
||||
|
||||
case SD_PATH_USER_PICTURES:
|
||||
return from_user_dir("XDG_PICTURES_DIR", buffer, ret);
|
||||
return from_xdg_user_dir("XDG_PICTURES_DIR", buffer, ret);
|
||||
|
||||
case SD_PATH_USER_VIDEOS:
|
||||
return from_user_dir("XDG_VIDEOS_DIR", buffer, ret);
|
||||
return from_xdg_user_dir("XDG_VIDEOS_DIR", buffer, ret);
|
||||
|
||||
case SD_PATH_USER_DOWNLOAD:
|
||||
return from_user_dir("XDG_DOWNLOAD_DIR", buffer, ret);
|
||||
return from_xdg_user_dir("XDG_DOWNLOAD_DIR", buffer, ret);
|
||||
|
||||
case SD_PATH_USER_PUBLIC:
|
||||
return from_user_dir("XDG_PUBLICSHARE_DIR", buffer, ret);
|
||||
return from_xdg_user_dir("XDG_PUBLICSHARE_DIR", buffer, ret);
|
||||
|
||||
case SD_PATH_USER_TEMPLATES:
|
||||
return from_user_dir("XDG_TEMPLATES_DIR", buffer, ret);
|
||||
return from_xdg_user_dir("XDG_TEMPLATES_DIR", buffer, ret);
|
||||
|
||||
case SD_PATH_USER_DESKTOP:
|
||||
return from_user_dir("XDG_DESKTOP_DIR", buffer, ret);
|
||||
return from_xdg_user_dir("XDG_DESKTOP_DIR", buffer, ret);
|
||||
|
||||
case SD_PATH_SYSTEMD_UTIL:
|
||||
*ret = PREFIX_NOSLASH "/lib/systemd";
|
||||
|
@ -390,55 +355,56 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int get_path_alloc(uint64_t type, const char *suffix, char **path) {
|
||||
static int get_path_alloc(uint64_t type, const char *suffix, char **ret) {
|
||||
_cleanup_free_ char *buffer = NULL;
|
||||
char *buffer2 = NULL;
|
||||
const char *ret;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(ret);
|
||||
|
||||
r = get_path(type, &buffer, &ret);
|
||||
r = get_path(type, &buffer, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (suffix) {
|
||||
suffix += strspn(suffix, "/");
|
||||
buffer2 = path_join(ret, suffix);
|
||||
if (!buffer2)
|
||||
char *suffixed = path_join(p, suffix);
|
||||
if (!suffixed)
|
||||
return -ENOMEM;
|
||||
|
||||
path_simplify(suffixed);
|
||||
|
||||
free_and_replace(buffer, suffixed);
|
||||
} else if (!buffer) {
|
||||
buffer = strdup(ret);
|
||||
buffer = strdup(p);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*path = buffer2 ?: TAKE_PTR(buffer);
|
||||
*ret = TAKE_PTR(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_path_lookup(uint64_t type, const char *suffix, char **path) {
|
||||
_public_ int sd_path_lookup(uint64_t type, const char *suffix, char **ret) {
|
||||
int r;
|
||||
|
||||
assert_return(path, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = get_path_alloc(type, suffix, path);
|
||||
r = get_path_alloc(type, suffix, ret);
|
||||
if (r != -EOPNOTSUPP)
|
||||
return r;
|
||||
|
||||
/* Fall back to sd_path_lookup_strv */
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
char *buffer;
|
||||
|
||||
r = sd_path_lookup_strv(type, suffix, &l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
buffer = strv_join(l, ":");
|
||||
if (!buffer)
|
||||
char *joined = strv_join(l, ":");
|
||||
if (!joined)
|
||||
return -ENOMEM;
|
||||
|
||||
*path = buffer;
|
||||
*ret = joined;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -615,25 +581,16 @@ static int get_search(uint64_t type, char ***ret) {
|
|||
}
|
||||
|
||||
case SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR:
|
||||
case SD_PATH_SYSTEMD_SEARCH_USER_GENERATOR: {
|
||||
RuntimeScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR ?
|
||||
RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER;
|
||||
char **t;
|
||||
|
||||
t = generator_binary_paths(scope);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case SD_PATH_SYSTEMD_SEARCH_USER_GENERATOR:
|
||||
case SD_PATH_SYSTEMD_SEARCH_SYSTEM_ENVIRONMENT_GENERATOR:
|
||||
case SD_PATH_SYSTEMD_SEARCH_USER_ENVIRONMENT_GENERATOR: {
|
||||
char **t;
|
||||
RuntimeScope scope = IN_SET(type, SD_PATH_SYSTEMD_SEARCH_SYSTEM_GENERATOR,
|
||||
SD_PATH_SYSTEMD_SEARCH_SYSTEM_ENVIRONMENT_GENERATOR) ?
|
||||
RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER;
|
||||
bool env_generator = IN_SET(type, SD_PATH_SYSTEMD_SEARCH_SYSTEM_ENVIRONMENT_GENERATOR,
|
||||
SD_PATH_SYSTEMD_SEARCH_USER_ENVIRONMENT_GENERATOR);
|
||||
|
||||
t = env_generator_binary_paths(type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_ENVIRONMENT_GENERATOR ?
|
||||
RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER);
|
||||
char **t = generator_binary_paths_internal(scope, env_generator);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -649,11 +606,11 @@ static int get_search(uint64_t type, char ***ret) {
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
_public_ int sd_path_lookup_strv(uint64_t type, const char *suffix, char ***paths) {
|
||||
_cleanup_strv_free_ char **l = NULL, **n = NULL;
|
||||
_public_ int sd_path_lookup_strv(uint64_t type, const char *suffix, char ***ret) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(paths, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = get_search(type, &l);
|
||||
if (r == -EOPNOTSUPP) {
|
||||
|
@ -669,31 +626,20 @@ _public_ int sd_path_lookup_strv(uint64_t type, const char *suffix, char ***path
|
|||
l[0] = TAKE_PTR(t);
|
||||
l[1] = NULL;
|
||||
|
||||
*paths = TAKE_PTR(l);
|
||||
*ret = TAKE_PTR(l);
|
||||
return 0;
|
||||
|
||||
} else if (r < 0)
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!suffix) {
|
||||
*paths = TAKE_PTR(l);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = new(char*, strv_length(l)+1);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
char **j = n;
|
||||
if (suffix)
|
||||
STRV_FOREACH(i, l) {
|
||||
*j = path_join(*i, suffix);
|
||||
if (!*j)
|
||||
if (!path_extend(i, suffix))
|
||||
return -ENOMEM;
|
||||
|
||||
j++;
|
||||
path_simplify(*i);
|
||||
}
|
||||
*j = NULL;
|
||||
|
||||
*paths = TAKE_PTR(n);
|
||||
*ret = TAKE_PTR(l);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1229,7 +1229,7 @@ static int generic_method_get_interface_description(
|
|||
sd_varlink_method_flags_t flags,
|
||||
void *userdata) {
|
||||
|
||||
static const struct sd_json_dispatch_field dispatch_table[] = {
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "interface", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, SD_JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -416,19 +416,18 @@ static int list_machine_one(sd_varlink *link, Machine *m, bool more) {
|
|||
}
|
||||
|
||||
static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
const char *mn = NULL;
|
||||
|
||||
const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&mn), 0 },
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
const char *mn = NULL;
|
||||
int r;
|
||||
|
||||
assert(parameters);
|
||||
|
||||
r = sd_varlink_dispatch(link, parameters, dispatch_table, 0);
|
||||
r = sd_varlink_dispatch(link, parameters, dispatch_table, &mn);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -97,8 +97,8 @@ static int neighbor_append_json(Neighbor *n, sd_json_variant **array) {
|
|||
|
||||
return sd_json_variant_append_arraybo(
|
||||
array,
|
||||
SD_JSON_BUILD_PAIR_INTEGER("Family", n->family),
|
||||
JSON_BUILD_PAIR_IN_ADDR("Destination", &n->in_addr, n->family),
|
||||
SD_JSON_BUILD_PAIR_INTEGER("Family", n->dst_addr.family),
|
||||
JSON_BUILD_PAIR_IN_ADDR("Destination", &n->dst_addr.address, n->dst_addr.family),
|
||||
JSON_BUILD_PAIR_HW_ADDR("LinkLayerAddress", &n->ll_addr),
|
||||
SD_JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n->source)),
|
||||
SD_JSON_BUILD_PAIR_STRING("ConfigState", state));
|
||||
|
@ -168,7 +168,7 @@ static int nexthop_append_json(NextHop *n, sd_json_variant **array) {
|
|||
return sd_json_variant_append_arraybo(
|
||||
array,
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("ID", n->id),
|
||||
JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n->gw, n->family),
|
||||
JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n->gw.address, n->family),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("Flags", n->flags),
|
||||
SD_JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags)),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("Protocol", n->protocol),
|
||||
|
|
|
@ -147,29 +147,29 @@ static int neighbor_dup(const Neighbor *neighbor, Neighbor **ret) {
|
|||
static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) {
|
||||
assert(neighbor);
|
||||
|
||||
siphash24_compress_typesafe(neighbor->family, state);
|
||||
siphash24_compress_typesafe(neighbor->dst_addr.family, state);
|
||||
|
||||
if (!IN_SET(neighbor->family, AF_INET, AF_INET6))
|
||||
if (!IN_SET(neighbor->dst_addr.family, AF_INET, AF_INET6))
|
||||
/* treat any other address family as AF_UNSPEC */
|
||||
return;
|
||||
|
||||
/* Equality of neighbors are given by the destination address.
|
||||
* See neigh_lookup() in the kernel. */
|
||||
in_addr_hash_func(&neighbor->in_addr, neighbor->family, state);
|
||||
in_addr_hash_func(&neighbor->dst_addr.address, neighbor->dst_addr.family, state);
|
||||
}
|
||||
|
||||
static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
|
||||
int r;
|
||||
|
||||
r = CMP(a->family, b->family);
|
||||
r = CMP(a->dst_addr.family, b->dst_addr.family);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (!IN_SET(a->family, AF_INET, AF_INET6))
|
||||
if (!IN_SET(a->dst_addr.family, AF_INET, AF_INET6))
|
||||
/* treat any other address family as AF_UNSPEC */
|
||||
return 0;
|
||||
|
||||
return memcmp(&a->in_addr, &b->in_addr, FAMILY_ADDRESS_SIZE(a->family));
|
||||
return memcmp(&a->dst_addr.address, &b->dst_addr.address, FAMILY_ADDRESS_SIZE(a->dst_addr.family));
|
||||
}
|
||||
|
||||
static int neighbor_get_request(Link *link, const Neighbor *neighbor, Request **ret) {
|
||||
|
@ -244,7 +244,7 @@ static void log_neighbor_debug(const Neighbor *neighbor, const char *str, const
|
|||
"%s %s neighbor (%s): lladdr: %s, dst: %s",
|
||||
str, strna(network_config_source_to_string(neighbor->source)), strna(state),
|
||||
HW_ADDR_TO_STR(&neighbor->ll_addr),
|
||||
IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr));
|
||||
IN_ADDR_TO_STRING(neighbor->dst_addr.family, &neighbor->dst_addr.address));
|
||||
}
|
||||
|
||||
static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
|
||||
|
@ -261,7 +261,7 @@ static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
|
|||
log_neighbor_debug(neighbor, "Configuring", link);
|
||||
|
||||
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_NEWNEIGH,
|
||||
link->ifindex, neighbor->family);
|
||||
link->ifindex, neighbor->dst_addr.family);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -273,7 +273,7 @@ static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->family, &neighbor->in_addr);
|
||||
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->dst_addr.family, &neighbor->dst_addr.address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -338,7 +338,7 @@ static int link_request_neighbor(Link *link, const Neighbor *neighbor) {
|
|||
"The link layer address length (%zu) for neighbor %s does not match with "
|
||||
"the hardware address length (%zu), ignoring the setting.",
|
||||
neighbor->ll_addr.length,
|
||||
IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr),
|
||||
IN_ADDR_TO_STRING(neighbor->dst_addr.family, &neighbor->dst_addr.address),
|
||||
link->hw_addr.length);
|
||||
return 0;
|
||||
}
|
||||
|
@ -451,11 +451,11 @@ int neighbor_remove(Neighbor *neighbor, Link *link) {
|
|||
log_neighbor_debug(neighbor, "Removing", link);
|
||||
|
||||
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_DELNEIGH,
|
||||
link->ifindex, neighbor->family);
|
||||
link->ifindex, neighbor->dst_addr.family);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not allocate RTM_DELNEIGH message: %m");
|
||||
|
||||
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->family, &neighbor->in_addr);
|
||||
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->dst_addr.family, &neighbor->dst_addr.address);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
|
||||
|
||||
|
@ -593,19 +593,19 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
return log_oom();
|
||||
|
||||
/* First, retrieve the fundamental information about the neighbor. */
|
||||
r = sd_rtnl_message_neigh_get_family(message, &tmp->family);
|
||||
r = sd_rtnl_message_neigh_get_family(message, &tmp->dst_addr.family);
|
||||
if (r < 0) {
|
||||
log_link_warning(link, "rtnl: received neighbor message without family, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
if (tmp->family == AF_BRIDGE) /* Currently, we do not support it. */
|
||||
if (tmp->dst_addr.family == AF_BRIDGE) /* Currently, we do not support it. */
|
||||
return 0;
|
||||
if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
|
||||
log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp->family);
|
||||
if (!IN_SET(tmp->dst_addr.family, AF_INET, AF_INET6)) {
|
||||
log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp->dst_addr.family);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = netlink_message_read_in_addr_union(message, NDA_DST, tmp->family, &tmp->in_addr);
|
||||
r = netlink_message_read_in_addr_union(message, NDA_DST, tmp->dst_addr.family, &tmp->dst_addr.address);
|
||||
if (r < 0) {
|
||||
log_link_warning_errno(link, r, "rtnl: received neighbor message without valid address, ignoring: %m");
|
||||
return 0;
|
||||
|
@ -660,28 +660,28 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
return 1;
|
||||
}
|
||||
|
||||
#define log_neighbor_section(neighbor, fmt, ...) \
|
||||
({ \
|
||||
const Neighbor *_neighbor = (neighbor); \
|
||||
log_section_warning_errno( \
|
||||
_neighbor ? _neighbor->section : NULL, \
|
||||
SYNTHETIC_ERRNO(EINVAL), \
|
||||
fmt " Ignoring [Neighbor] section.", \
|
||||
##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
static int neighbor_section_verify(Neighbor *neighbor) {
|
||||
if (section_is_invalid(neighbor->section))
|
||||
return -EINVAL;
|
||||
|
||||
if (neighbor->family == AF_UNSPEC)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: Neighbor section without Address= configured. "
|
||||
"Ignoring [Neighbor] section from line %u.",
|
||||
neighbor->section->filename, neighbor->section->line);
|
||||
if (neighbor->dst_addr.family == AF_UNSPEC)
|
||||
return log_neighbor_section(neighbor, "Neighbor section without Address= configured.");
|
||||
|
||||
if (neighbor->family == AF_INET6 && !socket_ipv6_is_supported())
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: Neighbor section with an IPv6 destination address configured, "
|
||||
"but the kernel does not support IPv6. "
|
||||
"Ignoring [Neighbor] section from line %u.",
|
||||
neighbor->section->filename, neighbor->section->line);
|
||||
if (neighbor->dst_addr.family == AF_INET6 && !socket_ipv6_is_supported())
|
||||
return log_neighbor_section(neighbor, "Neighbor section with an IPv6 destination address configured, but the kernel does not support IPv6.");
|
||||
|
||||
if (neighbor->ll_addr.length == 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: Neighbor section without LinkLayerAddress= configured. "
|
||||
"Ignoring [Neighbor] section from line %u.",
|
||||
neighbor->section->filename, neighbor->section->line);
|
||||
return log_neighbor_section(neighbor, "Neighbor section without LinkLayerAddress= configured.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -709,7 +709,7 @@ int network_drop_invalid_neighbors(Network *network) {
|
|||
log_warning("%s: Duplicated neighbor settings for %s is specified at line %u and %u, "
|
||||
"dropping the neighbor setting specified at line %u.",
|
||||
dup->section->filename,
|
||||
IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr),
|
||||
IN_ADDR_TO_STRING(neighbor->dst_addr.family, &neighbor->dst_addr.address),
|
||||
neighbor->section->line,
|
||||
dup->section->line, dup->section->line);
|
||||
/* neighbor_detach() will drop the neighbor from neighbors_by_section. */
|
||||
|
@ -728,7 +728,7 @@ int network_drop_invalid_neighbors(Network *network) {
|
|||
}
|
||||
|
||||
|
||||
int config_parse_neighbor_address(
|
||||
int config_parse_neighbor_section(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
|
@ -740,76 +740,26 @@ int config_parse_neighbor_address(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
|
||||
static const ConfigSectionParser table[_NEIGHBOR_CONF_PARSER_MAX] = {
|
||||
[NEIGHBOR_DESTINATION_ADDRESS] = { .parser = config_parse_in_addr_data, .ltype = 0, .offset = offsetof(Neighbor, dst_addr), },
|
||||
[NEIGHBOR_LINK_LAYER_ADDRESS] = { .parser = config_parse_hw_addr, .ltype = 0, .offset = offsetof(Neighbor, ll_addr), },
|
||||
};
|
||||
|
||||
_cleanup_(neighbor_unref_or_set_invalidp) Neighbor *neighbor = NULL;
|
||||
Network *network = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
r = neighbor_new_static(network, filename, section_line, &n);
|
||||
r = neighbor_new_static(network, filename, section_line, &neighbor);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
n->family = AF_UNSPEC;
|
||||
n->in_addr = IN_ADDR_NULL;
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = in_addr_from_string_auto(rvalue, &n->family, &n->in_addr);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Neighbor Address is invalid, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_neighbor_lladdr(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
|
||||
Network *network = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
r = neighbor_new_static(network, filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
n->ll_addr = HW_ADDR_NULL;
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_hw_addr(rvalue, &n->ll_addr);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Neighbor %s= is invalid, ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TAKE_PTR(n);
|
||||
r = config_section_parse(table, ELEMENTSOF(table),
|
||||
unit, filename, line, section, section_line, lvalue, ltype, rvalue, neighbor);
|
||||
if (r <= 0) /* 0 means non-critical error, but the section will be ignored. */
|
||||
return r;
|
||||
|
||||
TAKE_PTR(neighbor);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,8 +23,7 @@ typedef struct Neighbor {
|
|||
|
||||
unsigned n_ref;
|
||||
|
||||
int family;
|
||||
union in_addr_union in_addr;
|
||||
struct in_addr_data dst_addr;
|
||||
struct hw_addr_data ll_addr;
|
||||
} Neighbor;
|
||||
|
||||
|
@ -46,5 +45,11 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
|
||||
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Neighbor, neighbor);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_address);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_lladdr);
|
||||
typedef enum NeighborConfParserType {
|
||||
NEIGHBOR_DESTINATION_ADDRESS,
|
||||
NEIGHBOR_LINK_LAYER_ADDRESS,
|
||||
_NEIGHBOR_CONF_PARSER_MAX,
|
||||
_NEIGHBOR_CONF_PARSER_INVALID = -EINVAL,
|
||||
} NeighborConfParserType;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_section);
|
||||
|
|
|
@ -173,9 +173,9 @@ Address.NetLabel, config_parse_address_section,
|
|||
Address.NFTSet, config_parse_address_section, ADDRESS_NFT_SET, 0
|
||||
IPv6AddressLabel.Prefix, config_parse_ipv6_address_label_section, IPV6_ADDRESS_LABEL_PREFIX, 0
|
||||
IPv6AddressLabel.Label, config_parse_ipv6_address_label_section, IPV6_ADDRESS_LABEL, 0
|
||||
Neighbor.Address, config_parse_neighbor_address, 0, 0
|
||||
Neighbor.LinkLayerAddress, config_parse_neighbor_lladdr, 0, 0
|
||||
Neighbor.MACAddress, config_parse_neighbor_lladdr, 0, 0 /* deprecated */
|
||||
Neighbor.Address, config_parse_neighbor_section, NEIGHBOR_DESTINATION_ADDRESS, 0
|
||||
Neighbor.LinkLayerAddress, config_parse_neighbor_section, NEIGHBOR_LINK_LAYER_ADDRESS, 0
|
||||
Neighbor.MACAddress, config_parse_neighbor_section, NEIGHBOR_LINK_LAYER_ADDRESS, 0 /* deprecated */
|
||||
RoutingPolicyRule.TypeOfService, config_parse_routing_policy_rule, ROUTING_POLICY_RULE_TOS, 0
|
||||
RoutingPolicyRule.Priority, config_parse_routing_policy_rule, ROUTING_POLICY_RULE_PRIORITY, 0
|
||||
RoutingPolicyRule.GoTo, config_parse_routing_policy_rule, ROUTING_POLICY_RULE_GOTO, 0
|
||||
|
@ -219,12 +219,12 @@ Route.QuickAck, config_parse_route_metric_boolean,
|
|||
Route.TCPCongestionControlAlgorithm, config_parse_route_metric_tcp_congestion, RTAX_CC_ALGO, 0
|
||||
Route.FastOpenNoCookie, config_parse_route_metric_boolean, RTAX_FASTOPEN_NO_COOKIE, 0
|
||||
Route.TTLPropagate, config_parse_warn_compat, DISABLED_LEGACY, 0
|
||||
NextHop.Id, config_parse_nexthop_id, 0, 0
|
||||
NextHop.Gateway, config_parse_nexthop_gateway, 0, 0
|
||||
NextHop.Family, config_parse_nexthop_family, 0, 0
|
||||
NextHop.OnLink, config_parse_nexthop_onlink, 0, 0
|
||||
NextHop.Blackhole, config_parse_nexthop_blackhole, 0, 0
|
||||
NextHop.Group, config_parse_nexthop_group, 0, 0
|
||||
NextHop.Id, config_parse_nexthop_section, NEXTHOP_ID, 0
|
||||
NextHop.Gateway, config_parse_nexthop_section, NEXTHOP_GATEWAY, 0
|
||||
NextHop.Family, config_parse_nexthop_section, NEXTHOP_FAMILY, 0
|
||||
NextHop.OnLink, config_parse_nexthop_section, NEXTHOP_ONLINK, 0
|
||||
NextHop.Blackhole, config_parse_nexthop_section, NEXTHOP_BLACKHOLE, 0
|
||||
NextHop.Group, config_parse_nexthop_section, NEXTHOP_GROUP, 0
|
||||
DHCPv4.RequestAddress, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_request_address)
|
||||
DHCPv4.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
|
||||
DHCPv4.UseDNS, config_parse_tristate, 0, offsetof(Network, dhcp_use_dns)
|
||||
|
|
|
@ -854,7 +854,7 @@ bool network_has_static_ipv6_configurations(Network *network) {
|
|||
return true;
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
|
||||
if (neighbor->family == AF_INET6)
|
||||
if (neighbor->dst_addr.family == AF_INET6)
|
||||
return true;
|
||||
|
||||
if (!hashmap_isempty(network->address_labels_by_section))
|
||||
|
|
|
@ -236,7 +236,7 @@ static int nexthop_compare_full(const NextHop *a, const NextHop *b) {
|
|||
return r;
|
||||
|
||||
if (IN_SET(a->family, AF_INET, AF_INET6)) {
|
||||
r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
|
||||
r = memcmp(&a->gw.address, &b->gw.address, FAMILY_ADDRESS_SIZE(a->family));
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
@ -481,7 +481,7 @@ static void log_nexthop_debug(const NextHop *nexthop, const char *str, Manager *
|
|||
log_link_debug(link, "%s %s nexthop (%s): id: %"PRIu32", gw: %s, blackhole: %s, group: %s, flags: %s",
|
||||
str, strna(network_config_source_to_string(nexthop->source)), strna(state),
|
||||
nexthop->id,
|
||||
IN_ADDR_TO_STRING(nexthop->family, &nexthop->gw),
|
||||
IN_ADDR_TO_STRING(nexthop->family, &nexthop->gw.address),
|
||||
yes_no(nexthop->blackhole), strna(group), strna(flags));
|
||||
}
|
||||
|
||||
|
@ -627,8 +627,8 @@ static int nexthop_configure(NextHop *nexthop, Link *link, Request *req) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (in_addr_is_set(nexthop->family, &nexthop->gw)) {
|
||||
r = netlink_message_append_in_addr_union(m, NHA_GATEWAY, nexthop->family, &nexthop->gw);
|
||||
if (in_addr_is_set(nexthop->family, &nexthop->gw.address)) {
|
||||
r = netlink_message_append_in_addr_union(m, NHA_GATEWAY, nexthop->family, &nexthop->gw.address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -722,7 +722,7 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
|
|||
return r;
|
||||
}
|
||||
|
||||
return gateway_is_ready(link, FLAGS_SET(nexthop->flags, RTNH_F_ONLINK), nexthop->family, &nexthop->gw);
|
||||
return gateway_is_ready(link, FLAGS_SET(nexthop->flags, RTNH_F_ONLINK), nexthop->family, &nexthop->gw.address);
|
||||
}
|
||||
|
||||
static int nexthop_process_request(Request *req, Link *link, NextHop *nexthop) {
|
||||
|
@ -1093,9 +1093,9 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
(void) nexthop_update_group(nexthop, message);
|
||||
|
||||
if (nexthop->family != AF_UNSPEC) {
|
||||
r = netlink_message_read_in_addr_union(message, NHA_GATEWAY, nexthop->family, &nexthop->gw);
|
||||
r = netlink_message_read_in_addr_union(message, NHA_GATEWAY, nexthop->family, &nexthop->gw.address);
|
||||
if (r == -ENODATA)
|
||||
nexthop->gw = IN_ADDR_NULL;
|
||||
nexthop->gw.address = IN_ADDR_NULL;
|
||||
else if (r < 0)
|
||||
log_debug_errno(r, "rtnl: could not get NHA_GATEWAY attribute, ignoring: %m");
|
||||
}
|
||||
|
@ -1129,66 +1129,60 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
return 1;
|
||||
}
|
||||
|
||||
#define log_nexthop_section(nexthop, fmt, ...) \
|
||||
({ \
|
||||
const NextHop *_nexthop = (nexthop); \
|
||||
log_section_warning_errno( \
|
||||
_nexthop ? _nexthop->section : NULL, \
|
||||
SYNTHETIC_ERRNO(EINVAL), \
|
||||
fmt " Ignoring [NextHop] section.", \
|
||||
##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
static int nexthop_section_verify(NextHop *nh) {
|
||||
if (section_is_invalid(nh->section))
|
||||
return -EINVAL;
|
||||
|
||||
if (!nh->network->manager->manage_foreign_nexthops && nh->id == 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: [NextHop] section without specifying Id= is not supported "
|
||||
"if ManageForeignNextHops=no is set in networkd.conf. "
|
||||
"Ignoring [NextHop] section from line %u.",
|
||||
nh->section->filename, nh->section->line);
|
||||
return log_nexthop_section(nh, "Nexthop without specifying Id= is not supported if ManageForeignNextHops=no is set in networkd.conf.");
|
||||
|
||||
if (nh->family == AF_UNSPEC)
|
||||
nh->family = nh->gw.family;
|
||||
else if (nh->gw.family != AF_UNSPEC && nh->gw.family != nh->family)
|
||||
return log_nexthop_section(nh, "Family= and Gateway= settings for nexthop contradict each other.");
|
||||
|
||||
assert(nh->gw.family == nh->family || nh->gw.family == AF_UNSPEC);
|
||||
|
||||
if (!hashmap_isempty(nh->group)) {
|
||||
if (in_addr_is_set(nh->family, &nh->gw))
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: nexthop group cannot have gateway address. "
|
||||
"Ignoring [NextHop] section from line %u.",
|
||||
nh->section->filename, nh->section->line);
|
||||
if (in_addr_is_set(nh->family, &nh->gw.address))
|
||||
return log_nexthop_section(nh, "Nexthop group cannot have gateway address.");
|
||||
|
||||
if (nh->family != AF_UNSPEC)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: nexthop group cannot have Family= setting. "
|
||||
"Ignoring [NextHop] section from line %u.",
|
||||
nh->section->filename, nh->section->line);
|
||||
return log_nexthop_section(nh, "Nexthop group cannot have Family= setting.");
|
||||
|
||||
if (nh->blackhole)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: nexthop group cannot be a blackhole. "
|
||||
"Ignoring [NextHop] section from line %u.",
|
||||
nh->section->filename, nh->section->line);
|
||||
return log_nexthop_section(nh, "Nexthop group cannot be a blackhole.");
|
||||
|
||||
if (nh->onlink > 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: nexthop group cannot have on-link flag. "
|
||||
"Ignoring [NextHop] section from line %u.",
|
||||
nh->section->filename, nh->section->line);
|
||||
return log_nexthop_section(nh, "Nexthop group cannot have on-link flag.");
|
||||
|
||||
} else if (nh->family == AF_UNSPEC)
|
||||
/* When neither Family=, Gateway=, nor Group= is specified, assume IPv4. */
|
||||
nh->family = AF_INET;
|
||||
|
||||
if (nh->blackhole) {
|
||||
if (in_addr_is_set(nh->family, &nh->gw))
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: blackhole nexthop cannot have gateway address. "
|
||||
"Ignoring [NextHop] section from line %u.",
|
||||
nh->section->filename, nh->section->line);
|
||||
if (in_addr_is_set(nh->family, &nh->gw.address))
|
||||
return log_nexthop_section(nh, "Blackhole nexthop cannot have gateway address.");
|
||||
|
||||
if (nh->onlink > 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: blackhole nexthop cannot have on-link flag. "
|
||||
"Ignoring [NextHop] section from line %u.",
|
||||
nh->section->filename, nh->section->line);
|
||||
return log_nexthop_section(nh, "Blackhole nexthop cannot have on-link flag.");
|
||||
}
|
||||
|
||||
if (nh->onlink < 0 && in_addr_is_set(nh->family, &nh->gw) &&
|
||||
if (nh->onlink < 0 && in_addr_is_set(nh->family, &nh->gw.address) &&
|
||||
ordered_hashmap_isempty(nh->network->addresses_by_section)) {
|
||||
/* If no address is configured, in most cases the gateway cannot be reachable.
|
||||
* TODO: we may need to improve the condition above. */
|
||||
log_warning("%s: Gateway= without static address configured. "
|
||||
"Enabling OnLink= option.",
|
||||
nh->section->filename);
|
||||
log_section_warning(nh->section, "Nexthop with Gateway= specified, but no static address configured. Enabling OnLink= option.");
|
||||
nh->onlink = true;
|
||||
}
|
||||
|
||||
|
@ -1262,7 +1256,7 @@ int manager_build_nexthop_ids(Manager *manager) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_nexthop_id(
|
||||
static int config_parse_nexthop_family(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
|
@ -1274,261 +1268,38 @@ int config_parse_nexthop_id(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
|
||||
Network *network = userdata;
|
||||
uint32_t id;
|
||||
int *family = ASSERT_PTR(data);
|
||||
|
||||
if (isempty(rvalue))
|
||||
*family = AF_UNSPEC;
|
||||
else if (streq(rvalue, "ipv4"))
|
||||
*family = AF_INET;
|
||||
else if (streq(rvalue, "ipv6"))
|
||||
*family = AF_INET6;
|
||||
else
|
||||
return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int config_parse_nexthop_group(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Hashmap **group = ASSERT_PTR(data);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = nexthop_new_static(network, filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
n->id = 0;
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou32(rvalue, &id);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Could not parse nexthop id \"%s\", ignoring assignment: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (id == 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"Invalid nexthop id \"%s\", ignoring assignment: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n->id = id;
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_nexthop_gateway(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = nexthop_new_static(network, filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
n->family = AF_UNSPEC;
|
||||
n->gw = IN_ADDR_NULL;
|
||||
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_nexthop_family(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
|
||||
Network *network = userdata;
|
||||
AddressFamily a;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = nexthop_new_static(network, filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
if (isempty(rvalue) &&
|
||||
!in_addr_is_set(n->family, &n->gw)) {
|
||||
/* Accept an empty string only when Gateway= is null or not specified. */
|
||||
n->family = AF_UNSPEC;
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
a = nexthop_address_family_from_string(rvalue);
|
||||
if (a < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_addr_is_set(n->family, &n->gw) &&
|
||||
((a == ADDRESS_FAMILY_IPV4 && n->family == AF_INET6) ||
|
||||
(a == ADDRESS_FAMILY_IPV6 && n->family == AF_INET))) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"Specified family '%s' conflicts with the family of the previously specified Gateway=, "
|
||||
"ignoring assignment.", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (a) {
|
||||
case ADDRESS_FAMILY_IPV4:
|
||||
n->family = AF_INET;
|
||||
break;
|
||||
case ADDRESS_FAMILY_IPV6:
|
||||
n->family = AF_INET6;
|
||||
break;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_nexthop_onlink(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = nexthop_new_static(network, filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = parse_tristate(rvalue, &n->onlink);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_nexthop_blackhole(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = nexthop_new_static(network, filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = parse_boolean(rvalue);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n->blackhole = r;
|
||||
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_nexthop_group(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = nexthop_new_static(network, filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
n->group = hashmap_free_free(n->group);
|
||||
TAKE_PTR(n);
|
||||
return 0;
|
||||
*group = hashmap_free_free(*group);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (const char *p = rvalue;;) {
|
||||
|
@ -1538,15 +1309,10 @@ int config_parse_nexthop_group(
|
|||
char *sep;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, 0);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Invalid %s=, ignoring assignment: %s", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
|
||||
if (r == 0)
|
||||
break;
|
||||
return 1;
|
||||
|
||||
nhg = new0(struct nexthop_grp, 1);
|
||||
if (!nhg)
|
||||
|
@ -1586,7 +1352,7 @@ int config_parse_nexthop_group(
|
|||
continue;
|
||||
}
|
||||
|
||||
r = hashmap_ensure_put(&n->group, NULL, UINT32_TO_PTR(nhg->id), nhg);
|
||||
r = hashmap_ensure_put(group, NULL, UINT32_TO_PTR(nhg->id), nhg);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r == -EEXIST) {
|
||||
|
@ -1598,7 +1364,44 @@ int config_parse_nexthop_group(
|
|||
assert(r > 0);
|
||||
TAKE_PTR(nhg);
|
||||
}
|
||||
}
|
||||
|
||||
TAKE_PTR(n);
|
||||
int config_parse_nexthop_section(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
static const ConfigSectionParser table[_NEXTHOP_CONF_PARSER_MAX] = {
|
||||
[NEXTHOP_ID] = { .parser = config_parse_uint32, .ltype = 0, .offset = offsetof(NextHop, id), },
|
||||
[NEXTHOP_GATEWAY] = { .parser = config_parse_in_addr_data, .ltype = 0, .offset = offsetof(NextHop, gw), },
|
||||
[NEXTHOP_FAMILY] = { .parser = config_parse_nexthop_family, .ltype = 0, .offset = offsetof(NextHop, family), },
|
||||
[NEXTHOP_ONLINK] = { .parser = config_parse_tristate, .ltype = 0, .offset = offsetof(NextHop, onlink), },
|
||||
[NEXTHOP_BLACKHOLE] = { .parser = config_parse_bool, .ltype = 0, .offset = offsetof(NextHop, blackhole), },
|
||||
[NEXTHOP_GROUP] = { .parser = config_parse_nexthop_group, .ltype = 0, .offset = offsetof(NextHop, group), },
|
||||
};
|
||||
|
||||
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *nexthop = NULL;
|
||||
Network *network = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
||||
r = nexthop_new_static(network, filename, section_line, &nexthop);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = config_section_parse(table, ELEMENTSOF(table),
|
||||
unit, filename, line, section, section_line, lvalue, ltype, rvalue, nexthop);
|
||||
if (r <= 0) /* 0 means non-critical error, but the section will be ignored. */
|
||||
return r;
|
||||
|
||||
TAKE_PTR(nexthop);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ typedef struct NextHop {
|
|||
Hashmap *group; /* NHA_GROUP */
|
||||
bool blackhole; /* NHA_BLACKHOLE */
|
||||
int ifindex; /* NHA_OIF */
|
||||
union in_addr_union gw; /* NHA_GATEWAY */
|
||||
struct in_addr_data gw; /* NHA_GATEWAY, gw.family is only used by conf parser. */
|
||||
|
||||
/* Only used in conf parser and nexthop_section_verify(). */
|
||||
int onlink;
|
||||
|
@ -71,9 +71,15 @@ int manager_build_nexthop_ids(Manager *manager);
|
|||
|
||||
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(NextHop, nexthop);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_id);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_gateway);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_family);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_onlink);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_blackhole);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_group);
|
||||
typedef enum NextHopConfParserType {
|
||||
NEXTHOP_ID,
|
||||
NEXTHOP_GATEWAY,
|
||||
NEXTHOP_FAMILY,
|
||||
NEXTHOP_ONLINK,
|
||||
NEXTHOP_BLACKHOLE,
|
||||
NEXTHOP_GROUP,
|
||||
_NEXTHOP_CONF_PARSER_MAX,
|
||||
_NEXTHOP_CONF_PARSER_INVALID = -EINVAL,
|
||||
} NextHopConfParserType;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_section);
|
||||
|
|
|
@ -1742,7 +1742,7 @@ static int oci_seccomp_args(const char *name, sd_json_variant *v, sd_json_dispat
|
|||
int r;
|
||||
|
||||
JSON_VARIANT_ARRAY_FOREACH(e, v) {
|
||||
static const struct sd_json_dispatch_field table[] = {
|
||||
static const sd_json_dispatch_field table[] = {
|
||||
{ "index", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, offsetof(struct scmp_arg_cmp, arg), SD_JSON_MANDATORY },
|
||||
{ "value", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint64, offsetof(struct scmp_arg_cmp, datum_a), SD_JSON_MANDATORY },
|
||||
{ "valueTwo", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint64, offsetof(struct scmp_arg_cmp, datum_b), 0 },
|
||||
|
|
|
@ -369,7 +369,7 @@ static int run(int argc, char *argv[]) {
|
|||
event = TPM2_EVENT_PHASE;
|
||||
}
|
||||
|
||||
if (arg_graceful && tpm2_support() != TPM2_SUPPORT_FULL) {
|
||||
if (arg_graceful && !tpm2_is_fully_supported()) {
|
||||
log_notice("No complete TPM2 support detected, exiting gracefully.");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -2876,55 +2876,76 @@ static int print_answer(sd_json_variant *answer) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
typedef struct MonitorQueryParams {
|
||||
sd_json_variant *question;
|
||||
sd_json_variant *answer;
|
||||
sd_json_variant *collected_questions;
|
||||
int rcode;
|
||||
int error;
|
||||
int ede_code;
|
||||
const char *state;
|
||||
const char *result;
|
||||
const char *ede_msg;
|
||||
} MonitorQueryParams;
|
||||
|
||||
static void monitor_query_params_done(MonitorQueryParams *p) {
|
||||
assert(p);
|
||||
|
||||
sd_json_variant_unref(p->question);
|
||||
sd_json_variant_unref(p->answer);
|
||||
sd_json_variant_unref(p->collected_questions);
|
||||
}
|
||||
|
||||
static void monitor_query_dump(sd_json_variant *v) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *question = NULL, *answer = NULL, *collected_questions = NULL;
|
||||
int rcode = -1, error = 0, ede_code = -1;
|
||||
const char *state = NULL, *result = NULL, *ede_msg = NULL;
|
||||
|
||||
assert(v);
|
||||
|
||||
sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "question", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&question), SD_JSON_MANDATORY },
|
||||
{ "answer", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&answer), 0 },
|
||||
{ "collectedQuestions", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&collected_questions), 0 },
|
||||
{ "state", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&state), SD_JSON_MANDATORY },
|
||||
{ "result", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&result), 0 },
|
||||
{ "rcode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, PTR_TO_SIZE(&rcode), 0 },
|
||||
{ "errno", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, PTR_TO_SIZE(&error), 0 },
|
||||
{ "extendedDNSErrorCode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, PTR_TO_SIZE(&ede_code), 0 },
|
||||
{ "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&ede_msg), 0 },
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "question", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(MonitorQueryParams, question), SD_JSON_MANDATORY },
|
||||
{ "answer", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(MonitorQueryParams, answer), 0 },
|
||||
{ "collectedQuestions", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(MonitorQueryParams, collected_questions), 0 },
|
||||
{ "state", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MonitorQueryParams, state), SD_JSON_MANDATORY },
|
||||
{ "result", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MonitorQueryParams, result), 0 },
|
||||
{ "rcode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(MonitorQueryParams, rcode), 0 },
|
||||
{ "errno", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(MonitorQueryParams, error), 0 },
|
||||
{ "extendedDNSErrorCode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(MonitorQueryParams, ede_code), 0 },
|
||||
{ "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MonitorQueryParams, ede_msg), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
if (sd_json_dispatch(v, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, NULL) < 0)
|
||||
_cleanup_(monitor_query_params_done) MonitorQueryParams p = {
|
||||
.rcode = -1,
|
||||
.ede_code = -1,
|
||||
};
|
||||
|
||||
assert(v);
|
||||
|
||||
if (sd_json_dispatch(v, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, &p) < 0)
|
||||
return;
|
||||
|
||||
/* First show the current question */
|
||||
print_question('Q', ansi_highlight_cyan(), question);
|
||||
print_question('Q', ansi_highlight_cyan(), p.question);
|
||||
|
||||
/* And then show the questions that led to this one in case this was a CNAME chain */
|
||||
print_question('C', ansi_highlight_grey(), collected_questions);
|
||||
print_question('C', ansi_highlight_grey(), p.collected_questions);
|
||||
|
||||
printf("%s%s S%s: %s",
|
||||
streq_ptr(state, "success") ? ansi_highlight_green() : ansi_highlight_red(),
|
||||
streq_ptr(p.state, "success") ? ansi_highlight_green() : ansi_highlight_red(),
|
||||
special_glyph(SPECIAL_GLYPH_ARROW_LEFT),
|
||||
ansi_normal(),
|
||||
strna(streq_ptr(state, "errno") ? errno_to_name(error) :
|
||||
streq_ptr(state, "rcode-failure") ? dns_rcode_to_string(rcode) :
|
||||
state));
|
||||
strna(streq_ptr(p.state, "errno") ? errno_to_name(p.error) :
|
||||
streq_ptr(p.state, "rcode-failure") ? dns_rcode_to_string(p.rcode) :
|
||||
p.state));
|
||||
|
||||
if (!isempty(result))
|
||||
printf(": %s", result);
|
||||
if (!isempty(p.result))
|
||||
printf(": %s", p.result);
|
||||
|
||||
if (ede_code >= 0)
|
||||
if (p.ede_code >= 0)
|
||||
printf(" (%s%s%s)",
|
||||
FORMAT_DNS_EDE_RCODE(ede_code),
|
||||
!isempty(ede_msg) ? ": " : "",
|
||||
strempty(ede_msg));
|
||||
FORMAT_DNS_EDE_RCODE(p.ede_code),
|
||||
!isempty(p.ede_msg) ? ": " : "",
|
||||
strempty(p.ede_msg));
|
||||
|
||||
puts("");
|
||||
|
||||
print_answer(answer);
|
||||
print_answer(p.answer);
|
||||
}
|
||||
|
||||
static int monitor_reply(
|
||||
|
|
|
@ -2145,26 +2145,31 @@ int dns_resource_key_to_json(DnsResourceKey *key, sd_json_variant **ret) {
|
|||
}
|
||||
|
||||
int dns_resource_key_from_json(sd_json_variant *v, DnsResourceKey **ret) {
|
||||
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
|
||||
uint16_t type = 0, class = 0;
|
||||
const char *name = NULL;
|
||||
int r;
|
||||
struct params {
|
||||
uint16_t type;
|
||||
uint16_t class;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "class", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, PTR_TO_SIZE(&class), SD_JSON_MANDATORY },
|
||||
{ "type", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, PTR_TO_SIZE(&type), SD_JSON_MANDATORY },
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&name), SD_JSON_MANDATORY },
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "class", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(struct params, class), SD_JSON_MANDATORY },
|
||||
{ "type", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(struct params, type), SD_JSON_MANDATORY },
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct params, name), SD_JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
||||
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
|
||||
struct params p;
|
||||
int r;
|
||||
|
||||
assert(v);
|
||||
assert(ret);
|
||||
|
||||
r = sd_json_dispatch(v, dispatch_table, 0, NULL);
|
||||
r = sd_json_dispatch(v, dispatch_table, 0, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
key = dns_resource_key_new(class, type, name);
|
||||
key = dns_resource_key_new(p.class, p.type, p.name);
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -667,7 +667,7 @@ static int has_tpm2(void) {
|
|||
*
|
||||
* Note that we don't check if we ourselves are built with TPM2 support here! */
|
||||
|
||||
return FLAGS_SET(tpm2_support(), TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE);
|
||||
return FLAGS_SET(tpm2_support_full(TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE), TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE);
|
||||
}
|
||||
|
||||
static int condition_test_security(Condition *c, char **env) {
|
||||
|
|
|
@ -1764,7 +1764,7 @@ int config_parse_hw_addr(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
struct hw_addr_data a, *hwaddr = ASSERT_PTR(data);
|
||||
struct hw_addr_data *hwaddr = ASSERT_PTR(data);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -1776,11 +1776,10 @@ int config_parse_hw_addr(
|
|||
return 1;
|
||||
}
|
||||
|
||||
r = parse_hw_addr_full(rvalue, ltype, &a);
|
||||
r = parse_hw_addr_full(rvalue, ltype, hwaddr);
|
||||
if (r < 0)
|
||||
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
|
||||
|
||||
*hwaddr = a;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1973,6 +1972,36 @@ int config_parse_in_addr_non_null(
|
|||
return 1;
|
||||
}
|
||||
|
||||
int config_parse_in_addr_data(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
struct in_addr_data *p = ASSERT_PTR(data);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*p = (struct in_addr_data) {};
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = in_addr_from_string_auto(rvalue, &p->family, &p->address);
|
||||
if (r < 0)
|
||||
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int config_parse_unsigned_bounded(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
|
|
|
@ -304,6 +304,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_hw_addrs);
|
|||
CONFIG_PARSER_PROTOTYPE(config_parse_ether_addr);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_ether_addrs);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_in_addr_non_null);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_in_addr_data);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_percent);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_permyriad);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_pid);
|
||||
|
|
|
@ -886,7 +886,7 @@ int encrypt_credential_and_warn(
|
|||
* container tpm2_support will detect this, and will return a different flag combination of
|
||||
* TPM2_SUPPORT_FULL, effectively skipping the use of TPM2 when inside one. */
|
||||
|
||||
try_tpm2 = tpm2_support() == TPM2_SUPPORT_FULL;
|
||||
try_tpm2 = tpm2_is_fully_supported();
|
||||
if (!try_tpm2)
|
||||
log_debug("System lacks TPM2 support or running in a container, not attempting to use TPM2.");
|
||||
} else
|
||||
|
@ -1582,14 +1582,12 @@ int ipc_encrypt_credential(const char *name, usec_t timestamp, usec_t not_after,
|
|||
return log_error_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to encrypt: %s", error_id);
|
||||
}
|
||||
|
||||
r = sd_json_dispatch(
|
||||
reply,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "blob", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, PTR_TO_SIZE(ret), SD_JSON_MANDATORY },
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "blob", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, 0, SD_JSON_MANDATORY },
|
||||
{},
|
||||
},
|
||||
SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS,
|
||||
/* userdata= */ NULL);
|
||||
};
|
||||
|
||||
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -1649,14 +1647,12 @@ int ipc_decrypt_credential(const char *validate_name, usec_t validate_timestamp,
|
|||
return log_error_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to decrypt: %s", error_id);
|
||||
}
|
||||
|
||||
r = sd_json_dispatch(
|
||||
reply,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "data", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, PTR_TO_SIZE(ret), SD_JSON_MANDATORY },
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "data", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, 0, SD_JSON_MANDATORY },
|
||||
{},
|
||||
},
|
||||
SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS,
|
||||
/* userdata= */ NULL);
|
||||
};
|
||||
|
||||
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -170,6 +170,7 @@ shared_sources = files(
|
|||
'tpm2-util.c',
|
||||
'tpm2-event-log.c',
|
||||
'udev-util.c',
|
||||
'unit-file.c',
|
||||
'user-record-nss.c',
|
||||
'user-record-show.c',
|
||||
'user-record.c',
|
||||
|
|
|
@ -250,6 +250,18 @@ int nsresource_add_cgroup(int userns_fd, int cgroup_fd) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
typedef struct InterfaceParams {
|
||||
char *host_interface_name;
|
||||
char *namespace_interface_name;
|
||||
} InterfaceParams;
|
||||
|
||||
static void interface_params_done(InterfaceParams *p) {
|
||||
assert(p);
|
||||
|
||||
free(p->host_interface_name);
|
||||
free(p->namespace_interface_name);
|
||||
}
|
||||
|
||||
int nsresource_add_netif(
|
||||
int userns_fd,
|
||||
int netns_fd,
|
||||
|
@ -313,20 +325,20 @@ int nsresource_add_netif(
|
|||
if (error_id)
|
||||
return log_debug_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to add network to user namespace: %s", error_id);
|
||||
|
||||
_cleanup_free_ char *host_interface_name = NULL, *namespace_interface_name = NULL;
|
||||
r = sd_json_dispatch(
|
||||
reply,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "hostInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, PTR_TO_SIZE(&host_interface_name) },
|
||||
{ "namespaceInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, PTR_TO_SIZE(&namespace_interface_name) },
|
||||
},
|
||||
SD_JSON_ALLOW_EXTENSIONS,
|
||||
/* userdata= */ NULL);
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "hostInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, host_interface_name), 0 },
|
||||
{ "namespaceInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, namespace_interface_name), 0 },
|
||||
};
|
||||
|
||||
_cleanup_(interface_params_done) InterfaceParams p = {};
|
||||
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_host_ifname)
|
||||
*ret_host_ifname = TAKE_PTR(host_interface_name);
|
||||
*ret_host_ifname = TAKE_PTR(p.host_interface_name);
|
||||
if (ret_namespace_ifname)
|
||||
*ret_namespace_ifname = TAKE_PTR(namespace_interface_name);
|
||||
*ret_namespace_ifname = TAKE_PTR(p.namespace_interface_name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -281,6 +281,44 @@ static inline int run_test_table(void) {
|
|||
} \
|
||||
})
|
||||
|
||||
#define ASSERT_OK_ZERO_ERRNO(expr) \
|
||||
({ \
|
||||
typeof(expr) _result = (expr); \
|
||||
if (_result < 0) { \
|
||||
log_error_errno(errno, "%s:%i: Assertion failed: expected \"%s\" to succeed but got the following error: %m", \
|
||||
PROJECT_FILE, __LINE__, #expr); \
|
||||
abort(); \
|
||||
} \
|
||||
if (_result != 0) { \
|
||||
char _sexpr[DECIMAL_STR_MAX(typeof(expr))]; \
|
||||
xsprintf(_sexpr, DECIMAL_STR_FMT(_result), _result); \
|
||||
log_error("%s:%i: Assertion failed: expected \"%s\" to be zero, but it is %s.", \
|
||||
PROJECT_FILE, __LINE__, #expr, _sexpr); \
|
||||
abort(); \
|
||||
} \
|
||||
})
|
||||
|
||||
#define ASSERT_OK_EQ_ERRNO(expr1, expr2) \
|
||||
({ \
|
||||
typeof(expr1) _expr1 = (expr1); \
|
||||
typeof(expr2) _expr2 = (expr2); \
|
||||
if (_expr1 < 0) { \
|
||||
log_error_errno(errno, "%s:%i: Assertion failed: expected \"%s\" to succeed but got the following error: %m", \
|
||||
PROJECT_FILE, __LINE__, #expr1); \
|
||||
abort(); \
|
||||
} \
|
||||
if (_expr1 != _expr2) { \
|
||||
char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
|
||||
char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
|
||||
xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
|
||||
xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
|
||||
log_error("%s:%i: Assertion failed: expected \"%s == %s\", but %s != %s", \
|
||||
PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
|
||||
abort(); \
|
||||
} \
|
||||
})
|
||||
|
||||
|
||||
#define ASSERT_FAIL(expr) \
|
||||
({ \
|
||||
typeof(expr) _result = (expr); \
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <sys/file.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "ansi-color.h"
|
||||
#include "constants.h"
|
||||
#include "creds-util.h"
|
||||
#include "cryptsetup-util.h"
|
||||
|
@ -7872,11 +7873,11 @@ int tpm2_sym_mode_from_string(const char *mode) {
|
|||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown symmetric mode name '%s'", mode);
|
||||
}
|
||||
|
||||
Tpm2Support tpm2_support(void) {
|
||||
Tpm2Support tpm2_support_full(Tpm2Support mask) {
|
||||
Tpm2Support support = TPM2_SUPPORT_NONE;
|
||||
int r;
|
||||
|
||||
if (detect_container() <= 0) {
|
||||
if (((mask & (TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_DRIVER)) != 0) && detect_container() <= 0) {
|
||||
/* Check if there's a /dev/tpmrm* device via sysfs. If we run in a container we likely just
|
||||
* got the host sysfs mounted. Since devices are generally not virtualized for containers,
|
||||
* let's assume containers never have a TPM, at least for now. */
|
||||
|
@ -7893,18 +7894,24 @@ Tpm2Support tpm2_support(void) {
|
|||
support |= TPM2_SUPPORT_SUBSYSTEM;
|
||||
}
|
||||
|
||||
if (efi_has_tpm2())
|
||||
if (FLAGS_SET(mask, TPM2_SUPPORT_FIRMWARE) && efi_has_tpm2())
|
||||
support |= TPM2_SUPPORT_FIRMWARE;
|
||||
|
||||
#if HAVE_TPM2
|
||||
support |= TPM2_SUPPORT_SYSTEM;
|
||||
|
||||
if (FLAGS_SET(mask, TPM2_SUPPORT_LIBRARIES)) {
|
||||
r = dlopen_tpm2();
|
||||
if (r >= 0)
|
||||
support |= TPM2_SUPPORT_LIBRARIES;
|
||||
}
|
||||
#endif
|
||||
|
||||
return support;
|
||||
return support & mask;
|
||||
}
|
||||
|
||||
static void print_field(const char *s, bool supported) {
|
||||
printf("%s%s%s%s\n", supported ? ansi_green() : ansi_red(), plus_minus(supported), s, ansi_normal());
|
||||
}
|
||||
|
||||
int verb_has_tpm2_generic(bool quiet) {
|
||||
|
@ -7914,22 +7921,17 @@ int verb_has_tpm2_generic(bool quiet) {
|
|||
|
||||
if (!quiet) {
|
||||
if (s == TPM2_SUPPORT_FULL)
|
||||
puts("yes");
|
||||
printf("%syes%s\n", ansi_green(), ansi_normal());
|
||||
else if (s == TPM2_SUPPORT_NONE)
|
||||
puts("no");
|
||||
printf("%sno%s\n", ansi_red(), ansi_normal());
|
||||
else
|
||||
puts("partial");
|
||||
printf("%spartial%s\n", ansi_yellow(), ansi_normal());
|
||||
|
||||
printf("%sfirmware\n"
|
||||
"%sdriver\n"
|
||||
"%ssystem\n"
|
||||
"%ssubsystem\n"
|
||||
"%slibraries\n",
|
||||
plus_minus(s & TPM2_SUPPORT_FIRMWARE),
|
||||
plus_minus(s & TPM2_SUPPORT_DRIVER),
|
||||
plus_minus(s & TPM2_SUPPORT_SYSTEM),
|
||||
plus_minus(s & TPM2_SUPPORT_SUBSYSTEM),
|
||||
plus_minus(s & TPM2_SUPPORT_LIBRARIES));
|
||||
print_field("firmware", FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE));
|
||||
print_field("driver", FLAGS_SET(s, TPM2_SUPPORT_DRIVER));
|
||||
print_field("system", FLAGS_SET(s, TPM2_SUPPORT_SYSTEM));
|
||||
print_field("subsystem", FLAGS_SET(s, TPM2_SUPPORT_SUBSYSTEM));
|
||||
print_field("libraries", FLAGS_SET(s, TPM2_SUPPORT_LIBRARIES));
|
||||
}
|
||||
|
||||
/* Return inverted bit flags. So that TPM2_SUPPORT_FULL becomes EXIT_SUCCESS and the other values
|
||||
|
|
|
@ -450,8 +450,8 @@ typedef struct {
|
|||
} systemd_tpm2_plugin_params;
|
||||
|
||||
typedef enum Tpm2Support {
|
||||
/* NOTE! The systemd-creds tool returns these flags 1:1 as exit status. Hence these flags are pretty
|
||||
* much ABI! Hence, be extra careful when changing/extending these definitions. */
|
||||
/* NOTE! The systemd-analyze has-tpm2 command returns these flags 1:1 as exit status. Hence these
|
||||
* flags are pretty much ABI! Hence, be extra careful when changing/extending these definitions. */
|
||||
TPM2_SUPPORT_NONE = 0, /* no support */
|
||||
TPM2_SUPPORT_FIRMWARE = 1 << 0, /* firmware reports TPM2 was used */
|
||||
TPM2_SUPPORT_DRIVER = 1 << 1, /* the kernel has a driver loaded for it */
|
||||
|
@ -461,7 +461,13 @@ typedef enum Tpm2Support {
|
|||
TPM2_SUPPORT_FULL = TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER|TPM2_SUPPORT_SYSTEM|TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_LIBRARIES,
|
||||
} Tpm2Support;
|
||||
|
||||
Tpm2Support tpm2_support(void);
|
||||
Tpm2Support tpm2_support_full(Tpm2Support mask);
|
||||
static inline Tpm2Support tpm2_support(void) {
|
||||
return tpm2_support_full(TPM2_SUPPORT_FULL);
|
||||
}
|
||||
static inline bool tpm2_is_fully_supported(void) {
|
||||
return tpm2_support() == TPM2_SUPPORT_FULL;
|
||||
}
|
||||
|
||||
int verb_has_tpm2_generic(bool quiet);
|
||||
|
||||
|
|
|
@ -16,25 +16,6 @@
|
|||
#include "strv.h"
|
||||
#include "unit-file.h"
|
||||
|
||||
bool unit_type_may_alias(UnitType type) {
|
||||
return IN_SET(type,
|
||||
UNIT_SERVICE,
|
||||
UNIT_SOCKET,
|
||||
UNIT_TARGET,
|
||||
UNIT_DEVICE,
|
||||
UNIT_TIMER,
|
||||
UNIT_PATH);
|
||||
}
|
||||
|
||||
bool unit_type_may_template(UnitType type) {
|
||||
return IN_SET(type,
|
||||
UNIT_SERVICE,
|
||||
UNIT_SOCKET,
|
||||
UNIT_TARGET,
|
||||
UNIT_TIMER,
|
||||
UNIT_PATH);
|
||||
}
|
||||
|
||||
int unit_symlink_name_compatible(const char *symlink, const char *target, bool instance_propagation) {
|
||||
_cleanup_free_ char *template = NULL;
|
||||
int r, un_type1, un_type2;
|
|
@ -28,8 +28,24 @@ enum UnitFileState {
|
|||
_UNIT_FILE_STATE_INVALID = -EINVAL,
|
||||
};
|
||||
|
||||
bool unit_type_may_alias(UnitType type) _const_;
|
||||
bool unit_type_may_template(UnitType type) _const_;
|
||||
static inline bool unit_type_may_alias(UnitType type) {
|
||||
return IN_SET(type,
|
||||
UNIT_SERVICE,
|
||||
UNIT_SOCKET,
|
||||
UNIT_TARGET,
|
||||
UNIT_DEVICE,
|
||||
UNIT_TIMER,
|
||||
UNIT_PATH);
|
||||
}
|
||||
|
||||
static inline bool unit_type_may_template(UnitType type) {
|
||||
return IN_SET(type,
|
||||
UNIT_SERVICE,
|
||||
UNIT_SOCKET,
|
||||
UNIT_TARGET,
|
||||
UNIT_TIMER,
|
||||
UNIT_PATH);
|
||||
}
|
||||
|
||||
int unit_symlink_name_compatible(const char *symlink, const char *target, bool instance_propagation);
|
||||
int unit_validate_alias_symlink_or_warn(int log_level, const char *filename, const char *target);
|
|
@ -161,12 +161,12 @@ static int process_machine(const char *machine, const char *port) {
|
|||
|
||||
uint32_t cid = VMADDR_CID_ANY;
|
||||
|
||||
const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "vSockCid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, PTR_TO_SIZE(&cid), 0 },
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "vSockCid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, 0, 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
r = sd_json_dispatch(result, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, NULL);
|
||||
r = sd_json_dispatch(result, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &cid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse Varlink reply: %m");
|
||||
|
||||
|
|
|
@ -123,8 +123,8 @@ enum {
|
|||
_SD_PATH_MAX
|
||||
};
|
||||
|
||||
int sd_path_lookup(uint64_t type, const char *suffix, char **path);
|
||||
int sd_path_lookup_strv(uint64_t type, const char *suffix, char ***paths);
|
||||
int sd_path_lookup(uint64_t type, const char *suffix, char **ret);
|
||||
int sd_path_lookup_strv(uint64_t type, const char *suffix, char ***ret);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
|
|
|
@ -321,12 +321,27 @@ static int list_targets(sd_bus *bus) {
|
|||
return table_print_with_pager(table, SD_JSON_FORMAT_OFF, arg_pager_flags, arg_legend);
|
||||
}
|
||||
|
||||
typedef struct DescribeParams {
|
||||
Version v;
|
||||
sd_json_variant *contents_json;
|
||||
bool newest;
|
||||
bool available;
|
||||
bool installed;
|
||||
bool obsolete;
|
||||
bool protected;
|
||||
bool incomplete;
|
||||
} DescribeParams;
|
||||
|
||||
static void describe_params_done(DescribeParams *p) {
|
||||
assert(p);
|
||||
|
||||
version_done(&p->v);
|
||||
sd_json_variant_unref(p->contents_json);
|
||||
}
|
||||
|
||||
static int parse_describe(sd_bus_message *reply, Version *ret) {
|
||||
Version v = {};
|
||||
char *version_json = NULL;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *json = NULL, *contents_json = NULL;
|
||||
bool newest = false, available = false, installed = false, obsolete = false, protected = false,
|
||||
incomplete = false;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *json = NULL;
|
||||
int r;
|
||||
|
||||
assert(reply);
|
||||
|
@ -342,36 +357,37 @@ static int parse_describe(sd_bus_message *reply, Version *ret) {
|
|||
|
||||
assert(sd_json_variant_is_object(json));
|
||||
|
||||
r = sd_json_dispatch(json,
|
||||
(const sd_json_dispatch_field[]) {
|
||||
{ "version", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, PTR_TO_SIZE(&v.version), 0 },
|
||||
{ "newest", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&newest), 0 },
|
||||
{ "available", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&available), 0 },
|
||||
{ "installed", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&installed), 0 },
|
||||
{ "obsolete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&obsolete), 0 },
|
||||
{ "protected", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&protected), 0 },
|
||||
{ "incomplete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&incomplete), 0 },
|
||||
{ "changelog_urls", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, PTR_TO_SIZE(&v.changelog), 0 },
|
||||
{ "contents", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&contents_json), 0 },
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "version", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DescribeParams, v.version), 0 },
|
||||
{ "newest", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, newest), 0 },
|
||||
{ "available", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, available), 0 },
|
||||
{ "installed", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, installed), 0 },
|
||||
{ "obsolete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, obsolete), 0 },
|
||||
{ "protected", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, protected), 0 },
|
||||
{ "incomplete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, incomplete), 0 },
|
||||
{ "changelog_urls", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(DescribeParams, v.changelog), 0 },
|
||||
{ "contents", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(DescribeParams, contents_json), 0 },
|
||||
{},
|
||||
},
|
||||
SD_JSON_ALLOW_EXTENSIONS,
|
||||
/* userdata= */ NULL);
|
||||
};
|
||||
|
||||
_cleanup_(describe_params_done) DescribeParams p = {};
|
||||
|
||||
r = sd_json_dispatch(json, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse JSON: %m");
|
||||
|
||||
SET_FLAG(v.flags, UPDATE_NEWEST, newest);
|
||||
SET_FLAG(v.flags, UPDATE_AVAILABLE, available);
|
||||
SET_FLAG(v.flags, UPDATE_INSTALLED, installed);
|
||||
SET_FLAG(v.flags, UPDATE_OBSOLETE, obsolete);
|
||||
SET_FLAG(v.flags, UPDATE_PROTECTED, protected);
|
||||
SET_FLAG(v.flags, UPDATE_INCOMPLETE, incomplete);
|
||||
SET_FLAG(p.v.flags, UPDATE_NEWEST, p.newest);
|
||||
SET_FLAG(p.v.flags, UPDATE_AVAILABLE, p.available);
|
||||
SET_FLAG(p.v.flags, UPDATE_INSTALLED, p.installed);
|
||||
SET_FLAG(p.v.flags, UPDATE_OBSOLETE, p.obsolete);
|
||||
SET_FLAG(p.v.flags, UPDATE_PROTECTED, p.protected);
|
||||
SET_FLAG(p.v.flags, UPDATE_INCOMPLETE, p.incomplete);
|
||||
|
||||
r = sd_json_variant_format(contents_json, 0, &v.contents_json);
|
||||
r = sd_json_variant_format(p.contents_json, 0, &p.v.contents_json);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format JSON for contents: %m");
|
||||
|
||||
*ret = TAKE_STRUCT(v);
|
||||
*ret = TAKE_STRUCT(p.v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1141,6 +1141,18 @@ TEST(ASSERT) {
|
|||
ASSERT_SIGNAL(ASSERT_OK_ERRNO(-1), SIGABRT);
|
||||
ASSERT_SIGNAL(ASSERT_OK_ERRNO(-ENOANO), SIGABRT);
|
||||
|
||||
ASSERT_OK_ZERO_ERRNO(0);
|
||||
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(1), SIGABRT);
|
||||
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(255), SIGABRT);
|
||||
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(-1), SIGABRT);
|
||||
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(-ENOANO), SIGABRT);
|
||||
|
||||
ASSERT_OK_EQ_ERRNO(0, 0);
|
||||
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(1, 0), SIGABRT);
|
||||
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(255, 5), SIGABRT);
|
||||
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(-1, 0), SIGABRT);
|
||||
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(-ENOANO, 0), SIGABRT);
|
||||
|
||||
ASSERT_FAIL(-ENOENT);
|
||||
ASSERT_FAIL(-EPERM);
|
||||
ASSERT_SIGNAL(ASSERT_FAIL(0), SIGABRT);
|
||||
|
|
|
@ -54,46 +54,51 @@ static void test_pid_get_comm_one(pid_t pid) {
|
|||
xsprintf(path, "/proc/"PID_FMT"/comm", pid);
|
||||
|
||||
if (stat(path, &st) == 0) {
|
||||
assert_se(pid_get_comm(pid, &a) >= 0);
|
||||
ASSERT_OK(pid_get_comm(pid, &a));
|
||||
log_info("PID"PID_FMT" comm: '%s'", pid, a);
|
||||
} else
|
||||
log_warning("%s not exist.", path);
|
||||
|
||||
assert_se(pid_get_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c));
|
||||
log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
|
||||
|
||||
assert_se(pid_get_cmdline(pid, 8, 0, &d) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(pid, 8, 0, &d));
|
||||
log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d);
|
||||
|
||||
free(d);
|
||||
assert_se(pid_get_cmdline(pid, 1, 0, &d) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(pid, 1, 0, &d));
|
||||
log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d);
|
||||
|
||||
r = get_process_ppid(pid, &e);
|
||||
assert_se(pid == 1 ? r == -EADDRNOTAVAIL : r >= 0);
|
||||
if (pid == 1)
|
||||
ASSERT_ERROR(r, EADDRNOTAVAIL);
|
||||
else
|
||||
ASSERT_OK(r);
|
||||
if (r >= 0) {
|
||||
log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e);
|
||||
assert_se(e > 0);
|
||||
ASSERT_GT(e, 0);
|
||||
}
|
||||
|
||||
assert_se(pid_is_kernel_thread(pid) == 0 || pid != 1);
|
||||
ASSERT_TRUE(pid_is_kernel_thread(pid) == 0 || pid != 1);
|
||||
|
||||
r = get_process_exe(pid, &f);
|
||||
assert_se(r >= 0 || r == -EACCES);
|
||||
if (r != -EACCES)
|
||||
ASSERT_OK(r);
|
||||
log_info("PID"PID_FMT" exe: '%s'", pid, strna(f));
|
||||
|
||||
assert_se(pid_get_uid(pid, &u) == 0);
|
||||
ASSERT_OK_ZERO(pid_get_uid(pid, &u));
|
||||
log_info("PID"PID_FMT" UID: "UID_FMT, pid, u);
|
||||
|
||||
assert_se(get_process_gid(pid, &g) == 0);
|
||||
ASSERT_OK_ZERO(get_process_gid(pid, &g));
|
||||
log_info("PID"PID_FMT" GID: "GID_FMT, pid, g);
|
||||
|
||||
r = get_process_environ(pid, &env);
|
||||
assert_se(r >= 0 || r == -EACCES);
|
||||
if (r != -EACCES)
|
||||
ASSERT_OK(r);
|
||||
log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno);
|
||||
|
||||
if (!detect_container())
|
||||
assert_se(get_ctty_devnr(pid, &h) == -ENXIO || pid != 1);
|
||||
if (!detect_container() && pid == 1)
|
||||
ASSERT_ERROR(get_ctty_devnr(pid, &h), ENXIO);
|
||||
|
||||
(void) getenv_for_pid(pid, "PATH", &i);
|
||||
log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i));
|
||||
|
@ -136,14 +141,14 @@ static void test_pid_get_cmdline_one(pid_t pid) {
|
|||
|
||||
r = pid_get_cmdline_strv(pid, 0, &strv_a);
|
||||
if (r >= 0)
|
||||
assert_se(joined = strv_join(strv_a, "\", \""));
|
||||
ASSERT_NOT_NULL(joined = strv_join(strv_a, "\", \""));
|
||||
log_info(" \"%s\"", r >= 0 ? joined : errno_to_name(r));
|
||||
|
||||
joined = mfree(joined);
|
||||
|
||||
r = pid_get_cmdline_strv(pid, PROCESS_CMDLINE_COMM_FALLBACK, &strv_b);
|
||||
if (r >= 0)
|
||||
assert_se(joined = strv_join(strv_b, "\", \""));
|
||||
ASSERT_NOT_NULL(joined = strv_join(strv_b, "\", \""));
|
||||
log_info(" \"%s\"", r >= 0 ? joined : errno_to_name(r));
|
||||
}
|
||||
|
||||
|
@ -151,13 +156,13 @@ TEST(pid_get_cmdline) {
|
|||
_cleanup_closedir_ DIR *d = NULL;
|
||||
int r;
|
||||
|
||||
assert_se(proc_dir_open(&d) >= 0);
|
||||
ASSERT_OK(proc_dir_open(&d));
|
||||
|
||||
for (;;) {
|
||||
pid_t pid;
|
||||
|
||||
r = proc_dir_read(d, &pid);
|
||||
assert_se(r >= 0);
|
||||
ASSERT_OK(r);
|
||||
|
||||
if (r == 0) /* EOF */
|
||||
break;
|
||||
|
@ -171,8 +176,8 @@ static void test_pid_get_comm_escape_one(const char *input, const char *output)
|
|||
|
||||
log_debug("input: <%s> — output: <%s>", input, output);
|
||||
|
||||
assert_se(prctl(PR_SET_NAME, input) >= 0);
|
||||
assert_se(pid_get_comm(0, &n) >= 0);
|
||||
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, input));
|
||||
ASSERT_OK(pid_get_comm(0, &n));
|
||||
|
||||
log_debug("got: <%s>", n);
|
||||
|
||||
|
@ -182,7 +187,7 @@ static void test_pid_get_comm_escape_one(const char *input, const char *output)
|
|||
TEST(pid_get_comm_escape) {
|
||||
_cleanup_free_ char *saved = NULL;
|
||||
|
||||
assert_se(pid_get_comm(0, &saved) >= 0);
|
||||
ASSERT_OK(pid_get_comm(0, &saved));
|
||||
|
||||
test_pid_get_comm_escape_one("", "");
|
||||
test_pid_get_comm_escape_one("foo", "foo");
|
||||
|
@ -195,62 +200,62 @@ TEST(pid_get_comm_escape) {
|
|||
test_pid_get_comm_escape_one("xxxxäöüß", "xxxx\\303\\244\\303\\266\\303\\274\\303\\237");
|
||||
test_pid_get_comm_escape_one("xxxxxäöüß", "xxxxx\\303\\244\\303\\266\\303\\274\\303\\237");
|
||||
|
||||
assert_se(prctl(PR_SET_NAME, saved) >= 0);
|
||||
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, saved));
|
||||
}
|
||||
|
||||
TEST(pid_is_unwaited) {
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
assert_se(pid >= 0);
|
||||
ASSERT_OK_ERRNO(pid);
|
||||
if (pid == 0) {
|
||||
_exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
int status;
|
||||
|
||||
assert_se(waitpid(pid, &status, 0) == pid);
|
||||
assert_se(pid_is_unwaited(pid) == 0);
|
||||
ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
|
||||
ASSERT_OK_ZERO(pid_is_unwaited(pid));
|
||||
}
|
||||
assert_se(pid_is_unwaited(getpid_cached()) > 0);
|
||||
assert_se(pid_is_unwaited(-1) < 0);
|
||||
ASSERT_OK_POSITIVE(pid_is_unwaited(getpid_cached()));
|
||||
ASSERT_FAIL(pid_is_unwaited(-1));
|
||||
}
|
||||
|
||||
TEST(pid_is_alive) {
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
assert_se(pid >= 0);
|
||||
ASSERT_OK_ERRNO(pid);
|
||||
if (pid == 0) {
|
||||
_exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
int status;
|
||||
|
||||
assert_se(waitpid(pid, &status, 0) == pid);
|
||||
assert_se(pid_is_alive(pid) == 0);
|
||||
ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
|
||||
ASSERT_OK_ZERO(pid_is_alive(pid));
|
||||
}
|
||||
assert_se(pid_is_alive(getpid_cached()) > 0);
|
||||
assert_se(pid_is_alive(-1) < 0);
|
||||
ASSERT_OK_POSITIVE(pid_is_alive(getpid_cached()));
|
||||
ASSERT_FAIL(pid_is_alive(-1));
|
||||
}
|
||||
|
||||
TEST(personality) {
|
||||
assert_se(personality_to_string(PER_LINUX));
|
||||
assert_se(!personality_to_string(PERSONALITY_INVALID));
|
||||
ASSERT_NOT_NULL(personality_to_string(PER_LINUX));
|
||||
ASSERT_NULL(personality_to_string(PERSONALITY_INVALID));
|
||||
|
||||
ASSERT_STREQ(personality_to_string(PER_LINUX), architecture_to_string(native_architecture()));
|
||||
|
||||
assert_se(personality_from_string(personality_to_string(PER_LINUX)) == PER_LINUX);
|
||||
assert_se(personality_from_string(architecture_to_string(native_architecture())) == PER_LINUX);
|
||||
ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX)), (unsigned long) PER_LINUX);
|
||||
ASSERT_EQ(personality_from_string(architecture_to_string(native_architecture())), (unsigned long) PER_LINUX);
|
||||
|
||||
#ifdef __x86_64__
|
||||
ASSERT_STREQ(personality_to_string(PER_LINUX), "x86-64");
|
||||
ASSERT_STREQ(personality_to_string(PER_LINUX32), "x86");
|
||||
|
||||
assert_se(personality_from_string("x86-64") == PER_LINUX);
|
||||
assert_se(personality_from_string("x86") == PER_LINUX32);
|
||||
assert_se(personality_from_string("ia64") == PERSONALITY_INVALID);
|
||||
assert_se(personality_from_string(NULL) == PERSONALITY_INVALID);
|
||||
ASSERT_EQ(personality_from_string("x86-64"), (unsigned long) PER_LINUX);
|
||||
ASSERT_EQ(personality_from_string("x86"), (unsigned long) PER_LINUX32);
|
||||
ASSERT_EQ(personality_from_string("ia64"), PERSONALITY_INVALID);
|
||||
ASSERT_EQ(personality_from_string(NULL), PERSONALITY_INVALID);
|
||||
|
||||
assert_se(personality_from_string(personality_to_string(PER_LINUX32)) == PER_LINUX32);
|
||||
ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX32)), (unsigned long) PER_LINUX32);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -288,30 +293,31 @@ TEST(pid_get_cmdline_harder) {
|
|||
|
||||
(void) wait_for_terminate(pid, &si);
|
||||
|
||||
assert_se(si.si_code == CLD_EXITED);
|
||||
assert_se(si.si_status == 0);
|
||||
ASSERT_EQ(si.si_code, CLD_EXITED);
|
||||
ASSERT_OK_ZERO(si.si_status);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
assert_se(pid == 0);
|
||||
ASSERT_OK_ZERO(pid);
|
||||
|
||||
r = detach_mount_namespace();
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "detach mount namespace failed: %m");
|
||||
assert_se(ERRNO_IS_PRIVILEGE(r));
|
||||
if (!ERRNO_IS_PRIVILEGE(r))
|
||||
ASSERT_OK(r);
|
||||
return;
|
||||
}
|
||||
|
||||
fd = mkostemp(path, O_CLOEXEC);
|
||||
assert_se(fd >= 0);
|
||||
ASSERT_OK_ERRNO(fd);
|
||||
|
||||
/* Note that we don't unmount the following bind-mount at the end of the test because the kernel
|
||||
* will clear up its /proc/PID/ hierarchy automatically as soon as the test stops. */
|
||||
if (mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) < 0) {
|
||||
/* This happens under selinux… Abort the test in this case. */
|
||||
log_warning_errno(errno, "mount(..., \"/proc/self/cmdline\", \"bind\", ...) failed: %m");
|
||||
assert_se(IN_SET(errno, EPERM, EACCES));
|
||||
ASSERT_TRUE(IN_SET(errno, EPERM, EACCES));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -320,197 +326,197 @@ TEST(pid_get_cmdline_harder) {
|
|||
if (setrlimit(RLIMIT_STACK, &RLIMIT_MAKE_CONST(RLIM_INFINITY)) < 0)
|
||||
log_warning("Testing without RLIMIT_STACK=infinity");
|
||||
|
||||
assert_se(unlink(path) >= 0);
|
||||
ASSERT_OK_ERRNO(unlink(path));
|
||||
|
||||
assert_se(prctl(PR_SET_NAME, "testa") >= 0);
|
||||
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "testa"));
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) == -ENOENT);
|
||||
ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "[testa]");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_QUOTE, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_QUOTE, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "\"[testa]\""); /* quoting is enabled here */
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 0, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 0, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
ASSERT_STREQ(line, "…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
ASSERT_STREQ(line, "[…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
ASSERT_STREQ(line, "[t…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
ASSERT_STREQ(line, "[te…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
ASSERT_STREQ(line, "[tes…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
ASSERT_STREQ(line, "[test…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
ASSERT_STREQ(line, "[testa]");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
ASSERT_STREQ(line, "[testa]");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
|
||||
assert_se(strv_equal(args, STRV_MAKE("[testa]")));
|
||||
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
|
||||
ASSERT_TRUE(strv_equal(args, STRV_MAKE("[testa]")));
|
||||
args = strv_free(args);
|
||||
|
||||
/* Test with multiple arguments that don't require quoting */
|
||||
|
||||
assert_se(write(fd, "foo\0bar", 8) == 8);
|
||||
ASSERT_OK_EQ_ERRNO(write(fd, "foo\0bar", 8), 8);
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo bar");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
ASSERT_STREQ(line, "foo bar");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
|
||||
assert_se(strv_equal(args, STRV_MAKE("foo", "bar")));
|
||||
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
|
||||
ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar")));
|
||||
args = strv_free(args);
|
||||
|
||||
assert_se(write(fd, "quux", 4) == 4);
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) >= 0);
|
||||
ASSERT_OK_EQ_ERRNO(write(fd, "quux", 4), 4);
|
||||
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo bar quux");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo bar quux");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "f…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "fo…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo …");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo b…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo ba…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo bar…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 9, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 9, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo bar …");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo bar q…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo bar qu…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo bar quux");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 13, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 13, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo bar quux");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 14, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 14, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo bar quux");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "foo bar quux");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
|
||||
assert_se(strv_equal(args, STRV_MAKE("foo", "bar", "quux")));
|
||||
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
|
||||
ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar", "quux")));
|
||||
args = strv_free(args);
|
||||
|
||||
assert_se(ftruncate(fd, 0) >= 0);
|
||||
assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0);
|
||||
ASSERT_OK_ERRNO(ftruncate(fd, 0));
|
||||
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "aaaa bbbb cccc"));
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) == -ENOENT);
|
||||
ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "[aaaa bbbb cccc]");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "[aaaa bbb…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "[aaaa bbbb…");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
|
||||
log_debug("'%s'", line);
|
||||
ASSERT_STREQ(line, "[aaaa bbbb …");
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
|
||||
assert_se(strv_equal(args, STRV_MAKE("[aaaa bbbb cccc]")));
|
||||
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
|
||||
ASSERT_TRUE(strv_equal(args, STRV_MAKE("[aaaa bbbb cccc]")));
|
||||
args = strv_free(args);
|
||||
|
||||
/* Test with multiple arguments that do require quoting */
|
||||
|
@ -520,24 +526,24 @@ TEST(pid_get_cmdline_harder) {
|
|||
#define EXPECT1p "foo $'\\'bar\\'' $'\"bar$\"' $'x y z' $'!``'"
|
||||
#define EXPECT1v STRV_MAKE("foo", "'bar'", "\"bar$\"", "x y z", "!``")
|
||||
|
||||
assert_se(lseek(fd, SEEK_SET, 0) == 0);
|
||||
assert_se(write(fd, CMDLINE1, sizeof CMDLINE1) == sizeof CMDLINE1);
|
||||
assert_se(ftruncate(fd, sizeof CMDLINE1) == 0);
|
||||
ASSERT_OK_ZERO_ERRNO(lseek(fd, SEEK_SET, 0));
|
||||
ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE1, sizeof(CMDLINE1)), (ssize_t) sizeof(CMDLINE1));
|
||||
ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof(CMDLINE1)));
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
|
||||
log_debug("got: ==%s==", line);
|
||||
log_debug("exp: ==%s==", EXPECT1);
|
||||
ASSERT_STREQ(line, EXPECT1);
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
|
||||
log_debug("got: ==%s==", line);
|
||||
log_debug("exp: ==%s==", EXPECT1p);
|
||||
ASSERT_STREQ(line, EXPECT1p);
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline_strv(0, 0, &args) >= 0);
|
||||
assert_se(strv_equal(args, EXPECT1v));
|
||||
ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
|
||||
ASSERT_TRUE(strv_equal(args, EXPECT1v));
|
||||
args = strv_free(args);
|
||||
|
||||
#define CMDLINE2 "foo\0\1\2\3\0\0"
|
||||
|
@ -545,24 +551,24 @@ TEST(pid_get_cmdline_harder) {
|
|||
#define EXPECT2p "foo $'\\001\\002\\003'"
|
||||
#define EXPECT2v STRV_MAKE("foo", "\1\2\3")
|
||||
|
||||
assert_se(lseek(fd, SEEK_SET, 0) == 0);
|
||||
assert_se(write(fd, CMDLINE2, sizeof CMDLINE2) == sizeof CMDLINE2);
|
||||
assert_se(ftruncate(fd, sizeof CMDLINE2) == 0);
|
||||
ASSERT_OK_ZERO_ERRNO(lseek(fd, SEEK_SET, 0));
|
||||
ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE2, sizeof(CMDLINE2)), (ssize_t) sizeof(CMDLINE2));
|
||||
ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof CMDLINE2));
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
|
||||
log_debug("got: ==%s==", line);
|
||||
log_debug("exp: ==%s==", EXPECT2);
|
||||
ASSERT_STREQ(line, EXPECT2);
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
|
||||
log_debug("got: ==%s==", line);
|
||||
log_debug("exp: ==%s==", EXPECT2p);
|
||||
ASSERT_STREQ(line, EXPECT2p);
|
||||
line = mfree(line);
|
||||
|
||||
assert_se(pid_get_cmdline_strv(0, 0, &args) >= 0);
|
||||
assert_se(strv_equal(args, EXPECT2v));
|
||||
ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
|
||||
ASSERT_TRUE(strv_equal(args, EXPECT2v));
|
||||
args = strv_free(args);
|
||||
|
||||
safe_close(fd);
|
||||
|
@ -577,10 +583,11 @@ TEST(getpid_cached) {
|
|||
b = getpid_cached();
|
||||
c = getpid();
|
||||
|
||||
assert_se(a == b && a == c);
|
||||
ASSERT_EQ(a, b);
|
||||
ASSERT_EQ(a, c);
|
||||
|
||||
child = fork();
|
||||
assert_se(child >= 0);
|
||||
ASSERT_OK_ERRNO(child);
|
||||
|
||||
if (child == 0) {
|
||||
/* In child */
|
||||
|
@ -588,7 +595,8 @@ TEST(getpid_cached) {
|
|||
b = getpid_cached();
|
||||
c = getpid();
|
||||
|
||||
assert_se(a == b && a == c);
|
||||
ASSERT_EQ(a, b);
|
||||
ASSERT_EQ(a, c);
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
@ -596,11 +604,13 @@ TEST(getpid_cached) {
|
|||
e = getpid_cached();
|
||||
f = getpid();
|
||||
|
||||
assert_se(a == d && a == e && a == f);
|
||||
ASSERT_EQ(a, d);
|
||||
ASSERT_EQ(a, e);
|
||||
ASSERT_EQ(a, f);
|
||||
|
||||
assert_se(wait_for_terminate(child, &si) >= 0);
|
||||
assert_se(si.si_status == 0);
|
||||
assert_se(si.si_code == CLD_EXITED);
|
||||
ASSERT_OK(wait_for_terminate(child, &si));
|
||||
ASSERT_EQ(si.si_status, 0);
|
||||
ASSERT_EQ(si.si_code, CLD_EXITED);
|
||||
}
|
||||
|
||||
TEST(getpid_measure) {
|
||||
|
@ -635,7 +645,7 @@ TEST(safe_fork) {
|
|||
BLOCK_SIGNALS(SIGCHLD);
|
||||
|
||||
r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG, &pid);
|
||||
assert_se(r >= 0);
|
||||
ASSERT_OK(r);
|
||||
|
||||
if (r == 0) {
|
||||
/* child */
|
||||
|
@ -644,43 +654,42 @@ TEST(safe_fork) {
|
|||
_exit(88);
|
||||
}
|
||||
|
||||
assert_se(wait_for_terminate(pid, &status) >= 0);
|
||||
assert_se(status.si_code == CLD_EXITED);
|
||||
assert_se(status.si_status == 88);
|
||||
ASSERT_OK(wait_for_terminate(pid, &status));
|
||||
ASSERT_EQ(status.si_code, CLD_EXITED);
|
||||
ASSERT_EQ(status.si_status, 88);
|
||||
}
|
||||
|
||||
TEST(pid_to_ptr) {
|
||||
assert_se(PTR_TO_PID(NULL) == 0);
|
||||
ASSERT_EQ(PTR_TO_PID(NULL), 0);
|
||||
ASSERT_NULL(PID_TO_PTR(0));
|
||||
|
||||
assert_se(PTR_TO_PID(PID_TO_PTR(1)) == 1);
|
||||
assert_se(PTR_TO_PID(PID_TO_PTR(2)) == 2);
|
||||
assert_se(PTR_TO_PID(PID_TO_PTR(-1)) == -1);
|
||||
assert_se(PTR_TO_PID(PID_TO_PTR(-2)) == -2);
|
||||
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(1)), 1);
|
||||
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(2)), 2);
|
||||
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-1)), -1);
|
||||
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-2)), -2);
|
||||
|
||||
assert_se(PTR_TO_PID(PID_TO_PTR(INT16_MAX)) == INT16_MAX);
|
||||
assert_se(PTR_TO_PID(PID_TO_PTR(INT16_MIN)) == INT16_MIN);
|
||||
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MAX)), INT16_MAX);
|
||||
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MIN)), INT16_MIN);
|
||||
|
||||
assert_se(PTR_TO_PID(PID_TO_PTR(INT32_MAX)) == INT32_MAX);
|
||||
assert_se(PTR_TO_PID(PID_TO_PTR(INT32_MIN)) == INT32_MIN);
|
||||
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MAX)), INT32_MAX);
|
||||
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MIN)), INT32_MIN);
|
||||
}
|
||||
|
||||
static void test_ioprio_class_from_to_string_one(const char *val, int expected, int normalized) {
|
||||
assert_se(ioprio_class_from_string(val) == expected);
|
||||
ASSERT_EQ(ioprio_class_from_string(val), expected);
|
||||
if (expected >= 0) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
unsigned ret;
|
||||
int combined;
|
||||
|
||||
assert_se(ioprio_class_to_string_alloc(expected, &s) == 0);
|
||||
ASSERT_OK_ZERO(ioprio_class_to_string_alloc(expected, &s));
|
||||
/* We sometimes get a class number and sometimes a name back */
|
||||
assert_se(streq(s, val) ||
|
||||
safe_atou(val, &ret) == 0);
|
||||
ASSERT_TRUE(streq(s, val) || safe_atou(val, &ret) == 0);
|
||||
|
||||
/* Make sure normalization works, i.e. NONE → BE gets normalized */
|
||||
combined = ioprio_normalize(ioprio_prio_value(expected, 0));
|
||||
assert_se(ioprio_prio_class(combined) == normalized);
|
||||
assert_se(expected != IOPRIO_CLASS_NONE || ioprio_prio_data(combined) == 4);
|
||||
ASSERT_EQ(ioprio_prio_class(combined), normalized);
|
||||
ASSERT_TRUE(expected != IOPRIO_CLASS_NONE || ioprio_prio_data(combined) == 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -701,8 +710,8 @@ TEST(setpriority_closest) {
|
|||
int r;
|
||||
|
||||
r = safe_fork("(test-setprio)",
|
||||
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
|
||||
assert_se(r >= 0);
|
||||
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG|FORK_REOPEN_LOG, NULL);
|
||||
ASSERT_OK(r);
|
||||
|
||||
if (r == 0) {
|
||||
bool full_test;
|
||||
|
@ -713,16 +722,21 @@ TEST(setpriority_closest) {
|
|||
if (setrlimit(RLIMIT_NICE, &RLIMIT_MAKE_CONST(30)) < 0) {
|
||||
/* If this fails we are probably unprivileged or in a userns of some kind, let's skip
|
||||
* the full test */
|
||||
assert_se(ERRNO_IS_PRIVILEGE(errno));
|
||||
if (!ERRNO_IS_PRIVILEGE(errno))
|
||||
ASSERT_OK_ERRNO(-1);
|
||||
full_test = false;
|
||||
} else {
|
||||
/* However, if the hard limit was above 30, setrlimit would succeed unprivileged, so
|
||||
* check if the UID/GID can be changed before enabling the full test. */
|
||||
if (setresgid(GID_NOBODY, GID_NOBODY, GID_NOBODY) < 0) {
|
||||
assert_se(ERRNO_IS_PRIVILEGE(errno));
|
||||
/* If the nobody user does not exist (user namespace) we get EINVAL. */
|
||||
if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
|
||||
ASSERT_OK_ERRNO(-1);
|
||||
full_test = false;
|
||||
} else if (setresuid(UID_NOBODY, UID_NOBODY, UID_NOBODY) < 0) {
|
||||
assert_se(ERRNO_IS_PRIVILEGE(errno));
|
||||
/* If the nobody user does not exist (user namespace) we get EINVAL. */
|
||||
if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
|
||||
ASSERT_OK_ERRNO(-1);
|
||||
full_test = false;
|
||||
} else
|
||||
full_test = true;
|
||||
|
@ -730,61 +744,69 @@ TEST(setpriority_closest) {
|
|||
|
||||
errno = 0;
|
||||
p = getpriority(PRIO_PROCESS, 0);
|
||||
assert_se(errno == 0);
|
||||
ASSERT_EQ(errno, 0);
|
||||
|
||||
/* It should always be possible to set our nice level to the current one */
|
||||
assert_se(setpriority_closest(p) > 0);
|
||||
ASSERT_OK_POSITIVE(setpriority_closest(p));
|
||||
|
||||
errno = 0;
|
||||
q = getpriority(PRIO_PROCESS, 0);
|
||||
assert_se(errno == 0 && p == q);
|
||||
ASSERT_EQ(errno, 0);
|
||||
ASSERT_EQ(p, q);
|
||||
|
||||
/* It should also be possible to set the nice level to one higher */
|
||||
if (p < PRIO_MAX-1) {
|
||||
assert_se(setpriority_closest(++p) > 0);
|
||||
ASSERT_OK_POSITIVE(setpriority_closest(++p));
|
||||
|
||||
errno = 0;
|
||||
q = getpriority(PRIO_PROCESS, 0);
|
||||
assert_se(errno == 0 && p == q);
|
||||
ASSERT_EQ(errno, 0);
|
||||
ASSERT_EQ(p, q);
|
||||
}
|
||||
|
||||
/* It should also be possible to set the nice level to two higher */
|
||||
if (p < PRIO_MAX-1) {
|
||||
assert_se(setpriority_closest(++p) > 0);
|
||||
ASSERT_OK_POSITIVE(setpriority_closest(++p));
|
||||
|
||||
errno = 0;
|
||||
q = getpriority(PRIO_PROCESS, 0);
|
||||
assert_se(errno == 0 && p == q);
|
||||
ASSERT_EQ(errno, 0);
|
||||
ASSERT_EQ(p, q);
|
||||
}
|
||||
|
||||
if (full_test) {
|
||||
/* These two should work, given the RLIMIT_NICE we set above */
|
||||
assert_se(setpriority_closest(-10) > 0);
|
||||
ASSERT_OK_POSITIVE(setpriority_closest(-10));
|
||||
errno = 0;
|
||||
q = getpriority(PRIO_PROCESS, 0);
|
||||
assert_se(errno == 0 && q == -10);
|
||||
ASSERT_EQ(errno, 0);
|
||||
ASSERT_EQ(q, -10);
|
||||
|
||||
assert_se(setpriority_closest(-9) > 0);
|
||||
ASSERT_OK_POSITIVE(setpriority_closest(-9));
|
||||
errno = 0;
|
||||
q = getpriority(PRIO_PROCESS, 0);
|
||||
assert_se(errno == 0 && q == -9);
|
||||
ASSERT_EQ(errno, 0);
|
||||
ASSERT_EQ(q, -9);
|
||||
|
||||
/* This should succeed but should be clamped to the limit */
|
||||
assert_se(setpriority_closest(-11) == 0);
|
||||
ASSERT_OK_ZERO(setpriority_closest(-11));
|
||||
errno = 0;
|
||||
q = getpriority(PRIO_PROCESS, 0);
|
||||
assert_se(errno == 0 && q == -10);
|
||||
ASSERT_EQ(errno, 0);
|
||||
ASSERT_EQ(q, -10);
|
||||
|
||||
assert_se(setpriority_closest(-8) > 0);
|
||||
ASSERT_OK_POSITIVE(setpriority_closest(-8));
|
||||
errno = 0;
|
||||
q = getpriority(PRIO_PROCESS, 0);
|
||||
assert_se(errno == 0 && q == -8);
|
||||
ASSERT_EQ(errno, 0);
|
||||
ASSERT_EQ(q, -8);
|
||||
|
||||
/* This should succeed but should be clamped to the limit */
|
||||
assert_se(setpriority_closest(-12) == 0);
|
||||
ASSERT_OK_ZERO(setpriority_closest(-12));
|
||||
errno = 0;
|
||||
q = getpriority(PRIO_PROCESS, 0);
|
||||
assert_se(errno == 0 && q == -10);
|
||||
ASSERT_EQ(errno, 0);
|
||||
ASSERT_EQ(q, -10);
|
||||
}
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
|
@ -795,10 +817,10 @@ TEST(get_process_ppid) {
|
|||
uint64_t limit;
|
||||
int r;
|
||||
|
||||
assert_se(get_process_ppid(1, NULL) == -EADDRNOTAVAIL);
|
||||
ASSERT_ERROR(get_process_ppid(1, NULL), EADDRNOTAVAIL);
|
||||
|
||||
/* the process with the PID above the global limit definitely doesn't exist. Verify that */
|
||||
assert_se(procfs_get_pid_max(&limit) >= 0);
|
||||
ASSERT_OK(procfs_get_pid_max(&limit));
|
||||
log_debug("kernel.pid_max = %"PRIu64, limit);
|
||||
|
||||
if (limit < INT_MAX) {
|
||||
|
@ -817,10 +839,10 @@ TEST(get_process_ppid) {
|
|||
break;
|
||||
}
|
||||
|
||||
assert_se(r >= 0);
|
||||
ASSERT_OK(r);
|
||||
|
||||
assert_se(pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1) >= 0);
|
||||
assert_se(pid_get_cmdline(ppid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2) >= 0);
|
||||
ASSERT_OK(pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1));
|
||||
ASSERT_OK(pid_get_cmdline(ppid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2));
|
||||
|
||||
log_info("Parent of " PID_FMT " (%s) is " PID_FMT " (%s).", pid, c1, ppid, c2);
|
||||
|
||||
|
@ -831,19 +853,20 @@ TEST(get_process_ppid) {
|
|||
TEST(set_oom_score_adjust) {
|
||||
int a, b, r;
|
||||
|
||||
assert_se(get_oom_score_adjust(&a) >= 0);
|
||||
ASSERT_OK(get_oom_score_adjust(&a));
|
||||
|
||||
r = set_oom_score_adjust(OOM_SCORE_ADJ_MIN);
|
||||
assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r));
|
||||
if (!ERRNO_IS_PRIVILEGE(r))
|
||||
ASSERT_OK(r);
|
||||
|
||||
if (r >= 0) {
|
||||
assert_se(get_oom_score_adjust(&b) >= 0);
|
||||
assert_se(b == OOM_SCORE_ADJ_MIN);
|
||||
ASSERT_OK(get_oom_score_adjust(&b));
|
||||
ASSERT_EQ(b, OOM_SCORE_ADJ_MIN);
|
||||
}
|
||||
|
||||
assert_se(set_oom_score_adjust(a) >= 0);
|
||||
assert_se(get_oom_score_adjust(&b) >= 0);
|
||||
assert_se(b == a);
|
||||
ASSERT_OK(set_oom_score_adjust(a));
|
||||
ASSERT_OK(get_oom_score_adjust(&b));
|
||||
ASSERT_EQ(b, a);
|
||||
}
|
||||
|
||||
static void* dummy_thread(void *p) {
|
||||
|
@ -851,10 +874,10 @@ static void* dummy_thread(void *p) {
|
|||
char x;
|
||||
|
||||
/* let main thread know we are ready */
|
||||
assert_se(write(fd, &(const char) { 'x' }, 1) == 1);
|
||||
ASSERT_OK_EQ_ERRNO(write(fd, &(const char) { 'x' }, 1), 1);
|
||||
|
||||
/* wait for the main thread to tell us to shut down */
|
||||
assert_se(read(fd, &x, 1) == 1);
|
||||
ASSERT_OK_EQ_ERRNO(read(fd, &x, 1), 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -862,38 +885,42 @@ TEST(get_process_threads) {
|
|||
int r;
|
||||
|
||||
/* Run this test in a child, so that we can guarantee there's exactly one thread around in the child */
|
||||
r = safe_fork("(nthreads)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_WAIT|FORK_LOG, NULL);
|
||||
assert_se(r >= 0);
|
||||
r = safe_fork("(nthreads)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
|
||||
ASSERT_OK(r);
|
||||
|
||||
if (r == 0) {
|
||||
_cleanup_close_pair_ int pfd[2] = EBADF_PAIR, ppfd[2] = EBADF_PAIR;
|
||||
pthread_t t, tt;
|
||||
char x;
|
||||
|
||||
assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pfd) >= 0);
|
||||
assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, ppfd) >= 0);
|
||||
ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pfd));
|
||||
ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, ppfd));
|
||||
|
||||
assert_se(get_process_threads(0) == 1);
|
||||
assert_se(pthread_create(&t, NULL, &dummy_thread, FD_TO_PTR(pfd[0])) == 0);
|
||||
assert_se(read(pfd[1], &x, 1) == 1);
|
||||
assert_se(get_process_threads(0) == 2);
|
||||
assert_se(pthread_create(&tt, NULL, &dummy_thread, FD_TO_PTR(ppfd[0])) == 0);
|
||||
assert_se(read(ppfd[1], &x, 1) == 1);
|
||||
assert_se(get_process_threads(0) == 3);
|
||||
ASSERT_OK_EQ(get_process_threads(0), 1);
|
||||
ASSERT_OK_ZERO_ERRNO(pthread_create(&t, NULL, &dummy_thread, FD_TO_PTR(pfd[0])));
|
||||
ASSERT_OK_EQ_ERRNO(read(pfd[1], &x, 1), 1);
|
||||
ASSERT_OK_EQ(get_process_threads(0), 2);
|
||||
ASSERT_OK_ZERO_ERRNO(pthread_create(&tt, NULL, &dummy_thread, FD_TO_PTR(ppfd[0])));
|
||||
ASSERT_OK_EQ_ERRNO(read(ppfd[1], &x, 1), 1);
|
||||
ASSERT_OK_EQ(get_process_threads(0), 3);
|
||||
|
||||
assert_se(write(pfd[1], &(const char) { 'x' }, 1) == 1);
|
||||
assert_se(pthread_join(t, NULL) == 0);
|
||||
ASSERT_OK_EQ_ERRNO(write(pfd[1], &(const char) { 'x' }, 1), 1);
|
||||
ASSERT_OK_ZERO_ERRNO(pthread_join(t, NULL));
|
||||
|
||||
/* the value reported via /proc/ is decreased asynchronously, and there appears to be no nice
|
||||
* way to sync on it. Hence we do the weak >= 2 check, even though == 2 is what we'd actually
|
||||
* like to check here */
|
||||
assert_se(get_process_threads(0) >= 2);
|
||||
r = get_process_threads(0);
|
||||
ASSERT_OK(r);
|
||||
ASSERT_GE(r, 2);
|
||||
|
||||
assert_se(write(ppfd[1], &(const char) { 'x' }, 1) == 1);
|
||||
assert_se(pthread_join(tt, NULL) == 0);
|
||||
ASSERT_OK_EQ_ERRNO(write(ppfd[1], &(const char) { 'x' }, 1), 1);
|
||||
ASSERT_OK_ZERO_ERRNO(pthread_join(tt, NULL));
|
||||
|
||||
/* similar here */
|
||||
assert_se(get_process_threads(0) >= 1);
|
||||
r = get_process_threads(0);
|
||||
ASSERT_OK(r);
|
||||
ASSERT_GE(r, 1);
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
@ -902,17 +929,17 @@ TEST(get_process_threads) {
|
|||
TEST(is_reaper_process) {
|
||||
int r;
|
||||
|
||||
r = safe_fork("(regular)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
|
||||
assert_se(r >= 0);
|
||||
r = safe_fork("(regular)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
|
||||
ASSERT_OK(r);
|
||||
if (r == 0) {
|
||||
/* child */
|
||||
|
||||
assert_se(is_reaper_process() == 0);
|
||||
ASSERT_OK_ZERO(is_reaper_process());
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
r = safe_fork("(newpid)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
|
||||
assert_se(r >= 0);
|
||||
r = safe_fork("(newpid)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
|
||||
ASSERT_OK(r);
|
||||
if (r == 0) {
|
||||
/* child */
|
||||
|
||||
|
@ -923,25 +950,25 @@ TEST(is_reaper_process) {
|
|||
}
|
||||
}
|
||||
|
||||
r = safe_fork("(newpid1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
|
||||
assert_se(r >= 0);
|
||||
r = safe_fork("(newpid1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
|
||||
ASSERT_OK(r);
|
||||
if (r == 0) {
|
||||
/* grandchild, which is PID1 in a pidns */
|
||||
assert_se(getpid_cached() == 1);
|
||||
assert_se(is_reaper_process() > 0);
|
||||
ASSERT_OK_EQ(getpid_cached(), 1);
|
||||
ASSERT_OK_POSITIVE(is_reaper_process());
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
|
||||
assert_se(r >= 0);
|
||||
r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
|
||||
ASSERT_OK(r);
|
||||
if (r == 0) {
|
||||
/* child */
|
||||
assert_se(make_reaper_process(true) >= 0);
|
||||
ASSERT_OK(make_reaper_process(true));
|
||||
|
||||
assert_se(is_reaper_process() > 0);
|
||||
ASSERT_OK_POSITIVE(is_reaper_process());
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
@ -949,22 +976,22 @@ TEST(is_reaper_process) {
|
|||
TEST(pid_get_start_time) {
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
|
||||
assert_se(pidref_set_self(&pidref) >= 0);
|
||||
ASSERT_OK(pidref_set_self(&pidref));
|
||||
|
||||
usec_t start_time;
|
||||
assert_se(pidref_get_start_time(&pidref, &start_time) >= 0);
|
||||
ASSERT_OK(pidref_get_start_time(&pidref, &start_time));
|
||||
log_info("our starttime: " USEC_FMT, start_time);
|
||||
|
||||
_cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
|
||||
|
||||
assert_se(pidref_safe_fork("(stub)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &child) >= 0);
|
||||
ASSERT_OK(pidref_safe_fork("(stub)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG, &child));
|
||||
|
||||
usec_t start_time2;
|
||||
assert_se(pidref_get_start_time(&child, &start_time2) >= 0);
|
||||
ASSERT_OK(pidref_get_start_time(&child, &start_time2));
|
||||
|
||||
log_info("child starttime: " USEC_FMT, start_time2);
|
||||
|
||||
assert_se(start_time2 >= start_time);
|
||||
ASSERT_GE(start_time2, start_time);
|
||||
}
|
||||
|
||||
static int intro(void) {
|
||||
|
|
|
@ -250,12 +250,12 @@ static void context_done(Context *c) {
|
|||
}
|
||||
|
||||
/* Different kinds of errors that mean that information is not available in the environment. */
|
||||
static bool ERRNO_IS_NOINFO(int r) {
|
||||
return IN_SET(abs(r),
|
||||
EUNATCH, /* os-release or machine-id missing */
|
||||
ENOMEDIUM, /* machine-id or another file empty */
|
||||
ENOPKG, /* machine-id is uninitialized */
|
||||
ENXIO); /* env var is unset */
|
||||
static bool ERRNO_IS_NEG_NOINFO(intmax_t r) {
|
||||
return IN_SET(r,
|
||||
-EUNATCH, /* os-release or machine-id missing */
|
||||
-ENOMEDIUM, /* machine-id or another file empty */
|
||||
-ENOPKG, /* machine-id is uninitialized */
|
||||
-ENXIO); /* env var is unset */
|
||||
}
|
||||
|
||||
static int specifier_directory(
|
||||
|
@ -351,47 +351,33 @@ static int log_unresolvable_specifier(const char *filename, unsigned line) {
|
|||
|
||||
static int user_config_paths(char ***ret) {
|
||||
_cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
|
||||
_cleanup_free_ char *persistent_config = NULL, *runtime_config = NULL, *data_home = NULL;
|
||||
_cleanup_strv_free_ char **res = NULL;
|
||||
_cleanup_free_ char *runtime_config = NULL;
|
||||
int r;
|
||||
|
||||
r = xdg_user_dirs(&config_dirs, &data_dirs);
|
||||
assert(ret);
|
||||
|
||||
/* Combined user-specific and global dirs */
|
||||
r = user_search_dirs("/user-tmpfiles.d", &config_dirs, &data_dirs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = xdg_user_config_dir(&persistent_config, "/user-tmpfiles.d");
|
||||
if (r < 0 && !ERRNO_IS_NOINFO(r))
|
||||
r = xdg_user_runtime_dir("/user-tmpfiles.d", &runtime_config);
|
||||
if (r < 0 && !ERRNO_IS_NEG_NOINFO(r))
|
||||
return r;
|
||||
|
||||
r = xdg_user_runtime_dir(&runtime_config, "/user-tmpfiles.d");
|
||||
if (r < 0 && !ERRNO_IS_NOINFO(r))
|
||||
return r;
|
||||
|
||||
r = xdg_user_data_dir(&data_home, "/user-tmpfiles.d");
|
||||
if (r < 0 && !ERRNO_IS_NOINFO(r))
|
||||
return r;
|
||||
|
||||
r = strv_extend_strv_concat(&res, (const char* const*) config_dirs, "/user-tmpfiles.d");
|
||||
r = strv_consume(&config_dirs, TAKE_PTR(runtime_config));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_extend_many(
|
||||
&res,
|
||||
persistent_config,
|
||||
runtime_config,
|
||||
data_home);
|
||||
r = strv_extend_strv(&config_dirs, data_dirs, /* filter_duplicates = */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_extend_strv_concat(&res, (const char* const*) data_dirs, "/user-tmpfiles.d");
|
||||
r = path_strv_make_absolute_cwd(config_dirs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = path_strv_make_absolute_cwd(res);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(res);
|
||||
*ret = TAKE_PTR(config_dirs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3694,7 +3680,7 @@ static int parse_line(
|
|||
i.purge = purge;
|
||||
|
||||
r = specifier_printf(path, PATH_MAX-1, specifier_table, arg_root, NULL, &i.path);
|
||||
if (ERRNO_IS_NOINFO(r))
|
||||
if (ERRNO_IS_NEG_NOINFO(r))
|
||||
return log_unresolvable_specifier(fname, line);
|
||||
if (r < 0) {
|
||||
if (IN_SET(r, -EINVAL, -EBADSLT))
|
||||
|
@ -3858,7 +3844,7 @@ static int parse_line(
|
|||
if (!unbase64) {
|
||||
/* Do specifier expansion except if base64 mode is enabled */
|
||||
r = specifier_expansion_from_arg(specifier_table, &i);
|
||||
if (ERRNO_IS_NOINFO(r))
|
||||
if (ERRNO_IS_NEG_NOINFO(r))
|
||||
return log_unresolvable_specifier(fname, line);
|
||||
if (r < 0) {
|
||||
if (IN_SET(r, -EINVAL, -EBADSLT))
|
||||
|
@ -4551,7 +4537,7 @@ static int run(int argc, char *argv[]) {
|
|||
PHASE_CREATE,
|
||||
_PHASE_MAX
|
||||
} phase;
|
||||
int r, k;
|
||||
int r;
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
|
@ -4694,21 +4680,15 @@ static int run(int argc, char *argv[]) {
|
|||
continue;
|
||||
|
||||
/* The non-globbing ones usually create things, hence we apply them first */
|
||||
ORDERED_HASHMAP_FOREACH(a, c.items) {
|
||||
k = process_item_array(&c, a, op);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
}
|
||||
ORDERED_HASHMAP_FOREACH(a, c.items)
|
||||
RET_GATHER(r, process_item_array(&c, a, op));
|
||||
|
||||
/* The globbing ones usually alter things, hence we apply them second. */
|
||||
ORDERED_HASHMAP_FOREACH(a, c.globs) {
|
||||
k = process_item_array(&c, a, op);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
}
|
||||
ORDERED_HASHMAP_FOREACH(a, c.globs)
|
||||
RET_GATHER(r, process_item_array(&c, a, op));
|
||||
}
|
||||
|
||||
if (ERRNO_IS_RESOURCE(r))
|
||||
if (ERRNO_IS_NEG_RESOURCE(r))
|
||||
return r;
|
||||
if (invalid_config)
|
||||
return EX_DATAERR;
|
||||
|
|
|
@ -259,7 +259,7 @@ static int run(int argc, char *argv[]) {
|
|||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (arg_graceful && tpm2_support() != TPM2_SUPPORT_FULL) {
|
||||
if (arg_graceful && !tpm2_is_fully_supported()) {
|
||||
log_notice("No complete TPM2 support detected, exiting gracefully.");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -288,7 +288,7 @@ static int verb_info(int argc, char *argv[], void *userdata) {
|
|||
pager_open(arg_pager_flags);
|
||||
|
||||
if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF)) {
|
||||
static const struct sd_json_dispatch_field dispatch_table[] = {
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "vendor", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetInfoData, vendor), SD_JSON_MANDATORY },
|
||||
{ "product", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetInfoData, product), SD_JSON_MANDATORY },
|
||||
{ "version", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetInfoData, version), SD_JSON_MANDATORY },
|
||||
|
@ -380,12 +380,12 @@ static int verb_introspect(int argc, char *argv[], void *userdata) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
const struct sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "interfaces", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, PTR_TO_SIZE(&auto_interfaces), SD_JSON_MANDATORY },
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "interfaces", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, 0, SD_JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
||||
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, NULL);
|
||||
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, &auto_interfaces);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -412,7 +412,7 @@ static int verb_introspect(int argc, char *argv[], void *userdata) {
|
|||
return r;
|
||||
|
||||
if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF) || list_methods) {
|
||||
static const struct sd_json_dispatch_field dispatch_table[] = {
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "description", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, SD_JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -212,7 +212,7 @@ static int get_firmware_search_dirs(char ***ret) {
|
|||
* Prioritising entries in "more specific" directories */
|
||||
|
||||
_cleanup_free_ char *user_firmware_dir = NULL;
|
||||
r = xdg_user_config_dir(&user_firmware_dir, "/qemu/firmware");
|
||||
r = xdg_user_config_dir("/qemu/firmware", &user_firmware_dir);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -1488,11 +1488,11 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
|||
|
||||
/* if we are going to be starting any units with state then create our runtime dir */
|
||||
if (arg_tpm != 0 || arg_directory || arg_runtime_mounts.n_mounts != 0) {
|
||||
r = runtime_directory(&arg_runtime_directory, arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER, "systemd/vmspawn");
|
||||
r = runtime_directory(arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER, "systemd/vmspawn",
|
||||
&arg_runtime_directory);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to lookup runtime directory: %m");
|
||||
if (r) {
|
||||
/* r > 0 means we need to create our own runtime dir */
|
||||
if (r > 0) { /* We need to create our own runtime dir */
|
||||
r = mkdir_p(arg_runtime_directory, 0755);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create runtime directory: %m");
|
||||
|
|
|
@ -20,6 +20,39 @@
|
|||
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(xdgautostartservice_hash_ops, char, string_hash_func, string_compare_func, XdgAutostartService, xdg_autostart_service_free);
|
||||
|
||||
static int xdg_base_dirs(char ***ret_config_dirs, char ***ret_data_dirs) {
|
||||
_cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
|
||||
const char *e;
|
||||
|
||||
/* Implement the mechanisms defined in
|
||||
* https://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html */
|
||||
|
||||
assert(ret_config_dirs);
|
||||
assert(ret_data_dirs);
|
||||
|
||||
e = getenv("XDG_CONFIG_DIRS");
|
||||
if (e)
|
||||
config_dirs = strv_split(e, ":");
|
||||
else
|
||||
config_dirs = strv_new("/etc/xdg");
|
||||
if (!config_dirs)
|
||||
return -ENOMEM;
|
||||
|
||||
e = getenv("XDG_DATA_DIRS");
|
||||
if (e)
|
||||
data_dirs = strv_split(e, ":");
|
||||
else
|
||||
data_dirs = strv_new("/usr/local/share",
|
||||
"/usr/share");
|
||||
if (!data_dirs)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_config_dirs = TAKE_PTR(config_dirs);
|
||||
*ret_data_dirs = TAKE_PTR(data_dirs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enumerate_xdg_autostart(Hashmap *all_services) {
|
||||
_cleanup_strv_free_ char **autostart_dirs = NULL;
|
||||
_cleanup_strv_free_ char **config_dirs = NULL;
|
||||
|
@ -27,14 +60,14 @@ static int enumerate_xdg_autostart(Hashmap *all_services) {
|
|||
_cleanup_free_ char *user_config_autostart_dir = NULL;
|
||||
int r;
|
||||
|
||||
r = xdg_user_config_dir(&user_config_autostart_dir, "/autostart");
|
||||
r = xdg_user_config_dir("/autostart", &user_config_autostart_dir);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = strv_extend(&autostart_dirs, user_config_autostart_dir);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = xdg_user_dirs(&config_dirs, &data_dirs);
|
||||
r = xdg_base_dirs(&config_dirs, &data_dirs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = strv_extend_strv_concat(&autostart_dirs, (const char* const*) config_dirs, "/autostart");
|
||||
|
|
|
@ -4,5 +4,6 @@ integration_tests += [
|
|||
integration_test_template + {
|
||||
'name' : fs.name(meson.current_source_dir()),
|
||||
'storage': 'persistent',
|
||||
'vm' : true,
|
||||
},
|
||||
]
|
||||
|
|
|
@ -21,6 +21,9 @@ at_exit() {
|
|||
|
||||
trap at_exit EXIT
|
||||
|
||||
systemctl unmask systemd-networkd.service
|
||||
systemctl start systemd-networkd.service
|
||||
|
||||
export NETWORK_NAME="10-networkctl-test-$RANDOM.network"
|
||||
export NETDEV_NAME="10-networkctl-test-$RANDOM.netdev"
|
||||
export LINK_NAME="10-networkctl-test-$RANDOM.link"
|
||||
|
@ -75,15 +78,6 @@ cmp "+4" "/etc/systemd/network/${NETWORK_NAME}.d/test.conf"
|
|||
networkctl cat "$NETWORK_NAME" | grep '^# ' |
|
||||
cmp - <(printf '%s\n' "# /etc/systemd/network/$NETWORK_NAME" "# /etc/systemd/network/${NETWORK_NAME}.d/test.conf")
|
||||
|
||||
networkctl edit --stdin --runtime "$NETDEV_NAME" <<EOF
|
||||
[NetDev]
|
||||
Name=test2
|
||||
Kind=dummy
|
||||
EOF
|
||||
|
||||
networkctl cat "$NETDEV_NAME" | grep -v '^# ' |
|
||||
cmp - <(printf '%s\n' "[NetDev]" "Name=test2" "Kind=dummy")
|
||||
|
||||
cat >"/usr/lib/systemd/network/$LINK_NAME" <<EOF
|
||||
[Match]
|
||||
OriginalName=test2
|
||||
|
@ -95,13 +89,23 @@ EOF
|
|||
SYSTEMD_LOG_LEVEL=debug EDITOR='true' script -ec 'networkctl edit "$LINK_NAME"' /dev/null
|
||||
cmp "/usr/lib/systemd/network/$LINK_NAME" "/etc/systemd/network/$LINK_NAME"
|
||||
|
||||
# Test links
|
||||
systemctl unmask systemd-networkd
|
||||
systemctl stop systemd-networkd
|
||||
# The interface test2 does not exist, hence the below do not work.
|
||||
(! networkctl cat @test2)
|
||||
(! networkctl cat @test2:netdev)
|
||||
(! networkctl cat @test2:link)
|
||||
(! networkctl cat @test2:network)
|
||||
|
||||
systemctl start systemd-networkd
|
||||
# create .netdev file at last, otherwise, the .link file will not be applied to the interface.
|
||||
networkctl edit --stdin --runtime "$NETDEV_NAME" <<EOF
|
||||
[NetDev]
|
||||
Name=test2
|
||||
Kind=dummy
|
||||
EOF
|
||||
|
||||
networkctl cat "$NETDEV_NAME" | grep -v '^# ' |
|
||||
cmp - <(printf '%s\n' "[NetDev]" "Name=test2" "Kind=dummy")
|
||||
|
||||
# wait for the interface being created and configured.
|
||||
SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-networkd-wait-online -i test2:carrier --timeout 20
|
||||
|
||||
networkctl cat @test2:network | cmp - <(networkctl cat "$NETWORK_NAME")
|
||||
|
|
Loading…
Reference in New Issue