mirror of
https://github.com/systemd/systemd
synced 2026-03-28 17:54:51 +01:00
Compare commits
22 Commits
07db7f6bb8
...
1641c2b112
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1641c2b112 | ||
|
|
5918a93355 | ||
|
|
64782655e1 | ||
|
|
8c35c10d20 | ||
|
|
5b32e48f6e | ||
|
|
545c30c9ba | ||
|
|
35777f5178 | ||
|
|
92466b8da2 | ||
|
|
3e4a202519 | ||
|
|
0cd7e072b4 | ||
|
|
71c4f7e895 | ||
|
|
90496cc68c | ||
|
|
b0a67b202d | ||
|
|
5bff20ea62 | ||
|
|
aa3f8d4ca1 | ||
|
|
e9ea43136c | ||
|
|
b5dce07a5e | ||
|
|
4be699a8db | ||
|
|
3bf94dac91 | ||
|
|
1f1d48f96e | ||
|
|
8b036b223a | ||
|
|
059c0578d7 |
20
.github/workflows/unit_tests.sh
vendored
20
.github/workflows/unit_tests.sh
vendored
@ -6,7 +6,9 @@ ADDITIONAL_DEPS=(
|
||||
clang
|
||||
expect
|
||||
fdisk
|
||||
iproute2
|
||||
jekyll
|
||||
lcov
|
||||
libfdisk-dev
|
||||
libfido2-dev
|
||||
libp11-kit-dev
|
||||
@ -18,6 +20,7 @@ ADDITIONAL_DEPS=(
|
||||
perl
|
||||
python3-libevdev
|
||||
python3-pyparsing
|
||||
util-linux
|
||||
zstd
|
||||
)
|
||||
|
||||
@ -42,10 +45,21 @@ for phase in "${PHASES[@]}"; do
|
||||
if [[ "$phase" = "RUN_CLANG" ]]; then
|
||||
export CC=clang
|
||||
export CXX=clang++
|
||||
# The docs build is slow and is not affected by compiler/flags, so do it just once
|
||||
MESON_ARGS+=(-Dman=true)
|
||||
fi
|
||||
meson --werror -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true -Dman=true build
|
||||
if [[ "$phase" = "RUN_GCC" ]]; then
|
||||
MESON_ARGS+=(-Db_coverage=true)
|
||||
# See FIXME below
|
||||
(set +x; while :; do echo -ne "\n[WATCHDOG] $(date)\n"; sleep 30; done) &
|
||||
fi
|
||||
meson --werror -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true "${MESON_ARGS[@]}" build
|
||||
ninja -C build -v
|
||||
meson test -C build --print-errorlogs
|
||||
# Some of the unsafe tests irreparably break the host's network connectivity, so run them in a namespace
|
||||
unshare -n bash -c 'ip link set dev lo up; meson test -C build --print-errorlogs'
|
||||
if [[ "$phase" = "RUN_GCC" ]]; then
|
||||
ninja -C build coverage
|
||||
fi
|
||||
;;
|
||||
RUN_ASAN_UBSAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN)
|
||||
MESON_ARGS=(--optimization=1)
|
||||
@ -74,7 +88,7 @@ for phase in "${PHASES[@]}"; do
|
||||
# during debugging, wonderful), so let's at least keep a workaround
|
||||
# here to make the builds stable for the time being.
|
||||
(set +x; while :; do echo -ne "\n[WATCHDOG] $(date)\n"; sleep 30; done) &
|
||||
meson test --timeout-multiplier=3 -C build --print-errorlogs
|
||||
unshare -n bash -c 'ip link set dev lo up; meson test --timeout-multiplier=3 -C build --print-errorlogs'
|
||||
;;
|
||||
CLEANUP)
|
||||
info "Cleanup phase"
|
||||
|
||||
8
.github/workflows/unit_tests.yml
vendored
8
.github/workflows/unit_tests.yml
vendored
@ -16,8 +16,14 @@ jobs:
|
||||
run_phase: [GCC, GCC_ASAN_UBSAN, CLANG, CLANG_ASAN_UBSAN]
|
||||
steps:
|
||||
- name: Repository checkout
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v2
|
||||
- name: Install build dependencies
|
||||
run: sudo -E .github/workflows/unit_tests.sh SETUP
|
||||
- name: Build & test (${{ matrix.run_phase }})
|
||||
run: sudo -E .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }}
|
||||
- name: Coveralls
|
||||
if: matrix.run_phase == 'GCC' && github.repository == 'systemd/systemd'
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path-to-lcov: ./build/meson-logs/coverage.info
|
||||
|
||||
@ -14,6 +14,7 @@ System and Service Manager
|
||||
[](https://jenkins-systemd.apps.ocp.ci.centos.org/job/upstream-vagrant-archlinux/)<br/>
|
||||
[&job=upstream-vagrant-archlinux-sanitizers)](https://jenkins-systemd.apps.ocp.ci.centos.org/job/upstream-vagrant-archlinux-sanitizers/)<br/>
|
||||
[](https://fossies.org/linux/test/systemd-main.tar.gz/codespell.html)</br>
|
||||
[](https://coveralls.io/github/systemd/systemd?branch=main)</br>
|
||||
[](https://repology.org/project/systemd/versions)
|
||||
|
||||
## Details
|
||||
|
||||
@ -320,6 +320,7 @@ Most service unit settings are available for transient units.
|
||||
✓ RestartSec=
|
||||
✓ RootDirectoryStartOnly=
|
||||
✓ RuntimeMaxSec=
|
||||
✓ RuntimeRandomizedExtraSec=
|
||||
Sockets=
|
||||
✓ SuccessExitStatus=
|
||||
✓ TimeoutAbortSec=
|
||||
@ -395,6 +396,7 @@ such).
|
||||
|
||||
```
|
||||
✓ RuntimeMaxSec=
|
||||
✓ RuntimeRandomizedExtraSec=
|
||||
✓ TimeoutStopSec=
|
||||
```
|
||||
|
||||
|
||||
@ -2317,6 +2317,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
readonly s TimeoutStopFailureMode = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly t RuntimeMaxUSec = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly t RuntimeRandomizedExtraUSec = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||
readonly t WatchdogUSec = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||
@ -2737,6 +2739,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly as NoExecPaths = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly as ExecSearchPath = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly t MountFlags = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateTmp = ...;
|
||||
@ -2888,6 +2892,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<!--property RuntimeMaxUSec is not documented!-->
|
||||
|
||||
<!--property RuntimeRandomizedExtraUSec is not documented!-->
|
||||
|
||||
<!--property WatchdogUSec is not documented!-->
|
||||
|
||||
<!--property RootDirectoryStartOnly is not documented!-->
|
||||
@ -3260,6 +3266,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<!--property NoExecPaths is not documented!-->
|
||||
|
||||
<!--property ExecSearchPath is not documented!-->
|
||||
|
||||
<!--property PrivateTmp is not documented!-->
|
||||
|
||||
<!--property PrivateDevices is not documented!-->
|
||||
@ -3422,6 +3430,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="RuntimeMaxUSec"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="RuntimeRandomizedExtraUSec"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="WatchdogUSec"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="WatchdogTimestamp"/>
|
||||
@ -3858,6 +3868,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="NoExecPaths"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ExecSearchPath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
||||
@ -4567,6 +4579,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly as NoExecPaths = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly as ExecSearchPath = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly t MountFlags = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateTmp = ...;
|
||||
@ -5118,6 +5132,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<!--property NoExecPaths is not documented!-->
|
||||
|
||||
<!--property ExecSearchPath is not documented!-->
|
||||
|
||||
<!--property PrivateTmp is not documented!-->
|
||||
|
||||
<!--property PrivateDevices is not documented!-->
|
||||
@ -5714,6 +5730,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="NoExecPaths"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ExecSearchPath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
||||
@ -6320,6 +6338,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly as NoExecPaths = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly as ExecSearchPath = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly t MountFlags = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateTmp = ...;
|
||||
@ -6799,6 +6819,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<!--property NoExecPaths is not documented!-->
|
||||
|
||||
<!--property ExecSearchPath is not documented!-->
|
||||
|
||||
<!--property PrivateTmp is not documented!-->
|
||||
|
||||
<!--property PrivateDevices is not documented!-->
|
||||
@ -7313,6 +7335,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="NoExecPaths"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ExecSearchPath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
||||
@ -8040,6 +8064,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly as NoExecPaths = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly as ExecSearchPath = ['...', ...];
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly t MountFlags = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly b PrivateTmp = ...;
|
||||
@ -8505,6 +8531,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
|
||||
<!--property NoExecPaths is not documented!-->
|
||||
|
||||
<!--property ExecSearchPath is not documented!-->
|
||||
|
||||
<!--property PrivateTmp is not documented!-->
|
||||
|
||||
<!--property PrivateDevices is not documented!-->
|
||||
@ -9005,6 +9033,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="NoExecPaths"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ExecSearchPath"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
||||
@ -9721,6 +9751,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
|
||||
readonly s Result = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly t RuntimeMaxUSec = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly t RuntimeRandomizedExtraUSec = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||
readonly s Slice = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||
@ -9891,6 +9923,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
|
||||
|
||||
<!--property RuntimeMaxUSec is not documented!-->
|
||||
|
||||
<!--property RuntimeRandomizedExtraUSec is not documented!-->
|
||||
|
||||
<!--property Slice is not documented!-->
|
||||
|
||||
<!--property MemoryCurrent is not documented!-->
|
||||
@ -10069,6 +10103,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="RuntimeMaxUSec"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="RuntimeRandomizedExtraUSec"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Slice"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="ControlGroup"/>
|
||||
|
||||
@ -89,6 +89,20 @@
|
||||
|
||||
<variablelist class='unit-directives'>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ExecSearchPath=</varname></term>
|
||||
|
||||
<listitem><para>Takes a colon separated list of absolute paths relative to which the executable
|
||||
used by the <varname>Exec*=</varname> (e.g. <varname>ExecStart=</varname>,
|
||||
<varname>ExecStop=</varname>, etc.) properties can be found. <varname>ExecSearchPath=</varname>
|
||||
overrides <varname>$PATH</varname> if <varname>$PATH</varname> is not supplied by the user through
|
||||
<varname>Environment=</varname>, <varname>EnvironmentFile=</varname> or
|
||||
<varname>PassEnvironment=</varname>. Assigning an empty string removes previous assignments
|
||||
and setting <varname>ExecSearchPath=</varname> to a value multiple times will append
|
||||
to the previous setting.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>WorkingDirectory=</varname></term>
|
||||
|
||||
|
||||
@ -112,6 +112,15 @@
|
||||
active for longer than the specified time it is terminated and put into a failure state. Pass
|
||||
<literal>infinity</literal> (the default) to configure no runtime limit.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RuntimeRandomizedExtraSec=</varname></term>
|
||||
|
||||
<listitem><para>This option modifies <varname>RuntimeMaxSec=</varname> by increasing the maximum runtime by an
|
||||
evenly distributed duration between 0 and the specified value (in seconds). If <varname>RuntimeMaxSec=</varname> is
|
||||
unspecified, then this feature will be disabled.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<xi:include href="systemd.service.xml" xpointer="shared-unit-options" />
|
||||
|
||||
@ -695,6 +695,15 @@
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RuntimeRandomizedExtraSec=</varname></term>
|
||||
|
||||
<listitem><para>This option modifies <varname>RuntimeMaxSec=</varname> by increasing the maximum runtime by an
|
||||
evenly distributed duration between 0 and the specified value (in seconds). If <varname>RuntimeMaxSec=</varname> is
|
||||
unspecified, then this feature will be disabled.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>WatchdogSec=</varname></term>
|
||||
<listitem><para>Configures the watchdog timeout for a service.
|
||||
|
||||
10
mkosi.build
10
mkosi.build
@ -4,16 +4,6 @@ set -e
|
||||
# This is a build script for OS image generation using mkosi (https://github.com/systemd/mkosi).
|
||||
# Simply invoke "mkosi" in the project directory to build an OS image.
|
||||
|
||||
# Reset the permissions of the tree. Since Meson keeps the permissions
|
||||
# all the way to the installed files, reset them to one of 0644 or 0755
|
||||
# so the files keep those permissions, otherwise details of what umask
|
||||
# was set at the time the git tree was cloned will leak all the way
|
||||
# through. Also set umask explicitly during the build.
|
||||
if ! mountpoint -q "$SRCDIR"; then
|
||||
chmod -R u+w,go-w,a+rX .
|
||||
umask 022
|
||||
fi
|
||||
|
||||
# On Fedora "ld" is (unfortunately — if you ask me) managed via
|
||||
# "alternatives". Since we'd like to support building images in environments
|
||||
# with only /usr/ around (e.g. mkosi's UsrOnly=1 option), we have the problem
|
||||
|
||||
@ -142,7 +142,7 @@ int verify_executable(Unit *u, const ExecCommand *exec, const char *root) {
|
||||
if (exec->flags & EXEC_COMMAND_IGNORE_FAILURE)
|
||||
return 0;
|
||||
|
||||
r = find_executable_full(exec->path, root, false, NULL, NULL);
|
||||
r = find_executable_full(exec->path, root, NULL, false, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_unit_error_errno(u, r, "Command %s is not executable: %m", exec->path);
|
||||
|
||||
|
||||
@ -682,8 +682,8 @@ static int find_executable_impl(const char *name, const char *root, char **ret_f
|
||||
return 0;
|
||||
}
|
||||
|
||||
int find_executable_full(const char *name, const char *root, bool use_path_envvar, char **ret_filename, int *ret_fd) {
|
||||
int last_error, r;
|
||||
int find_executable_full(const char *name, const char *root, char **exec_search_path, bool use_path_envvar, char **ret_filename, int *ret_fd) {
|
||||
int last_error = -ENOENT, r = 0;
|
||||
const char *p = NULL;
|
||||
|
||||
assert(name);
|
||||
@ -698,7 +698,27 @@ int find_executable_full(const char *name, const char *root, bool use_path_envva
|
||||
if (!p)
|
||||
p = DEFAULT_PATH;
|
||||
|
||||
last_error = -ENOENT;
|
||||
if (exec_search_path) {
|
||||
char **element;
|
||||
|
||||
STRV_FOREACH(element, exec_search_path) {
|
||||
_cleanup_free_ char *full_path = NULL;
|
||||
if (!path_is_absolute(*element))
|
||||
continue;
|
||||
full_path = path_join(*element, name);
|
||||
if (!full_path)
|
||||
return -ENOMEM;
|
||||
|
||||
r = find_executable_impl(full_path, root, ret_filename, ret_fd);
|
||||
if (r < 0) {
|
||||
if (r != -EACCES)
|
||||
last_error = r;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return last_error;
|
||||
}
|
||||
|
||||
/* Resolve a single-component name to a full path */
|
||||
for (;;) {
|
||||
|
||||
@ -99,9 +99,9 @@ int path_strv_make_absolute_cwd(char **l);
|
||||
char** path_strv_resolve(char **l, const char *root);
|
||||
char** path_strv_resolve_uniq(char **l, const char *root);
|
||||
|
||||
int find_executable_full(const char *name, const char *root, bool use_path_envvar, char **ret_filename, int *ret_fd);
|
||||
int find_executable_full(const char *name, const char *root, char **exec_search_path, bool use_path_envvar, char **ret_filename, int *ret_fd);
|
||||
static inline int find_executable(const char *name, char **ret_filename) {
|
||||
return find_executable_full(name, /* root= */ NULL, true, ret_filename, NULL);
|
||||
return find_executable_full(name, /* root= */ NULL, NULL, true, ret_filename, NULL);
|
||||
}
|
||||
|
||||
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
|
||||
|
||||
@ -173,6 +173,16 @@ int prioq_put(Prioq *q, void *data, unsigned *idx) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prioq_ensure_put(Prioq **q, compare_func_t compare_func, void *data, unsigned *idx) {
|
||||
int r;
|
||||
|
||||
r = prioq_ensure_allocated(q, compare_func);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return prioq_put(*q, data, idx);
|
||||
}
|
||||
|
||||
static void remove_item(Prioq *q, struct prioq_item *i) {
|
||||
struct prioq_item *l;
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Prioq*, prioq_free);
|
||||
int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func);
|
||||
|
||||
int prioq_put(Prioq *q, void *data, unsigned *idx);
|
||||
int prioq_ensure_put(Prioq **q, compare_func_t compare_func, void *data, unsigned *idx);
|
||||
int prioq_remove(Prioq *q, void *data, unsigned *idx);
|
||||
int prioq_reshuffle(Prioq *q, void *data, unsigned *idx);
|
||||
|
||||
|
||||
@ -1161,6 +1161,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||
SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ExecPaths", "as", NULL, offsetof(ExecContext, exec_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("NoExecPaths", "as", NULL, offsetof(ExecContext, no_exec_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ExecSearchPath", "as", NULL, offsetof(ExecContext, exec_search_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@ -3140,6 +3141,36 @@ int bus_exec_context_set_transient_property(
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "ExecSearchPath")) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
char **p;
|
||||
|
||||
r = sd_bus_message_read_strv(message, &l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(p, l) {
|
||||
if (!path_is_absolute(*p) || !path_is_normalized(*p) || strchr(*p, ':'))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
|
||||
}
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
if (strv_isempty(l)) {
|
||||
c->exec_search_path = strv_free(c->exec_search_path);
|
||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "ExecSearchPath=");
|
||||
} else {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
r = strv_extend_strv(&c->exec_search_path, l, true);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
joined = strv_join(c->exec_search_path, ":");
|
||||
if (!joined)
|
||||
return log_oom();
|
||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "ExecSearchPath=%s", joined);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (STR_IN_SET(name, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
char **p;
|
||||
|
||||
@ -47,6 +47,7 @@ const sd_bus_vtable bus_scope_vtable[] = {
|
||||
SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Scope, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RuntimeRandomizedExtraUSec", "t", bus_property_get_usec, offsetof(Scope, runtime_rand_extra_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_SIGNAL("RequestStop", NULL, 0),
|
||||
SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_method_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_VTABLE_END
|
||||
@ -74,6 +75,9 @@ static int bus_scope_set_transient_property(
|
||||
if (streq(name, "RuntimeMaxUSec"))
|
||||
return bus_set_transient_usec(u, name, &s->runtime_max_usec, message, flags, error);
|
||||
|
||||
if (streq(name, "RuntimeRandomizedExtraUSec"))
|
||||
return bus_set_transient_usec(u, name, &s->runtime_rand_extra_usec, message, flags, error);
|
||||
|
||||
if (streq(name, "PIDs")) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
unsigned n = 0;
|
||||
|
||||
@ -202,6 +202,7 @@ const sd_bus_vtable bus_service_vtable[] = {
|
||||
SD_BUS_PROPERTY("TimeoutStartFailureMode", "s", property_get_timeout_failure_mode, offsetof(Service, timeout_start_failure_mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("TimeoutStopFailureMode", "s", property_get_timeout_failure_mode, offsetof(Service, timeout_stop_failure_mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Service, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RuntimeRandomizedExtraUSec", "t", bus_property_get_usec, offsetof(Service, runtime_rand_extra_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("WatchdogUSec", "t", property_get_watchdog_usec, 0, 0),
|
||||
BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0),
|
||||
SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* 😷 deprecated */
|
||||
@ -447,6 +448,9 @@ static int bus_service_set_transient_property(
|
||||
if (streq(name, "RuntimeMaxUSec"))
|
||||
return bus_set_transient_usec(u, name, &s->runtime_max_usec, message, flags, error);
|
||||
|
||||
if (streq(name, "RuntimeRandomizedExtraUSec"))
|
||||
return bus_set_transient_usec(u, name, &s->runtime_rand_extra_usec, message, flags, error);
|
||||
|
||||
if (streq(name, "WatchdogUSec"))
|
||||
return bus_set_transient_usec(u, name, &s->watchdog_usec, message, flags, error);
|
||||
|
||||
|
||||
@ -3742,7 +3742,7 @@ static int exec_child(
|
||||
int user_lookup_fd,
|
||||
int *exit_status) {
|
||||
|
||||
_cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **replaced_argv = NULL;
|
||||
_cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **joined_exec_search_path = NULL, **accum_env = NULL, **replaced_argv = NULL;
|
||||
int r, ngids = 0, exec_fd;
|
||||
_cleanup_free_ gid_t *supplementary_gids = NULL;
|
||||
const char *username = NULL, *groupname = NULL;
|
||||
@ -4158,8 +4158,31 @@ static int exec_child(
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
/* The PATH variable is set to the default path in params->environment.
|
||||
* However, this is overridden if user specified fields have PATH set.
|
||||
* The intention is to also override PATH if the user does
|
||||
* not specify PATH and the user has specified ExecSearchPath
|
||||
*/
|
||||
|
||||
if (!strv_isempty(context->exec_search_path)) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
|
||||
joined = strv_join(context->exec_search_path, ":");
|
||||
if (!joined) {
|
||||
*exit_status = EXIT_MEMORY;
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = strv_env_assign(&joined_exec_search_path, "PATH", joined);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_MEMORY;
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
accum_env = strv_env_merge(params->environment,
|
||||
our_env,
|
||||
joined_exec_search_path,
|
||||
pass_env,
|
||||
context->environment,
|
||||
files_env);
|
||||
@ -4350,7 +4373,7 @@ static int exec_child(
|
||||
|
||||
_cleanup_free_ char *executable = NULL;
|
||||
_cleanup_close_ int executable_fd = -1;
|
||||
r = find_executable_full(command->path, /* root= */ NULL, false, &executable, &executable_fd);
|
||||
r = find_executable_full(command->path, /* root= */ NULL, context->exec_search_path, false, &executable, &executable_fd);
|
||||
if (r < 0) {
|
||||
if (r != -ENOMEM && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
|
||||
log_unit_struct_errno(unit, LOG_INFO, r,
|
||||
@ -4926,6 +4949,7 @@ void exec_context_done(ExecContext *c) {
|
||||
c->inaccessible_paths = strv_free(c->inaccessible_paths);
|
||||
c->exec_paths = strv_free(c->exec_paths);
|
||||
c->no_exec_paths = strv_free(c->no_exec_paths);
|
||||
c->exec_search_path = strv_free(c->exec_search_path);
|
||||
|
||||
bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
|
||||
c->bind_mounts = NULL;
|
||||
@ -5597,6 +5621,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||
strv_dump(f, prefix, "InaccessiblePaths", c->inaccessible_paths);
|
||||
strv_dump(f, prefix, "ExecPaths", c->exec_paths);
|
||||
strv_dump(f, prefix, "NoExecPaths", c->no_exec_paths);
|
||||
strv_dump(f, prefix, "ExecSearchPath", c->exec_search_path);
|
||||
|
||||
for (size_t i = 0; i < c->n_bind_mounts; i++)
|
||||
fprintf(f, "%s%s: %s%s:%s:%s\n", prefix,
|
||||
|
||||
@ -254,6 +254,7 @@ struct ExecContext {
|
||||
char *smack_process_label;
|
||||
|
||||
char **read_write_paths, **read_only_paths, **inaccessible_paths, **exec_paths, **no_exec_paths;
|
||||
char **exec_search_path;
|
||||
unsigned long mount_flags;
|
||||
BindMount *bind_mounts;
|
||||
size_t n_bind_mounts;
|
||||
|
||||
@ -105,6 +105,7 @@
|
||||
{{type}}.InaccessiblePaths, config_parse_namespace_path_strv, 0, offsetof({{type}}, exec_context.inaccessible_paths)
|
||||
{{type}}.ExecPaths, config_parse_namespace_path_strv, 0, offsetof({{type}}, exec_context.exec_paths)
|
||||
{{type}}.NoExecPaths, config_parse_namespace_path_strv, 0, offsetof({{type}}, exec_context.no_exec_paths)
|
||||
{{type}}.ExecSearchPath, config_parse_colon_separated_paths, 0, offsetof({{type}}, exec_context.exec_search_path)
|
||||
{{type}}.BindPaths, config_parse_bind_paths, 0, offsetof({{type}}, exec_context)
|
||||
{{type}}.BindReadOnlyPaths, config_parse_bind_paths, 0, offsetof({{type}}, exec_context)
|
||||
{{type}}.TemporaryFileSystem, config_parse_temporary_filesystems, 0, offsetof({{type}}, exec_context)
|
||||
@ -381,6 +382,7 @@ Service.TimeoutAbortSec, config_parse_service_timeout_abort,
|
||||
Service.TimeoutStartFailureMode, config_parse_service_timeout_failure_mode, 0, offsetof(Service, timeout_start_failure_mode)
|
||||
Service.TimeoutStopFailureMode, config_parse_service_timeout_failure_mode, 0, offsetof(Service, timeout_stop_failure_mode)
|
||||
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
|
||||
Service.RuntimeRandomizedExtraSec, config_parse_sec, 0, offsetof(Service, runtime_rand_extra_usec)
|
||||
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
|
||||
{# The following five only exist for compatibility, they moved into Unit, see above #}
|
||||
Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_ratelimit.interval)
|
||||
@ -533,6 +535,7 @@ Path.DirectoryMode, config_parse_mode,
|
||||
{{ CGROUP_CONTEXT_CONFIG_ITEMS('Scope') }}
|
||||
{{ KILL_CONTEXT_CONFIG_ITEMS('Scope') }}
|
||||
Scope.RuntimeMaxSec, config_parse_sec, 0, offsetof(Scope, runtime_max_usec)
|
||||
Scope.RuntimeRandomizedExtraSec, config_parse_sec, 0, offsetof(Scope, runtime_rand_extra_usec)
|
||||
Scope.TimeoutStopSec, config_parse_sec, 0, offsetof(Scope, timeout_stop_usec)
|
||||
{# The [Install] section is ignored here #}
|
||||
Install.Alias, NULL, 0, 0
|
||||
|
||||
@ -305,6 +305,64 @@ int config_parse_unit_path_printf(
|
||||
return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
|
||||
}
|
||||
|
||||
int config_parse_colon_separated_paths(
|
||||
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) {
|
||||
char ***sv = data;
|
||||
const Unit *u = userdata;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
/* Empty assignment resets the list */
|
||||
*sv = strv_free(*sv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (const char *p = rvalue;;) {
|
||||
_cleanup_free_ char *word = NULL, *k = NULL;
|
||||
|
||||
r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to extract first word, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
r = unit_path_printf(u, word, &k);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to resolve unit specifiers in '%s', ignoring: %m", word);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = path_simplify_and_warn(k, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
r = strv_consume(sv, TAKE_PTR(k));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_unit_path_strv_printf(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
@ -5915,6 +5973,7 @@ void unit_dump_config_items(FILE *f) {
|
||||
{ config_parse_string, "STRING" },
|
||||
{ config_parse_path, "PATH" },
|
||||
{ config_parse_unit_path_printf, "PATH" },
|
||||
{ config_parse_colon_separated_paths, "PATH" },
|
||||
{ config_parse_strv, "STRING [...]" },
|
||||
{ config_parse_exec_nice, "NICE" },
|
||||
{ config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
|
||||
|
||||
@ -19,6 +19,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_obsolete_unit_deps);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_unit_string_printf);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_unit_strv_printf);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_unit_path_printf);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_colon_separated_paths);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_unit_path_strv_printf);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_documentation);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_socket_listen);
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include "load-dropin.h"
|
||||
#include "log.h"
|
||||
#include "process-util.h"
|
||||
#include "random-util.h"
|
||||
#include "scope.h"
|
||||
#include "serialize.h"
|
||||
#include "special.h"
|
||||
@ -51,6 +52,21 @@ static void scope_done(Unit *u) {
|
||||
s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
|
||||
}
|
||||
|
||||
static int scope_running_timeout(Scope *s) {
|
||||
usec_t delta = 0;
|
||||
|
||||
assert(s);
|
||||
|
||||
if (s->runtime_rand_extra_usec != 0) {
|
||||
delta = random_u64_range(s->runtime_rand_extra_usec);
|
||||
log_unit_debug(UNIT(s), "Adding delta of %s sec to timeout", FORMAT_TIMESPAN(delta, USEC_PER_SEC));
|
||||
}
|
||||
|
||||
return usec_add(usec_add(UNIT(s)->active_enter_timestamp.monotonic,
|
||||
s->runtime_max_usec),
|
||||
delta);
|
||||
}
|
||||
|
||||
static int scope_arm_timer(Scope *s, usec_t usec) {
|
||||
int r;
|
||||
|
||||
@ -209,7 +225,7 @@ static usec_t scope_coldplug_timeout(Scope *s) {
|
||||
switch (s->deserialized_state) {
|
||||
|
||||
case SCOPE_RUNNING:
|
||||
return usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec);
|
||||
return scope_running_timeout(s);
|
||||
|
||||
case SCOPE_STOP_SIGKILL:
|
||||
case SCOPE_STOP_SIGTERM:
|
||||
@ -262,10 +278,12 @@ static void scope_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
fprintf(f,
|
||||
"%sScope State: %s\n"
|
||||
"%sResult: %s\n"
|
||||
"%sRuntimeMaxSec: %s\n",
|
||||
"%sRuntimeMaxSec: %s\n"
|
||||
"%sRuntimeRandomizedExtraSec: %s\n",
|
||||
prefix, scope_state_to_string(s->state),
|
||||
prefix, scope_result_to_string(s->result),
|
||||
prefix, FORMAT_TIMESPAN(s->runtime_max_usec, USEC_PER_SEC));
|
||||
prefix, FORMAT_TIMESPAN(s->runtime_max_usec, USEC_PER_SEC),
|
||||
prefix, FORMAT_TIMESPAN(s->runtime_rand_extra_usec, USEC_PER_SEC));
|
||||
|
||||
cgroup_context_dump(UNIT(s), f, prefix);
|
||||
kill_context_dump(&s->kill_context, f, prefix);
|
||||
@ -379,7 +397,7 @@ static int scope_start(Unit *u) {
|
||||
scope_set_state(s, SCOPE_RUNNING);
|
||||
|
||||
/* Set the maximum runtime timeout. */
|
||||
scope_arm_timer(s, usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec));
|
||||
scope_arm_timer(s, scope_running_timeout(s));
|
||||
|
||||
/* On unified we use proper notifications hence we can unwatch the PIDs
|
||||
* we just attached to the scope. This can also be done on legacy as
|
||||
|
||||
@ -25,6 +25,7 @@ struct Scope {
|
||||
ScopeResult result;
|
||||
|
||||
usec_t runtime_max_usec;
|
||||
usec_t runtime_rand_extra_usec;
|
||||
usec_t timeout_stop_usec;
|
||||
|
||||
char *controller;
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "random-util.h"
|
||||
#include "serialize.h"
|
||||
#include "service.h"
|
||||
#include "signal-util.h"
|
||||
@ -514,6 +515,21 @@ static void service_remove_fd_store(Service *s, const char *name) {
|
||||
}
|
||||
}
|
||||
|
||||
static int service_running_timeout(Service *s) {
|
||||
usec_t delta = 0;
|
||||
|
||||
assert(s);
|
||||
|
||||
if (s->runtime_rand_extra_usec != 0) {
|
||||
delta = random_u64_range(s->runtime_rand_extra_usec);
|
||||
log_unit_debug(UNIT(s), "Adding delta of %s sec to timeout", FORMAT_TIMESPAN(delta, USEC_PER_SEC));
|
||||
}
|
||||
|
||||
return usec_add(usec_add(UNIT(s)->active_enter_timestamp.monotonic,
|
||||
s->runtime_max_usec),
|
||||
delta);
|
||||
}
|
||||
|
||||
static int service_arm_timer(Service *s, usec_t usec) {
|
||||
int r;
|
||||
|
||||
@ -587,6 +603,9 @@ static int service_verify(Service *s) {
|
||||
if (s->runtime_max_usec != USEC_INFINITY && s->type == SERVICE_ONESHOT)
|
||||
log_unit_warning(UNIT(s), "RuntimeMaxSec= has no effect in combination with Type=oneshot. Ignoring.");
|
||||
|
||||
if (s->runtime_max_usec == USEC_INFINITY && s->runtime_rand_extra_usec != 0)
|
||||
log_unit_warning(UNIT(s), "Service has RuntimeRandomizedExtraSec= setting, but no RuntimeMaxSec=. Ignoring.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -855,8 +874,10 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
|
||||
fprintf(f,
|
||||
"%sRuntimeMaxSec: %s\n"
|
||||
"%sRuntimeRandomizedExtraSec: %s\n"
|
||||
"%sWatchdogSec: %s\n",
|
||||
prefix, FORMAT_TIMESPAN(s->runtime_max_usec, USEC_PER_SEC),
|
||||
prefix, FORMAT_TIMESPAN(s->runtime_rand_extra_usec, USEC_PER_SEC),
|
||||
prefix, FORMAT_TIMESPAN(s->watchdog_usec, USEC_PER_SEC));
|
||||
|
||||
kill_context_dump(&s->kill_context, f, prefix);
|
||||
@ -1118,7 +1139,7 @@ static usec_t service_coldplug_timeout(Service *s) {
|
||||
return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_start_usec);
|
||||
|
||||
case SERVICE_RUNNING:
|
||||
return usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec);
|
||||
return service_running_timeout(s);
|
||||
|
||||
case SERVICE_STOP:
|
||||
case SERVICE_STOP_SIGTERM:
|
||||
@ -1989,7 +2010,7 @@ static void service_enter_running(Service *s, ServiceResult f) {
|
||||
service_enter_stop_by_notify(s);
|
||||
else {
|
||||
service_set_state(s, SERVICE_RUNNING);
|
||||
service_arm_timer(s, usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec));
|
||||
service_arm_timer(s, service_running_timeout(s));
|
||||
}
|
||||
|
||||
} else if (s->remain_after_exit)
|
||||
|
||||
@ -111,6 +111,7 @@ struct Service {
|
||||
usec_t timeout_abort_usec;
|
||||
bool timeout_abort_set;
|
||||
usec_t runtime_max_usec;
|
||||
usec_t runtime_rand_extra_usec;
|
||||
ServiceTimeoutFailureMode timeout_start_failure_mode;
|
||||
ServiceTimeoutFailureMode timeout_stop_failure_mode;
|
||||
|
||||
|
||||
@ -34,8 +34,12 @@ static int search_policy_hash(
|
||||
return log_error_errno(r, "Failed to read JSON token data off disk: %m");
|
||||
|
||||
keyslot = cryptsetup_get_keyslot_from_token(v);
|
||||
if (keyslot < 0)
|
||||
return log_error_errno(keyslot, "Failed to determine keyslot of JSON token: %m");
|
||||
if (keyslot < 0) {
|
||||
/* Handle parsing errors of the keyslots field gracefully, since it's not 'owned' by
|
||||
* us, but by the LUKS2 spec */
|
||||
log_warning_errno(keyslot, "Failed to determine keyslot of JSON token %i, skipping: %m", token);
|
||||
continue;
|
||||
}
|
||||
|
||||
w = json_variant_by_key(v, "tpm2-policy-hash");
|
||||
if (!w || !json_variant_is_string(w))
|
||||
|
||||
@ -133,6 +133,7 @@ int find_fido2_auto_data(
|
||||
for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token ++) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
JsonVariant *w;
|
||||
int ks;
|
||||
|
||||
r = cryptsetup_get_token_as_json(cd, token, "systemd-fido2", &v);
|
||||
if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE))
|
||||
@ -140,10 +141,21 @@ int find_fido2_auto_data(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read JSON token data off disk: %m");
|
||||
|
||||
ks = cryptsetup_get_keyslot_from_token(v);
|
||||
if (ks < 0) {
|
||||
/* Handle parsing errors of the keyslots field gracefully, since it's not 'owned' by
|
||||
* us, but by the LUKS2 spec */
|
||||
log_warning_errno(ks, "Failed to extract keyslot index from FIDO2 JSON data token %i, skipping: %m", token);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cid)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
|
||||
"Multiple FIDO2 tokens enrolled, cannot automatically determine token.");
|
||||
|
||||
assert(keyslot < 0);
|
||||
keyslot = ks;
|
||||
|
||||
w = json_variant_by_key(v, "fido2-credential");
|
||||
if (!w || !json_variant_is_string(w))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
@ -165,11 +177,6 @@ int find_fido2_auto_data(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to decode base64 encoded salt.");
|
||||
|
||||
assert(keyslot < 0);
|
||||
keyslot = cryptsetup_get_keyslot_from_token(v);
|
||||
if (keyslot < 0)
|
||||
return log_error_errno(keyslot, "Failed to extract keyslot index from FIDO2 JSON data: %m");
|
||||
|
||||
w = json_variant_by_key(v, "fido2-rp");
|
||||
if (w) {
|
||||
/* The "rp" field is optional. */
|
||||
|
||||
@ -111,6 +111,7 @@ int find_pkcs11_auto_data(
|
||||
for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token++) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
JsonVariant *w;
|
||||
int ks;
|
||||
|
||||
r = cryptsetup_get_token_as_json(cd, token, "systemd-pkcs11", &v);
|
||||
if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE))
|
||||
@ -118,10 +119,21 @@ int find_pkcs11_auto_data(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read JSON token data off disk: %m");
|
||||
|
||||
ks = cryptsetup_get_keyslot_from_token(v);
|
||||
if (ks < 0) {
|
||||
/* Handle parsing errors of the keyslots field gracefully, since it's not 'owned' by
|
||||
* us, but by the LUKS2 spec */
|
||||
log_warning_errno(ks, "Failed to extract keyslot index from PKCS#11 JSON data token %i, skipping: %m", token);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uri)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
|
||||
"Multiple PKCS#11 tokens enrolled, cannot automatically determine token.");
|
||||
|
||||
assert(keyslot < 0);
|
||||
keyslot = ks;
|
||||
|
||||
w = json_variant_by_key(v, "pkcs11-uri");
|
||||
if (!w || !json_variant_is_string(w))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
@ -145,11 +157,6 @@ int find_pkcs11_auto_data(
|
||||
r = unbase64mem(json_variant_string(w), SIZE_MAX, &key, &key_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to decode base64 encoded key.");
|
||||
|
||||
assert(keyslot < 0);
|
||||
keyslot = cryptsetup_get_keyslot_from_token(v);
|
||||
if (keyslot < 0)
|
||||
return log_error_errno(keyslot, "Failed to extract keyslot index from PKCS#11 JSON data: %m");
|
||||
}
|
||||
|
||||
if (!uri)
|
||||
|
||||
@ -93,6 +93,7 @@ int find_tpm2_auto_data(
|
||||
for (token = start_token; token < sym_crypt_token_max(CRYPT_LUKS2); token++) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
JsonVariant *w, *e;
|
||||
int ks;
|
||||
|
||||
r = cryptsetup_get_token_as_json(cd, token, "systemd-tpm2", &v);
|
||||
if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE))
|
||||
@ -100,6 +101,14 @@ int find_tpm2_auto_data(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read JSON token data off disk: %m");
|
||||
|
||||
ks = cryptsetup_get_keyslot_from_token(v);
|
||||
if (ks < 0) {
|
||||
/* Handle parsing errors of the keyslots field gracefully, since it's not 'owned' by
|
||||
* us, but by the LUKS2 spec */
|
||||
log_warning_errno(ks, "Failed to extract keyslot index from TPM2 JSON data token %i, skipping: %m", token);
|
||||
continue;
|
||||
}
|
||||
|
||||
w = json_variant_by_key(v, "tpm2-pcrs");
|
||||
if (!w || !json_variant_is_array(w))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
@ -125,6 +134,9 @@ int find_tpm2_auto_data(
|
||||
search_pcr_mask != pcr_mask) /* PCR mask doesn't match what is configured, ignore this entry */
|
||||
continue;
|
||||
|
||||
assert(keyslot < 0);
|
||||
keyslot = ks;
|
||||
|
||||
assert(pcr_bank == UINT16_MAX);
|
||||
assert(primary_alg == TPM2_ALG_ECC);
|
||||
|
||||
@ -184,11 +196,6 @@ int find_tpm2_auto_data(
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Invalid base64 data in 'tpm2-policy-hash' field.");
|
||||
|
||||
assert(keyslot < 0);
|
||||
keyslot = cryptsetup_get_keyslot_from_token(v);
|
||||
if (keyslot < 0)
|
||||
return log_error_errno(keyslot, "Failed to extract keyslot index from TPM2 JSON data: %m");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,9 @@
|
||||
#include "unaligned.h"
|
||||
|
||||
static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) {
|
||||
assert(id);
|
||||
assert(state);
|
||||
|
||||
siphash24_compress(id->chassis_id, id->chassis_id_size, state);
|
||||
siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state);
|
||||
siphash24_compress(id->port_id, id->port_id_size, state);
|
||||
@ -18,16 +21,27 @@ static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash
|
||||
}
|
||||
|
||||
int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y) {
|
||||
assert(x);
|
||||
assert(y);
|
||||
|
||||
return memcmp_nn(x->chassis_id, x->chassis_id_size, y->chassis_id, y->chassis_id_size)
|
||||
?: memcmp_nn(x->port_id, x->port_id_size, y->port_id, y->port_id_size);
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(lldp_neighbor_hash_ops, LLDPNeighborID, lldp_neighbor_id_hash_func, lldp_neighbor_id_compare_func,
|
||||
sd_lldp_neighbor, lldp_neighbor_unlink);
|
||||
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
lldp_neighbor_hash_ops,
|
||||
LLDPNeighborID,
|
||||
lldp_neighbor_id_hash_func,
|
||||
lldp_neighbor_id_compare_func,
|
||||
sd_lldp_neighbor,
|
||||
lldp_neighbor_unlink);
|
||||
|
||||
int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
|
||||
const sd_lldp_neighbor *x = a, *y = b;
|
||||
|
||||
assert(x);
|
||||
assert(y);
|
||||
|
||||
return CMP(x->until, y->until);
|
||||
}
|
||||
|
||||
@ -41,8 +55,9 @@ _public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) {
|
||||
return n;
|
||||
}
|
||||
|
||||
static void lldp_neighbor_free(sd_lldp_neighbor *n) {
|
||||
assert(n);
|
||||
static sd_lldp_neighbor *lldp_neighbor_free(sd_lldp_neighbor *n) {
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
free(n->id.port_id);
|
||||
free(n->id.chassis_id);
|
||||
@ -52,7 +67,7 @@ static void lldp_neighbor_free(sd_lldp_neighbor *n) {
|
||||
free(n->mud_url);
|
||||
free(n->chassis_id_as_string);
|
||||
free(n->port_id_as_string);
|
||||
free(n);
|
||||
return mfree(n);
|
||||
}
|
||||
|
||||
_public_ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) {
|
||||
|
||||
@ -56,15 +56,18 @@ int lldp_network_bind_raw_socket(int ifindex) {
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
/* customer bridge */
|
||||
r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
/* non TPMR bridge */
|
||||
mreq.mr_address[ETH_ALEN - 1] = 0x03;
|
||||
r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
/* nearest bridge */
|
||||
mreq.mr_address[ETH_ALEN - 1] = 0x0E;
|
||||
r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
if (r < 0)
|
||||
|
||||
@ -147,11 +147,11 @@ static int lldp_rx_add_neighbor(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
|
||||
/* Then, make room for at least one new neighbor */
|
||||
lldp_rx_make_space(lldp_rx, 1);
|
||||
|
||||
r = hashmap_put(lldp_rx->neighbor_by_id, &n->id, n);
|
||||
r = hashmap_ensure_put(&lldp_rx->neighbor_by_id, &lldp_neighbor_hash_ops, &n->id, n);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = prioq_put(lldp_rx->neighbor_by_expiry, n, &n->prioq_idx);
|
||||
r = prioq_ensure_put(&lldp_rx->neighbor_by_expiry, lldp_neighbor_prioq_compare_func, n, &n->prioq_idx);
|
||||
if (r < 0) {
|
||||
assert_se(hashmap_remove(lldp_rx->neighbor_by_id, &n->id) == n);
|
||||
goto finish;
|
||||
@ -178,16 +178,12 @@ static int lldp_rx_handle_datagram(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
|
||||
assert(n);
|
||||
|
||||
r = lldp_neighbor_parse(n);
|
||||
if (r == -EBADMSG) /* Ignore bad messages */
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = lldp_rx_add_neighbor(lldp_rx, n);
|
||||
if (r < 0) {
|
||||
log_lldp_rx_errno(lldp_rx, r, "Failed to add datagram. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_lldp_rx_errno(lldp_rx, r, "Failed to add datagram. Ignoring.");
|
||||
|
||||
log_lldp_rx(lldp_rx, "Successfully processed LLDP datagram.");
|
||||
return 0;
|
||||
@ -209,8 +205,10 @@ static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents
|
||||
}
|
||||
|
||||
n = lldp_neighbor_new(space);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
if (!n) {
|
||||
log_oom_debug();
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
|
||||
if (length < 0) {
|
||||
@ -232,7 +230,8 @@ static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents
|
||||
else
|
||||
triple_timestamp_get(&n->timestamp);
|
||||
|
||||
return lldp_rx_handle_datagram(lldp_rx, n);
|
||||
(void) lldp_rx_handle_datagram(lldp_rx, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lldp_rx_reset(sd_lldp_rx *lldp_rx) {
|
||||
@ -243,6 +242,13 @@ static void lldp_rx_reset(sd_lldp_rx *lldp_rx) {
|
||||
lldp_rx->fd = safe_close(lldp_rx->fd);
|
||||
}
|
||||
|
||||
int sd_lldp_rx_is_running(sd_lldp_rx *lldp_rx) {
|
||||
if (!lldp_rx)
|
||||
return false;
|
||||
|
||||
return lldp_rx->fd >= 0;
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_start(sd_lldp_rx *lldp_rx) {
|
||||
int r;
|
||||
|
||||
@ -250,7 +256,7 @@ _public_ int sd_lldp_rx_start(sd_lldp_rx *lldp_rx) {
|
||||
assert_return(lldp_rx->event, -EINVAL);
|
||||
assert_return(lldp_rx->ifindex > 0, -EINVAL);
|
||||
|
||||
if (lldp_rx->fd >= 0)
|
||||
if (sd_lldp_rx_is_running(lldp_rx))
|
||||
return 0;
|
||||
|
||||
assert(!lldp_rx->io_event_source);
|
||||
@ -278,10 +284,7 @@ fail:
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx) {
|
||||
if (!lldp_rx)
|
||||
return 0;
|
||||
|
||||
if (lldp_rx->fd < 0)
|
||||
if (!sd_lldp_rx_is_running(lldp_rx))
|
||||
return 0;
|
||||
|
||||
log_lldp_rx(lldp_rx, "Stopping LLDP client");
|
||||
@ -296,7 +299,7 @@ _public_ int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64
|
||||
int r;
|
||||
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(lldp_rx->fd < 0, -EBUSY);
|
||||
assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
|
||||
assert_return(!lldp_rx->event, -EBUSY);
|
||||
|
||||
if (event)
|
||||
@ -313,10 +316,11 @@ _public_ int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx) {
|
||||
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(lldp_rx->fd < 0, -EBUSY);
|
||||
assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
|
||||
|
||||
lldp_rx->io_event_source = sd_event_source_disable_unref(lldp_rx->io_event_source);
|
||||
lldp_rx->timer_event_source = sd_event_source_disable_unref(lldp_rx->timer_event_source);
|
||||
lldp_rx->event = sd_event_unref(lldp_rx->event);
|
||||
return 0;
|
||||
}
|
||||
@ -339,7 +343,7 @@ _public_ int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t
|
||||
_public_ int sd_lldp_rx_set_ifindex(sd_lldp_rx *lldp_rx, int ifindex) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(lldp_rx->fd < 0, -EBUSY);
|
||||
assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
|
||||
|
||||
lldp_rx->ifindex = ifindex;
|
||||
return 0;
|
||||
@ -363,11 +367,11 @@ const char *sd_lldp_rx_get_ifname(sd_lldp_rx *lldp_rx) {
|
||||
}
|
||||
|
||||
static sd_lldp_rx *lldp_rx_free(sd_lldp_rx *lldp_rx) {
|
||||
assert(lldp_rx);
|
||||
if (!lldp_rx)
|
||||
return NULL;
|
||||
|
||||
lldp_rx_reset(lldp_rx);
|
||||
|
||||
sd_event_source_unref(lldp_rx->timer_event_source);
|
||||
sd_lldp_rx_detach_event(lldp_rx);
|
||||
|
||||
lldp_rx_flush_neighbors(lldp_rx);
|
||||
@ -382,7 +386,6 @@ DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp_rx, sd_lldp_rx, lldp_rx_free);
|
||||
|
||||
_public_ int sd_lldp_rx_new(sd_lldp_rx **ret) {
|
||||
_cleanup_(sd_lldp_rx_unrefp) sd_lldp_rx *lldp_rx = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
@ -397,23 +400,10 @@ _public_ int sd_lldp_rx_new(sd_lldp_rx **ret) {
|
||||
.capability_mask = UINT16_MAX,
|
||||
};
|
||||
|
||||
lldp_rx->neighbor_by_id = hashmap_new(&lldp_neighbor_hash_ops);
|
||||
if (!lldp_rx->neighbor_by_id)
|
||||
return -ENOMEM;
|
||||
|
||||
r = prioq_ensure_allocated(&lldp_rx->neighbor_by_expiry, lldp_neighbor_prioq_compare_func);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(lldp_rx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_neighbor * const *b) {
|
||||
return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id);
|
||||
}
|
||||
|
||||
static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
sd_lldp_rx *lldp_rx = userdata;
|
||||
int r;
|
||||
@ -437,6 +427,7 @@ static int lldp_rx_start_timer(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *neighbor)
|
||||
sd_lldp_neighbor *n;
|
||||
|
||||
assert(lldp_rx);
|
||||
assert(lldp_rx->event);
|
||||
|
||||
if (neighbor)
|
||||
lldp_neighbor_start_ttl(neighbor);
|
||||
@ -445,9 +436,6 @@ static int lldp_rx_start_timer(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *neighbor)
|
||||
if (!n)
|
||||
return event_source_disable(lldp_rx->timer_event_source);
|
||||
|
||||
if (!lldp_rx->event)
|
||||
return 0;
|
||||
|
||||
return event_reset_time(lldp_rx->event, &lldp_rx->timer_event_source,
|
||||
clock_boottime_or_monotonic(),
|
||||
n->until, 0,
|
||||
@ -455,9 +443,19 @@ static int lldp_rx_start_timer(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *neighbor)
|
||||
lldp_rx->event_priority, "lldp-rx-timer", true);
|
||||
}
|
||||
|
||||
static inline int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_neighbor * const *b) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(*a);
|
||||
assert(*b);
|
||||
|
||||
return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id);
|
||||
}
|
||||
|
||||
_public_ int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***ret) {
|
||||
sd_lldp_neighbor **l = NULL, *n;
|
||||
int k = 0, r;
|
||||
_cleanup_free_ sd_lldp_neighbor **l = NULL;
|
||||
sd_lldp_neighbor *n;
|
||||
int k = 0;
|
||||
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
@ -471,12 +469,6 @@ _public_ int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***r
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
r = lldp_rx_start_timer(lldp_rx, NULL);
|
||||
if (r < 0) {
|
||||
free(l);
|
||||
return r;
|
||||
}
|
||||
|
||||
HASHMAP_FOREACH(n, lldp_rx->neighbor_by_id)
|
||||
l[k++] = sd_lldp_neighbor_ref(n);
|
||||
|
||||
@ -484,7 +476,7 @@ _public_ int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***r
|
||||
|
||||
/* Return things in a stable order */
|
||||
typesafe_qsort(l, k, neighbor_compare_func);
|
||||
*ret = l;
|
||||
*ret = TAKE_PTR(l);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
@ -1714,6 +1714,7 @@ static int run(int argc, char* argv[]) {
|
||||
if (!strv_isempty(arg_cmdline) &&
|
||||
arg_transport == BUS_TRANSPORT_LOCAL &&
|
||||
!strv_find_startswith(arg_property, "RootDirectory=") &&
|
||||
!strv_find_startswith(arg_property, "ExecSearchPath=") &&
|
||||
!strv_find_startswith(arg_property, "RootImage=")) {
|
||||
/* Patch in an absolute path to fail early for user convenience, but only when we can do it
|
||||
* (i.e. we will be running from the same file system). This also uses the user's $PATH,
|
||||
|
||||
@ -969,6 +969,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||
"InaccessiblePaths",
|
||||
"ExecPaths",
|
||||
"NoExecPaths",
|
||||
"ExecSearchPath",
|
||||
"RuntimeDirectory",
|
||||
"StateDirectory",
|
||||
"CacheDirectory",
|
||||
@ -1998,6 +1999,9 @@ static int bus_append_scope_property(sd_bus_message *m, const char *field, const
|
||||
if (streq(field, "RuntimeMaxSec"))
|
||||
return bus_append_parse_sec_rename(m, field, eq);
|
||||
|
||||
if (streq(field, "RuntimeRandomizedExtraSec"))
|
||||
return bus_append_parse_sec_rename(m, field, eq);
|
||||
|
||||
if (streq(field, "TimeoutStopSec"))
|
||||
return bus_append_parse_sec_rename(m, field, eq);
|
||||
|
||||
@ -2030,6 +2034,7 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
|
||||
"TimeoutStopSec",
|
||||
"TimeoutAbortSec",
|
||||
"RuntimeMaxSec",
|
||||
"RuntimeRandomizedExtraSec",
|
||||
"WatchdogSec"))
|
||||
return bus_append_parse_sec_rename(m, field, eq);
|
||||
|
||||
|
||||
@ -50,6 +50,7 @@ sd_lldp_rx *sd_lldp_rx_unref(sd_lldp_rx *lldp_rx);
|
||||
|
||||
int sd_lldp_rx_start(sd_lldp_rx *lldp_rx);
|
||||
int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx);
|
||||
int sd_lldp_rx_is_running(sd_lldp_rx *lldp_rx);
|
||||
|
||||
int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64_t priority);
|
||||
int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx);
|
||||
|
||||
@ -371,7 +371,7 @@ tests += [
|
||||
[['src/test/test-hashmap.c',
|
||||
'src/test/test-hashmap-plain.c',
|
||||
test_hashmap_ordered_c],
|
||||
[], [], [], '', 'timeout=90'],
|
||||
[], [], [], '', 'timeout=180'],
|
||||
|
||||
[['src/test/test-set.c'],
|
||||
[libbasic]],
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include "capability-util.h"
|
||||
#include "cpu-set-util.h"
|
||||
#include "copy.h"
|
||||
#include "dropin.h"
|
||||
#include "errno-list.h"
|
||||
#include "fd-util.h"
|
||||
@ -28,6 +29,7 @@
|
||||
#include "static-destruct.h"
|
||||
#include "stat-util.h"
|
||||
#include "tests.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "unit.h"
|
||||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
@ -273,6 +275,93 @@ static void test_exec_workingdirectory(Manager *m) {
|
||||
(void) rm_rf("/tmp/test-exec_workingdirectory", REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||
}
|
||||
|
||||
static void test_exec_execsearchpath(Manager *m) {
|
||||
assert_se(mkdir_p("/tmp/test-exec_execsearchpath", 0755) >= 0);
|
||||
|
||||
assert_se(copy_file("/bin/ls", "/tmp/test-exec_execsearchpath/ls_temp", 0, 0777, 0, 0, COPY_REPLACE) >= 0);
|
||||
|
||||
test(m, "exec-execsearchpath.service", 0, CLD_EXITED);
|
||||
|
||||
assert_se(rm_rf("/tmp/test-exec_execsearchpath", REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
|
||||
|
||||
test(m, "exec-execsearchpath.service", EXIT_EXEC, CLD_EXITED);
|
||||
}
|
||||
|
||||
static void test_exec_execsearchpath_specifier(Manager *m) {
|
||||
test(m, "exec-execsearchpath-unit-specifier.service", 0, CLD_EXITED);
|
||||
}
|
||||
|
||||
static void test_exec_execsearchpath_environment(Manager *m) {
|
||||
test(m, "exec-execsearchpath-environment.service", 0, CLD_EXITED);
|
||||
test(m, "exec-execsearchpath-environment-path-set.service", 0, CLD_EXITED);
|
||||
}
|
||||
|
||||
static void test_exec_execsearchpath_environment_files(Manager *m) {
|
||||
static const char path_not_set[] =
|
||||
"VAR1='word1 word2'\n"
|
||||
"VAR2=word3 \n"
|
||||
"# comment1\n"
|
||||
"\n"
|
||||
"; comment2\n"
|
||||
" ; # comment3\n"
|
||||
"line without an equal\n"
|
||||
"VAR3='$word 5 6'\n"
|
||||
"VAR4='new\nline'\n"
|
||||
"VAR5=password\\with\\backslashes";
|
||||
|
||||
static const char path_set[] =
|
||||
"VAR1='word1 word2'\n"
|
||||
"VAR2=word3 \n"
|
||||
"# comment1\n"
|
||||
"\n"
|
||||
"; comment2\n"
|
||||
" ; # comment3\n"
|
||||
"line without an equal\n"
|
||||
"VAR3='$word 5 6'\n"
|
||||
"VAR4='new\nline'\n"
|
||||
"VAR5=password\\with\\backslashes\n"
|
||||
"PATH=/usr";
|
||||
|
||||
int r;
|
||||
|
||||
r = write_string_file("/tmp/test-exec_execsearchpath_environmentfile.conf", path_not_set, WRITE_STRING_FILE_CREATE);
|
||||
|
||||
assert_se(r == 0);
|
||||
|
||||
test(m, "exec-execsearchpath-environmentfile.service", 0, CLD_EXITED);
|
||||
|
||||
(void) unlink("/tmp/test-exec_environmentfile.conf");
|
||||
|
||||
|
||||
r = write_string_file("/tmp/test-exec_execsearchpath_environmentfile-set.conf", path_set, WRITE_STRING_FILE_CREATE);
|
||||
|
||||
assert_se(r == 0);
|
||||
|
||||
test(m, "exec-execsearchpath-environmentfile-set.service", 0, CLD_EXITED);
|
||||
|
||||
(void) unlink("/tmp/test-exec_environmentfile-set.conf");
|
||||
}
|
||||
|
||||
static void test_exec_execsearchpath_passenvironment(Manager *m) {
|
||||
assert_se(setenv("VAR1", "word1 word2", 1) == 0);
|
||||
assert_se(setenv("VAR2", "word3", 1) == 0);
|
||||
assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
|
||||
assert_se(setenv("VAR4", "new\nline", 1) == 0);
|
||||
assert_se(setenv("VAR5", "passwordwithbackslashes", 1) == 0);
|
||||
|
||||
test(m, "exec-execsearchpath-passenvironment.service", 0, CLD_EXITED);
|
||||
|
||||
assert_se(setenv("PATH", "/usr", 1) == 0);
|
||||
test(m, "exec-execsearchpath-passenvironment-set.service", 0, CLD_EXITED);
|
||||
|
||||
assert_se(unsetenv("VAR1") == 0);
|
||||
assert_se(unsetenv("VAR2") == 0);
|
||||
assert_se(unsetenv("VAR3") == 0);
|
||||
assert_se(unsetenv("VAR4") == 0);
|
||||
assert_se(unsetenv("VAR5") == 0);
|
||||
assert_se(unsetenv("PATH") == 0);
|
||||
}
|
||||
|
||||
static void test_exec_personality(Manager *m) {
|
||||
#if defined(__x86_64__)
|
||||
test(m, "exec-personality-x86-64.service", 0, CLD_EXITED);
|
||||
@ -1089,11 +1178,16 @@ int main(int argc, char *argv[]) {
|
||||
entry(test_exec_unsetenvironment),
|
||||
entry(test_exec_user),
|
||||
entry(test_exec_workingdirectory),
|
||||
entry(test_exec_execsearchpath),
|
||||
entry(test_exec_execsearchpath_environment),
|
||||
entry(test_exec_execsearchpath_environment_files),
|
||||
entry(test_exec_execsearchpath_passenvironment),
|
||||
{},
|
||||
};
|
||||
static const test_entry system_tests[] = {
|
||||
entry(test_exec_dynamicuser),
|
||||
entry(test_exec_specifier),
|
||||
entry(test_exec_execsearchpath_specifier),
|
||||
entry(test_exec_systemcallfilter_system),
|
||||
{},
|
||||
};
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "exec-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "macro.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
@ -14,6 +15,7 @@
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tests.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "util.h"
|
||||
|
||||
static void test_print_paths(void) {
|
||||
@ -201,15 +203,18 @@ static void test_path_equal_root(void) {
|
||||
|
||||
static void test_find_executable_full(void) {
|
||||
char *p;
|
||||
char* test_file_name;
|
||||
_cleanup_close_ int fd = -1;
|
||||
char fn[] = "/tmp/test-XXXXXX";
|
||||
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(find_executable_full("sh", NULL, true, &p, NULL) == 0);
|
||||
assert_se(find_executable_full("sh", NULL, NULL, true, &p, NULL) == 0);
|
||||
puts(p);
|
||||
assert_se(streq(basename(p), "sh"));
|
||||
free(p);
|
||||
|
||||
assert_se(find_executable_full("sh", NULL, false, &p, NULL) == 0);
|
||||
assert_se(find_executable_full("sh", NULL, NULL, false, &p, NULL) == 0);
|
||||
puts(p);
|
||||
assert_se(streq(basename(p), "sh"));
|
||||
free(p);
|
||||
@ -221,18 +226,31 @@ static void test_find_executable_full(void) {
|
||||
|
||||
assert_se(unsetenv("PATH") == 0);
|
||||
|
||||
assert_se(find_executable_full("sh", NULL, true, &p, NULL) == 0);
|
||||
assert_se(find_executable_full("sh", NULL, NULL, true, &p, NULL) == 0);
|
||||
puts(p);
|
||||
assert_se(streq(basename(p), "sh"));
|
||||
free(p);
|
||||
|
||||
assert_se(find_executable_full("sh", NULL, false, &p, NULL) == 0);
|
||||
assert_se(find_executable_full("sh", NULL, NULL, false, &p, NULL) == 0);
|
||||
puts(p);
|
||||
assert_se(streq(basename(p), "sh"));
|
||||
free(p);
|
||||
|
||||
if (oldpath)
|
||||
assert_se(setenv("PATH", oldpath, true) >= 0);
|
||||
|
||||
assert_se((fd = mkostemp_safe(fn)) >= 0);
|
||||
assert_se(fchmod(fd, 0755) >= 0);
|
||||
|
||||
test_file_name = basename(fn);
|
||||
|
||||
assert_se(find_executable_full(test_file_name, NULL, STRV_MAKE("/doesnotexist", "/tmp", "/bin"), false, &p, NULL) == 0);
|
||||
puts(p);
|
||||
assert_se(streq(p, fn));
|
||||
free(p);
|
||||
|
||||
(void) unlink(fn);
|
||||
assert_se(find_executable_full(test_file_name, NULL, STRV_MAKE("/doesnotexist", "/tmp", "/bin"), false, &p, NULL) == -ENOENT);
|
||||
}
|
||||
|
||||
static void test_find_executable(const char *self) {
|
||||
@ -277,7 +295,7 @@ static void test_find_executable_exec_one(const char *path) {
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
r = find_executable_full(path, NULL, false, &t, &fd);
|
||||
r = find_executable_full(path, NULL, NULL, false, &t, &fd);
|
||||
|
||||
log_info_errno(r, "%s: %s → %s: %d/%m", __func__, path, t ?: "-", fd);
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ AllowedMemoryNodes=
|
||||
AmbientCapabilities=
|
||||
AppArmorProfile=
|
||||
BPFProgram=
|
||||
ExecSearchPath=
|
||||
BindPaths=
|
||||
BindReadOnlyPaths=
|
||||
BlockIOAccounting=
|
||||
|
||||
@ -50,6 +50,7 @@ NetClass=
|
||||
RestartKillSignal=
|
||||
RestrictNetworkInterfaces=
|
||||
RuntimeMaxSec=
|
||||
RuntimeRandomizedExtraSec=
|
||||
SendSIGHUP=
|
||||
SendSIGKILL=
|
||||
Slice=
|
||||
|
||||
@ -31,6 +31,7 @@ AssertUser=
|
||||
AssertVirtualization=
|
||||
BPFProgram=
|
||||
Before=
|
||||
ExecSearchPath=
|
||||
BindTo=
|
||||
BindsTo=
|
||||
CollectMode=
|
||||
@ -289,6 +290,7 @@ RuntimeDirectory=
|
||||
RuntimeDirectoryMode=
|
||||
RuntimeDirectoryPreserve=
|
||||
RuntimeMaxSec=
|
||||
RuntimeRandomizedExtraSec=
|
||||
SELinuxContext=
|
||||
SecureBits=
|
||||
SendSIGHUP=
|
||||
|
||||
@ -7,6 +7,7 @@ AmbientCapabilities=
|
||||
AppArmorProfile=
|
||||
BPFProgram=
|
||||
Backlog=
|
||||
ExecSearchPath=
|
||||
BindIPv6Only=
|
||||
BindPaths=
|
||||
BindReadOnlyPaths=
|
||||
|
||||
@ -5,6 +5,7 @@ AllowedMemoryNodes=
|
||||
AmbientCapabilities=
|
||||
AppArmorProfile=
|
||||
BPFProgram=
|
||||
ExecSearchPath=
|
||||
BindPaths=
|
||||
BindReadOnlyPaths=
|
||||
BlockIOAccounting=
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c 'test "$$PATH" = "/usr" && test "$$VAR1" = word3 && test "$$VAR2" = "\\$$word 5 6"'
|
||||
Type=oneshot
|
||||
ExecSearchPath=/tmp:/bin
|
||||
Environment="PATH=/usr" VAR1=word3 "VAR2=$word 5 6"
|
||||
@ -0,0 +1,5 @@
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6" && test "$$PATH" = "/tmp:/bin"'
|
||||
Type=oneshot
|
||||
ExecSearchPath=/tmp:/bin
|
||||
Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
|
||||
@ -0,0 +1,8 @@
|
||||
[Unit]
|
||||
Description=Test for ExecSearchPath with EnvironmentFile where EnvironmentFile sets PATH
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6" && test "$$VAR4" = "new\nline" && test "$$VAR5" = passwordwithbackslashes && test "$$PATH" = /usr'
|
||||
Type=oneshot
|
||||
EnvironmentFile=/tmp/test-exec_execsearchpath_environmentfile-set.conf
|
||||
ExecSearchPath=/tmp:/bin
|
||||
@ -0,0 +1,8 @@
|
||||
[Unit]
|
||||
Description=Test for ExecSearchPath with EnvironmentFile where EnvironmentFile does not set PATH
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6" && test "$$VAR4" = "new\nline" && test "$$VAR5" = passwordwithbackslashes && test "$$PATH" = "/tmp:/bin"'
|
||||
Type=oneshot
|
||||
ExecSearchPath=/tmp:/bin
|
||||
EnvironmentFile=/tmp/test-exec_execsearchpath_environmentfile.conf
|
||||
@ -0,0 +1,8 @@
|
||||
[Unit]
|
||||
Description=Test for PassEnvironment with ExecSearchPath with PATH set by user
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6" && test "$$VAR4" = "new\nline" && test "$$VAR5" = passwordwithbackslashes && test "$$PATH" = "/usr"'
|
||||
Type=oneshot
|
||||
PassEnvironment=VAR1 VAR2 VAR3 VAR4 VAR5 PATH
|
||||
ExecSearchPath=/tmp:/bin
|
||||
@ -0,0 +1,8 @@
|
||||
[Unit]
|
||||
Description=Test for PassEnvironment with ExecSearchPath with PATH not set by user
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6" && test "$$VAR4" = "new\nline" && test "$$VAR5" = passwordwithbackslashes && test "$$PATH" = "/tmp:/bin"'
|
||||
Type=oneshot
|
||||
PassEnvironment=VAR1 VAR2 VAR3 VAR4 VAR5
|
||||
ExecSearchPath=/tmp:/bin
|
||||
@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Test for specifiers with exec search path
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecSearchPath=/tmp:/bin:/usr/bin:%V
|
||||
ExecStart=/bin/sh -x -c 'test %V = /var/tmp && test "$$PATH" = "/tmp:/bin:/usr/bin:/var/tmp"'
|
||||
4
test/test-execute/exec-execsearchpath.service
Normal file
4
test/test-execute/exec-execsearchpath.service
Normal file
@ -0,0 +1,4 @@
|
||||
[Service]
|
||||
ExecStart=ls_temp
|
||||
Type=oneshot
|
||||
ExecSearchPath=/tmp/test-exec_execsearchpath
|
||||
Loading…
x
Reference in New Issue
Block a user