Allow systemd-executor to be compiled into a single binary.
The existing -Dlink-executor-shared=true|false is extended to also
allow -Dlink-executor-shared=single (*). The new mode is opt-in,
to allow experimentation and introduce this smoothly.
This saves a little space, but not as much as I expected:
$ ls -l build/{systemd,systemd-executor} build-new/systemd
-rwxr-xr-x 1 zbyszek zbyszek 631520 May 25 22:44 build/systemd
-rwxr-xr-x 1 zbyszek zbyszek 670464 May 25 22:44 build/systemd-executor
-rwxr-xr-x 1 zbyszek zbyszek
1214488 May 25 22:45 build-new/systemd
(This is with -Dbuildtype=debugoptimized -Db_lto=true).
The combined binary is slightly smaller than the sum of the separate
ones, but not much. In both cases, the binaries are linked to
libsystemd-core which is 10MB, so the size of the binaries themselves
doesn't make much of a difference. The executor needs exec-invoke.c
which is huge and not shared with anything else.
Longer term, I want to allow systemd to be linked statically. In
that case, having systemd-executor separate would be very painful.
So the option to use a multicall binary will be necessary.
Previously, we stored the resolved path to systemd-executor and
used it argv[0]. I don't think this was useful. After all, normally
we would use the non-resolved original path as argv[0]. So that
part is dropped, and the resolved path is only logged, but
"systemd-executor" is always used as argv[0]. This makes the
multicall binary work reliably, no matter what the actual file
name is.
(*) This means that compat as the commandline level is maintained:
'meson setup build -Dlink-executor-shared=true …' works as before.
Unfortunately, when using an existing build directory, meson chokes
on the type change and refuses to reconfigure the directory or change
the option or do anything useful. I think meson is DTWT here, but
this is hard to fix. So the build directory probably needs to be
recreated.
# We'll set this to '1' for EFI builds in a different place.
conf.set10('SD_BOOT', false)
+link_executor_shared = get_option('link-executor-shared')
+conf.set10('BUILD_EXECUTOR_SINGLE', link_executor_shared == 'single')
+
# Create a title-less summary section early, so it ends up first in the output.
# More items are added later after they have been detected.
summary({
description : 'sbin is not a symlink to bin')
option('link-udev-shared', type : 'boolean',
description : 'link systemd-udevd and its helpers to libsystemd-shared.so')
-option('link-executor-shared', type : 'boolean',
- description : 'link systemd-executor to libsystemd-shared.so and libsystemd-core.so')
+option('link-executor-shared', type : 'combo', choices : ['true', 'false', 'single'],
+ description : 'link systemd-executor to libsystemd-shared.so and libsystemd-core.so, or into systemd')
option('link-systemctl-shared', type: 'boolean',
description : 'link systemctl against libsystemd-shared.so')
option('link-networkd-shared', type: 'boolean',
assert(unit);
assert(unit->manager);
assert(unit->manager->executor_fd >= 0);
- assert(unit->manager->executor_path);
assert(command);
assert(context);
assert(params);
/* The executor binary is pinned, to avoid compatibility problems during upgrades. */
r = posix_spawn_wrapper(
FORMAT_PROC_FD_PATH(unit->manager->executor_fd),
- STRV_MAKE(unit->manager->executor_path,
+ STRV_MAKE("systemd-executor",
"--deserialize", serialization_fd_number,
"--log-level", max_log_levels,
"--log-target", log_target_to_string(manager_get_executor_log_target(unit->manager))),
#include "exec-invoke.h"
#include "execute.h"
#include "execute-serialize.h"
+#include "executor.h"
#include "exit-status.h"
#include "fd-util.h"
#include "fdset.h"
if (r < 0)
return log_oom();
- r = option_parser_get_help_table(&options);
+ r = option_parser_get_help_table_ns("systemd-executor", &options);
if (r < 0)
return r;
assert(argc >= 0);
assert(argv);
- OptionParser opts = { argc, argv };
+ OptionParser opts = { argc, argv, .namespace = "systemd-executor" };
FOREACH_OPTION_OR_RETURN(c, &opts)
switch (c) {
+ OPTION_NAMESPACE("systemd-executor"): {}
+
OPTION_COMMON_HELP:
return help();
return exit_status;
}
-int main(int argc, char *argv[]) {
+int run_executor(int argc, char *argv[]) {
int r;
/* We use safe_fork() for spawning sd-pam helper process, which internally calls rename_process().
return r < 0 ? EXIT_FAILURE : r;
}
+
+#if !BUILD_EXECUTOR_SINGLE
+_alias_(run_executor) main;
+#endif
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+int run_executor(int argc, char *argv[]);
#include "emergency-action.h"
#include "env-util.h"
#include "escape.h"
+#include "executor.h"
#include "extract-word.h"
#include "fd-util.h"
#include "fdset.h"
assert(argv);
int log_level_shift = getpid_cached() == 1 ? LOG_DEBUG - LOG_ERR : 0;
- OptionParser opts = { argc, argv, .log_level_shift = log_level_shift };
+ OptionParser opts = {
+ argc, argv,
+ .namespace = "systemd",
+ .log_level_shift = log_level_shift,
+ };
/* Note: when new options are added here, also add them to the exclusion list in proc-cmdline.c! */
FOREACH_OPTION(c, &opts)
switch (c) {
+ OPTION_NAMESPACE("systemd"): {}
+
OPTION_COMMON_HELP:
arg_action = ACTION_HELP;
break;
_cleanup_(table_unrefp) Table *options = NULL;
int r;
- r = option_parser_get_help_table(&options);
+ r = option_parser_get_help_table_ns("systemd", &options);
if (r < 0)
return r;
return 0;
}
-int main(int argc, char *argv[]) {
+static int run_systemd(int argc, char *argv[]) {
dual_timestamp
initrd_timestamp = DUAL_TIMESTAMP_NULL,
userspace_timestamp = DUAL_TIMESTAMP_NULL,
reset_arguments();
return retval;
}
+
+int main(int argc, char *argv[]) {
+#if BUILD_EXECUTOR_SINGLE
+ if (invoked_as(argv, "executor"))
+ return run_executor(argc, argv);
+#endif
+ return run_systemd(argc, argv);
+}
return scope == RUNTIME_SCOPE_SYSTEM ? DEFAULT_TIMEOUT_USEC : DEFAULT_USER_TIMEOUT_USEC;
}
+static int pin_executor_binary(int *ret_fd) {
+ _cleanup_free_ char *path = NULL;
+
+ assert(ret_fd);
+
+#if BUILD_EXECUTOR_SINGLE
+ int r;
+
+ r = open_and_check_executable("/proc/self/exe", /* root= */ NULL, &path, ret_fd);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to pin executor binary %s: %m", "/proc/self/exe");
+#else
+ int fd;
+
+ fd = pin_callout_binary(SYSTEMD_EXECUTOR_BINARY_PATH, &path);
+ if (fd < 0)
+ return log_debug_errno(fd, "Failed to pin executor binary %s: %m", SYSTEMD_EXECUTOR_BINARY_PATH);
+ *ret_fd = fd;
+#endif
+
+ log_debug("Using systemd-executor binary %s.", path);
+ return 0;
+}
+
int manager_new(RuntimeScope runtime_scope, ManagerTestRunFlags test_run_flags, Manager **ret) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
}
if (!FLAGS_SET(test_run_flags, MANAGER_TEST_DONT_OPEN_EXECUTOR)) {
- m->executor_fd = pin_callout_binary(SYSTEMD_EXECUTOR_BINARY_PATH, &m->executor_path);
- if (m->executor_fd < 0)
- return log_debug_errno(m->executor_fd, "Failed to pin executor binary: %m");
-
- log_debug("Using systemd-executor binary from '%s'.", m->executor_path);
+ r = pin_executor_binary(&m->executor_fd);
+ if (r < 0)
+ return r;
}
/* Note that we do not set up the notify fd here. We do that after deserialization,
safe_close(m->restrict_fsaccess_bss_map_fd);
safe_close(m->executor_fd);
- free(m->executor_path);
return mfree(m);
}
/* Pin the systemd-executor binary, so that it never changes until re-exec, ensuring we don't have
* serialization/deserialization compatibility issues during upgrades. */
- char *executor_path;
int executor_fd;
unsigned soft_reboots_count;
install : true,
install_dir : pkglibdir)
-executor_libs = get_option('link-executor-shared') ? \
- [
- libcore,
- libshared,
- ] : [
- libc_wrapper_static,
- libcore_static,
- libshared_static,
- libbasic_static,
- libsystemd_static,
+core_libs_static = [
+ libc_wrapper_static,
+ libcore_static,
+ libshared_static,
+ libbasic_static,
+ libsystemd_static,
+]
+core_libs_shared = [
+ libcore,
+ libshared,
+]
+
+systemd_deps = [
+ libapparmor_cflags,
+ libkmod_cflags,
+ libmount_cflags,
+ libseccomp_cflags,
+ libselinux_cflags,
+]
+
+link_executor_shared = get_option('link-executor-shared')
+
+executor_libs = link_executor_shared == 'true' ? core_libs_shared : core_libs_static
+
+if link_executor_shared == 'single'
+ systemd_sources += systemd_executor_sources
+ systemd_deps += [
+ libbpf_cflags,
+ libcryptsetup_cflags,
+ libpam_cflags,
]
+endif
executables += [
libexec_template + {
'dbus' : true,
'public' : true,
'sources' : systemd_sources,
- 'link_with' : [
- libcore,
- libshared,
- ],
- 'dependencies' : [
- libapparmor_cflags,
- libkmod_cflags,
- libmount_cflags,
- libseccomp_cflags,
- libselinux_cflags,
- ],
- },
- libexec_template + {
- 'name' : 'systemd-executor',
- 'public' : true,
- 'sources' : systemd_executor_sources,
- 'link_with' : executor_libs,
- 'dependencies' : [
- libapparmor_cflags,
- libbpf_cflags,
- libcryptsetup_cflags,
- libmount_cflags,
- libpam_cflags,
- libseccomp_cflags,
- libselinux_cflags,
- ],
+ 'link_with' : core_libs_shared,
+ 'dependencies' : systemd_deps,
},
+
fuzz_template + {
'sources' : files('fuzz-unit-file.c'),
'link_with' : [
},
]
+if link_executor_shared == 'single'
+ # Symlink for external callers
+ install_symlink('systemd-executor',
+ pointing_to : 'systemd',
+ install_dir : libexecdir)
+else
+ executables += [
+ libexec_template + {
+ 'name' : 'systemd-executor',
+ 'public' : true,
+ 'sources' : systemd_executor_sources,
+ 'link_with' : executor_libs,
+ 'dependencies' : [
+ libapparmor_cflags,
+ libbpf_cflags,
+ libcryptsetup_cflags,
+ libmount_cflags,
+ libpam_cflags,
+ libseccomp_cflags,
+ libselinux_cflags,
+ ],
+ },
+ ]
+endif
+
in_files = [['system.conf', pkgconfigfiledir],
['user.conf', pkgconfigfiledir],
['org.freedesktop.systemd1.policy', polkitpolicydir]]