operate in device mode
- add NVMe authentication
+- **sigpwr.target** doesn't do anything useful. Consider hooking it up to
+ poweroff.target.
+
+- Provide a fallback in **rescue.service** that prints a fixed message
+ if sulogin-shell could not be started.
+
- support boot into nvme-over-tcp: add generator that allows specifying nvme
devices on kernel cmdline + credentials. Also maybe add interactive mode
(where the user is prompted for nvme info), in order to boot from other
#####################################################################
+# 'src/core' embeds a built-in copy of some unit files, so the unit file list
+# from 'units' must be defined first.
+subdir('units')
# systemd-analyze requires 'libcore'
subdir('src/core')
# systemd-networkd requires 'libsystemd_network'
subdir('sysctl.d')
subdir('sysusers.d')
subdir('tmpfiles.d')
-subdir('units')
install_subdir('factory/etc',
install_dir : factorydir)
--- /dev/null
+#!/usr/bin/env python3
+
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+# Embed the contents of unit files passed on the command line into a C array
+# initializer, so that the manager can fall back to a built-in copy when no
+# unit file is found on disk. Comment and empty lines are stripped to keep the
+# embedded strings small. The unit name is derived from each file's basename.
+
+import pathlib
+import string
+import sys
+
+PRINTABLE = set(string.printable) - set('\t\r\x0b\x0c')
+
+
+def strip_comments(text: str) -> str:
+ # Unit files use '#' and ';' as comment markers at the start of a line.
+ # fmt: off
+ lines = (line for line in text.splitlines()
+ if line and line[0] not in '#;')
+ return '\n'.join(lines) + '\n'
+
+
+def c_escape(text: str) -> str:
+ assert set(text) <= PRINTABLE
+ return text.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n')
+
+
+for path in sys.argv[1:]:
+ path = pathlib.Path(path)
+ data = strip_comments(path.read_text())
+ print(f'{{ "{path.name}", "{c_escape(data)}" }},')
#include "execute.h"
#include "extract-word.h"
#include "fd-util.h"
+#include "fileio.h"
#include "fstab-util.h"
#include "hashmap.h"
#include "hexdecoct.h"
#include "user-util.h"
#include "web-util.h"
+/* Built-in copies of a few essential unit files, embedded at build time. They are used as a fallback
+ * when no fragment for the unit is found on disk, so that the manager can reach a usable state even on
+ * a system that ships none of these unit files. */
+static const struct {
+ const char *name;
+ const char *data;
+} builtin_units[] = {
+# include "builtin-units.inc"
+};
+
static int parse_socket_protocol(const char *s) {
int r;
return 0;
}
+static const char* builtin_unit_lookup(const char *name) {
+ assert(name);
+
+ FOREACH_ELEMENT(i, builtin_units)
+ if (streq(i->name, name))
+ return i->data;
+
+ return NULL;
+}
+
int unit_load_fragment(Unit *u) {
int r;
r = config_parse(u->id, fragment, f,
UNIT_VTABLE(u)->sections,
config_item_perf_lookup, load_fragment_gperf_lookup,
- 0,
- u,
- NULL);
+ /* flags= */ 0,
+ /* userdata= */ u,
+ /* ret_stat= */ NULL);
if (r == -ENOEXEC)
log_unit_notice_errno(u, r, "Unit configuration has fatal error, unit will not be started.");
if (r < 0)
return r;
}
+ } else if (u->manager->runtime_scope == RUNTIME_SCOPE_SYSTEM) {
+ /* No fragment found on disk. For system units, fall back to a built-in copy if we have one
+ * embedded. This way the manager can reach a usable state even if none of these unit files
+ * are installed. On-disk files always take precedence (including masks), since we only get
+ * here when nothing was found in the lookup paths. */
+
+ const char *data = builtin_unit_lookup(u->id);
+ if (data) {
+ _cleanup_fclose_ FILE *f = NULL;
+
+ f = fmemopen_unlocked((void*) data, strlen(data), "re");
+ if (!f)
+ return log_oom();
+
+ log_unit_debug(u, "Loading built-in fragment for %s.", u->id);
+
+ u->load_state = UNIT_LOADED;
+ u->fragment_mtime = 0;
+
+ r = config_parse(u->id, u->id, f,
+ UNIT_VTABLE(u)->sections,
+ config_item_perf_lookup, load_fragment_gperf_lookup,
+ /* flags= */ 0,
+ /* userdata= */ u,
+ /* ret_stat= */ NULL);
+ if (r == -ENOEXEC)
+ log_unit_notice_errno(u, r, "Built-in unit configuration has fatal error, unit will not be started.");
+ if (r < 0)
+ return r;
+ }
}
/* Call merge_by_names with the name derived from the fragment path as the preferred name.
command : [awk, '-f', '@INPUT0@', '@INPUT1@'],
capture : true)
+generate_builtin_units = files('generate-builtin-units.py')
+builtin_units_inc = custom_target(
+ input : [generate_builtin_units, embedded_units],
+ output : 'builtin-units.inc',
+ command : [python, generate_builtin_units, embedded_units],
+ capture : true)
+
generate_bpf_delegate_configs = files('generate-bpf-delegate-configs.py')
bpf_delegate_configs_inc = custom_target(
input : [generate_bpf_delegate_configs, bpf_delegate_sources],
capture : true)
man_page_depends += bpf_delegate_xml
-generated_sources += [load_fragment_gperf_c, load_fragment_gperf_nulstr_c, bpf_delegate_configs_inc]
-libcore_sources += [load_fragment_gperf_c, load_fragment_gperf_nulstr_c, bpf_delegate_configs_inc]
+generated_sources += [load_fragment_gperf_c, load_fragment_gperf_nulstr_c, bpf_delegate_configs_inc, builtin_units_inc]
+libcore_sources += [load_fragment_gperf_c, load_fragment_gperf_nulstr_c, bpf_delegate_configs_inc, builtin_units_inc]
libcore_build_dir = meson.current_build_dir()
libcore_name = 'systemd-core-@0@'.format(shared_lib_tag)
core_includes = [include_directories('.'), includes]
udev_units = []
hwdb_units = []
+# Unit files whose contents are embedded into the manager binary, so that it can
+# fall back to a built-in copy when the file is not present on disk. Referenced
+# from src/core/meson.build.
+embedded_unit_names = [
+ 'basic.target',
+ 'exit.target',
+ 'final.target',
+ 'graphical.target',
+ 'halt.target',
+ 'kexec.target',
+ 'multi-user.target',
+ 'poweroff.target',
+ 'reboot.target',
+ 'shutdown.target',
+ 'sigpwr.target',
+ 'soft-reboot.target',
+ 'sysinit.target',
+ 'systemd-exit.service',
+ 'systemd-halt.service',
+ 'systemd-kexec.service',
+ 'systemd-poweroff.service',
+ 'systemd-reboot.service',
+ 'systemd-soft-reboot.service',
+ 'umount.target',
+]
+embedded_units = []
+
foreach unit : units
source = unit.get('file')
endforeach
if needs_jinja
- t = custom_target(
+ processed = custom_target(
input : source,
output : name,
command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install_dir : systemunitdir,
install_tag : unit.get('install_tag', ''))
if unit.get('install_tag', '') == 'udev'
- udev_units += t
+ udev_units += processed
elif unit.get('install_tag', '') == 'hwdb'
- hwdb_units += t
+ hwdb_units += processed
endif
elif install
install_data(source,
install_tag : unit.get('install_tag', ''))
endif
+ if name in embedded_unit_names
+ # Embed either the processed output or the original file.
+ embedded_units += needs_jinja ? processed : source
+ endif
+
if install
foreach target : unit.get('symlinks', [])
if target.endswith('/')