diff options
85 files changed, 1228 insertions, 610 deletions
@@ -756,7 +756,7 @@ CHANGES WITH 218: * When querying unit file enablement status (for example via "systemctl is-enabled"), a new state "indirect" is now known which indicates that a unit might not be enabled itself, but - another unit listed in its Alias= setting might be. + another unit listed in its Also= setting might be. * Similar to the various existing ConditionXYZ= settings for units there are now matching AssertXYZ= settings. While @@ -274,8 +274,3 @@ WARNINGS: servers if not specified otherwise at configure time. You really should not ship an OS or device with this default setting. See DISTRO_PORTING for details. - -ENGINEERING AND CONSULTING SERVICES: - ENDOCODE <https://endocode.com/> offers professional - engineering and consulting services for systemd. Please - contact Chris Kühl <chris@endocode.com> for more information. @@ -6,7 +6,7 @@ Bugfixes: automount points even when the original .automount file did not exist anymore. Only the .mount unit was still around. -* ExecStart with unicode characters fails in strv_split_quoted: +* ExecStart with unicode characters fails in strv_split_extract: [Service] Environment=ONE='one' "TWO='two two' too" THREE= @@ -26,6 +26,12 @@ External: Features: +* PID 1 should send out sd_notify("WATCHDOG=1") messages (for usage in the --user mode, and when run via nspawn) + +* nspawn should send out sd_notify("WATCHDOG=1") messages + +* nspawn should optionally support receiving WATCHDOG=1 messages from its payload PID 1... + * introduce "machinectl shell" that is like systemd-run -M foo /bin/bash -t but also adds PAMName=login * allow loging into host with "machinectl login". @@ -267,7 +273,7 @@ Features: * maybe add support for specifier expansion in user.conf, specifically DefaultEnvironment= -* code cleanup: retire FOREACH_WORD_QUOTED, port to unquote_first_word() loops instead +* code cleanup: retire FOREACH_WORD_QUOTED, port to extract_first_word() loops instead * introduce systemd-timesync-wait.service or so to sync on an NTP fix? @@ -303,7 +309,7 @@ Features: * exponential backoff in timesyncd and resolved when we cannot reach a server -* unquote_many_words() should probably be used by a lot of code that +* extract_many_words() should probably be used by a lot of code that currently uses FOREACH_WORD and friends. For example, most conf parsing callbacks should use it. @@ -348,7 +354,9 @@ Features: - avahi compat - DNS-SD service registration from socket units - edns0 - - dname + - dname: Not necessary for plain DNS as synthesized cname is handed out instead if we do not + announce dname support. However, for DNSSEC it is necessary as the synthesized cname + will not be signed. - cname on PTR (?) * Allow multiple ExecStart= for all Type= settings, so that we can cover rescue.service nicely @@ -464,6 +472,7 @@ Features: ReadOnlyDirectories=... for whitelisting files for a service. * sd-bus: + - change argv list matching logic - GetAllProperties() on a non-existing object does not result in a failure currently - kdbus: process fd=-1 for incoming msgs - port to sd-resolve for connecting to TCP dbus servers diff --git a/hwdb/70-mouse.hwdb b/hwdb/70-mouse.hwdb index 7373be4778..1451fc02cc 100644 --- a/hwdb/70-mouse.hwdb +++ b/hwdb/70-mouse.hwdb @@ -171,6 +171,8 @@ mouse:usb:v17efp6044:name:ThinkPad USB Laser Mouse: # Logitech M-BJ58 Optical Mouse mouse:usb:v046dpc00e:name:Logitech USB-PS/2 Optical Mouse: +# Logitech Mini Optical Mouse +mouse:usb:v046dpc016:name:Logitech Optical USB Mouse: # Logitech MX310 Optical Mouse mouse:usb:v046dpc01b:name:Logitech USB-PS/2 Optical Mouse: # Logitech USB-PS/2 M-BT58 @@ -219,6 +221,8 @@ mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4008: # Logitech M705 (marathon mouse) mouse:usb:v046dp101b:name:Logitech M705: mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:101b: +# Logitech Performance MX +mouse:usb:v046dp101a:name:Logitech Performance MX: MOUSE_DPI=800@166 # Logitech MX Revolution @@ -300,6 +304,10 @@ mouse:usb:v046dpc068:name:Logitech G500: mouse:bluetooth:v046dpb00d:name:Ultrathin Touch Mouse: MOUSE_DPI=1000@1000 +# ImPS/2 Logitech Wheel Mouse +mouse:ps2:*:name:ImPS/2 Logitech Wheel Mouse: + MOUSE_DPI=400@100 + # ImExPS/2 Logitech Wheel Mouse mouse:ps2:*:name:ImExPS/2 Logitech Wheel Mouse: MOUSE_DPI=400@250 @@ -314,6 +322,10 @@ mouse:usb:v045ep0040:name:Microsoft Microsoft 3-Button Mouse with IntelliEye(TM) # Note: unsure that these work, it's likely that all devices on these # receivers show up with the same vid/pid/name +# Microsoft Wireless Mouse 5000 +mouse:usb:v045ep0745:name:Microsoft Microsoft® 2.4GHz Transceiver v6.0: + MOUSE_DPI=800@142 + # Microsoft Sculpt Ergonomic Mouse mouse:usb:v045ep07a5:name:Microsoft Microsoft® 2.4GHz Transceiver v9.0: MOUSE_DPI=1000@142 diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index d1e050cb89..4966749259 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -581,7 +581,9 @@ same path in the container --, or a colon-separated pair of paths -- in which case the first specified path is the source in the host, and the second path is the destination in the - container. This option may be specified multiple times for + container. Backslash escapes are interpreted so + <literal>\:</literal> may be used to embed colons in either path. + This option may be specified multiple times for creating multiple independent bind mount points. The <option>--bind-ro=</option> option creates read-only bind mounts.</para></listitem> @@ -600,7 +602,10 @@ otherwise specified). This option is particularly useful for mounting directories such as <filename>/var</filename> as tmpfs, to allow state-less systems, in particular when - combined with <option>--read-only</option>.</para></listitem> + combined with <option>--read-only</option>. + Backslash escapes are interpreted in the path so + <literal>\:</literal> may be used to embed colons in the path. + </para></listitem> </varlistentry> <varlistentry> @@ -612,6 +617,10 @@ list of colon-separated paths to the directory trees to combine and the destination mount point.</para> + <para>Backslash escapes are interpreted in the paths, so + <literal>\:</literal> may be used to embed colons in the paths. + </para> + <para>If three or more paths are specified, then the last specified path is the destination mount point in the container, all paths specified before refer to directory trees diff --git a/man/systemd-timesyncd.service.xml b/man/systemd-timesyncd.service.xml index ac1af2d136..01ed0b8149 100644 --- a/man/systemd-timesyncd.service.xml +++ b/man/systemd-timesyncd.service.xml @@ -71,6 +71,10 @@ files, and the per-link dynamic settings received over DHCP. See <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more details.</para> + + <para><citerefentry><refentrytitle>timedatectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s + <command>set-ntp</command> command may be used to enable and + start, or disable and stop this service.</para> </refsect1> <refsect1> diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 7e96989583..4c113a3479 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -337,6 +337,19 @@ <literal>-</literal>) fail, the rest are not executed and the unit is considered failed.</para> + <para><varname>ExecStart=</varname> commands are only run after + all <varname>ExecStartPre=</varname> commands that were not prefixed + with a <literal>-</literal> exit successfully.</para> + + <para><varname>ExecStartPost=</varname> commands are only run after + the service has started, as determined by <varname>Type=</varname> + (i.e. The process has been started for <varname>Type=simple</varname> + or <varname>Type=idle</varname>, the process exits successfully for + <varname>Type=oneshot</varname>, the initial process exits successfully + for <varname>Type=forking</varname>, <literal>READY=1</literal> is sent + for <varname>Type=notify</varname>, or the <varname>BusName=</varname> + has been taken for <varname>Type=dbus</varname>).</para> + <para>Note that <varname>ExecStartPre=</varname> may not be used to start long-running processes. All processes forked off by processes invoked via <varname>ExecStartPre=</varname> will diff --git a/man/timedatectl.xml b/man/timedatectl.xml index 2d42b41d5e..9a86c4126a 100644 --- a/man/timedatectl.xml +++ b/man/timedatectl.xml @@ -166,12 +166,27 @@ <term><command>set-ntp [BOOL]</command></term> <listitem><para>Takes a boolean argument. Controls whether - network time synchronization is enabled (if available). This - enables or disables the - <filename>systemd-timesyncd.service</filename> unit. Note that - even if this command turns time synchronization off a - different system service might still synchronize the clock - with the network.</para></listitem> + network time synchronization is active and enabled (if + available). This enables and starts, or disables and stops the + <filename>systemd-timesyncd.service</filename> unit. It does + not affect the state of any other, unrelated network time + synchronization services that might be installed on the + system. This command is hence mostly equivalent to: + <command>systemctl enable --now + systemd-timesyncd.service</command> and <command>systemctl + disable --now systemd-timesyncd.service</command>, but is + protected by a different access policy.</para> + + <para>Note that even if time synchronization is turned off + with this command another, unrelated system service might + still synchronize the clock with the network. Also note that + strictly speaking + <filename>systemd-timesyncd.service</filename> does more than + just network time synchronization as it ensures a monotonic + clock on systems without RTC even if no network is + available. See + <citerefentry><refentrytitle>systemd-timesyncd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> + for details about this.</para></listitem> </varlistentry> </variablelist> diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules index 5ab03fc278..0b14bb4a11 100644 --- a/rules/60-persistent-storage.rules +++ b/rules/60-persistent-storage.rules @@ -6,7 +6,7 @@ ACTION=="remove", GOTO="persistent_storage_end" SUBSYSTEM!="block", GOTO="persistent_storage_end" -KERNEL!="loop*|mmcblk*[0-9]|msblk*[0-9]|mspblk*[0-9]|nvme*|sd*|sr*|vd*|xvd*|bcache*|cciss*|dasd*", GOTO="persistent_storage_end" +KERNEL!="loop*|mmcblk*[0-9]|msblk*[0-9]|mspblk*[0-9]|nvme*|sd*|sr*|vd*|xvd*|bcache*|cciss*|dasd*|ubd*", GOTO="persistent_storage_end" # ignore partitions that span the entire disk TEST=="whole_disk", GOTO="persistent_storage_end" diff --git a/shell-completion/bash/machinectl b/shell-completion/bash/machinectl index 3789492d72..0d09258a0b 100644 --- a/shell-completion/bash/machinectl +++ b/shell-completion/bash/machinectl @@ -26,7 +26,8 @@ __contains_word() { __get_machines() { local a b - machinectl list --no-legend --no-pager | { while read a b; do echo " $a"; done; }; + (machinectl list-images --no-legend --no-pager; machinectl list --no-legend --no-pager) | \ + { while read a b; do echo " $a"; done; } | sort -u; } _machinectl() { @@ -39,8 +40,8 @@ _machinectl() { ) local -A VERBS=( - [STANDALONE]='list' - [MACHINES]='status show terminate kill reboot login' + [STANDALONE]='list list-images' + [MACHINES]='status show start login enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit list-transfers cancel-transfer' ) _init_completion || return diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in index c2707ba3a6..0bcd49f923 100644 --- a/shell-completion/bash/systemctl.in +++ b/shell-completion/bash/systemctl.in @@ -108,7 +108,7 @@ _systemctl () { comps=$(compgen -A signal) ;; --type|-t) - comps='automount busname device mount path service snapshot socket swap target timer' + comps=$(__systemctl $mode -t help) ;; --state) comps='loaded not-found stub diff --git a/shell-completion/zsh/_busctl b/shell-completion/zsh/_busctl index fb1841341e..ef790e558f 100644 --- a/shell-completion/zsh/_busctl +++ b/shell-completion/zsh/_busctl @@ -24,7 +24,14 @@ local -a _busctl_cmds _busctl_cmds=( "list:List bus names" + "status:Show bus service, process or bus owner credentials" "monitor:Show bus traffic" + "capture:Capture bus traffix as pcap" + "tree:Show object tree of service" + "introspect:Introspect object" + "call:Call a method" + "get-property:Get property value" + "set-property:Set property value" ) if (( CURRENT == 1 )); then _describe -t commands 'busctl command' _busctl_cmds || compadd "$@" @@ -54,4 +61,12 @@ _arguments \ '--acquired[Only show acquired names]' \ '--activatable[Only show activatable names]' \ '--match=[Only show matching messages]:match' \ + '--list[Do not show tree, but simple object path list]' \ + '--quiet[Do not show method call reply]'\ + '--verbose[Show result values in long format]' \ + '--expect-reply=[Expect a method call reply]:boolean:(1 0)' \ + '--auto-start=[Auto-start destination service]:boolean:(1 0)' \ + '--allow-interactive-authorization=[Allow interactive authorization for operation]:boolean:(1 0)' \ + '--timeout=[Maximum time to wait for method call completion]:timeout (seconds)' \ + '--augment-creds=[Extend credential data with data read from /proc/$PID]:boolean:(1 0)' \ '*::busctl command:_busctl_command' diff --git a/src/basic/def.h b/src/basic/def.h index 5aaba1fe87..e0d6822f38 100644 --- a/src/basic/def.h +++ b/src/basic/def.h @@ -63,7 +63,6 @@ #define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket" #define KERNEL_SYSTEM_BUS_ADDRESS "kernel:path=/sys/fs/kdbus/0-system/bus" -#define DEFAULT_SYSTEM_BUS_ADDRESS KERNEL_SYSTEM_BUS_ADDRESS ";" UNIX_SYSTEM_BUS_ADDRESS #define UNIX_USER_BUS_ADDRESS_FMT "unix:path=%s/bus" #define KERNEL_USER_BUS_ADDRESS_FMT "kernel:path=/sys/fs/kdbus/"UID_FMT"-user/bus" diff --git a/src/basic/env-util.c b/src/basic/env-util.c index ac7bbdc711..4804a67f91 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -550,7 +550,7 @@ char **replace_env_argv(char **argv, char **env) { if (e) { int r; - r = strv_split_quoted(&m, e, UNQUOTE_RELAX); + r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_QUOTES); if (r < 0) { ret[k] = NULL; strv_free(ret); diff --git a/src/basic/strv.c b/src/basic/strv.c index d44a72fc48..eaf440a4b2 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -278,7 +278,7 @@ char **strv_split_newlines(const char *s) { return l; } -int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags) { +int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) { size_t n = 0, allocated = 0; _cleanup_strv_free_ char **l = NULL; int r; @@ -289,11 +289,12 @@ int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags) { for (;;) { _cleanup_free_ char *word = NULL; - r = unquote_first_word(&s, &word, flags); + r = extract_first_word(&s, &word, separators, flags); if (r < 0) return r; - if (r == 0) + if (r == 0) { break; + } if (!GREEDY_REALLOC(l, allocated, n + 2)) return -ENOMEM; @@ -693,6 +694,26 @@ char **strv_reverse(char **l) { return l; } +char **strv_shell_escape(char **l, const char *bad) { + char **s; + + /* Escapes every character in every string in l that is in bad, + * edits in-place, does not roll-back on error. */ + + STRV_FOREACH(s, l) { + char *v; + + v = shell_escape(*s, bad); + if (!v) + return NULL; + + free(*s); + *s = v; + } + + return l; +} + bool strv_fnmatch(char* const* patterns, const char *s, int flags) { char* const* p; diff --git a/src/basic/strv.h b/src/basic/strv.h index 22f8f98fda..f07da8cdf3 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -73,7 +73,7 @@ static inline bool strv_isempty(char * const *l) { char **strv_split(const char *s, const char *separator); char **strv_split_newlines(const char *s); -int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags); +int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags); char *strv_join(char **l, const char *separator); char *strv_join_quoted(char **l); @@ -145,6 +145,7 @@ void strv_print(char **l); })) char **strv_reverse(char **l); +char **strv_shell_escape(char **l, const char *bad); bool strv_fnmatch(char* const* patterns, const char *s, int flags); diff --git a/src/basic/util.c b/src/basic/util.c index 3811460895..9571f0ab12 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -4843,7 +4843,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { _cleanup_free_ char *word = NULL; char *value = NULL; - r = unquote_first_word(&p, &word, UNQUOTE_RELAX); + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) return r; if (r == 0) @@ -4883,7 +4883,7 @@ int get_proc_cmdline_key(const char *key, char **value) { _cleanup_free_ char *word = NULL; const char *e; - r = unquote_first_word(&p, &word, UNQUOTE_RELAX); + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) return r; if (r == 0) @@ -5729,7 +5729,7 @@ int is_device_node(const char *path) { return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode)); } -int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { _cleanup_free_ char *s = NULL; size_t allocated = 0, sz = 0; int r; @@ -5742,13 +5742,19 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { SINGLE_QUOTE_ESCAPE, DOUBLE_QUOTE, DOUBLE_QUOTE_ESCAPE, - SPACE, + SEPARATOR, } state = START; assert(p); - assert(*p); assert(ret); + if (!separators) + separators = WHITESPACE; + + /* Bail early if called after last value or with no input */ + if (!*p) + goto finish_force_terminate; + /* Parses the first word of a string, and returns it in * *ret. Removes all quotes in the process. When parsing fails * (because of an uneven number of quotes or similar), leaves @@ -5760,32 +5766,46 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { switch (state) { case START: - if (c == 0) - goto finish; - else if (strchr(WHITESPACE, c)) + if (c == 0) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + goto finish_force_terminate; + } else if (strchr(separators, c)) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + (*p) ++; + goto finish_force_next; + } break; + } state = VALUE; /* fallthrough */ case VALUE: if (c == 0) - goto finish; - else if (c == '\'') { + goto finish_force_terminate; + else if (c == '\'' && (flags & EXTRACT_QUOTES)) { if (!GREEDY_REALLOC(s, allocated, sz+1)) return -ENOMEM; state = SINGLE_QUOTE; } else if (c == '\\') state = VALUE_ESCAPE; - else if (c == '\"') { + else if (c == '\"' && (flags & EXTRACT_QUOTES)) { if (!GREEDY_REALLOC(s, allocated, sz+1)) return -ENOMEM; state = DOUBLE_QUOTE; - } else if (strchr(WHITESPACE, c)) - state = SPACE; - else { + } else if (strchr(separators, c)) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { + (*p) ++; + goto finish_force_next; + } + state = SEPARATOR; + } else { if (!GREEDY_REALLOC(s, allocated, sz+2)) return -ENOMEM; @@ -5796,8 +5816,8 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { case SINGLE_QUOTE: if (c == 0) { - if (flags & UNQUOTE_RELAX) - goto finish; + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; return -EINVAL; } else if (c == '\'') state = VALUE; @@ -5835,29 +5855,29 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { return -ENOMEM; if (c == 0) { - if ((flags & UNQUOTE_CUNESCAPE_RELAX) && - (state == VALUE_ESCAPE || flags & UNQUOTE_RELAX)) { + if ((flags & EXTRACT_CUNESCAPE_RELAX) && + (state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) { /* If we find an unquoted trailing backslash and we're in - * UNQUOTE_CUNESCAPE_RELAX mode, keep it verbatim in the + * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the * output. * - * Unbalanced quotes will only be allowed in UNQUOTE_RELAX - * mode, UNQUOTE_CUNESCAP_RELAX mode does not allow them. + * Unbalanced quotes will only be allowed in EXTRACT_RELAX + * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them. */ s[sz++] = '\\'; - goto finish; + goto finish_force_terminate; } - if (flags & UNQUOTE_RELAX) - goto finish; + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; return -EINVAL; } - if (flags & UNQUOTE_CUNESCAPE) { + if (flags & EXTRACT_CUNESCAPE) { uint32_t u; r = cunescape_one(*p, (size_t) -1, &c, &u); if (r < 0) { - if (flags & UNQUOTE_CUNESCAPE_RELAX) { + if (flags & EXTRACT_CUNESCAPE_RELAX) { s[sz++] = '\\'; s[sz++] = c; goto end_escape; @@ -5880,24 +5900,29 @@ end_escape: VALUE; break; - case SPACE: + case SEPARATOR: if (c == 0) + goto finish_force_terminate; + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) + goto finish_force_next; + if (!strchr(separators, c)) goto finish; - if (!strchr(WHITESPACE, c)) - goto finish; - break; } (*p) ++; } +finish_force_terminate: + *p = NULL; finish: if (!s) { + *p = NULL; *ret = NULL; return 0; } +finish_force_next: s[sz] = 0; *ret = s; s = NULL; @@ -5905,26 +5930,27 @@ finish: return 1; } -int unquote_first_word_and_warn( +int extract_first_word_and_warn( const char **p, char **ret, - UnquoteFlags flags, + const char *separators, + ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue) { /* Try to unquote it, if it fails, warn about it and try again but this - * time using UNQUOTE_CUNESCAPE_RELAX to keep the backslashes verbatim + * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim * in invalid escape sequences. */ const char *save; int r; save = *p; - r = unquote_first_word(p, ret, flags); - if (r < 0 && !(flags&UNQUOTE_CUNESCAPE_RELAX)) { - /* Retry it with UNQUOTE_CUNESCAPE_RELAX. */ + r = extract_first_word(p, ret, separators, flags); + if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) { + /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ *p = save; - r = unquote_first_word(p, ret, flags|UNQUOTE_CUNESCAPE_RELAX); + r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); if (r < 0) log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue); @@ -5935,7 +5961,7 @@ int unquote_first_word_and_warn( return r; } -int unquote_many_words(const char **p, UnquoteFlags flags, ...) { +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) { va_list ap; char **l; int n = 0, i, c, r; @@ -5961,7 +5987,7 @@ int unquote_many_words(const char **p, UnquoteFlags flags, ...) { l = newa0(char*, n); for (c = 0; c < n; c++) { - r = unquote_first_word(p, &l[c], flags); + r = extract_first_word(p, &l[c], separators, flags); if (r < 0) { int j; @@ -6542,6 +6568,32 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char return 0; } +static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) { + assert(bad); + + for (; *s; s++) { + if (*s == '\\' || strchr(bad, *s)) + *(t++) = '\\'; + + *(t++) = *s; + } + + return t; +} + +char *shell_escape(const char *s, const char *bad) { + char *r, *t; + + r = new(char, strlen(s)*2+1); + if (!r) + return NULL; + + t = strcpy_backslash_escaped(r, s, bad); + *t = 0; + + return r; +} + char *shell_maybe_quote(const char *s) { const char *p; char *r, *t; @@ -6568,13 +6620,7 @@ char *shell_maybe_quote(const char *s) { *(t++) = '"'; t = mempcpy(t, s, p - s); - for (; *p; p++) { - - if (strchr(SHELL_NEED_ESCAPE, *p)) - *(t++) = '\\'; - - *(t++) = *p; - } + t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE); *(t++)= '"'; *t = 0; diff --git a/src/basic/util.h b/src/basic/util.h index 1667b35f00..8f21d56ed8 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -854,15 +854,17 @@ int is_symlink(const char *path); int is_dir(const char *path, bool follow); int is_device_node(const char *path); -typedef enum UnquoteFlags { - UNQUOTE_RELAX = 1, - UNQUOTE_CUNESCAPE = 2, - UNQUOTE_CUNESCAPE_RELAX = 4, -} UnquoteFlags; - -int unquote_first_word(const char **p, char **ret, UnquoteFlags flags); -int unquote_first_word_and_warn(const char **p, char **ret, UnquoteFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); -int unquote_many_words(const char **p, UnquoteFlags flags, ...) _sentinel_; +typedef enum ExtractFlags { + EXTRACT_RELAX = 1, + EXTRACT_CUNESCAPE = 2, + EXTRACT_CUNESCAPE_RELAX = 4, + EXTRACT_QUOTES = 8, + EXTRACT_DONT_COALESCE_SEPARATORS = 16, +} ExtractFlags; + +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); +int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; static inline void free_and_replace(char **s, char *v) { free(*s); @@ -917,6 +919,7 @@ void cmsg_close_all(struct msghdr *mh); int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); +char *shell_escape(const char *s, const char *bad); char *shell_maybe_quote(const char *s); int parse_mode(const char *s, mode_t *ret); diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 359fde9998..ac1711b318 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -818,7 +818,7 @@ static int remove_boot_efi(const char *esp_path) { if (r < 0) return log_error_errno(errno, "Failed to remove \"%s/%s\": %m", p, de->d_name); - log_info("Removed \"%s/\%s\".", p, de->d_name); + log_info("Removed \"%s/%s\".", p, de->d_name); } c++; diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c index 3cc3b33ae7..6e07aea94e 100644 --- a/src/bus-proxyd/bus-proxyd.c +++ b/src/bus-proxyd/bus-proxyd.c @@ -177,8 +177,9 @@ static int help(void) { " --configuration=PATH Configuration file or directory\n" " --machine=MACHINE Connect to specified machine\n" " --address=ADDRESS Connect to the bus specified by ADDRESS\n" - " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n", - program_invocation_short_name); + " (default: %s)\n", + program_invocation_short_name, + is_kdbus_available() ? KERNEL_SYSTEM_BUS_ADDRESS : UNIX_SYSTEM_BUS_ADDRESS); return 0; } @@ -262,7 +263,7 @@ static int parse_argv(int argc, char *argv[]) { } if (!arg_address) { - arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS); + arg_address = strdup(is_kdbus_available() ? KERNEL_SYSTEM_BUS_ADDRESS : UNIX_SYSTEM_BUS_ADDRESS); if (!arg_address) return log_oom(); } diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c index f275f6705f..c5dac396d3 100644 --- a/src/bus-proxyd/stdio-bridge.c +++ b/src/bus-proxyd/stdio-bridge.c @@ -50,8 +50,9 @@ static int help(void) { " --version Show package version\n" " --machine=MACHINE Connect to specified machine\n" " --address=ADDRESS Connect to the bus specified by ADDRESS\n" - " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n", - program_invocation_short_name); + " (default: %s)\n", + program_invocation_short_name, + is_kdbus_available() ? KERNEL_SYSTEM_BUS_ADDRESS : UNIX_SYSTEM_BUS_ADDRESS); return 0; } @@ -137,7 +138,7 @@ static int parse_argv(int argc, char *argv[]) { } if (!arg_address) { - arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS); + arg_address = strdup(is_kdbus_available() ? KERNEL_SYSTEM_BUS_ADDRESS : UNIX_SYSTEM_BUS_ADDRESS); if (!arg_address) return log_oom(); } diff --git a/src/core/automount.c b/src/core/automount.c index 4af381b4b6..2b84c441b2 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -39,7 +39,6 @@ #include "path-util.h" #include "dbus-automount.h" #include "bus-util.h" -#include "bus-error.h" #include "formats-util.h" #include "process-util.h" #include "async.h" diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c index 74a9914358..8ea2cf84a4 100644 --- a/src/core/dbus-timer.c +++ b/src/core/dbus-timer.c @@ -252,8 +252,7 @@ static int bus_timer_set_transient_property( v = new0(TimerValue, 1); if (!v) { - if (c) - calendar_spec_free(c); + calendar_spec_free(c); return -ENOMEM; } diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 299172123e..e1e3a5ffb7 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -552,7 +552,7 @@ int config_parse_exec( semicolon = false; - r = unquote_first_word_and_warn(&p, &firstword, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue); + r = extract_first_word_and_warn(&p, &firstword, WHITESPACE, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue); if (r <= 0) return 0; @@ -614,7 +614,7 @@ int config_parse_exec( path_kill_slashes(path); - for (;;) { + while (!isempty(p)) { _cleanup_free_ char *word = NULL; /* Check explicitly for an unquoted semicolon as @@ -627,7 +627,7 @@ int config_parse_exec( } /* Check for \; explicitly, to not confuse it with \\; - * or "\;" or "\\;" etc. unquote_first_word would + * or "\;" or "\\;" etc. extract_first_word would * return the same for all of those. */ if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) { p += 2; @@ -642,7 +642,7 @@ int config_parse_exec( continue; } - r = unquote_first_word_and_warn(&p, &word, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue); + r = extract_first_word_and_warn(&p, &word, WHITESPACE, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue); if (r == 0) break; else if (r < 0) diff --git a/src/core/service.c b/src/core/service.c index b790ec98be..7bd8cb8b91 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -42,7 +42,6 @@ #include "utf8.h" #include "env-util.h" #include "fileio.h" -#include "bus-error.h" #include "bus-util.h" #include "bus-kernel.h" #include "formats-util.h" diff --git a/src/core/socket.c b/src/core/socket.c index a387057473..c78e8ad01b 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -43,7 +43,6 @@ #include "def.h" #include "smack-util.h" #include "bus-util.h" -#include "bus-error.h" #include "selinux-util.h" #include "dbus-socket.h" #include "unit.h" diff --git a/src/core/timer.c b/src/core/timer.c index 7f4a2eb716..7027f83dfd 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -27,7 +27,6 @@ #include "dbus-timer.h" #include "special.h" #include "bus-util.h" -#include "bus-error.h" static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = { [TIMER_DEAD] = UNIT_INACTIVE, @@ -57,10 +56,7 @@ void timer_free_values(Timer *t) { while ((v = t->values)) { LIST_REMOVE(value, t->values, v); - - if (v->calendar_spec) - calendar_spec_free(v->calendar_spec); - + calendar_spec_free(v->calendar_spec); free(v); } } diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c index 4980fccc31..25c8e209fd 100644 --- a/src/dbus1-generator/dbus1-generator.c +++ b/src/dbus1-generator/dbus1-generator.c @@ -84,7 +84,8 @@ static int create_dbus_files( fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type); if (streq(type, "system")) - fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_ADDRESS "\n"); + fprintf(f, "Environment=DBUS_STARTER_ADDRESS=%s\n", + is_kdbus_available() ? KERNEL_SYSTEM_BUS_ADDRESS : UNIX_SYSTEM_BUS_ADDRESS); else if (streq(type, "session")) { char *run; @@ -94,8 +95,10 @@ static int create_dbus_files( return -EINVAL; } - fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT "\n", - getuid(), run); + if (is_kdbus_available()) + fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_ADDRESS_FMT "\n", getuid()); + else + fprintf(f, "Environment=DBUS_STARTER_ADDRESS="UNIX_USER_BUS_ADDRESS_FMT "\n", run); } } diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 9d889c17d8..0a34f86be7 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -240,82 +240,6 @@ static int add_mount( return 0; } -static int add_automount( - const char *id, - const char *what, - const char *where, - const char *fstype, - bool rw, - const char *options, - const char *description, - usec_t timeout) { - - _cleanup_free_ char *unit = NULL, *lnk = NULL; - _cleanup_free_ char *opt, *p = NULL; - _cleanup_fclose_ FILE *f = NULL; - int r; - - assert(id); - assert(where); - assert(description); - - if (options) - opt = strjoin(options, ",noauto", NULL); - else - opt = strdup("noauto"); - if (!opt) - return log_oom(); - - r = add_mount(id, - what, - where, - fstype, - rw, - opt, - description, - NULL); - if (r < 0) - return r; - - r = unit_name_from_path(where, ".automount", &unit); - if (r < 0) - return log_error_errno(r, "Failed to generate unit name: %m"); - - p = strjoin(arg_dest, "/", unit, NULL); - if (!p) - return log_oom(); - - f = fopen(p, "wxe"); - if (!f) - return log_error_errno(errno, "Failed to create unit file %s: %m", unit); - - fprintf(f, - "# Automatically generated by systemd-gpt-auto-generator\n\n" - "[Unit]\n" - "Description=%s\n" - "Documentation=man:systemd-gpt-auto-generator(8)\n" - "[Automount]\n" - "Where=%s\n" - "TimeoutIdleSec=%lld\n", - description, - where, - (unsigned long long)timeout / USEC_PER_SEC); - - r = fflush_and_check(f); - if (r < 0) - return log_error_errno(r, "Failed to write unit file %s: %m", p); - - lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/", unit, NULL); - if (!lnk) - return log_oom(); - mkdir_parents_label(lnk, 0755); - - if (symlink(p, lnk) < 0) - return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); - - return 0; -} - static bool path_is_busy(const char *where) { int r; @@ -441,8 +365,84 @@ static int add_swap(const char *path) { return 0; } -static int add_boot(const char *what) { #ifdef ENABLE_EFI +static int add_automount( + const char *id, + const char *what, + const char *where, + const char *fstype, + bool rw, + const char *options, + const char *description, + usec_t timeout) { + + _cleanup_free_ char *unit = NULL, *lnk = NULL; + _cleanup_free_ char *opt, *p = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(id); + assert(where); + assert(description); + + if (options) + opt = strjoin(options, ",noauto", NULL); + else + opt = strdup("noauto"); + if (!opt) + return log_oom(); + + r = add_mount(id, + what, + where, + fstype, + rw, + opt, + description, + NULL); + if (r < 0) + return r; + + r = unit_name_from_path(where, ".automount", &unit); + if (r < 0) + return log_error_errno(r, "Failed to generate unit name: %m"); + + p = strjoin(arg_dest, "/", unit, NULL); + if (!p) + return log_oom(); + + f = fopen(p, "wxe"); + if (!f) + return log_error_errno(errno, "Failed to create unit file %s: %m", unit); + + fprintf(f, + "# Automatically generated by systemd-gpt-auto-generator\n\n" + "[Unit]\n" + "Description=%s\n" + "Documentation=man:systemd-gpt-auto-generator(8)\n" + "[Automount]\n" + "Where=%s\n" + "TimeoutIdleSec=%lld\n", + description, + where, + (unsigned long long)timeout / USEC_PER_SEC); + + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write unit file %s: %m", p); + + lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/", unit, NULL); + if (!lnk) + return log_oom(); + mkdir_parents_label(lnk, 0755); + + if (symlink(p, lnk) < 0) + return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); + + return 0; +} + +static int add_boot(const char *what) { _cleanup_blkid_free_probe_ blkid_probe b = NULL; const char *fstype = NULL, *uuid = NULL; sd_id128_t id, type_id; @@ -532,10 +532,12 @@ static int add_boot(const char *what) { 120 * USEC_PER_SEC); return r; +} #else +static int add_boot(const char *what) { return 0; -#endif } +#endif static int enumerate_partitions(dev_t devnum) { @@ -616,9 +618,12 @@ static int enumerate_partitions(dev_t devnum) { errno = 0; r = blkid_do_safeprobe(b); - if (r == -2 || r == 1) /* no result or uncertain */ + if (r == 1) + return 0; /* no results */ + else if (r == -2) { + log_warning("%s: probe gave ambiguous results, ignoring", node); return 0; - else if (r != 0) + } else if (r != 0) return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node); errno = 0; @@ -666,7 +671,6 @@ static int enumerate_partitions(dev_t devnum) { blkid_partition pp; dev_t qn; int nr; - unsigned long long flags; q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); if (!q) @@ -690,13 +694,6 @@ static int enumerate_partitions(dev_t devnum) { if (!pp) continue; - flags = blkid_partition_get_flags(pp); - - /* Ignore partitions that are not marked for automatic - * mounting on discovery */ - if (flags & GPT_FLAG_NO_AUTO) - continue; - nr = blkid_partition_get_partno(pp); if (nr < 0) continue; @@ -709,6 +706,11 @@ static int enumerate_partitions(dev_t devnum) { continue; if (sd_id128_equal(type_id, GPT_SWAP)) { + unsigned long long flags; + + flags = blkid_partition_get_flags(pp); + if (flags & GPT_FLAG_NO_AUTO) + continue; if (flags & GPT_FLAG_READ_ONLY) { log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode); @@ -732,6 +734,11 @@ static int enumerate_partitions(dev_t devnum) { return log_oom(); } else if (sd_id128_equal(type_id, GPT_HOME)) { + unsigned long long flags; + + flags = blkid_partition_get_flags(pp); + if (flags & GPT_FLAG_NO_AUTO) + continue; /* We only care for the first /home partition */ if (home && nr >= home_nr) @@ -745,6 +752,11 @@ static int enumerate_partitions(dev_t devnum) { return log_oom(); } else if (sd_id128_equal(type_id, GPT_SRV)) { + unsigned long long flags; + + flags = blkid_partition_get_flags(pp); + if (flags & GPT_FLAG_NO_AUTO) + continue; /* We only care for the first /srv partition */ if (srv && nr >= srv_nr) diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 1eb07a1681..ebdd9edfc3 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -103,8 +103,7 @@ static void request_meta_free( if (!m) return; - if (m->journal) - sd_journal_close(m->journal); + sd_journal_close(m->journal); if (m->tmp) fclose(m->tmp); diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index e3bd76051b..cdcda1cb52 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -148,7 +148,7 @@ static int spawn_getter(const char *getter, const char *url) { _cleanup_strv_free_ char **words = NULL; assert(getter); - r = strv_split_quoted(&words, getter, 0); + r = strv_split_extract(&words, getter, WHITESPACE, EXTRACT_QUOTES); if (r < 0) return log_error_errno(r, "Failed to split getter option: %m"); diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index f7815b2796..4f94799ce7 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -169,7 +169,7 @@ void journal_file_close(JournalFile *f) { #ifdef HAVE_GCRYPT if (f->fss_file) munmap(f->fss_file, PAGE_ALIGN(f->fss_file_size)); - else if (f->fsprg_state) + else free(f->fsprg_state); free(f->fsprg_seed); diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index fe83edd2b3..ce2dd9da26 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -2066,8 +2066,12 @@ int main(int argc, char *argv[]) { goto finish; } if (r == 0) { - printf("-- No entries --\n"); - goto finish; + if (arg_follow) + need_seek = true; + else { + printf("-- No entries --\n"); + goto finish; + } } if (!arg_follow) diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 28b1472ac8..fa2e9b9825 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1689,6 +1689,5 @@ void server_done(Server *s) { if (s->mmap) mmap_cache_unref(s->mmap); - if (s->udev) - udev_unref(s->udev); + udev_unref(s->udev); } diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index 773c264cf0..92b12f2ae8 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -32,7 +32,6 @@ #include "bus-message.h" #include "bus-control.h" #include "bus-bloom.h" -#include "bus-util.h" #include "capability.h" _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) { diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c index dfd82e746d..79747e058b 100644 --- a/src/libsystemd/sd-bus/bus-convenience.c +++ b/src/libsystemd/sd-bus/bus-convenience.c @@ -22,7 +22,6 @@ #include "bus-internal.h" #include "bus-message.h" #include "bus-signature.h" -#include "bus-util.h" #include "bus-type.h" _public_ int sd_bus_emit_signal( @@ -108,15 +107,17 @@ _public_ int sd_bus_call_method( _cleanup_bus_message_unref_ sd_bus_message *m = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member); if (r < 0) - return r; + goto fail; if (!isempty(types)) { va_list ap; @@ -125,10 +126,13 @@ _public_ int sd_bus_call_method( r = bus_message_append_ap(m, types, ap); va_end(ap); if (r < 0) - return r; + goto fail; } return sd_bus_call(bus, m, 0, error, reply); + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_reply_method_return( @@ -290,15 +294,17 @@ _public_ int sd_bus_get_property( sd_bus_message *rep = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(reply, -EINVAL); - assert_return(signature_is_single(type, false), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(reply, -EINVAL, error); + bus_assert_return(signature_is_single(type, false), -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member); if (r < 0) @@ -307,11 +313,14 @@ _public_ int sd_bus_get_property( r = sd_bus_message_enter_container(rep, 'v', type); if (r < 0) { sd_bus_message_unref(rep); - return r; + goto fail; } *reply = rep; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_property_trivial( @@ -326,15 +335,17 @@ _public_ int sd_bus_get_property_trivial( _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(bus_type_is_trivial(type), -EINVAL); - assert_return(ptr, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(bus_type_is_trivial(type), -EINVAL, error); + bus_assert_return(ptr, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); if (r < 0) @@ -342,13 +353,16 @@ _public_ int sd_bus_get_property_trivial( r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type)); if (r < 0) - return r; + goto fail; r = sd_bus_message_read_basic(reply, type, ptr); if (r < 0) - return r; + goto fail; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_property_string( @@ -365,14 +379,16 @@ _public_ int sd_bus_get_property_string( char *n; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(ret, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(ret, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); if (r < 0) @@ -380,18 +396,23 @@ _public_ int sd_bus_get_property_string( r = sd_bus_message_enter_container(reply, 'v', "s"); if (r < 0) - return r; + goto fail; r = sd_bus_message_read_basic(reply, 's', &s); if (r < 0) - return r; + goto fail; n = strdup(s); - if (!n) - return -ENOMEM; + if (!n) { + r = -ENOMEM; + goto fail; + } *ret = n; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_property_strv( @@ -406,14 +427,16 @@ _public_ int sd_bus_get_property_strv( _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(ret, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(ret, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); if (r < 0) @@ -421,13 +444,16 @@ _public_ int sd_bus_get_property_strv( r = sd_bus_message_enter_container(reply, 'v', NULL); if (r < 0) - return r; + goto fail; r = sd_bus_message_read_strv(reply, ret); if (r < 0) - return r; + goto fail; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_set_property( @@ -443,38 +469,43 @@ _public_ int sd_bus_set_property( va_list ap; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(signature_is_single(type, false), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(signature_is_single(type, false), -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set"); if (r < 0) - return r; + goto fail; r = sd_bus_message_append(m, "ss", strempty(interface), member); if (r < 0) - return r; + goto fail; r = sd_bus_message_open_container(m, 'v', type); if (r < 0) - return r; + goto fail; va_start(ap, type); r = bus_message_append_ap(m, type, ap); va_end(ap); if (r < 0) - return r; + goto fail; r = sd_bus_message_close_container(m); if (r < 0) - return r; + goto fail; return sd_bus_call(bus, m, 0, error, NULL); + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) { diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index 1c365b7fcd..130fbf7a23 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -31,10 +31,10 @@ #include "fileio.h" #include "audit.h" #include "bus-message.h" -#include "bus-util.h" #include "strv.h" #include "bus-creds.h" #include "bus-label.h" +#include "bus-internal.h" enum { CAP_OFFSET_INHERITABLE = 0, diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c index fea796cd30..f4ab57f5bc 100644 --- a/src/libsystemd/sd-bus/bus-internal.c +++ b/src/libsystemd/sd-bus/bus-internal.c @@ -371,3 +371,45 @@ int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error) { return 1; } + +bool is_kdbus_wanted(void) { + _cleanup_free_ char *value = NULL; +#ifdef ENABLE_KDBUS + const bool configured = true; +#else + const bool configured = false; +#endif + int r; + + if (get_proc_cmdline_key("kdbus", NULL) > 0) + return true; + + r = get_proc_cmdline_key("kdbus=", &value); + if (r <= 0) + return configured; + + return parse_boolean(value) == 1; +} + +bool is_kdbus_available(void) { + static int cached = -1; + _cleanup_close_ int fd = -1; + struct kdbus_cmd cmd = { .size = sizeof(cmd), .flags = KDBUS_FLAG_NEGOTIATE }; + + if (cached >= 0) + return (bool) cached; + + if (!is_kdbus_wanted()) { + cached = false; + return false; + } + + fd = open("/sys/fs/kdbus/control", O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); + if (fd < 0) { + cached = false; + return false; + } + + cached = ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0; + return cached; +} diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index c3e20ee1bf..9b68fdd642 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -37,6 +37,29 @@ #include "bus-kernel.h" #include "kdbus.h" +typedef enum BusTransport { + BUS_TRANSPORT_LOCAL, + BUS_TRANSPORT_REMOTE, + BUS_TRANSPORT_MACHINE, + _BUS_TRANSPORT_MAX, + _BUS_TRANSPORT_INVALID = -1 +} BusTransport; + +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_flush_close_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_slot*, sd_bus_slot_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_track*, sd_bus_track_unref); + +#define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp) +#define _cleanup_bus_flush_close_unref_ _cleanup_(sd_bus_flush_close_unrefp) +#define _cleanup_bus_slot_unref_ _cleanup_(sd_bus_slot_unrefp) +#define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp) +#define _cleanup_bus_creds_unref_ _cleanup_(sd_bus_creds_unrefp) +#define _cleanup_bus_track_unref_ _cleanup_(sd_bus_slot_unrefp) +#define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free) + struct reply_callback { sd_bus_message_handler_t callback; usec_t timeout; @@ -393,3 +416,12 @@ int bus_remove_match_by_string(sd_bus *bus, const char *match, sd_bus_message_ha int bus_get_root_path(sd_bus *bus); int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error); + +bool is_kdbus_wanted(void); +bool is_kdbus_available(void); + +#define bus_assert_return(expr, r, error) \ + do { \ + if (!assert_log(expr)) \ + return sd_bus_error_set_errno(error, r); \ + } while (false) diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index 22a43c4542..21f3700128 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -45,7 +45,6 @@ #include "bus-message.h" #include "bus-kernel.h" #include "bus-bloom.h" -#include "bus-util.h" #include "bus-label.h" #define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t)) diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index 18c36ce243..f3b49c0c90 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -22,7 +22,6 @@ #include "bus-internal.h" #include "bus-message.h" #include "bus-match.h" -#include "bus-util.h" #include "strv.h" /* Example: diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 94427ed664..a212f0b398 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -35,7 +35,6 @@ #include "bus-type.h" #include "bus-signature.h" #include "bus-gvariant.h" -#include "bus-util.h" static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored); @@ -144,11 +143,7 @@ static void message_free(sd_bus_message *m) { if (m->iovec != m->iovec_fixed) free(m->iovec); - if (m->destination_ptr) { - free(m->destination_ptr); - m->destination_ptr = NULL; - } - + m->destination_ptr = mfree(m->destination_ptr); message_reset_containers(m); free(m->root_container.signature); free(m->root_container.offsets); @@ -2687,7 +2682,7 @@ _public_ int sd_bus_message_append_array_memfd( int r; assert_return(m, -EINVAL); - assert_return(memfd >= 0, -EINVAL); + assert_return(memfd >= 0, -EBADF); assert_return(bus_type_is_trivial(type), -EINVAL); assert_return(size > 0, -EINVAL); assert_return(!m->sealed, -EPERM); @@ -2763,7 +2758,7 @@ _public_ int sd_bus_message_append_string_memfd( int r; assert_return(m, -EINVAL); - assert_return(memfd >= 0, -EINVAL); + assert_return(memfd >= 0, -EBADF); assert_return(size > 0, -EINVAL); assert_return(!m->sealed, -EPERM); assert_return(!m->poisoned, -ESTALE); diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index c25293e5e9..17ce297510 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -26,7 +26,6 @@ #include "bus-type.h" #include "bus-signature.h" #include "bus-introspect.h" -#include "bus-util.h" #include "bus-slot.h" #include "bus-objects.h" diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c index e43891be25..7803e39c3d 100644 --- a/src/libsystemd/sd-bus/bus-track.c +++ b/src/libsystemd/sd-bus/bus-track.c @@ -20,7 +20,6 @@ ***/ #include "sd-bus.h" -#include "bus-util.h" #include "bus-internal.h" #include "bus-track.h" diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index a1f0f30d6c..181621ffc7 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -30,7 +30,6 @@ #include "set.h" #include "sd-bus.h" -#include "bus-internal.h" #include "bus-util.h" #include "bus-dump.h" #include "bus-signature.h" diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 0f075907d5..db4f21e9ff 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -43,7 +43,6 @@ #include "bus-kernel.h" #include "bus-control.h" #include "bus-objects.h" -#include "bus-util.h" #include "bus-container.h" #include "bus-protocol.h" #include "bus-track.h" @@ -214,8 +213,8 @@ _public_ int sd_bus_set_address(sd_bus *bus, const char *address) { _public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) { assert_return(bus, -EINVAL); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(input_fd >= 0, -EINVAL); - assert_return(output_fd >= 0, -EINVAL); + assert_return(input_fd >= 0, -EBADF); + assert_return(output_fd >= 0, -EBADF); assert_return(!bus_pid_changed(bus), -ECHILD); bus->input_fd = input_fd; @@ -1173,7 +1172,10 @@ int bus_set_address_system(sd_bus *b) { if (e) return sd_bus_set_address(b, e); - return sd_bus_set_address(b, DEFAULT_SYSTEM_BUS_ADDRESS); + if (is_kdbus_available()) + return sd_bus_set_address(b, KERNEL_SYSTEM_BUS_ADDRESS); + + return sd_bus_set_address(b, UNIX_SYSTEM_BUS_ADDRESS); } _public_ int sd_bus_open_system(sd_bus **ret) { @@ -1221,16 +1223,17 @@ int bus_set_address_user(sd_bus *b) { return sd_bus_set_address(b, e); e = secure_getenv("XDG_RUNTIME_DIR"); - if (e) { + if (is_kdbus_available()) + (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()); + else if (e) { _cleanup_free_ char *ee = NULL; ee = bus_address_escape(e); if (!ee) return -ENOMEM; - (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, getuid(), ee); - } else - (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()); + (void) asprintf(&b->address, UNIX_USER_BUS_ADDRESS_FMT, ee); + } if (!b->address) return -ENOMEM; @@ -1948,37 +1951,39 @@ _public_ int sd_bus_call( unsigned i; int r; - assert_return(m, -EINVAL); - assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); - assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL); - assert_return(!bus_error_is_dirty(error), -EINVAL); + bus_assert_return(m, -EINVAL, error); + bus_assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL, error); + bus_assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL, error); + bus_assert_return(!bus_error_is_dirty(error), -EINVAL, error); if (!bus) bus = m->bus; - assert_return(!bus_pid_changed(bus), -ECHILD); - assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); + bus_assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = bus_ensure_running(bus); if (r < 0) - return r; + goto fail; i = bus->rqueue_size; r = bus_seal_message(bus, m, usec); if (r < 0) - return r; + goto fail; r = bus_remarshal_message(bus, &m); if (r < 0) - return r; + goto fail; r = bus_send_internal(bus, m, &cookie, true); if (r < 0) - return r; + goto fail; timeout = calc_elapse(m->timeout); @@ -2009,14 +2014,17 @@ _public_ int sd_bus_call( } r = sd_bus_error_setf(error, SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptors which I couldn't accept. Sorry."); + sd_bus_message_unref(incoming); + return r; - } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) + } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) { r = sd_bus_error_copy(error, &incoming->error); - else + sd_bus_message_unref(incoming); + return r; + } else { r = -EIO; - - sd_bus_message_unref(incoming); - return r; + goto fail; + } } else if (BUS_MESSAGE_COOKIE(incoming) == cookie && bus->unique_name && @@ -2032,7 +2040,8 @@ _public_ int sd_bus_call( * immediately. */ sd_bus_message_unref(incoming); - return -ELOOP; + r = -ELOOP; + goto fail; } /* Try to read more, right-away */ @@ -2043,10 +2052,10 @@ _public_ int sd_bus_call( if (r < 0) { if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { bus_enter_closing(bus); - return -ECONNRESET; + r = -ECONNRESET; } - return r; + goto fail; } if (r > 0) continue; @@ -2055,8 +2064,10 @@ _public_ int sd_bus_call( usec_t n; n = now(CLOCK_MONOTONIC); - if (n >= timeout) - return -ETIMEDOUT; + if (n >= timeout) { + r = -ETIMEDOUT; + goto fail; + } left = timeout - n; } else @@ -2064,20 +2075,25 @@ _public_ int sd_bus_call( r = bus_poll(bus, true, left); if (r < 0) - return r; - if (r == 0) - return -ETIMEDOUT; + goto fail; + if (r == 0) { + r = -ETIMEDOUT; + goto fail; + } r = dispatch_wqueue(bus); if (r < 0) { if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { bus_enter_closing(bus); - return -ECONNRESET; + r = -ECONNRESET; } - return r; + goto fail; } } + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_fd(sd_bus *bus) { diff --git a/src/libsystemd/sd-bus/test-bus-benchmark.c b/src/libsystemd/sd-bus/test-bus-benchmark.c index d14110aa04..d3bf6da850 100644 --- a/src/libsystemd/sd-bus/test-bus-benchmark.c +++ b/src/libsystemd/sd-bus/test-bus-benchmark.c @@ -28,7 +28,6 @@ #include "sd-bus.h" #include "bus-kernel.h" #include "bus-internal.h" -#include "bus-util.h" #define MAX_SIZE (2*1024*1024) diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c index 754335b5e7..a0aecc1f55 100644 --- a/src/libsystemd/sd-bus/test-bus-chat.c +++ b/src/libsystemd/sd-bus/test-bus-chat.c @@ -33,7 +33,6 @@ #include "bus-error.h" #include "bus-match.h" #include "bus-internal.h" -#include "bus-util.h" static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m))); @@ -119,9 +118,7 @@ static int server_init(sd_bus **_bus) { return 0; fail: - if (bus) - sd_bus_unref(bus); - + sd_bus_unref(bus); return r; } diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c index f586880593..b483d47468 100644 --- a/src/libsystemd/sd-bus/test-bus-cleanup.c +++ b/src/libsystemd/sd-bus/test-bus-cleanup.c @@ -22,7 +22,6 @@ #include <stdio.h> #include "sd-bus.h" -#include "bus-util.h" #include "bus-internal.h" #include "bus-message.h" #include "refcnt.h" diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c index 5753c04b0e..f2cfbc706f 100644 --- a/src/libsystemd/sd-bus/test-bus-error.c +++ b/src/libsystemd/sd-bus/test-bus-error.c @@ -20,7 +20,6 @@ ***/ #include "sd-bus.h" -#include "bus-error.h" #include "bus-util.h" #include "errno-list.h" #include "bus-common-errors.h" diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c index b078bdc5f6..414d4e9a58 100644 --- a/src/libsystemd/sd-bus/test-bus-gvariant.c +++ b/src/libsystemd/sd-bus/test-bus-gvariant.c @@ -27,7 +27,6 @@ #include "macro.h" #include "sd-bus.h" #include "bus-gvariant.h" -#include "bus-util.h" #include "bus-internal.h" #include "bus-message.h" #include "bus-dump.h" diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c index 6506eaab2e..6284153a58 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel.c +++ b/src/libsystemd/sd-bus/test-bus-kernel.c @@ -25,8 +25,8 @@ #include "log.h" #include "sd-bus.h" -#include "bus-kernel.h" #include "bus-util.h" +#include "bus-kernel.h" #include "bus-dump.h" int main(int argc, char *argv[]) { diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c index 83cb5c62c2..f659ba3124 100644 --- a/src/libsystemd/sd-bus/test-bus-match.c +++ b/src/libsystemd/sd-bus/test-bus-match.c @@ -24,7 +24,6 @@ #include "bus-match.h" #include "bus-message.h" -#include "bus-util.h" #include "bus-slot.h" static bool mask[32]; diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c index 359984c7f3..1457759d0e 100644 --- a/src/libsystemd/sd-bus/test-bus-objects.c +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -30,7 +30,6 @@ #include "sd-bus.h" #include "bus-internal.h" #include "bus-message.h" -#include "bus-util.h" #include "bus-dump.h" struct context { diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c index 080d8eddb7..604df098cc 100644 --- a/src/libsystemd/sd-bus/test-bus-server.c +++ b/src/libsystemd/sd-bus/test-bus-server.c @@ -28,7 +28,6 @@ #include "sd-bus.h" #include "bus-internal.h" -#include "bus-util.h" struct context { int fds[2]; diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 82ac72c72a..d230a48daf 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -90,7 +90,7 @@ finish: _public_ int sd_is_fifo(int fd, const char *path) { struct stat st_fd; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); if (fstat(fd, &st_fd) < 0) return -errno; @@ -120,7 +120,7 @@ _public_ int sd_is_fifo(int fd, const char *path) { _public_ int sd_is_special(int fd, const char *path) { struct stat st_fd; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); if (fstat(fd, &st_fd) < 0) return -errno; @@ -155,7 +155,7 @@ _public_ int sd_is_special(int fd, const char *path) { static int sd_is_socket_internal(int fd, int type, int listening) { struct stat st_fd; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(type >= 0, -EINVAL); if (fstat(fd, &st_fd) < 0) @@ -198,7 +198,7 @@ static int sd_is_socket_internal(int fd, int type, int listening) { _public_ int sd_is_socket(int fd, int family, int type, int listening) { int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(family >= 0, -EINVAL); r = sd_is_socket_internal(fd, type, listening); @@ -226,7 +226,7 @@ _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint socklen_t l = sizeof(sockaddr); int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(IN_SET(family, 0, AF_INET, AF_INET6), -EINVAL); r = sd_is_socket_internal(fd, type, listening); @@ -269,7 +269,7 @@ _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path socklen_t l = sizeof(sockaddr); int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); r = sd_is_socket_internal(fd, type, listening); if (r <= 0) @@ -310,7 +310,7 @@ _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path _public_ int sd_is_mq(int fd, const char *path) { struct mq_attr attr; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); if (mq_getattr(fd, &attr) < 0) return -errno; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 754fb7614e..0e33ced342 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -816,7 +816,7 @@ _public_ int sd_event_add_io( int r; assert_return(e, -EINVAL); - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL); assert_return(callback, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); @@ -1311,7 +1311,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { int r; assert_return(s, -EINVAL); - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(s->type == SOURCE_IO, -EDOM); assert_return(!event_pid_changed(s->event), -ECHILD); diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index e3885ecba6..9bbf8974dd 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -94,7 +94,7 @@ _public_ int sd_peer_get_session(int fd, char **session) { struct ucred ucred = {}; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(session, -EINVAL); r = getpeercred(fd, &ucred); @@ -108,7 +108,7 @@ _public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(uid, -EINVAL); r = getpeercred(fd, &ucred); @@ -122,7 +122,7 @@ _public_ int sd_peer_get_unit(int fd, char **unit) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(unit, -EINVAL); r = getpeercred(fd, &ucred); @@ -136,7 +136,7 @@ _public_ int sd_peer_get_user_unit(int fd, char **unit) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(unit, -EINVAL); r = getpeercred(fd, &ucred); @@ -150,7 +150,7 @@ _public_ int sd_peer_get_machine_name(int fd, char **machine) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(machine, -EINVAL); r = getpeercred(fd, &ucred); @@ -164,7 +164,7 @@ _public_ int sd_peer_get_slice(int fd, char **slice) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(slice, -EINVAL); r = getpeercred(fd, &ucred); @@ -178,7 +178,7 @@ _public_ int sd_peer_get_user_slice(int fd, char **slice) { struct ucred ucred; int r; - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); assert_return(slice, -EINVAL); r = getpeercred(fd, &ucred); diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 3ba62a6be9..aee2ced2d9 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -501,7 +501,7 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t assert_return(m, -EINVAL); assert_return(m->sealed, -EPERM); assert_return(data, -EINVAL); - assert(m->n_containers <= RTNL_CONTAINER_DEPTH); + assert(m->n_containers < RTNL_CONTAINER_DEPTH); assert(m->containers[m->n_containers].attributes); assert(type < m->containers[m->n_containers].n_attributes); diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index c413b1c266..d248869c8d 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -106,7 +106,7 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) { int r; assert_return(ret, -EINVAL); - assert_return(fd >= 0, -EINVAL); + assert_return(fd >= 0, -EBADF); r = sd_netlink_new(&rtnl); if (r < 0) diff --git a/src/locale/localed.c b/src/locale/localed.c index cb4052fdd5..e9489f04c2 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -222,7 +222,7 @@ static int x11_read_data(Context *c) { if (in_section && first_word(l, "Option")) { _cleanup_strv_free_ char **a = NULL; - r = strv_split_quoted(&a, l, 0); + r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); if (r < 0) return r; @@ -245,7 +245,7 @@ static int x11_read_data(Context *c) { } else if (!in_section && first_word(l, "Section")) { _cleanup_strv_free_ char **a = NULL; - r = strv_split_quoted(&a, l, 0); + r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES); if (r < 0) return -ENOMEM; @@ -544,7 +544,7 @@ static int read_next_mapping(const char* filename, if (l[0] == 0 || l[0] == '#') continue; - r = strv_split_quoted(&b, l, 0); + r = strv_split_extract(&b, l, WHITESPACE, EXTRACT_QUOTES); if (r < 0) return r; diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index a261e6a719..cfae186edd 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -109,20 +109,24 @@ int inhibitor_save(Inhibitor *i) { _cleanup_free_ char *cc = NULL; cc = cescape(i->who); - if (!cc) + if (!cc) { r = -ENOMEM; - else - fprintf(f, "WHO=%s\n", cc); + goto fail; + } + + fprintf(f, "WHO=%s\n", cc); } if (i->why) { _cleanup_free_ char *cc = NULL; cc = cescape(i->why); - if (!cc) + if (!cc) { r = -ENOMEM; - else - fprintf(f, "WHY=%s\n", cc); + goto fail; + } + + fprintf(f, "WHY=%s\n", cc); } if (i->fifo_path) diff --git a/src/login/logind.c b/src/login/logind.c index cf71c0ec5a..8ac2aceb9b 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -153,17 +153,12 @@ static void manager_free(Manager *m) { safe_close(m->console_active_fd); - if (m->udev_seat_monitor) - udev_monitor_unref(m->udev_seat_monitor); - if (m->udev_device_monitor) - udev_monitor_unref(m->udev_device_monitor); - if (m->udev_vcsa_monitor) - udev_monitor_unref(m->udev_vcsa_monitor); - if (m->udev_button_monitor) - udev_monitor_unref(m->udev_button_monitor); - - if (m->udev) - udev_unref(m->udev); + udev_monitor_unref(m->udev_seat_monitor); + udev_monitor_unref(m->udev_device_monitor); + udev_monitor_unref(m->udev_vcsa_monitor); + udev_monitor_unref(m->udev_button_monitor); + + udev_unref(m->udev); if (m->unlink_nologin) (void) unlink("/run/nologin"); @@ -1170,8 +1165,7 @@ finish: "STOPPING=1\n" "STATUS=Shutting down..."); - if (m) - manager_free(m); + manager_free(m); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/machine/machined.c b/src/machine/machined.c index 1eeeaf17a5..c8ad157326 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -355,8 +355,7 @@ int main(int argc, char *argv[]) { log_debug("systemd-machined stopped as pid "PID_FMT, getpid()); finish: - if (m) - manager_free(m); + manager_free(m); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 0e74f20f1a..347260013a 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -655,17 +655,22 @@ static int parse_argv(int argc, char *argv[]) { case ARG_BIND: case ARG_BIND_RO: { + const char *current = optarg; _cleanup_free_ char *source = NULL, *destination = NULL; CustomMount *m; - char *e; + _cleanup_strv_free_ char **strv = NULL; - e = strchr(optarg, ':'); - if (e) { - source = strndup(optarg, e - optarg); - destination = strdup(e + 1); - } else { - source = strdup(optarg); - destination = strdup(optarg); + r = extract_many_words(¤t, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, NULL); + switch (r) { + case 1: + destination = strdup(source); + case 2: + break; + case -ENOMEM: + return log_oom(); + default: + log_error("Invalid bind mount specification: %s", optarg); + return -EINVAL; } if (!source || !destination) @@ -690,18 +695,21 @@ static int parse_argv(int argc, char *argv[]) { } case ARG_TMPFS: { + const char *current = optarg; _cleanup_free_ char *path = NULL, *opts = NULL; CustomMount *m; - char *e; - e = strchr(optarg, ':'); - if (e) { - path = strndup(optarg, e - optarg); - opts = strdup(e + 1); - } else { - path = strdup(optarg); - opts = strdup("mode=0755"); + r = extract_first_word(¤t, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r == -ENOMEM) + return log_oom(); + else if (r < 0) { + log_error("Invalid tmpfs specification: %s", optarg); + return r; } + if (r) + opts = strdup(current); + else + opts = strdup("mode=0755"); if (!path || !opts) return log_oom(); @@ -731,9 +739,13 @@ static int parse_argv(int argc, char *argv[]) { unsigned n = 0; char **i; - lower = strv_split(optarg, ":"); - if (!lower) + r = strv_split_extract(&lower, optarg, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r == -ENOMEM) return log_oom(); + else if (r < 0) { + log_error("Invalid overlay specification: %s", optarg); + return r; + } STRV_FOREACH(i, lower) { if (!path_is_absolute(*i)) { @@ -1227,6 +1239,21 @@ static int mount_tmpfs(const char *dest, CustomMount *m) { return 0; } +static char *joined_and_escaped_lower_dirs(char * const *lower) { + _cleanup_strv_free_ char **sv = NULL; + + sv = strv_copy(lower); + if (!sv) + return NULL; + + strv_reverse(sv); + + if (!strv_shell_escape(sv, ",:")) + return NULL; + + return strv_join(sv, ":"); +} + static int mount_overlay(const char *dest, CustomMount *m) { _cleanup_free_ char *lower = NULL; const char *where, *options; @@ -1243,19 +1270,32 @@ static int mount_overlay(const char *dest, CustomMount *m) { (void) mkdir_p_label(m->source, 0755); - strv_reverse(m->lower); - lower = strv_join(m->lower, ":"); - strv_reverse(m->lower); + lower = joined_and_escaped_lower_dirs(m->lower); if (!lower) return log_oom(); - if (m->read_only) - options = strjoina("lowerdir=", m->source, ":", lower); - else { + if (m->read_only) { + _cleanup_free_ char *escaped_source = NULL; + + escaped_source = shell_escape(m->source, ",:"); + if (!escaped_source) + return log_oom(); + + options = strjoina("lowerdir=", escaped_source, ":", lower); + } else { + _cleanup_free_ char *escaped_source = NULL, *escaped_work_dir = NULL; + assert(m->work_dir); (void) mkdir_label(m->work_dir, 0700); - options = strjoina("lowerdir=", lower, ",upperdir=", m->source, ",workdir=", m->work_dir); + escaped_source = shell_escape(m->source, ",:"); + if (!escaped_source) + return log_oom(); + escaped_work_dir = shell_escape(m->work_dir, ",:"); + if (!escaped_work_dir) + return log_oom(); + + options = strjoina("lowerdir=", lower, ",upperdir=", escaped_source, ",workdir=", escaped_work_dir); } if (mount("overlay", where, "overlay", m->read_only ? MS_RDONLY : 0, options) < 0) diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index ab96cb231e..69069cc75d 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -39,7 +39,6 @@ #define LOCALADDRESS_IPV4 (htonl(0x7F000002)) #define LOCALADDRESS_IPV6 &in6addr_loopback -#define LOOPBACK_INTERFACE "lo" NSS_GETHOSTBYNAME_PROTOTYPES(myhostname); NSS_GETHOSTBYADDR_PROTOTYPES(myhostname); @@ -117,7 +116,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( } /* If this call fails we fill in 0 as scope. Which is fine */ - lo_ifi = n_addresses <= 0 ? if_nametoindex(LOOPBACK_INTERFACE) : 0; + lo_ifi = n_addresses <= 0 ? LOOPBACK_IFINDEX : 0; l = strlen(canonical); ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 2); diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c index 0edba415b6..7525d7c32f 100644 --- a/src/resolve-host/resolve-host.c +++ b/src/resolve-host/resolve-host.c @@ -41,7 +41,8 @@ static uint16_t arg_class = 0; static bool arg_legend = true; static uint64_t arg_flags = 0; -static void print_source(int ifindex, uint64_t flags) { +static void print_source(int ifindex, uint64_t flags, usec_t rtt) { + char rtt_str[FORMAT_TIMESTAMP_MAX]; if (!arg_legend) return; @@ -62,6 +63,10 @@ static void print_source(int ifindex, uint64_t flags) { printf(" interface %s", strna(if_indextoname(ifindex, ifname))); } + assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100)); + + printf(" in %s", rtt_str); + fputc('.', stdout); fputc('\n', stdout); } @@ -74,6 +79,7 @@ static int resolve_host(sd_bus *bus, const char *name) { unsigned c = 0; int r, ifindex; uint64_t flags; + usec_t ts; assert(name); @@ -93,12 +99,16 @@ static int resolve_host(sd_bus *bus, const char *name) { if (r < 0) return bus_log_create_error(r); + ts = now(CLOCK_MONOTONIC); + r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply); if (r < 0) { log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r)); return r; } + ts = now(CLOCK_MONOTONIC) - ts; + r = sd_bus_message_read(reply, "i", &ifindex); if (r < 0) return bus_log_parse_error(r); @@ -182,7 +192,7 @@ static int resolve_host(sd_bus *bus, const char *name) { return -ESRCH; } - print_source(ifindex, flags); + print_source(ifindex, flags, ts); return 0; } @@ -195,6 +205,7 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a uint64_t flags; unsigned c = 0; const char *n; + usec_t ts; int r; assert(bus); @@ -243,12 +254,16 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a if (r < 0) return bus_log_create_error(r); + ts = now(CLOCK_MONOTONIC); + r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply); if (r < 0) { log_error("%s: resolve call failed: %s", pretty, bus_error_message(&error, r)); return r; } + ts = now(CLOCK_MONOTONIC) - ts; + r = sd_bus_message_read(reply, "i", &ifindex); if (r < 0) return bus_log_parse_error(r); @@ -283,7 +298,7 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a return -ESRCH; } - print_source(ifindex, flags); + print_source(ifindex, flags, ts); return 0; } @@ -321,6 +336,7 @@ static int resolve_record(sd_bus *bus, const char *name) { unsigned n = 0; uint64_t flags; int r, ifindex; + usec_t ts; assert(name); @@ -336,21 +352,21 @@ static int resolve_record(sd_bus *bus, const char *name) { if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_set_auto_start(req, false); - if (r < 0) - return bus_log_create_error(r); - assert((uint16_t) arg_type == arg_type); r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, arg_class, arg_type, arg_flags); if (r < 0) return bus_log_create_error(r); + ts = now(CLOCK_MONOTONIC); + r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply); if (r < 0) { log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r)); return r; } + ts = now(CLOCK_MONOTONIC) - ts; + r = sd_bus_message_read(reply, "i", &ifindex); if (r < 0) return bus_log_parse_error(r); @@ -418,7 +434,7 @@ static int resolve_record(sd_bus *bus, const char *name) { return -ESRCH; } - print_source(ifindex, flags); + print_source(ifindex, flags, ts); return 0; } diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 9ffaf4b19f..81ea1cafcb 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -95,14 +95,19 @@ void dns_cache_flush(DnsCache *c) { c->by_expiry = prioq_free(c->by_expiry); } -static void dns_cache_remove(DnsCache *c, DnsResourceKey *key) { +static bool dns_cache_remove(DnsCache *c, DnsResourceKey *key) { DnsCacheItem *i; + bool exist = false; assert(c); assert(key); - while ((i = hashmap_get(c->by_key, key))) + while ((i = hashmap_get(c->by_key, key))) { dns_cache_item_remove_and_free(c, i); + exist = true; + } + + return exist; } static void dns_cache_make_space(DnsCache *c, unsigned add) { @@ -263,6 +268,7 @@ static int dns_cache_put_positive( const union in_addr_union *owner_address) { _cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL; + _cleanup_free_ char *key_str = NULL; DnsCacheItem *existing; int r; @@ -272,7 +278,14 @@ static int dns_cache_put_positive( /* New TTL is 0? Delete the entry... */ if (rr->ttl <= 0) { - dns_cache_remove(c, rr->key); + if (dns_cache_remove(c, rr->key)) { + r = dns_resource_key_to_string(rr->key, &key_str); + if (r < 0) + return r; + + log_debug("Removed zero TTL entry from cache: %s", key_str); + } + return 0; } @@ -311,6 +324,12 @@ static int dns_cache_put_positive( if (r < 0) return r; + r = dns_resource_key_to_string(i->key, &key_str); + if (r < 0) + return r; + + log_debug("Added cache entry for %s", key_str); + i = NULL; return 0; } @@ -325,6 +344,7 @@ static int dns_cache_put_negative( const union in_addr_union *owner_address) { _cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL; + _cleanup_free_ char *key_str = NULL; int r; assert(c); @@ -337,8 +357,15 @@ static int dns_cache_put_negative( return 0; if (key->type == DNS_TYPE_ANY) return 0; - if (soa_ttl <= 0) + if (soa_ttl <= 0) { + r = dns_resource_key_to_string(key, &key_str); + if (r < 0) + return r; + + log_debug("Ignored negative cache entry with zero SOA TTL: %s", key_str); + return 0; + } if (!IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN)) return 0; @@ -364,6 +391,12 @@ static int dns_cache_put_negative( if (r < 0) return r; + r = dns_resource_key_to_string(i->key, &key_str); + if (r < 0) + return r; + + log_debug("Added %s cache entry for %s", i->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", key_str); + i = NULL; return 0; } @@ -468,11 +501,19 @@ int dns_cache_lookup(DnsCache *c, DnsQuestion *q, int *rcode, DnsAnswer **ret) { } for (i = 0; i < q->n_keys; i++) { + _cleanup_free_ char *key_str = NULL; DnsCacheItem *j; if (q->keys[i]->type == DNS_TYPE_ANY || q->keys[i]->class == DNS_CLASS_ANY) { /* If we have ANY lookups we simply refresh */ + + r = dns_resource_key_to_string(q->keys[i], &key_str); + if (r < 0) + return r; + + log_debug("Ignoring cache for ANY lookup: %s", key_str); + *ret = NULL; *rcode = 0; return 0; @@ -481,9 +522,24 @@ int dns_cache_lookup(DnsCache *c, DnsQuestion *q, int *rcode, DnsAnswer **ret) { j = hashmap_get(c->by_key, q->keys[i]); if (!j) { /* If one question cannot be answered we need to refresh */ + + r = dns_resource_key_to_string(q->keys[i], &key_str); + if (r < 0) + return r; + + log_debug("Cache miss for %s", key_str); + *ret = NULL; *rcode = 0; return 0; + } else { + r = dns_resource_key_to_string(j->key, &key_str); + if (r < 0) + return r; + + log_debug("%s cache hit for %s", + j->type == DNS_CACHE_POSITIVE ? "Positive" : + (j->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN"), key_str); } LIST_FOREACH(by_key, j, j) { diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 39951a362c..35ad899544 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -1712,7 +1712,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { if (r < 0) goto fail; - r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL); + r = dns_packet_read_type_windows(p, &rr->nsec3.types, offset + rdlength - p->rindex, NULL); if (r < 0) goto fail; diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index 418d9721ef..3ada442006 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -19,6 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "hostname-util.h" +#include "dns-domain.h" #include "resolved-dns-query.h" @@ -212,6 +214,156 @@ static int dns_query_add_transaction_split(DnsQuery *q, DnsScope *s) { return 0; } +static int SYNTHESIZE_IFINDEX(int ifindex) { + + /* When the caller asked for resolving on a specific interface, + * we synthesize the answer for that interface. However, if + * nothing specific was claimed, we synthesize the answer for + * localhost. */ + + if (ifindex > 0) + return ifindex; + + return LOOPBACK_IFINDEX; +} + +static int SYNTHESIZE_FAMILY(uint64_t flags) { + + /* Picks an address family depending on set flags. This is + * purely for synthesized answers, where the family we return + * for the reply should match what was requested in the + * question, even though we are synthesizing the answer + * here. */ + + if (!(flags & SD_RESOLVED_DNS)) { + if (flags & SD_RESOLVED_LLMNR_IPV4) + return AF_INET; + if (flags & SD_RESOLVED_LLMNR_IPV6) + return AF_INET6; + } + + return AF_UNSPEC; +} + +static DnsProtocol SYNTHESIZE_PROTOCOL(uint64_t flags) { + + /* Similar as SYNTHESIZE_FAMILY() but does this for the + * protocol. If resolving via DNS was requested, we claim it + * was DNS. Similar, if nothing specific was + * requested. However, if only resolving via LLMNR was + * requested we return that. */ + + if (flags & SD_RESOLVED_DNS) + return DNS_PROTOCOL_DNS; + if (flags & SD_RESOLVED_LLMNR) + return DNS_PROTOCOL_LLMNR; + + return DNS_PROTOCOL_DNS; +} + +static void dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + unsigned i; + int r; + + assert(q); + assert(state); + + /* Tries to synthesize localhost RR replies where appropriate */ + + if (!IN_SET(*state, + DNS_TRANSACTION_FAILURE, + DNS_TRANSACTION_NO_SERVERS, + DNS_TRANSACTION_TIMEOUT, + DNS_TRANSACTION_ATTEMPTS_MAX_REACHED)) + return; + + for (i = 0; i < q->question->n_keys; i++) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + const char *name; + + if (q->question->keys[i]->class != DNS_CLASS_IN && + q->question->keys[i]->class != DNS_CLASS_ANY) + continue; + + name = DNS_RESOURCE_KEY_NAME(q->question->keys[i]); + + if (is_localhost(name)) { + + switch (q->question->keys[i]->type) { + + case DNS_TYPE_A: + case DNS_TYPE_ANY: + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name); + if (!rr) { + log_oom(); + return; + } + + rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK); + break; + + case DNS_TYPE_AAAA: + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name); + if (!rr) { + log_oom(); + return; + } + + rr->aaaa.in6_addr = in6addr_loopback; + break; + } + + } else if (IN_SET(q->question->keys[i]->type, DNS_TYPE_PTR, DNS_TYPE_ANY) && + (dns_name_endswith(name, "127.in-addr.arpa") > 0 || + dns_name_equal(name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0)) { + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, name); + if (!rr) { + log_oom(); + return; + } + + rr->ptr.name = strdup("localhost"); + if (!rr->ptr.name) { + log_oom(); + return; + } + } + + if (!rr) + continue; + + if (!answer) { + answer = dns_answer_new(q->question->n_keys); + if (!answer) { + log_oom(); + return; + } + } + + r = dns_answer_add(answer, rr); + if (r < 0) { + log_error_errno(r, "Failed to add synthetic RR to answer: %m"); + return; + } + } + + if (!answer) + return; + + dns_answer_unref(q->answer); + q->answer = answer; + answer = NULL; + + q->answer_ifindex = SYNTHESIZE_IFINDEX(q->ifindex); + q->answer_family = SYNTHESIZE_FAMILY(q->flags); + q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags); + q->answer_rcode = DNS_RCODE_SUCCESS; + + *state = DNS_TRANSACTION_SUCCESS; +} + int dns_query_go(DnsQuery *q) { DnsScopeMatch found = DNS_SCOPE_NO; DnsScope *s, *first = NULL; @@ -253,8 +405,17 @@ int dns_query_go(DnsQuery *q) { } } - if (found == DNS_SCOPE_NO) + if (found == DNS_SCOPE_NO) { + DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS; + + dns_query_synthesize_reply(q, &state); + if (state != DNS_TRANSACTION_NO_SERVERS) { + dns_query_complete(q, state); + return 1; + } + return -ESRCH; + } r = dns_query_add_transaction_split(q, first); if (r < 0) @@ -428,6 +589,9 @@ void dns_query_ready(DnsQuery *q) { q->answer_family = scope ? scope->family : AF_UNSPEC; } + /* Try to synthesize a reply if we couldn't resolve something. */ + dns_query_synthesize_reply(q, &state); + dns_query_complete(q, state); } diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index b8414da87e..57d9071dfc 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -325,10 +325,6 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family) & flags) == 0) return DNS_SCOPE_NO; - STRV_FOREACH(i, s->domains) - if (dns_name_endswith(domain, *i) > 0) - return DNS_SCOPE_YES; - if (dns_name_root(domain) != 0) return DNS_SCOPE_NO; @@ -340,6 +336,10 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co dns_name_equal(domain, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) return DNS_SCOPE_NO; + STRV_FOREACH(i, s->domains) + if (dns_name_endswith(domain, *i) > 0) + return DNS_SCOPE_YES; + if (s->protocol == DNS_PROTOCOL_DNS) { if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 && dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0 && diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 53779f3372..2d9d1a47ee 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -624,7 +624,6 @@ int dns_transaction_go(DnsTransaction *t) { if (r < 0) return r; if (r > 0) { - log_debug("Cache hit!"); if (t->cached_rcode == DNS_RCODE_SUCCESS) dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); else @@ -661,8 +660,6 @@ int dns_transaction_go(DnsTransaction *t) { return 0; } - log_debug("Cache miss!"); - /* Otherwise, we need to ask the network */ r = dns_transaction_make_packet(t); if (r == -EDOM) { diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 5be01d3cb8..645f2a824c 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -176,8 +176,7 @@ static int manager_process_address(sd_netlink *rtnl, sd_netlink_message *mm, voi break; case RTM_DELADDR: - if (a) - link_address_free(a); + link_address_free(a); break; } diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index aa87cd0910..0df0594ea3 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -2027,37 +2027,3 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send *ret_external = external; return 1; } - -bool is_kdbus_wanted(void) { - _cleanup_free_ char *value = NULL; -#ifdef ENABLE_KDBUS - const bool configured = true; -#else - const bool configured = false; -#endif - - int r; - - if (get_proc_cmdline_key("kdbus", NULL) > 0) - return true; - - r = get_proc_cmdline_key("kdbus=", &value); - if (r <= 0) - return configured; - - return parse_boolean(value) == 1; -} - -bool is_kdbus_available(void) { - _cleanup_close_ int fd = -1; - struct kdbus_cmd cmd = { .size = sizeof(cmd), .flags = KDBUS_FLAG_NEGOTIATE }; - - if (!is_kdbus_wanted()) - return false; - - fd = open("/sys/fs/kdbus/control", O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); - if (fd < 0) - return false; - - return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0; -} diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index 4ae216b7d9..0c683c0713 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -23,18 +23,12 @@ #include "sd-event.h" #include "sd-bus.h" +#include "bus-error.h" +#include "bus-internal.h" #include "hashmap.h" #include "install.h" #include "time-util.h" -typedef enum BusTransport { - BUS_TRANSPORT_LOCAL, - BUS_TRANSPORT_REMOTE, - BUS_TRANSPORT_MACHINE, - _BUS_TRANSPORT_MAX, - _BUS_TRANSPORT_INVALID = -1 -} BusTransport; - typedef int (*bus_property_set_t) (sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata); struct bus_properties_map { @@ -135,21 +129,6 @@ typedef struct UnitInfo { int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_flush_close_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_slot*, sd_bus_slot_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_track*, sd_bus_track_unref); - -#define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp) -#define _cleanup_bus_flush_close_unref_ _cleanup_(sd_bus_flush_close_unrefp) -#define _cleanup_bus_slot_unref_ _cleanup_(sd_bus_slot_unrefp) -#define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp) -#define _cleanup_bus_creds_unref_ _cleanup_(sd_bus_creds_unrefp) -#define _cleanup_bus_track_unref_ _cleanup_(sd_bus_slot_unrefp) -#define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free) - #define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type) \ int function(sd_bus *bus, \ const char *path, \ @@ -197,6 +176,3 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path); int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external); - -bool is_kdbus_wanted(void); -bool is_kdbus_available(void); diff --git a/src/shared/condition.c b/src/shared/condition.c index 24871b0dae..f58e84a3d0 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -101,7 +101,7 @@ static int condition_test_kernel_command_line(Condition *c) { _cleanup_free_ char *word = NULL; bool found; - r = unquote_first_word(&p, &word, UNQUOTE_RELAX); + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) return r; if (r == 0) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 4e850ea1cf..1a9dbadbe1 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -7292,6 +7292,7 @@ static int halt_now(enum action a) { reboot(RB_POWER_OFF); return -errno; + case ACTION_KEXEC: case ACTION_REBOOT: { _cleanup_free_ char *param = NULL; diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 3a92d120d2..b5e09cad26 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1380,7 +1380,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { /* Parse columns */ p = buffer; - r = unquote_many_words(&p, 0, &action, &name, &id, &description, &home, NULL); + r = extract_many_words(&p, NULL, EXTRACT_QUOTES, &action, &name, &id, &description, &home, NULL); if (r < 0) { log_error("[%s:%u] Syntax error.", fname, line); return r; @@ -1389,7 +1389,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { log_error("[%s:%u] Missing action and name columns.", fname, line); return -EINVAL; } - if (*p != 0) { + if (!isempty(p)) { log_error("[%s:%u] Trailing garbage.", fname, line); return -EINVAL; } diff --git a/src/test/test-strv.c b/src/test/test-strv.c index 6e3c81395c..bff43950a9 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -165,7 +165,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted assert_se(p); assert_se(streq(p, quoted)); - r = strv_split_quoted(&s, quoted, 0); + r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES); assert_se(r == 0); assert_se(s); STRV_FOREACH(t, s) { @@ -182,7 +182,7 @@ static void test_strv_unquote(const char *quoted, char **list) { char **t; int r; - r = strv_split_quoted(&s, quoted, 0); + r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES); assert_se(r == 0); assert_se(s); j = strv_join(s, " | "); @@ -199,7 +199,7 @@ static void test_invalid_unquote(const char *quoted) { char **s = NULL; int r; - r = strv_split_quoted(&s, quoted, 0); + r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES); assert_se(s == NULL); assert_se(r == -EINVAL); } @@ -219,6 +219,21 @@ static void test_strv_split(void) { } } +static void test_strv_split_extract(void) { + _cleanup_strv_free_ char **l = NULL; + const char *str = ":foo\\:bar::waldo:"; + int r; + + r = strv_split_extract(&l, str, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + assert_se(r == 0); + assert_se(streq_ptr(l[0], "")); + assert_se(streq_ptr(l[1], "foo:bar")); + assert_se(streq_ptr(l[2], "")); + assert_se(streq_ptr(l[3], "waldo")); + assert_se(streq_ptr(l[4], "")); + assert_se(streq_ptr(l[5], NULL)); +} + static void test_strv_split_newlines(void) { unsigned i = 0; char **s; @@ -542,6 +557,18 @@ static void test_strv_reverse(void) { assert_se(streq_ptr(d[3], NULL)); } +static void test_strv_shell_escape(void) { + _cleanup_strv_free_ char **v = NULL; + + v = strv_new("foo:bar", "bar,baz", "wal\\do", NULL); + assert_se(v); + assert_se(strv_shell_escape(v, ",:")); + assert_se(streq_ptr(v[0], "foo\\:bar")); + assert_se(streq_ptr(v[1], "bar\\,baz")); + assert_se(streq_ptr(v[2], "wal\\\\do")); + assert_se(streq_ptr(v[3], NULL)); +} + int main(int argc, char *argv[]) { test_specifier_printf(); test_strv_foreach(); @@ -583,6 +610,7 @@ int main(int argc, char *argv[]) { test_invalid_unquote("'x'y'g"); test_strv_split(); + test_strv_split_extract(); test_strv_split_newlines(); test_strv_split_nulstr(); test_strv_parse_nulstr(); @@ -598,6 +626,7 @@ int main(int argc, char *argv[]) { test_strv_equal(); test_strv_is_uniq(); test_strv_reverse(); + test_strv_shell_escape(); return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index 03e18df080..3c1bac4606 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -1487,350 +1487,448 @@ static void test_execute_directory(void) { (void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL); } -static void test_unquote_first_word(void) { +static void test_extract_first_word(void) { const char *p, *original; char *t; p = original = "foobar waldo"; - assert_se(unquote_first_word(&p, &t, 0) > 0); + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); assert_se(streq(t, "foobar")); free(t); assert_se(p == original + 7); - assert_se(unquote_first_word(&p, &t, 0) > 0); + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); assert_se(streq(t, "waldo")); free(t); - assert_se(p == original + 12); + assert_se(isempty(p)); - assert_se(unquote_first_word(&p, &t, 0) == 0); + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); assert_se(!t); - assert_se(p == original + 12); + assert_se(isempty(p)); p = original = "\"foobar\" \'waldo\'"; - assert_se(unquote_first_word(&p, &t, 0) > 0); + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "\"foobar\"")); + free(t); + assert_se(p == original + 9); + + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "\'waldo\'")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foobar\" \'waldo\'"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); assert_se(streq(t, "foobar")); free(t); assert_se(p == original + 9); - assert_se(unquote_first_word(&p, &t, 0) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); assert_se(streq(t, "waldo")); free(t); - assert_se(p == original + 16); + assert_se(isempty(p)); - assert_se(unquote_first_word(&p, &t, 0) == 0); + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); assert_se(!t); - assert_se(p == original + 16); + assert_se(isempty(p)); p = original = "\""; - assert_se(unquote_first_word(&p, &t, 0) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\"")); + assert_se(isempty(p)); + + p = original = "\""; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); assert_se(p == original + 1); p = original = "\'"; - assert_se(unquote_first_word(&p, &t, 0) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\'")); + assert_se(isempty(p)); + + p = original = "\'"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); assert_se(p == original + 1); p = original = "\'fooo"; - assert_se(unquote_first_word(&p, &t, 0) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\'fooo")); + assert_se(isempty(p)); + + p = original = "\'fooo"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); assert_se(p == original + 5); p = original = "\'fooo"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); assert_se(streq(t, "fooo")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "yay\'foo\'bar"; - assert_se(unquote_first_word(&p, &t, 0) > 0); + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "yay\'foo\'bar")); + free(t); + assert_se(isempty(p)); + + p = original = "yay\'foo\'bar"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); assert_se(streq(t, "yayfoobar")); free(t); - assert_se(p == original + 11); + assert_se(isempty(p)); p = original = " foobar "; - assert_se(unquote_first_word(&p, &t, 0) > 0); + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); assert_se(streq(t, "foobar")); free(t); - assert_se(p == original + 12); + assert_se(isempty(p)); p = original = " foo\\ba\\x6ar "; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); assert_se(streq(t, "foo\ba\x6ar")); free(t); - assert_se(p == original + 13); + assert_se(isempty(p)); p = original = " foo\\ba\\x6ar "; - assert_se(unquote_first_word(&p, &t, 0) > 0); + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); assert_se(streq(t, "foobax6ar")); free(t); - assert_se(p == original + 13); + assert_se(isempty(p)); p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); assert_se(streq(t, "föo")); free(t); assert_se(p == original + 13); - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0); assert_se(streq(t, "pi\360\237\222\251le")); free(t); - assert_se(p == original + 32); + assert_se(isempty(p)); p = original = "fooo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); assert_se(streq(t, "fooo")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "fooo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); assert_se(streq(t, "fooo\\")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "fooo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(streq(t, "fooo\\")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "fooo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); assert_se(streq(t, "fooo\\")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(unquote_first_word(&p, &t, 0) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL); assert_se(p == original + 5); p = original = "\"foo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(isempty(p)); + + p = original = "foo::bar"; + assert_se(extract_first_word(&p, &t, ":", 0) == 1); assert_se(streq(t, "foo")); free(t); assert_se(p == original + 5); + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "bar")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, ":", 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "foo\\:bar::waldo"; + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "foo:bar")); + free(t); + assert_se(p == original + 10); + + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, ":", 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + p = original = "\"foo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX) == -EINVAL); assert_se(p == original + 5); p = original = "\"foo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(streq(t, "foo\\")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(streq(t, "foo\\")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); assert_se(streq(t, "fooo bar")); free(t); assert_se(p == original + 10); p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); assert_se(streq(t, "fooo bar")); free(t); assert_se(p == original + 10); p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(streq(t, "fooo bar")); free(t); assert_se(p == original + 10); p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); assert_se(p == original + 5); p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); assert_se(streq(t, "fooo\\ bar")); free(t); assert_se(p == original + 10); p = original = "\\w+@\\K[\\d.]+"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); assert_se(p == original + 1); p = original = "\\w+@\\K[\\d.]+"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); assert_se(streq(t, "\\w+@\\K[\\d.]+")); free(t); - assert_se(p == original + 12); + assert_se(isempty(p)); p = original = "\\w+\\b"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); assert_se(streq(t, "\\w+\b")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "-N ''"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); assert_se(streq(t, "-N")); free(t); assert_se(p == original + 3); - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); assert_se(streq(t, "")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); + + p = original = ":foo\\:bar::waldo:"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(t); + assert_se(streq(t, "")); + free(t); + assert_se(p == original + 1); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "foo:bar")); + free(t); + assert_se(p == original + 10); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(t); + assert_se(streq(t, "")); + free(t); + assert_se(p == original + 11); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "waldo")); + free(t); + assert_se(p == original + 17); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "")); + free(t); + assert_se(p == NULL); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0); + assert_se(!t); + assert_se(!p); } -static void test_unquote_first_word_and_warn(void) { +static void test_extract_first_word_and_warn(void) { const char *p, *original; char *t; p = original = "foobar waldo"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); assert_se(streq(t, "foobar")); free(t); assert_se(p == original + 7); - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); assert_se(streq(t, "waldo")); free(t); - assert_se(p == original + 12); + assert_se(isempty(p)); - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); assert_se(!t); - assert_se(p == original + 12); + assert_se(isempty(p)); p = original = "\"foobar\" \'waldo\'"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); assert_se(streq(t, "foobar")); free(t); assert_se(p == original + 9); - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); assert_se(streq(t, "waldo")); free(t); - assert_se(p == original + 16); + assert_se(isempty(p)); - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); assert_se(!t); - assert_se(p == original + 16); + assert_se(isempty(p)); p = original = "\""; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); assert_se(p == original + 1); p = original = "\'"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); assert_se(p == original + 1); p = original = "\'fooo"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); assert_se(p == original + 5); p = original = "\'fooo"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); assert_se(streq(t, "fooo")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = " foo\\ba\\x6ar "; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); assert_se(streq(t, "foo\ba\x6ar")); free(t); - assert_se(p == original + 13); + assert_se(isempty(p)); p = original = " foo\\ba\\x6ar "; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); assert_se(streq(t, "foobax6ar")); free(t); - assert_se(p == original + 13); + assert_se(isempty(p)); p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); assert_se(streq(t, "föo")); free(t); assert_se(p == original + 13); - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); assert_se(streq(t, "pi\360\237\222\251le")); free(t); - assert_se(p == original + 32); + assert_se(isempty(p)); p = original = "fooo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); assert_se(streq(t, "fooo")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "fooo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); assert_se(streq(t, "fooo\\")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "fooo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); assert_se(streq(t, "fooo\\")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); assert_se(p == original + 5); p = original = "\"foo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); assert_se(streq(t, "foo")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); assert_se(p == original + 5); p = original = "\"foo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); assert_se(streq(t, "foo")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); assert_se(streq(t, "fooo bar")); free(t); assert_se(p == original + 10); p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); assert_se(streq(t, "fooo bar")); free(t); assert_se(p == original + 10); p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); assert_se(streq(t, "fooo\\ bar")); free(t); assert_se(p == original + 10); p = original = "\\w+@\\K[\\d.]+"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); assert_se(streq(t, "\\w+@\\K[\\d.]+")); free(t); - assert_se(p == original + 12); + assert_se(isempty(p)); p = original = "\\w+\\b"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); assert_se(streq(t, "\\w+\b")); free(t); - assert_se(p == original + 5); + assert_se(isempty(p)); } -static void test_unquote_many_words(void) { +static void test_extract_many_words(void) { const char *p, *original; char *a, *b, *c; p = original = "foobar waldi piep"; - assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 3); - assert_se(p == original + 17); + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3); + assert_se(isempty(p)); assert_se(streq_ptr(a, "foobar")); assert_se(streq_ptr(b, "waldi")); assert_se(streq_ptr(c, "piep")); @@ -1839,8 +1937,17 @@ static void test_unquote_many_words(void) { free(c); p = original = "'foobar' wa\"ld\"i "; - assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 2); - assert_se(p == original + 19); + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "'foobar'")); + assert_se(streq_ptr(b, "wa\"ld\"i")); + assert_se(streq_ptr(c, NULL)); + free(a); + free(b); + + p = original = "'foobar' wa\"ld\"i "; + assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2); + assert_se(isempty(p)); assert_se(streq_ptr(a, "foobar")); assert_se(streq_ptr(b, "waldi")); assert_se(streq_ptr(c, NULL)); @@ -1848,32 +1955,32 @@ static void test_unquote_many_words(void) { free(b); p = original = ""; - assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 0); - assert_se(p == original); + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); + assert_se(isempty(p)); assert_se(streq_ptr(a, NULL)); assert_se(streq_ptr(b, NULL)); assert_se(streq_ptr(c, NULL)); p = original = " "; - assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 0); - assert_se(p == original+2); + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); + assert_se(isempty(p)); assert_se(streq_ptr(a, NULL)); assert_se(streq_ptr(b, NULL)); assert_se(streq_ptr(c, NULL)); p = original = "foobar"; - assert_se(unquote_many_words(&p, 0, NULL) == 0); + assert_se(extract_many_words(&p, NULL, 0, NULL) == 0); assert_se(p == original); p = original = "foobar waldi"; - assert_se(unquote_many_words(&p, 0, &a, NULL) == 1); + assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); assert_se(p == original+7); assert_se(streq_ptr(a, "foobar")); free(a); p = original = " foobar "; - assert_se(unquote_many_words(&p, 0, &a, NULL) == 1); - assert_se(p == original+15); + assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); + assert_se(isempty(p)); assert_se(streq_ptr(a, "foobar")); free(a); } @@ -1993,6 +2100,21 @@ static void test_sparse_write(void) { test_sparse_write_one(fd, test_e, sizeof(test_e)); } +static void test_shell_escape_one(const char *s, const char *bad, const char *expected) { + _cleanup_free_ char *r; + + assert_se(r = shell_escape(s, bad)); + assert_se(streq_ptr(r, expected)); +} + +static void test_shell_escape(void) { + test_shell_escape_one("", "", ""); + test_shell_escape_one("\\", "", "\\\\"); + test_shell_escape_one("foobar", "", "foobar"); + test_shell_escape_one("foobar", "o", "f\\o\\obar"); + test_shell_escape_one("foo:bar,baz", ",:", "foo\\:bar\\,baz"); +} + static void test_shell_maybe_quote_one(const char *s, const char *expected) { _cleanup_free_ char *r; @@ -2149,14 +2271,15 @@ int main(int argc, char *argv[]) { test_search_and_fopen_nulstr(); test_glob_exists(); test_execute_directory(); - test_unquote_first_word(); - test_unquote_first_word_and_warn(); - test_unquote_many_words(); + test_extract_first_word(); + test_extract_first_word_and_warn(); + test_extract_many_words(); test_parse_proc_cmdline(); test_raw_clone(); test_same_fd(); test_uid_ptr(); test_sparse_write(); + test_shell_escape(); test_shell_maybe_quote(); test_parse_mode(); test_tempfn(); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index d6f7801561..8f29256c6d 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -662,7 +662,7 @@ static int parse_xattrs_from_arg(Item *i) { for (;;) { _cleanup_free_ char *name = NULL, *value = NULL, *xattr = NULL, *xattr_replaced = NULL; - r = unquote_first_word(&p, &xattr, UNQUOTE_CUNESCAPE); + r = extract_first_word(&p, &xattr, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE); if (r < 0) log_warning_errno(r, "Failed to parse extended attribute '%s', ignoring: %m", p); if (r <= 0) @@ -1760,9 +1760,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { assert(line >= 1); assert(buffer); - r = unquote_many_words( + r = extract_many_words( &buffer, - 0, + NULL, + EXTRACT_QUOTES, &action, &path, &mode, diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index 1dad4476f3..b8066ea6e9 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -143,6 +143,11 @@ static int find_gpt_root(struct udev_device *dev, blkid_probe pr, bool test) { if (sd_id128_equal(type, GPT_ESP)) { sd_id128_t id, esp; + unsigned long long flags; + + flags = blkid_partition_get_flags(pp); + if (flags & GPT_FLAG_NO_AUTO) + continue; /* We found an ESP, let's see if it matches * the ESP we booted from. */ diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index aa5cda6fe7..f529ffcf25 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -117,8 +117,7 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, format_lun_number(parent, &lun); path_prepend(path, "fc-%s-%s", port, lun); - if (lun) - free(lun); + free(lun); out: udev_device_unref(fcdev); return parent; @@ -156,8 +155,7 @@ static struct udev_device *handle_scsi_sas_wide_port(struct udev_device *parent, format_lun_number(parent, &lun); path_prepend(path, "sas-%s-%s", sas_address, lun); - if (lun) - free(lun); + free(lun); out: udev_device_unref(sasdev); return parent; @@ -251,8 +249,7 @@ static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **pa else path_prepend(path, "sas-phy%s-%s", phy_id, lun); - if (lun) - free(lun); + free(lun); out: udev_device_unref(target_sasdev); udev_device_unref(expander_sasdev); @@ -313,8 +310,7 @@ static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char ** format_lun_number(parent, &lun); path_prepend(path, "ip-%s:%s-iscsi-%s-%s", addr, port, target, lun); - if (lun) - free(lun); + free(lun); out: udev_device_unref(sessiondev); udev_device_unref(conndev); diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index b0ad277f73..b4ae0944eb 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -379,13 +379,14 @@ struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) { cmsg_close_all(&smsg); cmsg = CMSG_FIRSTHDR(&smsg); - cred = (struct ucred *) CMSG_DATA(cmsg); if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { log_error("no sender credentials received, message ignored"); goto err; } + cred = (struct ucred *) CMSG_DATA(cmsg); + if (cred->uid != 0) { log_error("sender uid="UID_FMT", message ignored", cred->uid); goto err; diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c index ea9b0c9c84..61bcf02b2f 100644 --- a/src/update-utmp/update-utmp.c +++ b/src/update-utmp/update-utmp.c @@ -286,8 +286,6 @@ finish: audit_close(c.audit_fd); #endif - if (c.bus) - sd_bus_unref(c.bus); - + sd_bus_unref(c.bus); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } |