mirror of
https://github.com/systemd/systemd
synced 2025-11-08 03:14:45 +01:00
Compare commits
27 Commits
550c8784c5
...
0c789b6b81
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c789b6b81 | ||
|
|
6b8664cb5b | ||
|
|
a0fa268337 | ||
|
|
929d07ddcb | ||
|
|
400530c1e2 | ||
|
|
a94d11cc66 | ||
|
|
bb94ded693 | ||
|
|
579ca0a2b2 | ||
|
|
3d45f6b2d0 | ||
|
|
929fed02df | ||
|
|
ad76560525 | ||
|
|
f42aa41683 | ||
|
|
75f4bd7fd0 | ||
|
|
a2dd991d0f | ||
|
|
e0c17a7d1b | ||
|
|
2d3adfa6c4 | ||
|
|
ed0d1b2e99 | ||
|
|
73c8ced784 | ||
|
|
d6463307e0 | ||
|
|
4c0b8d563d | ||
|
|
b406c6d128 | ||
|
|
80f605c807 | ||
|
|
06a4eb0737 | ||
|
|
1addc46c8c | ||
|
|
ffe5c01eaa | ||
|
|
986935cf6a | ||
|
|
c600357ba6 |
@ -332,6 +332,7 @@ All mount unit settings are available to transient units:
|
||||
✓ SloppyOptions=
|
||||
✓ LazyUnmount=
|
||||
✓ ForceUnmount=
|
||||
✓ ReadWriteOnly=
|
||||
```
|
||||
|
||||
## Automount Unit Settings
|
||||
|
||||
@ -359,6 +359,17 @@
|
||||
<varname>Options=</varname> setting in a unit file.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>x-systemd.rw-only</option></term>
|
||||
|
||||
<listitem><para>If a mount operation fails to mount the file system
|
||||
read-write, it normally tries mounting the file system read-only instead.
|
||||
This option disables that behaviour, and causes the mount to fail
|
||||
immediately instead. This option is translated into the
|
||||
<varname>ReadWriteOnly=</varname> setting in a unit file.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>_netdev</option></term>
|
||||
|
||||
@ -497,6 +508,19 @@
|
||||
off.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ReadWriteOnly=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. If false, a mount
|
||||
point that shall be mounted read-write but cannot be mounted
|
||||
so is retried to be mounted read-only. If true the operation
|
||||
will fail immediately after the read-write mount attempt did
|
||||
not succeed. This corresponds with
|
||||
<citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
|
||||
<parameter>-w</parameter> switch. Defaults to
|
||||
off.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ForceUnmount=</varname></term>
|
||||
|
||||
|
||||
@ -1623,6 +1623,15 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>FallbackLeaseLifetimeSec=</varname></term>
|
||||
<listitem>
|
||||
<para>Allows to set DHCPv4 lease lifetime when DHCPv4 server does not send the lease lifetime.
|
||||
Takes one of <literal>forever</literal> or <literal>infinity</literal> means that the address
|
||||
never expires. Defaults to unset.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>SendRelease=</varname></term>
|
||||
<listitem>
|
||||
@ -1788,6 +1797,17 @@
|
||||
currently NUL bytes are not allowed.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>VendorClass=</varname></term>
|
||||
<listitem>
|
||||
<para>A DHCPv6 client can use VendorClass option to identify the vendor that
|
||||
manufactured the hardware on which the client is running. The information
|
||||
contained in the data area of this option is contained in one or more opaque
|
||||
fields that identify details of the hardware configuration. Takes a
|
||||
whitespace-separated list of strings.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@ -331,7 +331,7 @@ int systemd_efi_options_variable(char **line) {
|
||||
* does, let's return a recognizable error (EPERM), and if not ENODATA. */
|
||||
|
||||
if (access(k, F_OK) < 0)
|
||||
return errno == -ENOENT ? -ENODATA : -errno;
|
||||
return errno == ENOENT ? -ENODATA : -errno;
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@ -419,7 +419,7 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno != -EINTR)
|
||||
if (errno != EINTR)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
||||
@ -517,7 +517,7 @@ static int copy_file_with_version_check(const char *from, const char *to, bool f
|
||||
if (!force) {
|
||||
fd_to = open(to, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd_to < 0) {
|
||||
if (errno != -ENOENT)
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", to);
|
||||
} else {
|
||||
r = version_check(fd_from, from, fd_to, to);
|
||||
|
||||
@ -244,6 +244,76 @@ static int property_get_show_status(
|
||||
return sd_bus_message_append_basic(reply, 'b', &b);
|
||||
}
|
||||
|
||||
static int property_get_runtime_watchdog(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
Manager *m = userdata;
|
||||
|
||||
assert(m);
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
|
||||
return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_RUNTIME));
|
||||
}
|
||||
|
||||
static int property_get_reboot_watchdog(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
Manager *m = userdata;
|
||||
|
||||
assert(m);
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
|
||||
return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_REBOOT));
|
||||
}
|
||||
|
||||
static int property_get_kexec_watchdog(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
Manager *m = userdata;
|
||||
|
||||
assert(m);
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
|
||||
return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_KEXEC));
|
||||
}
|
||||
|
||||
static int property_set_watchdog(Manager *m, WatchdogType type, sd_bus_message *value) {
|
||||
usec_t timeout;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(value);
|
||||
|
||||
assert_cc(sizeof(usec_t) == sizeof(uint64_t));
|
||||
|
||||
r = sd_bus_message_read(value, "t", &timeout);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return manager_set_watchdog_overridden(m, type, timeout);
|
||||
}
|
||||
|
||||
static int property_set_runtime_watchdog(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
@ -253,19 +323,37 @@ static int property_set_runtime_watchdog(
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
usec_t *t = userdata;
|
||||
int r;
|
||||
return property_set_watchdog(userdata, WATCHDOG_RUNTIME, value);
|
||||
}
|
||||
|
||||
static int property_set_reboot_watchdog(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *value,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
return property_set_watchdog(userdata, WATCHDOG_REBOOT, value);
|
||||
}
|
||||
|
||||
static int property_set_kexec_watchdog(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *value,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
Manager *m = userdata;
|
||||
|
||||
assert(m);
|
||||
assert(bus);
|
||||
assert(value);
|
||||
|
||||
assert_cc(sizeof(usec_t) == sizeof(uint64_t));
|
||||
|
||||
r = sd_bus_message_read(value, "t", t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return watchdog_set_timeout(t);
|
||||
return property_set_watchdog(userdata, WATCHDOG_KEXEC, value);
|
||||
}
|
||||
|
||||
static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char *name, Unit **ret_unit, sd_bus_error *error) {
|
||||
@ -2404,11 +2492,11 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
||||
SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.search_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
|
||||
SD_BUS_WRITABLE_PROPERTY("RebootWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, reboot_watchdog), 0),
|
||||
SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", property_get_runtime_watchdog, property_set_runtime_watchdog, 0, 0),
|
||||
SD_BUS_WRITABLE_PROPERTY("RebootWatchdogUSec", "t", property_get_reboot_watchdog, property_set_reboot_watchdog, 0, 0),
|
||||
/* The following item is an obsolete alias */
|
||||
SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, reboot_watchdog), SD_BUS_VTABLE_HIDDEN),
|
||||
SD_BUS_WRITABLE_PROPERTY("KExecWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, kexec_watchdog), 0),
|
||||
SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", property_get_reboot_watchdog, property_set_reboot_watchdog, 0, SD_BUS_VTABLE_HIDDEN),
|
||||
SD_BUS_WRITABLE_PROPERTY("KExecWatchdogUSec", "t", property_get_kexec_watchdog, property_set_kexec_watchdog, 0, 0),
|
||||
SD_BUS_WRITABLE_PROPERTY("ServiceWatchdogs", "b", bus_property_get_bool, bus_property_set_bool, offsetof(Manager, service_watchdogs), 0),
|
||||
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
|
||||
SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
|
||||
|
||||
@ -51,6 +51,7 @@ const sd_bus_vtable bus_mount_vtable[] = {
|
||||
SD_BUS_PROPERTY("SloppyOptions", "b", bus_property_get_bool, offsetof(Mount, sloppy_options), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("LazyUnmount", "b", bus_property_get_bool, offsetof(Mount, lazy_unmount), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ForceUnmount", "b", bus_property_get_bool, offsetof(Mount, force_unmount), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ReadWriteOnly", "b", bus_property_get_bool, offsetof(Mount, read_write_only), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("GID", "u", bus_property_get_gid, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
@ -102,6 +103,9 @@ static int bus_mount_set_transient_property(
|
||||
if (streq(name, "ForceUnmount"))
|
||||
return bus_set_transient_bool(u, name, &m->force_unmount, message, flags, error);
|
||||
|
||||
if (streq(name, "ReadWriteOnly"))
|
||||
return bus_set_transient_bool(u, name, &m->read_write_only, message, flags, error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -429,6 +429,7 @@ Mount.DirectoryMode, config_parse_mode, 0,
|
||||
Mount.SloppyOptions, config_parse_bool, 0, offsetof(Mount, sloppy_options)
|
||||
Mount.LazyUnmount, config_parse_bool, 0, offsetof(Mount, lazy_unmount)
|
||||
Mount.ForceUnmount, config_parse_bool, 0, offsetof(Mount, force_unmount)
|
||||
Mount.ReadWriteOnly, config_parse_bool, 0, offsetof(Mount, read_write_only)
|
||||
EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
|
||||
CGROUP_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
|
||||
KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
|
||||
|
||||
@ -5157,7 +5157,7 @@ int config_parse_swap_priority(
|
||||
|
||||
r = safe_atoi(rvalue, &priority);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid swap pririty '%s', ignoring.", rvalue);
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid swap priority '%s', ignoring.", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -713,16 +713,18 @@ static void set_manager_settings(Manager *m) {
|
||||
|
||||
assert(m);
|
||||
|
||||
/* Propagates the various manager settings into the manager object, i.e. properties that effect the manager
|
||||
* itself (as opposed to just being inherited into newly allocated units, see set_manager_defaults() above). */
|
||||
/* Propagates the various manager settings into the manager object, i.e. properties that
|
||||
* effect the manager itself (as opposed to just being inherited into newly allocated
|
||||
* units, see set_manager_defaults() above). */
|
||||
|
||||
m->confirm_spawn = arg_confirm_spawn;
|
||||
m->service_watchdogs = arg_service_watchdogs;
|
||||
m->runtime_watchdog = arg_runtime_watchdog;
|
||||
m->reboot_watchdog = arg_reboot_watchdog;
|
||||
m->kexec_watchdog = arg_kexec_watchdog;
|
||||
m->cad_burst_action = arg_cad_burst_action;
|
||||
|
||||
manager_set_watchdog(m, WATCHDOG_RUNTIME, arg_runtime_watchdog);
|
||||
manager_set_watchdog(m, WATCHDOG_REBOOT, arg_reboot_watchdog);
|
||||
manager_set_watchdog(m, WATCHDOG_KEXEC, arg_kexec_watchdog);
|
||||
|
||||
manager_set_show_status(m, arg_show_status, "commandline");
|
||||
m->status_unit_format = arg_status_unit_format;
|
||||
}
|
||||
@ -1816,6 +1818,7 @@ static int invoke_main_loop(
|
||||
(void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
|
||||
|
||||
set_manager_defaults(m);
|
||||
set_manager_settings(m);
|
||||
|
||||
update_cpu_affinity(false);
|
||||
update_numa_policy(false);
|
||||
@ -2006,9 +2009,6 @@ static int initialize_runtime(
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", arg_watchdog_device);
|
||||
}
|
||||
|
||||
if (timestamp_is_set(arg_runtime_watchdog))
|
||||
watchdog_set_timeout(&arg_runtime_watchdog);
|
||||
}
|
||||
|
||||
if (arg_timer_slack_nsec != NSEC_INFINITY)
|
||||
@ -2282,29 +2282,6 @@ static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
|
||||
/* Note that this also parses bits from the kernel command line, including "debug". */
|
||||
log_parse_environment();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_configuration(
|
||||
int argc,
|
||||
char **argv,
|
||||
const struct rlimit *saved_rlimit_nofile,
|
||||
const struct rlimit *saved_rlimit_memlock,
|
||||
const char **ret_error_message) {
|
||||
int r;
|
||||
|
||||
assert(saved_rlimit_nofile);
|
||||
assert(saved_rlimit_memlock);
|
||||
assert(ret_error_message);
|
||||
|
||||
(void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r < 0) {
|
||||
*ret_error_message = "Failed to parse commandline arguments";
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Initialize the show status setting if it hasn't been set explicitly yet */
|
||||
if (arg_show_status == _SHOW_STATUS_INVALID)
|
||||
arg_show_status = SHOW_STATUS_YES;
|
||||
@ -2650,9 +2627,13 @@ int main(int argc, char *argv[]) {
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) ignore_signals(SIGNALS_IGNORE, -1);
|
||||
|
||||
r = load_configuration(argc, argv, &saved_rlimit_nofile, &saved_rlimit_memlock, &error_message);
|
||||
if (r < 0)
|
||||
(void) parse_configuration(&saved_rlimit_nofile, &saved_rlimit_memlock);
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r < 0) {
|
||||
error_message = "Failed to parse commandline arguments";
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = safety_checks();
|
||||
if (r < 0)
|
||||
@ -2787,8 +2768,8 @@ finish:
|
||||
pager_close();
|
||||
|
||||
if (m) {
|
||||
arg_reboot_watchdog = m->reboot_watchdog;
|
||||
arg_kexec_watchdog = m->kexec_watchdog;
|
||||
arg_reboot_watchdog = manager_get_watchdog(m, WATCHDOG_REBOOT);
|
||||
arg_kexec_watchdog = manager_get_watchdog(m, WATCHDOG_KEXEC);
|
||||
m = manager_free(m);
|
||||
}
|
||||
|
||||
|
||||
@ -110,6 +110,7 @@ static int manager_dispatch_sigchld(sd_event_source *source, void *userdata);
|
||||
static int manager_dispatch_timezone_change(sd_event_source *source, const struct inotify_event *event, void *userdata);
|
||||
static int manager_run_environment_generators(Manager *m);
|
||||
static int manager_run_generators(Manager *m);
|
||||
static void manager_vacuum(Manager *m);
|
||||
|
||||
static usec_t manager_watch_jobs_next_time(Manager *m) {
|
||||
return usec_add(now(CLOCK_MONOTONIC),
|
||||
@ -181,7 +182,7 @@ static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned po
|
||||
}
|
||||
}
|
||||
|
||||
void manager_flip_auto_status(Manager *m, bool enable, const char *reason) {
|
||||
static void manager_flip_auto_status(Manager *m, bool enable, const char *reason) {
|
||||
assert(m);
|
||||
|
||||
if (enable) {
|
||||
@ -779,6 +780,10 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager
|
||||
.original_log_level = -1,
|
||||
.original_log_target = _LOG_TARGET_INVALID,
|
||||
|
||||
.watchdog_overridden[WATCHDOG_RUNTIME] = USEC_INFINITY,
|
||||
.watchdog_overridden[WATCHDOG_REBOOT] = USEC_INFINITY,
|
||||
.watchdog_overridden[WATCHDOG_KEXEC] = USEC_INFINITY,
|
||||
|
||||
.notify_fd = -1,
|
||||
.cgroups_agent_fd = -1,
|
||||
.signal_fd = -1,
|
||||
@ -1596,20 +1601,6 @@ static void manager_preset_all(Manager *m) {
|
||||
log_info("Populated /etc with preset unit settings.");
|
||||
}
|
||||
|
||||
static void manager_vacuum(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
/* Release any dynamic users no longer referenced */
|
||||
dynamic_user_vacuum(m, true);
|
||||
|
||||
/* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
|
||||
manager_vacuum_uid_refs(m);
|
||||
manager_vacuum_gid_refs(m);
|
||||
|
||||
/* Release any runtimes no longer referenced */
|
||||
exec_runtime_vacuum(m);
|
||||
}
|
||||
|
||||
static void manager_ready(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
@ -2922,9 +2913,10 @@ int manager_loop(Manager *m) {
|
||||
return log_error_errno(r, "Failed to enable SIGCHLD event source: %m");
|
||||
|
||||
while (m->objective == MANAGER_OK) {
|
||||
usec_t wait_usec;
|
||||
usec_t wait_usec, watchdog_usec;
|
||||
|
||||
if (timestamp_is_set(m->runtime_watchdog) && MANAGER_IS_SYSTEM(m))
|
||||
watchdog_usec = manager_get_watchdog(m, WATCHDOG_RUNTIME);
|
||||
if (timestamp_is_set(watchdog_usec))
|
||||
watchdog_ping();
|
||||
|
||||
if (!ratelimit_below(&rl)) {
|
||||
@ -2955,7 +2947,7 @@ int manager_loop(Manager *m) {
|
||||
continue;
|
||||
|
||||
/* Sleep for watchdog runtime wait time */
|
||||
if (MANAGER_IS_SYSTEM(m))
|
||||
if (timestamp_is_set(watchdog_usec))
|
||||
wait_usec = watchdog_runtime_wait();
|
||||
else
|
||||
wait_usec = USEC_INFINITY;
|
||||
@ -3158,6 +3150,47 @@ static bool manager_timestamp_shall_serialize(ManagerTimestamp t) {
|
||||
MANAGER_TIMESTAMP_UNITS_LOAD_START, MANAGER_TIMESTAMP_UNITS_LOAD_FINISH);
|
||||
}
|
||||
|
||||
#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
|
||||
|
||||
static void manager_serialize_uid_refs_internal(
|
||||
Manager *m,
|
||||
FILE *f,
|
||||
Hashmap **uid_refs,
|
||||
const char *field_name) {
|
||||
|
||||
Iterator i;
|
||||
void *p, *k;
|
||||
|
||||
assert(m);
|
||||
assert(f);
|
||||
assert(uid_refs);
|
||||
assert(field_name);
|
||||
|
||||
/* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as
|
||||
* the actual counter of it is better rebuild after a reload/reexec. */
|
||||
|
||||
HASHMAP_FOREACH_KEY(p, k, *uid_refs, i) {
|
||||
uint32_t c;
|
||||
uid_t uid;
|
||||
|
||||
uid = PTR_TO_UID(k);
|
||||
c = PTR_TO_UINT32(p);
|
||||
|
||||
if (!(c & DESTROY_IPC_FLAG))
|
||||
continue;
|
||||
|
||||
(void) serialize_item_format(f, field_name, UID_FMT, uid);
|
||||
}
|
||||
}
|
||||
|
||||
static void manager_serialize_uid_refs(Manager *m, FILE *f) {
|
||||
manager_serialize_uid_refs_internal(m, f, &m->uid_refs, "destroy-ipc-uid");
|
||||
}
|
||||
|
||||
static void manager_serialize_gid_refs(Manager *m, FILE *f) {
|
||||
manager_serialize_uid_refs_internal(m, f, &m->gid_refs, "destroy-ipc-gid");
|
||||
}
|
||||
|
||||
int manager_serialize(
|
||||
Manager *m,
|
||||
FILE *f,
|
||||
@ -3196,6 +3229,10 @@ int manager_serialize(
|
||||
if (m->log_target_overridden)
|
||||
(void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target()));
|
||||
|
||||
(void) serialize_usec(f, "runtime-watchdog-overridden", m->watchdog_overridden[WATCHDOG_RUNTIME]);
|
||||
(void) serialize_usec(f, "reboot-watchdog-overridden", m->watchdog_overridden[WATCHDOG_REBOOT]);
|
||||
(void) serialize_usec(f, "kexec-watchdog-overridden", m->watchdog_overridden[WATCHDOG_KEXEC]);
|
||||
|
||||
for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
|
||||
@ -3328,6 +3365,114 @@ static int manager_deserialize_units(Manager *m, FILE *f, FDSet *fds) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
usec_t manager_get_watchdog(Manager *m, WatchdogType t) {
|
||||
assert(m);
|
||||
|
||||
if (MANAGER_IS_USER(m))
|
||||
return USEC_INFINITY;
|
||||
|
||||
if (timestamp_is_set(m->watchdog_overridden[t]))
|
||||
return m->watchdog_overridden[t];
|
||||
|
||||
return m->watchdog[t];
|
||||
}
|
||||
|
||||
void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
|
||||
int r = 0;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (MANAGER_IS_USER(m))
|
||||
return;
|
||||
|
||||
if (m->watchdog[t] == timeout)
|
||||
return;
|
||||
|
||||
if (t == WATCHDOG_RUNTIME)
|
||||
if (!timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME])) {
|
||||
if (timestamp_is_set(timeout))
|
||||
r = watchdog_set_timeout(&timeout);
|
||||
else
|
||||
watchdog_close(true);
|
||||
}
|
||||
|
||||
if (r >= 0)
|
||||
m->watchdog[t] = timeout;
|
||||
}
|
||||
|
||||
int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout) {
|
||||
int r = 0;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (MANAGER_IS_USER(m))
|
||||
return 0;
|
||||
|
||||
if (m->watchdog_overridden[t] == timeout)
|
||||
return 0;
|
||||
|
||||
if (t == WATCHDOG_RUNTIME) {
|
||||
usec_t *p;
|
||||
|
||||
p = timestamp_is_set(timeout) ? &timeout : &m->watchdog[t];
|
||||
if (timestamp_is_set(*p))
|
||||
r = watchdog_set_timeout(p);
|
||||
else
|
||||
watchdog_close(true);
|
||||
}
|
||||
|
||||
if (r >= 0)
|
||||
m->watchdog_overridden[t] = timeout;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void manager_deserialize_uid_refs_one_internal(
|
||||
Manager *m,
|
||||
Hashmap** uid_refs,
|
||||
const char *value) {
|
||||
|
||||
uid_t uid;
|
||||
uint32_t c;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(uid_refs);
|
||||
assert(value);
|
||||
|
||||
r = parse_uid(value, &uid);
|
||||
if (r < 0 || uid == 0) {
|
||||
log_debug("Unable to parse UID reference serialization: " UID_FMT, uid);
|
||||
return;
|
||||
}
|
||||
|
||||
r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops);
|
||||
if (r < 0) {
|
||||
log_oom();
|
||||
return;
|
||||
}
|
||||
|
||||
c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
|
||||
if (c & DESTROY_IPC_FLAG)
|
||||
return;
|
||||
|
||||
c |= DESTROY_IPC_FLAG;
|
||||
|
||||
r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to add UID reference entry: %m");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
|
||||
manager_deserialize_uid_refs_one_internal(m, &m->uid_refs, value);
|
||||
}
|
||||
|
||||
static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
|
||||
manager_deserialize_uid_refs_one_internal(m, &m->gid_refs, value);
|
||||
}
|
||||
|
||||
int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
||||
int r = 0;
|
||||
|
||||
@ -3451,6 +3596,30 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
||||
else
|
||||
manager_override_log_target(m, target);
|
||||
|
||||
} else if ((val = startswith(l, "runtime-watchdog-overridden="))) {
|
||||
usec_t t;
|
||||
|
||||
if (deserialize_usec(val, &t) < 0)
|
||||
log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val);
|
||||
else
|
||||
manager_set_watchdog_overridden(m, WATCHDOG_RUNTIME, t);
|
||||
|
||||
} else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
|
||||
usec_t t;
|
||||
|
||||
if (deserialize_usec(val, &t) < 0)
|
||||
log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val);
|
||||
else
|
||||
manager_set_watchdog_overridden(m, WATCHDOG_REBOOT, t);
|
||||
|
||||
} else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
|
||||
usec_t t;
|
||||
|
||||
if (deserialize_usec(val, &t) < 0)
|
||||
log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val);
|
||||
else
|
||||
manager_set_watchdog_overridden(m, WATCHDOG_KEXEC, t);
|
||||
|
||||
} else if (startswith(l, "env=")) {
|
||||
r = deserialize_environment(l + 4, &m->client_environment);
|
||||
if (r < 0)
|
||||
@ -4301,8 +4470,6 @@ ManagerState manager_state(Manager *m) {
|
||||
return MANAGER_RUNNING;
|
||||
}
|
||||
|
||||
#define DESTROY_IPC_FLAG (UINT32_C(1) << 31)
|
||||
|
||||
static void manager_unref_uid_internal(
|
||||
Manager *m,
|
||||
Hashmap **uid_refs,
|
||||
@ -4441,97 +4608,26 @@ static void manager_vacuum_uid_refs_internal(
|
||||
}
|
||||
}
|
||||
|
||||
void manager_vacuum_uid_refs(Manager *m) {
|
||||
static void manager_vacuum_uid_refs(Manager *m) {
|
||||
manager_vacuum_uid_refs_internal(m, &m->uid_refs, clean_ipc_by_uid);
|
||||
}
|
||||
|
||||
void manager_vacuum_gid_refs(Manager *m) {
|
||||
static void manager_vacuum_gid_refs(Manager *m) {
|
||||
manager_vacuum_uid_refs_internal(m, &m->gid_refs, clean_ipc_by_gid);
|
||||
}
|
||||
|
||||
static void manager_serialize_uid_refs_internal(
|
||||
Manager *m,
|
||||
FILE *f,
|
||||
Hashmap **uid_refs,
|
||||
const char *field_name) {
|
||||
|
||||
Iterator i;
|
||||
void *p, *k;
|
||||
|
||||
static void manager_vacuum(Manager *m) {
|
||||
assert(m);
|
||||
assert(f);
|
||||
assert(uid_refs);
|
||||
assert(field_name);
|
||||
|
||||
/* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as the actual counter
|
||||
* of it is better rebuild after a reload/reexec. */
|
||||
/* Release any dynamic users no longer referenced */
|
||||
dynamic_user_vacuum(m, true);
|
||||
|
||||
HASHMAP_FOREACH_KEY(p, k, *uid_refs, i) {
|
||||
uint32_t c;
|
||||
uid_t uid;
|
||||
/* Release any references to UIDs/GIDs no longer referenced, and destroy any IPC owned by them */
|
||||
manager_vacuum_uid_refs(m);
|
||||
manager_vacuum_gid_refs(m);
|
||||
|
||||
uid = PTR_TO_UID(k);
|
||||
c = PTR_TO_UINT32(p);
|
||||
|
||||
if (!(c & DESTROY_IPC_FLAG))
|
||||
continue;
|
||||
|
||||
(void) serialize_item_format(f, field_name, UID_FMT, uid);
|
||||
}
|
||||
}
|
||||
|
||||
void manager_serialize_uid_refs(Manager *m, FILE *f) {
|
||||
manager_serialize_uid_refs_internal(m, f, &m->uid_refs, "destroy-ipc-uid");
|
||||
}
|
||||
|
||||
void manager_serialize_gid_refs(Manager *m, FILE *f) {
|
||||
manager_serialize_uid_refs_internal(m, f, &m->gid_refs, "destroy-ipc-gid");
|
||||
}
|
||||
|
||||
static void manager_deserialize_uid_refs_one_internal(
|
||||
Manager *m,
|
||||
Hashmap** uid_refs,
|
||||
const char *value) {
|
||||
|
||||
uid_t uid;
|
||||
uint32_t c;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(uid_refs);
|
||||
assert(value);
|
||||
|
||||
r = parse_uid(value, &uid);
|
||||
if (r < 0 || uid == 0) {
|
||||
log_debug("Unable to parse UID reference serialization: " UID_FMT, uid);
|
||||
return;
|
||||
}
|
||||
|
||||
r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops);
|
||||
if (r < 0) {
|
||||
log_oom();
|
||||
return;
|
||||
}
|
||||
|
||||
c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid)));
|
||||
if (c & DESTROY_IPC_FLAG)
|
||||
return;
|
||||
|
||||
c |= DESTROY_IPC_FLAG;
|
||||
|
||||
r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c));
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to add UID reference entry: %m");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void manager_deserialize_uid_refs_one(Manager *m, const char *value) {
|
||||
manager_deserialize_uid_refs_one_internal(m, &m->uid_refs, value);
|
||||
}
|
||||
|
||||
void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
|
||||
manager_deserialize_uid_refs_one_internal(m, &m->gid_refs, value);
|
||||
/* Release any runtimes no longer referenced */
|
||||
exec_runtime_vacuum(m);
|
||||
}
|
||||
|
||||
int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
||||
|
||||
@ -114,6 +114,13 @@ typedef enum ManagerTimestamp {
|
||||
_MANAGER_TIMESTAMP_INVALID = -1,
|
||||
} ManagerTimestamp;
|
||||
|
||||
typedef enum WatchdogType {
|
||||
WATCHDOG_RUNTIME,
|
||||
WATCHDOG_REBOOT,
|
||||
WATCHDOG_KEXEC,
|
||||
_WATCHDOG_TYPE_MAX,
|
||||
} WatchdogType;
|
||||
|
||||
#include "execute.h"
|
||||
#include "job.h"
|
||||
#include "path-lookup.h"
|
||||
@ -231,9 +238,8 @@ struct Manager {
|
||||
char **transient_environment; /* The environment, as determined from config files, kernel cmdline and environment generators */
|
||||
char **client_environment; /* Environment variables created by clients through the bus API */
|
||||
|
||||
usec_t runtime_watchdog;
|
||||
usec_t reboot_watchdog;
|
||||
usec_t kexec_watchdog;
|
||||
usec_t watchdog[_WATCHDOG_TYPE_MAX];
|
||||
usec_t watchdog_overridden[_WATCHDOG_TYPE_MAX];
|
||||
|
||||
dual_timestamp timestamps[_MANAGER_TIMESTAMP_MAX];
|
||||
|
||||
@ -510,7 +516,6 @@ void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason);
|
||||
void manager_set_first_boot(Manager *m, bool b);
|
||||
|
||||
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5);
|
||||
void manager_flip_auto_status(Manager *m, bool enable, const char *reason);
|
||||
|
||||
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path);
|
||||
|
||||
@ -524,15 +529,6 @@ int manager_ref_uid(Manager *m, uid_t uid, bool clean_ipc);
|
||||
void manager_unref_gid(Manager *m, gid_t gid, bool destroy_now);
|
||||
int manager_ref_gid(Manager *m, gid_t gid, bool destroy_now);
|
||||
|
||||
void manager_vacuum_uid_refs(Manager *m);
|
||||
void manager_vacuum_gid_refs(Manager *m);
|
||||
|
||||
void manager_serialize_uid_refs(Manager *m, FILE *f);
|
||||
void manager_deserialize_uid_refs_one(Manager *m, const char *value);
|
||||
|
||||
void manager_serialize_gid_refs(Manager *m, FILE *f);
|
||||
void manager_deserialize_gid_refs_one(Manager *m, const char *value);
|
||||
|
||||
char *manager_taint_string(Manager *m);
|
||||
|
||||
void manager_ref_console(Manager *m);
|
||||
@ -555,5 +551,9 @@ const char *manager_timestamp_to_string(ManagerTimestamp m) _const_;
|
||||
ManagerTimestamp manager_timestamp_from_string(const char *s) _pure_;
|
||||
ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s);
|
||||
|
||||
usec_t manager_get_watchdog(Manager *m, WatchdogType t);
|
||||
void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout);
|
||||
int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout);
|
||||
|
||||
const char* oom_policy_to_string(OOMPolicy i) _const_;
|
||||
OOMPolicy oom_policy_from_string(const char *s) _pure_;
|
||||
|
||||
@ -780,6 +780,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
"%sSloppyOptions: %s\n"
|
||||
"%sLazyUnmount: %s\n"
|
||||
"%sForceUnmount: %s\n"
|
||||
"%sReadWriteOnly: %s\n"
|
||||
"%sTimeoutSec: %s\n",
|
||||
prefix, mount_state_to_string(m->state),
|
||||
prefix, mount_result_to_string(m->result),
|
||||
@ -795,6 +796,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
prefix, yes_no(m->sloppy_options),
|
||||
prefix, yes_no(m->lazy_unmount),
|
||||
prefix, yes_no(m->force_unmount),
|
||||
prefix, yes_no(m->read_write_only),
|
||||
prefix, format_timespan(buf, sizeof(buf), m->timeout_usec, USEC_PER_SEC));
|
||||
|
||||
if (m->control_pid > 0)
|
||||
@ -1026,6 +1028,8 @@ static void mount_enter_mounting(Mount *m) {
|
||||
r = exec_command_set(m->control_command, MOUNT_PATH, p->what, m->where, NULL);
|
||||
if (r >= 0 && m->sloppy_options)
|
||||
r = exec_command_append(m->control_command, "-s", NULL);
|
||||
if (r >= 0 && m->read_write_only)
|
||||
r = exec_command_append(m->control_command, "-w", NULL);
|
||||
if (r >= 0 && p->fstype)
|
||||
r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
|
||||
if (r >= 0 && !isempty(opts))
|
||||
@ -1086,6 +1090,8 @@ static void mount_enter_remounting(Mount *m) {
|
||||
"-o", o, NULL);
|
||||
if (r >= 0 && m->sloppy_options)
|
||||
r = exec_command_append(m->control_command, "-s", NULL);
|
||||
if (r >= 0 && m->read_write_only)
|
||||
r = exec_command_append(m->control_command, "-w", NULL);
|
||||
if (r >= 0 && p->fstype)
|
||||
r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
|
||||
} else
|
||||
|
||||
@ -59,6 +59,8 @@ struct Mount {
|
||||
bool lazy_unmount;
|
||||
bool force_unmount;
|
||||
|
||||
bool read_write_only;
|
||||
|
||||
MountResult result;
|
||||
MountResult reload_result;
|
||||
MountResult clean_result;
|
||||
|
||||
@ -35,6 +35,7 @@ typedef enum MountpointFlags {
|
||||
AUTOMOUNT = 1 << 2,
|
||||
MAKEFS = 1 << 3,
|
||||
GROWFS = 1 << 4,
|
||||
RWONLY = 1 << 5,
|
||||
} MountpointFlags;
|
||||
|
||||
static const char *arg_dest = NULL;
|
||||
@ -472,6 +473,9 @@ static int add_mount(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (flags & RWONLY)
|
||||
fprintf(f, "ReadWriteOnly=yes\n");
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write unit file %s: %m", name);
|
||||
@ -583,7 +587,7 @@ static int parse_fstab(bool initrd) {
|
||||
|
||||
while ((me = getmntent(f))) {
|
||||
_cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL;
|
||||
bool makefs, growfs, noauto, nofail;
|
||||
bool makefs, growfs, noauto, nofail, rwonly;
|
||||
int k;
|
||||
|
||||
if (initrd && !mount_in_initrd(me))
|
||||
@ -623,6 +627,7 @@ static int parse_fstab(bool initrd) {
|
||||
|
||||
makefs = fstab_test_option(me->mnt_opts, "x-systemd.makefs\0");
|
||||
growfs = fstab_test_option(me->mnt_opts, "x-systemd.growfs\0");
|
||||
rwonly = fstab_test_option(me->mnt_opts, "x-systemd.rw-only\0");
|
||||
noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
|
||||
nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
|
||||
|
||||
@ -655,7 +660,7 @@ static int parse_fstab(bool initrd) {
|
||||
me->mnt_type,
|
||||
me->mnt_opts,
|
||||
me->mnt_passno,
|
||||
makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT,
|
||||
makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT | rwonly*RWONLY,
|
||||
post,
|
||||
fstab);
|
||||
}
|
||||
|
||||
@ -1051,7 +1051,7 @@ static int home_remove(UserRecord *h) {
|
||||
assert(ip);
|
||||
|
||||
if (stat(ip, &st) < 0) {
|
||||
if (errno != -ENOENT)
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to stat() %s: %m", ip);
|
||||
|
||||
} else {
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
#include "udev-util.h"
|
||||
#include "virt.h"
|
||||
|
||||
#define SYSTEMD_PEN 43793
|
||||
#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
|
||||
#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
|
||||
#define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
#include "time-util.h"
|
||||
#include "unaligned.h"
|
||||
|
||||
#define SYSTEMD_PEN 43793
|
||||
|
||||
typedef enum DUIDType {
|
||||
DUID_TYPE_LLT = 1,
|
||||
DUID_TYPE_EN = 2,
|
||||
|
||||
@ -98,6 +98,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
|
||||
int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix);
|
||||
int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
|
||||
int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class);
|
||||
int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **user_class);
|
||||
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
|
||||
size_t *optlen, uint8_t **optvalue);
|
||||
int dhcp6_option_parse_status(DHCP6Option *option, size_t len);
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include "sd-dhcp6-client.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-lease-internal.h"
|
||||
#include "dhcp6-protocol.h"
|
||||
@ -180,7 +181,6 @@ int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_cl
|
||||
|
||||
if (len > 0xffff)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
q = realloc(p, total + len + 2);
|
||||
if (!q)
|
||||
return -ENOMEM;
|
||||
@ -197,6 +197,46 @@ int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_cl
|
||||
return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_USER_CLASS, total, p);
|
||||
}
|
||||
|
||||
int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendor_class) {
|
||||
_cleanup_free_ uint8_t *p = NULL;
|
||||
uint32_t enterprise_identifier;
|
||||
size_t total, offset;
|
||||
char **s;
|
||||
|
||||
assert(buf);
|
||||
assert(*buf);
|
||||
assert(buflen);
|
||||
assert(vendor_class);
|
||||
|
||||
enterprise_identifier = htobe32(SYSTEMD_PEN);
|
||||
|
||||
p = memdup(&enterprise_identifier, sizeof(enterprise_identifier));
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
total = sizeof(enterprise_identifier);
|
||||
offset = total;
|
||||
|
||||
STRV_FOREACH(s, vendor_class) {
|
||||
size_t len = strlen(*s);
|
||||
uint8_t *q;
|
||||
|
||||
q = realloc(p, total + len + 2);
|
||||
if (!q)
|
||||
return -ENOMEM;
|
||||
|
||||
p = q;
|
||||
|
||||
unaligned_write_be16(&p[offset], len);
|
||||
memcpy(&p[offset + 2], *s, len);
|
||||
|
||||
offset += 2 + len;
|
||||
total += 2 + len;
|
||||
}
|
||||
|
||||
return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, total, p);
|
||||
}
|
||||
|
||||
int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) {
|
||||
DHCP6Option *option = (DHCP6Option *)buf;
|
||||
size_t i = sizeof(*option) + sizeof(pd->ia_pd);
|
||||
|
||||
@ -87,6 +87,7 @@ struct sd_dhcp_client {
|
||||
char *mudurl;
|
||||
char **user_class;
|
||||
uint32_t mtu;
|
||||
uint32_t fallback_lease_lifetime;
|
||||
uint32_t xid;
|
||||
usec_t start_time;
|
||||
uint64_t attempt;
|
||||
@ -612,6 +613,15 @@ int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint32_t fallback_lease_lifetime) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(fallback_lease_lifetime > 0, -EINVAL);
|
||||
|
||||
client->fallback_lease_lifetime = fallback_lease_lifetime;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_notify(sd_dhcp_client *client, int event) {
|
||||
assert(client);
|
||||
|
||||
@ -850,11 +860,82 @@ static int dhcp_client_send_raw(
|
||||
packet, len);
|
||||
}
|
||||
|
||||
static int client_append_common_discover_request_options(sd_dhcp_client *client, DHCPPacket *packet, size_t *optoffset, size_t optlen) {
|
||||
sd_dhcp_option *j;
|
||||
Iterator i;
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
|
||||
if (client->hostname) {
|
||||
/* According to RFC 4702 "clients that send the Client FQDN option in
|
||||
their messages MUST NOT also send the Host Name option". Just send
|
||||
one of the two depending on the hostname type.
|
||||
*/
|
||||
if (dns_name_is_single_label(client->hostname)) {
|
||||
/* it is unclear from RFC 2131 if client should send hostname in
|
||||
DHCPDISCOVER but dhclient does and so we do as well
|
||||
*/
|
||||
r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
|
||||
SD_DHCP_OPTION_HOST_NAME,
|
||||
strlen(client->hostname), client->hostname);
|
||||
} else
|
||||
r = client_append_fqdn_option(&packet->dhcp, optlen, optoffset,
|
||||
client->hostname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->vendor_class_identifier) {
|
||||
r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
|
||||
SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
|
||||
strlen(client->vendor_class_identifier),
|
||||
client->vendor_class_identifier);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->mudurl) {
|
||||
r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
|
||||
SD_DHCP_OPTION_MUD_URL,
|
||||
strlen(client->mudurl),
|
||||
client->mudurl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->user_class) {
|
||||
r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
|
||||
SD_DHCP_OPTION_USER_CLASS,
|
||||
strv_length(client->user_class),
|
||||
client->user_class);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
|
||||
r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
|
||||
j->option, j->length, j->data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!ordered_hashmap_isempty(client->vendor_options)) {
|
||||
r = dhcp_option_append(
|
||||
&packet->dhcp, optlen, optoffset, 0,
|
||||
SD_DHCP_OPTION_VENDOR_SPECIFIC,
|
||||
ordered_hashmap_size(client->vendor_options), client->vendor_options);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_send_discover(sd_dhcp_client *client) {
|
||||
_cleanup_free_ DHCPPacket *discover = NULL;
|
||||
size_t optoffset, optlen;
|
||||
sd_dhcp_option *j;
|
||||
Iterator i;
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
@ -881,67 +962,9 @@ static int client_send_discover(sd_dhcp_client *client) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->hostname) {
|
||||
/* According to RFC 4702 "clients that send the Client FQDN option in
|
||||
their messages MUST NOT also send the Host Name option". Just send
|
||||
one of the two depending on the hostname type.
|
||||
*/
|
||||
if (dns_name_is_single_label(client->hostname)) {
|
||||
/* it is unclear from RFC 2131 if client should send hostname in
|
||||
DHCPDISCOVER but dhclient does and so we do as well
|
||||
*/
|
||||
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_HOST_NAME,
|
||||
strlen(client->hostname), client->hostname);
|
||||
} else
|
||||
r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
|
||||
client->hostname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->vendor_class_identifier) {
|
||||
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
|
||||
strlen(client->vendor_class_identifier),
|
||||
client->vendor_class_identifier);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->mudurl) {
|
||||
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_MUD_URL,
|
||||
strlen(client->mudurl),
|
||||
client->mudurl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->user_class) {
|
||||
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_USER_CLASS,
|
||||
strv_length(client->user_class),
|
||||
client->user_class);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
|
||||
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
|
||||
j->option, j->length, j->data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!ordered_hashmap_isempty(client->vendor_options)) {
|
||||
r = dhcp_option_append(
|
||||
&discover->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_VENDOR_SPECIFIC,
|
||||
ordered_hashmap_size(client->vendor_options), client->vendor_options);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
r = client_append_common_discover_request_options(client, discover, &optoffset, optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_END, 0, NULL);
|
||||
@ -1034,36 +1057,9 @@ static int client_send_request(sd_dhcp_client *client) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (client->hostname) {
|
||||
if (dns_name_is_single_label(client->hostname))
|
||||
r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_HOST_NAME,
|
||||
strlen(client->hostname), client->hostname);
|
||||
else
|
||||
r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
|
||||
client->hostname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->vendor_class_identifier) {
|
||||
r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
|
||||
strlen(client->vendor_class_identifier),
|
||||
client->vendor_class_identifier);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->mudurl) {
|
||||
r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_MUD_URL,
|
||||
strlen(client->mudurl),
|
||||
client->mudurl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = client_append_common_discover_request_options(client, request, &optoffset, optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_END, 0, NULL);
|
||||
@ -1419,6 +1415,9 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_
|
||||
lease->next_server = offer->siaddr;
|
||||
lease->address = offer->yiaddr;
|
||||
|
||||
if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
|
||||
lease->lifetime = client->fallback_lease_lifetime;
|
||||
|
||||
if (lease->address == 0 ||
|
||||
lease->server_address == 0 ||
|
||||
lease->lifetime == 0) {
|
||||
|
||||
@ -68,6 +68,7 @@ struct sd_dhcp6_client {
|
||||
char *fqdn;
|
||||
char *mudurl;
|
||||
char **user_class;
|
||||
char **vendor_class;
|
||||
sd_event_source *receive_message;
|
||||
usec_t retransmit_time;
|
||||
uint8_t retransmit_count;
|
||||
@ -359,7 +360,7 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
|
||||
|
||||
if (option <= 0 || option >= 255)
|
||||
if (option <= 0 || option >= UINT8_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
for (t = 0; t < client->req_opts_len; t++)
|
||||
@ -380,7 +381,7 @@ int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mud
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
|
||||
assert_return(mudurl, -EINVAL);
|
||||
assert_return(strlen(mudurl) <= 255, -EINVAL);
|
||||
assert_return(strlen(mudurl) <= UINT8_MAX, -EINVAL);
|
||||
assert_return(http_url_is_valid(mudurl), -EINVAL);
|
||||
|
||||
return free_and_strdup(&client->mudurl, mudurl);
|
||||
@ -392,13 +393,14 @@ int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
|
||||
|
||||
assert_return(user_class, -EINVAL);
|
||||
|
||||
STRV_FOREACH(p, user_class)
|
||||
if (strlen(*p) > UINT16_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
s = strv_copy((char **) user_class);
|
||||
s = strv_copy(user_class);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -407,6 +409,27 @@ int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char **vendor_class) {
|
||||
_cleanup_strv_free_ char **s = NULL;
|
||||
char **p;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
|
||||
assert_return(vendor_class, -EINVAL);
|
||||
|
||||
STRV_FOREACH(p, vendor_class)
|
||||
if (strlen(*p) > UINT8_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
s = strv_copy(vendor_class);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
client->vendor_class = TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(delegation, -EINVAL);
|
||||
@ -593,6 +616,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->vendor_class) {
|
||||
r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||
r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
|
||||
if (r < 0)
|
||||
@ -645,6 +674,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->vendor_class) {
|
||||
r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
|
||||
if (r < 0)
|
||||
@ -685,6 +720,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->vendor_class) {
|
||||
r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
|
||||
if (r < 0)
|
||||
@ -1645,6 +1686,7 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
|
||||
|
||||
ordered_hashmap_free(client->extra_options);
|
||||
strv_free(client->user_class);
|
||||
strv_free(client->vendor_class);
|
||||
|
||||
return mfree(client);
|
||||
}
|
||||
|
||||
@ -451,7 +451,7 @@ int bus_message_from_header(
|
||||
if (!IN_SET(h->version, 1, 2))
|
||||
return -EBADMSG;
|
||||
|
||||
if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
|
||||
if (h->type <= _SD_BUS_MESSAGE_TYPE_INVALID || h->type >= _SD_BUS_MESSAGE_TYPE_MAX)
|
||||
return -EBADMSG;
|
||||
|
||||
if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN))
|
||||
@ -589,7 +589,7 @@ _public_ int sd_bus_message_new(
|
||||
assert_return(bus = bus_resolve(bus), -ENOPKG);
|
||||
assert_return(bus->state != BUS_UNSET, -ENOTCONN);
|
||||
assert_return(m, -EINVAL);
|
||||
assert_return(type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
|
||||
assert_return(type > _SD_BUS_MESSAGE_TYPE_INVALID && type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
|
||||
|
||||
sd_bus_message *t = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
|
||||
if (!t)
|
||||
@ -5202,29 +5202,34 @@ int bus_message_parse_fields(sd_bus_message *m) {
|
||||
* table */
|
||||
m->user_body_size = m->body_size - ((char*) m->footer + m->footer_accessible - p);
|
||||
|
||||
/* Pull out the offset table for the fields array */
|
||||
sz = bus_gvariant_determine_word_size(m->fields_size, 0);
|
||||
if (sz > 0) {
|
||||
size_t framing;
|
||||
void *q;
|
||||
/* Pull out the offset table for the fields array, if any */
|
||||
if (m->fields_size > 0) {
|
||||
sz = bus_gvariant_determine_word_size(m->fields_size, 0);
|
||||
if (sz > 0) {
|
||||
size_t framing;
|
||||
void *q;
|
||||
|
||||
ri = m->fields_size - sz;
|
||||
r = message_peek_fields(m, &ri, 1, sz, &q);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (m->fields_size < sz)
|
||||
return -EBADMSG;
|
||||
|
||||
framing = bus_gvariant_read_word_le(q, sz);
|
||||
if (framing >= m->fields_size - sz)
|
||||
return -EBADMSG;
|
||||
if ((m->fields_size - framing) % sz != 0)
|
||||
return -EBADMSG;
|
||||
ri = m->fields_size - sz;
|
||||
r = message_peek_fields(m, &ri, 1, sz, &q);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ri = framing;
|
||||
r = message_peek_fields(m, &ri, 1, m->fields_size - framing, &offsets);
|
||||
if (r < 0)
|
||||
return r;
|
||||
framing = bus_gvariant_read_word_le(q, sz);
|
||||
if (framing >= m->fields_size - sz)
|
||||
return -EBADMSG;
|
||||
if ((m->fields_size - framing) % sz != 0)
|
||||
return -EBADMSG;
|
||||
|
||||
n_offsets = (m->fields_size - framing) / sz;
|
||||
ri = framing;
|
||||
r = message_peek_fields(m, &ri, 1, m->fields_size - framing, &offsets);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n_offsets = (m->fields_size - framing) / sz;
|
||||
}
|
||||
}
|
||||
} else
|
||||
m->user_body_size = m->body_size;
|
||||
@ -5492,6 +5497,9 @@ int bus_message_parse_fields(sd_bus_message *m) {
|
||||
if (m->reply_cookie == 0 || !m->error.name)
|
||||
return -EBADMSG;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Bad message type");
|
||||
}
|
||||
|
||||
/* Refuse non-local messages that claim they are local */
|
||||
|
||||
@ -329,6 +329,59 @@ int config_parse_dhcp_user_class(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_dhcp_vendor_class(
|
||||
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 ***l = data;
|
||||
int r;
|
||||
|
||||
assert(l);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*l = strv_free(*l);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *w = NULL;
|
||||
|
||||
r = extract_first_word(&rvalue, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to split vendor classes option, ignoring: %s", rvalue);
|
||||
break;
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (strlen(w) > UINT8_MAX) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"%s length is not in the range 1-255, ignoring.", w);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = strv_push(l, w);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
w = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_dhcp6_mud_url(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
|
||||
@ -51,5 +51,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_pd_hint);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp6_mud_url);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_vendor_class);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_option);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options);
|
||||
|
||||
@ -1488,6 +1488,12 @@ int dhcp4_configure(Link *link) {
|
||||
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ip service type: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_fallback_lease_lifetime > 0) {
|
||||
r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp_send_decline) {
|
||||
r = configure_dhcpv4_duplicate_address_detection(link);
|
||||
if (r < 0)
|
||||
@ -1674,6 +1680,44 @@ int config_parse_dhcp_mud_url(
|
||||
return free_and_strdup_warn(&network->dhcp_mudurl, unescaped);
|
||||
}
|
||||
|
||||
int config_parse_dhcp_fallback_lease_lifetime(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) {
|
||||
Network *network = userdata;
|
||||
unsigned k;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
network->dhcp_fallback_lease_lifetime = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We accept only "forever" or "infinity". */
|
||||
if (STR_IN_SET(rvalue, "forever", "infinity"))
|
||||
k = CACHE_INFO_INFINITY_LIFE_TIME;
|
||||
else {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Invalid LeaseLifetime= value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
network->dhcp_fallback_lease_lifetime = k;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
|
||||
[DHCP_CLIENT_ID_MAC] = "mac",
|
||||
[DHCP_CLIENT_ID_DUID] = "duid",
|
||||
|
||||
@ -27,3 +27,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_black_listed_ip_address);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_ip_service_type);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_mud_url);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_fallback_lease_lifetime);
|
||||
|
||||
@ -712,6 +712,12 @@ int dhcp6_configure(Link *link) {
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set user class: %m");
|
||||
}
|
||||
|
||||
if (link->network->dhcp6_vendor_class) {
|
||||
r = sd_dhcp6_client_set_request_vendor_class(client, link->network->dhcp6_vendor_class);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set vendor class: %m");
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set callback: %m");
|
||||
|
||||
@ -189,12 +189,14 @@ DHCPv4.IPServiceType, config_parse_dhcp_ip_service_type,
|
||||
DHCPv4.SendOption, config_parse_dhcp_send_option, AF_INET, offsetof(Network, dhcp_client_send_options)
|
||||
DHCPv4.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_vendor_options)
|
||||
DHCPv4.RouteMTUBytes, config_parse_mtu, AF_INET, offsetof(Network, dhcp_route_mtu)
|
||||
DHCPv4.FallbackLeaseLifetimeSec, config_parse_dhcp_fallback_lease_lifetime, 0, 0
|
||||
DHCPv6.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp6_use_dns)
|
||||
DHCPv6.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp6_use_ntp)
|
||||
DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
|
||||
DHCPv6.MUDURL, config_parse_dhcp6_mud_url, 0, 0
|
||||
DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0
|
||||
DHCPv6.UserClass, config_parse_dhcp_user_class, AF_INET6, offsetof(Network, dhcp6_user_class)
|
||||
DHCPv6.VendorClass, config_parse_dhcp_vendor_class, 0, offsetof(Network, dhcp6_vendor_class)
|
||||
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
|
||||
DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0
|
||||
DHCPv6.WithoutRA, config_parse_bool, 0, offsetof(Network, dhcp6_without_ra)
|
||||
|
||||
@ -654,6 +654,7 @@ static Network *network_free(Network *network) {
|
||||
free(network->mac);
|
||||
free(network->dhcp6_mudurl);
|
||||
strv_free(network->dhcp6_user_class);
|
||||
strv_free(network->dhcp6_vendor_class);
|
||||
|
||||
if (network->dhcp_acd)
|
||||
sd_ipv4acd_unref(network->dhcp_acd);
|
||||
|
||||
@ -97,6 +97,7 @@ struct Network {
|
||||
uint64_t dhcp_max_attempts;
|
||||
unsigned dhcp_route_metric;
|
||||
uint32_t dhcp_route_table;
|
||||
uint32_t dhcp_fallback_lease_lifetime;
|
||||
uint32_t dhcp_route_mtu;
|
||||
uint16_t dhcp_client_port;
|
||||
int dhcp_critical;
|
||||
@ -133,6 +134,7 @@ struct Network {
|
||||
uint8_t dhcp6_pd_length;
|
||||
char *dhcp6_mudurl;
|
||||
char **dhcp6_user_class;
|
||||
char **dhcp6_vendor_class;
|
||||
struct in6_addr dhcp6_pd_address;
|
||||
OrderedHashmap *dhcp6_client_send_options;
|
||||
Set *dhcp6_request_options;
|
||||
|
||||
@ -1436,7 +1436,8 @@ static int bus_append_mount_property(sd_bus_message *m, const char *field, const
|
||||
|
||||
if (STR_IN_SET(field, "SloppyOptions",
|
||||
"LazyUnmount",
|
||||
"ForceUnmount"))
|
||||
"ForceUnmount",
|
||||
"ReadwriteOnly"))
|
||||
return bus_append_parse_boolean(m, field, eq);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -185,6 +185,9 @@ int sd_dhcp_client_get_lease(
|
||||
int sd_dhcp_client_set_service_type(
|
||||
sd_dhcp_client *client,
|
||||
int type);
|
||||
int sd_dhcp_client_set_fallback_lease_lifetime(
|
||||
sd_dhcp_client *client,
|
||||
uint32_t fallback_lease_lifetime);
|
||||
|
||||
int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
|
||||
int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
|
||||
|
||||
@ -125,10 +125,12 @@ int sd_dhcp6_client_set_request_option(
|
||||
int sd_dhcp6_client_set_request_mud_url(
|
||||
sd_dhcp6_client *client,
|
||||
const char *mudurl);
|
||||
|
||||
int sd_dhcp6_client_set_request_user_class(
|
||||
sd_dhcp6_client *client,
|
||||
char** user_class);
|
||||
int sd_dhcp6_client_set_request_vendor_class(
|
||||
sd_dhcp6_client *client,
|
||||
char** vendor_class);
|
||||
int sd_dhcp6_client_set_prefix_delegation_hint(
|
||||
sd_dhcp6_client *client,
|
||||
uint8_t prefixlen,
|
||||
|
||||
BIN
test/fuzz/fuzz-bus-message/oss-fuzz-19446
Normal file
BIN
test/fuzz/fuzz-bus-message/oss-fuzz-19446
Normal file
Binary file not shown.
@ -105,6 +105,7 @@ SendVendorOption=
|
||||
SendDecline=
|
||||
MUDURL=
|
||||
RouteMTUBytes=
|
||||
FallbackLeaseLifetimeSec=
|
||||
[DHCPv6]
|
||||
UseNTP=
|
||||
UseDNS=
|
||||
@ -116,6 +117,7 @@ MUDURL=
|
||||
SendOption=
|
||||
RequestOptions=
|
||||
UserClass=
|
||||
VendorClass=
|
||||
[Route]
|
||||
Destination=
|
||||
Protocol=
|
||||
|
||||
@ -856,6 +856,7 @@ RateLimitIntervalSec=
|
||||
ReadKMsg=
|
||||
ReadOnly=
|
||||
ReadOnlyPaths=
|
||||
ReadWriteOnly=
|
||||
ReadWritePaths=
|
||||
RemoveIPC=
|
||||
ReserveVT=
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user