1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-02-02 09:47:03 +03:00

Merge pull request #13696 from keszybz/keep-dhcp-on-restart

Add a way to differentiate restart from stop and keep dhcp config on restart
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2019-10-03 11:25:12 +02:00 committed by GitHub
commit 6e2d361d53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 224 additions and 131 deletions

View File

@ -85,32 +85,36 @@
unless it is empty.</para>
<para>Processes will first be terminated via <constant>SIGTERM</constant> (unless the signal to send
is changed via <varname>KillSignal=</varname>). Optionally, this is immediately followed by a
<constant>SIGHUP</constant> (if enabled with <varname>SendSIGHUP=</varname>). If processes still
remain after the main process of a unit has exited or the delay configured via the
<varname>TimeoutStopSec=</varname> has passed, the termination request is repeated with the
<constant>SIGKILL</constant> signal or the signal specified via <varname>FinalKillSignal=</varname>
(unless this is disabled via the <varname>SendSIGKILL=</varname> option). See
<citerefentry><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry> for more
information.</para>
is changed via <varname>KillSignal=</varname> or <varname>RestartKillSignal=</varname>). Optionally,
this is immediately followed by a <constant>SIGHUP</constant> (if enabled with
<varname>SendSIGHUP=</varname>). If processes still remain after the main process of a unit has
exited or the delay configured via the <varname>TimeoutStopSec=</varname> has passed, the termination
request is repeated with the <constant>SIGKILL</constant> signal or the signal specified via
<varname>FinalKillSignal=</varname> (unless this is disabled via the <varname>SendSIGKILL=</varname>
option). See <citerefentry><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry>
for more information.</para>
<para>Defaults to <option>control-group</option>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>KillSignal=</varname></term>
<listitem><para>Specifies which signal to use when killing a
service. This controls the signal that is sent as first step
of shutting down a unit (see above), and is usually followed
by <constant>SIGKILL</constant> (see above and below). For a
list of valid signals, see
<listitem><para>Specifies which signal to use when stopping a service. This controls the signal that
is sent as first step of shutting down a unit (see above), and is usually followed by
<constant>SIGKILL</constant> (see above and below). For a list of valid signals, see
<citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
Defaults to <constant>SIGTERM</constant>. </para>
Defaults to <constant>SIGTERM</constant>.</para>
<para>Note that, right after sending the signal specified in
this setting, systemd will always send
<constant>SIGCONT</constant>, to ensure that even suspended
tasks can be terminated cleanly.</para>
<para>Note that, right after sending the signal specified in this setting, systemd will always send
<constant>SIGCONT</constant>, to ensure that even suspended tasks can be terminated cleanly.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RestartKillSignal=</varname></term>
<listitem><para>Specifies which signal to use when restarting a service. The same as
<varname>KillSignal=</varname> described above, with the exception that this setting is used in a
restart job. Not set by default, and the value of <varname>KillSignal=</varname> is used.</para>
</listitem>
</varlistentry>

View File

@ -876,8 +876,8 @@
lease expires. This is contrary to the DHCP specification, but may be the best choice if,
e.g., the root filesystem relies on this connection. The setting <literal>dhcp</literal>
implies <literal>dhcp-on-stop</literal>, and <literal>yes</literal> implies
<literal>dhcp</literal> and <literal>static</literal>. Defaults to
<literal>dhcp-on-stop</literal>.</para>
<literal>dhcp</literal> and <literal>static</literal>. Defaults to <literal>no</literal>.
</para>
</listitem>
</varlistentry>
@ -1568,7 +1568,7 @@
<term><varname>SendRelease=</varname></term>
<listitem>
<para>When true, the DHCPv4 client sends a DHCP release packet when it stops.
Defaults to false.</para>
Defaults to true.</para>
</listitem>
</varlistentry>

View File

@ -477,26 +477,24 @@
<varlistentry>
<term><varname>ExecStop=</varname></term>
<listitem><para>Commands to execute to stop the service
started via <varname>ExecStart=</varname>. This argument takes
multiple command lines, following the same scheme as described
for <varname>ExecStart=</varname> above. Use of this setting
is optional. After the commands configured in this option are
run, it is implied that the service is stopped, and any processes
remaining for it are terminated
according to the <varname>KillMode=</varname> setting (see
<listitem><para>Commands to execute to stop the service started via
<varname>ExecStart=</varname>. This argument takes multiple command lines, following the same scheme
as described for <varname>ExecStart=</varname> above. Use of this setting is optional. After the
commands configured in this option are run, it is implied that the service is stopped, and any
processes remaining for it are terminated according to the <varname>KillMode=</varname> setting (see
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
If this option is not specified, the process is terminated by
sending the signal specified in <varname>KillSignal=</varname>
when service stop is requested. Specifier and environment
variable substitution is supported (including
If this option is not specified, the process is terminated by sending the signal specified in
<varname>KillSignal=</varname> or <varname>RestartKillSignal=</varname> when service stop is
requested. Specifier and environment variable substitution is supported (including
<varname>$MAINPID</varname>, see above).</para>
<para>Note that it is usually not sufficient to specify a command for this setting that only asks the service
to terminate (for example, by queuing some form of termination signal for it), but does not wait for it to do
so. Since the remaining processes of the services are killed according to <varname>KillMode=</varname> and
<varname>KillSignal=</varname> as described above immediately after the command exited, this may not result in
a clean stop. The specified command should hence be a synchronous operation, not an asynchronous one.</para>
<para>Note that it is usually not sufficient to specify a command for this setting that only asks the
service to terminate (for example, by sending some form of termination signal to it), but does not
wait for it to do so. Since the remaining processes of the services are killed according to
<varname>KillMode=</varname> and <varname>KillSignal=</varname> or
<varname>RestartKillSignal=</varname> as described above immediately after the command exited, this
may not result in a clean stop. The specified command should hence be a synchronous operation, not an
asynchronous one.</para>
<para>Note that the commands specified in <varname>ExecStop=</varname> are only executed when the service
started successfully first. They are not invoked if the service was never started at all, or in case its

View File

@ -80,7 +80,7 @@ _systemd_run() {
SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group=
DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth=
BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment=
KillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA=
KillSignal= RestartKillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA=
LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC=
LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE=
LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices=

View File

@ -35,7 +35,7 @@ _arguments \
SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group= \
DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth= \
BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment= \
KillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA= \
KillSignal= RestartKillSignal= FinalKillSignal= LimitCPU= LimitFSIZE= LimitDATA= \
LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= \
LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= \
LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= \

View File

@ -4,7 +4,7 @@
#include "sd-bus.h"
#include "sd-bus-vtable.h"
#include "job.h"
#include "unit.h"
extern const sd_bus_vtable bus_job_vtable[];

View File

@ -8,10 +8,28 @@
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_kill_mode, kill_mode, KillMode);
static int property_get_restart_kill_signal(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
KillContext *c = userdata;
int s;
assert(c);
s = restart_kill_signal(c);
return sd_bus_message_append_basic(reply, 'i', &s);
}
const sd_bus_vtable bus_kill_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("KillMode", "s", property_get_kill_mode, offsetof(KillContext, kill_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillSignal", "i", bus_property_get_int, offsetof(KillContext, kill_signal), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestartKillSignal", "i", property_get_restart_kill_signal, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FinalKillSignal", "i", bus_property_get_int, offsetof(KillContext, final_kill_signal), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SendSIGKILL", "b", bus_property_get_bool, offsetof(KillContext, send_sigkill), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SendSIGHUP", "b", bus_property_get_bool, offsetof(KillContext, send_sighup), SD_BUS_VTABLE_PROPERTY_CONST),
@ -21,6 +39,7 @@ const sd_bus_vtable bus_kill_vtable[] = {
static BUS_DEFINE_SET_TRANSIENT_PARSE(kill_mode, KillMode, kill_mode_from_string);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(kill_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(restart_kill_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(final_kill_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(watchdog_signal, "i", int32_t, int, "%" PRIi32, signal_to_string_with_check);
@ -51,6 +70,9 @@ int bus_kill_context_set_transient_property(
if (streq(name, "KillSignal"))
return bus_set_transient_kill_signal(u, name, &c->kill_signal, message, flags, error);
if (streq(name, "RestartKillSignal"))
return bus_set_transient_restart_kill_signal(u, name, &c->restart_kill_signal, message, flags, error);
if (streq(name, "FinalKillSignal"))
return bus_set_transient_final_kill_signal(u, name, &c->final_kill_signal, message, flags, error);

View File

@ -4,7 +4,6 @@
#include "sd-bus.h"
#include "sd-bus-vtable.h"
#include "job.h"
#include "unit.h"
extern const sd_bus_vtable bus_unit_vtable[];

View File

@ -9,6 +9,7 @@ void kill_context_init(KillContext *c) {
assert(c);
c->kill_signal = SIGTERM;
/* restart_kill_signal is unset by default and we fall back to kill_signal */
c->final_kill_signal = SIGKILL;
c->send_sigkill = true;
c->send_sighup = false;
@ -23,11 +24,13 @@ void kill_context_dump(KillContext *c, FILE *f, const char *prefix) {
fprintf(f,
"%sKillMode: %s\n"
"%sKillSignal: SIG%s\n"
"%sRestartKillSignal: SIG%s\n"
"%sFinalKillSignal: SIG%s\n"
"%sSendSIGKILL: %s\n"
"%sSendSIGHUP: %s\n",
"%sSendSIGHUP: %s\n",
prefix, kill_mode_to_string(c->kill_mode),
prefix, signal_to_string(c->kill_signal),
prefix, signal_to_string(restart_kill_signal(c)),
prefix, signal_to_string(c->final_kill_signal),
prefix, yes_no(c->send_sigkill),
prefix, yes_no(c->send_sighup));
@ -35,20 +38,20 @@ void kill_context_dump(KillContext *c, FILE *f, const char *prefix) {
static const char* const kill_mode_table[_KILL_MODE_MAX] = {
[KILL_CONTROL_GROUP] = "control-group",
[KILL_PROCESS] = "process",
[KILL_MIXED] = "mixed",
[KILL_NONE] = "none"
[KILL_PROCESS] = "process",
[KILL_MIXED] = "mixed",
[KILL_NONE] = "none",
};
DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
static const char* const kill_who_table[_KILL_WHO_MAX] = {
[KILL_MAIN] = "main",
[KILL_CONTROL] = "control",
[KILL_ALL] = "all",
[KILL_MAIN_FAIL] = "main-fail",
[KILL_MAIN] = "main",
[KILL_CONTROL] = "control",
[KILL_ALL] = "all",
[KILL_MAIN_FAIL] = "main-fail",
[KILL_CONTROL_FAIL] = "control-fail",
[KILL_ALL_FAIL] = "all-fail"
[KILL_ALL_FAIL] = "all-fail",
};
DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);

View File

@ -21,6 +21,7 @@ typedef enum KillMode {
struct KillContext {
KillMode kill_mode;
int kill_signal;
int restart_kill_signal;
int final_kill_signal;
int watchdog_signal;
bool send_sigkill;
@ -47,3 +48,9 @@ KillMode kill_mode_from_string(const char *s) _pure_;
const char *kill_who_to_string(KillWho k) _const_;
KillWho kill_who_from_string(const char *s) _pure_;
static inline int restart_kill_signal(const KillContext *c) {
if (c->restart_kill_signal != 0)
return c->restart_kill_signal;
return c->kill_signal;
}

View File

@ -161,6 +161,7 @@ m4_define(`KILL_CONTEXT_CONFIG_ITEMS',
$1.SendSIGHUP, config_parse_bool, 0, offsetof($1, kill_context.send_sighup)
$1.KillMode, config_parse_kill_mode, 0, offsetof($1, kill_context.kill_mode)
$1.KillSignal, config_parse_signal, 0, offsetof($1, kill_context.kill_signal)
$1.RestartKillSignal, config_parse_signal, 0, offsetof($1, kill_context.restart_kill_signal)
$1.FinalKillSignal, config_parse_signal, 0, offsetof($1, kill_context.final_kill_signal)
$1.WatchdogSignal, config_parse_signal, 0, offsetof($1, kill_context.watchdog_signal)'
)m4_dnl

View File

@ -43,8 +43,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_prio);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
CONFIG_PARSER_PROTOTYPE(config_parse_capability_set);
CONFIG_PARSER_PROTOTYPE(config_parse_kill_signal);
CONFIG_PARSER_PROTOTYPE(config_parse_final_kill_signal);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags);
CONFIG_PARSER_PROTOTYPE(config_parse_timer);
CONFIG_PARSER_PROTOTYPE(config_parse_trigger_unit);

View File

@ -866,6 +866,8 @@ static int state_to_kill_operation(MountState state) {
switch (state) {
case MOUNT_REMOUNTING_SIGTERM:
return KILL_RESTART;
case MOUNT_UNMOUNTING_SIGTERM:
return KILL_TERMINATE;

View File

@ -1838,13 +1838,17 @@ fail:
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
static int state_to_kill_operation(ServiceState state) {
static int state_to_kill_operation(Service *s, ServiceState state) {
switch (state) {
case SERVICE_STOP_WATCHDOG:
return KILL_WATCHDOG;
case SERVICE_STOP_SIGTERM:
if (unit_has_job_type(UNIT(s), JOB_RESTART))
return KILL_RESTART;
_fallthrough_;
case SERVICE_FINAL_SIGTERM:
return KILL_TERMINATE;
@ -1875,7 +1879,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
r = unit_kill_context(
UNIT(s),
&s->kill_context,
state_to_kill_operation(state),
state_to_kill_operation(s, state),
s->main_pid,
s->control_pid,
s->main_pid_alien);
@ -2245,7 +2249,7 @@ static void service_enter_restart(Service *s) {
assert(s);
if (UNIT(s)->job && UNIT(s)->job->type == JOB_STOP) {
if (unit_has_job_type(UNIT(s), JOB_STOP)) {
/* Don't restart things if we are going down anyway */
log_unit_info(UNIT(s), "Stop job pending for unit, delaying automatic restart.");

View File

@ -2077,6 +2077,16 @@ fail:
socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
}
static int state_to_kill_operation(Socket *s, SocketState state) {
if (state == SOCKET_STOP_PRE_SIGTERM && unit_has_job_type(UNIT(s), JOB_RESTART))
return KILL_RESTART;
if (state == SOCKET_FINAL_SIGTERM)
return KILL_TERMINATE;
return KILL_KILL;
}
static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
int r;
@ -2088,8 +2098,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
r = unit_kill_context(
UNIT(s),
&s->kill_context,
!IN_SET(state, SOCKET_STOP_PRE_SIGTERM, SOCKET_FINAL_SIGTERM) ?
KILL_KILL : KILL_TERMINATE,
state_to_kill_operation(s, state),
-1,
s->control_pid,
false);

View File

@ -712,21 +712,32 @@ static void swap_enter_dead_or_active(Swap *s, SwapResult f) {
swap_enter_dead(s, f);
}
static int state_to_kill_operation(Swap *s, SwapState state) {
if (state == SWAP_DEACTIVATING_SIGTERM) {
if (unit_has_job_type(UNIT(s), JOB_RESTART))
return KILL_RESTART;
else
return KILL_TERMINATE;
}
return KILL_KILL;
}
static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
int r;
KillOperation kop;
assert(s);
if (s->result == SWAP_SUCCESS)
s->result = f;
if (state == SWAP_DEACTIVATING_SIGTERM)
kop = KILL_TERMINATE;
else
kop = KILL_KILL;
r = unit_kill_context(UNIT(s), &s->kill_context, kop, -1, s->control_pid, false);
r = unit_kill_context(UNIT(s),
&s->kill_context,
state_to_kill_operation(s, state),
-1,
s->control_pid,
false);
if (r < 0)
goto fail;

View File

@ -4022,7 +4022,7 @@ bool unit_stop_pending(Unit *u) {
* different from unit_inactive_or_pending() which checks both
* the current state and for a queued job. */
return u->job && u->job->type == JOB_STOP;
return unit_has_job_type(u, JOB_STOP);
}
bool unit_inactive_or_pending(Unit *u) {
@ -4057,12 +4057,7 @@ bool unit_active_or_pending(Unit *u) {
bool unit_will_restart_default(Unit *u) {
assert(u);
if (!u->job)
return false;
if (u->job->type == JOB_START)
return true;
return false;
return unit_has_job_type(u, JOB_START);
}
bool unit_will_restart(Unit *u) {
@ -4691,19 +4686,26 @@ static int log_kill(pid_t pid, int sig, void *userdata) {
return 1;
}
static int operation_to_signal(KillContext *c, KillOperation k) {
static int operation_to_signal(const KillContext *c, KillOperation k, bool *noteworthy) {
assert(c);
switch (k) {
case KILL_TERMINATE:
case KILL_TERMINATE_AND_LOG:
*noteworthy = false;
return c->kill_signal;
case KILL_RESTART:
*noteworthy = false;
return restart_kill_signal(c);
case KILL_KILL:
*noteworthy = true;
return c->final_kill_signal;
case KILL_WATCHDOG:
*noteworthy = true;
return c->watchdog_signal;
default:
@ -4732,16 +4734,16 @@ int unit_kill_context(
if (c->kill_mode == KILL_NONE)
return 0;
sig = operation_to_signal(c, k);
bool noteworthy;
sig = operation_to_signal(c, k, &noteworthy);
if (noteworthy)
log_func = log_kill;
send_sighup =
c->send_sighup &&
IN_SET(k, KILL_TERMINATE, KILL_TERMINATE_AND_LOG) &&
sig != SIGHUP;
if (k != KILL_TERMINATE || IN_SET(sig, SIGKILL, SIGABRT))
log_func = log_kill;
if (main_pid > 0) {
if (log_func)
log_func(main_pid, sig, u);

View File

@ -18,6 +18,7 @@ typedef struct UnitRef UnitRef;
typedef enum KillOperation {
KILL_TERMINATE,
KILL_TERMINATE_AND_LOG,
KILL_RESTART,
KILL_KILL,
KILL_WATCHDOG,
_KILL_OPERATION_MAX,
@ -842,6 +843,10 @@ const char *unit_label_path(Unit *u);
int unit_pid_attachable(Unit *unit, pid_t pid, sd_bus_error *error);
static inline bool unit_has_job_type(Unit *u, JobType type) {
return u && u->job && u->job->type == type;
}
/* unit_log_skip is for cases like ExecCondition= where a unit is considered "done"
* after some execution, rather than succeeded or failed. */
void unit_log_skip(Unit *u, const char *result);

View File

@ -870,41 +870,6 @@ static int client_send_discover(sd_dhcp_client *client) {
return 0;
}
static int client_send_release(sd_dhcp_client *client) {
_cleanup_free_ DHCPPacket *release = NULL;
size_t optoffset, optlen;
int r;
assert(client);
assert(!IN_SET(client->state, DHCP_STATE_STOPPED));
r = client_message_init(client, &release, DHCP_RELEASE,
&optlen, &optoffset);
if (r < 0)
return r;
/* Fill up release IP and MAC */
release->dhcp.ciaddr = client->lease->address;
memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
return r;
r = dhcp_network_send_udp_socket(client->fd,
client->lease->server_address,
DHCP_PORT_SERVER,
&release->dhcp,
sizeof(DHCPMessage) + optoffset);
if (r < 0)
return r;
log_dhcp_client(client, "RELEASE");
return 0;
}
static int client_send_request(sd_dhcp_client *client) {
_cleanup_free_ DHCPPacket *request = NULL;
size_t optoffset, optlen;
@ -1929,8 +1894,35 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
int sd_dhcp_client_send_release(sd_dhcp_client *client) {
assert_return(client, -EINVAL);
assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
assert_return(client->lease, -EUNATCH);
client_send_release(client);
_cleanup_free_ DHCPPacket *release = NULL;
size_t optoffset, optlen;
int r;
r = client_message_init(client, &release, DHCP_RELEASE, &optlen, &optoffset);
if (r < 0)
return r;
/* Fill up release IP and MAC */
release->dhcp.ciaddr = client->lease->address;
memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
return r;
r = dhcp_network_send_udp_socket(client->fd,
client->lease->server_address,
DHCP_PORT_SERVER,
&release->dhcp,
sizeof(DHCPMessage) + optoffset);
if (r < 0)
return r;
log_dhcp_client(client, "RELEASE");
return 0;
}

View File

@ -864,10 +864,10 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
return 0;
}
if (link->network->dhcp_send_release)
(void) sd_dhcp_client_send_release(client);
if (link->dhcp_lease) {
if (link->network->dhcp_send_release)
(void) sd_dhcp_client_send_release(client);
r = dhcp_lease_lost(link);
if (r < 0) {
link_enter_failed(link);

View File

@ -770,8 +770,12 @@ int link_stop_clients(Link *link, bool may_keep_dhcp) {
dhcp4_release_old_lease(link);
if (link->dhcp_client && (!may_keep_dhcp || !link->network ||
!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP))) {
bool keep_dhcp = may_keep_dhcp &&
link->network &&
(link->manager->restarting ||
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP));
if (link->dhcp_client && !keep_dhcp) {
k = sd_dhcp_client_stop(link->dhcp_client);
if (k < 0)
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");

View File

@ -30,6 +30,7 @@
#include "ordered-set.h"
#include "path-util.h"
#include "set.h"
#include "signal-util.h"
#include "strv.h"
#include "sysctl-util.h"
#include "tmpfile-util.h"
@ -1561,6 +1562,28 @@ static int manager_dirty_handler(sd_event_source *s, void *userdata) {
return 1;
}
static int signal_terminate_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
Manager *m = userdata;
assert(m);
m->restarting = false;
log_debug("Terminate operation initiated.");
return sd_event_exit(sd_event_source_get_event(s), 0);
}
static int signal_restart_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
Manager *m = userdata;
assert(m);
m->restarting = true;
log_debug("Restart operation initiated.");
return sd_event_exit(sd_event_source_get_event(s), 0);
}
int manager_new(Manager **ret) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
@ -1581,9 +1604,12 @@ int manager_new(Manager **ret) {
if (r < 0)
return r;
assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR2, -1) >= 0);
(void) sd_event_set_watchdog(m->event, true);
(void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
(void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
(void) sd_event_add_signal(m->event, NULL, SIGTERM, signal_terminate_callback, m);
(void) sd_event_add_signal(m->event, NULL, SIGINT, signal_terminate_callback, m);
(void) sd_event_add_signal(m->event, NULL, SIGUSR2, signal_restart_callback, m);
r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m);
if (r < 0)

View File

@ -29,6 +29,7 @@ struct Manager {
bool enumerating:1;
bool dirty:1;
bool restarting:1;
Set *dirty_links;

View File

@ -268,13 +268,11 @@ int network_verify(Network *network) {
/* CriticalConnection=yes also preserve foreign static configurations. */
network->keep_configuration = KEEP_CONFIGURATION_YES;
else
/* For backward compatibility, we do not release DHCP addresses on manager stop. */
network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
network->keep_configuration = KEEP_CONFIGURATION_NO;
}
if (network->keep_configuration < 0)
/* For backward compatibility, we do not release DHCP addresses on manager stop. */
network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
network->keep_configuration = KEEP_CONFIGURATION_NO;
LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
if (address_section_verify(address) < 0)
@ -373,6 +371,7 @@ int network_load_one(Manager *manager, const char *filename) {
.dhcp_use_routes = true,
/* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
.dhcp_send_hostname = true,
.dhcp_send_release = true,
/* To enable/disable RFC7844 Anonymity Profiles */
.dhcp_anonymize = false,
.dhcp_route_metric = DHCP_ROUTE_METRIC,

View File

@ -1355,15 +1355,12 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
if (streq(field, "KillMode"))
return bus_append_string(m, field, eq);
if (STR_IN_SET(field, "SendSIGHUP", "SendSIGKILL"))
return bus_append_parse_boolean(m, field, eq);
if (STR_IN_SET(field, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
if (STR_IN_SET(field, "KillSignal", "RestartKillSignal", "FinalKillSignal", "WatchdogSignal"))
return bus_append_signal_from_string(m, field, eq);
return 0;

View File

@ -106,9 +106,9 @@ int main(int argc, char *argv[]) {
printf("Test11: (Start/stop job ordering, execution cycle)\n");
assert_se(manager_add_job(m, JOB_START, i, JOB_FAIL, NULL, NULL, &j) == 0);
assert_se(a->job && a->job->type == JOB_STOP);
assert_se(d->job && d->job->type == JOB_STOP);
assert_se(b->job && b->job->type == JOB_START);
assert_se(unit_has_job_type(a, JOB_STOP));
assert_se(unit_has_job_type(d, JOB_STOP));
assert_se(unit_has_job_type(b, JOB_START));
manager_dump_jobs(m, stdout, "\t");
printf("Load6:\n");

View File

@ -2,7 +2,6 @@
#include <stdio.h>
#include "job.h"
#include "service.h"
#include "unit.h"

View File

@ -19,6 +19,14 @@ systemd-run --unit=four -p Type=exec /bin/sleep infinity
! systemd-run --unit=five -p Type=exec -p User=idontexist /bin/sleep infinity
! systemd-run --unit=six -p Type=exec /tmp/brokenbinary
systemd-run --unit=seven -p KillSignal=SIGTERM -p RestartKillSignal=SIGINT -p Type=exec /bin/sleep infinity
# Both TERM and SIGINT happen to have the same number on all architectures
test $(systemctl show --value -p KillSignal seven.service) -eq 15
test $(systemctl show --value -p RestartKillSignal seven.service) -eq 2
systemctl restart seven.service
systemctl stop seven.service
systemd-analyze log-level info
echo OK > /testok

View File

@ -185,6 +185,7 @@ RequiresMountsFor=
Requisite=
Restart=
RestartForceExitStatus=
RestartKillSignal=
RestartPreventExitStatus=
RestartSec=
ReusePort=

View File

@ -42,6 +42,7 @@ SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
Type=notify
RestartKillSignal=SIGUSR2
User=systemd-network
WatchdogSec=3min