mirror of
https://github.com/systemd/systemd.git
synced 2025-03-31 14:50:15 +03:00
Merge pull request #2506 from poettering/resolved-and-more
pid 1 fixes, resolved fixes, and more
This commit is contained in:
commit
14ddf4207f
2
TODO
2
TODO
@ -33,6 +33,8 @@ Janitorial Clean-ups:
|
||||
|
||||
Features:
|
||||
|
||||
* rework coredump tool to move actual processing into a socket activated service
|
||||
|
||||
* cache sd_event_now() result from before the first iteration...
|
||||
|
||||
* remove Capabilities=, after all AmbientCapabilities= and CapabilityBoundingSet= should be enough.
|
||||
|
@ -114,41 +114,28 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><function>sd_event_add_time()</function> adds a new timer
|
||||
event source to an event loop. The event loop object is specified
|
||||
in the <parameter>event</parameter> parameter, the event source
|
||||
object is returned in the <parameter>source</parameter>
|
||||
parameter. The <parameter>clock</parameter> parameter takes a
|
||||
clock identifier, one of <constant>CLOCK_REALTIME</constant>,
|
||||
<constant>CLOCK_MONOTONIC</constant>,
|
||||
<constant>CLOCK_BOOTTIME</constant>,
|
||||
<constant>CLOCK_REALTIME_ALARM</constant>, or
|
||||
<constant>CLOCK_BOOTTIME_ALARM</constant>. See
|
||||
<citerefentry><refentrytitle>timerfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
for details regarding the various types of clocks. The
|
||||
<parameter>usec</parameter> parameter specifies the earliest time,
|
||||
in microseconds (µs), relative to the clock's epoch, when
|
||||
the timer shall be triggered. If a time already in the past is
|
||||
specified (including <constant>0</constant>), this timer source
|
||||
"fires" immediately and is ready to be dispatched. The
|
||||
<parameter>accuracy</parameter> parameter specifies an additional
|
||||
accuracy value in µs specifying how much the timer event may be
|
||||
delayed. Use <constant>0</constant> to select the default accuracy
|
||||
(250ms). Use 1µs for maximum accuracy. Consider specifying
|
||||
60000000µs (1min) or larger for long-running events that may be
|
||||
delayed substantially. Picking higher accuracy values allows the
|
||||
system to coalesce timer events more aggressively, improving
|
||||
power efficiency. The <parameter>handler</parameter> parameter
|
||||
shall reference a function to call when the timer elapses. The
|
||||
handler function will be passed the
|
||||
<parameter>userdata</parameter> pointer, which may be chosen
|
||||
freely by the caller. The handler is also passed the configured
|
||||
trigger time, even if it is actually called
|
||||
slightly later, subject to the specified accuracy value,
|
||||
the kernel timer slack (see
|
||||
<citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>),
|
||||
and additional scheduling latencies. To query the actual time the
|
||||
handler was called use
|
||||
<para><function>sd_event_add_time()</function> adds a new timer event source to an event loop. The event loop
|
||||
object is specified in the <parameter>event</parameter> parameter, the event source object is returned in the
|
||||
<parameter>source</parameter> parameter. The <parameter>clock</parameter> parameter takes a clock identifier, one
|
||||
of <constant>CLOCK_REALTIME</constant>, <constant>CLOCK_MONOTONIC</constant>, <constant>CLOCK_BOOTTIME</constant>,
|
||||
<constant>CLOCK_REALTIME_ALARM</constant>, or <constant>CLOCK_BOOTTIME_ALARM</constant>. See
|
||||
<citerefentry><refentrytitle>timerfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details
|
||||
regarding the various types of clocks. The <parameter>usec</parameter> parameter specifies the earliest time, in
|
||||
microseconds (µs), relative to the clock's epoch, when the timer shall be triggered. If a time already in the past
|
||||
is specified (including <constant>0</constant>), this timer source "fires" immediately and is ready to be
|
||||
dispatched. If the paramater is specified as <constant>UINT64_MAX</constant> the timer event will never elapse,
|
||||
which may be used as an alternative to explicitly disabling a timer event source with
|
||||
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>. The
|
||||
<parameter>accuracy</parameter> parameter specifies an additional accuracy value in µs specifying how much the
|
||||
timer event may be delayed. Use <constant>0</constant> to select the default accuracy (250ms). Use 1µs for maximum
|
||||
accuracy. Consider specifying 60000000µs (1min) or larger for long-running events that may be delayed
|
||||
substantially. Picking higher accuracy values allows the system to coalesce timer events more aggressively,
|
||||
improving power efficiency. The <parameter>handler</parameter> parameter shall reference a function to call when
|
||||
the timer elapses. The handler function will be passed the <parameter>userdata</parameter> pointer, which may be
|
||||
chosen freely by the caller. The handler is also passed the configured trigger time, even if it is actually called
|
||||
slightly later, subject to the specified accuracy value, the kernel timer slack (see
|
||||
<citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>), and additional
|
||||
scheduling latencies. To query the actual time the handler was called use
|
||||
<citerefentry><refentrytitle>sd_event_now</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>By default, the timer will elapse once
|
||||
|
@ -470,7 +470,7 @@
|
||||
configured time, the service will be considered failed and
|
||||
will be shut down again. Takes a unit-less value in seconds,
|
||||
or a time span value such as "5min 20s". Pass
|
||||
<literal>0</literal> to disable the timeout logic. Defaults to
|
||||
<literal>infinity</literal> to disable the timeout logic. Defaults to
|
||||
<varname>DefaultTimeoutStartSec=</varname> from the manager
|
||||
configuration file, except when
|
||||
<varname>Type=oneshot</varname> is used, in which case the
|
||||
@ -489,7 +489,7 @@
|
||||
<varname>KillMode=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
|
||||
Takes a unit-less value in seconds, or a time span value such
|
||||
as "5min 20s". Pass <literal>0</literal> to disable the
|
||||
as "5min 20s". Pass <literal>infinity</literal> to disable the
|
||||
timeout logic. Defaults to
|
||||
<varname>DefaultTimeoutStopSec=</varname> from the manager
|
||||
configuration file (see
|
||||
@ -505,6 +505,16 @@
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>RuntimeMaxSec=</varname></term>
|
||||
|
||||
<listitem><para>Configures a maximum time for the service to run. If this is used and the service has been
|
||||
active for longer than the specified time it is terminated and put into a failure state. Note that this setting
|
||||
does not have any effect on <varname>Type=oneshot</varname> services, as they terminate immediately after
|
||||
activation completed. Pass <literal>infinity</literal> (the default) to configure no runtime
|
||||
limit.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>WatchdogSec=</varname></term>
|
||||
<listitem><para>Configures the watchdog timeout for a service.
|
||||
|
@ -151,24 +151,44 @@ static int launch(char* name, char **argv, char **env, int fds) {
|
||||
return log_oom();
|
||||
|
||||
STRV_FOREACH(s, arg_setenv) {
|
||||
if (strchr(*s, '='))
|
||||
envp[n_env++] = *s;
|
||||
else {
|
||||
if (strchr(*s, '=')) {
|
||||
char *k;
|
||||
|
||||
k = strdup(*s);
|
||||
if (!k)
|
||||
return log_oom();
|
||||
|
||||
envp[n_env++] = k;
|
||||
} else {
|
||||
_cleanup_free_ char *p;
|
||||
const char *n;
|
||||
|
||||
p = strappend(*s, "=");
|
||||
if (!p)
|
||||
return log_oom();
|
||||
envp[n_env] = strv_find_prefix(env, p);
|
||||
if (envp[n_env])
|
||||
n_env ++;
|
||||
|
||||
n = strv_find_prefix(env, p);
|
||||
if (!n)
|
||||
continue;
|
||||
|
||||
envp[n_env] = strdup(n);
|
||||
if (!envp[n_env])
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(tocopy); i++) {
|
||||
envp[n_env] = strv_find_prefix(env, tocopy[i]);
|
||||
if (envp[n_env])
|
||||
n_env ++;
|
||||
const char *n;
|
||||
|
||||
n = strv_find_prefix(env, tocopy[i]);
|
||||
if (!n)
|
||||
continue;
|
||||
|
||||
envp[n_env] = strdup(n);
|
||||
if (!envp[n_env])
|
||||
return log_oom();
|
||||
|
||||
n_env ++;
|
||||
}
|
||||
|
||||
if ((asprintf((char**)(envp + n_env++), "LISTEN_FDS=%d", fds) < 0) ||
|
||||
@ -309,12 +329,12 @@ static void help(void) {
|
||||
printf("%s [OPTIONS...]\n\n"
|
||||
"Listen on sockets and launch child on connection.\n\n"
|
||||
"Options:\n"
|
||||
" -d --datagram Datagram sockets\n"
|
||||
" -l --listen=ADDR Listen for raw connections at ADDR\n"
|
||||
" -a --accept Spawn separate child for each connection\n"
|
||||
" -h --help Show this help and exit\n"
|
||||
" --version Print version string and exit\n"
|
||||
" -l --listen=ADDR Listen for raw connections at ADDR\n"
|
||||
" -d --datagram Listen on datagram instead of stream socket\n"
|
||||
" -a --accept Spawn separate child for each connection\n"
|
||||
" -E --setenv=NAME[=VALUE] Pass an environment variable to children\n"
|
||||
" --version Print version string and exit\n"
|
||||
"\n"
|
||||
"Note: file descriptors from sd_listen_fds() will be passed through.\n"
|
||||
, program_invocation_short_name);
|
||||
|
@ -22,10 +22,14 @@
|
||||
#include <errno.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "extract-word.h"
|
||||
#include "formats-util.h"
|
||||
#include "macro.h"
|
||||
#include "missing.h"
|
||||
#include "rlimit-util.h"
|
||||
#include "string-table.h"
|
||||
#include "time-util.h"
|
||||
|
||||
int setrlimit_closest(int resource, const struct rlimit *rlim) {
|
||||
struct rlimit highest, fixed;
|
||||
@ -51,6 +55,202 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rlimit_parse_u64(const char *val, rlim_t *ret) {
|
||||
uint64_t u;
|
||||
int r;
|
||||
|
||||
assert(val);
|
||||
assert(ret);
|
||||
|
||||
if (streq(val, "infinity")) {
|
||||
*ret = RLIM_INFINITY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
|
||||
assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
|
||||
|
||||
r = safe_atou64(val, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (u >= (uint64_t) RLIM_INFINITY)
|
||||
return -ERANGE;
|
||||
|
||||
*ret = (rlim_t) u;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rlimit_parse_size(const char *val, rlim_t *ret) {
|
||||
uint64_t u;
|
||||
int r;
|
||||
|
||||
assert(val);
|
||||
assert(ret);
|
||||
|
||||
if (streq(val, "infinity")) {
|
||||
*ret = RLIM_INFINITY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_size(val, 1024, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (u >= (uint64_t) RLIM_INFINITY)
|
||||
return -ERANGE;
|
||||
|
||||
*ret = (rlim_t) u;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rlimit_parse_sec(const char *val, rlim_t *ret) {
|
||||
uint64_t u;
|
||||
usec_t t;
|
||||
int r;
|
||||
|
||||
assert(val);
|
||||
assert(ret);
|
||||
|
||||
if (streq(val, "infinity")) {
|
||||
*ret = RLIM_INFINITY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_sec(val, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY) {
|
||||
*ret = RLIM_INFINITY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u = (uint64_t) DIV_ROUND_UP(t, USEC_PER_SEC);
|
||||
if (u >= (uint64_t) RLIM_INFINITY)
|
||||
return -ERANGE;
|
||||
|
||||
*ret = (rlim_t) u;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rlimit_parse_usec(const char *val, rlim_t *ret) {
|
||||
usec_t t;
|
||||
int r;
|
||||
|
||||
assert(val);
|
||||
assert(ret);
|
||||
|
||||
if (streq(val, "infinity")) {
|
||||
*ret = RLIM_INFINITY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_time(val, &t, 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY) {
|
||||
*ret = RLIM_INFINITY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*ret = (rlim_t) t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = {
|
||||
[RLIMIT_CPU] = rlimit_parse_sec,
|
||||
[RLIMIT_FSIZE] = rlimit_parse_size,
|
||||
[RLIMIT_DATA] = rlimit_parse_size,
|
||||
[RLIMIT_STACK] = rlimit_parse_size,
|
||||
[RLIMIT_CORE] = rlimit_parse_size,
|
||||
[RLIMIT_RSS] = rlimit_parse_size,
|
||||
[RLIMIT_NOFILE] = rlimit_parse_u64,
|
||||
[RLIMIT_AS] = rlimit_parse_size,
|
||||
[RLIMIT_NPROC] = rlimit_parse_u64,
|
||||
[RLIMIT_MEMLOCK] = rlimit_parse_size,
|
||||
[RLIMIT_LOCKS] = rlimit_parse_u64,
|
||||
[RLIMIT_SIGPENDING] = rlimit_parse_u64,
|
||||
[RLIMIT_MSGQUEUE] = rlimit_parse_size,
|
||||
[RLIMIT_NICE] = rlimit_parse_u64,
|
||||
[RLIMIT_RTPRIO] = rlimit_parse_u64,
|
||||
[RLIMIT_RTTIME] = rlimit_parse_usec,
|
||||
};
|
||||
|
||||
int rlimit_parse_one(int resource, const char *val, rlim_t *ret) {
|
||||
assert(val);
|
||||
assert(ret);
|
||||
|
||||
if (resource < 0)
|
||||
return -EINVAL;
|
||||
if (resource >= _RLIMIT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
return rlimit_parse_table[resource](val, ret);
|
||||
}
|
||||
|
||||
int rlimit_parse(int resource, const char *val, struct rlimit *ret) {
|
||||
_cleanup_free_ char *hard = NULL, *soft = NULL;
|
||||
rlim_t hl, sl;
|
||||
int r;
|
||||
|
||||
assert(val);
|
||||
assert(ret);
|
||||
|
||||
r = extract_first_word(&val, &soft, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = rlimit_parse_one(resource, soft, &sl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = extract_first_word(&val, &hard, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!isempty(val))
|
||||
return -EINVAL;
|
||||
if (r == 0)
|
||||
hl = sl;
|
||||
else {
|
||||
r = rlimit_parse_one(resource, hard, &hl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (sl > hl)
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
*ret = (struct rlimit) {
|
||||
.rlim_cur = sl,
|
||||
.rlim_max = hl,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rlimit_format(const struct rlimit *rl, char **ret) {
|
||||
char *s = NULL;
|
||||
|
||||
assert(rl);
|
||||
assert(ret);
|
||||
|
||||
if (rl->rlim_cur >= RLIM_INFINITY && rl->rlim_max >= RLIM_INFINITY)
|
||||
s = strdup("infinity");
|
||||
else if (rl->rlim_cur >= RLIM_INFINITY)
|
||||
(void) asprintf(&s, "infinity:" RLIM_FMT, rl->rlim_max);
|
||||
else if (rl->rlim_max >= RLIM_INFINITY)
|
||||
(void) asprintf(&s, RLIM_FMT ":infinity", rl->rlim_cur);
|
||||
else if (rl->rlim_cur == rl->rlim_max)
|
||||
(void) asprintf(&s, RLIM_FMT, rl->rlim_cur);
|
||||
else
|
||||
(void) asprintf(&s, RLIM_FMT ":" RLIM_FMT, rl->rlim_cur, rl->rlim_max);
|
||||
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* const rlimit_table[_RLIMIT_MAX] = {
|
||||
[RLIMIT_CPU] = "LimitCPU",
|
||||
[RLIMIT_FSIZE] = "LimitFSIZE",
|
||||
|
@ -30,4 +30,9 @@ int rlimit_from_string(const char *s) _pure_;
|
||||
|
||||
int setrlimit_closest(int resource, const struct rlimit *rlim);
|
||||
|
||||
int rlimit_parse_one(int resource, const char *val, rlim_t *ret);
|
||||
int rlimit_parse(int resource, const char *val, struct rlimit *ret);
|
||||
|
||||
int rlimit_format(const struct rlimit *rl, char **ret);
|
||||
|
||||
#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
|
||||
|
@ -127,3 +127,16 @@ time_t mktime_or_timegm(struct tm *tm, bool utc);
|
||||
struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);
|
||||
|
||||
unsigned long usec_to_jiffies(usec_t usec);
|
||||
|
||||
static inline usec_t usec_add(usec_t a, usec_t b) {
|
||||
usec_t c;
|
||||
|
||||
/* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output, and doesn't
|
||||
* overflow. */
|
||||
|
||||
c = a + b;
|
||||
if (c < a || c < b) /* overflow check */
|
||||
return USEC_INFINITY;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
@ -112,29 +112,27 @@ static void busname_done(Unit *u) {
|
||||
n->timer_event_source = sd_event_source_unref(n->timer_event_source);
|
||||
}
|
||||
|
||||
static int busname_arm_timer(BusName *n) {
|
||||
static int busname_arm_timer(BusName *n, usec_t usec) {
|
||||
int r;
|
||||
|
||||
assert(n);
|
||||
|
||||
if (n->timeout_usec <= 0) {
|
||||
n->timer_event_source = sd_event_source_unref(n->timer_event_source);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n->timer_event_source) {
|
||||
r = sd_event_source_set_time(n->timer_event_source, now(CLOCK_MONOTONIC) + n->timeout_usec);
|
||||
r = sd_event_source_set_time(n->timer_event_source, usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_event_source_set_enabled(n->timer_event_source, SD_EVENT_ONESHOT);
|
||||
}
|
||||
|
||||
if (usec == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
r = sd_event_add_time(
|
||||
UNIT(n)->manager->event,
|
||||
&n->timer_event_source,
|
||||
CLOCK_MONOTONIC,
|
||||
now(CLOCK_MONOTONIC) + n->timeout_usec, 0,
|
||||
usec, 0,
|
||||
busname_dispatch_timer, n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -372,7 +370,7 @@ static int busname_coldplug(Unit *u) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = busname_arm_timer(n);
|
||||
r = busname_arm_timer(n, usec_add(u->state_change_timestamp.monotonic, n->timeout_usec));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -397,7 +395,7 @@ static int busname_make_starter(BusName *n, pid_t *_pid) {
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
r = busname_arm_timer(n);
|
||||
r = busname_arm_timer(n, usec_add(now(CLOCK_MONOTONIC), n->timeout_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -475,7 +473,7 @@ static void busname_enter_signal(BusName *n, BusNameState state, BusNameResult f
|
||||
}
|
||||
|
||||
if (r > 0) {
|
||||
r = busname_arm_timer(n);
|
||||
r = busname_arm_timer(n, usec_add(now(CLOCK_MONOTONIC), n->timeout_usec));
|
||||
if (r < 0) {
|
||||
log_unit_warning_errno(UNIT(n), r, "Failed to arm timer: %m");
|
||||
goto fail;
|
||||
|
@ -835,7 +835,8 @@ int bus_exec_context_set_transient_property(
|
||||
UnitSetPropertiesMode mode,
|
||||
sd_bus_error *error) {
|
||||
|
||||
int r;
|
||||
const char *soft = NULL;
|
||||
int r, ri;
|
||||
|
||||
assert(u);
|
||||
assert(c);
|
||||
@ -1492,7 +1493,23 @@ int bus_exec_context_set_transient_property(
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (rlimit_from_string(name) >= 0) {
|
||||
}
|
||||
|
||||
ri = rlimit_from_string(name);
|
||||
if (ri < 0) {
|
||||
soft = endswith(name, "Soft");
|
||||
if (soft) {
|
||||
const char *n;
|
||||
|
||||
n = strndupa(name, soft - name);
|
||||
ri = rlimit_from_string(n);
|
||||
if (ri >= 0)
|
||||
name = n;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (ri >= 0) {
|
||||
uint64_t rl;
|
||||
rlim_t x;
|
||||
|
||||
@ -1510,22 +1527,36 @@ int bus_exec_context_set_transient_property(
|
||||
}
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
int z;
|
||||
_cleanup_free_ char *f = NULL;
|
||||
struct rlimit nl;
|
||||
|
||||
z = rlimit_from_string(name);
|
||||
if (c->rlimit[ri]) {
|
||||
nl = *c->rlimit[ri];
|
||||
|
||||
if (!c->rlimit[z]) {
|
||||
c->rlimit[z] = new(struct rlimit, 1);
|
||||
if (!c->rlimit[z])
|
||||
if (soft)
|
||||
nl.rlim_cur = x;
|
||||
else
|
||||
nl.rlim_max = x;
|
||||
} else
|
||||
/* When the resource limit is not initialized yet, then assign the value to both fields */
|
||||
nl = (struct rlimit) {
|
||||
.rlim_cur = x,
|
||||
.rlim_max = x,
|
||||
};
|
||||
|
||||
r = rlimit_format(&nl, &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (c->rlimit[ri])
|
||||
*c->rlimit[ri] = nl;
|
||||
else {
|
||||
c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
|
||||
if (!c->rlimit[ri])
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
c->rlimit[z]->rlim_cur = c->rlimit[z]->rlim_max = x;
|
||||
|
||||
if (x == RLIM_INFINITY)
|
||||
unit_write_drop_in_private_format(u, mode, name, "%s=infinity\n", name);
|
||||
else
|
||||
unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64 "\n", name, rl);
|
||||
unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, f);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -49,6 +49,7 @@ const sd_bus_vtable bus_service_vtable[] = {
|
||||
SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Service, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("WatchdogUSec", "t", bus_property_get_usec, offsetof(Service, watchdog_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0),
|
||||
SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@ -124,6 +125,19 @@ static int bus_service_set_transient_property(
|
||||
unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s\n", service_type_to_string(s->type));
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else if (streq(name, "RuntimeMaxUSec")) {
|
||||
usec_t u;
|
||||
|
||||
r = sd_bus_message_read(message, "t", &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
s->runtime_max_usec = u;
|
||||
unit_write_drop_in_private_format(UNIT(s), mode, name, "RuntimeMaxSec=" USEC_FMT "us\n", u);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (STR_IN_SET(name,
|
||||
|
@ -267,19 +267,19 @@ static int bus_timer_set_transient_property(
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "AccuracySec")) {
|
||||
|
||||
} else if (STR_IN_SET(name, "AccuracyUSec", "AccuracySec")) {
|
||||
usec_t u = 0;
|
||||
|
||||
if (streq(name, "AccuracySec"))
|
||||
log_notice("Client is using obsolete AccuracySec= transient property, please use AccuracyUSec= instead.");
|
||||
|
||||
r = sd_bus_message_read(message, "t", &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
char time[FORMAT_TIMESPAN_MAX];
|
||||
|
||||
t->accuracy_usec = u;
|
||||
unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
|
||||
unit_write_drop_in_private_format(UNIT(t), mode, name, "AccuracySec=" USEC_FMT "us\n", u);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -292,10 +292,8 @@ static int bus_timer_set_transient_property(
|
||||
return r;
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
char time[FORMAT_TIMESPAN_MAX];
|
||||
|
||||
t->random_usec = u;
|
||||
unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
|
||||
unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=" USEC_FMT "us\n", u);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -674,6 +674,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
|
||||
SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
|
||||
SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
|
||||
BUS_PROPERTY_DUAL_TIMESTAMP("StateChangeTimestamp", offsetof(Unit, state_change_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
|
@ -932,14 +932,14 @@ int job_start_timer(Job *j) {
|
||||
|
||||
j->begin_usec = now(CLOCK_MONOTONIC);
|
||||
|
||||
if (j->unit->job_timeout <= 0)
|
||||
if (j->unit->job_timeout == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
r = sd_event_add_time(
|
||||
j->manager->event,
|
||||
&j->timer_event_source,
|
||||
CLOCK_MONOTONIC,
|
||||
j->begin_usec + j->unit->job_timeout, 0,
|
||||
usec_add(j->begin_usec, j->unit->job_timeout), 0,
|
||||
job_dispatch_timer, j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1117,17 +1117,16 @@ int job_coldplug(Job *j) {
|
||||
if (j->state == JOB_WAITING)
|
||||
job_add_to_run_queue(j);
|
||||
|
||||
if (j->begin_usec == 0 || j->unit->job_timeout == 0)
|
||||
if (j->begin_usec == 0 || j->unit->job_timeout == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
if (j->timer_event_source)
|
||||
j->timer_event_source = sd_event_source_unref(j->timer_event_source);
|
||||
j->timer_event_source = sd_event_source_unref(j->timer_event_source);
|
||||
|
||||
r = sd_event_add_time(
|
||||
j->manager->event,
|
||||
&j->timer_event_source,
|
||||
CLOCK_MONOTONIC,
|
||||
j->begin_usec + j->unit->job_timeout, 0,
|
||||
usec_add(j->begin_usec, j->unit->job_timeout), 0,
|
||||
job_dispatch_timer, j);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to restart timeout for job: %m");
|
||||
|
@ -60,22 +60,22 @@ $1.RestrictAddressFamilies, config_parse_address_families, 0,
|
||||
$1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||
$1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||
$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
|
||||
$1.LimitCPU, config_parse_sec_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitCORE, config_parse_bytes_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitRSS, config_parse_bytes_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitAS, config_parse_bytes_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitMEMLOCK, config_parse_bytes_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitRTTIME, config_parse_usec_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
|
||||
$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs)
|
||||
$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs)
|
||||
$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs)
|
||||
@ -214,6 +214,7 @@ Service.RestartSec, config_parse_sec, 0,
|
||||
Service.TimeoutSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
|
||||
Service.TimeoutStartSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
|
||||
Service.TimeoutStopSec, config_parse_service_timeout, 0, offsetof(Service, timeout_stop_usec)
|
||||
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
|
||||
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
|
||||
Service.StartLimitInterval, config_parse_sec, 0, offsetof(Service, start_limit.interval)
|
||||
Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst)
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "rlimit-util.h"
|
||||
#ifdef HAVE_SECCOMP
|
||||
#include "seccomp-util.h"
|
||||
#endif
|
||||
@ -1101,122 +1102,6 @@ int config_parse_capability_set(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rlim_parse_u64(const char *val, rlim_t *res) {
|
||||
int r = 0;
|
||||
|
||||
if (streq(val, "infinity"))
|
||||
*res = RLIM_INFINITY;
|
||||
else {
|
||||
uint64_t u;
|
||||
|
||||
/* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
|
||||
assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
|
||||
|
||||
r = safe_atou64(val, &u);
|
||||
if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
|
||||
r = -ERANGE;
|
||||
if (r == 0)
|
||||
*res = (rlim_t) u;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int rlim_parse_size(const char *val, rlim_t *res) {
|
||||
int r = 0;
|
||||
|
||||
if (streq(val, "infinity"))
|
||||
*res = RLIM_INFINITY;
|
||||
else {
|
||||
uint64_t u;
|
||||
|
||||
r = parse_size(val, 1024, &u);
|
||||
if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
|
||||
r = -ERANGE;
|
||||
if (r == 0)
|
||||
*res = (rlim_t) u;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int rlim_parse_sec(const char *val, rlim_t *res) {
|
||||
int r = 0;
|
||||
|
||||
if (streq(val, "infinity"))
|
||||
*res = RLIM_INFINITY;
|
||||
else {
|
||||
usec_t t;
|
||||
|
||||
r = parse_sec(val, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY)
|
||||
*res = RLIM_INFINITY;
|
||||
else
|
||||
*res = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC));
|
||||
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int rlim_parse_usec(const char *val, rlim_t *res) {
|
||||
int r = 0;
|
||||
|
||||
if (streq(val, "infinity"))
|
||||
*res = RLIM_INFINITY;
|
||||
else {
|
||||
usec_t t;
|
||||
|
||||
r = parse_time(val, &t, 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY)
|
||||
*res = RLIM_INFINITY;
|
||||
else
|
||||
*res = (rlim_t) t;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int parse_rlimit_range(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *value,
|
||||
struct rlimit **rl,
|
||||
int (*rlim_parser)(const char *, rlim_t *)) {
|
||||
|
||||
const char *whole_value = value;
|
||||
rlim_t soft, hard;
|
||||
_cleanup_free_ char *sword = NULL, *hword = NULL;
|
||||
int nwords, r;
|
||||
|
||||
assert(value);
|
||||
|
||||
/* <value> or <soft:hard> */
|
||||
nwords = extract_many_words(&value, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &sword, &hword, NULL);
|
||||
r = nwords < 0 ? nwords : nwords == 0 ? -EINVAL : 0;
|
||||
|
||||
if (r == 0)
|
||||
r = rlim_parser(sword, &soft);
|
||||
if (r == 0 && nwords == 2)
|
||||
r = rlim_parser(hword, &hard);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", whole_value);
|
||||
return 0;
|
||||
}
|
||||
if (nwords == 2 && soft > hard)
|
||||
return log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid resource value ("RLIM_FMT" > "RLIM_FMT"), ignoring: %s", soft, hard, whole_value);
|
||||
|
||||
if (!*rl) {
|
||||
*rl = new(struct rlimit, 1);
|
||||
if (!*rl)
|
||||
return log_oom();
|
||||
}
|
||||
(*rl)->rlim_cur = soft;
|
||||
(*rl)->rlim_max = nwords == 2 ? hard : soft;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_limit(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
@ -1229,88 +1114,35 @@ int config_parse_limit(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
struct rlimit **rl = data;
|
||||
struct rlimit **rl = data, d = {};
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
rl += ltype;
|
||||
return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_u64);
|
||||
r = rlimit_parse(ltype, rvalue, &d);
|
||||
if (r == -EILSEQ) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rl[ltype])
|
||||
*rl[ltype] = d;
|
||||
else {
|
||||
rl[ltype] = newdup(struct rlimit, &d, 1);
|
||||
if (!rl[ltype])
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_bytes_limit(
|
||||
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) {
|
||||
|
||||
struct rlimit **rl = data;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
rl += ltype;
|
||||
return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_size);
|
||||
}
|
||||
|
||||
int config_parse_sec_limit(
|
||||
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) {
|
||||
|
||||
struct rlimit **rl = data;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
rl += ltype;
|
||||
return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_sec);
|
||||
}
|
||||
|
||||
int config_parse_usec_limit(
|
||||
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) {
|
||||
|
||||
struct rlimit **rl = data;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
rl += ltype;
|
||||
return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_usec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_SYSV_COMPAT
|
||||
int config_parse_sysv_priority(const char *unit,
|
||||
const char *filename,
|
||||
@ -1911,6 +1743,15 @@ int config_parse_service_timeout(const char *unit,
|
||||
} else if (streq(lvalue, "TimeoutStartSec"))
|
||||
s->start_timeout_defined = true;
|
||||
|
||||
/* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
|
||||
* immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
|
||||
* all other timeouts. */
|
||||
|
||||
if (s->timeout_start_usec <= 0)
|
||||
s->timeout_start_usec = USEC_INFINITY;
|
||||
if (s->timeout_stop_usec <= 0)
|
||||
s->timeout_stop_usec = USEC_INFINITY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -58,9 +58,6 @@ int config_parse_exec_capabilities(const char *unit, const char *filename, unsig
|
||||
int config_parse_exec_secure_bits(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);
|
||||
int config_parse_capability_set(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);
|
||||
int config_parse_limit(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);
|
||||
int config_parse_bytes_limit(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);
|
||||
int config_parse_sec_limit(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);
|
||||
int config_parse_usec_limit(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);
|
||||
int config_parse_sysv_priority(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);
|
||||
int config_parse_kill_signal(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);
|
||||
int config_parse_exec_mount_flags(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);
|
||||
|
@ -676,22 +676,22 @@ static int parse_config_file(void) {
|
||||
{ "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval },
|
||||
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
|
||||
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
|
||||
{ "Manager", "DefaultLimitCPU", config_parse_sec_limit, 0, &arg_default_rlimit[RLIMIT_CPU] },
|
||||
{ "Manager", "DefaultLimitFSIZE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] },
|
||||
{ "Manager", "DefaultLimitDATA", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_DATA] },
|
||||
{ "Manager", "DefaultLimitSTACK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_STACK] },
|
||||
{ "Manager", "DefaultLimitCORE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_CORE] },
|
||||
{ "Manager", "DefaultLimitRSS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_RSS] },
|
||||
{ "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE] },
|
||||
{ "Manager", "DefaultLimitAS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_AS] },
|
||||
{ "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC] },
|
||||
{ "Manager", "DefaultLimitMEMLOCK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] },
|
||||
{ "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] },
|
||||
{ "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] },
|
||||
{ "Manager", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] },
|
||||
{ "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] },
|
||||
{ "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] },
|
||||
{ "Manager", "DefaultLimitRTTIME", config_parse_usec_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] },
|
||||
{ "Manager", "DefaultLimitCPU", config_parse_limit, RLIMIT_CPU, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitFSIZE", config_parse_limit, RLIMIT_FSIZE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitDATA", config_parse_limit, RLIMIT_DATA, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitSTACK", config_parse_limit, RLIMIT_STACK, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitCORE", config_parse_limit, RLIMIT_CORE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitRSS", config_parse_limit, RLIMIT_RSS, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitNOFILE", config_parse_limit, RLIMIT_NOFILE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitAS", config_parse_limit, RLIMIT_AS, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitNPROC", config_parse_limit, RLIMIT_NPROC, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitMEMLOCK", config_parse_limit, RLIMIT_MEMLOCK, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitLOCKS", config_parse_limit, RLIMIT_LOCKS, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitSIGPENDING", config_parse_limit, RLIMIT_SIGPENDING, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, RLIMIT_MSGQUEUE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitNICE", config_parse_limit, RLIMIT_NICE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitRTPRIO", config_parse_limit, RLIMIT_RTPRIO, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitRTTIME", config_parse_limit, RLIMIT_RTTIME, arg_default_rlimit },
|
||||
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
|
||||
{ "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
|
||||
{ "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
|
||||
@ -710,8 +710,14 @@ static int parse_config_file(void) {
|
||||
CONF_PATHS_NULSTR("systemd/system.conf.d") :
|
||||
CONF_PATHS_NULSTR("systemd/user.conf.d");
|
||||
|
||||
config_parse_many(fn, conf_dirs_nulstr, "Manager\0",
|
||||
config_item_table_lookup, items, false, NULL);
|
||||
config_parse_many(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, false, NULL);
|
||||
|
||||
/* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY
|
||||
* like everywhere else. */
|
||||
if (arg_default_timeout_start_usec <= 0)
|
||||
arg_default_timeout_start_usec = USEC_INFINITY;
|
||||
if (arg_default_timeout_stop_usec <= 0)
|
||||
arg_default_timeout_stop_usec = USEC_INFINITY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -152,29 +152,27 @@ static void mount_init(Unit *u) {
|
||||
u->ignore_on_isolate = true;
|
||||
}
|
||||
|
||||
static int mount_arm_timer(Mount *m) {
|
||||
static int mount_arm_timer(Mount *m, usec_t usec) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (m->timeout_usec <= 0) {
|
||||
m->timer_event_source = sd_event_source_unref(m->timer_event_source);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m->timer_event_source) {
|
||||
r = sd_event_source_set_time(m->timer_event_source, now(CLOCK_MONOTONIC) + m->timeout_usec);
|
||||
r = sd_event_source_set_time(m->timer_event_source, usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_event_source_set_enabled(m->timer_event_source, SD_EVENT_ONESHOT);
|
||||
}
|
||||
|
||||
if (usec == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
r = sd_event_add_time(
|
||||
UNIT(m)->manager->event,
|
||||
&m->timer_event_source,
|
||||
CLOCK_MONOTONIC,
|
||||
now(CLOCK_MONOTONIC) + m->timeout_usec, 0,
|
||||
usec, 0,
|
||||
mount_dispatch_timer, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -653,7 +651,7 @@ static int mount_coldplug(Unit *u) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = mount_arm_timer(m);
|
||||
r = mount_arm_timer(m, usec_add(u->state_change_timestamp.monotonic, m->timeout_usec));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -725,11 +723,11 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
|
||||
|
||||
r = unit_setup_exec_runtime(UNIT(m));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
r = mount_arm_timer(m);
|
||||
r = mount_arm_timer(m, usec_add(now(CLOCK_MONOTONIC), m->timeout_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
exec_params.environment = UNIT(m)->manager->environment;
|
||||
exec_params.confirm_spawn = UNIT(m)->manager->confirm_spawn;
|
||||
@ -745,21 +743,16 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
|
||||
m->exec_runtime,
|
||||
&pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
r = unit_watch_pid(UNIT(m), pid);
|
||||
if (r < 0)
|
||||
/* FIXME: we need to do something here */
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
*_pid = pid;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
m->timer_event_source = sd_event_source_unref(m->timer_event_source);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void mount_enter_dead(Mount *m, MountResult f) {
|
||||
@ -805,7 +798,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
|
||||
goto fail;
|
||||
|
||||
if (r > 0) {
|
||||
r = mount_arm_timer(m);
|
||||
r = mount_arm_timer(m, usec_add(now(CLOCK_MONOTONIC), m->timeout_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -66,29 +66,27 @@ static void scope_done(Unit *u) {
|
||||
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
|
||||
}
|
||||
|
||||
static int scope_arm_timer(Scope *s) {
|
||||
static int scope_arm_timer(Scope *s, usec_t usec) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
if (s->timeout_stop_usec <= 0) {
|
||||
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s->timer_event_source) {
|
||||
r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec);
|
||||
r = sd_event_source_set_time(s->timer_event_source, usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
|
||||
}
|
||||
|
||||
if (usec == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
r = sd_event_add_time(
|
||||
UNIT(s)->manager->event,
|
||||
&s->timer_event_source,
|
||||
CLOCK_MONOTONIC,
|
||||
now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0,
|
||||
usec, 0,
|
||||
scope_dispatch_timer, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -190,20 +188,19 @@ static int scope_coldplug(Unit *u) {
|
||||
assert(s);
|
||||
assert(s->state == SCOPE_DEAD);
|
||||
|
||||
if (s->deserialized_state != s->state) {
|
||||
if (s->deserialized_state == s->state)
|
||||
return 0;
|
||||
|
||||
if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) {
|
||||
r = scope_arm_timer(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED))
|
||||
unit_watch_all_pids(UNIT(s));
|
||||
|
||||
scope_set_state(s, s->deserialized_state);
|
||||
if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) {
|
||||
r = scope_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_stop_usec));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED))
|
||||
unit_watch_all_pids(UNIT(s));
|
||||
|
||||
scope_set_state(s, s->deserialized_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -261,7 +258,7 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
|
||||
r = 1;
|
||||
|
||||
if (r > 0) {
|
||||
r = scope_arm_timer(s);
|
||||
r = scope_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -112,6 +112,7 @@ static void service_init(Unit *u) {
|
||||
s->timeout_start_usec = u->manager->default_timeout_start_usec;
|
||||
s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
|
||||
s->restart_usec = u->manager->default_restart_usec;
|
||||
s->runtime_max_usec = USEC_INFINITY;
|
||||
s->type = _SERVICE_TYPE_INVALID;
|
||||
s->socket_fd = -1;
|
||||
s->bus_endpoint_fd = -1;
|
||||
@ -216,7 +217,7 @@ static void service_start_watchdog(Service *s) {
|
||||
return;
|
||||
|
||||
if (s->watchdog_event_source) {
|
||||
r = sd_event_source_set_time(s->watchdog_event_source, s->watchdog_timestamp.monotonic + s->watchdog_usec);
|
||||
r = sd_event_source_set_time(s->watchdog_event_source, usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec));
|
||||
if (r < 0) {
|
||||
log_unit_warning_errno(UNIT(s), r, "Failed to reset watchdog timer: %m");
|
||||
return;
|
||||
@ -228,7 +229,7 @@ static void service_start_watchdog(Service *s) {
|
||||
UNIT(s)->manager->event,
|
||||
&s->watchdog_event_source,
|
||||
CLOCK_MONOTONIC,
|
||||
s->watchdog_timestamp.monotonic + s->watchdog_usec, 0,
|
||||
usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec), 0,
|
||||
service_dispatch_watchdog, s);
|
||||
if (r < 0) {
|
||||
log_unit_warning_errno(UNIT(s), r, "Failed to add watchdog timer: %m");
|
||||
@ -433,18 +434,21 @@ static int service_arm_timer(Service *s, usec_t usec) {
|
||||
assert(s);
|
||||
|
||||
if (s->timer_event_source) {
|
||||
r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + usec);
|
||||
r = sd_event_source_set_time(s->timer_event_source, usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
|
||||
}
|
||||
|
||||
if (usec == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
r = sd_event_add_time(
|
||||
UNIT(s)->manager->event,
|
||||
&s->timer_event_source,
|
||||
CLOCK_MONOTONIC,
|
||||
now(CLOCK_MONOTONIC) + usec, 0,
|
||||
usec, 0,
|
||||
service_dispatch_timer, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -509,6 +513,9 @@ static int service_verify(Service *s) {
|
||||
if (!s->usb_function_descriptors && s->usb_function_strings)
|
||||
log_unit_warning(UNIT(s), "Service has USBFunctionStrings= setting, but no USBFunctionDescriptors=. Ignoring.");
|
||||
|
||||
if (s->runtime_max_usec != USEC_INFINITY && s->type == SERVICE_ONESHOT)
|
||||
log_unit_warning(UNIT(s), "MaxRuntimeSec= has no effect in combination with Type=oneshot. Ignoring.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -624,7 +631,7 @@ static int service_add_extras(Service *s) {
|
||||
|
||||
/* Oneshot services have disabled start timeout by default */
|
||||
if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined)
|
||||
s->timeout_start_usec = 0;
|
||||
s->timeout_start_usec = USEC_INFINITY;
|
||||
|
||||
service_fix_output(s);
|
||||
|
||||
@ -882,6 +889,7 @@ static void service_set_state(Service *s, ServiceState state) {
|
||||
|
||||
if (!IN_SET(state,
|
||||
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
|
||||
SERVICE_RUNNING,
|
||||
SERVICE_RELOAD,
|
||||
SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
|
||||
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
|
||||
@ -954,6 +962,37 @@ static void service_set_state(Service *s, ServiceState state) {
|
||||
unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
|
||||
}
|
||||
|
||||
static usec_t service_coldplug_timeout(Service *s) {
|
||||
assert(s);
|
||||
|
||||
switch (s->deserialized_state) {
|
||||
|
||||
case SERVICE_START_PRE:
|
||||
case SERVICE_START:
|
||||
case SERVICE_START_POST:
|
||||
case SERVICE_RELOAD:
|
||||
return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_start_usec);
|
||||
|
||||
case SERVICE_RUNNING:
|
||||
return usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec);
|
||||
|
||||
case SERVICE_STOP:
|
||||
case SERVICE_STOP_SIGABRT:
|
||||
case SERVICE_STOP_SIGTERM:
|
||||
case SERVICE_STOP_SIGKILL:
|
||||
case SERVICE_STOP_POST:
|
||||
case SERVICE_FINAL_SIGTERM:
|
||||
case SERVICE_FINAL_SIGKILL:
|
||||
return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_stop_usec);
|
||||
|
||||
case SERVICE_AUTO_RESTART:
|
||||
return usec_add(UNIT(s)->inactive_enter_timestamp.monotonic, s->restart_usec);
|
||||
|
||||
default:
|
||||
return USEC_INFINITY;
|
||||
}
|
||||
}
|
||||
|
||||
static int service_coldplug(Unit *u) {
|
||||
Service *s = SERVICE(u);
|
||||
int r;
|
||||
@ -964,31 +1003,9 @@ static int service_coldplug(Unit *u) {
|
||||
if (s->deserialized_state == s->state)
|
||||
return 0;
|
||||
|
||||
if (IN_SET(s->deserialized_state,
|
||||
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
|
||||
SERVICE_RELOAD,
|
||||
SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
|
||||
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
|
||||
|
||||
usec_t k;
|
||||
|
||||
k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec;
|
||||
|
||||
/* For the start/stop timeouts 0 means off */
|
||||
if (k > 0) {
|
||||
r = service_arm_timer(s, k);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->deserialized_state == SERVICE_AUTO_RESTART) {
|
||||
|
||||
/* The restart timeouts 0 means immediately */
|
||||
r = service_arm_timer(s, s->restart_usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
r = service_arm_timer(s, service_coldplug_timeout(s));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (s->main_pid > 0 &&
|
||||
pid_is_unwaited(s->main_pid) &&
|
||||
@ -1175,7 +1192,7 @@ static int service_spawn(
|
||||
|
||||
r = unit_setup_exec_runtime(UNIT(s));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
if (pass_fds ||
|
||||
s->exec_context.std_input == EXEC_INPUT_SOCKET ||
|
||||
@ -1184,55 +1201,42 @@ static int service_spawn(
|
||||
|
||||
r = service_collect_fds(s, &fds, &fd_names);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
n_fds = r;
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
r = service_arm_timer(s, timeout);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
} else
|
||||
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
|
||||
r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), timeout));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = unit_full_printf_strv(UNIT(s), c->argv, &argv);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
our_env = new0(char*, 6);
|
||||
if (!our_env) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (!our_env)
|
||||
return -ENOMEM;
|
||||
|
||||
if (is_control ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE)
|
||||
if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (s->main_pid > 0)
|
||||
if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
|
||||
if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (s->socket_fd >= 0) {
|
||||
union sockaddr_union sa;
|
||||
socklen_t salen = sizeof(sa);
|
||||
|
||||
r = getpeername(s->socket_fd, &sa.sa, &salen);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (IN_SET(sa.sa.sa_family, AF_INET, AF_INET6)) {
|
||||
_cleanup_free_ char *addr = NULL;
|
||||
@ -1241,34 +1245,26 @@ static int service_spawn(
|
||||
|
||||
r = sockaddr_pretty(&sa.sa, salen, true, false, &addr);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
t = strappend("REMOTE_ADDR=", addr);
|
||||
if (!t) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
our_env[n_env++] = t;
|
||||
|
||||
port = sockaddr_port(&sa.sa);
|
||||
if (port < 0) {
|
||||
r = port;
|
||||
goto fail;
|
||||
}
|
||||
if (port < 0)
|
||||
return port;
|
||||
|
||||
if (asprintf(&t, "REMOTE_PORT=%u", port) < 0) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (asprintf(&t, "REMOTE_PORT=%u", port) < 0)
|
||||
return -ENOMEM;
|
||||
our_env[n_env++] = t;
|
||||
}
|
||||
}
|
||||
|
||||
final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
|
||||
if (!final_env) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (!final_env)
|
||||
return -ENOMEM;
|
||||
|
||||
if (is_control && UNIT(s)->cgroup_path) {
|
||||
path = strjoina(UNIT(s)->cgroup_path, "/control");
|
||||
@ -1280,7 +1276,7 @@ static int service_spawn(
|
||||
r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == MANAGER_SYSTEM ? "system" : "user",
|
||||
UNIT(s)->id, &bus_endpoint_path);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
/* Pass the fd to the exec_params so that the child process can upload the policy.
|
||||
* Keep a reference to the fd in the service, so the endpoint is kept alive as long
|
||||
@ -1314,22 +1310,16 @@ static int service_spawn(
|
||||
s->exec_runtime,
|
||||
&pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
r = unit_watch_pid(UNIT(s), pid);
|
||||
if (r < 0)
|
||||
/* FIXME: we need to do something here */
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
*_pid = pid;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (timeout)
|
||||
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int main_pid_good(Service *s) {
|
||||
@ -1437,7 +1427,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||
|
||||
if (allow_restart && service_shall_restart(s)) {
|
||||
|
||||
r = service_arm_timer(s, s->restart_usec);
|
||||
r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -1458,7 +1448,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||
* out-of-date, and some software might be confused by it, so
|
||||
* let's remove it. */
|
||||
if (s->pid_file)
|
||||
unlink_noerrno(s->pid_file);
|
||||
(void) unlink(s->pid_file);
|
||||
|
||||
return;
|
||||
|
||||
@ -1545,11 +1535,9 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
|
||||
goto fail;
|
||||
|
||||
if (r > 0) {
|
||||
if (s->timeout_stop_usec > 0) {
|
||||
r = service_arm_timer(s, s->timeout_stop_usec);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
service_set_state(s, state);
|
||||
} else if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM) && s->kill_context.send_sigkill)
|
||||
@ -1577,8 +1565,7 @@ static void service_enter_stop_by_notify(Service *s) {
|
||||
|
||||
unit_watch_all_pids(UNIT(s));
|
||||
|
||||
if (s->timeout_stop_usec > 0)
|
||||
service_arm_timer(s, s->timeout_stop_usec);
|
||||
service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
|
||||
|
||||
/* The service told us it's stopping, so it's as if we SIGTERM'd it. */
|
||||
service_set_state(s, SERVICE_STOP_SIGTERM);
|
||||
@ -1656,8 +1643,10 @@ static void service_enter_running(Service *s, ServiceResult f) {
|
||||
service_enter_reload_by_notify(s);
|
||||
else if (s->notify_state == NOTIFY_STOPPING)
|
||||
service_enter_stop_by_notify(s);
|
||||
else
|
||||
else {
|
||||
service_set_state(s, SERVICE_RUNNING);
|
||||
service_arm_timer(s, usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec));
|
||||
}
|
||||
|
||||
} else if (s->remain_after_exit)
|
||||
service_set_state(s, SERVICE_EXITED);
|
||||
@ -1711,6 +1700,7 @@ static void service_kill_control_processes(Service *s) {
|
||||
|
||||
static void service_enter_start(Service *s) {
|
||||
ExecCommand *c;
|
||||
usec_t timeout;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
@ -1742,9 +1732,16 @@ static void service_enter_start(Service *s) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IN_SET(s->type, SERVICE_SIMPLE, SERVICE_IDLE))
|
||||
/* For simple + idle this is the main process. We don't apply any timeout here, but
|
||||
* service_enter_running() will later apply the .runtime_max_usec timeout. */
|
||||
timeout = USEC_INFINITY;
|
||||
else
|
||||
timeout = s->timeout_start_usec;
|
||||
|
||||
r = service_spawn(s,
|
||||
c,
|
||||
IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_ONESHOT) ? s->timeout_start_usec : 0,
|
||||
timeout,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
@ -1754,7 +1751,7 @@ static void service_enter_start(Service *s) {
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (s->type == SERVICE_SIMPLE || s->type == SERVICE_IDLE) {
|
||||
if (IN_SET(s->type, SERVICE_SIMPLE, SERVICE_IDLE)) {
|
||||
/* For simple services we immediately start
|
||||
* the START_POST binaries. */
|
||||
|
||||
@ -1769,9 +1766,7 @@ static void service_enter_start(Service *s) {
|
||||
s->control_pid = pid;
|
||||
service_set_state(s, SERVICE_START);
|
||||
|
||||
} else if (s->type == SERVICE_ONESHOT ||
|
||||
s->type == SERVICE_DBUS ||
|
||||
s->type == SERVICE_NOTIFY) {
|
||||
} else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY)) {
|
||||
|
||||
/* For oneshot services we wait until the start
|
||||
* process exited, too, but it is our main process. */
|
||||
@ -1840,7 +1835,7 @@ static void service_enter_restart(Service *s) {
|
||||
/* Don't restart things if we are going down anyway */
|
||||
log_unit_info(UNIT(s), "Stop job pending for unit, delaying automatic restart.");
|
||||
|
||||
r = service_arm_timer(s, s->restart_usec);
|
||||
r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -1870,9 +1865,7 @@ fail:
|
||||
static void service_enter_reload_by_notify(Service *s) {
|
||||
assert(s);
|
||||
|
||||
if (s->timeout_start_usec > 0)
|
||||
service_arm_timer(s, s->timeout_start_usec);
|
||||
|
||||
service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_start_usec));
|
||||
service_set_state(s, SERVICE_RELOAD);
|
||||
}
|
||||
|
||||
@ -1913,6 +1906,7 @@ fail:
|
||||
}
|
||||
|
||||
static void service_run_next_control(Service *s) {
|
||||
usec_t timeout;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
@ -1924,9 +1918,14 @@ static void service_run_next_control(Service *s) {
|
||||
s->control_command = s->control_command->command_next;
|
||||
service_unwatch_control_pid(s);
|
||||
|
||||
if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
|
||||
timeout = s->timeout_start_usec;
|
||||
else
|
||||
timeout = s->timeout_stop_usec;
|
||||
|
||||
r = service_spawn(s,
|
||||
s->control_command,
|
||||
IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec,
|
||||
timeout,
|
||||
false,
|
||||
!s->permissions_start_only,
|
||||
!s->root_directory_start_only,
|
||||
@ -2882,6 +2881,11 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
|
||||
service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
|
||||
break;
|
||||
|
||||
case SERVICE_RUNNING:
|
||||
log_unit_warning(UNIT(s), "Service reached runtime time limit. Stopping.");
|
||||
service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
|
||||
break;
|
||||
|
||||
case SERVICE_RELOAD:
|
||||
log_unit_warning(UNIT(s), "Reload operation timed out. Stopping.");
|
||||
service_unwatch_control_pid(s);
|
||||
|
@ -118,6 +118,7 @@ struct Service {
|
||||
usec_t restart_usec;
|
||||
usec_t timeout_start_usec;
|
||||
usec_t timeout_stop_usec;
|
||||
usec_t runtime_max_usec;
|
||||
|
||||
dual_timestamp watchdog_timestamp;
|
||||
usec_t watchdog_usec;
|
||||
|
@ -170,29 +170,27 @@ static void socket_done(Unit *u) {
|
||||
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
|
||||
}
|
||||
|
||||
static int socket_arm_timer(Socket *s) {
|
||||
static int socket_arm_timer(Socket *s, usec_t usec) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
if (s->timeout_usec <= 0) {
|
||||
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s->timer_event_source) {
|
||||
r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec);
|
||||
r = sd_event_source_set_time(s->timer_event_source, usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
|
||||
}
|
||||
|
||||
if (usec == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
r = sd_event_add_time(
|
||||
UNIT(s)->manager->event,
|
||||
&s->timer_event_source,
|
||||
CLOCK_MONOTONIC,
|
||||
now(CLOCK_MONOTONIC) + s->timeout_usec, 0,
|
||||
usec, 0,
|
||||
socket_dispatch_timer, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1494,7 +1492,7 @@ static int socket_coldplug(Unit *u) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = socket_arm_timer(s);
|
||||
r = socket_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -1507,6 +1505,7 @@ static int socket_coldplug(Unit *u) {
|
||||
SOCKET_STOP_PRE,
|
||||
SOCKET_STOP_PRE_SIGTERM,
|
||||
SOCKET_STOP_PRE_SIGKILL)) {
|
||||
|
||||
r = socket_open_fds(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1548,15 +1547,15 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
|
||||
|
||||
r = unit_setup_exec_runtime(UNIT(s));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
r = socket_arm_timer(s);
|
||||
r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
r = unit_full_printf_strv(UNIT(s), c->argv, &argv);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
exec_params.argv = argv;
|
||||
exec_params.environment = UNIT(s)->manager->environment;
|
||||
@ -1573,26 +1572,22 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
|
||||
s->exec_runtime,
|
||||
&pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
r = unit_watch_pid(UNIT(s), pid);
|
||||
if (r < 0)
|
||||
/* FIXME: we need to do something here */
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
*_pid = pid;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int socket_chown(Socket *s, pid_t *_pid) {
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
r = socket_arm_timer(s);
|
||||
r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -1735,7 +1730,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
|
||||
goto fail;
|
||||
|
||||
if (r > 0) {
|
||||
r = socket_arm_timer(s);
|
||||
r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -160,29 +160,27 @@ static void swap_done(Unit *u) {
|
||||
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
|
||||
}
|
||||
|
||||
static int swap_arm_timer(Swap *s) {
|
||||
static int swap_arm_timer(Swap *s, usec_t usec) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
if (s->timeout_usec <= 0) {
|
||||
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s->timer_event_source) {
|
||||
r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec);
|
||||
r = sd_event_source_set_time(s->timer_event_source, usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
|
||||
}
|
||||
|
||||
if (usec == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
r = sd_event_add_time(
|
||||
UNIT(s)->manager->event,
|
||||
&s->timer_event_source,
|
||||
CLOCK_MONOTONIC,
|
||||
now(CLOCK_MONOTONIC) + s->timeout_usec, 0,
|
||||
usec, 0,
|
||||
swap_dispatch_timer, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -552,7 +550,7 @@ static int swap_coldplug(Unit *u) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = swap_arm_timer(s);
|
||||
r = swap_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -633,7 +631,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = swap_arm_timer(s);
|
||||
r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -710,7 +708,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
|
||||
goto fail;
|
||||
|
||||
if (r > 0) {
|
||||
r = swap_arm_timer(s);
|
||||
r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -99,6 +99,7 @@ Unit *unit_new(Manager *m, size_t size) {
|
||||
u->unit_file_preset = -1;
|
||||
u->on_failure_job_mode = JOB_REPLACE;
|
||||
u->cgroup_inotify_wd = -1;
|
||||
u->job_timeout = USEC_INFINITY;
|
||||
|
||||
RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16);
|
||||
|
||||
@ -869,6 +870,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
Iterator i;
|
||||
const char *prefix2;
|
||||
char
|
||||
timestamp0[FORMAT_TIMESTAMP_MAX],
|
||||
timestamp1[FORMAT_TIMESTAMP_MAX],
|
||||
timestamp2[FORMAT_TIMESTAMP_MAX],
|
||||
timestamp3[FORMAT_TIMESTAMP_MAX],
|
||||
@ -890,6 +892,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
"%s\tInstance: %s\n"
|
||||
"%s\tUnit Load State: %s\n"
|
||||
"%s\tUnit Active State: %s\n"
|
||||
"%s\nState Change Timestamp: %s\n"
|
||||
"%s\tInactive Exit Timestamp: %s\n"
|
||||
"%s\tActive Enter Timestamp: %s\n"
|
||||
"%s\tActive Exit Timestamp: %s\n"
|
||||
@ -907,6 +910,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
prefix, strna(u->instance),
|
||||
prefix, unit_load_state_to_string(u->load_state),
|
||||
prefix, unit_active_state_to_string(unit_active_state(u)),
|
||||
prefix, strna(format_timestamp(timestamp0, sizeof(timestamp0), u->state_change_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->inactive_exit_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->active_enter_timestamp.realtime)),
|
||||
prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->active_exit_timestamp.realtime)),
|
||||
@ -947,7 +951,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
STRV_FOREACH(j, u->dropin_paths)
|
||||
fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
|
||||
|
||||
if (u->job_timeout > 0)
|
||||
if (u->job_timeout != USEC_INFINITY)
|
||||
fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
|
||||
|
||||
if (u->job_timeout_action != FAILURE_ACTION_NONE)
|
||||
@ -1821,19 +1825,17 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
|
||||
|
||||
/* Update timestamps for state changes */
|
||||
if (m->n_reloading <= 0) {
|
||||
dual_timestamp ts;
|
||||
|
||||
dual_timestamp_get(&ts);
|
||||
dual_timestamp_get(&u->state_change_timestamp);
|
||||
|
||||
if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
|
||||
u->inactive_exit_timestamp = ts;
|
||||
u->inactive_exit_timestamp = u->state_change_timestamp;
|
||||
else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns))
|
||||
u->inactive_enter_timestamp = ts;
|
||||
u->inactive_enter_timestamp = u->state_change_timestamp;
|
||||
|
||||
if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
|
||||
u->active_enter_timestamp = ts;
|
||||
u->active_enter_timestamp = u->state_change_timestamp;
|
||||
else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
|
||||
u->active_exit_timestamp = ts;
|
||||
u->active_exit_timestamp = u->state_change_timestamp;
|
||||
}
|
||||
|
||||
/* Keep track of failed units */
|
||||
@ -2553,10 +2555,13 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
|
||||
}
|
||||
}
|
||||
|
||||
dual_timestamp_serialize(f, "state-change-timestamp", &u->state_change_timestamp);
|
||||
|
||||
dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
|
||||
dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp);
|
||||
dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp);
|
||||
dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
|
||||
|
||||
dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp);
|
||||
dual_timestamp_serialize(f, "assert-timestamp", &u->assert_timestamp);
|
||||
|
||||
@ -2695,7 +2700,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
|
||||
/* End marker */
|
||||
if (isempty(l))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
k = strcspn(l, "=");
|
||||
|
||||
@ -2735,6 +2740,9 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
} else /* legacy for pre-44 */
|
||||
log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v);
|
||||
continue;
|
||||
} else if (streq(l, "state-change-timestamp")) {
|
||||
dual_timestamp_deserialize(v, &u->state_change_timestamp);
|
||||
continue;
|
||||
} else if (streq(l, "inactive-exit-timestamp")) {
|
||||
dual_timestamp_deserialize(v, &u->inactive_exit_timestamp);
|
||||
continue;
|
||||
@ -2841,6 +2849,15 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Versions before 228 did not carry a state change timestamp. In this case, take the current time. This is
|
||||
* useful, so that timeouts based on this timestamp don't trigger too early, and is in-line with the logic from
|
||||
* before 228 where the base for timeouts was not peristet across reboots. */
|
||||
|
||||
if (!dual_timestamp_is_set(&u->state_change_timestamp))
|
||||
dual_timestamp_get(&u->state_change_timestamp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep) {
|
||||
|
@ -121,6 +121,10 @@ struct Unit {
|
||||
dual_timestamp condition_timestamp;
|
||||
dual_timestamp assert_timestamp;
|
||||
|
||||
/* Updated whenever the low-level state changes */
|
||||
dual_timestamp state_change_timestamp;
|
||||
|
||||
/* Updated whenever the (high-level) active state enters or leaves the active or inactive states */
|
||||
dual_timestamp inactive_exit_timestamp;
|
||||
dual_timestamp active_enter_timestamp;
|
||||
dual_timestamp active_exit_timestamp;
|
||||
|
@ -635,16 +635,19 @@ static int enumerate_partitions(dev_t devnum) {
|
||||
if (r == 1)
|
||||
return 0; /* no results */
|
||||
else if (r == -2) {
|
||||
log_warning("%s: probe gave ambiguous results, ignoring", node);
|
||||
log_warning("%s: probe gave ambiguous results, ignoring.", node);
|
||||
return 0;
|
||||
} else if (r != 0)
|
||||
return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
|
||||
if (r != 0)
|
||||
return log_error_errno(errno ?: EIO,
|
||||
"%s: failed to determine partition table type: %m", node);
|
||||
if (r != 0) {
|
||||
if (errno == 0)
|
||||
return 0; /* No partition table found. */
|
||||
|
||||
return log_error_errno(errno, "%s: failed to determine partition table type: %m", node);
|
||||
}
|
||||
|
||||
/* We only do this all for GPT... */
|
||||
if (!streq_ptr(pttype, "gpt")) {
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include "syslog-util.h"
|
||||
#include "util.h"
|
||||
|
||||
static char *arg_identifier = NULL;
|
||||
static const char *arg_identifier = NULL;
|
||||
static int arg_priority = LOG_INFO;
|
||||
static bool arg_level_prefix = true;
|
||||
|
||||
@ -82,14 +82,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return version();
|
||||
|
||||
case 't':
|
||||
free(arg_identifier);
|
||||
if (isempty(optarg))
|
||||
arg_identifier = NULL;
|
||||
else {
|
||||
arg_identifier = strdup(optarg);
|
||||
if (!arg_identifier)
|
||||
return log_oom();
|
||||
}
|
||||
else
|
||||
arg_identifier = optarg;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
|
@ -327,6 +327,10 @@ static int earliest_time_prioq_compare(const void *a, const void *b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static usec_t time_event_source_latest(const sd_event_source *s) {
|
||||
return usec_add(s->time.next, s->time.accuracy);
|
||||
}
|
||||
|
||||
static int latest_time_prioq_compare(const void *a, const void *b) {
|
||||
const sd_event_source *x = a, *y = b;
|
||||
|
||||
@ -346,9 +350,9 @@ static int latest_time_prioq_compare(const void *a, const void *b) {
|
||||
return 1;
|
||||
|
||||
/* Order by time */
|
||||
if (x->time.next + x->time.accuracy < y->time.next + y->time.accuracy)
|
||||
if (time_event_source_latest(x) < time_event_source_latest(y))
|
||||
return -1;
|
||||
if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy)
|
||||
if (time_event_source_latest(x) > time_event_source_latest(y))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@ -1066,7 +1070,6 @@ _public_ int sd_event_add_time(
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
assert_return(usec != (uint64_t) -1, -EINVAL);
|
||||
assert_return(accuracy != (uint64_t) -1, -EINVAL);
|
||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(!event_pid_changed(e), -ECHILD);
|
||||
@ -1756,7 +1759,6 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) {
|
||||
struct clock_data *d;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(usec != (uint64_t) -1, -EINVAL);
|
||||
assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM);
|
||||
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||
@ -1886,6 +1888,8 @@ static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) {
|
||||
|
||||
if (a <= 0)
|
||||
return 0;
|
||||
if (a >= USEC_INFINITY)
|
||||
return USEC_INFINITY;
|
||||
|
||||
if (b <= a + 1)
|
||||
return a;
|
||||
@ -1975,7 +1979,7 @@ static int event_arm_timer(
|
||||
d->needs_rearm = false;
|
||||
|
||||
a = prioq_peek(d->earliest);
|
||||
if (!a || a->enabled == SD_EVENT_OFF) {
|
||||
if (!a || a->enabled == SD_EVENT_OFF || a->time.next == USEC_INFINITY) {
|
||||
|
||||
if (d->fd < 0)
|
||||
return 0;
|
||||
@ -1995,7 +1999,7 @@ static int event_arm_timer(
|
||||
b = prioq_peek(d->latest);
|
||||
assert_se(b && b->enabled != SD_EVENT_OFF);
|
||||
|
||||
t = sleep_between(e, a->time.next, b->time.next + b->time.accuracy);
|
||||
t = sleep_between(e, a->time.next, time_event_source_latest(b));
|
||||
if (d->next == t)
|
||||
return 0;
|
||||
|
||||
|
@ -44,11 +44,8 @@ static int sd_netlink_new(sd_netlink **ret) {
|
||||
return -ENOMEM;
|
||||
|
||||
rtnl->n_ref = REFCNT_INIT;
|
||||
|
||||
rtnl->fd = -1;
|
||||
|
||||
rtnl->sockaddr.nl.nl_family = AF_NETLINK;
|
||||
|
||||
rtnl->original_pid = getpid();
|
||||
|
||||
LIST_HEAD_INIT(rtnl->match_callbacks);
|
||||
@ -87,6 +84,9 @@ int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) {
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (rtnl->sockaddr.nl.nl_family != AF_NETLINK)
|
||||
return -EINVAL;
|
||||
|
||||
rtnl->fd = fd;
|
||||
|
||||
*ret = rtnl;
|
||||
@ -118,8 +118,10 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) {
|
||||
rtnl->fd = fd;
|
||||
|
||||
r = socket_bind(rtnl);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret = rtnl;
|
||||
rtnl = NULL;
|
||||
|
@ -166,17 +166,9 @@ int register_machine(
|
||||
}
|
||||
|
||||
STRV_FOREACH(i, properties) {
|
||||
r = sd_bus_message_open_container(m, 'r', "sv");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = bus_append_unit_property_assignment(m, *i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
|
@ -240,31 +240,69 @@ int dns_class_from_string(const char *s) {
|
||||
}
|
||||
|
||||
const char* tlsa_cert_usage_to_string(uint8_t cert_usage) {
|
||||
switch(cert_usage) {
|
||||
case 0: return "CA constraint";
|
||||
case 1: return "Service certificate constraint";
|
||||
case 2: return "Trust anchor assertion";
|
||||
case 3: return "Domain-issued certificate";
|
||||
case 4 ... 254: return "Unassigned";
|
||||
case 255: return "Private use";
|
||||
|
||||
switch (cert_usage) {
|
||||
|
||||
case 0:
|
||||
return "CA constraint";
|
||||
|
||||
case 1:
|
||||
return "Service certificate constraint";
|
||||
|
||||
case 2:
|
||||
return "Trust anchor assertion";
|
||||
|
||||
case 3:
|
||||
return "Domain-issued certificate";
|
||||
|
||||
case 4 ... 254:
|
||||
return "Unassigned";
|
||||
|
||||
case 255:
|
||||
return "Private use";
|
||||
}
|
||||
|
||||
return NULL; /* clang cannot count that we covered everything */
|
||||
}
|
||||
|
||||
const char* tlsa_selector_to_string(uint8_t selector) {
|
||||
switch(selector) {
|
||||
case 0: return "Full Certificate";
|
||||
case 1: return "SubjectPublicKeyInfo";
|
||||
case 2 ... 254: return "Unassigned";
|
||||
case 255: return "Private use";
|
||||
switch (selector) {
|
||||
|
||||
case 0:
|
||||
return "Full Certificate";
|
||||
|
||||
case 1:
|
||||
return "SubjectPublicKeyInfo";
|
||||
|
||||
case 2 ... 254:
|
||||
return "Unassigned";
|
||||
|
||||
case 255:
|
||||
return "Private use";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* tlsa_matching_type_to_string(uint8_t selector) {
|
||||
switch(selector) {
|
||||
case 0: return "No hash used";
|
||||
case 1: return "SHA-256";
|
||||
case 2: return "SHA-512";
|
||||
case 3 ... 254: return "Unassigned";
|
||||
case 255: return "Private use";
|
||||
|
||||
switch (selector) {
|
||||
|
||||
case 0:
|
||||
return "No hash used";
|
||||
|
||||
case 1:
|
||||
return "SHA-256";
|
||||
|
||||
case 2:
|
||||
return "SHA-512";
|
||||
|
||||
case 3 ... 254:
|
||||
return "Unassigned";
|
||||
|
||||
case 255:
|
||||
return "Private use";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -281,6 +281,7 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
|
||||
q->request = sd_bus_message_ref(message);
|
||||
q->request_family = family;
|
||||
q->complete = bus_method_resolve_hostname_complete;
|
||||
q->suppress_unroutable_family = family == AF_UNSPEC;
|
||||
|
||||
r = dns_query_bus_track(q, message);
|
||||
if (r < 0)
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dns-domain.h"
|
||||
#include "dns-type.h"
|
||||
#include "hostname-util.h"
|
||||
#include "local-addresses.h"
|
||||
#include "resolved-dns-query.h"
|
||||
@ -161,6 +162,7 @@ static int dns_query_candidate_go(DnsQueryCandidate *c) {
|
||||
DnsTransaction *t;
|
||||
Iterator i;
|
||||
int r;
|
||||
unsigned n = 0;
|
||||
|
||||
assert(c);
|
||||
|
||||
@ -172,8 +174,14 @@ static int dns_query_candidate_go(DnsQueryCandidate *c) {
|
||||
r = dns_transaction_go(t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
/* If there was nothing to start, then let's proceed immediately */
|
||||
if (n == 0)
|
||||
dns_query_candidate_notify(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -222,6 +230,31 @@ static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) {
|
||||
return state;
|
||||
}
|
||||
|
||||
static bool dns_query_candidate_is_routable(DnsQueryCandidate *c, uint16_t type) {
|
||||
int family;
|
||||
|
||||
assert(c);
|
||||
|
||||
/* Checks whether the specified RR type matches an address family that is routable on the link(s) the scope of
|
||||
* this candidate belongs to. Specifically, whether there's a routable IPv4 address on it if we query an A RR,
|
||||
* or a routable IPv6 address if we query an AAAA RR. */
|
||||
|
||||
if (!c->query->suppress_unroutable_family)
|
||||
return true;
|
||||
|
||||
if (c->scope->protocol != DNS_PROTOCOL_DNS)
|
||||
return true;
|
||||
|
||||
family = dns_type_to_af(type);
|
||||
if (family < 0)
|
||||
return true;
|
||||
|
||||
if (c->scope->link)
|
||||
return link_relevant(c->scope->link, family, false);
|
||||
else
|
||||
return manager_routable(c->scope->manager, family);
|
||||
}
|
||||
|
||||
static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
|
||||
DnsQuestion *question;
|
||||
DnsResourceKey *key;
|
||||
@ -236,14 +269,24 @@ static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
|
||||
/* Create one transaction per question key */
|
||||
DNS_QUESTION_FOREACH(key, question) {
|
||||
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL;
|
||||
DnsResourceKey *qkey;
|
||||
|
||||
if (!dns_query_candidate_is_routable(c, key->type))
|
||||
continue;
|
||||
|
||||
if (c->search_domain) {
|
||||
r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = dns_query_candidate_add_transaction(c, new_key ?: key);
|
||||
qkey = new_key;
|
||||
} else
|
||||
qkey = key;
|
||||
|
||||
if (!dns_scope_good_key(c->scope, qkey))
|
||||
continue;
|
||||
|
||||
r = dns_query_candidate_add_transaction(c, qkey);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -69,6 +69,10 @@ struct DnsQuery {
|
||||
uint64_t flags;
|
||||
int ifindex;
|
||||
|
||||
/* If true, A or AAAA RR lookups will be suppressed on links with no routable address of the matching address
|
||||
* family */
|
||||
bool suppress_unroutable_family;
|
||||
|
||||
DnsTransactionState state;
|
||||
unsigned n_cname_redirects;
|
||||
|
||||
|
@ -490,7 +490,9 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co
|
||||
}
|
||||
}
|
||||
|
||||
int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
|
||||
bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) {
|
||||
int key_family;
|
||||
|
||||
assert(s);
|
||||
assert(key);
|
||||
|
||||
@ -498,6 +500,9 @@ int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
|
||||
* this scope. Note that this call assumes as fully qualified
|
||||
* name, i.e. the search suffixes already appended. */
|
||||
|
||||
if (key->class != DNS_CLASS_IN)
|
||||
return false;
|
||||
|
||||
if (s->protocol == DNS_PROTOCOL_DNS) {
|
||||
|
||||
/* On classic DNS, looking up non-address RRs is always
|
||||
@ -519,13 +524,11 @@ int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {
|
||||
/* On mDNS and LLMNR, send A and AAAA queries only on the
|
||||
* respective scopes */
|
||||
|
||||
if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA)
|
||||
return false;
|
||||
key_family = dns_type_to_af(key->type);
|
||||
if (key_family < 0)
|
||||
return true;
|
||||
|
||||
if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return key_family == s->family;
|
||||
}
|
||||
|
||||
static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in, struct in6_addr in6) {
|
||||
@ -1017,9 +1020,6 @@ bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name) {
|
||||
}
|
||||
|
||||
bool dns_scope_network_good(DnsScope *s) {
|
||||
Iterator i;
|
||||
Link *l;
|
||||
|
||||
/* Checks whether the network is in good state for lookups on this scope. For mDNS/LLMNR/Classic DNS scopes
|
||||
* bound to links this is easy, as they don't even exist if the link isn't in a suitable state. For the global
|
||||
* DNS scope we check whether there are any links that are up and have an address. */
|
||||
@ -1027,10 +1027,5 @@ bool dns_scope_network_good(DnsScope *s) {
|
||||
if (s->link)
|
||||
return true;
|
||||
|
||||
HASHMAP_FOREACH(l, s->manager->links, i) {
|
||||
if (link_relevant(l, AF_UNSPEC, false))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return manager_routable(s->manager, AF_UNSPEC);
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *add
|
||||
int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port);
|
||||
|
||||
DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain);
|
||||
int dns_scope_good_key(DnsScope *s, DnsResourceKey *key);
|
||||
bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key);
|
||||
|
||||
DnsServer *dns_scope_get_dns_server(DnsScope *s);
|
||||
void dns_scope_next_dns_server(DnsScope *s);
|
||||
|
@ -1411,12 +1411,6 @@ static int dns_transaction_make_packet(DnsTransaction *t) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dns_scope_good_key(t->scope, t->key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EDOM;
|
||||
|
||||
r = dns_packet_append_key(p, t->key, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1498,13 +1492,6 @@ int dns_transaction_go(DnsTransaction *t) {
|
||||
|
||||
/* Otherwise, we need to ask the network */
|
||||
r = dns_transaction_make_packet(t);
|
||||
if (r == -EDOM) {
|
||||
/* Not the right request to make on this network?
|
||||
* (i.e. an A request made on IPv6 or an AAAA request
|
||||
* made on IPv4, on LLMNR or mDNS.) */
|
||||
dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -515,14 +515,17 @@ int link_update_monitor(Link *l) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool link_relevant(Link *l, int family, bool multicast) {
|
||||
bool link_relevant(Link *l, int family, bool local_multicast) {
|
||||
_cleanup_free_ char *state = NULL;
|
||||
LinkAddress *a;
|
||||
|
||||
assert(l);
|
||||
|
||||
/* A link is relevant for multicast traffic if it isn't a loopback or pointopoint device, has a link beat, can
|
||||
* do multicast and has at least one relevant IP address */
|
||||
/* A link is relevant for local multicast traffic if it isn't a loopback or pointopoint device, has a link
|
||||
* beat, can do multicast and has at least one link-local (or better) IP address.
|
||||
*
|
||||
* A link is relevant for non-multicast traffic if it isn't a loopback device, has a link beat, and has at
|
||||
* least one routable address.*/
|
||||
|
||||
if (l->flags & (IFF_LOOPBACK|IFF_DORMANT))
|
||||
return false;
|
||||
@ -530,7 +533,7 @@ bool link_relevant(Link *l, int family, bool multicast) {
|
||||
if ((l->flags & (IFF_UP|IFF_LOWER_UP)) != (IFF_UP|IFF_LOWER_UP))
|
||||
return false;
|
||||
|
||||
if (multicast) {
|
||||
if (local_multicast) {
|
||||
if (l->flags & IFF_POINTOPOINT)
|
||||
return false;
|
||||
|
||||
@ -548,7 +551,7 @@ bool link_relevant(Link *l, int family, bool multicast) {
|
||||
return false;
|
||||
|
||||
LIST_FOREACH(addresses, a, l->addresses)
|
||||
if ((family == AF_UNSPEC || a->family == family) && link_address_relevant(a))
|
||||
if ((family == AF_UNSPEC || a->family == family) && link_address_relevant(a, local_multicast))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -692,7 +695,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
|
||||
if (a->family == AF_INET) {
|
||||
|
||||
if (!force_remove &&
|
||||
link_address_relevant(a) &&
|
||||
link_address_relevant(a, true) &&
|
||||
a->link->llmnr_ipv4_scope &&
|
||||
a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
|
||||
a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
|
||||
@ -749,7 +752,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
|
||||
if (a->family == AF_INET6) {
|
||||
|
||||
if (!force_remove &&
|
||||
link_address_relevant(a) &&
|
||||
link_address_relevant(a, true) &&
|
||||
a->link->llmnr_ipv6_scope &&
|
||||
a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
|
||||
a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
|
||||
@ -826,13 +829,13 @@ int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool link_address_relevant(LinkAddress *a) {
|
||||
bool link_address_relevant(LinkAddress *a, bool local_multicast) {
|
||||
assert(a);
|
||||
|
||||
if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
|
||||
return false;
|
||||
|
||||
if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
|
||||
if (a->scope >= (local_multicast ? RT_SCOPE_HOST : RT_SCOPE_LINK))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -89,7 +89,7 @@ int link_new(Manager *m, Link **ret, int ifindex);
|
||||
Link *link_free(Link *l);
|
||||
int link_update_rtnl(Link *l, sd_netlink_message *m);
|
||||
int link_update_monitor(Link *l);
|
||||
bool link_relevant(Link *l, int family, bool multicast);
|
||||
bool link_relevant(Link *l, int family, bool local_multicast);
|
||||
LinkAddress* link_find_address(Link *l, int family, const union in_addr_union *in_addr);
|
||||
void link_add_rrs(Link *l, bool force_remove);
|
||||
|
||||
@ -107,7 +107,7 @@ bool link_dnssec_supported(Link *l);
|
||||
int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr);
|
||||
LinkAddress *link_address_free(LinkAddress *a);
|
||||
int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m);
|
||||
bool link_address_relevant(LinkAddress *l);
|
||||
bool link_address_relevant(LinkAddress *l, bool local_multicast);
|
||||
void link_address_add_rrs(LinkAddress *a, bool force_remove);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free);
|
||||
|
@ -1226,3 +1226,18 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource
|
||||
|
||||
m->n_dnssec_verdict[verdict]++;
|
||||
}
|
||||
|
||||
bool manager_routable(Manager *m, int family) {
|
||||
Iterator i;
|
||||
Link *l;
|
||||
|
||||
assert(m);
|
||||
|
||||
/* Returns true if the host has at least one interface with a routable address of the specified type */
|
||||
|
||||
HASHMAP_FOREACH(l, m->links, i)
|
||||
if (link_relevant(l, family, false))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -169,3 +169,5 @@ DnssecMode manager_get_dnssec_mode(Manager *m);
|
||||
bool manager_dnssec_supported(Manager *m);
|
||||
|
||||
void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResourceKey *key);
|
||||
|
||||
bool manager_routable(Manager *m, int family);
|
||||
|
@ -422,17 +422,9 @@ static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(i, properties) {
|
||||
r = sd_bus_message_open_container(m, 'r', "sv");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bus_append_unit_property_assignment(m, *i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1398,7 +1398,7 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
|
||||
|
||||
int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
|
||||
const char *eq, *field;
|
||||
int r;
|
||||
int r, rl;
|
||||
|
||||
assert(m);
|
||||
assert(assignment);
|
||||
@ -1409,20 +1409,18 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
field = strndupa(assignment, eq - assignment);
|
||||
eq ++;
|
||||
|
||||
if (streq(field, "CPUQuota")) {
|
||||
|
||||
if (isempty(eq)) {
|
||||
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "v", "t", USEC_INFINITY);
|
||||
|
||||
} else if (endswith(eq, "%")) {
|
||||
if (isempty(eq))
|
||||
r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
|
||||
else if (endswith(eq, "%")) {
|
||||
double percent;
|
||||
|
||||
if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
|
||||
@ -1430,58 +1428,69 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
|
||||
r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) percent * USEC_PER_SEC / 100);
|
||||
} else {
|
||||
log_error("CPU quota needs to be in percent.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 0;
|
||||
goto finish;
|
||||
|
||||
} else if (streq(field, "EnvironmentFile")) {
|
||||
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "EnvironmentFiles");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "v", "a(sb)", 1,
|
||||
r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1,
|
||||
eq[0] == '-' ? eq + 1 : eq,
|
||||
eq[0] == '-');
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
goto finish;
|
||||
|
||||
return 0;
|
||||
|
||||
} else if (streq(field, "RandomizedDelaySec")) {
|
||||
} else if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) {
|
||||
char *n;
|
||||
usec_t t;
|
||||
|
||||
size_t l;
|
||||
r = parse_sec(eq, &t);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse RandomizedDelaySec= parameter: %s", eq);
|
||||
return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
|
||||
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomizedDelayUSec");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
l = strlen(field);
|
||||
n = newa(char, l + 2);
|
||||
if (!n)
|
||||
return log_oom();
|
||||
|
||||
r = sd_bus_message_append(m, "v", "t", t);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 0;
|
||||
/* Change suffix Sec → USec */
|
||||
strcpy(mempcpy(n, field, l - 3), "USec");
|
||||
r = sd_bus_message_append(m, "sv", n, "t", t);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
if (STR_IN_SET(field,
|
||||
rl = rlimit_from_string(field);
|
||||
if (rl >= 0) {
|
||||
const char *sn;
|
||||
struct rlimit l;
|
||||
|
||||
r = rlimit_parse(rl, eq, &l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse resource limit: %s", eq);
|
||||
|
||||
r = sd_bus_message_append(m, "v", "t", l.rlim_max);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
sn = strjoina(field, "Soft");
|
||||
r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur);
|
||||
|
||||
} else if (STR_IN_SET(field,
|
||||
"CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
|
||||
"SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
|
||||
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
|
||||
@ -1662,21 +1671,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
r = sd_bus_message_append(m, "v", "a(st)", path, u);
|
||||
}
|
||||
|
||||
} else if (rlimit_from_string(field) >= 0) {
|
||||
uint64_t rl;
|
||||
|
||||
if (streq(eq, "infinity"))
|
||||
rl = (uint64_t) -1;
|
||||
else {
|
||||
r = safe_atou64(eq, &rl);
|
||||
if (r < 0) {
|
||||
log_error("Invalid resource limit: %s", eq);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(m, "v", "t", rl);
|
||||
|
||||
} else if (streq(field, "Nice")) {
|
||||
int32_t i;
|
||||
|
||||
@ -1746,16 +1740,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
|
||||
r = sd_bus_message_append(m, "v", "i", sig);
|
||||
|
||||
} else if (streq(field, "AccuracySec")) {
|
||||
usec_t u;
|
||||
|
||||
r = parse_sec(eq, &u);
|
||||
if (r < 0) {
|
||||
log_error("Failed to parse %s value %s", field, eq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(m, "v", "t", u);
|
||||
} else if (streq(field, "TimerSlackNSec")) {
|
||||
nsec_t n;
|
||||
|
||||
@ -1869,6 +1853,11 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
finish:
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
|
@ -4873,17 +4873,9 @@ static int set_property(int argc, char *argv[], void *userdata) {
|
||||
return bus_log_create_error(r);
|
||||
|
||||
STRV_FOREACH(i, strv_skip(argv, 2)) {
|
||||
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = bus_append_unit_property_assignment(m, *i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
|
@ -17,12 +17,37 @@
|
||||
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "capability-util.h"
|
||||
#include "macro.h"
|
||||
#include "rlimit-util.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
static void test_rlimit_parse_format(int resource, const char *string, rlim_t soft, rlim_t hard, int ret, const char *formatted) {
|
||||
_cleanup_free_ char *f = NULL;
|
||||
struct rlimit rl = {
|
||||
.rlim_cur = 4711,
|
||||
.rlim_max = 4712,
|
||||
}, rl2 = {
|
||||
.rlim_cur = 4713,
|
||||
.rlim_max = 4714
|
||||
};
|
||||
|
||||
assert_se(rlimit_parse(resource, string, &rl) == ret);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
assert_se(rl.rlim_cur == soft);
|
||||
assert_se(rl.rlim_max == hard);
|
||||
|
||||
assert_se(rlimit_format(&rl, &f) >= 0);
|
||||
assert_se(streq(formatted, f));
|
||||
|
||||
assert_se(rlimit_parse(resource, formatted, &rl2) >= 0);
|
||||
assert_se(memcmp(&rl, &rl2, sizeof(struct rlimit)) == 0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct rlimit old, new, high;
|
||||
struct rlimit err = {
|
||||
@ -65,5 +90,15 @@ int main(int argc, char *argv[]) {
|
||||
assert_se(old.rlim_cur == new.rlim_cur);
|
||||
assert_se(old.rlim_max == new.rlim_max);
|
||||
|
||||
test_rlimit_parse_format(RLIMIT_NOFILE, "4:5", 4, 5, 0, "4:5");
|
||||
test_rlimit_parse_format(RLIMIT_NOFILE, "6", 6, 6, 0, "6");
|
||||
test_rlimit_parse_format(RLIMIT_NOFILE, "infinity", RLIM_INFINITY, RLIM_INFINITY, 0, "infinity");
|
||||
test_rlimit_parse_format(RLIMIT_NOFILE, "infinity:infinity", RLIM_INFINITY, RLIM_INFINITY, 0, "infinity");
|
||||
test_rlimit_parse_format(RLIMIT_NOFILE, "8:infinity", 8, RLIM_INFINITY, 0, "8:infinity");
|
||||
test_rlimit_parse_format(RLIMIT_CPU, "25min:13h", (25*USEC_PER_MINUTE) / USEC_PER_SEC, (13*USEC_PER_HOUR) / USEC_PER_SEC, 0, "1500:46800");
|
||||
test_rlimit_parse_format(RLIMIT_NOFILE, "", 0, 0, -EINVAL, NULL);
|
||||
test_rlimit_parse_format(RLIMIT_NOFILE, "5:4", 0, 0, -EILSEQ, NULL);
|
||||
test_rlimit_parse_format(RLIMIT_NOFILE, "5:4:3", 0, 0, -EINVAL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -176,9 +176,19 @@ static void test_get_timezones(void) {
|
||||
r = get_timezones(&zones);
|
||||
assert_se(r == 0);
|
||||
|
||||
STRV_FOREACH(zone, zones) {
|
||||
STRV_FOREACH(zone, zones)
|
||||
assert_se(timezone_is_valid(*zone));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_usec_add(void) {
|
||||
assert_se(usec_add(0, 0) == 0);
|
||||
assert_se(usec_add(1, 4) == 5);
|
||||
assert_se(usec_add(USEC_INFINITY, 5) == USEC_INFINITY);
|
||||
assert_se(usec_add(5, USEC_INFINITY) == USEC_INFINITY);
|
||||
assert_se(usec_add(USEC_INFINITY-5, 2) == USEC_INFINITY-3);
|
||||
assert_se(usec_add(USEC_INFINITY-2, 2) == USEC_INFINITY);
|
||||
assert_se(usec_add(USEC_INFINITY-1, 2) == USEC_INFINITY);
|
||||
assert_se(usec_add(USEC_INFINITY, 2) == USEC_INFINITY);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
@ -190,6 +200,7 @@ int main(int argc, char *argv[]) {
|
||||
test_format_timespan(USEC_PER_SEC);
|
||||
test_timezone_is_valid();
|
||||
test_get_timezones();
|
||||
test_usec_add();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -712,12 +712,15 @@ static void test_config_parse_rlimit(void) {
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
|
||||
|
||||
rl[RLIMIT_NOFILE]->rlim_cur = 10;
|
||||
rl[RLIMIT_NOFILE]->rlim_max = 20;
|
||||
|
||||
/* Invalid values don't change rl */
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
|
||||
|
||||
/* Invalid values don't change rl */
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
|
||||
@ -735,64 +738,64 @@ static void test_config_parse_rlimit(void) {
|
||||
|
||||
rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
|
||||
|
||||
assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == 56);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
|
||||
|
||||
assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == 57);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
|
||||
|
||||
assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == 40);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_max == 60);
|
||||
|
||||
assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
|
||||
|
||||
assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == 2);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
|
||||
|
||||
rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
Loading…
x
Reference in New Issue
Block a user