1
0
mirror of https://github.com/systemd/systemd synced 2025-10-05 03:34:46 +02:00

Compare commits

..

No commits in common. "2d8ce4c70114d9163be9ff45bdece1551a7036cc" and "43b4e3058c106e663bbd5413e7bd106e55d6fd79" have entirely different histories.

25 changed files with 264 additions and 379 deletions

58
NEWS
View File

@ -438,40 +438,36 @@ CHANGES WITH 248:
portable service image, useful for updating images on-the-fly. portable service image, useful for updating images on-the-fly.
Contributions from: Adam Nielsen, Adrian Vovk, AJ Jordan, Alan Perry, Contributions from: Adam Nielsen, Adrian Vovk, AJ Jordan, Alan Perry,
Alastair Pharo, Alexander Batischev, Ali Abdallah, Andrew Balmos, Anita Alexander Batischev, Ali Abdallah, Andrew Balmos, Anita Zhang, Ansgar
Zhang, Annika Wickert, Ansgar Burchardt, Antonius Frie, Ardy, Arian van Burchardt, Antonius Frie, Ardy, Arian van Putten, Ariel Fermani, Arnaud
Putten, Ariel Fermani, Arnaud T, A S Alam, Bastien Nocera, Benjamin T, A S Alam, Bastien Nocera, Benjamin Berg, Benjamin Robin, Björn
Berg, Benjamin Robin, Björn Daase, caoxia, Carlo Wood, Charles Lee, Daase, chri2, Christian Ehrhardt, Christian Hesse, Christopher Obbard,
ChopperRob, chri2, Christian Ehrhardt, Christian Hesse, Christopher clayton craft, corvusnix, cprn, d032747, Daan De Meyer, Daniele Medri,
Obbard, clayton craft, corvusnix, cprn, d032747, Daan De Meyer, Daniele Dan Streetman, Darren Ng, David Edmundson, Deepak Rawat, Devon Pringle,
Medri, Daniel Rusek, Dan Streetman, Darren Ng, David Edmundson, Deepak Dmitry Borodaenko, dropsignal, Einsler Lee, Endre Szabo, Evgeny
Rawat, Devon Pringle, Dmitry Borodaenko, dropsignal, Einsler Lee, Endre Vereshchagin, Fabian Affolter, Felipe Borges, feliperodriguesfr, Felix
Szabo, Evgeny Vereshchagin, Fabian Affolter, Felipe Borges, Stupp, Florian Hülsmann, Florian Klink, Florian Westphal, Franck Bui,
feliperodriguesfr, Felix Stupp, Florian Hülsmann, Florian Klink, Frantisek Sumsal, Gablegritule, Gaël PORTAY, Gaurav, Giedrius
Florian Westphal, Franck Bui, Frantisek Sumsal, Gablegritule, Gaël Statkevičius, Greg Depoire--Ferrer, Hans de Goede, heretoenhance, Iago
PORTAY, Gaurav, Giedrius Statkevičius, Greg Depoire--Ferrer, Gustavo López Galeiras, igo95862, Ilya Dmitrichenko, Jameer Pathan, Jan Tojnar,
Costa, Hans de Goede, Hela Basa, heretoenhance, Iago López Galeiras, Jiehong, Jinyuan Si, John Slade, Jonathan G. Underwood, Jonathan
igo95862, Ilya Dmitrichenko, Jameer Pathan, Jan Tojnar, Jiehong,
Jinyuan Si, Joerg Behrmann, John Slade, Jonathan G. Underwood, Jonathan
McDowell, Josh Triplett, Joshua Watt, Julia Cartwright, Julien Humbert, McDowell, Josh Triplett, Joshua Watt, Julia Cartwright, Julien Humbert,
Kairui Song, Karel Zak, Kevin P. Fleming, Khem Raj, Konomi, krissgjeng, Kairui Song, Karel Zak, Kevin P. Fleming, Khem Raj, Konomi, krissgjeng,
l4gfcm, Lajos Veres, Lennart Poettering, Luca Boccassi, Luca BRUNO, l4gfcm, Lennart Poettering, Luca Boccassi, Luca BRUNO, Lucas
Lucas Werkmeister, Luka Kudra, Luna Jernberg, Marc-André Lureau, Martin Werkmeister, Luka Kudra, Luna Jernberg, Marc-André Lureau, Matthias
Wilck, Matthias Klumpp, Matt Turner, Michael Marley, Michal Fabik, Klumpp, Matt Turner, Michael Marley, Michal Fabik, Michał Kopeć, Michal
Michał Kopeć, Michal Koutný, Michal Sekletár, Mike Gilbert, milovlad, Sekletár, Mike Gilbert, milovlad, moson-mo, Nick, nihilix-melix, Oğuz
moson-mo, Nick, nihilix-melix, Oğuz Ersen, Ondrej Mosnacek, pali, Pavel Ersen, Ondrej Mosnacek, pali, Pavel Hrdina, Pavel Sapezhko, Peter
Hrdina, Pavel Sapezhko, Perry Yuan, Peter Hutterer, Pierre Dubouilh, Hutterer, Pierre Dubouilh, Piotr Drąg, Richard Laager, rnhmjoj,
Piotr Drąg, Richard Laager, rnhmjoj, RussianNeuroMancer, Sebastiaan van RussianNeuroMancer, Sebastiaan van Stijn, Sergey Bugaev, shenyangyang4,
Stijn, Sergey Bugaev, shenyangyang4, simmon, Simonas Kazlauskas, Simonas Kazlauskas, Stefan Agner, Steve Ramage, Susant Sahani, Sven
Slimane Selyan Amiri, Stefan Agner, Steve Ramage, Susant Sahani, Sven Mueller, Tad Fisher, Takashi Iwai, Thomas Haller, Topi Miettinen,
Mueller, Tad Fisher, Takashi Iwai, Thomas Haller, Tom Shield, Topi Torsten Hilbrich, Tyler Hicks, Ulrich Ölmann, Vinnie Magro, Vito
Miettinen, Torsten Hilbrich, Tyler Hicks, Ulrich Ölmann, Vincent Caputo, Vlad, walbit-de, Weblate, Weblate (bot), Whired Planck, wouter
Pelletier, Vinnie Magro, Vito Caputo, Vlad, walbit-de, Weblate, Weblate bolsterlee, Yuri Chornoivan, Yu Watanabe, Zach Smith, Zbigniew
(bot), Whired Planck, wouter bolsterlee, X Ruoyao, Yuri Chornoivan, Yu Jędrzejewski-Szmek, Zmicer Turok, Дамјан Георгиевски
Watanabe, Zach Smith, Zbigniew Jędrzejewski-Szmek, Zmicer Turok, Дамјан
Георгиевски
— Warsaw, 2021-03-11 — Warsaw, 2021-02-23
CHANGES WITH 247: CHANGES WITH 247:

View File

@ -587,11 +587,11 @@ layout: default
time you need that please immediately undefine `basename()`, and add a time you need that please immediately undefine `basename()`, and add a
comment about it, so that no code ever ends up using the POSIX version! comment about it, so that no code ever ends up using the POSIX version!
- Never use `FILENAME_MAX`. Use `PATH_MAX` instead (for checking maximum size - Never use FILENAME_MAX. Use PATH_MAX instead (for checking maximum size of
of paths) and `NAME_MAX` (for checking maximum size of filenames). paths) and NAME_MAX (for checking maximum size of filenames). FILENAME_MAX is
`FILENAME_MAX` is not POSIX, and is a confusingly named alias for `PATH_MAX` not POSIX, and is a confusingly named alias for PATH_MAX on Linux. Note the
on Linux. Note the `NAME_MAX` does not include space for a trailing `NUL`, NAME_MAX does not include space for a trailing NUL, but PATH_MAX does. UNIX
but `PATH_MAX` does. UNIX FTW! FTW!
## Committing to git ## Committing to git

View File

@ -216,7 +216,7 @@
<listitem><para>Specifies the network interface to execute the query on. This may either be specified as numeric <listitem><para>Specifies the network interface to execute the query on. This may either be specified as numeric
interface index or as network interface string (e.g. <literal>en0</literal>). Note that this option has no interface index or as network interface string (e.g. <literal>en0</literal>). Note that this option has no
effect if system-wide DNS configuration (as configured in <filename>/etc/resolv.conf</filename> or effect if system-wide DNS configuration (as configured in <filename>/etc/resolv.conf</filename> or
<filename>/etc/systemd/resolved.conf</filename>) in place of per-link configuration is used.</para></listitem> <filename>/etc/systemd/resolve.conf</filename>) in place of per-link configuration is used.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -533,12 +533,14 @@ static int controller_is_v1_accessible(const char *root, const char *controller)
assert(controller); assert(controller);
dn = controller_to_dirname(controller); dn = controller_to_dirname(controller);
cpath = strjoina("/sys/fs/cgroup/", dn);
if (root)
/* Also check that:
* - possible subcgroup is created at root,
* - we can modify the hierarchy.
* "Leak" cpath on stack */
cpath = strjoina(cpath, root, "/cgroup.procs");
/* If root if specified, we check that:
* - possible subcgroup is created at root,
* - we can modify the hierarchy. */
cpath = strjoina("/sys/fs/cgroup/", dn, root, root ? "/cgroup.procs" : NULL);
if (laccess(cpath, root ? W_OK : F_OK) < 0) if (laccess(cpath, root ? W_OK : F_OK) < 0)
return -errno; return -errno;

View File

@ -69,14 +69,14 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
return -ENOMEM; return -ENOMEM;
if (c == 0) { if (c == 0) {
if ((flags & EXTRACT_UNESCAPE_RELAX) && if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
(quote == 0 || flags & EXTRACT_RELAX)) { (quote == 0 || flags & EXTRACT_RELAX)) {
/* If we find an unquoted trailing backslash and we're in /* If we find an unquoted trailing backslash and we're in
* EXTRACT_UNESCAPE_RELAX mode, keep it verbatim in the * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
* output. * output.
* *
* Unbalanced quotes will only be allowed in EXTRACT_RELAX * Unbalanced quotes will only be allowed in EXTRACT_RELAX
* mode, EXTRACT_UNESCAPE_RELAX mode does not allow them. * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
*/ */
s[sz++] = '\\'; s[sz++] = '\\';
goto finish_force_terminate; goto finish_force_terminate;
@ -102,10 +102,10 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
else else
sz += utf8_encode_unichar(s + sz, u); sz += utf8_encode_unichar(s + sz, u);
} else if ((flags & EXTRACT_UNESCAPE_SEPARATORS) && } else if ((flags & EXTRACT_UNESCAPE_SEPARATORS) &&
(strchr(separators, **p) || **p == '\\')) strchr(separators, **p))
/* An escaped separator char or the escape char itself */ /* An escaped separator char */
s[sz++] = c; s[sz++] = c;
else if (flags & EXTRACT_UNESCAPE_RELAX) { else if (flags & EXTRACT_CUNESCAPE_RELAX) {
s[sz++] = '\\'; s[sz++] = '\\';
s[sz++] = c; s[sz++] = c;
} else } else
@ -196,7 +196,7 @@ int extract_first_word_and_warn(
const char *rvalue) { const char *rvalue) {
/* Try to unquote it, if it fails, warn about it and try again /* Try to unquote it, if it fails, warn about it and try again
* but this time using EXTRACT_UNESCAPE_RELAX to keep the * but this time using EXTRACT_CUNESCAPE_RELAX to keep the
* backslashes verbatim in invalid escape sequences. */ * backslashes verbatim in invalid escape sequences. */
const char *save; const char *save;
@ -207,11 +207,11 @@ int extract_first_word_and_warn(
if (r >= 0) if (r >= 0)
return r; return r;
if (r == -EINVAL && !(flags & EXTRACT_UNESCAPE_RELAX)) { if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
/* Retry it with EXTRACT_UNESCAPE_RELAX. */ /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
*p = save; *p = save;
r = extract_first_word(p, ret, separators, flags|EXTRACT_UNESCAPE_RELAX); r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
if (r >= 0) { if (r >= 0) {
/* It worked this time, hence it must have been an invalid escape sequence. */ /* It worked this time, hence it must have been an invalid escape sequence. */
log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Ignoring unknown escape sequences: \"%s\"", *ret); log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Ignoring unknown escape sequences: \"%s\"", *ret);

View File

@ -4,15 +4,13 @@
#include "macro.h" #include "macro.h"
typedef enum ExtractFlags { typedef enum ExtractFlags {
EXTRACT_RELAX = 1 << 0, /* Allow unbalanced quote and eat up trailing backslash. */ EXTRACT_RELAX = 1 << 0,
EXTRACT_CUNESCAPE = 1 << 1, /* Unescape known escape sequences. */ EXTRACT_CUNESCAPE = 1 << 1,
EXTRACT_UNESCAPE_RELAX = 1 << 2, /* Allow and keep unknown escape sequences, allow and keep trailing backslash. */ EXTRACT_CUNESCAPE_RELAX = 1 << 2,
EXTRACT_UNESCAPE_SEPARATORS = 1 << 3, /* Unescape separators (those specified, or whitespace by default). */ EXTRACT_UNESCAPE_SEPARATORS = 1 << 3,
EXTRACT_UNQUOTE = 1 << 4, /* Remove quoting with "" and ''. */ EXTRACT_UNQUOTE = 1 << 4,
EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5, /* Don't treat multiple adjacent separators as one */ EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5,
EXTRACT_RETAIN_ESCAPE = 1 << 6, /* Treat escape character '\' as any other character without special meaning */ EXTRACT_RETAIN_ESCAPE = 1 << 6,
/* Note that if no flags are specified, escaped escape characters will be silently stripped. */
} ExtractFlags; } ExtractFlags;
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);

View File

@ -142,7 +142,7 @@ static int vl_method_subscribe_managed_oom_cgroups(
/* We only take one subscriber for this method so return an error if there's already an existing one. /* We only take one subscriber for this method so return an error if there's already an existing one.
* This shouldn't happen since systemd-oomd is the only client of this method. */ * This shouldn't happen since systemd-oomd is the only client of this method. */
if (FLAGS_SET(flags, VARLINK_METHOD_MORE) && m->managed_oom_varlink_request) if (FLAGS_SET(flags, VARLINK_METHOD_MORE) && m->managed_oom_varlink_request)
return varlink_error(link, VARLINK_ERROR_SUBSCRIPTION_TAKEN, NULL); return varlink_error(m->managed_oom_varlink_request, VARLINK_ERROR_SUBSCRIPTION_TAKEN, NULL);
r = json_build(&arr, JSON_BUILD_EMPTY_ARRAY); r = json_build(&arr, JSON_BUILD_EMPTY_ARRAY);
if (r < 0) if (r < 0)
@ -188,7 +188,6 @@ static int vl_method_subscribe_managed_oom_cgroups(
if (!FLAGS_SET(flags, VARLINK_METHOD_MORE)) if (!FLAGS_SET(flags, VARLINK_METHOD_MORE))
return varlink_reply(link, v); return varlink_reply(link, v);
assert(!m->managed_oom_varlink_request);
m->managed_oom_varlink_request = varlink_ref(link); m->managed_oom_varlink_request = varlink_ref(link);
return varlink_notify(m->managed_oom_varlink_request, v); return varlink_notify(m->managed_oom_varlink_request, v);
} }
@ -476,7 +475,8 @@ void manager_varlink_done(Manager *m) {
assert(m); assert(m);
/* Send the final message if we still have a subscribe request open. */ /* Send the final message if we still have a subscribe request open. */
m->managed_oom_varlink_request = varlink_close_unref(m->managed_oom_varlink_request); if (m->managed_oom_varlink_request)
m->managed_oom_varlink_request = varlink_close_unref(m->managed_oom_varlink_request);
m->varlink_server = varlink_server_unref(m->varlink_server); m->varlink_server = varlink_server_unref(m->varlink_server);
} }

View File

@ -1019,7 +1019,7 @@ static void mount_enter_mounting(Mount *m) {
if (p) { if (p) {
_cleanup_free_ char *opts = NULL; _cleanup_free_ char *opts = NULL;
r = fstab_filter_options(p->options, "nofail\0" "noauto\0" "auto\0", NULL, NULL, NULL, &opts); r = fstab_filter_options(p->options, "nofail\0" "noauto\0" "auto\0", NULL, NULL, &opts);
if (r < 0) if (r < 0)
goto fail; goto fail;

View File

@ -301,9 +301,7 @@ static int create_disk(
netdev = fstab_test_option(options, "_netdev\0"); netdev = fstab_test_option(options, "_netdev\0");
attach_in_initrd = fstab_test_option(options, "x-initrd.attach\0"); attach_in_initrd = fstab_test_option(options, "x-initrd.attach\0");
keyfile_can_timeout = fstab_filter_options(options, keyfile_can_timeout = fstab_filter_options(options, "keyfile-timeout\0", NULL, &keyfile_timeout_value, NULL);
"keyfile-timeout\0",
NULL, &keyfile_timeout_value, NULL, NULL);
if (keyfile_can_timeout < 0) if (keyfile_can_timeout < 0)
return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m"); return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m");
@ -312,12 +310,11 @@ static int create_disk(
"header\0", "header\0",
NULL, NULL,
&header_path, &header_path,
NULL,
headerdev ? &filtered_header : NULL); headerdev ? &filtered_header : NULL);
if (detached_header < 0) if (detached_header < 0)
return log_error_errno(detached_header, "Failed to parse header= option value: %m"); return log_error_errno(detached_header, "Failed to parse header= option value: %m");
tmp = fstab_filter_options(options, "tmp\0", NULL, &tmp_fstype, NULL, NULL); tmp = fstab_filter_options(options, "tmp\0", NULL, &tmp_fstype, NULL);
if (tmp < 0) if (tmp < 0)
return log_error_errno(tmp, "Failed to parse tmp= option value: %m"); return log_error_errno(tmp, "Failed to parse tmp= option value: %m");
@ -605,7 +602,7 @@ static int filter_header_device(const char *options,
assert(ret_headerdev); assert(ret_headerdev);
assert(ret_filtered_headerdev_options); assert(ret_filtered_headerdev_options);
r = fstab_filter_options(options, "header\0", NULL, &headerspec, NULL, &filtered_headerspec); r = fstab_filter_options(options, "header\0", NULL, &headerspec, &filtered_headerspec);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse header= option value: %m"); return log_error_errno(r, "Failed to parse header= option value: %m");

View File

@ -631,7 +631,7 @@ static int action_copy(DissectedImage *m, LoopDevice *d) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to copy bytes from %s in mage '%s' to stdout: %m", arg_source, arg_image); return log_error_errno(r, "Failed to copy bytes from %s in mage '%s' to stdout: %m", arg_source, arg_image);
/* When we copy to stdout we don't copy any attributes (i.e. no access mode, no ownership, no xattr, no times) */ /* When we copy to stdou we don't copy any attributes (i.e. no access mode, no ownership, no xattr, no times) */
return 0; return 0;
} }

View File

@ -200,7 +200,7 @@ static int write_timeout(
usec_t u; usec_t u;
int r; int r;
r = fstab_filter_options(opts, filter, NULL, &timeout, NULL, NULL); r = fstab_filter_options(opts, filter, NULL, &timeout, NULL);
if (r < 0) if (r < 0)
return log_warning_errno(r, "Failed to parse options: %m"); return log_warning_errno(r, "Failed to parse options: %m");
if (r == 0) if (r == 0)
@ -241,7 +241,7 @@ static int write_dependency(
assert(f); assert(f);
assert(opts); assert(opts);
r = fstab_filter_options(opts, filter, NULL, NULL, &names, NULL); r = fstab_extract_values(opts, filter, &names);
if (r < 0) if (r < 0)
return log_warning_errno(r, "Failed to parse options: %m"); return log_warning_errno(r, "Failed to parse options: %m");
if (r == 0) if (r == 0)
@ -274,17 +274,17 @@ static int write_dependency(
static int write_after(FILE *f, const char *opts) { static int write_after(FILE *f, const char *opts) {
return write_dependency(f, opts, return write_dependency(f, opts,
"x-systemd.after\0", "After=%1$s\n"); "x-systemd.after", "After=%1$s\n");
} }
static int write_requires_after(FILE *f, const char *opts) { static int write_requires_after(FILE *f, const char *opts) {
return write_dependency(f, opts, return write_dependency(f, opts,
"x-systemd.requires\0", "After=%1$s\nRequires=%1$s\n"); "x-systemd.requires", "After=%1$s\nRequires=%1$s\n");
} }
static int write_before(FILE *f, const char *opts) { static int write_before(FILE *f, const char *opts) {
return write_dependency(f, opts, return write_dependency(f, opts,
"x-systemd.before\0", "Before=%1$s\n"); "x-systemd.before", "Before=%1$s\n");
} }
static int write_requires_mounts_for(FILE *f, const char *opts) { static int write_requires_mounts_for(FILE *f, const char *opts) {
@ -295,7 +295,7 @@ static int write_requires_mounts_for(FILE *f, const char *opts) {
assert(f); assert(f);
assert(opts); assert(opts);
r = fstab_filter_options(opts, "x-systemd.requires-mounts-for\0", NULL, NULL, &paths, NULL); r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths);
if (r < 0) if (r < 0)
return log_warning_errno(r, "Failed to parse options: %m"); return log_warning_errno(r, "Failed to parse options: %m");
if (r == 0) if (r == 0)
@ -376,11 +376,11 @@ static int add_mount(
mount_point_ignore(where)) mount_point_ignore(where))
return 0; return 0;
r = fstab_filter_options(opts, "x-systemd.wanted-by\0", NULL, NULL, &wanted_by, NULL); r = fstab_extract_values(opts, "x-systemd.wanted-by", &wanted_by);
if (r < 0) if (r < 0)
return r; return r;
r = fstab_filter_options(opts, "x-systemd.required-by\0", NULL, NULL, &required_by, NULL); r = fstab_extract_values(opts, "x-systemd.required-by", &required_by);
if (r < 0) if (r < 0)
return r; return r;
@ -611,11 +611,11 @@ static int parse_fstab(bool initrd) {
* /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
* where a symlink refers to another mount target; this works assuming the sub-mountpoint * where a symlink refers to another mount target; this works assuming the sub-mountpoint
* target is the final directory. */ * target is the final directory. */
k = chase_symlinks(where, initrd ? "/sysroot" : NULL, r = chase_symlinks(where, initrd ? "/sysroot" : NULL,
CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
&canonical_where, NULL); &canonical_where, NULL);
if (k < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */ if (r < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */
log_debug_errno(k, "Failed to read symlink target for %s, ignoring: %m", where); log_debug_errno(r, "Failed to read symlink target for %s, ignoring: %m", where);
else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */ else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */
canonical_where = mfree(canonical_where); canonical_where = mfree(canonical_where);
else else

View File

@ -201,8 +201,6 @@ static void test_basic(bool with_pidfd) {
uint64_t event_now; uint64_t event_now;
int64_t priority; int64_t priority;
log_info("/* %s(pidfd=%s) */", __func__, yes_no(with_pidfd));
assert_se(setenv("SYSTEMD_PIDFD", yes_no(with_pidfd), 1) >= 0); assert_se(setenv("SYSTEMD_PIDFD", yes_no(with_pidfd), 1) >= 0);
assert_se(pipe(a) >= 0); assert_se(pipe(a) >= 0);
@ -304,8 +302,6 @@ static void test_sd_event_now(void) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL; _cleanup_(sd_event_unrefp) sd_event *e = NULL;
uint64_t event_now; uint64_t event_now;
log_info("/* %s */", __func__);
assert_se(sd_event_new(&e) >= 0); assert_se(sd_event_new(&e) >= 0);
assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0); assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0); assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0);
@ -343,8 +339,6 @@ static void test_rtqueue(void) {
sd_event_source *u = NULL, *v = NULL, *s = NULL; sd_event_source *u = NULL, *v = NULL, *s = NULL;
sd_event *e = NULL; sd_event *e = NULL;
log_info("/* %s */", __func__);
assert_se(sd_event_default(&e) >= 0); assert_se(sd_event_default(&e) >= 0);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0);
@ -485,8 +479,6 @@ static void test_inotify(unsigned n_create_events) {
const char *q; const char *q;
unsigned i; unsigned i;
log_info("/* %s(%u) */", __func__, n_create_events);
assert_se(sd_event_default(&e) >= 0); assert_se(sd_event_default(&e) >= 0);
assert_se(mkdtemp_malloc("/tmp/test-inotify-XXXXXX", &p) >= 0); assert_se(mkdtemp_malloc("/tmp/test-inotify-XXXXXX", &p) >= 0);
@ -553,8 +545,6 @@ static void test_pidfd(void) {
int pidfd; int pidfd;
pid_t pid, pid2; pid_t pid, pid2;
log_info("/* %s */", __func__);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
pid = fork(); pid = fork();
@ -629,8 +619,6 @@ static void test_ratelimit(void) {
uint64_t interval; uint64_t interval;
unsigned count, burst; unsigned count, burst;
log_info("/* %s */", __func__);
assert_se(sd_event_default(&e) >= 0); assert_se(sd_event_default(&e) >= 0);
assert_se(pipe2(p, O_CLOEXEC|O_NONBLOCK) >= 0); assert_se(pipe2(p, O_CLOEXEC|O_NONBLOCK) >= 0);

View File

@ -170,7 +170,7 @@ static int run(int argc, char *argv[]) {
notify_msg = notify_start(NOTIFY_READY, NOTIFY_STOPPING); notify_msg = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
log_debug("systemd-oomd started%s.", arg_dry_run ? " in dry run mode" : ""); log_info("systemd-oomd starting%s!", arg_dry_run ? " in dry run mode" : "");
r = sd_event_loop(m->event); r = sd_event_loop(m->event);
if (r < 0) if (r < 0)

View File

@ -2,7 +2,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later # SPDX-License-Identifier: LGPL-2.1-or-later
set -ex set -ex
[[ -e /dev/loop-control ]] || exit 77 [[ -f /dev/loop-control ]] || exit 77
repart=$1 repart=$1
test -x $repart test -x $repart

View File

@ -348,7 +348,7 @@ int config_parse_dnssd_txt(
int r; int r;
r = extract_first_word(&rvalue, &word, NULL, r = extract_first_word(&rvalue, &word, NULL,
EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX); EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX);
if (r == 0) if (r == 0)
break; break;
if (r == -ENOMEM) if (r == -ENOMEM)

View File

@ -1344,28 +1344,20 @@ static int mount_partition(
} }
if (directory) { if (directory) {
/* Automatically create missing mount points inside the image, if necessary. */ if (!FLAGS_SET(flags, DISSECT_IMAGE_READ_ONLY)) {
r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755); /* Automatically create missing mount points, if necessary. */
if (r < 0 && r != -EROFS) r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755);
return r; if (r < 0)
return r;
}
r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased, NULL); r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased, NULL);
if (r < 0) if (r < 0)
return r; return r;
p = chased; p = chased;
} else { } else
/* Create top-level mount if missing but only if this is asked for. This won't modify the
* image (as the branch above does) but the host hierarchy, and the created directory might
* survive our mount in the host hierarchy hence. */
if (FLAGS_SET(flags, DISSECT_IMAGE_MKDIR)) {
r = mkdir_p(where, 0755);
if (r < 0)
return r;
}
p = where; p = where;
}
/* If requested, turn on discard support. */ /* If requested, turn on discard support. */
if (fstype_can_discard(fstype) && if (fstype_can_discard(fstype) &&
@ -1390,6 +1382,12 @@ static int mount_partition(
if (!strextend_with_separator(&options, ",", m->mount_options)) if (!strextend_with_separator(&options, ",", m->mount_options))
return -ENOMEM; return -ENOMEM;
if (FLAGS_SET(flags, DISSECT_IMAGE_MKDIR)) {
r = mkdir_p(p, 0755);
if (r < 0)
return r;
}
r = mount_nofollow_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options); r = mount_nofollow_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options);
if (r < 0) if (r < 0)
return r; return r;
@ -1422,6 +1420,10 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
return r; return r;
} }
/* Mask DISSECT_IMAGE_MKDIR for all subdirs: the idea is that only the top-level mount point is
* created if needed, but the image itself not modified. */
flags &= ~DISSECT_IMAGE_MKDIR;
if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0) { if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0) {
/* For us mounting root always means mounting /usr as well */ /* For us mounting root always means mounting /usr as well */
r = mount_partition(m->partitions + PARTITION_USR, where, "/usr", uid_shift, flags); r = mount_partition(m->partitions + PARTITION_USR, where, "/usr", uid_shift, flags);

View File

@ -86,7 +86,7 @@ typedef enum DissectImageFlags {
DISSECT_IMAGE_FSCK = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */ DISSECT_IMAGE_FSCK = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
DISSECT_IMAGE_NO_PARTITION_TABLE = 1 << 12, /* Only recognize single file system images */ DISSECT_IMAGE_NO_PARTITION_TABLE = 1 << 12, /* Only recognize single file system images */
DISSECT_IMAGE_VERITY_SHARE = 1 << 13, /* When activating a verity device, reuse existing one if already open */ DISSECT_IMAGE_VERITY_SHARE = 1 << 13, /* When activating a verity device, reuse existing one if already open */
DISSECT_IMAGE_MKDIR = 1 << 14, /* Make top-level directory to mount right before mounting, if missing */ DISSECT_IMAGE_MKDIR = 1 << 14, /* Make directory to mount right before mounting, if missing */
} DissectImageFlags; } DissectImageFlags;
struct DissectedImage { struct DissectedImage {

View File

@ -79,95 +79,34 @@ int fstab_is_mount_point(const char *mount) {
return false; return false;
} }
int fstab_filter_options( int fstab_filter_options(const char *opts, const char *names,
const char *opts, const char **ret_namefound, char **ret_value, char **ret_filtered) {
const char *names,
const char **ret_namefound,
char **ret_value,
char ***ret_values,
char **ret_filtered) {
const char *name, *namefound = NULL, *x; const char *name, *namefound = NULL, *x;
_cleanup_strv_free_ char **stor = NULL, **values = NULL; _cleanup_strv_free_ char **stor = NULL;
_cleanup_free_ char *value = NULL, **filtered = NULL; _cleanup_free_ char *v = NULL, **strv = NULL;
int r; int r;
assert(names && *names); assert(names && *names);
assert(!(ret_value && ret_values));
if (!opts) if (!opts)
goto answer; goto answer;
/* Finds any options matching 'names', and returns: /* If !ret_value and !ret_filtered, this function is not allowed to fail. */
* - the last matching option name in ret_namefound,
* - the last matching value in ret_value,
* - any matching values in ret_values,
* - the rest of the option string in ret_filtered.
*
* If !ret_value and !ret_values and !ret_filtered, this function is not allowed to fail.
*
* Returns negative on error, true if any matching options were found, false otherwise. */
if (ret_filtered || ret_value || ret_values) { if (!ret_filtered) {
/* For backwards compatibility, we need to pass-through escape characters.
* The only ones we "consume" are the ones used as "\," or "\\". */
r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS | EXTRACT_UNESCAPE_RELAX);
if (r < 0)
return r;
filtered = memdup(stor, sizeof(char*) * (strv_length(stor) + 1));
if (!filtered)
return -ENOMEM;
char **t = filtered;
for (char **s = t; *s; s++) {
NULSTR_FOREACH(name, names) {
x = startswith(*s, name);
if (!x)
continue;
/* Match name, but when ret_values, only when followed by assignment. */
if (*x == '=' || (!ret_values && *x == '\0'))
goto found;
}
*t = *s;
t++;
continue;
found:
/* Keep the last occurrence found */
namefound = name;
if (ret_value || ret_values) {
assert(IN_SET(*x, '=', '\0'));
if (ret_value) {
r = free_and_strdup(&value, *x == '=' ? x + 1 : NULL);
if (r < 0)
return r;
} else if (*x) {
r = strv_extend(&values, x + 1);
if (r < 0)
return r;
}
}
}
*t = NULL;
} else
for (const char *word = opts;;) { for (const char *word = opts;;) {
const char *end = word; const char *end = word;
/* Look for a *non-escaped* comma separator. Only commas and backslashes can be /* Look for an *non-escaped* comma separator. Only commas can be escaped, so "\," is
* escaped, so "\," and "\\" are the only valid escape sequences, and we can do a * the only valid escape sequence, so we can do a very simple test here. */
* very simple test here. */
for (;;) { for (;;) {
end += strcspn(end, ",\\"); size_t n = strcspn(end, ",");
if (IN_SET(*end, ',', '\0')) end += n;
if (n > 0 && end[-1] == '\\')
end++;
else
break; break;
assert(*end == '\\');
end ++; /* Skip the backslash */
if (*end != '\0')
end ++; /* Skip the escaped char, but watch out for a trailing commma */
} }
NULSTR_FOREACH(name, names) { NULSTR_FOREACH(name, names) {
@ -180,6 +119,17 @@ int fstab_filter_options(
x = word + strlen(name); x = word + strlen(name);
if (IN_SET(*x, '\0', '=', ',')) { if (IN_SET(*x, '\0', '=', ',')) {
namefound = name; namefound = name;
if (ret_value) {
bool eq = *x == '=';
assert(eq || IN_SET(*x, ',', '\0'));
r = free_and_strndup(&v,
eq ? x + 1 : NULL,
eq ? end - x - 1 : 0);
if (r < 0)
return r;
}
break; break;
} }
} }
@ -189,6 +139,38 @@ int fstab_filter_options(
else else
break; break;
} }
} else {
r = strv_split_full(&stor, opts, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
if (r < 0)
return r;
strv = memdup(stor, sizeof(char*) * (strv_length(stor) + 1));
if (!strv)
return -ENOMEM;
char **t = strv;
for (char **s = strv; *s; s++) {
NULSTR_FOREACH(name, names) {
x = startswith(*s, name);
if (x && IN_SET(*x, '\0', '='))
goto found;
}
*t = *s;
t++;
continue;
found:
/* Keep the last occurrence found */
namefound = name;
if (ret_value) {
assert(IN_SET(*x, '=', '\0'));
r = free_and_strdup(&v, *x == '=' ? x + 1 : NULL);
if (r < 0)
return r;
}
}
*t = NULL;
}
answer: answer:
if (ret_namefound) if (ret_namefound)
@ -196,27 +178,54 @@ answer:
if (ret_filtered) { if (ret_filtered) {
char *f; char *f;
f = strv_join_full(filtered, ",", NULL, true); f = strv_join_full(strv, ",", NULL, true);
if (!f) if (!f)
return -ENOMEM; return -ENOMEM;
*ret_filtered = f; *ret_filtered = f;
} }
if (ret_value) if (ret_value)
*ret_value = TAKE_PTR(value); *ret_value = TAKE_PTR(v);
if (ret_values)
*ret_values = TAKE_PTR(values);
return !!namefound; return !!namefound;
} }
int fstab_extract_values(const char *opts, const char *name, char ***values) {
_cleanup_strv_free_ char **optsv = NULL, **res = NULL;
char **s;
assert(opts);
assert(name);
assert(values);
optsv = strv_split(opts, ",");
if (!optsv)
return -ENOMEM;
STRV_FOREACH(s, optsv) {
char *arg;
int r;
arg = startswith(*s, name);
if (!arg || *arg != '=')
continue;
r = strv_extend(&res, arg + 1);
if (r < 0)
return r;
}
*values = TAKE_PTR(res);
return !!*values;
}
int fstab_find_pri(const char *options, int *ret) { int fstab_find_pri(const char *options, int *ret) {
_cleanup_free_ char *opt = NULL; _cleanup_free_ char *opt = NULL;
int r, pri; int r, pri;
assert(ret); assert(ret);
r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL, NULL); r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL);
if (r < 0) if (r < 0)
return r; return r;
if (r == 0 || !opt) if (r == 0 || !opt)

View File

@ -10,16 +10,12 @@ bool fstab_is_extrinsic(const char *mount, const char *opts);
int fstab_is_mount_point(const char *mount); int fstab_is_mount_point(const char *mount);
int fstab_has_fstype(const char *fstype); int fstab_has_fstype(const char *fstype);
int fstab_filter_options( int fstab_filter_options(const char *opts, const char *names, const char **namefound, char **value, char **filtered);
const char *opts,
const char *names, int fstab_extract_values(const char *opts, const char *name, char ***values);
const char **ret_namefound,
char **ret_value,
char ***ret_values,
char **ret_filtered);
static inline bool fstab_test_option(const char *opts, const char *names) { static inline bool fstab_test_option(const char *opts, const char *names) {
return !!fstab_filter_options(opts, names, NULL, NULL, NULL, NULL); return !!fstab_filter_options(opts, names, NULL, NULL, NULL);
} }
int fstab_find_pri(const char *options, int *ret); int fstab_find_pri(const char *options, int *ret);
@ -30,7 +26,7 @@ static inline bool fstab_test_yes_no_option(const char *opts, const char *yes_no
/* If first name given is last, return 1. /* If first name given is last, return 1.
* If second name given is last or neither is found, return 0. */ * If second name given is last or neither is found, return 0. */
assert_se(fstab_filter_options(opts, yes_no, &opt, NULL, NULL, NULL) >= 0); assert_se(fstab_filter_options(opts, yes_no, &opt, NULL, NULL) >= 0);
return opt == yes_no; return opt == yes_no;
} }

View File

@ -215,13 +215,9 @@ int generator_write_timeouts(
r = fstab_filter_options(opts, "comment=systemd.device-timeout\0" r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
"x-systemd.device-timeout\0", "x-systemd.device-timeout\0",
NULL, &timeout, NULL, filtered); NULL, &timeout, filtered);
if (r < 0) { if (r <= 0)
log_warning_errno(r, "Failed to parse fstab options, ignoring: %m"); return r;
return 0;
}
if (r == 0)
return 0;
r = parse_sec_fix_0(timeout, &u); r = parse_sec_fix_0(timeout, &u);
if (r < 0) { if (r < 0) {

View File

@ -1206,9 +1206,8 @@ int varlink_close(Varlink *v) {
varlink_set_state(v, VARLINK_DISCONNECTED); varlink_set_state(v, VARLINK_DISCONNECTED);
/* Let's take a reference first, since varlink_detach_server() might drop the final ref from the /* Let's take a reference first, since varlink_detach_server() might drop the final (dangling) ref
* disconnect callback, which would invalidate the pointer we are holding before we can call * which would destroy us before we can call varlink_clear() */
* varlink_clear(). */
varlink_ref(v); varlink_ref(v);
varlink_detach_server(v); varlink_detach_server(v);
varlink_clear(v); varlink_clear(v);
@ -1221,33 +1220,17 @@ Varlink* varlink_close_unref(Varlink *v) {
if (!v) if (!v)
return NULL; return NULL;
/* A reference is given to us to be destroyed. But when calling varlink_close(), a callback might (void) varlink_close(v);
* also drop a reference. We allow this, and will hold a temporary reference to the object to make
* sure that the object still exists when control returns to us. If there's just one reference
* remaining after varlink_close(), even though there were at least two right before, we'll handle
* that gracefully instead of crashing.
*
* In other words, this call drops the donated reference, but if the internal call to varlink_close()
* dropped a reference to, we don't drop the reference afain. This allows the caller to say:
* global_object->varlink = varlink_close_unref(global_object->varlink);
* even though there is some callback which has access to global_object and may drop the reference
* stored in global_object->varlink. Without this step, the same code would have to be written as:
* Varlink *t = TAKE_PTR(global_object->varlink);
* varlink_close_unref(t);
*/
/* n_ref >= 1 */
varlink_ref(v); /* n_ref >= 2 */
varlink_close(v); /* n_ref >= 1 */
if (v->n_ref > 1)
v->n_ref--; /* n_ref >= 1 */
return varlink_unref(v); return varlink_unref(v);
} }
Varlink* varlink_flush_close_unref(Varlink *v) { Varlink* varlink_flush_close_unref(Varlink *v) {
if (v) if (!v)
varlink_flush(v); return NULL;
return varlink_close_unref(v); (void) varlink_flush(v);
(void) varlink_close(v);
return varlink_unref(v);
} }
static int varlink_enqueue_json(Varlink *v, JsonVariant *m) { static int varlink_enqueue_json(Varlink *v, JsonVariant *m) {

View File

@ -172,19 +172,19 @@ static void test_extract_first_word(void) {
assert_se(isempty(p)); assert_se(isempty(p));
p = original = "fooo\\"; p = original = "fooo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0); assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo\\")); assert_se(streq(t, "fooo\\"));
free(t); free(t);
assert_se(isempty(p)); assert_se(isempty(p));
p = original = "fooo\\"; p = original = "fooo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "fooo\\")); assert_se(streq(t, "fooo\\"));
free(t); free(t);
assert_se(isempty(p)); assert_se(isempty(p));
p = original = "fooo\\"; p = original = "fooo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0); assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo\\")); assert_se(streq(t, "fooo\\"));
free(t); free(t);
assert_se(isempty(p)); assert_se(isempty(p));
@ -230,17 +230,17 @@ static void test_extract_first_word(void) {
assert_se(isempty(p)); assert_se(isempty(p));
p = original = "\"foo\\"; p = original = "\"foo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_UNESCAPE_RELAX) == -EINVAL); assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX) == -EINVAL);
assert_se(p == original + 5); assert_se(p == original + 5);
p = original = "\"foo\\"; p = original = "\"foo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "foo\\")); assert_se(streq(t, "foo\\"));
free(t); free(t);
assert_se(isempty(p)); assert_se(isempty(p));
p = original = "\"foo\\"; p = original = "\"foo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "foo\\")); assert_se(streq(t, "foo\\"));
free(t); free(t);
assert_se(isempty(p)); assert_se(isempty(p));
@ -252,13 +252,13 @@ static void test_extract_first_word(void) {
assert_se(p == original + 10); assert_se(p == original + 10);
p = original = "fooo\\ bar quux"; p = original = "fooo\\ bar quux";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0); assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo bar")); assert_se(streq(t, "fooo bar"));
free(t); free(t);
assert_se(p == original + 10); assert_se(p == original + 10);
p = original = "fooo\\ bar quux"; p = original = "fooo\\ bar quux";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "fooo bar")); assert_se(streq(t, "fooo bar"));
free(t); free(t);
assert_se(p == original + 10); assert_se(p == original + 10);
@ -268,7 +268,7 @@ static void test_extract_first_word(void) {
assert_se(p == original + 5); assert_se(p == original + 5);
p = original = "fooo\\ bar quux"; p = original = "fooo\\ bar quux";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0); assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo\\ bar")); assert_se(streq(t, "fooo\\ bar"));
free(t); free(t);
assert_se(p == original + 10); assert_se(p == original + 10);
@ -278,13 +278,13 @@ static void test_extract_first_word(void) {
assert_se(p == original + 1); assert_se(p == original + 1);
p = original = "\\w+@\\K[\\d.]+"; p = original = "\\w+@\\K[\\d.]+";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0); assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "\\w+@\\K[\\d.]+")); assert_se(streq(t, "\\w+@\\K[\\d.]+"));
free(t); free(t);
assert_se(isempty(p)); assert_se(isempty(p));
p = original = "\\w+\\b"; p = original = "\\w+\\b";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0); assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(streq(t, "\\w+\b")); assert_se(streq(t, "\\w+\b"));
free(t); free(t);
assert_se(isempty(p)); assert_se(isempty(p));
@ -344,39 +344,6 @@ static void test_extract_first_word(void) {
free(t); free(t);
assert_se(p == NULL); assert_se(p == NULL);
p = "\\:";
assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
assert_se(streq(t, ":"));
free(t);
assert_se(p == NULL);
p = "a\\:b";
assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
assert_se(streq(t, "a:b"));
free(t);
assert_se(p == NULL);
p = "a\\ b:c";
assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
assert_se(streq(t, "a b"));
free(t);
assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
assert_se(streq(t, "c"));
free(t);
assert_se(p == NULL);
p = "a\\ b:c\\x";
assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == -EINVAL);
p = "a\\\\ b:c\\\\x";
assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
assert_se(streq(t, "a\\ b"));
free(t);
assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
assert_se(streq(t, "c\\x"));
free(t);
assert_se(p == NULL);
p = "\\:"; p = "\\:";
assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1); assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
assert_se(streq(t, ":")); assert_se(streq(t, ":"));
@ -398,18 +365,6 @@ static void test_extract_first_word(void) {
free(t); free(t);
assert_se(p == NULL); assert_se(p == NULL);
p = "a\\ b:c\\x";
assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == -EINVAL);
p = "a\\\\ b:c\\\\x";
assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
assert_se(streq(t, "a\\ b"));
free(t);
assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
assert_se(streq(t, "c\\x"));
free(t);
assert_se(p == NULL);
p = "\\:"; p = "\\:";
assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE) == -EINVAL); assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE) == -EINVAL);

View File

@ -6,125 +6,94 @@
#include "fstab-util.h" #include "fstab-util.h"
#include "log.h" #include "log.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h"
/* /*
int fstab_filter_options( int fstab_filter_options(const char *opts, const char *names,
const char *opts, const char **namefound, char **value, char **filtered);
const char *names,
const char **ret_namefound,
const char **ret_value,
const char **ret_values,
char **ret_filtered);
*/ */
static void do_fstab_filter_options(const char *opts, static void do_fstab_filter_options(const char *opts,
const char *remove, const char *remove,
int r_expected, int r_expected,
int r_values_expected,
const char *name_expected, const char *name_expected,
const char *value_expected, const char *value_expected,
const char *values_expected,
const char *filtered_expected) { const char *filtered_expected) {
int r; int r;
const char *name; const char *name;
_cleanup_free_ char *value = NULL, *filtered = NULL, *joined = NULL; _cleanup_free_ char *value = NULL, *filtered = NULL;
_cleanup_strv_free_ char **values = NULL;
/* test mode which returns the last value */ r = fstab_filter_options(opts, remove, &name, &value, &filtered);
log_info("\"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"",
r = fstab_filter_options(opts, remove, &name, &value, NULL, &filtered); opts, r, name, value, filtered,
log_info("1: \"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"",
opts, r, strnull(name), value, filtered,
r_expected, name_expected, value_expected, filtered_expected ?: opts); r_expected, name_expected, value_expected, filtered_expected ?: opts);
assert_se(r == r_expected); assert_se(r == r_expected);
assert_se(streq_ptr(name, name_expected)); assert_se(streq_ptr(name, name_expected));
assert_se(streq_ptr(value, value_expected)); assert_se(streq_ptr(value, value_expected));
assert_se(streq_ptr(filtered, filtered_expected ?: opts)); assert_se(streq_ptr(filtered, filtered_expected ?: opts));
/* test mode which returns all the values */
r = fstab_filter_options(opts, remove, &name, NULL, &values, NULL);
assert_se(joined = strv_join(values, ":"));
log_info("2: \"%s\" → %d, \"%s\", \"%s\", expected %d, \"%s\", \"%s\"",
opts, r, strnull(name), joined,
r_values_expected, name_expected, values_expected);
assert_se(r == r_values_expected);
assert_se(streq_ptr(name, r_values_expected > 0 ? name_expected : NULL));
assert_se(streq_ptr(joined, values_expected));
/* also test the malloc-less mode */ /* also test the malloc-less mode */
r = fstab_filter_options(opts, remove, &name, NULL, NULL, NULL); r = fstab_filter_options(opts, remove, &name, NULL, NULL);
log_info("3: \"%s\" → %d, \"%s\", expected %d, \"%s\"\n-", log_info("\"%s\" → %d, \"%s\", expected %d, \"%s\"\n-",
opts, r, strnull(name), opts, r, name,
r_expected, name_expected); r_expected, name_expected);
assert_se(r == r_expected); assert_se(r == r_expected);
assert_se(streq_ptr(name, name_expected)); assert_se(streq_ptr(name, name_expected));
} }
static void test_fstab_filter_options(void) { static void test_fstab_filter_options(void) {
do_fstab_filter_options("opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", ""); do_fstab_filter_options("opt=0", "opt\0x-opt\0", 1, "opt", "0", "");
do_fstab_filter_options("opt=0", "x-opt\0opt\0", 1, 1, "opt", "0", "0", ""); do_fstab_filter_options("opt=0", "x-opt\0opt\0", 1, "opt", "0", "");
do_fstab_filter_options("opt", "opt\0x-opt\0", 1, 0, "opt", NULL, "", ""); do_fstab_filter_options("opt", "opt\0x-opt\0", 1, "opt", NULL, "");
do_fstab_filter_options("opt", "x-opt\0opt\0", 1, 0, "opt", NULL, "", ""); do_fstab_filter_options("opt", "x-opt\0opt\0", 1, "opt", NULL, "");
do_fstab_filter_options("x-opt", "x-opt\0opt\0", 1, 0, "x-opt", NULL, "", ""); do_fstab_filter_options("x-opt", "x-opt\0opt\0", 1, "x-opt", NULL, "");
do_fstab_filter_options("opt=0,other", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "other"); do_fstab_filter_options("opt=0,other", "opt\0x-opt\0", 1, "opt", "0", "other");
do_fstab_filter_options("opt=0,other", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "other"); do_fstab_filter_options("opt=0,other", "x-opt\0opt\0", 1, "opt", "0", "other");
do_fstab_filter_options("opt,other", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other"); do_fstab_filter_options("opt,other", "opt\0x-opt\0", 1, "opt", NULL, "other");
do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "other"); do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, "opt", NULL, "other");
do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, 0, "x-opt", NULL, "", "other"); do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, "x-opt", NULL, "other");
do_fstab_filter_options("opt=0\\,1,other", "opt\0x-opt\0", 1, 1, "opt", "0,1", "0,1", "other"); do_fstab_filter_options("opt=0\\,1,other", "opt\0x-opt\0", 1, "opt", "0,1", "other");
do_fstab_filter_options("opt=0,other,x-opt\\,foobar", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "other,x-opt\\,foobar"); do_fstab_filter_options("opt=0,other,x-opt\\,foobar", "x-opt\0opt\0", 1, "opt", "0", "other,x-opt\\,foobar");
do_fstab_filter_options("opt,other,x-opt\\,part", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other,x-opt\\,part"); do_fstab_filter_options("opt,other,x-opt\\,part", "opt\0x-opt\0", 1, "opt", NULL, "other,x-opt\\,part");
do_fstab_filter_options("opt,other,part\\,x-opt", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "other,part\\,x-opt"); do_fstab_filter_options("opt,other,part\\,x-opt", "x-opt\0opt\0", 1, "opt", NULL, "other,part\\,x-opt");
do_fstab_filter_options("opt,other\\,\\,\\,opt,x-part", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other\\,\\,\\,opt,x-part"); do_fstab_filter_options("opt,other\\,\\,\\,opt,x-part", "opt\0x-opt\0", 1, "opt", NULL, "other\\,\\,\\,opt,x-part");
do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL); do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
do_fstab_filter_options("opto,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL); do_fstab_filter_options("opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
do_fstab_filter_options("x-opto,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL); do_fstab_filter_options("x-opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
do_fstab_filter_options("first,opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first"); do_fstab_filter_options("first,opt=0", "opt\0x-opt\0", 1, "opt", "0", "first");
do_fstab_filter_options("first=1,opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first=1"); do_fstab_filter_options("first=1,opt=0", "opt\0x-opt\0", 1, "opt", "0", "first=1");
do_fstab_filter_options("first,opt=", "opt\0x-opt\0", 1, 1, "opt", "", "", "first"); do_fstab_filter_options("first,opt=", "opt\0x-opt\0", 1, "opt", "", "first");
do_fstab_filter_options("first=1,opt", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "first=1"); do_fstab_filter_options("first=1,opt", "opt\0x-opt\0", 1, "opt", NULL, "first=1");
do_fstab_filter_options("first=1,x-opt", "opt\0x-opt\0", 1, 0, "x-opt", NULL, "", "first=1"); do_fstab_filter_options("first=1,x-opt", "opt\0x-opt\0", 1, "x-opt", NULL, "first=1");
do_fstab_filter_options("first,opt=0,last=1", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first,last=1"); do_fstab_filter_options("first,opt=0,last=1", "opt\0x-opt\0", 1, "opt", "0", "first,last=1");
do_fstab_filter_options("first=1,opt=0,last=2", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "first=1,last=2"); do_fstab_filter_options("first=1,opt=0,last=2", "x-opt\0opt\0", 1, "opt", "0", "first=1,last=2");
do_fstab_filter_options("first,opt,last", "opt\0", 1, 0, "opt", NULL, "", "first,last"); do_fstab_filter_options("first,opt,last", "opt\0", 1, "opt", NULL, "first,last");
do_fstab_filter_options("first=1,opt,last", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "first=1,last"); do_fstab_filter_options("first=1,opt,last", "x-opt\0opt\0", 1, "opt", NULL, "first=1,last");
do_fstab_filter_options("first=,opt,last", "opt\0noopt\0", 1, 0, "opt", NULL, "", "first=,last"); do_fstab_filter_options("first=,opt,last", "opt\0noopt\0", 1, "opt", NULL, "first=,last");
/* check repeated options */ /* check repeated options */
do_fstab_filter_options("first,opt=0,noopt=1,last=1", "opt\0noopt\0", 1, 1, "noopt", "1", "0:1", "first,last=1"); do_fstab_filter_options("first,opt=0,noopt=1,last=1", "opt\0noopt\0", 1, "noopt", "1", "first,last=1");
do_fstab_filter_options("first=1,opt=0,last=2,opt=1", "opt\0", 1, 1, "opt", "1", "0:1", "first=1,last=2"); do_fstab_filter_options("first=1,opt=0,last=2,opt=1", "opt\0", 1, "opt", "1", "first=1,last=2");
do_fstab_filter_options("x-opt=0,x-opt=1", "opt\0x-opt\0", 1, 1, "x-opt", "1", "0:1", ""); do_fstab_filter_options("x-opt=0,x-opt=1", "opt\0x-opt\0", 1, "x-opt", "1", "");
do_fstab_filter_options("opt=0,x-opt=1", "opt\0x-opt\0", 1, 1, "x-opt", "1", "0:1", ""); do_fstab_filter_options("opt=0,x-opt=1", "opt\0x-opt\0", 1, "x-opt", "1", "");
do_fstab_filter_options("opt=0,opt=1,opt=,opt=,opt=2", "opt\0noopt\0", 1, 1, "opt", "2", "0:1:::2", "");
/* check that semicolons are not misinterpreted */ /* check that semicolons are not misinterpreted */
do_fstab_filter_options("opt=0;", "opt\0", 1, 1, "opt", "0;", "0;", ""); do_fstab_filter_options("opt=0;", "opt\0", 1, "opt", "0;", "");
do_fstab_filter_options("opt;=0", "x-opt\0opt\0noopt\0x-noopt\0", 0, 0, NULL, NULL, "", NULL); do_fstab_filter_options("opt;=0", "x-opt\0opt\0noopt\0x-noopt\0", 0, NULL, NULL, NULL);
do_fstab_filter_options("opt;", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL); do_fstab_filter_options("opt;", "opt\0x-opt\0", 0, NULL, NULL, NULL);
/* check that spaces are not misinterpreted */ /* check that spaces are not misinterpreted */
do_fstab_filter_options("opt=0 ", "opt\0", 1, 1, "opt", "0 ", "0 ", ""); do_fstab_filter_options("opt=0 ", "opt\0", 1, "opt", "0 ", "");
do_fstab_filter_options("opt =0", "x-opt\0opt\0noopt\0x-noopt\0", 0, 0, NULL, NULL, "", NULL); do_fstab_filter_options("opt =0", "x-opt\0opt\0noopt\0x-noopt\0", 0, NULL, NULL, NULL);
do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL); do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, NULL, NULL, NULL);
/* check function with NULL args */ /* check function will NULL args */
do_fstab_filter_options(NULL, "opt\0", 0, 0, NULL, NULL, "", ""); do_fstab_filter_options(NULL, "opt\0", 0, NULL, NULL, "");
do_fstab_filter_options("", "opt\0", 0, 0, NULL, NULL, "", ""); do_fstab_filter_options("", "opt\0", 0, NULL, NULL, "");
/* unnecessary comma separators */
do_fstab_filter_options("opt=x,,,,", "opt\0", 1, 1, "opt", "x", "x", "");
do_fstab_filter_options(",,,opt=x,,,,", "opt\0", 1, 1, "opt", "x", "x", "");
/* escaped characters */
do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt1\0", 1, 1, "opt1", "\\", "\\", "opt2=\\xff");
do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt2\0", 1, 1, "opt2", "\\xff", "\\xff", "opt1=\\");
} }
static void test_fstab_find_pri(void) { static void test_fstab_find_pri(void) {

View File

@ -345,12 +345,6 @@ static void test_strjoina(void) {
actual = strjoina("foo", NULL, "bar"); actual = strjoina("foo", NULL, "bar");
assert_se(streq(actual, "foo")); assert_se(streq(actual, "foo"));
actual = strjoina("/sys/fs/cgroup/", "dn", "/a/b/c", "/cgroup.procs");
assert_se(streq(actual, "/sys/fs/cgroup/dn/a/b/c/cgroup.procs"));
actual = strjoina("/sys/fs/cgroup/", "dn", NULL, NULL);
assert_se(streq(actual, "/sys/fs/cgroup/dn"));
} }
static void test_strjoin(void) { static void test_strjoin(void) {

View File

@ -333,12 +333,12 @@ static void test_strv_split(void) {
l = strv_free_erase(l); l = strv_free_erase(l);
assert_se(strv_split_full(&l, " 'one' \" two\t three \"' four five", NULL, assert_se(strv_split_full(&l, " 'one' \" two\t three \"' four five", NULL,
EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_UNESCAPE_RELAX) == 2); EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_CUNESCAPE_RELAX) == 2);
assert_se(strv_equal(l, (char**) input_table_quoted_joined)); assert_se(strv_equal(l, (char**) input_table_quoted_joined));
l = strv_free_erase(l); l = strv_free_erase(l);
assert_se(strv_split_full(&l, "\\", NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_UNESCAPE_RELAX) == 1); assert_se(strv_split_full(&l, "\\", NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_CUNESCAPE_RELAX) == 1);
assert_se(strv_equal(l, STRV_MAKE("\\"))); assert_se(strv_equal(l, STRV_MAKE("\\")));
} }