1
0
mirror of https://github.com/systemd/systemd synced 2025-10-04 19:24:44 +02:00

Compare commits

..

27 Commits

Author SHA1 Message Date
ulf-f
2d8ce4c701 Update resolvectl.xml
fixed typo of filename
2021-03-11 19:24:53 +01:00
Frantisek Sumsal
cb72605436 Revert "sd-event: re-check new epoll events when a child event is queued"
This reverts commit 84e998c112ff18bba786660bd6c1f96f62a77ffe.

Temporarily revert this commit, since it breaks CI.
2021-03-11 18:57:43 +01:00
Lennart Poettering
d55d61823f
Merge pull request #18922 from yuwata/sd-event-fix-issue-18190
sd-event: re-check new epoll events when a child event is queued
2021-03-11 16:36:38 +01:00
Yu Watanabe
84e998c112 sd-event: re-check new epoll events when a child event is queued
Previously, when a process outputs something and exit just after
epoll_wait() but before process_child(), then the IO event is ignored
even if the IO event has higher priority. See #18190.

This can be solved by checking epoll event again after process_child().

However, there exists a possibility that another process outputs and
exits just after process_child() but before the second epoll_wait().
When the IO event has lower priority than the child event, still IO
event is processed.

So, this makes new epoll events and child events are checked in a loop
until no new event is detected. To prevent an infinite loop, the number
of maximum trial is set to 10.

Fixes #18190.
2021-03-11 23:09:04 +09:00
Yu Watanabe
7fe11e84c2 test: add log messages 2021-03-11 23:09:04 +09:00
Zbigniew Jędrzejewski-Szmek
e3c82b1b1a NEWS: update contributors list for v248-rc3 2021-03-11 15:07:26 +01:00
Zbigniew Jędrzejewski-Szmek
47d1cae6cf
Merge pull request #18915 from keszybz/reexec-bug
Fix crash during daemon-reexec with systemd-oomd running
2021-03-11 14:46:16 +01:00
Zbigniew Jędrzejewski-Szmek
eb406c4e19
Merge pull request #18955 from keszybz/fstab-escaping
Fix handling of escaped characters in fstab
2021-03-11 14:45:11 +01:00
Zbigniew Jędrzejewski-Szmek
e4645ca599 basic/group-util: optimize alloca use
Follow-up for 0fa7b50053.
2021-03-11 14:43:16 +01:00
Zbigniew Jędrzejewski-Szmek
bcef0f33cc docs: more markup 2021-03-11 14:43:16 +01:00
Frantisek Sumsal
3a1bc3fcc0 repart: fix the loop dev support check
Since f17bdf8264e231fa31c769bff2475ef698487d0b the test-repart was
effectively disabled, since `/dev/loop-control` is a character special
file, whereas `-f` works only on regular files. Even though we could use
`-c` to check specifically for character special files, let's use `-e`
just in case.
2021-03-11 14:42:33 +01:00
Zbigniew Jędrzejewski-Szmek
ceffd6a961
Merge pull request #18962 from poettering/dissect-fixes
three image dissection fixes
2021-03-11 14:42:17 +01:00
Lennart Poettering
38db55ab0c dissect: fix trivial typo 2021-03-11 11:49:19 +01:00
Lennart Poettering
334eb5b099 dissect-image: fix volatile images
This makes sure nspawn's --volatile=yes switch works again: there we
have a read-only image that is overmounted by a tmpfs (with the
exception of /usr). This we need to mkdir all mount points even though
the image is read-only.

Hence, let's drop the optimizatio of avoiding mkdir() on images that are
read-only, it's wrong and misleading here, since the image itself might
be read-only but our mounts are not.
2021-03-11 11:48:31 +01:00
Lennart Poettering
9842905ede dissect-image: clean up meaning of DISSECT_IMAGE_MKDIR
Previously handling of DISSECT_IMAGE_MKDIR was pretty weird and broken:
it would control both if we create the top-level mount point when
mounting an image, and the inner mount points for images that consist of
multiple file systems. However, the latter is redundant, since
1f0f82f1311e4c52152b8e2b6f266258709c137d does this too, a few lines
further up – unconditionally!

Hence, let's make the meaning of DISSECT_IMAGE_MKDIR more strict: it
shall be only about the top-level mount point, not about the inner ones
(where we'll continue to create what is missing alwayway). Having a
separate flag for the top-level mount point is relevant, since the mount
point dir created by it will remain on the host fs – unlike the
directories we create inside the image, which will stay within the
image.

This slightly change of meaning is actually inline with what the flag is
actually used for and documented in systemd-dissect.
2021-03-11 11:48:31 +01:00
Zbigniew Jędrzejewski-Szmek
d6cef552dc fstab-generator: get rid of fstab_extract_values()
This was a parallel implementation of option parsing that didn't
support escaping of separators. Let's port this over to the common code.

Fixes #18952.
2021-03-11 11:25:15 +01:00
Zbigniew Jędrzejewski-Szmek
ff0c31bc27 shared/fstab-util: teach fstab_filter_options() a mode where all values are returned
Apart from tests, the new argument isn't used anywhere, so there should be no
functional change. Note that the two arms of the big conditional are switched, so the
diff is artificially inflated. The actual code change is rather small. I dropped the
path which extracts ret_value manually, because it wasn't supporting unescaping of the
escape character properly.
2021-03-11 11:25:15 +01:00
Zbigniew Jędrzejewski-Szmek
0264b404b9 shared/fstab-util: pass through the escape character
… when not used to escape the separator (,) or the escape character (\).
This mostly restores behaviour from before 0645b83a40d1c782f173c4d8440ab2fc82a75006,
but still allows "," to be escaped.

Partially fixes #18952.
2021-03-11 11:25:06 +01:00
Zbigniew Jędrzejewski-Szmek
3141089f53 basic/extract-word: rename flag
The flag enables "relaxed mode" for all kinds of unescaping, not just c-unescaping.
2021-03-11 09:21:07 +01:00
Zbigniew Jędrzejewski-Szmek
76c4e48ee6 basic/extract-word: allow escape character to be escaped
With EXTRACT_UNESCAPE_SEPARATORS, backslash is used to escape the separator.
But it wasn't possible to insert the backslash itself. Let's allow this and
add test.
2021-03-11 09:21:07 +01:00
Zbigniew Jędrzejewski-Szmek
8723c716c7 basic/extract_word: try to explain what the various options do
A test for stripping of escaped backslashes without any flags was explicitly
added back in 4034a06ddb82ec9868cd52496fef2f5faa25575f. So it seems to be on
purpose, though I would say that this is at least surprising and hence deserves
a comment.

In test-extract-word, add tests for standalone EXTRACT_UNESCAPE_SEPARATORS.
Only behaviour combined with EXTRACT_CUNESCAPE was tested.
2021-03-11 09:21:04 +01:00
Zbigniew Jędrzejewski-Szmek
5fa2da1251 shared/fstab-util: immediately drop empty options again
In the conversion from strv_split() to strv_split_full() done in
7bb553bb98a57b4e03804f8192bdc5a534325582, EXTRACT_DONT_COALESCE_SEPARATORS was
added. I think this was just by mistake… We never look for "empty options", so
whether we immediately ignore the extra separator or store the empty string in
strv, should make no difference.
2021-03-11 09:19:54 +01:00
Zbigniew Jędrzejewski-Szmek
924f650305 generators: warn but ignore failure to write timeouts
When we failed to split the options (because of disallowed quoting syntax, which
might be a bug in its own), we would silently fail. Instead, let's emit a warning.
Since we ignore the value if we cannot parse it anyway, let's ignore this error
too.
2021-03-11 09:19:00 +01:00
Zbigniew Jędrzejewski-Szmek
1677b88d01 fstab-generator: do not propagate error if we fail to canonicalize
r is used for the return value of the function, so we shouldn't
use it a non-fatal check.
2021-03-10 16:54:18 +01:00
Zbigniew Jędrzejewski-Szmek
a19c1a4baa oomd: "downgrade" level of message
PID1 already logs about the service being started, so this line isn't necessary
in normal use. Also, by the time it is emitted, the service has already
signalled readiness, so let's not say "starting" but "started".
2021-03-09 14:05:49 +01:00
Zbigniew Jędrzejewski-Szmek
39ad3f1c09 varlink: avoid using dangling ref in varlink_close_unref()
Fixes #18025, https://bugzilla.redhat.com/show_bug.cgi?id=1931034.

We drop the reference stored in Manager.managed_oom_varlink_request in two code paths:
vl_disconnect() which is installed as a disconnect callback, and in manager_varlink_done().
But we also make a disconnect from manager_varlink_done(). So we end up with the following
call stack:

(gdb) bt
 0  vl_disconnect (s=0x112c7b0, link=0xea0070, userdata=0xe9bcc0) at ../src/core/core-varlink.c:414
 1  0x00007f1366e9d5ac in varlink_detach_server (v=0xea0070) at ../src/shared/varlink.c:1210
 2  0x00007f1366e9d664 in varlink_close (v=0xea0070) at ../src/shared/varlink.c:1228
 3  0x00007f1366e9d6b5 in varlink_close_unref (v=0xea0070) at ../src/shared/varlink.c:1240
 4  0x0000000000524629 in manager_varlink_done (m=0xe9bcc0) at ../src/core/core-varlink.c:479
 5  0x000000000048ef7b in manager_free (m=0xe9bcc0) at ../src/core/manager.c:1357
 6  0x000000000042602c in main (argc=5, argv=0x7fff439c43d8) at ../src/core/main.c:2909

When we enter vl_disconnect(), m->managed_oom_varlink_request.n_ref==1.
When we exit from vl_discconect(), m->managed_oom_varlink_request==NULL. But
varlink_close_unref() has a copy of the pointer in *v. When we continue executing
varlink_close_unref(), this pointer is dangling, and the call to varlink_unref()
is done with an invalid pointer.
2021-03-09 14:05:49 +01:00
Zbigniew Jędrzejewski-Szmek
8b0f54c929 pid1: return varlink error on the right connection 2021-03-09 13:49:02 +01:00
25 changed files with 379 additions and 264 deletions

58
NEWS
View File

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

View File

@ -587,11 +587,11 @@ layout: default
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!
- Never use FILENAME_MAX. Use PATH_MAX instead (for checking maximum size of
paths) and NAME_MAX (for checking maximum size of filenames). FILENAME_MAX is
not POSIX, and is a confusingly named alias for PATH_MAX on Linux. Note the
NAME_MAX does not include space for a trailing NUL, but PATH_MAX does. UNIX
FTW!
- Never use `FILENAME_MAX`. Use `PATH_MAX` instead (for checking maximum size
of paths) and `NAME_MAX` (for checking maximum size of filenames).
`FILENAME_MAX` is not POSIX, and is a confusingly named alias for `PATH_MAX`
on Linux. Note the `NAME_MAX` does not include space for a trailing `NUL`,
but `PATH_MAX` does. UNIX FTW!
## 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
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
<filename>/etc/systemd/resolve.conf</filename>) in place of per-link configuration is used.</para></listitem>
<filename>/etc/systemd/resolved.conf</filename>) in place of per-link configuration is used.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -533,14 +533,12 @@ static int controller_is_v1_accessible(const char *root, const char *controller)
assert(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)
return -errno;

View File

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

View File

@ -4,13 +4,15 @@
#include "macro.h"
typedef enum ExtractFlags {
EXTRACT_RELAX = 1 << 0,
EXTRACT_CUNESCAPE = 1 << 1,
EXTRACT_CUNESCAPE_RELAX = 1 << 2,
EXTRACT_UNESCAPE_SEPARATORS = 1 << 3,
EXTRACT_UNQUOTE = 1 << 4,
EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5,
EXTRACT_RETAIN_ESCAPE = 1 << 6,
EXTRACT_RELAX = 1 << 0, /* Allow unbalanced quote and eat up trailing backslash. */
EXTRACT_CUNESCAPE = 1 << 1, /* Unescape known escape sequences. */
EXTRACT_UNESCAPE_RELAX = 1 << 2, /* Allow and keep unknown escape sequences, allow and keep trailing backslash. */
EXTRACT_UNESCAPE_SEPARATORS = 1 << 3, /* Unescape separators (those specified, or whitespace by default). */
EXTRACT_UNQUOTE = 1 << 4, /* Remove quoting with "" and ''. */
EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5, /* Don't treat multiple adjacent separators as one */
EXTRACT_RETAIN_ESCAPE = 1 << 6, /* Treat escape character '\' as any other character without special meaning */
/* Note that if no flags are specified, escaped escape characters will be silently stripped. */
} ExtractFlags;
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.
* 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)
return varlink_error(m->managed_oom_varlink_request, VARLINK_ERROR_SUBSCRIPTION_TAKEN, NULL);
return varlink_error(link, VARLINK_ERROR_SUBSCRIPTION_TAKEN, NULL);
r = json_build(&arr, JSON_BUILD_EMPTY_ARRAY);
if (r < 0)
@ -188,6 +188,7 @@ static int vl_method_subscribe_managed_oom_cgroups(
if (!FLAGS_SET(flags, VARLINK_METHOD_MORE))
return varlink_reply(link, v);
assert(!m->managed_oom_varlink_request);
m->managed_oom_varlink_request = varlink_ref(link);
return varlink_notify(m->managed_oom_varlink_request, v);
}
@ -475,8 +476,7 @@ void manager_varlink_done(Manager *m) {
assert(m);
/* Send the final message if we still have a subscribe request open. */
if (m->managed_oom_varlink_request)
m->managed_oom_varlink_request = varlink_close_unref(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);
}

View File

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

View File

@ -301,7 +301,9 @@ static int create_disk(
netdev = fstab_test_option(options, "_netdev\0");
attach_in_initrd = fstab_test_option(options, "x-initrd.attach\0");
keyfile_can_timeout = fstab_filter_options(options, "keyfile-timeout\0", NULL, &keyfile_timeout_value, NULL);
keyfile_can_timeout = fstab_filter_options(options,
"keyfile-timeout\0",
NULL, &keyfile_timeout_value, NULL, NULL);
if (keyfile_can_timeout < 0)
return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m");
@ -310,11 +312,12 @@ static int create_disk(
"header\0",
NULL,
&header_path,
NULL,
headerdev ? &filtered_header : NULL);
if (detached_header < 0)
return log_error_errno(detached_header, "Failed to parse header= option value: %m");
tmp = fstab_filter_options(options, "tmp\0", NULL, &tmp_fstype, NULL);
tmp = fstab_filter_options(options, "tmp\0", NULL, &tmp_fstype, NULL, NULL);
if (tmp < 0)
return log_error_errno(tmp, "Failed to parse tmp= option value: %m");
@ -602,7 +605,7 @@ static int filter_header_device(const char *options,
assert(ret_headerdev);
assert(ret_filtered_headerdev_options);
r = fstab_filter_options(options, "header\0", NULL, &headerspec, &filtered_headerspec);
r = fstab_filter_options(options, "header\0", NULL, &headerspec, NULL, &filtered_headerspec);
if (r < 0)
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)
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 stdou we don't copy any attributes (i.e. no access mode, no ownership, no xattr, no times) */
/* When we copy to stdout we don't copy any attributes (i.e. no access mode, no ownership, no xattr, no times) */
return 0;
}

View File

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

View File

@ -201,6 +201,8 @@ static void test_basic(bool with_pidfd) {
uint64_t event_now;
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(pipe(a) >= 0);
@ -302,6 +304,8 @@ static void test_sd_event_now(void) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
uint64_t event_now;
log_info("/* %s */", __func__);
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_REALTIME, &event_now) > 0);
@ -339,6 +343,8 @@ static void test_rtqueue(void) {
sd_event_source *u = NULL, *v = NULL, *s = NULL;
sd_event *e = NULL;
log_info("/* %s */", __func__);
assert_se(sd_event_default(&e) >= 0);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0);
@ -479,6 +485,8 @@ static void test_inotify(unsigned n_create_events) {
const char *q;
unsigned i;
log_info("/* %s(%u) */", __func__, n_create_events);
assert_se(sd_event_default(&e) >= 0);
assert_se(mkdtemp_malloc("/tmp/test-inotify-XXXXXX", &p) >= 0);
@ -545,6 +553,8 @@ static void test_pidfd(void) {
int pidfd;
pid_t pid, pid2;
log_info("/* %s */", __func__);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
pid = fork();
@ -619,6 +629,8 @@ static void test_ratelimit(void) {
uint64_t interval;
unsigned count, burst;
log_info("/* %s */", __func__);
assert_se(sd_event_default(&e) >= 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);
log_info("systemd-oomd starting%s!", arg_dry_run ? " in dry run mode" : "");
log_debug("systemd-oomd started%s.", arg_dry_run ? " in dry run mode" : "");
r = sd_event_loop(m->event);
if (r < 0)

View File

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

View File

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

View File

@ -1344,20 +1344,28 @@ static int mount_partition(
}
if (directory) {
if (!FLAGS_SET(flags, DISSECT_IMAGE_READ_ONLY)) {
/* Automatically create missing mount points, if necessary. */
r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755);
if (r < 0)
return r;
}
/* Automatically create missing mount points inside the image, if necessary. */
r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755);
if (r < 0 && r != -EROFS)
return r;
r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased, NULL);
if (r < 0)
return r;
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;
}
/* If requested, turn on discard support. */
if (fstype_can_discard(fstype) &&
@ -1382,12 +1390,6 @@ static int mount_partition(
if (!strextend_with_separator(&options, ",", m->mount_options))
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);
if (r < 0)
return r;
@ -1420,10 +1422,6 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
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) {
/* For us mounting root always means mounting /usr as well */
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_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_MKDIR = 1 << 14, /* Make directory to mount right before mounting, if missing */
DISSECT_IMAGE_MKDIR = 1 << 14, /* Make top-level directory to mount right before mounting, if missing */
} DissectImageFlags;
struct DissectedImage {

View File

@ -79,34 +79,95 @@ int fstab_is_mount_point(const char *mount) {
return false;
}
int fstab_filter_options(const char *opts, const char *names,
const char **ret_namefound, char **ret_value, char **ret_filtered) {
int fstab_filter_options(
const char *opts,
const char *names,
const char **ret_namefound,
char **ret_value,
char ***ret_values,
char **ret_filtered) {
const char *name, *namefound = NULL, *x;
_cleanup_strv_free_ char **stor = NULL;
_cleanup_free_ char *v = NULL, **strv = NULL;
_cleanup_strv_free_ char **stor = NULL, **values = NULL;
_cleanup_free_ char *value = NULL, **filtered = NULL;
int r;
assert(names && *names);
assert(!(ret_value && ret_values));
if (!opts)
goto answer;
/* If !ret_value and !ret_filtered, this function is not allowed to fail. */
/* Finds any options matching 'names', and returns:
* - 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) {
if (ret_filtered || ret_value || ret_values) {
/* 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;;) {
const char *end = word;
/* Look for an *non-escaped* comma separator. Only commas can be escaped, so "\," is
* the only valid escape sequence, so we can do a very simple test here. */
/* Look for a *non-escaped* comma separator. Only commas and backslashes can be
* escaped, so "\," and "\\" are the only valid escape sequences, and we can do a
* very simple test here. */
for (;;) {
size_t n = strcspn(end, ",");
end += strcspn(end, ",\\");
end += n;
if (n > 0 && end[-1] == '\\')
end++;
else
if (IN_SET(*end, ',', '\0'))
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) {
@ -119,17 +180,6 @@ int fstab_filter_options(const char *opts, const char *names,
x = word + strlen(name);
if (IN_SET(*x, '\0', '=', ',')) {
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;
}
}
@ -139,38 +189,6 @@ int fstab_filter_options(const char *opts, const char *names,
else
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:
if (ret_namefound)
@ -178,54 +196,27 @@ answer:
if (ret_filtered) {
char *f;
f = strv_join_full(strv, ",", NULL, true);
f = strv_join_full(filtered, ",", NULL, true);
if (!f)
return -ENOMEM;
*ret_filtered = f;
}
if (ret_value)
*ret_value = TAKE_PTR(v);
*ret_value = TAKE_PTR(value);
if (ret_values)
*ret_values = TAKE_PTR(values);
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) {
_cleanup_free_ char *opt = NULL;
int r, pri;
assert(ret);
r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL);
r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL, NULL);
if (r < 0)
return r;
if (r == 0 || !opt)

View File

@ -10,12 +10,16 @@ bool fstab_is_extrinsic(const char *mount, const char *opts);
int fstab_is_mount_point(const char *mount);
int fstab_has_fstype(const char *fstype);
int fstab_filter_options(const char *opts, const char *names, const char **namefound, char **value, char **filtered);
int fstab_extract_values(const char *opts, const char *name, char ***values);
int fstab_filter_options(
const char *opts,
const char *names,
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) {
return !!fstab_filter_options(opts, names, NULL, NULL, NULL);
return !!fstab_filter_options(opts, names, NULL, NULL, NULL, NULL);
}
int fstab_find_pri(const char *options, int *ret);
@ -26,7 +30,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 second name given is last or neither is found, return 0. */
assert_se(fstab_filter_options(opts, yes_no, &opt, NULL, NULL) >= 0);
assert_se(fstab_filter_options(opts, yes_no, &opt, NULL, NULL, NULL) >= 0);
return opt == yes_no;
}

View File

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

View File

@ -1206,8 +1206,9 @@ int varlink_close(Varlink *v) {
varlink_set_state(v, VARLINK_DISCONNECTED);
/* Let's take a reference first, since varlink_detach_server() might drop the final (dangling) ref
* which would destroy us before we can call varlink_clear() */
/* Let's take a reference first, since varlink_detach_server() might drop the final ref from the
* disconnect callback, which would invalidate the pointer we are holding before we can call
* varlink_clear(). */
varlink_ref(v);
varlink_detach_server(v);
varlink_clear(v);
@ -1220,17 +1221,33 @@ Varlink* varlink_close_unref(Varlink *v) {
if (!v)
return NULL;
(void) varlink_close(v);
/* A reference is given to us to be destroyed. But when calling varlink_close(), a callback might
* 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);
}
Varlink* varlink_flush_close_unref(Varlink *v) {
if (!v)
return NULL;
if (v)
varlink_flush(v);
(void) varlink_flush(v);
(void) varlink_close(v);
return varlink_unref(v);
return varlink_close_unref(v);
}
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));
p = original = "fooo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo\\"));
free(t);
assert_se(isempty(p));
p = original = "fooo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "fooo\\"));
free(t);
assert_se(isempty(p));
p = original = "fooo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo\\"));
free(t);
assert_se(isempty(p));
@ -230,17 +230,17 @@ static void test_extract_first_word(void) {
assert_se(isempty(p));
p = original = "\"foo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX) == -EINVAL);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_UNESCAPE_RELAX) == -EINVAL);
assert_se(p == original + 5);
p = original = "\"foo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "foo\\"));
free(t);
assert_se(isempty(p));
p = original = "\"foo\\";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "foo\\"));
free(t);
assert_se(isempty(p));
@ -252,13 +252,13 @@ static void test_extract_first_word(void) {
assert_se(p == original + 10);
p = original = "fooo\\ bar quux";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo bar"));
free(t);
assert_se(p == original + 10);
p = original = "fooo\\ bar quux";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
assert_se(streq(t, "fooo bar"));
free(t);
assert_se(p == original + 10);
@ -268,7 +268,7 @@ static void test_extract_first_word(void) {
assert_se(p == original + 5);
p = original = "fooo\\ bar quux";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
assert_se(streq(t, "fooo\\ bar"));
free(t);
assert_se(p == original + 10);
@ -278,13 +278,13 @@ static void test_extract_first_word(void) {
assert_se(p == original + 1);
p = original = "\\w+@\\K[\\d.]+";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
assert_se(streq(t, "\\w+@\\K[\\d.]+"));
free(t);
assert_se(isempty(p));
p = original = "\\w+\\b";
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
assert_se(streq(t, "\\w+\b"));
free(t);
assert_se(isempty(p));
@ -344,6 +344,39 @@ static void test_extract_first_word(void) {
free(t);
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 = "\\:";
assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
assert_se(streq(t, ":"));
@ -365,6 +398,18 @@ static void test_extract_first_word(void) {
free(t);
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 = "\\:";
assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE) == -EINVAL);

View File

@ -6,94 +6,125 @@
#include "fstab-util.h"
#include "log.h"
#include "string-util.h"
#include "strv.h"
/*
int fstab_filter_options(const char *opts, const char *names,
const char **namefound, char **value, char **filtered);
int fstab_filter_options(
const char *opts,
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,
const char *remove,
int r_expected,
int r_values_expected,
const char *name_expected,
const char *value_expected,
const char *values_expected,
const char *filtered_expected) {
int r;
const char *name;
_cleanup_free_ char *value = NULL, *filtered = NULL;
_cleanup_free_ char *value = NULL, *filtered = NULL, *joined = NULL;
_cleanup_strv_free_ char **values = NULL;
r = fstab_filter_options(opts, remove, &name, &value, &filtered);
log_info("\"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"",
opts, r, name, value, filtered,
/* test mode which returns the last value */
r = fstab_filter_options(opts, remove, &name, &value, NULL, &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);
assert_se(r == r_expected);
assert_se(streq_ptr(name, name_expected));
assert_se(streq_ptr(value, value_expected));
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 */
r = fstab_filter_options(opts, remove, &name, NULL, NULL);
log_info("\"%s\" → %d, \"%s\", expected %d, \"%s\"\n-",
opts, r, name,
r = fstab_filter_options(opts, remove, &name, NULL, NULL, NULL);
log_info("3: \"%s\" → %d, \"%s\", expected %d, \"%s\"\n-",
opts, r, strnull(name),
r_expected, name_expected);
assert_se(r == r_expected);
assert_se(streq_ptr(name, name_expected));
}
static void test_fstab_filter_options(void) {
do_fstab_filter_options("opt=0", "opt\0x-opt\0", 1, "opt", "0", "");
do_fstab_filter_options("opt=0", "x-opt\0opt\0", 1, "opt", "0", "");
do_fstab_filter_options("opt", "opt\0x-opt\0", 1, "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, "x-opt", NULL, "");
do_fstab_filter_options("opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "");
do_fstab_filter_options("opt=0", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "");
do_fstab_filter_options("opt", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "");
do_fstab_filter_options("opt", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "");
do_fstab_filter_options("x-opt", "x-opt\0opt\0", 1, 0, "x-opt", NULL, "", "");
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, "opt", "0", "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, "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,other", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "other");
do_fstab_filter_options("opt=0,other", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "other");
do_fstab_filter_options("opt,other", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other");
do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "other");
do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, 0, "x-opt", NULL, "", "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, "opt", "0", "other,x-opt\\,foobar");
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, "opt", NULL, "other,part\\,x-opt");
do_fstab_filter_options("opt,other\\,\\,\\,opt,x-part", "opt\0x-opt\0", 1, "opt", NULL, "other\\,\\,\\,opt,x-part");
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,other,x-opt\\,foobar", "x-opt\0opt\0", 1, 1, "opt", "0", "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,part\\,x-opt", "x-opt\0opt\0", 1, 0, "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("opto=0,other", "opt\0x-opt\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, NULL, NULL, NULL);
do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
do_fstab_filter_options("opto,other", "opt\0x-opt\0", 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("first,opt=0", "opt\0x-opt\0", 1, "opt", "0", "first");
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, "opt", "", "first");
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, "x-opt", NULL, "first=1");
do_fstab_filter_options("first,opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "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,opt=", "opt\0x-opt\0", 1, 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,x-opt", "opt\0x-opt\0", 1, 0, "x-opt", NULL, "", "first=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, "opt", "0", "first=1,last=2");
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, "opt", NULL, "first=1,last");
do_fstab_filter_options("first=,opt,last", "opt\0noopt\0", 1, "opt", NULL, "first=,last");
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=1,opt=0,last=2", "x-opt\0opt\0", 1, 1, "opt", "0", "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=1,opt,last", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "first=1,last");
do_fstab_filter_options("first=,opt,last", "opt\0noopt\0", 1, 0, "opt", NULL, "", "first=,last");
/* check repeated options */
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, "opt", "1", "first=1,last=2");
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, "x-opt", "1", "");
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=1,opt=0,last=2,opt=1", "opt\0", 1, 1, "opt", "1", "0: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("opt=0,x-opt=1", "opt\0x-opt\0", 1, 1, "x-opt", "1", "0: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 */
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, NULL, NULL, NULL);
do_fstab_filter_options("opt;", "opt\0x-opt\0", 0, NULL, NULL, NULL);
do_fstab_filter_options("opt=0;", "opt\0", 1, 1, "opt", "0;", "0;", "");
do_fstab_filter_options("opt;=0", "x-opt\0opt\0noopt\0x-noopt\0", 0, 0, NULL, NULL, "", NULL);
do_fstab_filter_options("opt;", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
/* check that spaces are not misinterpreted */
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, NULL, NULL, NULL);
do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, NULL, NULL, NULL);
do_fstab_filter_options("opt=0 ", "opt\0", 1, 1, "opt", "0 ", "0 ", "");
do_fstab_filter_options("opt =0", "x-opt\0opt\0noopt\0x-noopt\0", 0, 0, NULL, NULL, "", NULL);
do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
/* check function will NULL args */
do_fstab_filter_options(NULL, "opt\0", 0, NULL, NULL, "");
do_fstab_filter_options("", "opt\0", 0, NULL, NULL, "");
/* check function with NULL args */
do_fstab_filter_options(NULL, "opt\0", 0, 0, NULL, NULL, "", "");
do_fstab_filter_options("", "opt\0", 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) {

View File

@ -345,6 +345,12 @@ static void test_strjoina(void) {
actual = strjoina("foo", NULL, "bar");
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) {

View File

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