Compare commits

..

22 Commits

Author SHA1 Message Date
Lennart Poettering 611cb82612
Merge pull request #15318 from fbuihuu/inherit-umask-for-user-units
pid1: by default make user units inherit their umask from the user ma…
2020-04-09 17:15:55 +02:00
Lennart Poettering f58921bde3
Merge pull request #15332 from keszybz/coredump-filter
CoredumpFilter=
2020-04-09 17:15:26 +02:00
Jian-Hong Pan e58cd39f63 hwdb: Fix kbd brightness keys on Acer Predator PH 315-52
Acer defines Fn+F9/10 as keyboard brightness down/up on Predator PH
315-52 laptop. So, add the quirk to correct key mappings.
2020-04-09 14:33:12 +02:00
Franck Bui 5e37d1930b pid1: by default make user units inherit their umask from the user manager
This patch changes the way user managers set the default umask for the units it
manages.

Indeed one can expect that if user manager's umask is redefined through PAM
(via /etc/login.defs or pam_umask), all its children including the units it
spawns have their umask set to the new value.

Hence make user units inherit their umask value from their parent instead of
the hard coded value 0022 but allow them to override this value via their unit
file.

Note that reexecuting managers with 'systemctl daemon-reexec' after changing
UMask= has no effect. To take effect managers need to be restarted with
'systemct restart' instead. This behavior was already present before this
patch.

Fixes #6077.
2020-04-09 14:17:07 +02:00
Zbigniew Jędrzejewski-Szmek b94fb74bae manager: also log at debug level failure to read oom_score_adj 2020-04-09 14:08:48 +02:00
Zbigniew Jędrzejewski-Szmek ad21e542b2 manager: add CoredumpFilter= setting
Fixes #6685.
2020-04-09 14:08:48 +02:00
Lennart Poettering 4d1f2c621f
Merge pull request #15345 from keszybz/systemctl-show-spaces
Show Environment= entries with spaces in systemctl
2020-04-09 13:55:35 +02:00
Zbigniew Jędrzejewski-Szmek b34612bd5a Add parser and printer for coredump filter mask 2020-04-09 12:51:41 +02:00
Luca Boccassi a1db42eb0b man: add missing varname around keywords in systemd.unit.xml 2020-04-09 11:55:07 +02:00
Luca Boccassi fe78538cab man: explicitly note that ExecSt*Post does count for After/Before ordering 2020-04-09 11:39:31 +02:00
Zbigniew Jędrzejewski-Szmek ce51632a35 basic/parse-util: add safe_atoux64() 2020-04-09 11:29:55 +02:00
Lennart Poettering 0ed4b54e05 sleep: improve log msg slightly
Let's make the log msgs a bit longer, to make clearer what is going on
here...

Prompted bymy attempts to debug #15354
2020-04-09 10:17:54 +02:00
Zbigniew Jędrzejewski-Szmek 302dc5b913
Merge pull request #15368 from poettering/color-fix
minor terminal ansi color seq fixes
2020-04-09 10:17:18 +02:00
Wen Yang f74349d88b mount-setup: change the system mount propagation to shared by default only at bootup
The commit b3ac5f8cb9 has changed the system mount propagation to
shared by default, and according to the following patch:
https://github.com/opencontainers/runc/pull/208
When starting the container, the pouch daemon will call runc to execute
make-private.

However, if the systemctl daemon-reexec is executed after the container
has been started, the system mount propagation will be changed to share
again by default, and the make-private operation above will have no chance
to execute.
2020-04-09 10:14:20 +02:00
Zbigniew Jędrzejewski-Szmek 241c4b6ada systemctl: show Environment entries with whitespace
This makes the Environment entries more round-trippable: a similar format is
used for input and output. It is certainly more useful for users, because
showing [unprintable] on anything non-trivial makes systemctl show -p Environment
useless in many cases.

Fixes: #14723 and https://bugzilla.redhat.com/show_bug.cgi?id=1525593.

$ systemctl --user show -p Environment run-*.service
Environment=ASDF=asfd "SPACE= "
Environment=ASDF=asfd "SPACE=\n\n\n"
Environment=ASDF=asfd "TAB=\t\\" "FOO=X X"
2020-04-09 09:58:17 +02:00
Zbigniew Jędrzejewski-Szmek 2b99f645c6 shared/escape: add new escape style with \n\t escaped 2020-04-09 09:58:10 +02:00
Zbigniew Jędrzejewski-Szmek ca03142040
Merge pull request #15331 from vcaputo/busdpi
bus: introduce some sd-bus convenience helpers
2020-04-09 09:32:58 +02:00
Marc-André Lureau 2c7039b316 systemd-run: add --slice-inherit
Add a new option to easily place a slice within the systemd-run slice.
2020-04-09 09:32:37 +02:00
Lennart Poettering ba45534917 man: correct the default slice for systemd-run units
As suggested in #15362
2020-04-09 09:32:13 +02:00
Lennart Poettering a45aced09a test-terminal-util: fix typo 2020-04-08 19:45:08 +02:00
Lennart Poettering a851ba0795 terminal-util: fixate underlined yellow color too
non-underlined yellow uses RGB ANSI sequences while the underlined
version uses the paletted ANSI sequences. Let's unify that and use the
RGB sequence for both cases, so that underlined or not doesn't alter the
color.
2020-04-08 19:43:44 +02:00
Vito Caputo 219ab1fbd0 bus: introduce some sd-bus convenience helpers
Many of the convenience functions from sd-bus operate on verbose sets
of discrete strings for destination/path/interface/member.

For most callers, destination/path/interface are uniform, and just the
member is distinct.

This commit introduces a new struct encapsulating the
destination/path/interface pointers called BusAddress, and wrapper
functions which take a BusAddress* instead of three strings, and just
pass the encapsulated strings on to the sd-bus convenience functions.

Future commits will update call sites to use these helpers throwing
out a bunch of repetitious destination/path/interface strings littered
throughout the codebase, replacing them with some appropriately named
static structs passed by pointer to these new helpers.
2020-04-04 13:38:58 -07:00
37 changed files with 714 additions and 46 deletions

View File

@ -114,6 +114,7 @@ All execution-related settings are available for transient units.
✓ SupplementaryGroups=
✓ Nice=
✓ OOMScoreAdjust=
✓ CoredumpFilter=
✓ IOSchedulingClass=
✓ IOSchedulingPriority=
✓ CPUSchedulingPolicy=

View File

@ -160,6 +160,11 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*8930:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*7750G:pvr*
KEYBOARD_KEY_e0=!pageup
# Predator PH 315-52
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnPredator*PH*315-52:pvr*
KEYBOARD_KEY_ef=kbdillumup # Fn+F10
KEYBOARD_KEY_f0=kbdillumdown # Fn+F9
# Travelmate C300
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*C3[01]0*:pvr*
KEYBOARD_KEY_67=f24 # FIXME: rotate screen

View File

@ -146,8 +146,24 @@
<varlistentry>
<term><option>--slice=</option></term>
<listitem><para>Make the new <filename>.service</filename> or <filename>.scope</filename> unit part of the
specified slice, instead of <filename>system.slice</filename>.</para>
<listitem><para>Make the new <filename>.service</filename> or <filename>.scope</filename> unit part
of the specified slice, instead of <filename>system.slice</filename> (when running in
<option>--system</option> mode) or the root slice (when running in <option>--user</option>
mode).</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--slice-inherit</option></term>
<listitem><para>Make the new <filename>.service</filename> or <filename>.scope</filename> unit part
of the inherited slice. This option can be combined with <option>--slice=</option>.</para>
<para>An inherited slice is located within <command>systemd-run</command> slice. Example: if
<command>systemd-run</command> slice is <filename>foo.slice</filename>, and the
<option>--slice=</option> argument is <filename>bar</filename>, the unit will be placed under the
<filename>foo-bar.slice</filename>.</para>
</listitem>
</varlistentry>

View File

@ -652,8 +652,39 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
<term><varname>UMask=</varname></term>
<listitem><para>Controls the file mode creation mask. Takes an access mode in octal notation. See
<citerefentry><refentrytitle>umask</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details. Defaults
to 0022.</para></listitem>
<citerefentry><refentrytitle>umask</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
details. Defaults to 0022 for system units. For units of the user service manager the default value
is inherited from the user instance (whose default is inherited from the system service manager, and
thus also is 0022). Hence changing the default value of a user instance, either via
<varname>UMask=</varname> or via a PAM module, will affect the user instance itself and all user
units started by the user instance unless a user unit has specified its own
<varname>UMask=</varname>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>CoredumpFilter=</varname></term>
<listitem><para>Controls which types of memory mappings will be saved if the process dumps core
(using the <filename>/proc/<replaceable>pid</replaceable>/coredump_filter</filename> file). Takes a
whitespace-separated combination of mapping type names or numbers (with the default base 16). Mapping
type names are <constant>private-anonymous</constant>, <constant>shared-anonymous</constant>,
<constant>private-file-backed</constant>, <constant>shared-file-backed</constant>,
<constant>elf-headers</constant>, <constant>private-huge</constant>,
<constant>shared-huge</constant>, <constant>private-dax</constant>, <constant>shared-dax</constant>,
and the special values <constant>all</constant> (all types) and <constant>default</constant> (the
kernel default of <literal><constant>private-anonymous</constant>
<constant>shared-anonymous</constant> <constant>elf-headers</constant>
<constant>private-huge</constant></literal>). See
<citerefentry><refentrytitle>core</refentrytitle><manvolnum>5</manvolnum></citerefentry> for the
meaning of the mapping types. When specified multiple times, all specified masks are ORed. When not
set, or if the empty value is assigned, the inherited value is not changed.</para>
<example>
<title>Add DAX pages to the dump filter</title>
<programlisting>CoredumpFilter=default private-dax shared-dax</programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry>

View File

@ -423,6 +423,9 @@
<varname>ExecStart=</varname>, or <varname>ExecStartPost=</varname> fail (and are not prefixed with
<literal>-</literal>, see above) or time out before the service is fully up, execution continues with commands
specified in <varname>ExecStopPost=</varname>, the commands in <varname>ExecStop=</varname> are skipped.</para>
<para>Note that the execution of <varname>ExecStartPost=</varname> is taken into account for the purpose of
<varname>Before=</varname>/<varname>After=</varname> ordering constraints.</para>
</listitem>
</varlistentry>
@ -534,7 +537,10 @@
service, as well as the main process' exit code and status, set in the <varname>$SERVICE_RESULT</varname>,
<varname>$EXIT_CODE</varname> and <varname>$EXIT_STATUS</varname> environment variables, see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details.</para></listitem>
details.</para>
<para>Note that the execution of <varname>ExecStopPost=</varname> is taken into account for the purpose of
<varname>Before=</varname>/<varname>After=</varname> ordering constraints.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -750,7 +750,8 @@
type when precisely a unit has finished starting up. Most importantly, for service units start-up is
considered completed for the purpose of <varname>Before=</varname>/<varname>After=</varname> when all
its configured start-up commands have been invoked and they either failed or reported start-up
success.</para>
success. Note that this does includes <varname>ExecStartPost=</varname> (or
<varname>ExecStopPost=</varname> for the shutdown case).</para>
<para>Note that those settings are independent of and orthogonal to the requirement dependencies as
configured by <varname>Requires=</varname>, <varname>Wants=</varname>, <varname>Requisite=</varname>,

View File

@ -518,22 +518,28 @@ char* shell_maybe_quote(const char *s, EscapeStyle style) {
return NULL;
t = r;
if (style == ESCAPE_BACKSLASH)
switch (style) {
case ESCAPE_BACKSLASH:
case ESCAPE_BACKSLASH_ONELINE:
*(t++) = '"';
else if (style == ESCAPE_POSIX) {
break;
case ESCAPE_POSIX:
*(t++) = '$';
*(t++) = '\'';
} else
break;
default:
assert_not_reached("Bad EscapeStyle");
}
t = mempcpy(t, s, p - s);
if (style == ESCAPE_BACKSLASH)
t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE, false);
if (IN_SET(style, ESCAPE_BACKSLASH, ESCAPE_BACKSLASH_ONELINE))
t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE,
style == ESCAPE_BACKSLASH_ONELINE);
else
t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE_POSIX, true);
if (style == ESCAPE_BACKSLASH)
if (IN_SET(style, ESCAPE_BACKSLASH, ESCAPE_BACKSLASH_ONELINE))
*(t++) = '"';
else
*(t++) = '\'';

View File

@ -34,8 +34,13 @@ typedef enum UnescapeFlags {
} UnescapeFlags;
typedef enum EscapeStyle {
ESCAPE_BACKSLASH = 1,
ESCAPE_POSIX = 2,
ESCAPE_BACKSLASH = 1, /* Add shell quotes ("") so the shell will consider this a single
argument, possibly multiline. Tabs and newlines are not escaped. */
ESCAPE_BACKSLASH_ONELINE = 2, /* Similar to ESCAPE_BACKSLASH, but always produces a single-line
string instead. Shell escape sequences are produced for tabs and
newlines. */
ESCAPE_POSIX = 3, /* Similar to ESCAPE_BACKSLASH_ONELINE, but uses POSIX shell escape
* syntax (a string enclosed in $'') instead of plain quotes. */
} EscapeStyle;
char *cescape(const char *s);

View File

@ -395,7 +395,7 @@ int safe_atoi(const char *s, int *ret_i) {
return 0;
}
int safe_atollu(const char *s, long long unsigned *ret_llu) {
int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu) {
char *x = NULL;
unsigned long long l;
@ -404,7 +404,7 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
s += strspn(s, WHITESPACE);
errno = 0;
l = strtoull(s, &x, 0);
l = strtoull(s, &x, base);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)

View File

@ -28,7 +28,6 @@ static inline int safe_atou(const char *s, unsigned *ret_u) {
}
int safe_atoi(const char *s, int *ret_i);
int safe_atollu(const char *s, unsigned long long *ret_u);
int safe_atolli(const char *s, long long int *ret_i);
int safe_atou8(const char *s, uint8_t *ret);
@ -59,6 +58,12 @@ static inline int safe_atoi32(const char *s, int32_t *ret_i) {
return safe_atoi(s, (int*) ret_i);
}
int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu);
static inline int safe_atollu(const char *s, long long unsigned *ret_llu) {
return safe_atollu_full(s, 0, ret_llu);
}
static inline int safe_atou64(const char *s, uint64_t *ret_u) {
assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
return safe_atollu(s, (unsigned long long*) ret_u);
@ -69,6 +74,11 @@ static inline int safe_atoi64(const char *s, int64_t *ret_i) {
return safe_atolli(s, (long long int*) ret_i);
}
static inline int safe_atoux64(const char *s, uint64_t *ret) {
assert_cc(sizeof(int64_t) == sizeof(long long unsigned));
return safe_atollu_full(s, 16, (long long unsigned*) ret);
}
#if LONG_MAX == INT_MAX
static inline int safe_atolu(const char *s, unsigned long *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned));

View File

@ -628,6 +628,23 @@ int get_process_ppid(pid_t pid, pid_t *_ppid) {
return 0;
}
int get_process_umask(pid_t pid, mode_t *umask) {
_cleanup_free_ char *m = NULL;
const char *p;
int r;
assert(umask);
assert(pid >= 0);
p = procfs_file_alloca(pid, "status");
r = get_proc_field(p, "Umask", WHITESPACE, &m);
if (r == -ENOENT)
return -ESRCH;
return parse_mode(m, umask);
}
int wait_for_terminate(pid_t pid, siginfo_t *status) {
siginfo_t dummy;

View File

@ -45,6 +45,7 @@ int get_process_cwd(pid_t pid, char **cwd);
int get_process_root(pid_t pid, char **root);
int get_process_environ(pid_t pid, char **environ);
int get_process_ppid(pid_t pid, pid_t *ppid);
int get_process_umask(pid_t pid, mode_t *umask);
int wait_for_terminate(pid_t pid, siginfo_t *status);

View File

@ -30,7 +30,7 @@
/* Underlined */
#define ANSI_HIGHLIGHT_RED_UNDERLINE "\x1B[0;1;4;31m"
#define ANSI_HIGHLIGHT_GREEN_UNDERLINE "\x1B[0;1;4;32m"
#define ANSI_HIGHLIGHT_YELLOW_UNDERLINE "\x1B[0;1;4;33m"
#define ANSI_HIGHLIGHT_YELLOW_UNDERLINE "\x1B[0;1;4;38;5;185m"
#define ANSI_HIGHLIGHT_BLUE_UNDERLINE "\x1B[0;1;4;34m"
#define ANSI_HIGHLIGHT_MAGENTA_UNDERLINE "\x1B[0;1;4;35m"
#define ANSI_HIGHLIGHT_GREY_UNDERLINE "\x1B[0;1;4;38;5;245m"

View File

@ -102,6 +102,7 @@ static int property_get_oom_score_adjust(
ExecContext *c = userdata;
int32_t n;
int r;
assert(bus);
assert(reply);
@ -113,13 +114,55 @@ static int property_get_oom_score_adjust(
_cleanup_free_ char *t = NULL;
n = 0;
if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
safe_atoi32(t, &n);
r = read_one_line_file("/proc/self/oom_score_adj", &t);
if (r < 0)
log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m");
else {
r = safe_atoi32(t, &n);
if (r < 0)
log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/oom_score_adj, ignoring: %m", t);
}
}
return sd_bus_message_append(reply, "i", n);
}
static int property_get_coredump_filter(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
ExecContext *c = userdata;
uint64_t n;
int r;
assert(bus);
assert(reply);
assert(c);
if (c->coredump_filter_set)
n = c->coredump_filter;
else {
_cleanup_free_ char *t = NULL;
n = COREDUMP_FILTER_MASK_DEFAULT;
r = read_one_line_file("/proc/self/coredump_filter", &t);
if (r < 0)
log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m");
else {
r = safe_atoux64(t, &n);
if (r < 0)
log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t);
}
}
return sd_bus_message_append(reply, "t", n);
}
static int property_get_nice(
sd_bus *bus,
const char *path,
@ -747,6 +790,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IOSchedulingClass", "i", property_get_ioprio_class, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IOSchedulingPriority", "i", property_get_ioprio_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@ -2190,6 +2234,21 @@ int bus_exec_context_set_transient_property(
return 1;
} else if (streq(name, "CoredumpFilter")) {
uint64_t f;
r = sd_bus_message_read(message, "t", &f);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->coredump_filter = f;
c->coredump_filter_set = true;
unit_write_settingf(u, flags, name, "CoredumpFilter=0x%"PRIx64, f);
}
return 1;
} else if (streq(name, "EnvironmentFiles")) {
_cleanup_free_ char *joined = NULL;

View File

@ -3323,6 +3323,14 @@ static int exec_child(
}
}
if (context->coredump_filter_set) {
r = set_coredump_filter(context->coredump_filter);
if (ERRNO_IS_PRIVILEGE(r))
log_unit_debug_errno(unit, r, "Failed to adjust coredump_filter, ignoring: %m");
else if (r < 0)
return log_unit_error_errno(unit, r, "Failed to adjust coredump_filter: %m");
}
if (context->nice_set) {
r = setpriority_closest(context->nice);
if (r < 0)
@ -4614,6 +4622,11 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
"%sOOMScoreAdjust: %i\n",
prefix, c->oom_score_adjust);
if (c->coredump_filter_set)
fprintf(f,
"%sCoredumpFilter: 0x%"PRIx64"\n",
prefix, c->coredump_filter);
for (i = 0; i < RLIM_NLIMITS; i++)
if (c->rlimit[i]) {
fprintf(f, "%sLimit%s: " RLIM_FMT "\n",

View File

@ -14,6 +14,7 @@ typedef struct Manager Manager;
#include <sys/capability.h>
#include "cgroup-util.h"
#include "coredump-util.h"
#include "cpu-set-util.h"
#include "exec-util.h"
#include "fdset.h"
@ -161,6 +162,7 @@ struct ExecContext {
bool working_directory_home:1;
bool oom_score_adjust_set:1;
bool coredump_filter_set:1;
bool nice_set:1;
bool ioprio_set:1;
bool cpu_sched_set:1;
@ -179,6 +181,7 @@ struct ExecContext {
int ioprio;
int cpu_sched_policy;
int cpu_sched_priority;
uint64_t coredump_filter;
CPUSet cpu_set;
NUMAPolicy numa_policy;

View File

@ -28,6 +28,7 @@ $1.Group, config_parse_user_group_compat, 0,
$1.SupplementaryGroups, config_parse_user_group_strv_compat, 0, offsetof($1, exec_context.supplementary_groups)
$1.Nice, config_parse_exec_nice, 0, offsetof($1, exec_context)
$1.OOMScoreAdjust, config_parse_exec_oom_score_adjust, 0, offsetof($1, exec_context)
$1.CoredumpFilter, config_parse_exec_coredump_filter, 0, offsetof($1, exec_context)
$1.IOSchedulingClass, config_parse_exec_io_class, 0, offsetof($1, exec_context)
$1.IOSchedulingPriority, config_parse_exec_io_priority, 0, offsetof($1, exec_context)
$1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0, offsetof($1, exec_context)

View File

@ -592,6 +592,45 @@ int config_parse_exec_oom_score_adjust(
return 0;
}
int config_parse_exec_coredump_filter(
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) {
ExecContext *c = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
if (isempty(rvalue)) {
c->coredump_filter = 0;
c->coredump_filter_set = false;
return 0;
}
uint64_t f;
r = coredump_filter_mask_from_string(rvalue, &f);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse the CoredumpFilter=%s, ignoring: %m", rvalue);
return 0;
}
c->coredump_filter |= f;
c->oom_score_adjust_set = true;
return 0;
}
int config_parse_exec(
const char *unit,
const char *filename,

View File

@ -26,6 +26,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_socket_protocol);
CONFIG_PARSER_PROTOTYPE(config_parse_socket_bind);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_nice);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_oom_score_adjust);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_coredump_filter);
CONFIG_PARSER_PROTOTYPE(config_parse_exec);
CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout);
CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_abort);

View File

@ -2581,7 +2581,7 @@ int main(int argc, char *argv[]) {
if (!skip_setup)
kmod_setup();
r = mount_setup(loaded_policy);
r = mount_setup(loaded_policy, skip_setup);
if (r < 0) {
error_message = "Failed to mount API filesystems";
goto finish;

View File

@ -478,7 +478,7 @@ static int relabel_extra(void) {
}
#endif
int mount_setup(bool loaded_policy) {
int mount_setup(bool loaded_policy, bool leave_propagation) {
int r = 0;
r = mount_points_setup(ELEMENTSOF(mount_table), loaded_policy);
@ -524,7 +524,7 @@ int mount_setup(bool loaded_policy) {
* needed. Note that we set this only when we are invoked directly by the kernel. If we are invoked by a
* container manager we assume the container manager knows what it is doing (for example, because it set up
* some directories with different propagation modes). */
if (detect_container() <= 0)
if (detect_container() <= 0 && !leave_propagation)
if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0)
log_warning_errno(errno, "Failed to set up the root directory for shared mount propagation: %m");

View File

@ -4,7 +4,7 @@
#include <stdbool.h>
int mount_setup_early(void);
int mount_setup(bool loaded_policy);
int mount_setup(bool loaded_policy, bool leave_propagation);
int mount_cgroup_controllers(void);

View File

@ -187,8 +187,16 @@ static void unit_init(Unit *u) {
if (ec) {
exec_context_init(ec);
ec->keyring_mode = MANAGER_IS_SYSTEM(u->manager) ?
EXEC_KEYRING_SHARED : EXEC_KEYRING_INHERIT;
if (MANAGER_IS_SYSTEM(u->manager))
ec->keyring_mode = EXEC_KEYRING_SHARED;
else {
ec->keyring_mode = EXEC_KEYRING_INHERIT;
/* User manager might have its umask redefined by PAM or UMask=. In this
* case let the units it manages inherit this value by default. They can
* still tune this value through their own unit file */
(void) get_process_umask(getpid_cached(), &ec->umask);
}
}
kc = unit_get_kill_context(u);

View File

@ -41,6 +41,7 @@ static bool arg_wait = false;
static const char *arg_unit = NULL;
static const char *arg_description = NULL;
static const char *arg_slice = NULL;
static bool arg_slice_inherit = false;
static bool arg_send_sighup = false;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static const char *arg_host = NULL;
@ -97,6 +98,7 @@ static int help(void) {
" -p --property=NAME=VALUE Set service or scope unit property\n"
" --description=TEXT Description for unit\n"
" --slice=SLICE Run in the specified slice\n"
" --slice-inherit Inherit the slice\n"
" --no-block Do not wait until operation finished\n"
" -r --remain-after-exit Leave service around until explicitly stopped\n"
" --wait Wait until service stopped again\n"
@ -162,6 +164,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SCOPE,
ARG_DESCRIPTION,
ARG_SLICE,
ARG_SLICE_INHERIT,
ARG_SEND_SIGHUP,
ARG_SERVICE_TYPE,
ARG_EXEC_USER,
@ -194,6 +197,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "unit", required_argument, NULL, 'u' },
{ "description", required_argument, NULL, ARG_DESCRIPTION },
{ "slice", required_argument, NULL, ARG_SLICE },
{ "slice-inherit", no_argument, NULL, ARG_SLICE_INHERIT },
{ "remain-after-exit", no_argument, NULL, 'r' },
{ "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP },
{ "host", required_argument, NULL, 'H' },
@ -273,6 +277,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_slice = optarg;
break;
case ARG_SLICE_INHERIT:
arg_slice_inherit = true;
break;
case ARG_SEND_SIGHUP:
arg_send_sighup = true;
break;
@ -637,23 +645,50 @@ static int transient_unit_set_properties(sd_bus_message *m, UnitType t, char **p
}
static int transient_cgroup_set_properties(sd_bus_message *m) {
_cleanup_free_ char *name = NULL;
_cleanup_free_ char *slice = NULL;
int r;
assert(m);
if (!isempty(arg_slice)) {
_cleanup_free_ char *slice = NULL;
if (arg_slice_inherit) {
char *end;
r = unit_name_mangle_with_suffix(arg_slice, "as slice",
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
".slice", &slice);
if (arg_user)
r = cg_pid_get_user_slice(0, &name);
else
r = cg_pid_get_slice(0, &name);
if (r < 0)
return log_error_errno(r, "Failed to mangle name '%s': %m", arg_slice);
return log_error_errno(r, "Failed to get PID slice: %m");
r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
if (r < 0)
return bus_log_create_error(r);
end = endswith(name, ".slice");
if (!end)
return -ENXIO;
*end = 0;
}
if (!isempty(arg_slice)) {
if (name) {
char *j = strjoin(name, "-", arg_slice);
free_and_replace(name, j);
} else
name = strdup(arg_slice);
if (!name)
return log_oom();
}
if (!name)
return 0;
r = unit_name_mangle_with_suffix(name, "as slice",
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
".slice", &slice);
if (r < 0)
return log_error_errno(r, "Failed to mangle name '%s': %m", arg_slice);
r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
if (r < 0)
return bus_log_create_error(r);
return 0;
}

View File

@ -8,6 +8,7 @@
#include "cgroup-setup.h"
#include "cgroup-util.h"
#include "condition.h"
#include "coredump-util.h"
#include "cpu-set-util.h"
#include "escape.h"
#include "exec-util.h"
@ -119,6 +120,7 @@ DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64);
DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode);
DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou);
DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string);
static int bus_append_string(sd_bus_message *m, const char *field, const char *eq) {
int r;
@ -898,6 +900,9 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"OOMScoreAdjust"))
return bus_append_safe_atoi(m, field, eq);
if (streq(field, "CoredumpFilter"))
return bus_append_coredump_filter_mask_from_string(m, field, eq);
if (streq(field, "Nice"))
return bus_append_parse_nice(m, field, eq);

View File

@ -21,6 +21,7 @@
#include "bus-util.h"
#include "cap-list.h"
#include "cgroup-util.h"
#include "escape.h"
#include "mountpoint-util.h"
#include "nsflags.h"
#include "parse-util.h"
@ -373,6 +374,12 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
(void) format_timespan(timespan, sizeof(timespan), u, 0);
bus_print_property_value(name, expected_value, value, timespan);
} else if (streq(name, "CoredumpFilter")) {
char buf[STRLEN("0xFFFFFFFF")];
xsprintf(buf, "0x%"PRIx64, u);
bus_print_property_value(name, expected_value, value, buf);
} else if (streq(name, "RestrictNamespaces")) {
_cleanup_free_ char *s = NULL;
const char *result;
@ -500,18 +507,20 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
return r;
while ((r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &str)) > 0) {
bool good;
_cleanup_free_ char *e = NULL;
if (first && !value)
printf("%s=", name);
e = shell_maybe_quote(str, ESCAPE_BACKSLASH_ONELINE);
if (!e)
return -ENOMEM;
/* This property has multiple space-separated values, so
* neither spaces nor newlines can be allowed in a value. */
good = str[strcspn(str, " \n")] == '\0';
if (first) {
if (!value)
printf("%s=", name);
first = false;
} else
fputs(" ", stdout);
printf("%s%s", first ? "" : " ", good ? str : "[unprintable]");
first = false;
fputs(e, stdout);
}
if (r < 0)
return r;
@ -1390,3 +1399,142 @@ const struct hash_ops bus_message_hash_ops = {
.compare = trivial_compare_func,
.free_value = bus_message_unref_wrapper,
};
/* Shorthand flavors of the sd-bus convenience helpers with destination,path,interface
* strings encapsulated within a single struct.
*/
int bus_call_method_async(
sd_bus *bus,
sd_bus_slot **slot,
const BusAddress *address,
const char *member,
sd_bus_message_handler_t callback,
void *userdata,
const char *types, ...) {
va_list ap;
int r;
assert(address);
va_start(ap, types);
r = sd_bus_call_method_asyncv(bus, slot, address->destination, address->path, address->interface, member, callback, userdata, types, ap);
va_end(ap);
return r;
}
int bus_call_method(
sd_bus *bus,
const BusAddress *address,
const char *member,
sd_bus_error *error,
sd_bus_message **reply,
const char *types, ...) {
va_list ap;
int r;
assert(address);
va_start(ap, types);
r = sd_bus_call_methodv(bus, address->destination, address->path, address->interface, member, error, reply, types, ap);
va_end(ap);
return r;
}
int bus_get_property(
sd_bus *bus,
const BusAddress *address,
const char *member,
sd_bus_error *error,
sd_bus_message **reply,
const char *type) {
assert(address);
return sd_bus_get_property(bus, address->destination, address->path, address->interface, member, error, reply, type);
}
int bus_get_property_trivial(
sd_bus *bus,
const BusAddress *address,
const char *member,
sd_bus_error *error,
char type, void *ptr) {
assert(address);
return sd_bus_get_property_trivial(bus, address->destination, address->path, address->interface, member, error, type, ptr);
}
int bus_get_property_string(
sd_bus *bus,
const BusAddress *address,
const char *member,
sd_bus_error *error,
char **ret) {
assert(address);
return sd_bus_get_property_string(bus, address->destination, address->path, address->interface, member, error, ret);
}
int bus_get_property_strv(
sd_bus *bus,
const BusAddress *address,
const char *member,
sd_bus_error *error,
char ***ret) {
assert(address);
return sd_bus_get_property_strv(bus, address->destination, address->path, address->interface, member, error, ret);
}
int bus_set_property(
sd_bus *bus,
const BusAddress *address,
const char *member,
sd_bus_error *error,
const char *type, ...) {
va_list ap;
int r;
assert(address);
va_start(ap, type);
r = sd_bus_set_propertyv(bus, address->destination, address->path, address->interface, member, error, type, ap);
va_end(ap);
return r;
}
int bus_match_signal(
sd_bus *bus,
sd_bus_slot **ret,
const BusAddress *address,
const char *member,
sd_bus_message_handler_t callback,
void *userdata) {
assert(address);
return sd_bus_match_signal(bus, ret, address->destination, address->path, address->interface, member, callback, userdata);
}
int bus_match_signal_async(
sd_bus *bus,
sd_bus_slot **ret,
const BusAddress *address,
const char *member,
sd_bus_message_handler_t callback,
sd_bus_message_handler_t install_callback,
void *userdata) {
assert(address);
return sd_bus_match_signal_async(bus, ret, address->destination, address->path, address->interface, member, callback, install_callback, userdata);
}

View File

@ -22,6 +22,12 @@ typedef enum BusTransport {
_BUS_TRANSPORT_INVALID = -1
} BusTransport;
typedef struct BusAddress {
const char *destination;
const char *path;
const char *interface;
} BusAddress;
typedef int (*bus_property_set_t) (sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
struct bus_properties_map {
@ -179,3 +185,16 @@ static inline int bus_open_system_watch_bind(sd_bus **ret) {
int bus_reply_pair_array(sd_bus_message *m, char **l);
extern const struct hash_ops bus_message_hash_ops;
/* Shorthand flavors of the sd-bus convenience helpers with destination,path,interface
* strings encapsulated within a single struct.
*/
int bus_call_method_async(sd_bus *bus, sd_bus_slot **slot, const BusAddress *address, const char *member, sd_bus_message_handler_t callback, void *userdata, const char *types, ...);
int bus_call_method(sd_bus *bus, const BusAddress *address, const char *member, sd_bus_error *error, sd_bus_message **reply, const char *types, ...);
int bus_get_property(sd_bus *bus, const BusAddress *address, const char *member, sd_bus_error *error, sd_bus_message **reply, const char *type);
int bus_get_property_trivial(sd_bus *bus, const BusAddress *address, const char *member, sd_bus_error *error, char type, void *ptr);
int bus_get_property_string(sd_bus *bus, const BusAddress *address, const char *member, sd_bus_error *error, char **ret);
int bus_get_property_strv(sd_bus *bus, const BusAddress *address, const char *member, sd_bus_error *error, char ***ret);
int bus_set_property(sd_bus *bus, const BusAddress *address, const char *member, sd_bus_error *error, const char *type, ...);
int bus_match_signal(sd_bus *bus, sd_bus_slot **ret, const BusAddress *address, const char *member, sd_bus_message_handler_t callback, void *userdata);
int bus_match_signal_async(sd_bus *bus, sd_bus_slot **ret, const BusAddress *address, const char *member, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata);

View File

@ -0,0 +1,74 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "coredump-util.h"
#include "extract-word.h"
#include "fileio.h"
#include "string-table.h"
static const char *const coredump_filter_table[_COREDUMP_FILTER_MAX] = {
[COREDUMP_FILTER_PRIVATE_ANONYMOUS] = "private-anonymous",
[COREDUMP_FILTER_SHARED_ANONYMOUS] = "shared-anonymous",
[COREDUMP_FILTER_PRIVATE_FILE_BACKED] = "private-file-backed",
[COREDUMP_FILTER_SHARED_FILE_BACKED] = "shared-file-backed",
[COREDUMP_FILTER_ELF_HEADERS] = "elf-headers",
[COREDUMP_FILTER_PRIVATE_HUGE] = "private-huge",
[COREDUMP_FILTER_SHARED_HUGE] = "shared-huge",
[COREDUMP_FILTER_PRIVATE_DAX] = "private-dax",
[COREDUMP_FILTER_SHARED_DAX] = "shared-dax",
};
DEFINE_STRING_TABLE_LOOKUP(coredump_filter, CoredumpFilter);
int coredump_filter_mask_from_string(const char *s, uint64_t *ret) {
uint64_t m = 0;
assert(s);
assert(ret);
for (;;) {
_cleanup_free_ char *n = NULL;
CoredumpFilter v;
int r;
r = extract_first_word(&s, &n, NULL, 0);
if (r < 0)
return r;
if (r == 0)
break;
if (streq(n, "default")) {
m |= COREDUMP_FILTER_MASK_DEFAULT;
continue;
}
if (streq(n, "all")) {
m = UINT64_MAX;
continue;
}
v = coredump_filter_from_string(n);
if (v >= 0) {
m |= 1u << v;
continue;
}
uint64_t x;
r = safe_atoux64(n, &x);
if (r < 0)
return r;
m |= x;
}
*ret = m;
return 0;
}
int set_coredump_filter(uint64_t value) {
char t[STRLEN("0xFFFFFFFF")];
sprintf(t, "0x%"PRIx64, value);
return write_string_file("/proc/self/coredump_filter", t,
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
}

View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "macro.h"
typedef enum CoredumpFilter {
COREDUMP_FILTER_PRIVATE_ANONYMOUS = 0,
COREDUMP_FILTER_SHARED_ANONYMOUS,
COREDUMP_FILTER_PRIVATE_FILE_BACKED,
COREDUMP_FILTER_SHARED_FILE_BACKED,
COREDUMP_FILTER_ELF_HEADERS,
COREDUMP_FILTER_PRIVATE_HUGE,
COREDUMP_FILTER_SHARED_HUGE,
COREDUMP_FILTER_PRIVATE_DAX,
COREDUMP_FILTER_SHARED_DAX,
_COREDUMP_FILTER_MAX,
_COREDUMP_FILTER_INVALID = -1,
} CoredumpFilter;
#define COREDUMP_FILTER_MASK_DEFAULT (1u << COREDUMP_FILTER_PRIVATE_ANONYMOUS | \
1u << COREDUMP_FILTER_SHARED_ANONYMOUS | \
1u << COREDUMP_FILTER_ELF_HEADERS | \
1u << COREDUMP_FILTER_PRIVATE_HUGE)
const char* coredump_filter_to_string(CoredumpFilter i) _const_;
CoredumpFilter coredump_filter_from_string(const char *s) _pure_;
int coredump_filter_mask_from_string(const char *s, uint64_t *ret);
int set_coredump_filter(uint64_t value);

View File

@ -51,6 +51,8 @@ shared_sources = files('''
condition.h
conf-parser.c
conf-parser.h
coredump-util.c
coredump-util.h
cpu-set-util.c
cpu-set-util.h
crypt-util.c

View File

@ -223,7 +223,7 @@ static int calculate_swap_file_offset(const SwapEntry *swap, uint64_t *ret_offse
fd = open(swap->device, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return log_error_errno(errno, "Failed to open %s: %m", swap->device);
return log_error_errno(errno, "Failed to open swap file %s to determine on-disk offset: %m", swap->device);
if (fstat(fd, &sb) < 0)
return log_error_errno(errno, "Failed to stat %s: %m", swap->device);

View File

@ -588,6 +588,10 @@ tests += [
[],
[]],
[['src/test/test-coredump-util.c'],
[],
[]],
[['src/test/test-daemon.c'],
[],
[]],

View File

@ -0,0 +1,78 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "alloc-util.h"
#include "coredump-util.h"
#include "macro.h"
#include "tests.h"
static void test_coredump_filter_to_from_string(void) {
log_info("/* %s */", __func__);
for (CoredumpFilter i = 0; i < _COREDUMP_FILTER_MAX; i++) {
const char *n;
assert_se(n = coredump_filter_to_string(i));
log_info("0x%x\t%s", 1<<i, n);
assert_se(coredump_filter_from_string(n) == i);
uint64_t f;
assert_se(coredump_filter_mask_from_string(n, &f) == 0);
assert_se(f == 1u << i);
}
}
static void test_coredump_filter_mask_from_string(void) {
log_info("/* %s */", __func__);
uint64_t f;
assert_se(coredump_filter_mask_from_string("default", &f) == 0);
assert_se(f == COREDUMP_FILTER_MASK_DEFAULT);
assert_se(coredump_filter_mask_from_string(" default\tdefault\tdefault ", &f) == 0);
assert_se(f == COREDUMP_FILTER_MASK_DEFAULT);
assert_se(coredump_filter_mask_from_string("defaulta", &f) < 0);
assert_se(coredump_filter_mask_from_string("default defaulta default", &f) < 0);
assert_se(coredump_filter_mask_from_string("default default defaulta", &f) < 0);
assert_se(coredump_filter_mask_from_string("private-anonymous default", &f) == 0);
assert_se(f == COREDUMP_FILTER_MASK_DEFAULT);
assert_se(coredump_filter_mask_from_string("shared-file-backed shared-dax", &f) == 0);
assert_se(f == (1 << COREDUMP_FILTER_SHARED_FILE_BACKED |
1 << COREDUMP_FILTER_SHARED_DAX));
assert_se(coredump_filter_mask_from_string("private-file-backed private-dax 0xF", &f) == 0);
assert_se(f == (1 << COREDUMP_FILTER_PRIVATE_FILE_BACKED |
1 << COREDUMP_FILTER_PRIVATE_DAX |
0xF));
assert_se(coredump_filter_mask_from_string("11", &f) == 0);
assert_se(f == 0x11);
assert_se(coredump_filter_mask_from_string("0x1101", &f) == 0);
assert_se(f == 0x1101);
assert_se(coredump_filter_mask_from_string("0", &f) == 0);
assert_se(f == 0);
assert_se(coredump_filter_mask_from_string("all", &f) == 0);
assert_se(FLAGS_SET(f, (1 << COREDUMP_FILTER_PRIVATE_ANONYMOUS |
1 << COREDUMP_FILTER_SHARED_ANONYMOUS |
1 << COREDUMP_FILTER_PRIVATE_FILE_BACKED |
1 << COREDUMP_FILTER_SHARED_FILE_BACKED |
1 << COREDUMP_FILTER_ELF_HEADERS |
1 << COREDUMP_FILTER_PRIVATE_HUGE |
1 << COREDUMP_FILTER_SHARED_HUGE |
1 << COREDUMP_FILTER_PRIVATE_DAX |
1 << COREDUMP_FILTER_SHARED_DAX)));
}
int main(int argc, char **argv) {
test_setup_logging(LOG_INFO);
test_coredump_filter_to_from_string();
test_coredump_filter_mask_from_string();
return 0;
}

View File

@ -142,31 +142,42 @@ static void test_shell_maybe_quote_one(const char *s,
static void test_shell_maybe_quote(void) {
test_shell_maybe_quote_one("", ESCAPE_BACKSLASH, "");
test_shell_maybe_quote_one("", ESCAPE_BACKSLASH_ONELINE, "");
test_shell_maybe_quote_one("", ESCAPE_POSIX, "");
test_shell_maybe_quote_one("\\", ESCAPE_BACKSLASH, "\"\\\\\"");
test_shell_maybe_quote_one("\\", ESCAPE_BACKSLASH_ONELINE, "\"\\\\\"");
test_shell_maybe_quote_one("\\", ESCAPE_POSIX, "$'\\\\'");
test_shell_maybe_quote_one("\"", ESCAPE_BACKSLASH, "\"\\\"\"");
test_shell_maybe_quote_one("\"", ESCAPE_BACKSLASH_ONELINE, "\"\\\"\"");
test_shell_maybe_quote_one("\"", ESCAPE_POSIX, "$'\"'");
test_shell_maybe_quote_one("foobar", ESCAPE_BACKSLASH, "foobar");
test_shell_maybe_quote_one("foobar", ESCAPE_BACKSLASH_ONELINE, "foobar");
test_shell_maybe_quote_one("foobar", ESCAPE_POSIX, "foobar");
test_shell_maybe_quote_one("foo bar", ESCAPE_BACKSLASH, "\"foo bar\"");
test_shell_maybe_quote_one("foo bar", ESCAPE_BACKSLASH_ONELINE, "\"foo bar\"");
test_shell_maybe_quote_one("foo bar", ESCAPE_POSIX, "$'foo bar'");
test_shell_maybe_quote_one("foo\tbar", ESCAPE_BACKSLASH, "\"foo\tbar\"");
test_shell_maybe_quote_one("foo\tbar", ESCAPE_BACKSLASH_ONELINE, "\"foo\\tbar\"");
test_shell_maybe_quote_one("foo\tbar", ESCAPE_POSIX, "$'foo\\tbar'");
test_shell_maybe_quote_one("foo\nbar", ESCAPE_BACKSLASH, "\"foo\nbar\"");
test_shell_maybe_quote_one("foo\nbar", ESCAPE_BACKSLASH_ONELINE, "\"foo\\nbar\"");
test_shell_maybe_quote_one("foo\nbar", ESCAPE_POSIX, "$'foo\\nbar'");
test_shell_maybe_quote_one("foo \"bar\" waldo", ESCAPE_BACKSLASH, "\"foo \\\"bar\\\" waldo\"");
test_shell_maybe_quote_one("foo \"bar\" waldo", ESCAPE_BACKSLASH_ONELINE, "\"foo \\\"bar\\\" waldo\"");
test_shell_maybe_quote_one("foo \"bar\" waldo", ESCAPE_POSIX, "$'foo \"bar\" waldo'");
test_shell_maybe_quote_one("foo$bar", ESCAPE_BACKSLASH, "\"foo\\$bar\"");
test_shell_maybe_quote_one("foo$bar", ESCAPE_BACKSLASH_ONELINE, "\"foo\\$bar\"");
test_shell_maybe_quote_one("foo$bar", ESCAPE_POSIX, "$'foo$bar'");
/* Note that current users disallow control characters, so this "test"
* is here merely to establish current behaviour. If control characters
* were allowed, they should be quoted, i.e. \001 should become \\001. */
test_shell_maybe_quote_one("a\nb\001", ESCAPE_BACKSLASH, "\"a\nb\001\"");
test_shell_maybe_quote_one("a\nb\001", ESCAPE_BACKSLASH_ONELINE, "\"a\\nb\001\"");
test_shell_maybe_quote_one("a\nb\001", ESCAPE_POSIX, "$'a\\nb\001'");
test_shell_maybe_quote_one("foo!bar", ESCAPE_BACKSLASH, "\"foo!bar\"");
test_shell_maybe_quote_one("foo!bar", ESCAPE_BACKSLASH_ONELINE, "\"foo!bar\"");
test_shell_maybe_quote_one("foo!bar", ESCAPE_POSIX, "$'foo!bar'");
}

View File

@ -561,6 +561,44 @@ static void test_safe_atoi64(void) {
assert_se(r == -EINVAL);
}
static void test_safe_atoux64(void) {
int r;
uint64_t l;
r = safe_atoux64("12345", &l);
assert_se(r == 0);
assert_se(l == 0x12345);
r = safe_atoux64(" 12345", &l);
assert_se(r == 0);
assert_se(l == 0x12345);
r = safe_atoux64("0x12345", &l);
assert_se(r == 0);
assert_se(l == 0x12345);
r = safe_atoux64("18446744073709551617", &l);
assert_se(r == -ERANGE);
r = safe_atoux64("-1", &l);
assert_se(r == -ERANGE);
r = safe_atoux64(" -1", &l);
assert_se(r == -ERANGE);
r = safe_atoux64("junk", &l);
assert_se(r == -EINVAL);
r = safe_atoux64("123x", &l);
assert_se(r == -EINVAL);
r = safe_atoux64("12.3", &l);
assert_se(r == -EINVAL);
r = safe_atoux64("", &l);
assert_se(r == -EINVAL);
}
static void test_safe_atod(void) {
int r;
double d;
@ -838,6 +876,7 @@ int main(int argc, char *argv[]) {
test_safe_atoux16();
test_safe_atou64();
test_safe_atoi64();
test_safe_atoux64();
test_safe_atod();
test_parse_percent();
test_parse_percent_unbounded();

View File

@ -88,7 +88,7 @@ static void test_colors(void) {
test_one_color("green", ansi_green());
test_one_color("yellow", ansi_yellow());
test_one_color("blue", ansi_blue());
test_one_color("megenta", ansi_magenta());
test_one_color("magenta", ansi_magenta());
test_one_color("grey", ansi_grey());
test_one_color("highlight-red", ansi_highlight_red());
test_one_color("highlight-green", ansi_highlight_green());

View File

@ -44,6 +44,7 @@ BlockIOWeight=
BlockIOWriteBandwidth=
Broadcast=
BusName=
CoredumpFilter=
CPUAccounting=
CPUQuota=
CPUShares=