]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #7532 from yuwata/test-execute
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 5 Dec 2017 20:43:14 +0000 (21:43 +0100)
committerGitHub <noreply@github.com>
Tue, 5 Dec 2017 20:43:14 +0000 (21:43 +0100)
test-execute: add test for that DynamicUser= migrates StateDirectory=

64 files changed:
.ycm_extra_conf.py
man/busctl.xml
man/coredumpctl.xml
man/custom-entities.ent.in
man/journalctl.xml
man/localectl.xml
man/machinectl.xml
man/systemd-hwdb.xml
man/systemd-journal-gatewayd.service.xml
man/systemd-journal-remote.xml
man/systemd-journal-upload.xml
man/systemd-udevd.service.xml
man/systemd.exec.xml
man/systemd.network.xml
man/udevadm.xml
meson.build
meson_options.txt
src/analyze/analyze.c
src/basic/fs-util.c
src/basic/hexdecoct.c
src/basic/missing.h
src/basic/mount-util.c
src/basic/mount-util.h
src/basic/path-util.c
src/basic/string-util.c
src/basic/string-util.h
src/busctl/busctl.c
src/core/execute.c
src/core/load-fragment.c
src/core/namespace.c
src/core/service.c
src/core/service.h
src/core/unit.c
src/core/unit.h
src/dissect/dissect.c
src/fstab-generator/fstab-generator.c
src/journal-remote/journal-upload.c
src/mount/mount-tool.c
src/nspawn/nspawn-cgroup.c
src/nspawn/nspawn-cgroup.h
src/nspawn/nspawn.c
src/partition/growfs.c
src/shared/bootspec.c
src/shared/bus-unit-util.c
src/shared/dissect-image.c
src/shared/dissect-image.h
src/stdio-bridge/stdio-bridge.c
src/test/meson.build
src/test/test-fs-util.c
src/test/test-hexdecoct.c
src/test/test-string-util.c
src/udev/udevadm-control.c
src/udev/udevadm-hwdb.c
src/udev/udevadm-info.c
src/udev/udevadm-monitor.c
src/udev/udevadm-settle.c
src/udev/udevadm-test-builtin.c
src/udev/udevadm-test.c
src/udev/udevadm-trigger.c
src/udev/udevadm-util.h
src/udev/udevd.c
sysusers.d/basic.conf.in
test/TEST-10-ISSUE-2467/test.sh
test/run-integration-tests.sh [new file with mode: 0755]

index 4edd3c8a7433ae209b8122b9d734881340b7b7d3..f297deefe2bd0dbe4d115574c72d1be8815ff81c 100644 (file)
-import itertools
+#!/usr/bin/env python
+
+# SPDX-License-Identifier: Unlicense
+#
+# Based on the template file provided by the 'YCM-Generator' project authored by
+# Reuben D'Netto.
+# Jiahui Xie has re-reformatted and expanded the original script in accordance
+# to the requirements of the PEP 8 style guide and 'systemd' project,
+# respectively.
+#
+# The original license is preserved as it is.
+#
+#
+# This is free and unencumbered software released into the public domain.
+#
+# Anyone is free to copy, modify, publish, use, compile, sell, or
+# distribute this software, either in source code form or as a compiled
+# binary, for any purpose, commercial or non-commercial, and by any
+# means.
+#
+# In jurisdictions that recognize copyright laws, the author or authors
+# of this software dedicate any and all copyright interest in the
+# software to the public domain. We make this dedication for the benefit
+# of the public at large and to the detriment of our heirs and
+# successors. We intend this dedication to be an overt act of
+# relinquishment in perpetuity of all present and future rights to this
+# software under copyright law.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# For more information, please refer to <http://unlicense.org/>
+
+"""
+YouCompleteMe configuration file tailored to support the 'meson' build system
+used by the 'systemd' project.
+"""
+
+import glob
 import os
-import subprocess
+import ycm_core
 
-def GetFlagsFromMakefile(varname):
-  return subprocess.check_output([
-      "make", "-s", "print-%s" % varname]).decode().split()
 
-
-def Flatten(lists):
-  return list(itertools.chain.from_iterable(lists))
+SOURCE_EXTENSIONS = (".C", ".cpp", ".cxx", ".cc", ".c", ".m", ".mm")
+HEADER_EXTENSIONS = (".H", ".h", ".hxx", ".hpp", ".hh")
 
 
 def DirectoryOfThisScript():
-  return os.path.dirname(os.path.abspath(__file__))
+    """
+    Return the absolute path of the parent directory containing this
+    script.
+    """
+    return os.path.dirname(os.path.abspath(__file__))
+
+
+def GuessBuildDirectory():
+    """
+    Guess the build directory using the following heuristics:
+
+    1. Returns the current directory of this script plus 'build'
+    subdirectory in absolute path if this subdirectory exists.
+
+    2. Otherwise, probes whether there exists any directory
+    containing '.ninja_log' file two levels above the current directory;
+    returns this single directory only if there is one candidate.
+    """
+    result = os.path.join(DirectoryOfThisScript(), "build")
+
+    if os.path.exists(result):
+        return result
+
+    result = glob.glob(os.path.join(DirectoryOfThisScript(),
+                                    "..", "..", "*", ".ninja_log"))
+
+    if not result:
+        return ""
+
+    if 1 != len(result):
+        return ""
+
+    return os.path.split(result[0])[0]
+
+
+def TraverseByDepth(root, include_extensions):
+    """
+    Return a set of child directories of the 'root' containing file
+    extensions specified in 'include_extensions'.
+
+    NOTE:
+        1. The 'root' directory itself is excluded from the result set.
+        2. No subdirectories would be excluded if 'include_extensions' is left
+           to 'None'.
+        3. Each entry in 'include_extensions' must begin with string '.'.
+    """
+    is_root = True
+    result = set()
+    # Perform a depth first top down traverse of the given directory tree.
+    for root_dir, subdirs, file_list in os.walk(root):
+        if not is_root:
+            # print("Relative Root: ", root_dir)
+            # print(subdirs)
+            if include_extensions:
+                get_ext = os.path.splitext
+                subdir_extensions = {
+                    get_ext(f)[-1] for f in file_list if get_ext(f)[-1]
+                }
+                if subdir_extensions & include_extensions:
+                    result.add(root_dir)
+            else:
+                result.add(root_dir)
+        else:
+            is_root = False
+
+    return result
+
+
+_project_src_dir = os.path.join(DirectoryOfThisScript(), "src")
+_include_dirs_set = TraverseByDepth(_project_src_dir, frozenset({".h"}))
+flags = [
+    "-x",
+    "c"
+    # The following flags are partially redundant due to the existence of
+    # 'compile_commands.json'.
+    #    '-Wall',
+    #    '-Wextra',
+    #    '-Wfloat-equal',
+    #    '-Wpointer-arith',
+    #    '-Wshadow',
+    #    '-std=gnu99',
+]
+
+for include_dir in _include_dirs_set:
+    flags.append("-I" + include_dir)
+
+# Set this to the absolute path to the folder (NOT the file!) containing the
+# compile_commands.json file to use that instead of 'flags'. See here for
+# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
+#
+# You can get CMake to generate this file for you by adding:
+#   set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
+# to your CMakeLists.txt file.
+#
+# Most projects will NOT need to set this to anything; you can just change the
+# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
+compilation_database_folder = GuessBuildDirectory()
+
+if os.path.exists(compilation_database_folder):
+    database = ycm_core.CompilationDatabase(compilation_database_folder)
+else:
+    database = None
 
 
 def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
-  if not working_directory:
-    return flags
-  new_flags = []
-  make_next_absolute = False
-  path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
-  for flag in flags:
-    new_flag = flag
-
-    if make_next_absolute:
-      make_next_absolute = False
-      if not flag.startswith('/'):
-        new_flag = os.path.join(working_directory, flag)
-
-    for path_flag in path_flags:
-      if flag == path_flag:
-        make_next_absolute = True
-        break
-
-      if flag.startswith(path_flag):
-        path = flag[ len(path_flag): ]
-        new_flag = path_flag + os.path.join(working_directory, path)
-        break
-
-    if new_flag:
-      new_flags.append(new_flag)
-  return new_flags
-
-
-def FlagsForFile(filename):
-  relative_to = DirectoryOfThisScript()
-
-  return {
-    'flags': MakeRelativePathsInFlagsAbsolute(flags, relative_to),
-    'do_cache': True
-  }
-
-flags = Flatten(map(GetFlagsFromMakefile, [
-  'AM_CPPFLAGS',
-  'CPPFLAGS',
-  'AM_CFLAGS',
-  'CFLAGS',
-]))
-
-# these flags cause crashes in libclang, so remove them
-flags.remove('-Wlogical-op')
-flags.remove('-Wsuggest-attribute=noreturn')
-flags.remove('-Wdate-time')
-
-# vim: set et ts=2 sw=2:
+    """
+    Iterate through 'flags' and replace the relative paths prefixed by
+    '-isystem', '-I', '-iquote', '--sysroot=' with absolute paths
+    start with 'working_directory'.
+    """
+    if not working_directory:
+        return list(flags)
+    new_flags = []
+    make_next_absolute = False
+    path_flags = ["-isystem", "-I", "-iquote", "--sysroot="]
+    for flag in flags:
+        new_flag = flag
+
+        if make_next_absolute:
+            make_next_absolute = False
+            if not flag.startswith("/"):
+                new_flag = os.path.join(working_directory, flag)
+
+        for path_flag in path_flags:
+            if flag == path_flag:
+                make_next_absolute = True
+                break
+
+            if flag.startswith(path_flag):
+                path = flag[len(path_flag):]
+                new_flag = path_flag + os.path.join(working_directory, path)
+                break
+
+        if new_flag:
+            new_flags.append(new_flag)
+    return new_flags
+
+
+def IsHeaderFile(filename):
+    """
+    Check whether 'filename' is considered as a header file.
+    """
+    extension = os.path.splitext(filename)[1]
+    return extension in HEADER_EXTENSIONS
+
+
+def GetCompilationInfoForFile(filename):
+    """
+    Helper function to look up compilation info of 'filename' in the 'database'.
+    """
+    # The compilation_commands.json file generated by CMake does not have
+    # entries for header files. So we do our best by asking the db for flags for
+    # a corresponding source file, if any. If one exists, the flags for that
+    # file should be good enough.
+    if not database:
+        return None
+
+    if IsHeaderFile(filename):
+        basename = os.path.splitext(filename)[0]
+        for extension in SOURCE_EXTENSIONS:
+            replacement_file = basename + extension
+            if os.path.exists(replacement_file):
+                compilation_info = \
+                    database.GetCompilationInfoForFile(replacement_file)
+                if compilation_info.compiler_flags_:
+                    return compilation_info
+        return None
+    return database.GetCompilationInfoForFile(filename)
+
+
+def FlagsForFile(filename, **kwargs):
+    """
+    Callback function to be invoked by YouCompleteMe in order to get the
+    information necessary to compile 'filename'.
+
+    It returns a dictionary with a single element 'flags'. This element is a
+    list of compiler flags to pass to libclang for the file 'filename'.
+    """
+    if database:
+        # Bear in mind that compilation_info.compiler_flags_ does NOT return a
+        # python list, but a "list-like" StringVec object
+        compilation_info = GetCompilationInfoForFile(filename)
+        if not compilation_info:
+            return None
+
+        final_flags = MakeRelativePathsInFlagsAbsolute(
+            compilation_info.compiler_flags_,
+            compilation_info.compiler_working_dir_)
+
+    else:
+        relative_to = DirectoryOfThisScript()
+        final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to)
+
+    return {
+        "flags": final_flags,
+        "do_cache": True
+    }
index 2446a8caa440020e6461828cc5adf3994cb2dc4d..0c0d28b5d3280a4656181ad7dcc25e2ea98cd01b 100644 (file)
       </varlistentry>
 
       <varlistentry>
+        <term><option>-q</option></term>
         <term><option>--quiet</option></term>
 
         <listitem>
index 73f4b87dacdbd9e67745e6a0c20adc69eb0db659..72191d1dc264dfcd5c88e3db043451bc434c6bdc 100644 (file)
         <term><option>-q</option></term>
         <term><option>--quiet</option></term>
 
-        <listitem><para>Suppresses info messages about lack
+        <listitem><para>Suppresses informational messages about lack
         of access to journal files and possible in-flight coredumps.
         </para></listitem>
       </varlistentry>
index 0257c2a94f283dd78b73383fa6093e7000bfd7f6..9ea92384aa7dd1df9df569862daa3073f52cc797 100644 (file)
@@ -5,3 +5,4 @@
 <!ENTITY usergeneratordir @USER_GENERATOR_PATH@>
 <!ENTITY systemenvgeneratordir @SYSTEM_ENV_GENERATOR_PATH@>
 <!ENTITY userenvgeneratordir @USER_ENV_GENERATOR_PATH@>
+<!ENTITY CERTIFICATE_ROOT @CERTIFICATE_ROOT@>
index 089fb1378f4a2ee89fabf38574fd7014c127b051..257ff5a8168d3a16dd3592f18bf6b7e1417986b4 100644 (file)
         <term><option>-q</option></term>
         <term><option>--quiet</option></term>
 
-        <listitem><para>Suppresses all info messages
+        <listitem><para>Suppresses all informational messages
         (i.e. "-- Logs begin at â€¦", "-- Reboot --"),
         any warning messages regarding
         inaccessible system journals when run as a normal
index 858854104195088314abe4d08d08694361798294..89a7ab28554fd1b9d77509d956c5236d8d262bbd 100644 (file)
       </varlistentry>
 
       <xi:include href="user-system-options.xml" xpointer="host" />
+      <xi:include href="user-system-options.xml" xpointer="machine" />
 
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
index 73fc5a68f6da6335d23619b925909c0a5764ee62..43f4d127b85808db33f3e90a92c6f257e0744f8e 100644 (file)
         <literal>,</literal> if another address will be output afterwards. </para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>-q</option></term>
+        <term><option>--quiet</option></term>
+
+        <listitem><para>Suppresses additional informational output while running.</para></listitem>
+      </varlistentry>
+
       <xi:include href="user-system-options.xml" xpointer="host" />
 
       <varlistentry>
index c54762a254b19f05c515d46f3c0cbec6dedfe99e..58b151653b086f1df415428498a88ba8984a9ed0 100644 (file)
@@ -23,7 +23,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 -->
 
-<refentry id="systemd-hwdb" conditional="ENABLE_HWDB">
+<refentry id="systemd-hwdb" conditional="ENABLE_HWDB"
+          xmlns:xi="http://www.w3.org/2001/XInclude">
+
   <refentryinfo>
     <title>systemd-hwdb</title>
     <productname>systemd</productname>
 
   <refsect1><title>Options</title>
     <variablelist>
-      <varlistentry>
-        <term><option>-h</option></term>
-        <term><option>--help</option></term>
-        <listitem>
-          <para>Print help text.</para>
-        </listitem>
-      </varlistentry>
       <varlistentry>
         <term><option>--usr</option></term>
         <listitem>
@@ -88,6 +83,8 @@
           <para>Alternate root path in the filesystem.</para>
         </listitem>
       </varlistentry>
+
+      <xi:include href="standard-options.xml" xpointer="help" />
     </variablelist>
 
     <refsect2><title>systemd-hwdb
index b82cc979e7e2f2ee5e7c1d334d5b5edbe28c03ce..4d461d9be4b0d1a63116052dd708cfa9ffc77ae5 100644 (file)
         with <option>--cert=</option>.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--trust=</option></term>
+
+        <listitem><para>Specify the path to a file containing a
+        CA certificate in PEM format.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>-D <replaceable>DIR</replaceable></option></term>
         <term><option>--directory=<replaceable>DIR</replaceable></option></term>
index ba88df535b09fdecd1ef067a73b1d6b935358729..658c7e07f4f5fedb85be4193cd682cbbe0e43cfd 100644 (file)
@@ -1,6 +1,9 @@
 <?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
 
 <!--
   SPDX-License-Identifier: LGPL-2.1+
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--key=</option></term>
+
+        <listitem><para>
+          Takes a path to a SSL key file in PEM format.
+          Defaults to <filename>&CERTIFICATE_ROOT;/private/journal-remote.pem</filename>.
+          This option can be used with <option>--listen-https=</option>.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--cert=</option></term>
+
+        <listitem><para>
+          Takes a path to a SSL certificate file in PEM format.
+          Defaults to <filename>&CERTIFICATE_ROOT;/certs/journal-remote.pem</filename>.
+          This option can be used with <option>--listen-https=</option>.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--trust=</option></term>
+
+        <listitem><para>
+          Takes a path to a SSL CA certificate file in PEM format,
+          or <option>all</option>. If <option>all</option> is set,
+          then certificate checking will be disabled.
+          Defaults to <filename>&CERTIFICATE_ROOT;/ca/trusted.pem</filename>.
+          This option can be used with <option>--listen-https=</option>.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--gnutls-log=</option></term>
+
+        <listitem><para>
+          Takes a comma separated list of gnutls logging categories.
+          This option can be used with <option>--listen-http=</option> or
+          <option>--listen-https=</option>.
+        </para></listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
 
index 6fc477d75a10fce42aa65a36f6ac25619275abee..a43062a6d5a225992c306c3b5bc4244d6148f130 100644 (file)
@@ -1,6 +1,9 @@
 <?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
 
 <!--
   SPDX-License-Identifier: LGPL-2.1+
         </para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--follow</option><optional>=<replaceable>BOOL</replaceable></optional></term>
+
+        <listitem><para>
+          If set to yes, then <command>systemd-journal-upload</command> waits for input.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--key=</option></term>
+
+        <listitem><para>
+          Takes a path to a SSL key file in PEM format.
+          Defaults to <filename>&CERTIFICATE_ROOT;/private/journal-upload.pem</filename>.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--cert=</option></term>
+
+        <listitem><para>
+          Takes a path to a SSL certificate file in PEM format.
+          Defaults to <filename>&CERTIFICATE_ROOT;/certs/journal-upload.pem</filename>.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--trust=</option></term>
+
+        <listitem><para>
+          Takes a path to a SSL CA certificate file in PEM format,
+          or <option>all</option>. If <option>all</option> is set,
+          then certificate checking will be disabled.
+          Defaults to <filename>&CERTIFICATE_ROOT;/ca/trusted.pem</filename>.
+        </para></listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
     </variablelist>
index 12b51a152de9ed8aa1ba020a0b3eaa8fcdc429a3..ee18dae6ebb36c57ae3b542353453b429cbdce92 100644 (file)
@@ -89,6 +89,7 @@
   <refsect1><title>Options</title>
     <variablelist>
       <varlistentry>
+        <term><option>-d</option></term>
         <term><option>--daemon</option></term>
         <listitem>
           <para>Detach and run in the background.</para>
@@ -96,6 +97,7 @@
       </varlistentry>
 
       <varlistentry>
+        <term><option>-D</option></term>
         <term><option>--debug</option></term>
         <listitem>
           <para>Print debug messages to standard error.</para>
       </varlistentry>
 
       <varlistentry>
+        <term><option>-c=</option></term>
         <term><option>--children-max=</option></term>
         <listitem>
           <para>Limit the number of events executed in parallel.</para>
       </varlistentry>
 
       <varlistentry>
+        <term><option>-e=</option></term>
         <term><option>--exec-delay=</option></term>
         <listitem>
           <para>Delay the execution of <varname>RUN</varname>
       </varlistentry>
 
       <varlistentry>
+        <term><option>-t=</option></term>
         <term><option>--event-timeout=</option></term>
         <listitem>
           <para>Set the number of seconds to wait for events to finish. After
       </varlistentry>
 
       <varlistentry>
+        <term><option>-N=</option></term>
         <term><option>--resolve-names=</option></term>
         <listitem>
           <para>Specify when systemd-udevd should resolve names of users and groups.
         </listitem>
       </varlistentry>
 
-      <varlistentry>
-        <term><option>--help</option></term>
-
-        <xi:include href="standard-options.xml" xpointer="help-text" />
-      </varlistentry>
+      <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
     </variablelist>
   </refsect1>
index 019bc3bae51062101b789663cd10101c382f5fcf..849baec974f1fb8821ca8948649db3789df5d0a5 100644 (file)
@@ -1053,7 +1053,7 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
 
         <listitem><para>Takes a boolean argument. If true, explicit module loading will be denied. This allows to turn
         off module load and unload operations on modular kernels. It is recommended to turn this on for most services
-        that do not need special file systems or extra kernel modules to work. Default to off. Enabling this option
+        that do not need special file systems or extra kernel modules to work. Defaults to off. Enabling this option
         removes <constant>CAP_SYS_MODULE</constant> from the capability bounding set for the unit, and installs a
         system call filter to block module system calls, also <filename>/usr/lib/modules</filename> is made
         inaccessible. For this setting the same restrictions regarding mount propagation and privileges apply as for
index 5a5ecb0b168f4277a8435a033bbc1e53f77948c8..3466f3a3cf71af3da6ff6d26c0ac046beb8f7fa4 100644 (file)
           <term><varname>VLANId=</varname></term>
           <listitem>
             <para>The VLAN ID for the new static MAC table entry. If
-            omitted, no VLAN ID info is appended to the new static MAC
+            omitted, no VLAN ID information is appended to the new static MAC
             table entry.</para>
           </listitem>
         </varlistentry>
index 471108642bd1dd6aaf3310c24c3d38e1756382d7..753ddf98daedd1d812585cc29e8def7bec2e4553 100644 (file)
@@ -23,7 +23,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 -->
 
-<refentry id="udevadm">
+<refentry id="udevadm"
+          xmlns:xi="http://www.w3.org/2001/XInclude">
+
   <refentryinfo>
     <title>udevadm</title>
     <productname>systemd</productname>
         <arg><option>--help</option></arg>
     </cmdsynopsis>
     <cmdsynopsis>
-      <command>udevadm info <replaceable>options</replaceable></command>
+      <command>udevadm info <optional>options</optional> <optional>devpath</optional></command>
     </cmdsynopsis>
     <cmdsynopsis>
-      <command>udevadm trigger <optional>options</optional></command>
+      <command>udevadm trigger <optional>options</optional> <optional>devpath</optional></command>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>udevadm settle <optional>options</optional></command>
     </cmdsynopsis>
     <cmdsynopsis>
-      <command>udevadm control <replaceable>command</replaceable></command>
+      <command>udevadm control <replaceable>option</replaceable></command>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>udevadm monitor <optional>options</optional></command>
   <refsect1><title>Options</title>
     <variablelist>
       <varlistentry>
+        <term><option>-d</option></term>
         <term><option>--debug</option></term>
         <listitem>
           <para>Print debug messages to standard error.</para>
         </listitem>
       </varlistentry>
-      <varlistentry>
-        <term><option>--version</option></term>
-        <listitem>
-          <para>Print version number.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>-h</option></term>
-        <term><option>--help</option></term>
-        <listitem>
-          <para>Print help text.</para>
-        </listitem>
-      </varlistentry>
+
+      <xi:include href="standard-options.xml" xpointer="version" />
+      <xi:include href="standard-options.xml" xpointer="help" />
     </variablelist>
 
     <refsect2><title>udevadm info
             <para>Cleanup the udev database.</para>
           </listitem>
         </varlistentry>
-        <varlistentry>
-          <term><option>--version</option></term>
-          <listitem>
-            <para>Print version.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><option>-h</option></term>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
+
+        <xi:include href="standard-options.xml" xpointer="version" />
+        <xi:include href="standard-options.xml" xpointer="help" />
       </variablelist>
 
       <para>In addition, an optional positional argument can be used
             device.</para>
           </listitem>
         </varlistentry>
-        <varlistentry>
-          <term><option>-h</option></term>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
+
+        <xi:include href="standard-options.xml" xpointer="version" />
+        <xi:include href="standard-options.xml" xpointer="help" />
       </variablelist>
 
       <para>In addition, optional positional arguments can be used
             <para>Stop waiting if file exists.</para>
           </listitem>
         </varlistentry>
-        <varlistentry>
-          <term><option>-h</option></term>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
+
+        <xi:include href="standard-options.xml" xpointer="version" />
+        <xi:include href="standard-options.xml" xpointer="help" />
       </variablelist>
     </refsect2>
 
-    <refsect2><title>udevadm control <replaceable>command</replaceable></title>
+    <refsect2><title>udevadm control <replaceable>option</replaceable></title>
       <para>Modify the internal state of the running udev daemon.</para>
       <variablelist>
         <varlistentry>
           </listitem>
         </varlistentry>
         <varlistentry>
+          <term><option>-t</option></term>
           <term><option>--timeout=</option><replaceable>seconds</replaceable></term>
           <listitem>
             <para>The maximum number of seconds to wait for a reply from systemd-udevd.</para>
           </listitem>
         </varlistentry>
-        <varlistentry>
-          <term><option>-h</option></term>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
+
+        <xi:include href="standard-options.xml" xpointer="version" />
+        <xi:include href="standard-options.xml" xpointer="help" />
       </variablelist>
     </refsect2>
 
             <para>Filter udev events by tag. Only udev events with a given tag attached will pass.</para>
           </listitem>
         </varlistentry>
-        <varlistentry>
-          <term><option>-h</option></term>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
+
+        <xi:include href="standard-options.xml" xpointer="version" />
+        <xi:include href="standard-options.xml" xpointer="help" />
       </variablelist>
     </refsect2>
 
             and all devices will be owned by root.</para>
           </listitem>
         </varlistentry>
-        <varlistentry>
-          <term><option>-h</option></term>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
+
+        <xi:include href="standard-options.xml" xpointer="version" />
+        <xi:include href="standard-options.xml" xpointer="help" />
       </variablelist>
     </refsect2>
 
       for device <replaceable>DEVPATH</replaceable>, and print debug
       output.</para>
       <variablelist>
-        <varlistentry>
-          <term><option>-h</option></term>
-          <term><option>--help</option></term>
-          <listitem>
-            <para>Print help text.</para>
-          </listitem>
-        </varlistentry>
+        <xi:include href="standard-options.xml" xpointer="version" />
+        <xi:include href="standard-options.xml" xpointer="help" />
       </variablelist>
     </refsect2>
   </refsect1>
index 6eff25f45c6ecd094713f5a0d83541e309e75230..edfa02afbb46574562c4432ed15cb2b1c816894a 100644 (file)
@@ -633,6 +633,14 @@ tty_gid = get_option('tty-gid')
 conf.set('TTY_GID', tty_gid)
 substs.set('TTY_GID', tty_gid)
 
+# Ensure provided GID argument is numeric, otherwise fallback to default assignment
+if get_option('users-gid') != ''
+        users_gid = get_option('users-gid').to_int()
+else
+        users_gid = '-'
+endif
+substs.set('USERS_GID', users_gid)
+
 if get_option('adm-group')
         m4_defines += ['-DENABLE_ADM_GROUP']
 endif
@@ -2495,6 +2503,7 @@ status = [
         'debug shell:                       @0@ @ @1@'.format(get_option('debug-shell'),
                                                               get_option('debug-tty')),
         'TTY GID:                           @0@'.format(tty_gid),
+        'users GID:                         @0@'.format(users_gid),
         'maximum system UID:                @0@'.format(system_uid_max),
         'maximum system GID:                @0@'.format(system_gid_max),
         '/dev/kvm access mode:              @0@'.format(get_option('dev-kvm-mode')),
index 498a32ab1171330b29badd5103655f9350e9290b..8c03b0c6dec292453c117eb3ada32c270d042937 100644 (file)
@@ -150,6 +150,8 @@ option('system-gid-max', type : 'string',
 option('tty-gid', type : 'string',
        description : 'the numeric GID of the "tty" group',
        value : '5')
+option('users-gid', type : 'string',
+       description : 'the numeric GID of the "users" group')
 option('adm-group', type : 'boolean',
        description : 'the ACL for adm group should be added')
 option('wheel-group', type : 'boolean',
index 5229b3a082f1735c9d8448013bb118b2bd5c1b7b..8b220d197820566f7e0d539e5326e7b706a42c9c 100644 (file)
@@ -491,11 +491,40 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) {
         size_t size;
         char *ptr;
         int r;
+        usec_t activated_time = USEC_INFINITY;
+        _cleanup_free_ char* path = NULL, *unit_id = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
 
         r = acquire_boot_times(bus, &t);
         if (r < 0)
                 return r;
 
+        path = unit_dbus_path_from_name(SPECIAL_DEFAULT_TARGET);
+        if (!path)
+                return log_oom();
+
+        r = sd_bus_get_property_string(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.systemd1.Unit",
+                        "Id",
+                        &error,
+                        &unit_id);
+        if (r < 0) {
+                log_error_errno(r, "default.target doesn't seem to exist: %s", bus_error_message(&error, r));
+                unit_id = NULL;
+        }
+
+        r = bus_get_uint64_property(bus, path,
+                        "org.freedesktop.systemd1.Unit",
+                        "ActiveEnterTimestampMonotonic",
+                        &activated_time);
+        if (r < 0) {
+                log_info_errno(r, "default.target seems not to be started. Continuing...");
+                activated_time = USEC_INFINITY;
+        }
+
         ptr = buf;
         size = sizeof(buf);
 
@@ -512,6 +541,9 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) {
         size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
         strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
 
+        if (unit_id && activated_time != USEC_INFINITY)
+                size = strpcpyf(&ptr, size, "\n%s reached after %s in userspace", unit_id, format_timespan(ts, sizeof(ts), activated_time - t->userspace_time, USEC_PER_MSEC));
+
         ptr = strdup(buf);
         if (!ptr)
                 return log_oom();
index 475400177a696449898b384b9d85e1d361a5d146..aa33da48b0d669540090f31397d0ccefabb04f3e 100644 (file)
@@ -621,10 +621,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
          * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got
          * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this
          * function what to do when encountering a symlink with an absolute path as directory: prefix it by the
-         * specified path.
-         *
-         * Note: there's also chase_symlinks_prefix() (see below), which as first step prefixes the passed path by the
-         * passed root. */
+         * specified path. */
 
         if (original_root) {
                 r = path_make_absolute_cwd(original_root, &root);
@@ -722,6 +719,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                                  * what we got so far. But don't allow this if the remaining path contains "../ or "./"
                                  * or something else weird. */
 
+                                /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */
+                                if (streq_ptr(done, "/"))
+                                        *done = '\0';
+
                                 if (!strextend(&done, first, todo, NULL))
                                         return -ENOMEM;
 
@@ -794,6 +795,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                         done = first;
                         first = NULL;
                 } else {
+                        /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */
+                        if (streq(done, "/"))
+                                *done = '\0';
+
                         if (!strextend(&done, first, NULL))
                                 return -ENOMEM;
                 }
index 3ffedcafe5a66c9620e017cf3a59f8e7b1bb5e4b..fe7e4954ef4633db7a7ce847e1f3762b6c5277e6 100644 (file)
@@ -624,112 +624,135 @@ int base64_append(
                 return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
 }
 
-int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
-        _cleanup_free_ uint8_t *r = NULL;
-        int a, b, c, d;
-        uint8_t *z;
+static int unbase64_next(const char **p, size_t *l) {
+        int ret;
+
+        assert(p);
+        assert(l);
+
+        /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
+         * greedily skip all preceeding and all following whitespace. */
+
+        for (;;) {
+                if (*l == 0)
+                        return -EPIPE;
+
+                if (!strchr(WHITESPACE, **p))
+                        break;
+
+                /* Skip leading whitespace */
+                (*p)++, (*l)--;
+        }
+
+        if (**p == '=')
+                ret = INT_MAX; /* return padding as INT_MAX */
+        else {
+                ret = unbase64char(**p);
+                if (ret < 0)
+                        return ret;
+        }
+
+        for (;;) {
+                (*p)++, (*l)--;
+
+                if (*l == 0)
+                        break;
+                if (!strchr(WHITESPACE, **p))
+                        break;
+
+                /* Skip following whitespace */
+        }
+
+        return ret;
+}
+
+int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
+        _cleanup_free_ uint8_t *buf = NULL;
         const char *x;
+        uint8_t *z;
         size_t len;
 
         assert(p || l == 0);
-        assert(mem);
-        assert(_len);
+        assert(ret);
+        assert(ret_size);
 
         if (l == (size_t) -1)
                 l = strlen(p);
 
-        /* padding ensures any base63 input has input divisible by 4 */
-        if (l % 4 != 0)
-                return -EINVAL;
-
-        /* strip the padding */
-        if (l > 0 && p[l - 1] == '=')
-                l--;
-        if (l > 0 && p[l - 1] == '=')
-                l--;
-
-        /* a group of four input bytes needs three output bytes, in case of
-           padding we need to add two or three extra bytes */
-        len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
+        /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
+           bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
+        len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
 
-        z = r = malloc(len + 1);
-        if (!r)
+        buf = malloc(len + 1);
+        if (!buf)
                 return -ENOMEM;
 
-        for (x = p; x < p + (l / 4) * 4; x += 4) {
-                /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
-                a = unbase64char(x[0]);
+        for (x = p, z = buf;;) {
+                int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
+
+                a = unbase64_next(&x, &l);
+                if (a == -EPIPE) /* End of string */
+                        break;
                 if (a < 0)
+                        return a;
+                if (a == INT_MAX) /* Padding is not allowed at the beginning of a 4ch block */
                         return -EINVAL;
 
-                b = unbase64char(x[1]);
+                b = unbase64_next(&x, &l);
                 if (b < 0)
+                        return b;
+                if (b == INT_MAX) /* Padding is not allowed at the second character of a 4ch block either */
                         return -EINVAL;
 
-                c = unbase64char(x[2]);
+                c = unbase64_next(&x, &l);
                 if (c < 0)
-                        return -EINVAL;
+                        return c;
 
-                d = unbase64char(x[3]);
+                d = unbase64_next(&x, &l);
                 if (d < 0)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
-                *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
-                *(z++) = (uint8_t) c << 6 | (uint8_t) d;      /* ZZWWWWWW */
-        }
-
-        switch (l % 4) {
+                        return d;
 
-        case 3:
-                a = unbase64char(x[0]);
-                if (a < 0)
-                        return -EINVAL;
+                if (c == INT_MAX) { /* Padding at the third character */
 
-                b = unbase64char(x[1]);
-                if (b < 0)
-                        return -EINVAL;
+                        if (d != INT_MAX) /* If the third character is padding, the fourth must be too */
+                                return -EINVAL;
 
-                c = unbase64char(x[2]);
-                if (c < 0)
-                        return -EINVAL;
+                        /* b == 00YY0000 */
+                        if (b & 15)
+                                return -EINVAL;
 
-                /* c == 00ZZZZ00 */
-                if (c & 3)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
-                *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
-
-                break;
-        case 2:
-                a = unbase64char(x[0]);
-                if (a < 0)
-                        return -EINVAL;
+                        if (l > 0) /* Trailing rubbish? */
+                                return -ENAMETOOLONG;
 
-                b = unbase64char(x[1]);
-                if (b < 0)
-                        return -EINVAL;
+                        *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
+                        break;
+                }
 
-                /* b == 00YY0000 */
-                if (b & 15)
-                        return -EINVAL;
+                if (d == INT_MAX) {
+                        /* c == 00ZZZZ00 */
+                        if (c & 3)
+                                return -EINVAL;
 
-                *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
+                        if (l > 0) /* Trailing rubbish? */
+                                return -ENAMETOOLONG;
 
-                break;
-        case 0:
+                        *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+                        *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+                        break;
+                }
 
-                break;
-        default:
-                return -EINVAL;
+                *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+                *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+                *(z++) = (uint8_t) c << 6 | (uint8_t) d;      /* ZZWWWWWW */
         }
 
         *z = 0;
 
-        *mem = r;
-        r = NULL;
-        *_len = len;
+        if (ret_size)
+                *ret_size = (size_t) (z - buf);
+
+        *ret = buf;
+        buf = NULL;
 
         return 0;
 }
index 76cb0a23acbbdd3383556862a0b4df87b6af4e05..bbdded984fb3a75c1be0afaf6103e6ac3e48c6ef 100644 (file)
@@ -543,10 +543,6 @@ struct btrfs_ioctl_quota_ctl_args {
 #define PR_SET_CHILD_SUBREAPER 36
 #endif
 
-#ifndef MAX_HANDLE_SZ
-#define MAX_HANDLE_SZ 128
-#endif
-
 #if ! HAVE_SECURE_GETENV
 #  if HAVE___SECURE_GETENV
 #    define secure_getenv __secure_getenv
index e60750c531fd952f8c3e54ac8fcc94c2b5601382..7f8b53f2b54480eda70db514942d5367ba19f57b 100644 (file)
 #include "string-util.h"
 #include "strv.h"
 
+/* This is the original MAX_HANDLE_SZ definition from the kernel, when the API was introduced. We use that in place of
+ * any more currently defined value to future-proof things: if the size is increased in the API headers, and our code
+ * is recompiled then it would cease working on old kernels, as those refuse any sizes larger than this value with
+ * EINVAL right-away. Hence, let's disconnect ourselves from any such API changes, and stick to the original definition
+ * from when it was introduced. We use it as a start value only anyway (see below), and hence should be able to deal
+ * with large file handles anyway. */
+#define ORIGINAL_MAX_HANDLE_SZ 128
+
 int name_to_handle_at_loop(
                 int fd,
                 const char *path,
@@ -48,7 +56,7 @@ int name_to_handle_at_loop(
                 int flags) {
 
         _cleanup_free_ struct file_handle *h;
-        size_t n = MAX_HANDLE_SZ;
+        size_t n = ORIGINAL_MAX_HANDLE_SZ;
 
         /* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified
          * buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a
@@ -665,6 +673,22 @@ bool fstype_can_discard(const char *fstype) {
                           "xfs");
 }
 
+bool fstype_can_uid_gid(const char *fstype) {
+
+        /* All file systems that have a uid=/gid= mount option that fixates the owners of all files and directories,
+         * current and future. */
+
+        return STR_IN_SET(fstype,
+                          "adfs",
+                          "fat",
+                          "hfs",
+                          "hpfs",
+                          "iso9660",
+                          "msdos",
+                          "ntfs",
+                          "vfat");
+}
+
 int repeat_unmount(const char *path, int flags) {
         bool done = false;
 
index a19b0d9c42101d8f74cce8f2ab63db52e4fd9e45..a81d01927745785b83f2a22657b99956c138564b 100644 (file)
@@ -52,6 +52,7 @@ bool fstype_is_network(const char *fstype);
 bool fstype_is_api_vfs(const char *fstype);
 bool fstype_is_ro(const char *fsype);
 bool fstype_can_discard(const char *fstype);
+bool fstype_can_uid_gid(const char *fstype);
 
 const char* mode_to_inaccessible_node(mode_t mode);
 
index 3bde1d1e01bf3ddae470a5f9b2520e95d8965040..056fa7d63324e68cb0f12a654c77c3d39eba5864 100644 (file)
@@ -882,7 +882,9 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version)
                         * for Gentoo which does a merge without making /lib a symlink.
                         */
                        "lib/systemd/libsystemd-shared-*.so\0"
-                       "usr/lib/systemd/libsystemd-shared-*.so\0") {
+                       "lib64/systemd/libsystemd-shared-*.so\0"
+                       "usr/lib/systemd/libsystemd-shared-*.so\0"
+                       "usr/lib64/systemd/libsystemd-shared-*.so\0") {
 
                 _cleanup_strv_free_ char **names = NULL;
                 _cleanup_free_ char *path = NULL;
index 312e83433e4e5ec9723e54be34f31070f40504db..e916000b25bb274c330907d88310f22c7d8e2384 100644 (file)
@@ -734,16 +734,20 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
         return obuf;
 }
 
-char *strextend(char **x, ...) {
-        va_list ap;
-        size_t f, l;
+char *strextend_with_separator(char **x, const char *separator, ...) {
+        bool need_separator;
+        size_t f, l, l_separator;
         char *r, *p;
+        va_list ap;
 
         assert(x);
 
         l = f = strlen_ptr(*x);
 
-        va_start(ap, x);
+        need_separator = !isempty(*x);
+        l_separator = strlen_ptr(separator);
+
+        va_start(ap, separator);
         for (;;) {
                 const char *t;
                 size_t n;
@@ -753,22 +757,29 @@ char *strextend(char **x, ...) {
                         break;
 
                 n = strlen(t);
+
+                if (need_separator)
+                        n += l_separator;
+
                 if (n > ((size_t) -1) - l) {
                         va_end(ap);
                         return NULL;
                 }
 
                 l += n;
+                need_separator = true;
         }
         va_end(ap);
 
+        need_separator = !isempty(*x);
+
         r = realloc(*x, l+1);
         if (!r)
                 return NULL;
 
         p = r + f;
 
-        va_start(ap, x);
+        va_start(ap, separator);
         for (;;) {
                 const char *t;
 
@@ -776,10 +787,17 @@ char *strextend(char **x, ...) {
                 if (!t)
                         break;
 
+                if (need_separator && separator)
+                        p = stpcpy(p, separator);
+
                 p = stpcpy(p, t);
+
+                need_separator = true;
         }
         va_end(ap);
 
+        assert(p == r + l);
+
         *p = 0;
         *x = r;
 
index 684af0f3e48e9b49be5cb680a644ba7aa4d855a6..09a737ad3763a0618bd5b9b704237323f4f0bc99 100644 (file)
@@ -179,7 +179,9 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin
 
 char *strip_tab_ansi(char **p, size_t *l);
 
-char *strextend(char **x, ...) _sentinel_;
+char *strextend_with_separator(char **x, const char *separator, ...) _sentinel_;
+
+#define strextend(x, ...) strextend_with_separator(x, NULL, __VA_ARGS__)
 
 char *strrep(const char *s, unsigned n);
 
index 44110b63f9bac036ce3e2a404def71847918d660..953816c46dc7a0a945737cc5879d84feed0b6d3e 100644 (file)
@@ -1733,7 +1733,7 @@ static int help(void) {
                "     --match=MATCH        Only show matching messages\n"
                "     --size=SIZE          Maximum length of captured packet\n"
                "     --list               Don't show tree, but simple object path list\n"
-               "     --quiet              Don't show method call reply\n"
+               "  -q --quiet              Don't show method call reply\n"
                "     --verbose            Show result values in long format\n"
                "     --expect-reply=BOOL  Expect a method call reply\n"
                "     --auto-start=BOOL    Auto-start destination service\n"
index 59a8d60fe3e38df7e52d2e5fad162bf871610df5..62f8ca7731af8a1840974e469230b49ae6736fd8 100644 (file)
@@ -2146,6 +2146,7 @@ fail:
         return r;
 }
 
+#if ENABLE_SMACK
 static int setup_smack(
                 const ExecContext *context,
                 const ExecCommand *command) {
@@ -2176,6 +2177,7 @@ static int setup_smack(
 
         return 0;
 }
+#endif
 
 static int compile_bind_mounts(
                 const ExecContext *context,
@@ -2733,7 +2735,7 @@ static int exec_child(
                 int *exit_status) {
 
         _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL;
-        _cleanup_free_ char *mac_selinux_context_net = NULL, *home_buffer = NULL;
+        _cleanup_free_ char *home_buffer = NULL;
         _cleanup_free_ gid_t *supplementary_gids = NULL;
         const char *username = NULL, *groupname = NULL;
         const char *home = NULL, *shell = NULL;
@@ -2744,6 +2746,7 @@ static int exec_child(
                 needs_mount_namespace,  /* Do we need to set up a mount namespace for this kernel? */
                 needs_ambient_hack;     /* Do we need to apply the ambient capabilities hack? */
 #if HAVE_SELINUX
+        _cleanup_free_ char *mac_selinux_context_net = NULL;
         bool use_selinux = false;
 #endif
 #if ENABLE_SMACK
index 035fa8844bc4f939ec8c0c795bbd64c3f5109ff8..d99176adbe0d672728abcd8df5758f7e18d7321e 100644 (file)
@@ -978,7 +978,6 @@ int config_parse_exec_input_data(
                 void *data,
                 void *userdata) {
 
-        _cleanup_free_ char *cleaned = NULL;
         _cleanup_free_ void *p = NULL;
         ExecContext *c = data;
         size_t sz;
@@ -997,15 +996,9 @@ int config_parse_exec_input_data(
                 return 0;
         }
 
-        /* Be tolerant to whitespace. Remove it all before decoding */
-        cleaned = strdup(rvalue);
-        if (!cleaned)
-                return log_oom();
-        delete_chars(cleaned, WHITESPACE);
-
-        r = unbase64mem(cleaned, (size_t) -1, &p, &sz);
+        r = unbase64mem(rvalue, (size_t) -1, &p, &sz);
         if (r < 0)
-                return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode base64 data, ignoring: %s", cleaned);
+                return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode base64 data, ignoring: %s", rvalue);
 
         assert(sz > 0);
 
index 218f2d8d9ac33ceb5174b7c2efc62b660ac554d3..a3262fcc4da82bb3345d47f4660f22742e0d38bd 100644 (file)
@@ -1155,7 +1155,7 @@ int setup_namespace(
 
         if (root_image) {
                 /* A root image is specified, mount it to the right place */
-                r = dissected_image_mount(dissected_image, root, dissect_image_flags);
+                r = dissected_image_mount(dissected_image, root, UID_INVALID, dissect_image_flags);
                 if (r < 0)
                         goto finish;
 
index e7a829a564f79da24fb68b73d06b61d1425ee0d8..97f129b8f02b51f58e22ee9fabfa987829df437f 100644 (file)
@@ -1493,9 +1493,13 @@ static bool service_shall_restart(Service *s) {
         }
 }
 
-static bool service_will_restart(Service *s) {
+static bool service_will_restart(Unit *u) {
+        Service *s = SERVICE(u);
+
         assert(s);
 
+        if (s->will_auto_restart)
+                return true;
         if (s->state == SERVICE_AUTO_RESTART)
                 return true;
         if (!UNIT(s)->job)
@@ -1521,13 +1525,17 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
         if (s->result != SERVICE_SUCCESS)
                 log_unit_warning(UNIT(s), "Failed with result '%s'.", service_result_to_string(s->result));
 
+        if (allow_restart && service_shall_restart(s))
+                s->will_auto_restart = true;
+
         /* Make sure service_release_resources() doesn't destroy our FD store, while we are changing through
          * SERVICE_FAILED/SERVICE_DEAD before entering into SERVICE_AUTO_RESTART. */
         s->n_keep_fd_store ++;
 
         service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
 
-        if (allow_restart && service_shall_restart(s)) {
+        if (s->will_auto_restart) {
+                s->will_auto_restart = false;
 
                 r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec));
                 if (r < 0) {
@@ -1554,7 +1562,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
         s->exec_runtime = exec_runtime_unref(s->exec_runtime);
 
         if (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_NO ||
-            (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_RESTART && !service_will_restart(s)))
+            (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_RESTART && !service_will_restart(UNIT(s))))
                 /* Also, remove the runtime directory */
                 exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
 
@@ -3772,6 +3780,8 @@ const UnitVTable service_vtable = {
         .active_state = service_active_state,
         .sub_state_to_string = service_sub_state_to_string,
 
+        .will_restart = service_will_restart,
+
         .check_gc = service_check_gc,
 
         .sigchld_event = service_sigchld_event,
index dfe27e894fa2a4c75a15dd272cd66ac9f3437ba9..5c5b24e3efdb6cbd4257e4b9f95981805ba32afa 100644 (file)
@@ -164,6 +164,8 @@ struct Service {
         bool main_pid_alien:1;
         bool bus_name_good:1;
         bool forbid_restart:1;
+        /* Keep restart intention between UNIT_FAILED and UNIT_ACTIVATING */
+        bool will_auto_restart:1;
         bool start_timeout_defined:1;
 
         char *bus_name;
index 1bbe5fdded1f41396f5bca0eb569cbaffa984dad..ed0cf026785cd2aeab81bc8e89291fe52d270b1e 100644 (file)
@@ -2003,7 +2003,7 @@ static void unit_check_unneeded(Unit *u) {
                 void *v;
 
                 HASHMAP_FOREACH_KEY(v, other, u->dependencies[needed_dependencies[j]], i)
-                        if (unit_active_or_pending(other))
+                        if (unit_active_or_pending(other) || unit_will_restart(other))
                                 return;
         }
 
@@ -3794,6 +3794,15 @@ bool unit_active_or_pending(Unit *u) {
         return false;
 }
 
+bool unit_will_restart(Unit *u) {
+        assert(u);
+
+        if (!UNIT_VTABLE(u)->will_restart)
+                return false;
+
+        return UNIT_VTABLE(u)->will_restart(u);
+}
+
 int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) {
         assert(u);
         assert(w >= 0 && w < _KILL_WHO_MAX);
index 92bb4779a9735a5c24ed7a9720bb182d78036900..fdd82315bac5adc37b5af0eee2fb70275d7c681a 100644 (file)
@@ -484,6 +484,9 @@ struct UnitVTable {
          * unit is in. */
         const char* (*sub_state_to_string)(Unit *u);
 
+        /* Additionally to UnitActiveState determine whether unit is to be restarted. */
+        bool (*will_restart)(Unit *u);
+
         /* Return true when there is reason to keep this entry around
          * even nothing references it and it isn't active in any
          * way */
@@ -706,6 +709,7 @@ const char *unit_slice_name(Unit *u);
 bool unit_stop_pending(Unit *u) _pure_;
 bool unit_inactive_or_pending(Unit *u) _pure_;
 bool unit_active_or_pending(Unit *u);
+bool unit_will_restart(Unit *u);
 
 int unit_add_default_target_dependency(Unit *u, Unit *target);
 
index 0210e463720d39cd259796bda4f3190d81555a59..c8fb1c80d720fcea845048033f3cefda0fc1441c 100644 (file)
@@ -29,6 +29,7 @@
 #include "loop-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "user-util.h"
 #include "util.h"
 
 static enum {
@@ -303,7 +304,7 @@ int main(int argc, char *argv[]) {
                 if (r < 0)
                         goto finish;
 
-                r = dissected_image_mount(m, arg_path, arg_flags);
+                r = dissected_image_mount(m, arg_path, UID_INVALID, arg_flags);
                 if (r < 0) {
                         log_error_errno(r, "Failed to mount image: %m");
                         goto finish;
index 68e7c23cbea9cb9a593cd0a11006ebe67ec3f4c5..c0886547e08d5e636fb1b530b4a792d4f3add450 100644 (file)
@@ -820,19 +820,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                         return log_oom();
 
         } else if (streq(key, "rootflags")) {
-                char *o;
 
                 if (proc_cmdline_value_missing(key, value))
                         return 0;
 
-                o = arg_root_options ?
-                        strjoin(arg_root_options, ",", value) :
-                        strdup(value);
-                if (!o)
+                if (!strextend_with_separator(&arg_root_options, ",", value, NULL))
                         return log_oom();
 
-                free(arg_root_options);
-                arg_root_options = o;
         } else if (streq(key, "roothash")) {
 
                 if (proc_cmdline_value_missing(key, value))
@@ -858,20 +852,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                         return log_oom();
 
         } else if (streq(key, "mount.usrflags")) {
-                char *o;
 
                 if (proc_cmdline_value_missing(key, value))
                         return 0;
 
-                o = arg_usr_options ?
-                        strjoin(arg_usr_options, ",", value) :
-                        strdup(value);
-                if (!o)
+                if (!strextend_with_separator(&arg_usr_options, ",", value, NULL))
                         return log_oom();
 
-                free(arg_usr_options);
-                arg_usr_options = o;
-
         } else if (streq(key, "rw") && !value)
                 arg_root_rw = true;
         else if (streq(key, "ro") && !value)
index 8137799ce88788083264e4cb73592d206d04b057..69718aae8757d36fe5da6de40954c2636c3ec592 100644 (file)
@@ -571,8 +571,6 @@ static void help(void) {
                "     --follow[=BOOL]        Do [not] wait for input\n"
                "     --save-state[=FILE]    Save uploaded cursors (default \n"
                "                            " STATE_FILE ")\n"
-               "  -h --help                 Show this help and exit\n"
-               "     --version              Print version string and exit\n"
                , program_invocation_short_name);
 }
 
index dd5f62e824c72892aa58a848507f80d7690c2267..da3647e7e2fe50ece1efd1477a21dfe8f5f2d1c0 100644 (file)
@@ -30,6 +30,7 @@
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
 #include "fstab-util.h"
 #include "mount-util.h"
 #include "pager.h"
@@ -333,19 +334,15 @@ static int parse_argv(int argc, char *argv[]) {
                                 return log_oom();
 
                 } else if (arg_transport == BUS_TRANSPORT_LOCAL) {
-                        _cleanup_free_ char *u = NULL, *p = NULL;
+                        _cleanup_free_ char *u = NULL;
 
                         u = fstab_node_to_udev_node(argv[optind]);
                         if (!u)
                                 return log_oom();
 
-                        r = path_make_absolute_cwd(u, &p);
+                        r = chase_symlinks(u, NULL, 0, &arg_mount_what);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to make path %s absolute: %m", u);
-
-                        arg_mount_what = canonicalize_file_name(p);
-                        if (!arg_mount_what)
-                                return log_error_errno(errno, "Failed to canonicalize path %s: %m", p);
                 } else {
                         arg_mount_what = strdup(argv[optind]);
                         if (!arg_mount_what)
@@ -361,16 +358,9 @@ static int parse_argv(int argc, char *argv[]) {
 
                 if (argc > optind+1) {
                         if (arg_transport == BUS_TRANSPORT_LOCAL) {
-                                _cleanup_free_ char *p = NULL;
-
-                                r = path_make_absolute_cwd(argv[optind+1], &p);
+                                r = chase_symlinks(argv[optind+1], NULL, CHASE_NONEXISTENT, &arg_mount_where);
                                 if (r < 0)
                                         return log_error_errno(r, "Failed to make path %s absolute: %m", argv[optind+1]);
-
-                                arg_mount_where = canonicalize_file_name(p);
-                                if (!arg_mount_where)
-                                        return log_error_errno(errno, "Failed to canonicalize path %s: %m", p);
-
                         } else {
                                 arg_mount_where = strdup(argv[optind+1]);
                                 if (!arg_mount_where)
@@ -829,7 +819,7 @@ static int stop_mount(
 
         r = unit_name_from_path(where, suffix, &mount_unit);
         if (r < 0)
-                return log_error_errno(r, "Failed to make mount unit name from path %s: %m", where);
+                return log_error_errno(r, "Failed to make %s unit name from path %s: %m", suffix + 1, where);
 
         r = sd_bus_message_new_method_call(
                         bus,
@@ -853,8 +843,12 @@ static int stop_mount(
         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
 
         r = sd_bus_call(bus, m, 0, &error, &reply);
-        if (r < 0)
-                return log_error_errno(r, "Failed to stop mount unit: %s", bus_error_message(&error, r));
+        if (r < 0) {
+                if (streq(suffix, ".automount") &&
+                    sd_bus_error_has_name(&error, "org.freedesktop.systemd1.NoSuchUnit"))
+                        return 0;
+                return log_error_errno(r, "Failed to stop %s unit: %s", suffix + 1, bus_error_message(&error, r));
+        }
 
         if (w) {
                 const char *object;
@@ -991,26 +985,19 @@ static int action_umount(
         }
 
         for (i = optind; i < argc; i++) {
-                _cleanup_free_ char *u = NULL, *a = NULL, *p = NULL;
+                _cleanup_free_ char *u = NULL, *p = NULL;
                 struct stat st;
 
                 u = fstab_node_to_udev_node(argv[i]);
                 if (!u)
                         return log_oom();
 
-                r = path_make_absolute_cwd(u, &a);
+                r = chase_symlinks(u, NULL, 0, &p);
                 if (r < 0) {
                         r2 = log_error_errno(r, "Failed to make path %s absolute: %m", argv[i]);
                         continue;
                 }
 
-                p = canonicalize_file_name(a);
-
-                if (!p) {
-                        r2 = log_error_errno(errno, "Failed to canonicalize path %s: %m", argv[i]);
-                        continue;
-                }
-
                 if (stat(p, &st) < 0)
                         return log_error_errno(errno, "Can't stat %s (from %s): %m", p, argv[i]);
 
index 1820f33c2c86190e0887e5b6b5cf39b722dd3cd2..d51585a6524fb7394497cc03ff99d8dc39369e30 100644 (file)
@@ -41,13 +41,15 @@ static int chown_cgroup_path(const char *path, uid_t uid_shift) {
 
         FOREACH_STRING(fn,
                        ".",
-                       "tasks",
-                       "notify_on_release",
-                       "cgroup.procs",
-                       "cgroup.events",
                        "cgroup.clone_children",
                        "cgroup.controllers",
-                       "cgroup.subtree_control")
+                       "cgroup.events",
+                       "cgroup.procs",
+                       "cgroup.stat",
+                       "cgroup.subtree_control",
+                       "cgroup.threads",
+                       "notify_on_release",
+                       "tasks")
                 if (fchownat(fd, fn, uid_shift, uid_shift, 0) < 0)
                         log_full_errno(errno == ENOENT ? LOG_DEBUG :  LOG_WARNING, errno,
                                        "Failed to chown \"%s/%s\", ignoring: %m", path, fn);
@@ -55,7 +57,7 @@ static int chown_cgroup_path(const char *path, uid_t uid_shift) {
         return 0;
 }
 
-int chown_cgroup(pid_t pid, uid_t uid_shift) {
+int chown_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift) {
         _cleanup_free_ char *path = NULL, *fs = NULL;
         int r;
 
@@ -71,6 +73,19 @@ int chown_cgroup(pid_t pid, uid_t uid_shift) {
         if (r < 0)
                 return log_error_errno(r, "Failed to chown() cgroup %s: %m", fs);
 
+        if (unified_requested == CGROUP_UNIFIED_SYSTEMD) {
+                _cleanup_free_ char *lfs = NULL;
+                /* Always propagate access rights from unified to legacy controller */
+
+                r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, NULL, &lfs);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get file system path for container cgroup: %m");
+
+                r = chown_cgroup_path(lfs, uid_shift);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to chown() cgroup %s: %m", lfs);
+        }
+
         return 0;
 }
 
index e66a85484315bf6eda2b962146e793312304ff62..3855e5b4eaafc73a54433d725afb62cc5acb4caa 100644 (file)
@@ -25,6 +25,6 @@
 
 #include "cgroup-util.h"
 
-int chown_cgroup(pid_t pid, uid_t uid_shift);
+int chown_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
 int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
 int create_subcgroup(pid_t pid, CGroupUnified unified_requested);
index 63a55e85ac364f3cb2997bf3f264795ca177d45a..ccf5418ceb67372714d11463dd5fc7dd8e81d948 100644 (file)
@@ -320,7 +320,7 @@ static int custom_mount_check_all(void) {
         return 0;
 }
 
-static int detect_unified_cgroup_hierarchy(const char *directory) {
+static int detect_unified_cgroup_hierarchy_from_environment(void) {
         const char *e;
         int r;
 
@@ -334,11 +334,16 @@ static int detect_unified_cgroup_hierarchy(const char *directory) {
                         arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_ALL;
                 else
                         arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE;
-
-                return 0;
         }
 
-        /* Otherwise inherit the default from the host system */
+        return 0;
+}
+
+static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
+        int r;
+
+        /* Let's inherit the mode to use from the host system, but let's take into consideration what systemd in the
+         * image actually supports. */
         r = cg_all_unified();
         if (r < 0)
                 return log_error_errno(r, "Failed to determine whether we are in all unified mode.");
@@ -364,6 +369,10 @@ static int detect_unified_cgroup_hierarchy(const char *directory) {
         } else
                 arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE;
 
+        log_debug("Using %s hierarchy for container.",
+                  arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_NONE ? "legacy" :
+                  arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_SYSTEMD ? "hybrid" : "unified");
+
         return 0;
 }
 
@@ -2522,6 +2531,7 @@ static int outer_child(
                 int kmsg_socket,
                 int rtnl_socket,
                 int uid_shift_socket,
+                int unified_cgroup_hierarchy_socket,
                 FDSet *fds) {
 
         pid_t pid;
@@ -2572,7 +2582,13 @@ static int outer_child(
                 return r;
 
         if (dissected_image) {
-                r = dissected_image_mount(dissected_image, directory, DISSECT_IMAGE_DISCARD_ON_LOOP|(arg_read_only ? DISSECT_IMAGE_READ_ONLY : 0));
+                /* If we are operating on a disk image, then mount its root directory now, but leave out the rest. We
+                 * can read the UID shift from it if we need to. Further down we'll mount the rest, but then with the
+                 * uid shift known. That way we can mount VFAT file systems shifted to the right place right away. This
+                 * makes sure ESP partitions and userns are compatible. */
+
+                r = dissected_image_mount(dissected_image, directory, arg_uid_shift,
+                                          DISSECT_IMAGE_MOUNT_ROOT_ONLY|DISSECT_IMAGE_DISCARD_ON_LOOP|(arg_read_only ? DISSECT_IMAGE_READ_ONLY : 0));
                 if (r < 0)
                         return r;
         }
@@ -2608,6 +2624,32 @@ static int outer_child(
                 log_info("Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
         }
 
+        if (dissected_image) {
+                /* Now we know the uid shift, let's now mount everything else that might be in the image. */
+                r = dissected_image_mount(dissected_image, directory, arg_uid_shift,
+                                          DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY|DISSECT_IMAGE_DISCARD_ON_LOOP|(arg_read_only ? DISSECT_IMAGE_READ_ONLY : 0));
+                if (r < 0)
+                        return r;
+        }
+
+        if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) {
+                /* OK, we don't know yet which cgroup mode to use yet. Let's figure it out, and tell the parent. */
+
+                r = detect_unified_cgroup_hierarchy_from_image(directory);
+                if (r < 0)
+                        return r;
+
+                l = send(unified_cgroup_hierarchy_socket, &arg_unified_cgroup_hierarchy, sizeof(arg_unified_cgroup_hierarchy), MSG_NOSIGNAL);
+                if (l < 0)
+                        return log_error_errno(errno, "Failed to send cgroup mode: %m");
+                if (l != sizeof(arg_unified_cgroup_hierarchy)) {
+                        log_error("Short write while sending cgroup mode: %m");
+                        return -EIO;
+                }
+
+                unified_cgroup_hierarchy_socket = safe_close(unified_cgroup_hierarchy_socket);
+        }
+
         /* Turn directory into bind mount */
         r = mount_verbose(LOG_ERR, directory, directory, NULL, MS_BIND|MS_REC, NULL);
         if (r < 0)
@@ -3254,7 +3296,9 @@ static int run(int master,
                 pid_socket_pair[2] = { -1, -1 },
                 uuid_socket_pair[2] = { -1, -1 },
                 notify_socket_pair[2] = { -1, -1 },
-                uid_shift_socket_pair[2] = { -1, -1 };
+                uid_shift_socket_pair[2] = { -1, -1 },
+                unified_cgroup_hierarchy_socket_pair[2] = { -1, -1};
+
         _cleanup_close_ int notify_socket= -1;
         _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
         _cleanup_(sd_event_source_unrefp) sd_event_source *notify_event_source = NULL;
@@ -3307,6 +3351,10 @@ static int run(int master,
                 if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0)
                         return log_error_errno(errno, "Failed to create uid shift socket pair: %m");
 
+        if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN)
+                if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, unified_cgroup_hierarchy_socket_pair) < 0)
+                        return log_error_errno(errno, "Failed to create unified cgroup socket pair: %m");
+
         /* Child can be killed before execv(), so handle SIGCHLD in order to interrupt
          * parent's blocking calls and give it a chance to call wait() and terminate. */
         r = sigprocmask(SIG_UNBLOCK, &mask_chld, NULL);
@@ -3335,6 +3383,7 @@ static int run(int master,
                 uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]);
                 notify_socket_pair[0] = safe_close(notify_socket_pair[0]);
                 uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]);
+                unified_cgroup_hierarchy_socket_pair[0] = safe_close(unified_cgroup_hierarchy_socket_pair[0]);
 
                 (void) reset_all_signal_handlers();
                 (void) reset_signal_mask();
@@ -3351,6 +3400,7 @@ static int run(int master,
                                 kmsg_socket_pair[1],
                                 rtnl_socket_pair[1],
                                 uid_shift_socket_pair[1],
+                                unified_cgroup_hierarchy_socket_pair[1],
                                 fds);
                 if (r < 0)
                         _exit(EXIT_FAILURE);
@@ -3368,6 +3418,7 @@ static int run(int master,
         uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]);
         notify_socket_pair[1] = safe_close(notify_socket_pair[1]);
         uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]);
+        unified_cgroup_hierarchy_socket_pair[1] = safe_close(unified_cgroup_hierarchy_socket_pair[1]);
 
         if (arg_userns_mode != USER_NAMESPACE_NO) {
                 /* The child just let us know the UID shift it might have read from the image. */
@@ -3398,6 +3449,17 @@ static int run(int master,
                 }
         }
 
+        if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) {
+                /* The child let us know the support cgroup mode it might have read from the image. */
+                l = recv(unified_cgroup_hierarchy_socket_pair[0], &arg_unified_cgroup_hierarchy, sizeof(arg_unified_cgroup_hierarchy), 0);
+                if (l < 0)
+                        return log_error_errno(errno, "Failed to read cgroup mode: %m");
+                if (l != sizeof(arg_unified_cgroup_hierarchy)) {
+                        log_error("Short read while reading cgroup mode.");
+                        return -EIO;
+                }
+        }
+
         /* Wait for the outer child. */
         r = wait_for_terminate_and_warn("namespace helper", *pid, NULL);
         if (r != 0)
@@ -3557,7 +3619,7 @@ static int run(int master,
                         return r;
         }
 
-        r = chown_cgroup(*pid, arg_uid_shift);
+        r = chown_cgroup(*pid, arg_unified_cgroup_hierarchy, arg_uid_shift);
         if (r < 0)
                 return r;
 
@@ -3736,6 +3798,10 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 goto finish;
 
+        r = detect_unified_cgroup_hierarchy_from_environment();
+        if (r < 0)
+                goto finish;
+
         n_fd_passed = sd_listen_fds(false);
         if (n_fd_passed > 0) {
                 r = fdset_new_listen_fds(&fds, false);
@@ -3983,10 +4049,6 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 goto finish;
 
-        r = detect_unified_cgroup_hierarchy(arg_directory);
-        if (r < 0)
-                goto finish;
-
         interactive =
                 isatty(STDIN_FILENO) > 0 &&
                 isatty(STDOUT_FILENO) > 0;
index 8b44c1ded76561caedb2383541e1209155c3f36e..901b33e39eedd05e68ee0c66f26de69ee63ace06 100644 (file)
@@ -83,6 +83,7 @@ static int resize_btrfs(const char *path, int mountfd, int devfd, uint64_t numbl
         return 0;
 }
 
+#if HAVE_LIBCRYPTSETUP
 static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_devno) {
         char devpath[DEV_NUM_PATH_MAX], main_devpath[DEV_NUM_PATH_MAX];
         _cleanup_close_ int main_devfd = -1;
@@ -127,6 +128,7 @@ static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_
 
         return 1;
 }
+#endif
 
 static int maybe_resize_slave_device(const char *mountpath, dev_t main_devno) {
         dev_t devno;
@@ -134,8 +136,10 @@ static int maybe_resize_slave_device(const char *mountpath, dev_t main_devno) {
         _cleanup_free_ char *fstype = NULL;
         int r;
 
+#if HAVE_LIBCRYPTSETUP
         crypt_set_log_callback(NULL, cryptsetup_log_glue, NULL);
         crypt_set_debug_level(1);
+#endif
 
         r = get_block_device_harder(mountpath, &devno);
         if (r < 0)
@@ -156,8 +160,10 @@ static int maybe_resize_slave_device(const char *mountpath, dev_t main_devno) {
         if (r < 0)
                 return log_warning_errno(r, "Failed to probe \"%s\": %m", devpath);
 
+#if HAVE_LIBCRYPTSETUP
         if (streq_ptr(fstype, "crypto_LUKS"))
                 return resize_crypt_luks_device(devno, fstype, main_devno);
+#endif
 
         log_debug("Don't know how to resize %s of type %s, ignoring", devpath, strnull(fstype));
         return 0;
index aa722c304a08fe1b60e467db30bf55078ebb6286..0481293a50c14abb7f5c1717321da03ffd11d53f 100644 (file)
@@ -419,12 +419,14 @@ static int verify_esp(
                 uint64_t *ret_pstart,
                 uint64_t *ret_psize,
                 sd_id128_t *ret_uuid) {
-
+#if HAVE_BLKID
         _cleanup_blkid_free_probe_ blkid_probe b = NULL;
         char t[DEV_NUM_PATH_MAX];
+        const char *v;
+#endif
         uint64_t pstart = 0, psize = 0;
         struct stat st, st2;
-        const char *v, *t2;
+        const char *t2;
         struct statfs sfs;
         sd_id128_t uuid = SD_ID128_NULL;
         uint32_t part = 0;
@@ -479,6 +481,7 @@ static int verify_esp(
         if (detect_container() > 0 || geteuid() != 0)
                 goto finish;
 
+#if HAVE_BLKID
         xsprintf_dev_num_path(t, "block", st.st_dev);
         errno = 0;
         b = blkid_new_probe_from_filename(t);
@@ -561,6 +564,7 @@ static int verify_esp(
         r = safe_atou64(v, &psize);
         if (r < 0)
                 return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
+#endif
 
 finish:
         if (ret_part)
index cfd4c833b0b30671de178920cd4ef2d992edbba8..6ed0085953799cae98b827a81fcab2f610fc5f43 100644 (file)
@@ -415,19 +415,12 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
                 r = sd_bus_message_append(m, "v", "s", eq);
 
         else if (streq(field, "StandardInputData")) {
-                _cleanup_free_ char *cleaned = NULL;
                 _cleanup_free_ void *decoded = NULL;
                 size_t sz;
 
-                cleaned = strdup(eq);
-                if (!cleaned)
-                        return log_oom();
-
-                delete_chars(cleaned, WHITESPACE);
-
-                r = unbase64mem(cleaned, (size_t) -1, &decoded, &sz);
+                r = unbase64mem(eq, (size_t) -1, &decoded, &sz);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to decode base64 data '%s': %m", cleaned);
+                        return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
 
                 r = sd_bus_message_open_container(m, 'v', "ay");
                 if (r < 0)
index 7835d99020b6d71768408fc64019630b2b17f090..8789fd163ab809fee887d7cbef27f1ba9b5cd7d1 100644 (file)
@@ -49,6 +49,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "udev-util.h"
+#include "user-util.h"
 #include "xattr-util.h"
 
 int probe_filesystem(const char *node, char **ret_fstype) {
@@ -686,10 +687,11 @@ static int mount_partition(
                 DissectedPartition *m,
                 const char *where,
                 const char *directory,
+                uid_t uid_shift,
                 DissectImageFlags flags) {
 
-        const char *p, *options = NULL, *node, *fstype;
-        _cleanup_free_ char *chased = NULL;
+        _cleanup_free_ char *chased = NULL, *options = NULL;
+        const char *p, *node, *fstype;
         bool rw;
         int r;
 
@@ -720,13 +722,26 @@ static int mount_partition(
         /* If requested, turn on discard support. */
         if (fstype_can_discard(fstype) &&
             ((flags & DISSECT_IMAGE_DISCARD) ||
-             ((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node))))
-                options = "discard";
+             ((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node)))) {
+                options = strdup("discard");
+                if (!options)
+                        return -ENOMEM;
+        }
+
+        if (uid_is_valid(uid_shift) && uid_shift != 0 && fstype_can_uid_gid(fstype)) {
+                _cleanup_free_ char *uid_option = NULL;
+
+                if (asprintf(&uid_option, "uid=" UID_FMT ",gid=" GID_FMT, uid_shift, (gid_t) uid_shift) < 0)
+                        return -ENOMEM;
+
+                if (!strextend_with_separator(&options, ",", uid_option, NULL))
+                        return -ENOMEM;
+        }
 
         return mount_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options);
 }
 
-int dissected_image_mount(DissectedImage *m, const char *where, DissectImageFlags flags) {
+int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags) {
         int r;
 
         assert(m);
@@ -735,15 +750,20 @@ int dissected_image_mount(DissectedImage *m, const char *where, DissectImageFlag
         if (!m->partitions[PARTITION_ROOT].found)
                 return -ENXIO;
 
-        r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL, flags);
-        if (r < 0)
-                return r;
+        if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0) {
+                r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL, uid_shift, flags);
+                if (r < 0)
+                        return r;
+        }
 
-        r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", flags);
+        if ((flags & DISSECT_IMAGE_MOUNT_ROOT_ONLY))
+                return 0;
+
+        r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", uid_shift, flags);
         if (r < 0)
                 return r;
 
-        r = mount_partition(m->partitions + PARTITION_SRV, where, "/srv", flags);
+        r = mount_partition(m->partitions + PARTITION_SRV, where, "/srv", uid_shift, flags);
         if (r < 0)
                 return r;
 
@@ -761,7 +781,7 @@ int dissected_image_mount(DissectedImage *m, const char *where, DissectImageFlag
 
                         r = dir_is_empty(p);
                         if (r > 0) {
-                                r = mount_partition(m->partitions + PARTITION_ESP, where, mp, flags);
+                                r = mount_partition(m->partitions + PARTITION_ESP, where, mp, uid_shift, flags);
                                 if (r < 0)
                                         return r;
                         }
@@ -976,8 +996,8 @@ int dissected_image_decrypt(
                 DissectImageFlags flags,
                 DecryptedImage **ret) {
 
-        _cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
 #if HAVE_LIBCRYPTSETUP
+        _cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
         unsigned i;
         int r;
 #endif
@@ -1254,7 +1274,7 @@ int dissected_image_acquire_metadata(DissectedImage *m) {
                 if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0)
                         _exit(EXIT_FAILURE);
 
-                r = dissected_image_mount(m, t, DISSECT_IMAGE_READ_ONLY);
+                r = dissected_image_mount(m, t, UID_INVALID, DISSECT_IMAGE_READ_ONLY);
                 if (r < 0)
                         _exit(EXIT_FAILURE);
 
index 7c7ce46015b21c75e9d38aed7745dfcb78e55884..53a1554a2879b1e35d5444eec221b9e6e9c6adb0 100644 (file)
@@ -62,15 +62,17 @@ static inline int PARTITION_VERITY_OF(int p) {
 }
 
 typedef enum DissectImageFlags {
-        DISSECT_IMAGE_READ_ONLY = 1,
-        DISSECT_IMAGE_DISCARD_ON_LOOP = 2,   /* Turn on "discard" if on a loop device and file system supports it */
-        DISSECT_IMAGE_DISCARD = 4,           /* Turn on "discard" if file system supports it, on all block devices */
-        DISSECT_IMAGE_DISCARD_ON_CRYPTO = 8, /* Turn on "discard" also on crypto devices */
+        DISSECT_IMAGE_READ_ONLY           = 1 << 0,
+        DISSECT_IMAGE_DISCARD_ON_LOOP     = 1 << 1,  /* Turn on "discard" if on a loop device and file system supports it */
+        DISSECT_IMAGE_DISCARD             = 1 << 2,  /* Turn on "discard" if file system supports it, on all block devices */
+        DISSECT_IMAGE_DISCARD_ON_CRYPTO   = 1 << 3,  /* Turn on "discard" also on crypto devices */
         DISSECT_IMAGE_DISCARD_ANY = DISSECT_IMAGE_DISCARD_ON_LOOP |
                                     DISSECT_IMAGE_DISCARD |
                                     DISSECT_IMAGE_DISCARD_ON_CRYPTO,
-        DISSECT_IMAGE_GPT_ONLY = 16,         /* Only recognize images with GPT partition tables */
-        DISSECT_IMAGE_REQUIRE_ROOT = 32,     /* Don't accept disks without root partition */
+        DISSECT_IMAGE_GPT_ONLY            = 1 << 4,  /* Only recognize images with GPT partition tables */
+        DISSECT_IMAGE_REQUIRE_ROOT        = 1 << 5,  /* Don't accept disks without root partition */
+        DISSECT_IMAGE_MOUNT_ROOT_ONLY     = 1 << 6,  /* Mount only the root partition */
+        DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7,  /* Mount only non-root partitions */
 } DissectImageFlags;
 
 struct DissectedImage {
@@ -94,7 +96,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
 
 int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret);
 int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret);
-int dissected_image_mount(DissectedImage *m, const char *dest, DissectImageFlags flags);
+int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, DissectImageFlags flags);
 
 int dissected_image_acquire_metadata(DissectedImage *m);
 
index e8b977e9e46966d9cb349c686339cf1382c28b33..4c099990ed627a4254c2657d9987d52fcb09f413 100644 (file)
@@ -44,7 +44,7 @@ static int help(void) {
                "STDIO or socket-activatable proxy to a given DBus endpoint.\n\n"
                "  -h --help              Show this help\n"
                "     --version           Show package version\n"
-               "     --bus-path=PATH     Path to the kernel bus (default: %s)\n",
+               "  -p --bus-path=PATH     Path to the kernel bus (default: %s)\n",
                program_invocation_short_name, DEFAULT_BUS_PATH);
 
         return 0;
@@ -57,9 +57,10 @@ static int parse_argv(int argc, char *argv[]) {
         };
 
         static const struct option options[] = {
-                { "help",            no_argument,       NULL, 'h'     },
-                { "bus-path",        required_argument, NULL, 'p'     },
-                { NULL,              0,                 NULL, 0       }
+                { "help",            no_argument,       NULL, 'h'         },
+                { "version",         no_argument,       NULL, ARG_VERSION },
+                { "bus-path",        required_argument, NULL, 'p'         },
+                {},
         };
 
         int c;
index efaa259d763bc567cde11fd99e8e1364466be344..327c2859e8592799cf5ce21de65b9c4102144c6c 100644 (file)
@@ -155,7 +155,8 @@ tests += [
 
         [['src/test/test-async.c'],
          [],
-         []],
+         [],
+         '', 'timeout=120'],
 
         [['src/test/test-locale-util.c'],
          [],
index 83ddc398b8834239418245c7db6774753974b309..86d963c4c788124d3c0dc5f664719dde7bdeffca 100644 (file)
@@ -168,6 +168,26 @@ static void test_chase_symlinks(void) {
         assert_se(r > 0 && path_equal(result, "/etc"));
         result = mfree(result);
 
+        r = chase_symlinks("/../.././//../../etc", NULL, 0, &result);
+        assert_se(r > 0);
+        assert_se(streq(result, "/etc"));
+        result = mfree(result);
+
+        r = chase_symlinks("/../.././//../../test-chase.fsldajfl", NULL, CHASE_NONEXISTENT, &result);
+        assert_se(r == 0);
+        assert_se(streq(result, "/test-chase.fsldajfl"));
+        result = mfree(result);
+
+        r = chase_symlinks("/../.././//../../etc", "/", CHASE_PREFIX_ROOT, &result);
+        assert_se(r > 0);
+        assert_se(streq(result, "/etc"));
+        result = mfree(result);
+
+        r = chase_symlinks("/../.././//../../test-chase.fsldajfl", "/", CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &result);
+        assert_se(r == 0);
+        assert_se(streq(result, "/test-chase.fsldajfl"));
+        result = mfree(result);
+
         r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result);
         assert_se(r == -ENOTDIR);
         result = mfree(result);
@@ -242,6 +262,7 @@ static void test_readlink_and_make_absolute(void) {
         char name2[] = "test-readlink_and_make_absolute/original";
         char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias";
         char *r = NULL;
+        _cleanup_free_ char *pwd = NULL;
 
         assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid(), false) >= 0);
         assert_se(touch(name) >= 0);
@@ -252,6 +273,8 @@ static void test_readlink_and_make_absolute(void) {
         free(r);
         assert_se(unlink(name_alias) >= 0);
 
+        assert_se(pwd = get_current_dir_name());
+
         assert_se(chdir(tempdir) >= 0);
         assert_se(symlink(name2, name_alias) >= 0);
         assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
@@ -259,6 +282,8 @@ static void test_readlink_and_make_absolute(void) {
         free(r);
         assert_se(unlink(name_alias) >= 0);
 
+        assert_se(chdir(pwd) >= 0);
+
         assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
 }
 
index 5767baebb13ca38ede3f52ecbb5422bda92e041a..7675d0cba72776ec3206e6c37ddee091d9ba7d9a 100644 (file)
@@ -301,42 +301,43 @@ static void test_base64mem(void) {
         free(b64);
 }
 
-static void test_unbase64mem(void) {
-        void *mem;
-        size_t len;
-
-        assert_se(unbase64mem("", strlen(""), &mem, &len) == 0);
-        assert_se(streq(strndupa(mem, len), ""));
-        free(mem);
+static void test_unbase64mem_one(const char *input, const char *output, int ret) {
+        _cleanup_free_ void *buffer = NULL;
+        size_t size = 0;
 
-        assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0);
-        assert_se(streq(strndupa(mem, len), "f"));
-        free(mem);
-
-        assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0);
-        assert_se(streq(strndupa(mem, len), "fo"));
-        free(mem);
+        assert_se(unbase64mem(input, (size_t) -1, &buffer, &size) == ret);
 
-        assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0);
-        assert_se(streq(strndupa(mem, len), "foo"));
-        free(mem);
-
-        assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0);
-        assert_se(streq(strndupa(mem, len), "foob"));
-        free(mem);
-
-        assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0);
-        assert_se(streq(strndupa(mem, len), "fooba"));
-        free(mem);
+        if (ret >= 0) {
+                assert_se(size == strlen(output));
+                assert_se(memcmp(buffer, output, size) == 0);
+                assert_se(((char*) buffer)[size] == 0);
+        }
+}
 
-        assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0);
-        assert_se(streq(strndupa(mem, len), "foobar"));
-        free(mem);
+static void test_unbase64mem(void) {
 
-        assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL);
-        assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL);
-        assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL);
-        assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL);
+        test_unbase64mem_one("", "", 0);
+        test_unbase64mem_one("Zg==", "f", 0);
+        test_unbase64mem_one("Zm8=", "fo", 0);
+        test_unbase64mem_one("Zm9v", "foo", 0);
+        test_unbase64mem_one("Zm9vYg==", "foob", 0);
+        test_unbase64mem_one("Zm9vYmE=", "fooba", 0);
+        test_unbase64mem_one("Zm9vYmFy", "foobar", 0);
+
+        test_unbase64mem_one(" ", "", 0);
+        test_unbase64mem_one(" \n\r ", "", 0);
+        test_unbase64mem_one("    Zg\n==       ", "f", 0);
+        test_unbase64mem_one(" Zm 8=\r", "fo", 0);
+        test_unbase64mem_one("  Zm9\n\r\r\nv   ", "foo", 0);
+        test_unbase64mem_one(" Z m9vYg==\n\r", "foob", 0);
+        test_unbase64mem_one(" Zm 9vYmE=   ", "fooba", 0);
+        test_unbase64mem_one("   Z m9v    YmFy   ", "foobar", 0);
+
+        test_unbase64mem_one("A", NULL, -EPIPE);
+        test_unbase64mem_one("A====", NULL, -EINVAL);
+        test_unbase64mem_one("AAB==", NULL, -EINVAL);
+        test_unbase64mem_one(" A A A B = ", NULL, -EINVAL);
+        test_unbase64mem_one(" Z m 8 = q u u x ", NULL, -ENAMETOOLONG);
 }
 
 static void test_hexdump(void) {
index 7a14b8efd38a754f522cfcd032f89ad041073aac..07ee98465c63e933d330e53e557671030136bb38 100644 (file)
@@ -104,9 +104,37 @@ static void test_strstrip(void) {
 }
 
 static void test_strextend(void) {
-        _cleanup_free_ char *str = strdup("0123");
-        strextend(&str, "456", "78", "9", NULL);
-        assert_se(streq(str, "0123456789"));
+        _cleanup_free_ char *str = NULL;
+
+        assert_se(strextend(&str, NULL));
+        assert_se(streq_ptr(str, ""));
+        assert_se(strextend(&str, "", "0", "", "", "123", NULL));
+        assert_se(streq_ptr(str, "0123"));
+        assert_se(strextend(&str, "456", "78", "9", NULL));
+        assert_se(streq_ptr(str, "0123456789"));
+}
+
+static void test_strextend_with_separator(void) {
+        _cleanup_free_ char *str = NULL;
+
+        assert_se(strextend_with_separator(&str, NULL, NULL));
+        assert_se(streq_ptr(str, ""));
+        str = mfree(str);
+
+        assert_se(strextend_with_separator(&str, "...", NULL));
+        assert_se(streq_ptr(str, ""));
+        assert_se(strextend_with_separator(&str, "...", NULL));
+        assert_se(streq_ptr(str, ""));
+        str = mfree(str);
+
+        assert_se(strextend_with_separator(&str, "xyz", "a", "bb", "ccc", NULL));
+        assert_se(streq_ptr(str, "axyzbbxyzccc"));
+        str = mfree(str);
+
+        assert_se(strextend_with_separator(&str, ",", "start", "", "1", "234", NULL));
+        assert_se(streq_ptr(str, "start,,1,234"));
+        assert_se(strextend_with_separator(&str, ";", "more", "5", "678", NULL));
+        assert_se(streq_ptr(str, "start,,1,234;more;5;678"));
 }
 
 static void test_strrep(void) {
@@ -399,6 +427,7 @@ int main(int argc, char *argv[]) {
         test_streq_ptr();
         test_strstrip();
         test_strextend();
+        test_strextend_with_separator();
         test_strrep();
         test_strappend();
         test_string_has_cc();
index 735deab2525cc77372846ae4f04aebabe1a54da9..ab9237ff7857010610a03e1179cfe50ef8abb2f3 100644 (file)
 #include "time-util.h"
 #include "udev-util.h"
 #include "udev.h"
+#include "udevadm-util.h"
 
 static void print_help(void) {
-        printf("%s control COMMAND\n\n"
+        printf("%s control OPTION\n\n"
                "Control the udev daemon.\n\n"
                "  -h --help                Show this help\n"
-               "     --version             Show package version\n"
+               "  -V --version             Show package version\n"
                "  -e --exit                Instruct the daemon to cleanup and exit\n"
                "  -l --log-priority=LEVEL  Set the udev log level for the daemon\n"
                "  -s --stop-exec-queue     Do not execute events, queue only\n"
@@ -37,7 +38,7 @@ static void print_help(void) {
                "  -R --reload              Reload rules and databases\n"
                "  -p --property=KEY=VALUE  Set a global property for all events\n"
                "  -m --children-max=N      Maximum number of children\n"
-               "     --timeout=SECONDS     Maximum time to block for a reply\n"
+               "  -t --timeout=SECONDS     Maximum time to block for a reply\n"
                , program_invocation_short_name);
 }
 
@@ -57,6 +58,7 @@ static int adm_control(struct udev *udev, int argc, char *argv[]) {
                 { "env",              required_argument, NULL, 'p' }, /* alias for -p */
                 { "children-max",     required_argument, NULL, 'm' },
                 { "timeout",          required_argument, NULL, 't' },
+                { "version",          no_argument,       NULL, 'V' },
                 { "help",             no_argument,       NULL, 'h' },
                 {}
         };
@@ -70,7 +72,7 @@ static int adm_control(struct udev *udev, int argc, char *argv[]) {
         if (uctrl == NULL)
                 return 2;
 
-        while ((c = getopt_long(argc, argv, "el:sSRp:m:h", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "el:sSRp:m:t:Vh", options, NULL)) >= 0)
                 switch (c) {
                 case 'e':
                         if (udev_ctrl_send_exit(uctrl, timeout) < 0)
@@ -153,6 +155,10 @@ static int adm_control(struct udev *udev, int argc, char *argv[]) {
                         }
                         break;
                 }
+                case 'V':
+                        print_version();
+                        rc = 0;
+                        break;
                 case 'h':
                         print_help();
                         rc = 0;
index ba7a15e6e9d07b7c9256ab3b68c86bbd6e90d2fc..ab5dc7ab6420102be14e868a125fe748854afbfb 100644 (file)
@@ -34,6 +34,7 @@
 #include "strbuf.h"
 #include "string-util.h"
 #include "udev.h"
+#include "udevadm-util.h"
 #include "util.h"
 
 /*
@@ -546,12 +547,17 @@ static int import_file(struct udev *udev, struct trie *trie, const char *filenam
 }
 
 static void help(void) {
-        printf("Usage: udevadm hwdb OPTIONS\n"
-               "  -u,--update          update the hardware database\n"
-               "  --usr                generate in " UDEVLIBEXECDIR " instead of /etc/udev\n"
-               "  -t,--test=MODALIAS   query database and print result\n"
-               "  -r,--root=PATH       alternative root path in the filesystem\n"
-               "  -h,--help\n\n");
+        printf("%s hwdb [OPTIONS]\n\n"
+               "  -h --help            Print this message\n"
+               "  -V --version         Print version of the program\n"
+               "  -u --update          Update the hardware database\n"
+               "     --usr             Generate in " UDEVLIBEXECDIR " instead of /etc/udev\n"
+               "  -t --test=MODALIAS   Query database and print result\n"
+               "  -r --root=PATH       Alternative root path in the filesystem\n\n"
+               "NOTE:\n"
+               "The sub-command 'hwdb' is deprecated, and is left for backwards compatibility.\n"
+               "Please use systemd-hwdb instead.\n"
+               , program_invocation_short_name);
 }
 
 static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
@@ -560,11 +566,12 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
         };
 
         static const struct option options[] = {
-                { "update", no_argument,       NULL, 'u' },
-                { "usr",    no_argument,       NULL, ARG_USR },
-                { "test",   required_argument, NULL, 't' },
-                { "root",   required_argument, NULL, 'r' },
-                { "help",   no_argument,       NULL, 'h' },
+                { "update",  no_argument,       NULL, 'u'     },
+                { "usr",     no_argument,       NULL, ARG_USR },
+                { "test",    required_argument, NULL, 't'     },
+                { "root",    required_argument, NULL, 'r'     },
+                { "version", no_argument,       NULL, 'V'     },
+                { "help",    no_argument,       NULL, 'h'     },
                 {}
         };
         const char *test = NULL;
@@ -575,7 +582,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
         int err, c;
         int rc = EXIT_SUCCESS;
 
-        while ((c = getopt_long(argc, argv, "ut:r:h", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "ut:r:Vh", options, NULL)) >= 0)
                 switch(c) {
                 case 'u':
                         update = true;
@@ -589,6 +596,9 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
                 case 'r':
                         root = optarg;
                         break;
+                case 'V':
+                        print_version();
+                        return EXIT_SUCCESS;
                 case 'h':
                         help();
                         return EXIT_SUCCESS;
index df7fbc21ae26c51a3fd6a81f8b1badf8a834c531..396ccfb4e2047baafa2c3734d9b8df0b4e1943c6 100644 (file)
@@ -250,7 +250,7 @@ static void help(void) {
         printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
                "Query sysfs or the udev database.\n\n"
                "  -h --help                   Print this message\n"
-               "     --version                Print version of the program\n"
+               "  -V --version                Print version of the program\n"
                "  -q --query=TYPE             Query device information:\n"
                "       name                     Name of device node\n"
                "       symlink                  Pointing to node\n"
@@ -377,7 +377,7 @@ static int uinfo(struct udev *udev, int argc, char *argv[]) {
                         export_prefix = optarg;
                         break;
                 case 'V':
-                        printf("%s\n", PACKAGE_VERSION);
+                        print_version();
                         return 0;
                 case 'h':
                         help();
index c8b85fb0f4c218f5d60b274ae202b539dfc47741..028ef92bc2e79ccb355fde21d1e5cc6db9d55141 100644 (file)
@@ -30,6 +30,7 @@
 #include "format-util.h"
 #include "udev-util.h"
 #include "udev.h"
+#include "udevadm-util.h"
 
 static bool udev_exit;
 
@@ -60,10 +61,10 @@ static void print_device(struct udev_device *device, const char *source, int pro
 }
 
 static void help(void) {
-        printf("%s monitor [--property] [--kernel] [--udev] [--help]\n\n"
+        printf("%s monitor [OPTIONS]\n\n"
                "Listen to kernel and udev events.\n\n"
                "  -h --help                                Show this help\n"
-               "     --version                             Show package version\n"
+               "  -V --version                             Show package version\n"
                "  -p --property                            Print the event properties\n"
                "  -k --kernel                              Print kernel uevents\n"
                "  -u --udev                                Print udev events\n"
@@ -94,6 +95,7 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) {
                 { "udev",            no_argument,       NULL, 'u' },
                 { "subsystem-match", required_argument, NULL, 's' },
                 { "tag-match",       required_argument, NULL, 't' },
+                { "version",         no_argument,       NULL, 'V' },
                 { "help",            no_argument,       NULL, 'h' },
                 {}
         };
@@ -101,7 +103,7 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) {
         udev_list_init(udev, &subsystem_match_list, true);
         udev_list_init(udev, &tag_match_list, true);
 
-        while ((c = getopt_long(argc, argv, "pekus:t:h", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "pekus:t:Vh", options, NULL)) >= 0)
                 switch (c) {
                 case 'p':
                 case 'e':
@@ -130,6 +132,9 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) {
                 case 't':
                         udev_list_entry_add(&tag_match_list, optarg, NULL);
                         break;
+                case 'V':
+                        print_version();
+                        return 0;
                 case 'h':
                         help();
                         return 0;
index d72b6ffe208b43d1a11f0ac8278536dbe92ce92d..0af3e6412b0c72d3be977edd67e8575dfbae221f 100644 (file)
 
 #include "parse-util.h"
 #include "udev.h"
+#include "udevadm-util.h"
 #include "util.h"
 
 static void help(void) {
-        printf("%s settle OPTIONS\n\n"
+        printf("%s settle [OPTIONS]\n\n"
                "Wait for pending udev events.\n\n"
                "  -h --help                 Show this help\n"
-               "     --version              Show package version\n"
+               "  -V --version              Show package version\n"
                "  -t --timeout=SECONDS      Maximum time to wait for events\n"
                "  -E --exit-if-exists=FILE  Stop waiting if file exists\n"
                , program_invocation_short_name);
@@ -45,6 +46,7 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) {
         static const struct option options[] = {
                 { "timeout",        required_argument, NULL, 't' },
                 { "exit-if-exists", required_argument, NULL, 'E' },
+                { "version",        no_argument,       NULL, 'V' },
                 { "help",           no_argument,       NULL, 'h' },
                 { "seq-start",      required_argument, NULL, 's' }, /* removed */
                 { "seq-end",        required_argument, NULL, 'e' }, /* removed */
@@ -59,7 +61,7 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) {
         struct udev_queue *queue;
         int rc = EXIT_FAILURE;
 
-        while ((c = getopt_long(argc, argv, "t:E:hs:e:q", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "t:E:Vhs:e:q", options, NULL)) >= 0) {
                 switch (c) {
 
                 case 't': {
@@ -77,6 +79,10 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) {
                         exists = optarg;
                         break;
 
+                case 'V':
+                        print_version();
+                        return EXIT_SUCCESS;
+
                 case 'h':
                         help();
                         return EXIT_SUCCESS;
index 2cdbec050f0309bb517a3ece115bc33bb11f873a..f5a39a11c11c7094977f0979f86fedfa6b118b13 100644 (file)
 #include "path-util.h"
 #include "string-util.h"
 #include "udev.h"
+#include "udevadm-util.h"
 
 static void help(struct udev *udev) {
-        printf("%s builtin [--help] COMMAND SYSPATH\n\n"
+        printf("%s test-builtin [OPTIONS] COMMAND DEVPATH\n\n"
                "Test a built-in command.\n\n"
                "  -h --help     Print this message\n"
-               "     --version  Print version of the program\n\n"
+               "  -V --version  Print version of the program\n\n"
                "Commands:\n"
                , program_invocation_short_name);
 
@@ -39,7 +40,8 @@ static void help(struct udev *udev) {
 
 static int adm_builtin(struct udev *udev, int argc, char *argv[]) {
         static const struct option options[] = {
-                { "help", no_argument, NULL, 'h' },
+                { "version", no_argument, NULL, 'V' },
+                { "help",    no_argument, NULL, 'h' },
                 {}
         };
         char *command = NULL;
@@ -49,8 +51,11 @@ static int adm_builtin(struct udev *udev, int argc, char *argv[]) {
         enum udev_builtin_cmd cmd;
         int rc = EXIT_SUCCESS, c;
 
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "Vh", options, NULL)) >= 0)
                 switch (c) {
+                case 'V':
+                        print_version();
+                        goto out;
                 case 'h':
                         help(udev);
                         goto out;
index 6d20987fa2ea5440486ee3e5bd99bc65392e10ec..ef1f2f0269a257269a6c5c6d057ca5e374e8913d 100644 (file)
 #include "string-util.h"
 #include "udev-util.h"
 #include "udev.h"
+#include "udevadm-util.h"
 
 static void help(void) {
 
-        printf("%s test OPTIONS <syspath>\n\n"
-               "Test an event run.\n"
+        printf("%s test [OPTIONS] DEVPATH\n\n"
+               "Test an event run.\n\n"
                "  -h --help                            Show this help\n"
-               "     --version                         Show package version\n"
+               "  -V --version                         Show package version\n"
                "  -a --action=ACTION                   Set action string\n"
                "  -N --resolve-names=early|late|never  When to resolve names\n"
                , program_invocation_short_name);
@@ -54,15 +55,16 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
         int rc = 0, c;
 
         static const struct option options[] = {
-                { "action", required_argument, NULL, 'a' },
+                { "action",        required_argument, NULL, 'a' },
                 { "resolve-names", required_argument, NULL, 'N' },
-                { "help", no_argument, NULL, 'h' },
+                { "version",       no_argument,       NULL, 'V' },
+                { "help",          no_argument,       NULL, 'h' },
                 {}
         };
 
         log_debug("version %s", PACKAGE_VERSION);
 
-        while ((c = getopt_long(argc, argv, "a:N:h", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "a:N:Vh", options, NULL)) >= 0)
                 switch (c) {
                 case 'a':
                         action = optarg;
@@ -80,6 +82,9 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
                                 exit(EXIT_FAILURE);
                         }
                         break;
+                case 'V':
+                        print_version();
+                        exit(EXIT_SUCCESS);
                 case 'h':
                         help();
                         exit(EXIT_SUCCESS);
index 23aaa474233f96f69a54009586c78993eaaa55cf..f78a2ba4373eb11466750831ac5dcf4c99d94791 100644 (file)
@@ -68,10 +68,10 @@ static const char *keyval(const char *str, const char **val, char *buf, size_t s
 }
 
 static void help(void) {
-        printf("%s trigger OPTIONS\n\n"
+        printf("%s trigger [OPTIONS] DEVPATH\n\n"
                "Request events from the kernel.\n\n"
                "  -h --help                         Show this help\n"
-               "     --version                      Show package version\n"
+               "  -V --version                      Show package version\n"
                "  -v --verbose                      Print the list of devices while running\n"
                "  -n --dry-run                      Do not actually trigger the events\n"
                "  -t --type=                        Type of events to trigger\n"
@@ -109,6 +109,7 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
                 { "sysname-match",     required_argument, NULL, 'y'      },
                 { "name-match",        required_argument, NULL, ARG_NAME },
                 { "parent-match",      required_argument, NULL, 'b'      },
+                { "version",           no_argument,       NULL, 'V'      },
                 { "help",              no_argument,       NULL, 'h'      },
                 {}
         };
@@ -124,7 +125,7 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
         if (udev_enumerate == NULL)
                 return 1;
 
-        while ((c = getopt_long(argc, argv, "vno:t:c:s:S:a:A:p:g:y:b:h", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "vnt:c:s:S:a:A:p:g:y:b:Vh", options, NULL)) >= 0) {
                 const char *key;
                 const char *val;
                 char buf[UTIL_PATH_SIZE];
@@ -240,6 +241,9 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
                         break;
                 }
 
+                case 'V':
+                        print_version();
+                        return 0;
                 case 'h':
                         help();
                         return 0;
index 7963acaa53e344acfa3d40d9ab0338c69e406e83..8262a8343f77b81421d9a0cb168b5403da65bb2c 100644 (file)
@@ -23,3 +23,7 @@
 struct udev_device *find_device(struct udev *udev,
                                 const char *id,
                                 const char *prefix);
+
+static inline void print_version(void) {
+        printf("%s\n", PACKAGE_VERSION);
+}
index e2c7f99cd4f63869e7b8639ba2777bf7294a4e03..38ced53676394f9ba44ae1aca103ce3ca630a192 100644 (file)
@@ -1407,13 +1407,13 @@ static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Manages devices.\n\n"
                "  -h --help                   Print this message\n"
-               "     --version                Print version of the program\n"
-               "     --daemon                 Detach and run in the background\n"
-               "     --debug                  Enable debug output\n"
-               "     --children-max=INT       Set maximum number of workers\n"
-               "     --exec-delay=SECONDS     Seconds to wait before executing RUN=\n"
-               "     --event-timeout=SECONDS  Seconds to wait before terminating an event\n"
-               "     --resolve-names=early|late|never\n"
+               "  -V --version                Print version of the program\n"
+               "  -d --daemon                 Detach and run in the background\n"
+               "  -D --debug                  Enable debug output\n"
+               "  -c --children-max=INT       Set maximum number of workers\n"
+               "  -e --exec-delay=SECONDS     Seconds to wait before executing RUN=\n"
+               "  -t --event-timeout=SECONDS  Seconds to wait before terminating an event\n"
+               "  -N --resolve-names=early|late|never\n"
                "                              When to resolve users and groups\n"
                , program_invocation_short_name);
 }
index edaa3d91b0ec5b78dac22a0492d5d8b7da3affe8..78b764bdefef258ea7fc7e3b25902cd413613750 100644 (file)
@@ -35,4 +35,4 @@ g tape    -     -            -
 g video   -     -            -
 
 # Default group for normal users
-g users   -     -            -
+g users   @USERS_GID@     -            -
index e7eb1cb303c2aa1fbf9b26f564de969bf9460e25..2f95e9062daeca95450007f7d822dda278b3fa7a 100755 (executable)
@@ -3,7 +3,6 @@
 # ex: ts=8 sw=4 sts=4 et filetype=sh
 set -e
 TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/2467"
-TEST_NO_NSPAWN=1
 
 . $TEST_BASE_DIR/test-functions
 SKIP_INITRD=yes
@@ -19,7 +18,7 @@ test_setup() {
         eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
 
         setup_basic_environment
-        dracut_install nc true rm
+        dracut_install true rm
 
         # setup the testsuite service
         cat >$initdir/etc/systemd/system/testsuite.service <<'EOF'
@@ -29,13 +28,15 @@ After=multi-user.target
 
 [Service]
 Type=oneshot
-ExecStart=/bin/sh -e -x -c 'rm -f /tmp/nonexistent; systemctl start test.socket; echo a | nc -U /run/test.ctl; >/testok'
+StandardOutput=tty
+StandardError=tty
+ExecStart=/bin/sh -e -x -c 'rm -f /tmp/nonexistent; systemctl start test.socket; echo > /run/test.ctl; >/testok'
 TimeoutStartSec=10s
 EOF
 
        cat  >$initdir/etc/systemd/system/test.socket <<'EOF'
 [Socket]
-ListenStream=/run/test.ctl
+ListenFIFO=/run/test.ctl
 EOF
 
        cat > $initdir/etc/systemd/system/test.service <<'EOF'
@@ -49,6 +50,7 @@ EOF
 
         setup_testsuite
     ) || return 1
+    setup_nspawn_root
 
     # mask some services that we do not want to run in these tests
     ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
diff --git a/test/run-integration-tests.sh b/test/run-integration-tests.sh
new file mode 100755 (executable)
index 0000000..3ece46c
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash -e
+
+if ! test -d ../build ; then
+        echo "Expected build directory in ../build, but couldn't find it." >&2
+        exit 1
+fi
+
+ninja -C ../build
+
+declare -A results
+
+RESULT=0
+FAILURES=0
+
+for TEST in TEST-??-* ; do
+        echo -e "\n--x-- Starting $TEST --x--"
+        set +e
+        make -C "$TEST" BUILD_DIR=$(pwd)/../build clean setup run
+        RESULT=$?
+        set -e
+        echo "--x-- Result of $TEST: $RESULT --x--"
+
+        results["$TEST"]="$RESULT"
+
+        [ "$RESULT" -ne "0" ] && FAILURES=$(($FAILURES+1))
+done
+
+echo ""
+
+for TEST in ${!results[@]}; do
+        RESULT="${results[$TEST]}"
+        if [ "$RESULT" -eq "0" ] ; then
+                echo "$TEST: SUCCESS"
+        else
+                echo "$TEST: FAIL"
+        fi
+done | sort
+
+if [ "$FAILURES" -eq 0 ] ; then
+        echo -e "\nALL PASSED"
+else
+        echo -e "\nTOTAL FAILURES: $FAILURES"
+fi
+
+exit "$FAILURES"