SECONDS=0
info "Checking build with $args"
- if ! AR="$AR" CC="$CC" CXX="$CXX" meson -Dtests=unsafe -Dslow-tests=true --werror $args build; then
+ if ! AR="$AR" CC="$CC" CXX="$CXX" CFLAGS="-Werror" CXXFLAGS="-Werror" meson -Dtests=unsafe -Dslow-tests=true --werror $args build; then
fatal "meson failed with $args"
fi
-sudo: required
+---
+# vi: ts=2 sw=2 et:
+
+language: bash
dist: bionic
services:
- - docker
+ - docker
env:
- global:
- - AUTHOR_EMAIL="$(git log -1 $TRAVIS_COMMIT --pretty=\"%aE\")"
- - CI_MANAGERS="$TRAVIS_BUILD_DIR/travis-ci/managers"
- - CI_TOOLS="$TRAVIS_BUILD_DIR/travis-ci/tools"
- - REPO_ROOT="$TRAVIS_BUILD_DIR"
+ global:
+ - AUTHOR_EMAIL="$(git log -1 $TRAVIS_COMMIT --pretty=\"%aE\")"
+ - CI_MANAGERS="$TRAVIS_BUILD_DIR/travis-ci/managers"
+ - CI_TOOLS="$TRAVIS_BUILD_DIR/travis-ci/tools"
+ - REPO_ROOT="$TRAVIS_BUILD_DIR"
+ jobs:
+ - DEBIAN_RELEASE=testing PHASE="RUN_GCC"
+ - DEBIAN_RELEASE=testing PHASE="RUN_GCC_ASAN_UBSAN"
+ - DEBIAN_RELEASE=testing PHASE="RUN_CLANG"
+ - DEBIAN_RELEASE=testing PHASE="RUN_CLANG_ASAN_UBSAN"
stages:
- - name: Build & test
- if: type != cron
+ # 'Test' is the default stage (for matrix jobs)
+ - name: Test
+ if: type != cron
# Run Coverity periodically instead of for each commit/PR
- - name: Coverity
- if: type = cron
-
-jobs:
- include:
- - stage: Build & test
- name: Debian Testing
- language: bash
- env:
- - DEBIAN_RELEASE="testing"
- - CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
- - DOCKER_EXEC="docker exec -ti $CONT_NAME"
- before_install:
- - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- - docker --version
- install:
- - $CI_MANAGERS/debian.sh SETUP
- script:
- - $CI_MANAGERS/debian.sh RUN || travis_terminate 1
- after_script:
- - $CI_MANAGERS/debian.sh CLEANUP
+ - name: Coverity
+ if: type = cron
- - name: Debian Testing (ASan+UBSan)
- language: bash
- env:
- - DEBIAN_RELEASE="testing"
- - CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
- - DOCKER_EXEC="docker exec -ti $CONT_NAME"
- before_install:
- - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- - docker --version
- install:
- - $CI_MANAGERS/debian.sh SETUP
- script:
- - $CI_MANAGERS/debian.sh RUN_ASAN || travis_terminate 1
- after_script:
- - $CI_MANAGERS/debian.sh CLEANUP
+# Matrix job definition - this is run for each combination of env variables
+# from the env.jobs array above
+before_install:
+ - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
+ - docker --version
+install:
+ - $CI_MANAGERS/debian.sh SETUP
+script:
+ - $CI_MANAGERS/debian.sh $PHASE || travis_terminate 1
+after_script:
+ - $CI_MANAGERS/debian.sh CLEANUP
- - name: Debian Testing (clang)
- language: bash
- env:
- - DEBIAN_RELEASE="testing"
- - CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
- - DOCKER_EXEC="docker exec -ti $CONT_NAME"
- before_install:
- - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- - docker --version
- install:
- - $CI_MANAGERS/debian.sh SETUP
- script:
- - $CI_MANAGERS/debian.sh RUN_CLANG || travis-travis_terminate 1
- after_script:
- - $CI_MANAGERS/debian.sh CLEANUP
-
- - name: Debian Testing (clang ASan+UBSan)
- language: bash
- env:
- - DEBIAN_RELEASE="testing"
- - CONT_NAME="systemd-debian-$DEBIAN_RELEASE"
- - DOCKER_EXEC="docker exec -ti $CONT_NAME"
- before_install:
- - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- - docker --version
- install:
- - $CI_MANAGERS/debian.sh SETUP
- script:
- - $CI_MANAGERS/debian.sh RUN_CLANG_ASAN || travis_terminate 1
- after_script:
- - $CI_MANAGERS/debian.sh CLEANUP
-
- - stage: Coverity
- language: bash
- env:
- - FEDORA_RELEASE="latest"
- - CONT_NAME="coverity-fedora-$FEDORA_RELEASE"
- - DOCKER_EXEC="docker exec -ti $CONT_NAME"
- - TOOL_BASE="/var/tmp/coverity-scan-analysis"
- - DOCKER_RUN="docker run -v $TOOL_BASE:$TOOL_BASE:rw --env-file .cov-env"
- # Coverity env variables
- - PLATFORM="$(uname)"
- - TOOL_ARCHIVE="/var/tmp/cov-analysis-$PLATFORM.tgz"
- - SCAN_URL="https://scan.coverity.com"
- - UPLOAD_URL="https://scan.coverity.com/builds"
- - COVERITY_SCAN_PROJECT_NAME="$TRAVIS_REPO_SLUG"
- - COVERITY_SCAN_NOTIFICATION_EMAIL="${AUTHOR_EMAIL}"
- - COVERITY_SCAN_BRANCH_PATTERN="$TRAVIS_BRANCH"
- # Encrypted COVERITY_SCAN_TOKEN env variable
- # Generated using `travis encrypt -r systemd/systemd COVERITY_SCAN_TOKEN=xxxx`
- - secure: "jKSz+Y1Mv8xMpQHh7g5lzW7E6HQGndFz/vKDJQ1CVShwFoyjV3Zu+MFS3UYKlh1236zL0Z4dvsYFx/b3Hq8nxZWCrWeZs2NdXgy/wh8LZhxwzcGYigp3sIA/cYdP5rDjFJO0MasNkl25/rml8+eZWz+8/xQic98UQHjSco/EOWtssoRcg0J0c4eDM7bGLfIQWE73NNY1Q1UtWjKmx1kekVrM8dPmHXJ9aERka7bmcbJAcKd6vabs6DQ5AfWccUPIn/EsRYqIJTRxJrFYU6XizANZ1a7Vwk/DWHZUEn2msxcZw5BbAMDTMx0TbfrNkKSHMHuvQUCu6KCBAq414i+LgkMfmQ2SWwKiIUsud1kxXX3ZPl9bxDv1HkvVdcniC/EM7lNEEVwm4meOnjuhI2lhOyOjmP3FTSlMHGP7xlK8DS2k9fqL58vn0BaSjwWgd+2+HuL2+nJmxcK1eLGzKqaostFxrk2Xs2vPZkUdV2nWY/asUrcWHml6YlWDn2eP83pfwxHYsMiEHY/rTKvxeVY+iirO/AphoO+eaYu7LvjKZU1Yx5Z4u/SnGWAiCH0yhMis0bWmgi7SCbw+sDd2uya+aoiLIGiB2ChW7hXHXCue/dif6/gLU7b+L8R00pQwnWdvKUPoIJCmZJYCluTeib4jpW+EmARB2+nR8wms2K9FGKM="
- before_install:
- - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
- - docker --version
- install:
- # Install Coverity on the host
- - $CI_TOOLS/get-coverity.sh
- # Export necessary env variables for Coverity
- - env | grep -E "TRAVIS|COV|TOOL|URL" > .cov-env
- # Pull a Docker image and start a new container
- - $CI_MANAGERS/fedora.sh SETUP
- script:
- - set -e
- # Preconfigure with meson to prevent Coverity from capturing meson metadata
- - $DOCKER_EXEC meson cov-build -Dman=false
- # Run Coverity
- - $DOCKER_EXEC tools/coverity.sh build
- - $DOCKER_EXEC tools/coverity.sh upload
+# Inject another (single) job into the matrix for Coverity
+jobs:
+ include:
+ - stage: Coverity
+ language: bash
+ env:
+ - FEDORA_RELEASE="latest"
+ - TOOL_BASE="/var/tmp/coverity-scan-analysis"
+ - DOCKER_RUN="docker run -v $TOOL_BASE:$TOOL_BASE:rw --env-file .cov-env"
+ # Coverity env variables
+ - PLATFORM="$(uname)"
+ - TOOL_ARCHIVE="/var/tmp/cov-analysis-$PLATFORM.tgz"
+ - SCAN_URL="https://scan.coverity.com"
+ - UPLOAD_URL="https://scan.coverity.com/builds"
+ - COVERITY_SCAN_PROJECT_NAME="$TRAVIS_REPO_SLUG"
+ - COVERITY_SCAN_NOTIFICATION_EMAIL="${AUTHOR_EMAIL}"
+ - COVERITY_SCAN_BRANCH_PATTERN="$TRAVIS_BRANCH"
+ # Encrypted COVERITY_SCAN_TOKEN env variable
+ # Generated using `travis encrypt -r systemd/systemd COVERITY_SCAN_TOKEN=xxxx`
+ - secure: "jKSz+Y1Mv8xMpQHh7g5lzW7E6HQGndFz/vKDJQ1CVShwFoyjV3Zu+MFS3UYKlh1236zL0Z4dvsYFx/b3Hq8nxZWCrWeZs2NdXgy/wh8LZhxwzcGYigp3sIA/cYdP5rDjFJO0MasNkl25/rml8+eZWz+8/xQic98UQHjSco/EOWtssoRcg0J0c4eDM7bGLfIQWE73NNY1Q1UtWjKmx1kekVrM8dPmHXJ9aERka7bmcbJAcKd6vabs6DQ5AfWccUPIn/EsRYqIJTRxJrFYU6XizANZ1a7Vwk/DWHZUEn2msxcZw5BbAMDTMx0TbfrNkKSHMHuvQUCu6KCBAq414i+LgkMfmQ2SWwKiIUsud1kxXX3ZPl9bxDv1HkvVdcniC/EM7lNEEVwm4meOnjuhI2lhOyOjmP3FTSlMHGP7xlK8DS2k9fqL58vn0BaSjwWgd+2+HuL2+nJmxcK1eLGzKqaostFxrk2Xs2vPZkUdV2nWY/asUrcWHml6YlWDn2eP83pfwxHYsMiEHY/rTKvxeVY+iirO/AphoO+eaYu7LvjKZU1Yx5Z4u/SnGWAiCH0yhMis0bWmgi7SCbw+sDd2uya+aoiLIGiB2ChW7hXHXCue/dif6/gLU7b+L8R00pQwnWdvKUPoIJCmZJYCluTeib4jpW+EmARB2+nR8wms2K9FGKM="
+ before_install:
+ - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
+ - docker --version
+ install:
+ # Install Coverity on the host
+ - $CI_TOOLS/get-coverity.sh
+ # Export necessary env variables for Coverity
+ - env | grep -E "TRAVIS|COV|TOOL|URL" > .cov-env
+ # Pull a Docker image and start a new container
+ - $CI_MANAGERS/fedora.sh SETUP
+ script:
+ - set -e
+ # Preconfigure with meson to prevent Coverity from capturing meson metadata
+ - $DOCKER_EXEC meson cov-build -Dman=false
+ # Run Coverity
+ - $DOCKER_EXEC tools/coverity.sh build
+ - $DOCKER_EXEC tools/coverity.sh upload
- - set +e
- after_script:
- - $CI_MANAGERS/fedora.sh CLEANUP
+ - set +e
+ after_script:
+ - $CI_MANAGERS/fedora.sh CLEANUP
used, the DNS-over-TLS certificate is validated to match the
specified hostname.
+ * systemd-resolved may be configured to forward single-label DNS names.
+ This is not standard-conformant, but may make sense in setups where
+ public DNS servers are not used.
+
+ * systemd-resolved's DNS-over-TLS support gained SNI validation.
+
* The fs.suid_dumpable sysctl is set to 2 / "suidsafe". This allows
systemd-coredump to save core files for suid processes. When saving
the core file, systemd-coredump will use the effective uid and gid of
* systemd-sysusers gained support for creating users with the primary
group named differently than the user.
- * systemd-resolved's DNS-over-TLS support gained SNI validation.
-
* systemd-growfs (i.e. the x-systemd.growfs mount option in /etc/fstab)
gained support for growing XFS partitions. Previously it supported
only ext4 and btrfs partitions.
--- /dev/null
+@@
+local idexpression r;
+expression p, k, x;
+@@
+- r = set_ensure_allocated(&p, k);
+- if (r < 0)
+- return ...;
+- r = set_put(p, x);
++ r = set_ensure_put(&p, k, x);
+@@
+local idexpression r;
+expression p, k, x;
+@@
+- r = set_ensure_allocated(p, k);
+- if (r < 0)
+- return ...;
+- r = set_put(*p, x);
++ r = set_ensure_put(p, k, x);
* systemd maintains various hash tables internally. In order to harden them
against [collision
- attacks](https://rt.perl.org/Public/Bug/Display.html?CSRF_Token=165691af9ddaa95f653402f1b68de728)
+ attacks](https://www.cs.auckland.ac.nz/~mcw/Teaching/refs/misc/denial-of-service.pdf)
they are seeded with random numbers.
* At various places systemd needs random bytes for temporary file name
--- /dev/null
+# This file is part of systemd.
+#
+# The lookup keys are $MODALIAS strings, see udev's hwdb builtin.
+#
+# Match string formats:
+# <subsystem>:<modalias>
+#
+# pci:v<vendor>d<device>
+# usb:v<vendor>p<product>
+#
+# To add local entries, create a new file
+# /etc/udev/hwdb.d/61-autosuspend-local.hwdb
+# and add your rules there. To load the new rules execute (as root):
+# systemd-hwdb update
+# udevadm trigger /dev/…
+#
+# If your changes are generally applicable, preferably send them as a pull
+# request to
+# https://github.com/systemd/systemd
+# or create a bug report on https://github.com/systemd/systemd/issues and
+# include your new rules, a description of the device, and the output of
+# udevadm info
+# the device.
+#
+# Allowed properties are:
+# ID_AUTOSUSPEND=1
+
+#
+# Sort by brand, model
+
+#########################################
+# Alcor
+#########################################
+
+# AU9540 Smartcard Reader
+usb:v058Fp9540*
+ ID_AUTOSUSPEND=1
+
+#########################################
+# Wacom
+#########################################
+
+usb:v056Ap51A0*
+ ID_AUTOSUSPEND=1
mouse:usb:v046dpc332:name:Logitech Gaming Mouse G502:
# Logitech G502 HERO SE
mouse:usb:v046dpc08b:name:Logitech G502 HERO SE:
+# Logitech G502 Hero
+mouse:usb:v046dpc08b:name:Logitech G502 HERO Gaming Mouse:
MOUSE_DPI=1200@1000 *2400@1000 3200@1000 6400@1000
# Logitech G700 Laser Mouse (Wired)
# SPDX-License-Identifier: LGPL-2.1+
-hwdb_files = files('''
+# Those files right now are not supported by the grammar. Also,
+# they are very long but quite repetitive and the parser is not very fast.
+# So we don't "test" them.
+hwdb_files_notest = files('''
20-pci-vendor-model.hwdb
20-pci-classes.hwdb
20-usb-vendor-model.hwdb
20-OUI.hwdb
20-net-ifname.hwdb
20-vmbus-class.hwdb
+'''.split())
+
+hwdb_files_test = files('''
+ 60-autosuspend.hwdb
60-evdev.hwdb
60-input-id.hwdb
60-keyboard.hwdb
'''.split())
if conf.get('ENABLE_HWDB') == 1
- install_data(hwdb_files,
+ auto_suspend_rules = custom_target(
+ '60-autosuspend-chromiumos.hwdb',
+ output : '60-autosuspend-chromiumos.hwdb',
+ command : make_autosuspend_rules_py,
+ capture : true,
+ install : true,
+ install_dir: udevhwdbdir)
+
+ install_data(hwdb_files_notest,
+ hwdb_files_test,
install_dir : udevhwdbdir)
meson.add_install_script('sh', '-c',
meson.add_install_script('sh', '-c',
'test -n "$DESTDIR" || @0@/systemd-hwdb update'
.format(rootbindir))
-endif
-
-############################################################
-parse_hwdb_py = find_program('parse_hwdb.py')
-if want_tests != 'false'
- test('parse-hwdb',
- parse_hwdb_py,
- timeout : 90)
+ if want_tests != 'false'
+ parse_hwdb_py = find_program('parse_hwdb.py')
+ test('parse-hwdb',
+ parse_hwdb_py,
+ args : [hwdb_files_test,
+ auto_suspend_rules],
+ timeout : 90)
+ endif
endif
############################################################
SIGNED_REAL = Combine(Optional(Word('-+')) + REAL)
UDEV_TAG = Word(string.ascii_uppercase, alphanums + '_')
+# Those patterns are used in type-specific matches
TYPES = {'mouse': ('usb', 'bluetooth', 'ps2', '*'),
'evdev': ('name', 'atkbd', 'input'),
'id-input': ('modalias'),
'sensor': ('modalias', ),
}
+# Patterns that are used to set general properties on a device
+GENERAL_MATCHES = {'acpi',
+ 'bluetooth',
+ 'usb',
+ 'pci',
+ 'sdio',
+ 'vmbus',
+ 'OUI',
+ }
+
@lru_cache()
def hwdb_grammar():
ParserElement.setDefaultWhitespaceChars('')
prefix = Or(category + ':' + Or(conn) + ':'
for category, conn in TYPES.items())
- matchline = Combine(prefix + Word(printables + ' ' + '®')) + EOL
+
+ matchline_typed = Combine(prefix + Word(printables + ' ' + '®'))
+ matchline_general = Combine(Or(GENERAL_MATCHES) + ':' + Word(printables))
+ matchline = (matchline_typed | matchline_general) + EOL
+
propertyline = (White(' ', exact=1).suppress() +
Combine(UDEV_TAG - '=' - Word(alphanums + '_=:@*.!-;, "') - Optional(pythonStyleComment)) +
EOL)
('MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL', INTEGER),
('MOUSE_WHEEL_CLICK_COUNT', INTEGER),
('MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL', INTEGER),
+ ('ID_AUTOSUSPEND', Literal('1')),
('ID_INPUT', Literal('1')),
('ID_INPUT_ACCELEROMETER', Literal('1')),
('ID_INPUT_JOYSTICK', Literal('1')),
v graphical-session-pre.target
(various user services) | (printers)
| v |
- | (services for the graphical sesion) v
+ | (services for the graphical session) v
| | printer.target
v v
<emphasis>default.target</emphasis> graphical-session.target</programlisting>
<xsl:template match="citerefentry[not(@project)]">
<a>
<xsl:attribute name="href">
- <xsl:value-of select="refentrytitle"/><xsl:text>.html#</xsl:text>
+ <xsl:value-of select="refentrytitle"/>
+ <xsl:text>.html#</xsl:text>
<xsl:value-of select="refentrytitle/@target"/>
</xsl:attribute>
<xsl:call-template name="inline.charseq"/>
</a>
</xsl:template>
+<xsl:template match="citerefentry[@project='url']">
+ <a>
+ <xsl:attribute name="href">
+ <xsl:value-of select="refentrytitle/@url"/>
+ </xsl:attribute>
+ <xsl:call-template name="inline.charseq"/>
+ </a>
+</xsl:template>
+
<!--
- helper template to do conflict resolution between various headings with the same inferred ID attribute/tag from the headerlink template
- this conflict resolution is necessary to prevent malformed HTML output (multiple ID attributes with the same value)
independently, for example with <citerefentry
project='man-pages'><refentrytitle>groupadd</refentrytitle><manvolnum>8</manvolnum></citerefentry>. If
non-existent groups that are listed there are ignored. This option may be used more than once, in
- which case all specified group lists are combined.</para></listitem>
+ which case all specified group lists are combined. If the user is currently a member of a group
+ which is not listed, the user will be removed from the group.</para></listitem>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>Domains=</varname></term>
- <listitem><para>A space-separated list of domains. These domains are used as search suffixes when resolving
- single-label hostnames (domain names which contain no dot), in order to qualify them into fully-qualified
- domain names (FQDNs). Search domains are strictly processed in the order they are specified, until the name
- with the suffix appended is found. For compatibility reasons, if this setting is not specified, the search
- domains listed in <filename>/etc/resolv.conf</filename> are used instead, if that file exists and any domains
- are configured in it. This setting defaults to the empty list.</para>
-
- <para>Specified domain names may optionally be prefixed with <literal>~</literal>. In this case they do not
- define a search path, but preferably direct DNS queries for the indicated domains to the DNS servers configured
- with the system <varname>DNS=</varname> setting (see above), in case additional, suitable per-link DNS servers
- are known. If no per-link DNS servers are known using the <literal>~</literal> syntax has no effect. Use the
- construct <literal>~.</literal> (which is composed of <literal>~</literal> to indicate a routing domain and
- <literal>.</literal> to indicate the DNS root domain that is the implied suffix of all DNS domains) to use the
- system DNS server defined with <varname>DNS=</varname> preferably for all domains.</para></listitem>
+ <listitem><para>A space-separated list of domains optionally prefixed with <literal>~</literal>,
+ used for two distinct purposes described below. Defaults to the empty list.</para>
+
+ <para>Any domains <emphasis>not</emphasis> prefixed with <literal>~</literal> are used as search
+ suffixes when resolving single-label hostnames (domain names which contain no dot), in order to
+ qualify them into fully-qualified domain names (FQDNs). These "search domains" are strictly processed
+ in the order they are specified in, until the name with the suffix appended is found. For
+ compatibility reasons, if this setting is not specified, the search domains listed in
+ <filename>/etc/resolv.conf</filename> with the <varname>search</varname> keyword are used instead, if
+ that file exists and any domains are configured in it.</para>
+
+ <para>The domains prefixed with <literal>~</literal> are called "routing domains". All domains listed
+ here (both search domains and routing domains after removing the <literal>~</literal> prefix) define
+ a search path that preferably directs DNS queries to this inteface. This search path has an effect
+ only when suitable per-link DNS servers are known. Such servers may be defined through the
+ <varname>DNS=</varname> setting (see above) and dynamically at run time, for example from DHCP
+ leases. If no per-link DNS servers are known, routing domains have no effect.</para>
+
+ <para>Use the construct <literal>~.</literal> (which is composed from <literal>~</literal> to
+ indicate a routing domain and <literal>.</literal> to indicate the DNS root domain that is the
+ implied suffix of all DNS domains) to use the DNS servers defined for this link preferably for all
+ domains.</para></listitem>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>ReadEtcHosts=</varname></term>
- <listitem><para>Takes a boolean argument. If <literal>yes</literal> (the default), the DNS stub resolver will read
- <filename>/etc/hosts</filename>, and try to resolve hosts or address by using the entries in the file before
- sending query to DNS servers.</para></listitem>
+ <listitem><para>Takes a boolean argument. If <literal>yes</literal> (the default),
+ <command>systemd-resolved</command> will read <filename>/etc/hosts</filename>, and try to resolve
+ hosts or address by using the entries in the file before sending query to DNS servers.
+ </para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>ResolveUnicastSingleLabel=</varname></term>
+ <listitem><para>Takes a boolean argument. When false (the default),
+ <command>systemd-resolved</command> will not resolve A and AAAA queries for single-label names over
+ classic DNS. Note that such names may still be resolved if search domains are specified (see
+ <varname>Domains=</varname> above), or using other mechanisms, in particular via LLMNR or from
+ <filename>/etc/hosts</filename>. When true, queries for single-label names will be forwarded to
+ global DNS servers even if no search domains are defined.
+ </para>
+
+ <para>This option is provided for compatibility with configurations where <emphasis>public DNS
+ servers are not used</emphasis>. Forwarding single-label names to servers not under your control is
+ not standard-conformant, see <ulink
+ url="https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-statement-dotless-domains-considered-harmful/">IAB
+ Statement</ulink>, and may create a privacy and security risk.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
<para><filename>systemd-makefs</filename> knows very little about specific file
systems and swap devices, and after checking that the block device does not already
contain a file system or other content, it will execute binaries specific to
- each filesystem type (<filename>/sbin/mkfs.<replaceable>type</replaceable></filename>).</para>
+ each filesystem type (<filename>/sbin/mkfs.<replaceable>type</replaceable></filename>
+ or <filename>/sbin/mkswap</filename>).</para>
<para><filename>systemd-growfs</filename> knows very little about specific file
systems and swap devices, and will instruct the kernel to grow the mounted
number specific to each file system, so only certain types are supported.
Currently:
<citerefentry project='man-pages'><refentrytitle>ext4</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- btrfs (see
- <citerefentry project='man-pages'><refentrytitle>btrfs-man5</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
+ <citerefentry project='url'><refentrytitle url='https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)'>btrfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>xfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<!-- yes, that's what the man page is called. -->
and dm-crypt partitions (see
<refsect1>
<title>Description</title>
- <para><filename>systemd-modules-load.service</filename> is an
- early boot service that loads kernel modules based on static
- configuration.</para>
+ <para><filename>systemd-modules-load.service</filename> is an early boot service that loads kernel
+ modules. It reads static configuration from files in <filename>/usr</filename> and
+ <filename>/etc</filename>, but also runtime configuration from <filename>/run</filename> and the kernel
+ command line (see below).</para>
<para>See
- <citerefentry><refentrytitle>modules-load.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for information about the configuration of this service.</para>
-
+ <citerefentry><refentrytitle>modules-load.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ information about the configuration format of this service and paths where configuration files can be
+ created.</para>
</refsect1>
<refsect1>
IPv6.</para></listitem>
<listitem><para>Resolution of address records (A and AAAA) via unicast DNS (i.e. not LLMNR or
- MulticastDNS) for non-synthesized single-label names is only allowed for non-top-level domains. This
- means that such records can only be resolved when search domains are defined. For any interface which
- defines search domains, such look-ups are routed to that interface, suffixed with each of the search
- domains defined on that interface in turn. When global search domains are defined, such look-ups are
- routed to all interfaces, suffixed by each of the global search domains in turn. The details of which
- servers are queried and how the final reply is chosen are described below. Note that this means that
- address queries for single-label names are never sent out to remote DNS servers, and if no search
- domains are defined, resolution will fail.</para></listitem>
+ MulticastDNS) for non-synthesized single-label names is allowed for non-top-level domains. This means
+ that such records can be resolved when search domains are defined. For any interface which defines
+ search domains, such look-ups are routed to that interface, suffixed with each of the search domains
+ defined on that interface in turn. When global search domains are defined, such look-ups are routed to
+ all interfaces, suffixed by each of the global search domains in turn. Additionally, lookup of
+ single-label names via unicast DNS may be enabled with the
+ <varname>ResolveUnicastSingleLabel=yes</varname> setting. The details of which servers are queried and
+ how the final reply is chosen are described below. Note that this means that address queries for
+ single-label names are never sent out to remote DNS servers by default, and if no search domains are
+ defined, resolution will fail.</para></listitem>
<listitem><para>Other multi-label names are routed to all local interfaces that have a DNS server
configured, plus the globally configured DNS servers if there are any. Note that by default, lookups for
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>RootHash=</varname></term>
+
+ <listitem><para>Takes a data integrity (dm-verity) root hash specified in hexadecimal, or the path to a file
+ containing a root hash in ASCII hexadecimal format. This option enables data integrity checks using dm-verity,
+ if the used image contains the appropriate integrity data (see above) or if <varname>RootVerity=</varname> is used.
+ The specified hash must match the root hash of integrity data, and is usually at least 256 bits (and hence 64
+ formatted hexadecimal characters) long (in case of SHA256 for example). If this option is not specified, but
+ the image file carries the <literal>user.verity.roothash</literal> extended file attribute (see <citerefentry
+ project='man-pages'><refentrytitle>xattr</refentrytitle><manvolnum>7</manvolnum></citerefentry>), then the root
+ hash is read from it, also as formatted hexadecimal characters. If the extended file attribute is not found (or
+ is not supported by the underlying file system), but a file with the <filename>.roothash</filename> suffix is
+ found next to the image file, bearing otherwise the same name (except if the image has the
+ <filename>.raw</filename> suffix, in which case the root hash file must not have it in its name), the root hash
+ is read from it and automatically used, also as formatted hexadecimal characters.</para>
+
+ <xi:include href="system-only.xml" xpointer="singular"/></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>RootVerity=</varname></term>
+
+ <listitem><para>Takes the path to a data integrity (dm-verity) file. This option enables data integrity checks
+ using dm-verity, if <varname>RootImage=</varname> is used and a root-hash is passed and if the used image itself
+ does not contains the integrity data. The integrity data must be matched by the root hash. If this option is not
+ specified, but a file with the <filename>.verity</filename> suffix is found next to the image file, bearing otherwise
+ the same name (except if the image has the <filename>.raw</filename> suffix, in which case the verity data file must
+ not have it in its name), the verity data is read from it and automatically used.</para>
+
+ <para>This option is supported only for disk images that contain a single file system, without an enveloping partition
+ table. Images that contain a GPT partition table should instead include both root file system and matching Verity
+ data in the same image, implementing the
+ [Discoverable Partition Specification](https://systemd.io/DISCOVERABLE_PARTITIONS)</para>
+
+ <xi:include href="system-only.xml" xpointer="singular"/></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>MountAPIVFS=</varname></term>
</varlistentry>
<varlistentry>
- <term><varname>IPIngressFilterPath=<replaceable>BPF_FS_PROGRAMM_PATH</replaceable></varname></term>
- <term><varname>IPEgressFilterPath=<replaceable>BPF_FS_PROGRAMM_PATH</replaceable></varname></term>
+ <term><varname>IPIngressFilterPath=<replaceable>BPF_FS_PROGRAM_PATH</replaceable></varname></term>
+ <term><varname>IPEgressFilterPath=<replaceable>BPF_FS_PROGRAM_PATH</replaceable></varname></term>
<listitem>
<para>Add custom network traffic filters implemented as BPF programs, applying to all IP packets
build_by_default : want_tests != 'false')
foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
- ['systemd', 'ENABLE_NSS_SYSTEMD', 'src/nss-systemd/userdb-glue.c src/nss-systemd/userdb-glue.h'],
+ ['systemd', 'ENABLE_NSS_SYSTEMD', 'src/nss-systemd/userdb-glue.c src/nss-systemd/userdb-glue.h src/nss-systemd/nss-systemd.h'],
['mymachines', 'ENABLE_NSS_MYMACHINES'],
['resolve', 'ENABLE_NSS_RESOLVE']]
SUBSYSTEM=="rtc", ATTR{hctosys}=="1", SYMLINK+="rtc"
SUBSYSTEM=="rtc", KERNEL=="rtc0", SYMLINK+="rtc", OPTIONS+="link_priority=-100"
-SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb", GOTO="default_hwdb_imported"
ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}"
+LABEL="default_hwdb_imported"
ACTION!="add", GOTO="default_end"
--- /dev/null
+# do not edit this file, it will be overwritten on update
+
+ACTION!="add", GOTO="autosuspend_end"
+
+# I2C rules
+SUBSYSTEM=="i2c", ATTR{name}=="cyapa", \
+ ATTR{power/control}="on", GOTO="autosuspend_end"
+
+# Enable autosuspend if hwdb says so. Here we are relying on
+# the hwdb import done earlier based on MODALIAS.
+ENV{ID_AUTOSUSPEND}=="1", TEST=="power/control", \
+ ATTR{power/control}="auto"
+
+LABEL="autosuspend_end"
SUBSYSTEM!="tty", GOTO="serial_end"
SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
-SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci"
-SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
+# We already ran the hwdb builtin for devices with MODALIAS in 50-default.rules.
+# Let's cover the remaining case here, where we walk up the tree to find a node with $MODALIAS.
+ENV{MODALIAS}=="", SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci"
# /dev/serial/by-path/, /dev/serial/by-id/ for USB devices
KERNEL!="ttyUSB[0-9]*|ttyACM[0-9]*", GOTO="serial_end"
+++ /dev/null
-# This udev rule is for any devices that should enter automatic suspend
-# but are not already included in generated rules from Chromium OS via
-# tools/make-autosuspend-rules.py
-#
-
-ACTION!="add", GOTO="autosuspend_manual_end"
-SUBSYSTEM!="usb", GOTO="autosuspend_manual_end"
-
-SUBSYSTEM=="usb", GOTO="autosuspend_manual_usb"
-
-# USB rules
-LABEL="autosuspend_manual_usb"
-GOTO="autosuspend_manual_end"
-
-# Enable autosuspend
-LABEL="autosuspend_manual_enable"
-TEST=="power/control", ATTR{power/control}="auto", GOTO="autosuspend_manual_end"
-
-LABEL="autosuspend_manual_end"
# SPDX-License-Identifier: LGPL-2.1+
rules = files('''
+ 60-autosuspend.rules
60-block.rules
60-cdrom_id.rules
60-drm.rules
60-persistent-v4l.rules
60-sensor.rules
60-serial.rules
- 61-autosuspend-manual.rules
70-joystick.rules
70-mouse.rules
70-touchpad.rules
install_dir : udevrulesdir)
all_rules += gen
endforeach
-
-auto_suspend_rules = custom_target(
- '60-autosuspend-chromiumos.rules',
- output : '60-autosuspend-chromiumos.rules',
- command : make_autosuspend_rules_py,
- capture : true,
- install : true,
- install_dir: [udevrulesdir])
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C"); /* we want to format/parse floats in C style */
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <dlfcn.h>
+
+#include "macro.h"
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(void*, dlclose);
memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets);
}
-static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
+static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
HashmapBase *h;
const struct hashmap_type_info *hi = &hashmap_type_info[type];
bool up;
}
Hashmap *_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
+ return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
}
OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
+ return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
}
Set *_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
+ return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
}
static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops,
- enum HashmapType type HASHMAP_DEBUG_PARAMS) {
+ enum HashmapType type HASHMAP_DEBUG_PARAMS) {
HashmapBase *q;
assert(h);
if (*h)
return 0;
- q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS);
+ q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS);
if (!q)
return -ENOMEM;
}
int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
+ return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
}
int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
+ return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
}
int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
+ return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
}
static void hashmap_free_no_clear(HashmapBase *h) {
return hashmap_put_boldly(s, hash, &swap, true);
}
+int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key HASHMAP_DEBUG_PARAMS) {
+ int r;
+
+ r = _set_ensure_allocated(s, hash_ops HASHMAP_DEBUG_PASS_ARGS);
+ if (r < 0)
+ return r;
+
+ return set_put(*s, key);
+}
+
+int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HASHMAP_DEBUG_PARAMS) {
+ int r;
+
+ r = _set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_PASS_ARGS);
+ if (r <= 0) {
+ if (hash_ops && hash_ops->free_key)
+ hash_ops->free_key(key);
+ else
+ free(key);
+ }
+
+ return r;
+}
+
int hashmap_replace(Hashmap *h, const void *key, void *value) {
struct swap_entries swap;
struct plain_hashmap_entry *e;
return 0;
}
-HashmapBase *_hashmap_copy(HashmapBase *h) {
+HashmapBase *_hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS) {
HashmapBase *copy;
int r;
assert(h);
- copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS);
+ copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_PASS_ARGS);
if (!copy)
return NULL;
assert_not_reached("Unknown hashmap type");
}
- if (r < 0) {
- _hashmap_free(copy, false, false);
- return NULL;
- }
+ if (r < 0)
+ return _hashmap_free(copy, false, false);
return copy;
}
return r;
}
-int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) {
+int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS) {
int r;
- r = hashmap_ensure_allocated(h, &string_hash_ops_free_free);
+ r = _hashmap_ensure_allocated(h, &string_hash_ops_free_free HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
return r;
}
-int set_put_strdup(Set **s, const char *p) {
+int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS) {
char *c;
int r;
assert(s);
assert(p);
- r = set_ensure_allocated(s, &string_hash_ops_free);
+ r = _set_ensure_allocated(s, &string_hash_ops_free HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
return set_consume(*s, c);
}
-int set_put_strdupv(Set **s, char **l) {
+int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS) {
int n = 0, r;
char **i;
assert(s);
STRV_FOREACH(i, l) {
- r = set_put_strdup(s, *i);
+ r = _set_put_strdup(s, *i HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
IteratedCache *iterated_cache_free(IteratedCache *cache);
int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries);
-HashmapBase *_hashmap_copy(HashmapBase *h);
-static inline Hashmap *hashmap_copy(Hashmap *h) {
- return (Hashmap*) _hashmap_copy(HASHMAP_BASE(h));
-}
-static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) {
- return (OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h));
-}
+HashmapBase *_hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS);
+#define hashmap_copy(h) ((Hashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS))
+#define ordered_hashmap_copy(h) ((OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS))
int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
return hashmap_put(PLAIN_HASHMAP(h), key, value);
}
-int hashmap_put_strdup(Hashmap **h, const char *k, const char *v);
+int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS);
+#define hashmap_put_strdup(h, k, v) _hashmap_put_strdup(h, k, v HASHMAP_DEBUG_SRC_ARGS)
int hashmap_update(Hashmap *h, const void *key, void *value);
static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) {
#include <stdarg.h>
#include <stddef.h>
#include <sys/signalfd.h>
+#include <sys/stat.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/un.h>
return r;
}
+static bool stderr_is_journal(void) {
+ _cleanup_free_ char *w = NULL;
+ const char *e;
+ uint64_t dev, ino;
+ struct stat st;
+
+ e = getenv("JOURNAL_STREAM");
+ if (!e)
+ return false;
+
+ if (extract_first_word(&e, &w, ":", EXTRACT_DONT_COALESCE_SEPARATORS) <= 0)
+ return false;
+ if (!e)
+ return false;
+
+ if (safe_atou64(w, &dev) < 0)
+ return false;
+ if (safe_atou64(e, &ino) < 0)
+ return false;
+
+ if (fstat(STDERR_FILENO, &st) < 0)
+ return false;
+
+ return st.st_dev == dev && st.st_ino == ino;
+}
+
int log_open(void) {
int r;
return 0;
}
- if (log_target != LOG_TARGET_AUTO ||
- getpid_cached() == 1 ||
- isatty(STDERR_FILENO) <= 0) {
+ if (log_target != LOG_TARGET_AUTO || getpid_cached() == 1 || stderr_is_journal()) {
if (!prohibit_ipc &&
IN_SET(log_target, LOG_TARGET_AUTO,
}
void log_parse_environment_realm(LogRealm realm) {
- /* Do not call from library code. */
-
- const char *e;
-
if (getpid_cached() == 1 || get_ctty_devnr(0, NULL) < 0)
/* Only try to read the command line in daemons. We assume that anything that has a
* controlling tty is user stuff. For PID1 we do a special check in case it hasn't
* closed the console yet. */
(void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
+ log_parse_environment_cli_realm(realm);
+}
+
+void log_parse_environment_cli_realm(LogRealm realm) {
+ /* Do not call from library code. */
+
+ const char *e;
+
e = getenv("SYSTEMD_LOG_TARGET");
if (e && log_set_target_from_string(e) < 0)
log_warning("Failed to parse log target '%s'. Ignoring.", e);
log_parse_environment();
(void) log_open();
}
+
+void log_setup_cli(void) {
+ /* Sets up logging the way it is most appropriate for running a program as a CLI utility. */
+
+ log_show_color(true);
+ log_parse_environment_cli();
+ (void) log_open();
+}
void log_forget_fds(void);
void log_parse_environment_realm(LogRealm realm);
+void log_parse_environment_cli_realm(LogRealm realm);
#define log_parse_environment() \
log_parse_environment_realm(LOG_REALM)
+#define log_parse_environment_cli() \
+ log_parse_environment_cli_realm(LOG_REALM)
int log_dispatch_internal(
int level,
#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
void log_setup_service(void);
+void log_setup_cli(void);
size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
#define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1))
+#define PAGE_OFFSET(l) ((l) & (page_size() - 1))
/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
static inline void memcpy_safe(void *dst, const void *src, size_t n) {
device-nodes.h
dirent-util.c
dirent-util.h
+ dlfcn-util.h
efivars.c
efivars.h
env-file.c
threads,
libcap,
libselinux,
- libm],
+ libm,
+ libdl],
c_args : ['-fvisibility=default'],
install : false)
static struct selabel_handle *label_hnd = NULL;
#define log_enforcing(...) log_full(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
-#define log_enforcing_errno(r, ...) log_full_errno(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, r, __VA_ARGS__)
+
+#define log_enforcing_errno(error, ...) \
+ ({ \
+ bool _enforcing = mac_selinux_enforcing(); \
+ int _level = _enforcing ? LOG_ERR : LOG_WARNING; \
+ int _e = (error); \
+ \
+ int _r = (log_get_max_level() >= LOG_PRI(_level)) \
+ ? log_internal_realm(_level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
+ : -ERRNO_VALUE(_e); \
+ _enforcing ? _r : 0; \
+ })
#endif
bool mac_selinux_use(void) {
#if HAVE_SELINUX
if (_unlikely_(cached_enforcing < 0)) {
cached_enforcing = security_getenforce();
- if (cached_enforcing == -1)
- log_error_errno(errno, "Failed to get SELinux enforced status, continue in enforcing mode: %m");
- else
- log_debug("SELinux enforcing state cached to: %s", cached_enforcing ? "enforcing" : "permissive");
+ if (cached_enforcing < 0) {
+ log_debug_errno(errno, "Failed to get SELinux enforced status, continuing in enforcing mode: %m");
+ return true; /* treat failure as enforcing mode */
+ }
+
+ log_debug("SELinux enforcing state cached to: %s", cached_enforcing ? "enforcing" : "permissive");
}
- /* treat failure as enforcing mode */
- return (cached_enforcing != 0);
+ return cached_enforcing > 0;
#else
return false;
#endif
#endif
int mac_selinux_init(void) {
- int r = 0;
-
#if HAVE_SELINUX
usec_t before_timestamp, after_timestamp;
struct mallinfo before_mallinfo, after_mallinfo;
+ char timespan[FORMAT_TIMESPAN_MAX];
+ int l;
selinux_set_callback(SELINUX_CB_POLICYLOAD, (union selinux_callback) mac_selinux_reload);
selinux_set_callback(SELINUX_CB_SETENFORCE, (union selinux_callback) setenforce_callback);
before_timestamp = now(CLOCK_MONOTONIC);
label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
- if (!label_hnd) {
- log_enforcing_errno(errno, "Failed to initialize SELinux context: %m");
- r = mac_selinux_enforcing() ? -errno : 0;
- } else {
- char timespan[FORMAT_TIMESPAN_MAX];
- int l;
+ if (!label_hnd)
+ return log_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m");
- after_timestamp = now(CLOCK_MONOTONIC);
- after_mallinfo = mallinfo();
+ after_timestamp = now(CLOCK_MONOTONIC);
+ after_mallinfo = mallinfo();
- l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
+ l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
- log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
- format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
- (l+1023)/1024);
- }
-#endif
+ log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
+ format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
+ (l+1023)/1024);
- return r;
+#endif
+ return 0;
}
void mac_selinux_finish(void) {
return 0;
fail:
- log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", path, inside_path);
- if (mac_selinux_enforcing())
- return r;
+ return log_enforcing_errno(r, "Unable to fix SELinux security context of %s (%s): %m", path, inside_path);
#endif
return 0;
assert(path);
assert(label);
- if (setfilecon(path, label) < 0) {
- log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path);
- if (mac_selinux_enforcing())
- return -errno;
- }
+ if (setfilecon(path, label) < 0)
+ return log_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path);
#endif
return 0;
}
int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
- int r = -EOPNOTSUPP;
-
#if HAVE_SELINUX
_cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
security_class_t sclass;
+ int r;
assert(exe);
assert(label);
r = security_compute_create_raw(mycon, fcon, sclass, label);
if (r < 0)
return -errno;
-#endif
- return r;
+ return 0;
+#else
+ return -EOPNOTSUPP;
+#endif
}
int mac_selinux_get_our_label(char **label) {
- int r = -EOPNOTSUPP;
+#if HAVE_SELINUX
+ int r;
assert(label);
-#if HAVE_SELINUX
if (!mac_selinux_use())
return -EOPNOTSUPP;
r = getcon_raw(label);
if (r < 0)
return -errno;
-#endif
- return r;
+ return 0;
+#else
+ return -EOPNOTSUPP;
+#endif
}
int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
- int r = -EOPNOTSUPP;
-
#if HAVE_SELINUX
_cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
_cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
security_class_t sclass;
const char *range = NULL;
+ int r;
assert(socket_fd >= 0);
assert(exe);
r = security_compute_create_raw(mycon, fcon, sclass, label);
if (r < 0)
return -errno;
-#endif
- return r;
+ return 0;
+#else
+ return -EOPNOTSUPP;
+#endif
}
char* mac_selinux_free(char *label) {
#if HAVE_SELINUX
- if (!label)
- return NULL;
-
- if (!mac_selinux_use())
- return NULL;
-
freecon(label);
+#else
+ assert(!label);
#endif
return NULL;
if (errno == ENOENT)
return 0;
- log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath);
- } else {
- if (setfscreatecon_raw(filecon) >= 0)
- return 0; /* Success! */
-
- log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath);
+ return log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath);
}
- if (mac_selinux_enforcing())
- return -errno;
+ if (setfscreatecon_raw(filecon) < 0)
+ return log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath);
return 0;
}
#endif
int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) {
- int r = 0;
-
#if HAVE_SELINUX
_cleanup_free_ char *abspath = NULL;
+ int r;
+
assert(path);
return -ENOMEM;
}
- r = selinux_create_file_prepare_abspath(path, mode);
+ return selinux_create_file_prepare_abspath(path, mode);
+#else
+ return 0;
#endif
- return r;
}
int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
- int r = 0;
-
#if HAVE_SELINUX
+ int r;
+
_cleanup_free_ char *abspath = NULL;
assert(path);
if (r < 0)
return r;
- r = selinux_create_file_prepare_abspath(abspath, mode);
+ return selinux_create_file_prepare_abspath(abspath, mode);
+#else
+ return 0;
#endif
- return r;
}
void mac_selinux_create_file_clear(void) {
int mac_selinux_create_socket_prepare(const char *label) {
#if HAVE_SELINUX
- if (!mac_selinux_use())
- return 0;
-
assert(label);
- if (setsockcreatecon(label) < 0) {
- log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label);
+ if (!mac_selinux_use())
+ return 0;
- if (mac_selinux_enforcing())
- return -errno;
- }
+ if (setsockcreatecon(label) < 0)
+ return log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label);
#endif
return 0;
if (errno == ENOENT)
goto skipped;
- log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
- if (mac_selinux_enforcing())
- return -errno;
-
+ r = log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
+ if (r < 0)
+ return r;
} else {
if (setfscreatecon_raw(fcon) < 0) {
- log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path);
- if (mac_selinux_enforcing())
- return -errno;
+ r = log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path);
+ if (r < 0)
+ return r;
} else
context_changed = true;
}
r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
if (context_changed)
- setfscreatecon_raw(NULL);
+ (void) setfscreatecon_raw(NULL);
return r;
/* no set_free_free_free */
-static inline Set *set_copy(Set *s) {
- return (Set*) _hashmap_copy(HASHMAP_BASE(s));
-}
+#define set_copy(s) ((Set*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS))
int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
#define set_ensure_allocated(h, ops) _set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
return _hashmap_get_strv(HASHMAP_BASE(s));
}
+int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key HASHMAP_DEBUG_PARAMS);
+#define set_ensure_put(s, hash_ops, key) _set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS)
+
+int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HASHMAP_DEBUG_PARAMS);
+#define set_ensure_consume(s, hash_ops, key) _set_ensure_consume(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS)
+
int set_consume(Set *s, void *value);
-int set_put_strdup(Set **s, const char *p);
-int set_put_strdupv(Set **s, char **l);
+
+int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS);
+#define set_put_strdup(s, p) _set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS)
+int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS);
+#define set_put_strdupv(s, l) _set_put_strdupv(s, l HASHMAP_DEBUG_SRC_ARGS)
+
int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags);
#define SET_FOREACH(e, s, i) \
static int run(int argc, char *argv[]) {
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
static int run(int argc, char *argv[]) {
int r, output_flags;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
CGroupMask mask;
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
if (safe_atou(value, &token) < 0)
log_unit_debug(u, "Failed to parse token value: %s", value);
else {
- r = set_ensure_allocated(&a->tokens, NULL);
- if (r < 0) {
- log_oom();
- return 0;
- }
-
- r = set_put(a->tokens, UINT_TO_PTR(token));
+ r = set_ensure_put(&a->tokens, NULL, UINT_TO_PTR(token));
if (r < 0)
log_unit_error_errno(u, r, "Failed to add token to set: %m");
}
if (safe_atou(value, &token) < 0)
log_unit_debug(u, "Failed to parse token value: %s", value);
else {
- r = set_ensure_allocated(&a->expire_tokens, NULL);
- if (r < 0) {
- log_oom();
- return 0;
- }
-
- r = set_put(a->expire_tokens, UINT_TO_PTR(token));
+ r = set_ensure_put(&a->expire_tokens, NULL, UINT_TO_PTR(token));
if (r < 0)
log_unit_error_errno(u, r, "Failed to add expire token to set: %m");
}
} else
log_unit_debug(UNIT(a), "Got direct mount request on %s", a->where);
- r = set_ensure_allocated(&a->tokens, NULL);
- if (r < 0) {
- log_unit_error(UNIT(a), "Failed to allocate token set.");
- goto fail;
- }
-
- r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
+ r = set_ensure_put(&a->tokens, NULL, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
if (r < 0) {
log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
goto fail;
automount_stop_expire(a);
- r = set_ensure_allocated(&a->expire_tokens, NULL);
- if (r < 0) {
- log_unit_error(UNIT(a), "Failed to allocate token set.");
- goto fail;
- }
-
- r = set_put(a->expire_tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
+ r = set_ensure_put(&a->expire_tokens, NULL, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
if (r < 0) {
log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
goto fail;
set_clear(*set);
STRV_FOREACH(bpf_fs_path, filter_paths) {
- _cleanup_free_ BPFProgram *prog = NULL;
+ _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
int r;
r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, &prog);
if (r < 0)
return log_unit_error_errno(u, r, "Loading of ingress BPF program %s failed: %m", *bpf_fs_path);
- r = set_ensure_allocated(set, &filter_prog_hash_ops);
- if (r < 0)
- return log_unit_error_errno(u, r, "Can't allocate BPF program set: %m");
-
- r = set_put(*set, prog);
+ r = set_ensure_consume(set, &filter_prog_hash_ops, TAKE_PTR(prog));
if (r < 0)
return log_unit_error_errno(u, r, "Can't add program to BPF program set: %m");
- TAKE_PTR(prog);
}
return 0;
r = bpf_program_cgroup_attach(prog, attach_type, path, BPF_F_ALLOW_MULTI);
if (r < 0)
return log_unit_error_errno(u, r, "Attaching custom egress BPF program to cgroup %s failed: %m", path);
- /* Remember that these BPF programs are installed now. */
- r = set_ensure_allocated(set_installed, &filter_prog_hash_ops);
- if (r < 0)
- return log_unit_error_errno(u, r, "Can't allocate BPF program set: %m");
- r = set_put(*set_installed, prog);
+ /* Remember that these BPF programs are installed now. */
+ r = set_ensure_put(set_installed, &filter_prog_hash_ops, prog);
if (r < 0)
return log_unit_error_errno(u, r, "Can't add program to BPF program set: %m");
bpf_program_ref(prog);
return 1; \
}
-#define BUS_DEFINE_SET_CGROUP_PROTECTION(function, mask, scale) \
- static int bus_cgroup_set_##function( \
- Unit *u, \
- const char *name, \
- uint64_t *p, \
- bool *s, \
- sd_bus_message *message, \
- UnitWriteFlags flags, \
- sd_bus_error *error) { \
- \
- uint64_t v = CGROUP_LIMIT_MIN; \
- bool nonempty = true; \
- char type; \
- int r; \
- \
- assert(p); \
- assert(s); \
- \
- r = sd_bus_message_peek_type(message, &type, NULL); \
- if (r < 0) \
- return r; \
- if (type == SD_BUS_TYPE_BOOLEAN) { \
- r = sd_bus_message_read(message, "b", &nonempty); \
- if (r < 0) \
- return r; \
- /* Bool is used to denote empty value only */ \
- if (nonempty) \
- return -EINVAL; \
- } else if (type != SD_BUS_TYPE_UINT64) { \
- return -EINVAL; \
- } else { \
- r = sd_bus_message_read(message, "t", &v); \
- if (r < 0) \
- return r; \
- } \
- \
- if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
- *p = v; \
- unit_invalidate_cgroup(u, mask); \
- if (!nonempty) { \
- *s = false; \
- unit_write_settingf(u, flags, name, \
- "%s=", name); \
- } else if (v == CGROUP_LIMIT_MAX) { \
- *s = true; \
- unit_write_settingf(u, flags, name, \
- "%s=infinity", name); \
- } else { \
- *s = true; \
- unit_write_settingf(u, flags, name, \
- "%s=%" PRIu64, name, v); \
- } \
- } \
- \
- return 1; \
- } \
- static int bus_cgroup_set_##function##_scale( \
- Unit *u, \
- const char *name, \
- uint64_t *p, \
- bool *s, \
- sd_bus_message *message, \
- UnitWriteFlags flags, \
- sd_bus_error *error) { \
- \
- uint64_t v; \
- uint32_t raw; \
- int r; \
- \
- assert(p); \
- assert(s); \
- \
- r = sd_bus_message_read(message, "u", &raw); \
- if (r < 0) \
- return r; \
- \
- v = scale(raw, UINT32_MAX); \
- if (v >= UINT64_MAX) \
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
- "Value specified in %s is out of range", name); \
- \
- if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
- *p = v; \
- unit_invalidate_cgroup(u, mask); \
- \
- /* Prepare to chop off suffix */ \
- assert_se(endswith(name, "Scale")); \
- \
- uint32_t scaled = DIV_ROUND_UP((uint64_t) raw * 1000, (uint64_t) UINT32_MAX); \
- unit_write_settingf(u, flags, name, "%.*s=%" PRIu32 ".%" PRIu32 "%%", \
- (int)(strlen(name) - strlen("Scale")), name, \
- scaled / 10, scaled % 10); \
- } \
- \
- *s = true; \
- return 1; \
- }
-
DISABLE_WARNING_TYPE_LIMITS;
BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_weight, CGROUP_MASK_CPU, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_shares, CGROUP_MASK_CPU, CGROUP_CPU_SHARES_IS_OK, CGROUP_CPU_SHARES_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(io_weight, CGROUP_MASK_IO, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(blockio_weight, CGROUP_MASK_BLKIO, CGROUP_BLKIO_WEIGHT_IS_OK, CGROUP_BLKIO_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_LIMIT(memory, CGROUP_MASK_MEMORY, physical_memory_scale, 1);
+BUS_DEFINE_SET_CGROUP_LIMIT(memory_protection, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
BUS_DEFINE_SET_CGROUP_LIMIT(swap, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
-BUS_DEFINE_SET_CGROUP_PROTECTION(memory_protection, CGROUP_MASK_MEMORY, physical_memory_scale);
REENABLE_WARNING;
static int bus_cgroup_set_tasks_max(
if (streq(name, "MemoryAccounting"))
return bus_cgroup_set_boolean(u, name, &c->memory_accounting, CGROUP_MASK_MEMORY, message, flags, error);
- if (streq(name, "MemoryMin"))
- return bus_cgroup_set_memory_protection(u, name, &c->memory_min, &c->memory_min_set, message, flags, error);
+ if (streq(name, "MemoryMin")) {
+ r = bus_cgroup_set_memory_protection(u, name, &c->memory_min, message, flags, error);
+ if (r > 0)
+ c->memory_min_set = true;
+ return r;
+ }
- if (streq(name, "MemoryLow"))
- return bus_cgroup_set_memory_protection(u, name, &c->memory_low, &c->memory_low_set, message, flags, error);
+ if (streq(name, "MemoryLow")) {
+ r = bus_cgroup_set_memory_protection(u, name, &c->memory_low, message, flags, error);
+ if (r > 0)
+ c->memory_low_set = true;
+ return r;
+ }
- if (streq(name, "DefaultMemoryMin"))
- return bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, &c->default_memory_min_set, message, flags, error);
+ if (streq(name, "DefaultMemoryMin")) {
+ r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, message, flags, error);
+ if (r > 0)
+ c->default_memory_min_set = true;
+ return r;
+ }
- if (streq(name, "DefaultMemoryLow"))
- return bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, &c->default_memory_low_set, message, flags, error);
+ if (streq(name, "DefaultMemoryLow")) {
+ r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, message, flags, error);
+ if (r > 0)
+ c->default_memory_low_set = true;
+ return r;
+ }
if (streq(name, "MemoryHigh"))
return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, error);
if (streq(name, "MemoryLimit"))
return bus_cgroup_set_memory(u, name, &c->memory_limit, message, flags, error);
- if (streq(name, "MemoryMinScale"))
- return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, &c->memory_min_set, message, flags, error);
+ if (streq(name, "MemoryMinScale")) {
+ r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, error);
+ if (r > 0)
+ c->memory_min_set = true;
+ return r;
+ }
- if (streq(name, "MemoryLowScale"))
- return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, &c->memory_low_set, message, flags, error);
+ if (streq(name, "MemoryLowScale")) {
+ r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, message, flags, error);
+ if (r > 0)
+ c->memory_low_set = true;
+ return r;
+ }
- if (streq(name, "DefaultMemoryMinScale"))
- return bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, &c->default_memory_min_set, message, flags, error);
+ if (streq(name, "DefaultMemoryMinScale")) {
+ r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, message, flags, error);
+ if (r > 0)
+ c->default_memory_min_set = true;
+ return r;
+ }
- if (streq(name, "DefaultMemoryLowScale"))
- return bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, &c->default_memory_low_set, message, flags, error);
+ if (streq(name, "DefaultMemoryLowScale")) {
+ r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, message, flags, error);
+ if (r > 0)
+ c->default_memory_low_set = true;
+ return r;
+ }
if (streq(name, "MemoryHighScale"))
return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, error);
return sd_bus_message_close_container(reply);
}
+static int property_get_root_hash(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+
+ assert(bus);
+ assert(c);
+ assert(property);
+ assert(reply);
+
+ return sd_bus_message_append_array(reply, 'y', c->root_hash, c->root_hash_size);
+}
+
const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RootHash", "ay", property_get_root_hash, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RootHashPath", "s", NULL, offsetof(ExecContext, root_hash_path), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
if (streq(name, "RootImage"))
return bus_set_transient_path(u, name, &c->root_image, message, flags, error);
+ if (streq(name, "RootHash")) {
+ const void *roothash_decoded;
+ size_t roothash_decoded_size;
+
+ r = sd_bus_message_read_array(message, 'y', &roothash_decoded, &roothash_decoded_size);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ _cleanup_free_ char *encoded = NULL;
+
+ if (roothash_decoded_size == 0) {
+ c->root_hash_path = mfree(c->root_hash_path);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+
+ unit_write_settingf(u, flags, name, "RootHash=");
+ } else {
+ _cleanup_free_ void *p;
+
+ encoded = hexmem(roothash_decoded, roothash_decoded_size);
+ if (!encoded)
+ return -ENOMEM;
+
+ p = memdup(roothash_decoded, roothash_decoded_size);
+ if (!p)
+ return -ENOMEM;
+
+ free_and_replace(c->root_hash, p);
+ c->root_hash_size = roothash_decoded_size;
+ c->root_hash_path = mfree(c->root_hash_path);
+
+ unit_write_settingf(u, flags, name, "RootHash=%s", encoded);
+ }
+ }
+
+ return 1;
+ }
+
+ if (streq(name, "RootHashPath")) {
+ c->root_hash_size = 0;
+ c->root_hash = mfree(c->root_hash);
+
+ return bus_set_transient_path(u, "RootHash", &c->root_hash_path, message, flags, error);
+ }
+
+ if (streq(name, "RootVerity"))
+ return bus_set_transient_path(u, name, &c->root_verity, message, flags, error);
+
if (streq(name, "RootDirectory"))
return bus_set_transient_path(u, name, &c->root_directory, message, flags, error);
else {
char **s;
- r = set_ensure_allocated(&c->syscall_archs, NULL);
- if (r < 0)
- return r;
-
STRV_FOREACH(s, l) {
uint32_t a;
if (r < 0)
return r;
- r = set_put(c->syscall_archs, UINT32_TO_PTR(a + 1));
+ r = set_ensure_put(&c->syscall_archs, NULL, UINT32_TO_PTR(a + 1));
if (r < 0)
return r;
}
sd_bus_error *error) {
Manager *m = userdata;
- int b;
+ assert(m);
assert(bus);
assert(reply);
- assert(m);
- b = IN_SET(m->show_status, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES);
- return sd_bus_message_append_basic(reply, 'b', &b);
+ return sd_bus_message_append(reply, "b", manager_get_show_status_on(m));
}
static int property_get_runtime_watchdog(
if (r < 0)
return r;
- return manager_set_watchdog_overridden(m, type, timeout);
+ return manager_override_watchdog(m, type, timeout);
}
static int property_set_runtime_watchdog(
return bus_scope_method_abandon(message, u, error);
}
+static int method_set_show_status(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ ShowStatus mode = _SHOW_STATUS_INVALID;
+ const char *t;
+ int r;
+
+ assert(m);
+ assert(message);
+
+ r = sd_bus_message_read(message, "s", &t);
+ if (r < 0)
+ return r;
+
+ if (!isempty(t)) {
+ mode = show_status_from_string(t);
+ if (mode < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid show status '%s'", t);
+ }
+
+ manager_override_show_status(m, mode, "bus");
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_VTABLE_START(0),
NULL,
method_reset_failed,
SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_NAMES("SetShowStatus",
+ "s",
+ SD_BUS_PARAM(mode),
+ NULL,,
+ method_set_show_status,
+ SD_BUS_VTABLE_CAPABILITY(CAP_SYS_ADMIN)),
SD_BUS_METHOD_WITH_NAMES("ListUnits",
NULL,,
"a(ssssssouso)",
#include "terminal-util.h"
#include "virt.h"
+static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
+ [EMERGENCY_ACTION_NONE] = "none",
+ [EMERGENCY_ACTION_REBOOT] = "reboot",
+ [EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
+ [EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
+ [EMERGENCY_ACTION_POWEROFF] = "poweroff",
+ [EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
+ [EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
+ [EMERGENCY_ACTION_EXIT] = "exit",
+ [EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
+};
+
static void log_and_status(Manager *m, bool warn, const char *message, const char *reason) {
log_full(warn ? LOG_WARNING : LOG_DEBUG, "%s: %s", message, reason);
if (warn)
int exit_status,
const char *reason) {
+ Unit *u;
+
assert(m);
assert(action >= 0);
assert(action < _EMERGENCY_ACTION_MAX);
+ /* Is the special shutdown target active or queued? If so, we are in shutdown state */
+ if (IN_SET(action, EMERGENCY_ACTION_REBOOT, EMERGENCY_ACTION_POWEROFF, EMERGENCY_ACTION_EXIT)) {
+ u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
+ if (u && unit_active_or_pending(u)) {
+ log_notice("Shutdown is already active. Skipping emergency action request %s.",
+ emergency_action_table[action]);
+ return;
+ }
+ }
+
if (action == EMERGENCY_ACTION_NONE)
return;
}
}
-static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
- [EMERGENCY_ACTION_NONE] = "none",
- [EMERGENCY_ACTION_REBOOT] = "reboot",
- [EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
- [EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
- [EMERGENCY_ACTION_POWEROFF] = "poweroff",
- [EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
- [EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
- [EMERGENCY_ACTION_EXIT] = "exit",
- [EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
-};
DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction);
int parse_emergency_action(
#include "format-util.h"
#include "fs-util.h"
#include "glob-util.h"
+#include "hexdecoct.h"
#include "io-util.h"
#include "ioprio.h"
#include "label.h"
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
context->mount_flags,
+ context->root_hash, context->root_hash_size, context->root_hash_path, context->root_verity,
DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
error_path);
c->working_directory = mfree(c->working_directory);
c->root_directory = mfree(c->root_directory);
c->root_image = mfree(c->root_image);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+ c->root_hash_path = mfree(c->root_hash_path);
+ c->root_verity = mfree(c->root_verity);
c->tty_path = mfree(c->tty_path);
c->syslog_identifier = mfree(c->syslog_identifier);
c->user = mfree(c->user);
if (c->root_image)
fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
+ if (c->root_hash) {
+ _cleanup_free_ char *encoded = NULL;
+ encoded = hexmem(c->root_hash, c->root_hash_size);
+ if (encoded)
+ fprintf(f, "%sRootHash: %s\n", prefix, encoded);
+ }
+
+ if (c->root_hash_path)
+ fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
+
+ if (c->root_verity)
+ fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
+
STRV_FOREACH(e, c->environment)
fprintf(f, "%sEnvironment: %s\n", prefix, *e);
char **unset_environment;
struct rlimit *rlimit[_RLIMIT_MAX];
- char *working_directory, *root_directory, *root_image;
+ char *working_directory, *root_directory, *root_image, *root_verity, *root_hash_path;
+ void *root_hash;
+ size_t root_hash_size;
bool working_directory_missing_ok:1;
bool working_directory_home:1;
return job_merging_table[(a - 1) * a / 2 + b];
}
-bool job_later_link_matters(Job *j, JobType type, unsigned generation) {
- JobDependency *l;
-
- assert(j);
-
- j->generation = generation;
-
- LIST_FOREACH(subject, l, j->subject_list) {
- UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
-
- /* Have we seen this before? */
- if (l->object->generation == generation)
- continue;
-
- state = unit_active_state(l->object->unit);
- switch (type) {
-
- case JOB_START:
- return IN_SET(state, UNIT_INACTIVE, UNIT_FAILED) ||
- job_later_link_matters(l->object, type, generation);
-
- case JOB_STOP:
- return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING) ||
- job_later_link_matters(l->object, type, generation);
-
- default:
- assert_not_reached("Invalid job type");
- }
- }
-
- return false;
-}
-
-bool job_is_redundant(Job *j, unsigned generation) {
-
- assert(j);
-
- UnitActiveState state = unit_active_state(j->unit);
- switch (j->type) {
+bool job_type_is_redundant(JobType a, UnitActiveState b) {
+ switch (a) {
case JOB_START:
- return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING) && !job_later_link_matters(j, JOB_START, generation);
+ return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
case JOB_STOP:
- return IN_SET(state, UNIT_INACTIVE, UNIT_FAILED) && !job_later_link_matters(j, JOB_STOP, generation);
+ return IN_SET(b, UNIT_INACTIVE, UNIT_FAILED);
case JOB_VERIFY_ACTIVE:
- return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING);
+ return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
case JOB_RELOAD:
return
- state == UNIT_RELOADING;
+ b == UNIT_RELOADING;
case JOB_RESTART:
return
- state == UNIT_ACTIVATING;
+ b == UNIT_ACTIVATING;
case JOB_NOP:
return true;
return a == job_type_lookup_merge(a, b);
}
-bool job_later_link_matters(Job *j, JobType type, unsigned generation);
-bool job_is_redundant(Job *j, unsigned generation);
+bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_;
/* Collapses a state-dependent job type into a simpler type by observing
* the state of the unit which it is going to be applied to. */
`$1.WorkingDirectory, config_parse_working_directory, 0, offsetof($1, exec_context)
$1.RootDirectory, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_directory)
$1.RootImage, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_image)
+$1.RootHash, config_parse_exec_root_hash, 0, offsetof($1, exec_context)
+$1.RootVerity, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_verity)
$1.User, config_parse_user_group_compat, 0, offsetof($1, exec_context.user)
$1.Group, config_parse_user_group_compat, 0, offsetof($1, exec_context.group)
$1.SupplementaryGroups, config_parse_user_group_strv_compat, 0, offsetof($1, exec_context.supplementary_groups)
#include "errno-list.h"
#include "escape.h"
#include "fd-util.h"
+#include "fileio.h"
#include "fs-util.h"
#include "hexdecoct.h"
#include "io-util.h"
return 0;
}
+int config_parse_exec_root_hash(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ void *roothash_decoded = NULL;
+ ExecContext *c = data;
+ size_t roothash_decoded_size = 0;
+ int r;
+
+ assert(data);
+ assert(filename);
+ assert(line);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ /* Reset if the empty string is assigned */
+ c->root_hash_path = mfree(c->root_hash_path);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+ return 0;
+ }
+
+ if (path_is_absolute(rvalue)) {
+ /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
+ _cleanup_free_ char *p = NULL;
+
+ p = strdup(rvalue);
+ if (!p)
+ return -ENOMEM;
+
+ free_and_replace(c->root_hash_path, p);
+ c->root_hash = mfree(c->root_hash);
+ c->root_hash_size = 0;
+ return 0;
+ }
+
+ /* We have a roothash to decode, eg: RootHash=012345789abcdef */
+ r = unhexmem(rvalue, strlen(rvalue), &roothash_decoded, &roothash_decoded_size);
+ if (r < 0)
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode RootHash=, ignoring: %s", rvalue);
+ if (roothash_decoded_size < sizeof(sd_id128_t))
+ return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "RootHash= is too short, ignoring: %s", rvalue);
+
+ free_and_replace(c->root_hash, roothash_decoded);
+ c->root_hash_size = roothash_decoded_size;
+ c->root_hash_path = mfree(c->root_hash_path);
+
+ return 0;
+}
+
int config_parse_exec_cpu_affinity(const char *unit,
const char *filename,
unsigned line,
return 0;
}
- r = set_ensure_allocated(archs, NULL);
- if (r < 0)
- return log_oom();
-
for (;;) {
_cleanup_free_ char *word = NULL;
uint32_t a;
continue;
}
- r = set_put(*archs, UINT32_TO_PTR(a + 1));
+ r = set_ensure_put(archs, NULL, UINT32_TO_PTR(a + 1));
if (r < 0)
return log_oom();
}
}
}
- /* Keep Memory{Low,Min} unset with empty assignment so that we fall back to DefaultMemory* which in
- * contrast means zeroing the property. */
if (streq(lvalue, "DefaultMemoryLow")) {
c->default_memory_low = bytes;
c->default_memory_low_set = true;
c->default_memory_min_set = true;
} else if (streq(lvalue, "MemoryMin")) {
c->memory_min = bytes;
- c->memory_min_set = !isempty(rvalue);
+ c->memory_min_set = true;
} else if (streq(lvalue, "MemoryLow")) {
c->memory_low = bytes;
- c->memory_low_set = !isempty(rvalue);
+ c->memory_low_set = true;
} else if (streq(lvalue, "MemoryHigh"))
c->memory_high = bytes;
else if (streq(lvalue, "MemoryMax"))
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_prio);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
+CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash);
CONFIG_PARSER_PROTOTYPE(config_parse_capability_set);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags);
CONFIG_PARSER_PROTOTYPE(config_parse_timer);
}
if (mac_selinux_init() < 0) {
- error_message = "Failed to initialize SELinux policy";
+ error_message = "Failed to initialize SELinux support";
goto finish;
}
/* clear the kernel timestamp,
* because we are not PID 1 */
kernel_timestamp = DUAL_TIMESTAMP_NULL;
+
+ if (mac_selinux_init() < 0) {
+ error_message = "Failed to initialize SELinux support";
+ goto finish;
+ }
}
if (arg_system) {
.watchdog_overridden[WATCHDOG_REBOOT] = USEC_INFINITY,
.watchdog_overridden[WATCHDOG_KEXEC] = USEC_INFINITY,
+ .show_status_overridden = _SHOW_STATUS_INVALID,
+
.notify_fd = -1,
.cgroups_agent_fd = -1,
.signal_fd = -1,
switch (sfsi.ssi_signo - SIGRTMIN) {
case 20:
- manager_set_show_status(m, SHOW_STATUS_YES, "signal");
+ manager_override_show_status(m, SHOW_STATUS_YES, "signal");
break;
case 21:
- manager_set_show_status(m, SHOW_STATUS_NO, "signal");
+ manager_override_show_status(m, SHOW_STATUS_NO, "signal");
break;
case 22:
/* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */
(void) serialize_bool(f, "honor-device-enumeration", !switching_root);
- t = show_status_to_string(m->show_status);
- if (t)
- (void) serialize_item(f, "show-status", t);
+ if (m->show_status_overridden != _SHOW_STATUS_INVALID)
+ (void) serialize_item(f, "show-status-overridden",
+ show_status_to_string(m->show_status_overridden));
if (m->log_level_overridden)
(void) serialize_item_format(f, "log-level-override", "%i", log_get_max_level());
m->watchdog[t] = timeout;
}
-int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout) {
+int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
int r = 0;
assert(m);
else
m->honor_device_enumeration = b;
- } else if ((val = startswith(l, "show-status="))) {
+ } else if ((val = startswith(l, "show-status-overridden="))) {
ShowStatus s;
s = show_status_from_string(val);
if (s < 0)
- log_notice("Failed to parse show-status flag '%s', ignoring.", val);
+ log_notice("Failed to parse show-status-overridden flag '%s', ignoring.", val);
else
- manager_set_show_status(m, s, "deserialization");
+ manager_override_show_status(m, s, "deserialize");
} else if ((val = startswith(l, "log-level-override="))) {
int level;
if (deserialize_usec(val, &t) < 0)
log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val);
else
- manager_set_watchdog_overridden(m, WATCHDOG_RUNTIME, t);
+ manager_override_watchdog(m, WATCHDOG_RUNTIME, t);
} else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
usec_t t;
if (deserialize_usec(val, &t) < 0)
log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val);
else
- manager_set_watchdog_overridden(m, WATCHDOG_REBOOT, t);
+ manager_override_watchdog(m, WATCHDOG_REBOOT, t);
} else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
usec_t t;
if (deserialize_usec(val, &t) < 0)
log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val);
else
- manager_set_watchdog_overridden(m, WATCHDOG_KEXEC, t);
+ manager_override_watchdog(m, WATCHDOG_KEXEC, t);
} else if (startswith(l, "env=")) {
r = deserialize_environment(l + 4, &m->client_environment);
log_open();
}
+static ShowStatus manager_get_show_status(Manager *m) {
+ assert(m);
+
+ if (MANAGER_IS_USER(m))
+ return _SHOW_STATUS_INVALID;
+
+ if (m->show_status_overridden != _SHOW_STATUS_INVALID)
+ return m->show_status_overridden;
+
+ return m->show_status;
+}
+
+bool manager_get_show_status_on(Manager *m) {
+ assert(m);
+
+ return show_status_on(manager_get_show_status(m));
+}
+
+static void set_show_status_marker(bool b) {
+ if (b)
+ (void) touch("/run/systemd/show-status");
+ else
+ (void) unlink("/run/systemd/show-status");
+}
+
void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason) {
assert(m);
+ assert(reason);
assert(mode >= 0 && mode < _SHOW_STATUS_MAX);
- if (!MANAGER_IS_SYSTEM(m))
+ if (MANAGER_IS_USER(m))
return;
if (mode == m->show_status)
return;
- bool enabled = IN_SET(mode, SHOW_STATUS_TEMPORARY, SHOW_STATUS_YES);
- log_debug("%s (%s) showing of status (%s).",
- enabled ? "Enabling" : "Disabling",
- strna(show_status_to_string(mode)),
- reason);
- m->show_status = mode;
+ if (m->show_status_overridden == _SHOW_STATUS_INVALID) {
+ bool enabled;
- if (enabled)
- (void) touch("/run/systemd/show-status");
- else
- (void) unlink("/run/systemd/show-status");
+ enabled = show_status_on(mode);
+ log_debug("%s (%s) showing of status (%s).",
+ enabled ? "Enabling" : "Disabling",
+ strna(show_status_to_string(mode)),
+ reason);
+
+ set_show_status_marker(enabled);
+ }
+
+ m->show_status = mode;
}
-static bool manager_get_show_status(Manager *m, StatusType type) {
+void manager_override_show_status(Manager *m, ShowStatus mode, const char *reason) {
assert(m);
+ assert(mode < _SHOW_STATUS_MAX);
- if (!MANAGER_IS_SYSTEM(m))
- return false;
+ if (MANAGER_IS_USER(m))
+ return;
- if (m->no_console_output)
- return false;
+ if (mode == m->show_status_overridden)
+ return;
- if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING))
- return false;
+ m->show_status_overridden = mode;
- /* If we cannot find out the status properly, just proceed. */
- if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
- return false;
+ if (mode == _SHOW_STATUS_INVALID)
+ mode = m->show_status;
- if (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO)
- return true;
+ log_debug("%s (%s) showing of status (%s).",
+ m->show_status_overridden != _SHOW_STATUS_INVALID ? "Overriding" : "Restoring",
+ strna(show_status_to_string(mode)),
+ reason);
- return show_status_on(m->show_status);
+ set_show_status_marker(show_status_on(mode));
}
const char *manager_get_confirm_spawn(Manager *m) {
return access("/run/systemd/confirm_spawn_disabled", F_OK) >= 0;
}
+static bool manager_should_show_status(Manager *m, StatusType type) {
+ assert(m);
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return false;
+
+ if (m->no_console_output)
+ return false;
+
+ if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING))
+ return false;
+
+ /* If we cannot find out the status properly, just proceed. */
+ if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
+ return false;
+
+ if (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO)
+ return true;
+
+ return manager_get_show_status_on(m);
+}
+
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) {
va_list ap;
/* If m is NULL, assume we're after shutdown and let the messages through. */
- if (m && !manager_get_show_status(m, type))
+ if (m && !manager_should_show_status(m, type))
return;
/* XXX We should totally drop the check for ephemeral here
size = set_size(m->failed_units);
if (failed) {
- r = set_ensure_allocated(&m->failed_units, NULL);
+ r = set_ensure_put(&m->failed_units, NULL, u);
if (r < 0)
return log_oom();
-
- if (set_put(m->failed_units, u) < 0)
- return log_oom();
} else
(void) set_remove(m->failed_units, u);
uint8_t return_value;
ShowStatus show_status;
+ ShowStatus show_status_overridden;
StatusUnitFormat status_unit_format;
char *confirm_spawn;
bool no_console_output;
void manager_recheck_dbus(Manager *m);
void manager_recheck_journal(Manager *m);
+bool manager_get_show_status_on(Manager *m);
void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason);
+void manager_override_show_status(Manager *m, ShowStatus mode, const char *reason);
+
void manager_set_first_boot(Manager *m, bool b);
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5);
usec_t manager_get_watchdog(Manager *m, WatchdogType t);
void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout);
-int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout);
+int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout);
const char* oom_policy_to_string(OOMPolicy i) _const_;
OOMPolicy oom_policy_from_string(const char *s) _pure_;
ProtectHome protect_home,
ProtectSystem protect_system,
unsigned long mount_flags,
+ const void *root_hash,
+ size_t root_hash_size,
+ const char *root_hash_path,
+ const char *root_verity,
DissectImageFlags dissect_image_flags,
char **error_path) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
- _cleanup_free_ void *root_hash = NULL;
+ _cleanup_free_ void *root_hash_decoded = NULL;
_cleanup_free_ char *verity_data = NULL;
MountEntry *m = NULL, *mounts = NULL;
- size_t n_mounts, root_hash_size = 0;
+ size_t n_mounts;
bool require_prefix = false;
const char *root;
int r = 0;
if (r < 0)
return log_debug_errno(r, "Failed to create loop device for root image: %m");
- r = verity_metadata_load(root_image, &root_hash, &root_hash_size, &verity_data);
+ r = verity_metadata_load(root_image, root_hash_path, root_hash ? NULL : &root_hash_decoded, root_hash ? NULL : &root_hash_size, root_verity ? NULL : &verity_data);
if (r < 0)
return log_debug_errno(r, "Failed to load root hash: %m");
- dissect_image_flags |= verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
+ dissect_image_flags |= root_verity || verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
- r = dissect_image(loop_device->fd, root_hash, root_hash_size, verity_data, dissect_image_flags, &dissected_image);
+ r = dissect_image(loop_device->fd, root_hash ?: root_hash_decoded, root_hash_size, root_verity ?: verity_data, dissect_image_flags, &dissected_image);
if (r < 0)
return log_debug_errno(r, "Failed to dissect image: %m");
- r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, verity_data, dissect_image_flags, &decrypted_image);
+ r = dissected_image_decrypt(dissected_image, NULL, root_hash ?: root_hash_decoded, root_hash_size, root_verity ?: verity_data, dissect_image_flags, &decrypted_image);
if (r < 0)
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
}
ProtectHome protect_home,
ProtectSystem protect_system,
unsigned long mount_flags,
+ const void *root_hash,
+ size_t root_hash_size,
+ const char *root_hash_path,
+ const char *root_verity,
DissectImageFlags dissected_image_flags,
char **error_path);
send_interface="org.freedesktop.systemd1.Manager"
send_member="AddDependencyUnitFiles"/>
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
+ send_member="SetShowStatus"/>
+
<!-- Managed via polkit or other criteria: org.freedesktop.systemd1.Job interface -->
<allow send_destination="org.freedesktop.systemd1"
return 0;
}
-static void transaction_drop_redundant(Transaction *tr, unsigned generation) {
+static void transaction_drop_redundant(Transaction *tr) {
bool again;
/* Goes through the transaction and removes all jobs of the units whose jobs are all noops. If not
LIST_FOREACH(transaction, k, j)
if (tr->anchor_job == k ||
- !job_is_redundant(k, generation) ||
+ !job_type_is_redundant(k->type, unit_active_state(k->unit)) ||
(k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type))) {
keep = true;
break;
transaction_minimize_impact(tr);
/* Third step: Drop redundant jobs */
- transaction_drop_redundant(tr, generation++);
+ transaction_drop_redundant(tr);
for (;;) {
/* Fourth step: Let's remove unneeded jobs that might
}
/* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
- transaction_drop_redundant(tr, generation++);
+ transaction_drop_redundant(tr);
/* Ninth step: check whether we can actually apply this */
r = transaction_is_destructive(tr, mode, e);
static int unit_add_startup_units(Unit *u) {
CGroupContext *c;
- int r;
c = unit_get_cgroup_context(u);
if (!c)
c->startup_blockio_weight == CGROUP_BLKIO_WEIGHT_INVALID)
return 0;
- r = set_ensure_allocated(&u->manager->startup_units, NULL);
- if (r < 0)
- return r;
-
- return set_put(u->manager->startup_units, u);
+ return set_ensure_put(&u->manager->startup_units, NULL, u);
}
int unit_load(Unit *u) {
int r, units_active;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
/* The journal merging logic potentially needs a lot of fds. */
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
static int run(int argc, char *argv[]) {
int r, k, n_found = 0;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
* to detect whether we are being run in a virtualized
* environment or not */
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
if (r < 0)
return log_error_errno(r, "Failed to set up loopback device: %m");
- r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
+ r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
arg_verity_data ? NULL : &arg_verity_data);
if (r < 0)
return log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
char **i;
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
return r;
umask(0022);
- mac_selinux_init();
+
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
if (r <= 0)
return r;
- mac_selinux_init();
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
return hwdb_main(argc, argv);
}
static int run(int argc, char *argv[]) {
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
int r;
log_show_color(true);
- log_parse_environment();
+ log_parse_environment_cli();
/* The journal merging logic potentially needs a lot of fds. */
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
int r;
log_show_color(true);
- log_parse_environment();
+ log_parse_environment_cli();
/* The journal merging logic potentially needs a lot of fds. */
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
_cleanup_close_ int outfd = -1, errfd = -1, saved_stderr = -1;
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Bad --facility= argument \"%s\".", fac);
- r = set_ensure_allocated(&arg_facilities, NULL);
- if (r < 0)
- return log_oom();
-
- r = set_put(arg_facilities, INT_TO_PTR(num));
- if (r < 0)
+ if (set_ensure_put(&arg_facilities, NULL, INT_TO_PTR(num)) < 0)
return log_oom();
}
int n_shown = 0, r, poll_fd = -1;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
/* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
* split up into many files. */
int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);
int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len);
-
-int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
-int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
/* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */
struct sd_dhcp_route;
+struct sd_dhcp_lease;
void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size);
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string);
/* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */
int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size);
+
+int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
+int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
"ADDRESS", &address,
"ROUTER", &router,
"NETMASK", &netmask,
- "SERVER_IDENTIFIER", &server_address,
+ "SERVER_ADDRESS", &server_address,
"NEXT_SERVER", &next_server,
"BROADCAST", &broadcast,
"DNS", &dns,
if (!IN_SET(h->version, 1, 2))
return -EBADMSG;
- if (h->type <= _SD_BUS_MESSAGE_TYPE_INVALID || h->type >= _SD_BUS_MESSAGE_TYPE_MAX)
+ if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
return -EBADMSG;
if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN))
assert_return(bus = bus_resolve(bus), -ENOPKG);
assert_return(bus->state != BUS_UNSET, -ENOTCONN);
assert_return(m, -EINVAL);
- assert_return(type > _SD_BUS_MESSAGE_TYPE_INVALID && type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
+ /* Creation of messages with _SD_BUS_MESSAGE_TYPE_INVALID is allowed. */
+ assert_return(type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
sd_bus_message *t = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
if (!t)
return 0;
}
- shift = part->memfd_offset - ((part->memfd_offset / page_size()) * page_size());
+ shift = PAGE_OFFSET(part->memfd_offset);
psz = PAGE_ALIGN(part->size + shift);
if (part->memfd >= 0)
return NULL;
if (p)
- *p = (uint8_t*) part->data + index - begin;
+ *p = part->data ? (uint8_t*) part->data + index - begin
+ : NULL; /* Avoid dereferencing a NULL pointer. */
m->cached_rindex_part = part;
m->cached_rindex_part_begin = begin;
if (m->reply_cookie == 0 || !m->error.name)
return -EBADMSG;
break;
-
- default:
- assert_not_reached("Bad message type");
}
/* Refuse non-local messages that claim they are local */
}
_public_ int sd_device_monitor_filter_add_match_tag(sd_device_monitor *m, const char *tag) {
- _cleanup_free_ char *t = NULL;
- int r;
-
assert_return(m, -EINVAL);
assert_return(tag, -EINVAL);
- t = strdup(tag);
- if (!t)
- return -ENOMEM;
-
- r = set_ensure_allocated(&m->tag_filter, &string_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(m->tag_filter, t);
- if (r == -EEXIST)
- return 0;
- if (r < 0)
- return r;
-
- TAKE_PTR(t);
- m->filter_uptodate = false;
-
- return 0;
+ int r = set_put_strdup(&m->tag_filter, tag);
+ if (r > 0)
+ m->filter_uptodate = false;
+ return r;
}
_public_ int sd_device_monitor_filter_remove(sd_device_monitor *m) {
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
- r = set_ensure_allocated(&e->post_sources, NULL);
- if (r < 0)
- return r;
-
s = source_new(e, !ret, SOURCE_POST);
if (!s)
return -ENOMEM;
s->userdata = userdata;
s->enabled = SD_EVENT_ON;
- r = set_put(e->post_sources, s);
+ r = set_ensure_put(&e->post_sources, NULL, s);
if (r < 0)
return r;
+ assert(r > 0);
if (ret)
*ret = s;
return network_link_get_string(ifindex, "ADDRESS_STATE", state);
}
-_public_ int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id) {
- return network_link_get_string(ifindex, "DHCP4_CLIENT_ID", client_id);
-}
-
_public_ int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **iaid) {
return network_link_get_string(ifindex, "DHCP6_CLIENT_IAID", iaid);
}
return network_link_get_strv(ifindex, "DNSSEC_NTA", nta);
}
-_public_ int sd_network_link_get_timezone(int ifindex, char **ret) {
- return network_link_get_string(ifindex, "TIMEZONE", ret);
-}
-
-_public_ int sd_network_link_get_dhcp4_address(int ifindex, char **ret) {
- return network_link_get_string(ifindex, "DHCP4_ADDRESS", ret);
-}
-
_public_ int sd_network_link_get_dns(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "DNS", ret);
}
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
#include "bus-message.h"
#include "bus-polkit.h"
#include "def.h"
+#include "dlfcn-util.h"
#include "keymap-util.h"
#include "locale-util.h"
#include "macro.h"
};
struct xkb_context *ctx = NULL;
struct xkb_keymap *km = NULL;
- void *dl;
+ _cleanup_(dlclosep) void *dl = NULL;
int r;
/* Compile keymap from RMLVO information to check out its validity */
if (symbol_xkb_context_unref && ctx)
symbol_xkb_context_unref(ctx);
- (void) dlclose(dl);
return r;
}
return r;
umask(0022);
- mac_selinux_init();
+
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
'src/locale/keymap-util.c',
'src/locale/keymap-util.h'],
[libshared],
- [libdl]],
+ []],
]
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
/* The journal merging logic potentially needs a lot of fds. */
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
if (r <= 0)
return r;
- r = set_ensure_allocated(set, &bus_message_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(*set, message);
- if (r < 0)
+ r = set_ensure_put(set, &bus_message_hash_ops, message);
+ if (r <= 0)
return r;
-
sd_bus_message_ref(message);
+
return 1;
}
r = mac_selinux_init();
if (r < 0)
- return log_error_errno(r, "Could not initialize labelling: %m");
+ return r;
/* Always create the directories people can create inotify watches in. Note that some applications might check
* for the existence of /run/systemd/seats/ to determine whether logind is available, so please always make
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"First argument must be either \"start\" or \"stop\".");
+ umask(0022);
+
r = mac_selinux_init();
if (r < 0)
- return log_error_errno(r, "Could not initialize labelling: %m\n");
-
- umask(0022);
+ return r;
if (streq(argv[1], "start"))
return do_mount(argv[2]);
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
/* The journal merging logic potentially needs a lot of fds. */
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
if (ret != 0) {
log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", peer->endpoint_host, peer->endpoint_port, gai_strerror(ret));
- r = set_ensure_allocated(&w->peers_with_failed_endpoint, NULL);
- if (r < 0) {
- log_oom();
- peer->section->invalid = true;
- goto resolve_next;
- }
-
- r = set_put(w->peers_with_failed_endpoint, peer);
+ r = set_ensure_put(&w->peers_with_failed_endpoint, NULL, peer);
if (r < 0) {
log_netdev_error(netdev, "Failed to save a peer, dropping the peer: %m");
peer->section->invalid = true;
void *data,
void *userdata) {
- _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
+ WireguardPeer *peer;
Wireguard *w;
int r;
if (r < 0)
return r;
- r = wireguard_decode_key_and_warn(rvalue, peer->preshared_key, unit, filename, line, lvalue);
- if (r < 0)
- return r;
-
- TAKE_PTR(peer);
- return 0;
+ return wireguard_decode_key_and_warn(rvalue, peer->preshared_key, unit, filename, line, lvalue);
}
int config_parse_wireguard_preshared_key_file(
w = WIREGUARD(data);
assert(w);
- r = wireguard_peer_new_static(w, filename, section_line, &peer);
- if (r < 0)
- return r;
-
if (rvalue[0] == '[') {
begin = &rvalue[1];
end = strchr(rvalue, ']');
++end;
}
+ r = wireguard_peer_new_static(w, filename, section_line, &peer);
+ if (r < 0)
+ return r;
+
r = free_and_strndup(&peer->endpoint_host, begin, len);
if (r < 0)
return log_oom();
if (r < 0)
return log_oom();
- r = set_ensure_allocated(&w->peers_with_unresolved_endpoint, NULL);
+ r = set_ensure_put(&w->peers_with_unresolved_endpoint, NULL, peer);
if (r < 0)
return log_oom();
+ TAKE_PTR(peer); /* The peer may already have been in the hash map, that is fine too. */
- r = set_put(w->peers_with_unresolved_endpoint, peer);
- if (r < 0)
- return r;
-
- TAKE_PTR(peer);
return 0;
}
void *data,
void *userdata) {
- _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
+ WireguardPeer *peer;
uint16_t keepalive = 0;
Wireguard *w;
int r;
r = safe_atou16(rvalue, &keepalive);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "The persistent keepalive interval must be 0-65535. Ignore assignment: %s",
+ "Failed to parse \"%s\" as keepalive interval (range 0–65535), ignoring assignment: %m",
rvalue);
return 0;
}
}
peer->persistent_keepalive_interval = keepalive;
-
- TAKE_PTR(peer);
return 0;
}
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <arpa/inet.h>
#include <getopt.h>
#include <linux/if_addrlabel.h>
#include <net/if.h>
static int dump_addresses(
sd_netlink *rtnl,
+ sd_dhcp_lease *lease,
Table *table,
int ifindex) {
_cleanup_free_ struct local_address *local = NULL;
- _cleanup_free_ char *dhcp4_address = NULL;
_cleanup_strv_free_ char **buf = NULL;
+ struct in_addr dhcp4_address = {};
int r, n, i;
assert(rtnl);
if (n <= 0)
return n;
- (void) sd_network_link_get_dhcp4_address(ifindex, &dhcp4_address);
+ if (lease)
+ (void) sd_dhcp_lease_get_address(lease, &dhcp4_address);
for (i = 0; i < n; i++) {
_cleanup_free_ char *pretty = NULL;
if (r < 0)
return r;
- if (dhcp4_address && streq(pretty, dhcp4_address)) {
- _cleanup_free_ char *p = NULL;
+ if (local[i].family == AF_INET && in4_addr_equal(&local[i].address.in, &dhcp4_address)) {
+ struct in_addr server_address;
+ char *p, s[INET_ADDRSTRLEN];
- p = pretty;
- pretty = strjoin(pretty , " (DHCP4)");
- if (!pretty)
+ r = sd_dhcp_lease_get_server_identifier(lease, &server_address);
+ if (r >= 0 && inet_ntop(AF_INET, &server_address, s, sizeof(s)))
+ p = strjoin(pretty, " (DHCP4 via ", s, ")");
+ else
+ p = strjoin(pretty, " (DHCP4)");
+ if (!p)
return log_oom();
+
+ free_and_replace(pretty, p);
}
r = strv_extendf(&buf, "%s%s%s",
const LinkInfo *info) {
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL;
- _cleanup_free_ char *t = NULL, *network = NULL, *client_id = NULL, *iaid = NULL, *duid = NULL;
- const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
- _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
- const char *on_color_operational, *off_color_operational,
- *on_color_setup, *off_color_setup;
+ _cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL,
+ *setup_state = NULL, *operational_state = NULL, *lease_file = NULL;
+ const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL,
+ *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup;
_cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL;
+ _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
_cleanup_(table_unrefp) Table *table = NULL;
TableCell *cell;
int r;
(void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
(void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
+ if (asprintf(&lease_file, "/run/systemd/netif/leases/%d", info->ifindex) < 0)
+ return log_oom();
+
+ (void) dhcp_lease_load(&lease, lease_file);
+
table = table_new("dot", "key", "value");
if (!table)
return log_oom();
}
}
- r = dump_addresses(rtnl, table, info->ifindex);
+ r = dump_addresses(rtnl, lease, table, info->ifindex);
if (r < 0)
return r;
r = dump_gateways(rtnl, hwdb, table, info->ifindex);
if (r < 0)
return r;
- (void) sd_network_link_get_timezone(info->ifindex, &tz);
- if (tz) {
- r = table_add_many(table,
- TABLE_EMPTY,
- TABLE_STRING, "Time Zone:",
- TABLE_STRING, tz);
- if (r < 0)
- return table_log_add_error(r);
- }
+ if (lease) {
+ const void *client_id;
+ size_t client_id_len;
+ const char *tz;
- r = sd_network_link_get_dhcp4_client_id_string(info->ifindex, &client_id);
- if (r >= 0) {
- r = table_add_many(table,
- TABLE_EMPTY,
- TABLE_STRING, "DHCP4 Client ID:",
- TABLE_STRING, client_id);
- if (r < 0)
- return table_log_add_error(r);
+ r = sd_dhcp_lease_get_timezone(lease, &tz);
+ if (r >= 0) {
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "Time Zone:",
+ TABLE_STRING, tz);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
+ r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
+ if (r >= 0) {
+ _cleanup_free_ char *id = NULL;
+
+ r = sd_dhcp_client_id_to_string(client_id, client_id_len, &id);
+ if (r >= 0) {
+ r = table_add_many(table,
+ TABLE_EMPTY,
+ TABLE_STRING, "DHCP4 Client ID:",
+ TABLE_STRING, id);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+ }
}
r = sd_network_link_get_dhcp6_client_iaid_string(info->ifindex, &iaid);
if (r < 0)
return table_log_add_error(r);
- r = dump_addresses(rtnl, table, 0);
+ r = dump_addresses(rtnl, NULL, table, 0);
if (r < 0)
return r;
r = dump_gateways(rtnl, hwdb, table, 0);
static int run(int argc, char* argv[]) {
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
/* Consider address tentative until we get the real flags from the kernel */
address->flags = IFA_F_TENTATIVE;
- r = set_ensure_allocated(addresses, &address_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(*addresses, address);
+ r = set_ensure_put(addresses, &address_hash_ops, address);
if (r < 0)
return r;
if (r == 0)
if (ret)
*ret = address;
-
- address = NULL;
-
+ TAKE_PTR(address);
return 0;
}
return r;
} else if (r == 0) {
/* Take over a foreign address */
- r = set_ensure_allocated(&link->addresses, &address_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(link->addresses, address);
+ r = set_ensure_put(&link->addresses, &address_hash_ops, address);
if (r < 0)
return r;
continue;
}
- if (ltype == AF_INET)
- r = set_ensure_allocated(&network->dhcp_request_options, NULL);
- else
- r = set_ensure_allocated(&network->dhcp6_request_options, NULL);
- if (r < 0)
- return log_oom();
-
- if (ltype == AF_INET)
- r = set_put(network->dhcp_request_options, UINT32_TO_PTR(i));
- else
- r = set_put(network->dhcp6_request_options, UINT32_TO_PTR(i));
+ r = set_ensure_put(ltype == AF_INET ? &network->dhcp_request_options : &network->dhcp6_request_options,
+ NULL, UINT32_TO_PTR(i));
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to store DHCP request option '%s', ignoring assignment: %m", n);
case SD_DHCP_LEASE_LPR:
/* For the other server types we currently do not allow local configuration of server data,
* since there are typically no local consumers of the data. */
- ;
+ break;
default:
assert_not_reached("Unexpected server type");
void *userdata) {
Network *network = data;
- const char *p;
int r;
assert(filename);
return 0;
}
- for (p = rvalue;;) {
+ for (const char *p = rvalue;;) {
_cleanup_free_ char *n = NULL;
union in_addr_union ip;
continue;
}
- r = set_ensure_allocated(&network->dhcp_black_listed_ip, NULL);
- if (r < 0)
- return log_oom();
-
- r = set_put(network->dhcp_black_listed_ip, UINT32_TO_PTR(ip.in.s_addr));
+ r = set_ensure_put(&network->dhcp_black_listed_ip, NULL, UINT32_TO_PTR(ip.in.s_addr));
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to store DHCP black listed ip address '%s', ignoring assignment: %m", n);
address->in_addr.in6 = *prefix;
if (!in_addr_is_null(AF_INET6, &link->network->dhcp6_delegation_prefix_token))
- memcpy(&address->in_addr.in6.s6_addr + 8, &link->network->dhcp6_delegation_prefix_token.in6.s6_addr + 8, 8);
+ memcpy(address->in_addr.in6.s6_addr + 8, link->network->dhcp6_delegation_prefix_token.in6.s6_addr + 8, 8);
else {
r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
if (r < 0)
if (r < 0)
return r;
- r = set_ensure_allocated(&master->slaves, NULL);
- if (r < 0)
- return r;
-
- r = set_put(master->slaves, link);
+ r = set_ensure_put(&master->slaves, NULL, link);
if (r <= 0)
return r;
r = set_put(m->links_requesting_uuid, link);
if (r < 0)
return log_oom();
+ if (r > 0)
+ link_ref(link);
r = set_put(m->duids_requesting_uuid, duid);
if (r < 0)
return log_oom();
-
- link_ref(link);
}
return 0;
print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
if (link->dhcp_lease) {
- struct in_addr address;
- const char *tz = NULL;
- size_t client_id_len;
- const void *client_id;
-
- assert(link->network);
-
- r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
- if (r >= 0)
- fprintf(f, "TIMEZONE=%s\n", tz);
-
- r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
- if (r >= 0) {
- fputs("DHCP4_ADDRESS=", f);
- serialize_in_addrs(f, &address, 1, NULL, NULL);
- fputc('\n', f);
- }
-
- r = sd_dhcp_lease_get_client_id(link->dhcp_lease, &client_id, &client_id_len);
- if (r >= 0) {
- _cleanup_free_ char *id = NULL;
-
- r = sd_dhcp_client_id_to_string(client_id, client_id_len, &id);
- if (r >= 0)
- fprintf(f, "DHCP4_CLIENT_ID=%s\n", id);
- }
-
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
if (r < 0)
goto fail;
/* mark manager dirty as link is dirty */
manager_dirty(link->manager);
- r = set_ensure_allocated(&link->manager->dirty_links, NULL);
- if (r < 0)
- /* allocation errors are ignored */
- return;
-
- r = set_put(link->manager->dirty_links, link);
+ r = set_ensure_put(&link->manager->dirty_links, NULL, link);
if (r <= 0)
- /* don't take another ref if the link was already dirty */
+ /* Ignore allocation errors and don't take another ref if the link was already dirty */
return;
-
link_ref(link);
}
assert_se(duid = link_get_duid(link));
- r = set_ensure_allocated(&m->links_requesting_uuid, NULL);
+ r = set_ensure_put(&m->links_requesting_uuid, NULL, link);
if (r < 0)
return log_oom();
+ if (r > 0)
+ link_ref(link);
- r = set_ensure_allocated(&m->duids_requesting_uuid, NULL);
+ r = set_ensure_put(&m->duids_requesting_uuid, NULL, duid);
if (r < 0)
return log_oom();
-
- r = set_put(m->links_requesting_uuid, link);
- if (r < 0)
- return log_oom();
-
- r = set_put(m->duids_requesting_uuid, duid);
- if (r < 0)
- return log_oom();
-
- link_ref(link);
}
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
continue;
}
- r = set_ensure_allocated(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops);
- if (r < 0)
- return log_oom();
-
x = new(NDiscRDNSS, 1);
if (!x)
return log_oom();
.valid_until = time_now + lifetime * USEC_PER_SEC,
};
- r = set_put(link->ndisc_rdnss, x);
+ r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
if (r < 0)
return log_oom();
-
- TAKE_PTR(x);
-
assert(r > 0);
+
link_dirty(link);
}
continue;
}
- r = set_ensure_allocated(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops);
- if (r < 0) {
- log_oom();
- return;
- }
-
s->valid_until = time_now + lifetime * USEC_PER_SEC;
- r = set_put(link->ndisc_dnssl, s);
+ r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
if (r < 0) {
log_oom();
return;
}
-
- s = NULL;
assert(r > 0);
+
link_dirty(link);
}
}
if (set_contains(network->ndisc_black_listed_prefix, &ip.in6))
continue;
- r = set_ensure_allocated(&network->ndisc_black_listed_prefix, &in6_addr_hash_ops);
- if (r < 0)
- return log_oom();
-
a = newdup(struct in6_addr, &ip.in6, 1);
if (!a)
return log_oom();
- r = set_put(network->ndisc_black_listed_prefix, a);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to store NDISC black listed prefix '%s', ignoring assignment: %m", n);
- continue;
- }
-
- TAKE_PTR(a);
+ r = set_ensure_consume(&network->ndisc_black_listed_prefix, &in6_addr_hash_ops, TAKE_PTR(a));
+ if (r < 0)
+ return log_oom();
}
return 0;
.lladdr_size = lladdr_size,
};
- r = set_ensure_allocated(neighbors, &neighbor_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(*neighbors, neighbor);
+ r = set_ensure_put(neighbors, &neighbor_hash_ops, neighbor);
if (r < 0)
return r;
if (r == 0)
if (ret)
*ret = neighbor;
-
- neighbor = NULL;
+ TAKE_PTR(neighbor);
return 0;
}
return r;
} else if (r == 0) {
/* Neighbor is foreign, claim it as recognized */
- r = set_ensure_allocated(&link->neighbors, &neighbor_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(link->neighbors, neighbor);
+ r = set_ensure_put(&link->neighbors, &neighbor_hash_ops, neighbor);
if (r < 0)
return r;
continue;
}
- r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
+ r = set_ensure_consume(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops, TAKE_PTR(w));
if (r < 0)
return log_oom();
-
- r = set_put(n->dnssec_negative_trust_anchors, w);
- if (r < 0)
- return log_oom();
- if (r > 0)
- w = NULL;
}
return 0;
nexthop->family = in->family;
nexthop->gw = in->gw;
- r = set_ensure_allocated(nexthops, &nexthop_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(*nexthops, nexthop);
+ r = set_ensure_put(nexthops, &nexthop_hash_ops, nexthop);
if (r < 0)
return r;
if (r == 0)
return r;
} else if (r == 0) {
/* Take over a foreign nexthop */
- r = set_ensure_allocated(&link->nexthops, &nexthop_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(link->nexthops, nexthop);
+ r = set_ensure_put(&link->nexthops, &nexthop_hash_ops, nexthop);
if (r < 0)
return r;
route->initrwnd = in->initrwnd;
route->lifetime = in->lifetime;
- r = set_ensure_allocated(routes, &route_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(*routes, route);
+ r = set_ensure_put(routes, &route_hash_ops, route);
if (r < 0)
return r;
if (r == 0)
return r;
} else if (r == 0) {
/* Take over a foreign route */
- r = set_ensure_allocated(&link->routes, &route_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(link->routes, route);
+ r = set_ensure_put(&link->routes, &route_hash_ops, route);
if (r < 0)
return r;
if (set_contains(m->rules_foreign, rule)) {
set_remove(m->rules_foreign, rule);
- r = set_ensure_allocated(&m->rules, &routing_policy_rule_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(m->rules, rule);
+ r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, rule);
if (r < 0)
return r;
if (r == 0)
if (r < 0)
return r;
- r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(*rules, rule);
+ r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);
if (r < 0)
return r;
if (r == 0)
if (!l)
return -ENOMEM;
- r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
- if (r < 0)
- return r;
-
STRV_FOREACH(i, l) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
}
}
- r = set_put(*rules, rule);
+ r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);
if (r < 0) {
log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
continue;
#if HAVE_SELINUX
{ "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND,
- 0 }, /* Bind mount first */
+ MOUNT_MKDIR }, /* Bind mount first (mkdir/chown the mount point in case /sys/ is mounted as minimal skeleton tmpfs) */
{ NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
- 0 }, /* Then, make it r/o */
+ 0 }, /* Then, make it r/o (don't mkdir/chown the mount point here, the previous entry already did that) */
#endif
};
goto finish;
}
- r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
+ r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
arg_verity_data ? NULL : &arg_verity_data);
if (r < 0) {
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
#include "fd-util.h"
#include "group-record-nss.h"
#include "macro.h"
+#include "nss-systemd.h"
#include "nss-util.h"
#include "pthread-util.h"
#include "signal-util.h"
PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
- if (userdb_nss_compat_is_enabled() <= 0)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
- if (userdb_nss_compat_is_enabled() <= 0)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
assert(result);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- UNPROTECT_ERRNO;
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
assert(result);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- UNPROTECT_ERRNO;
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
- return NSS_STATUS_UNAVAIL;
+ if (_nss_systemd_is_blocked())
+ return NSS_STATUS_NOTFOUND;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
}
if (getgrent_data.by_membership) {
- _cleanup_close_ int lock_fd = -1;
+ _cleanup_(_nss_systemd_unblockp) bool blocked = false;
for (;;) {
_cleanup_free_ char *user_name = NULL, *group_name = NULL;
continue;
/* We are about to recursively call into NSS, let's make sure we disable recursion into our own code. */
- if (lock_fd < 0) {
- lock_fd = userdb_nss_compat_disable();
- if (lock_fd < 0 && lock_fd != -EBUSY) {
+ if (!blocked) {
+ r = _nss_systemd_block(true);
+ if (r < 0) {
UNPROTECT_ERRNO;
- *errnop = -lock_fd;
+ *errnop = -r;
return NSS_STATUS_UNAVAIL;
}
+
+ blocked = true;
}
r = nss_group_record_by_name(group_name, false, &gr);
if (STR_IN_SET(user_name, root_passwd.pw_name, nobody_passwd.pw_name))
return NSS_STATUS_NOTFOUND;
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- UNPROTECT_ERRNO;
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
r = membershipdb_by_user(user_name, nss_glue_userdb_flags(), &iterator);
/* The group might be defined via traditional NSS only, hence let's do a full look-up without
* disabling NSS. This means we are operating recursively here. */
- r = groupdb_by_name(group_name, nss_glue_userdb_flags() & ~USERDB_AVOID_NSS, &g);
+ r = groupdb_by_name(group_name, (nss_glue_userdb_flags() & ~USERDB_AVOID_NSS) | USERDB_AVOID_SHADOW, &g);
if (r == -ESRCH)
continue;
if (r < 0) {
return any ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND;
}
+
+static thread_local unsigned _blocked = 0;
+
+_public_ int _nss_systemd_block(bool b) {
+
+ /* This blocks recursively: it's blocked for as many times this function is called with `true` until
+ * it is called an equal time with `false`. */
+
+ if (b) {
+ if (_blocked >= UINT_MAX)
+ return -EOVERFLOW;
+
+ _blocked++;
+ } else {
+ if (_blocked <= 0)
+ return -EOVERFLOW;
+
+ _blocked--;
+ }
+
+ return b; /* Return what is passed in, i.e. the new state from the PoV of the caller */
+}
+
+_public_ bool _nss_systemd_is_blocked(void) {
+ return _blocked > 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+
+int _nss_systemd_block(bool b);
+bool _nss_systemd_is_blocked(void);
+
+/* For use with the _cleanup_() macro */
+static inline void _nss_systemd_unblockp(bool *b) {
+ if (*b)
+ assert_se(_nss_systemd_block(false) >= 0);
+}
_nss_systemd_setgrent;
_nss_systemd_getgrent_r;
_nss_systemd_initgroups_dyn;
+
+ /* These two are not used by glibc, but can be used by apps to explicitly disable nss-systemd for the calling thread. */
+ _nss_systemd_block;
+ _nss_systemd_is_blocked;
local: *;
};
#include "env-util.h"
#include "fd-util.h"
#include "group-record-nss.h"
+#include "nss-systemd.h"
#include "strv.h"
#include "user-record.h"
#include "userdb-glue.h"
assert(pwd);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
r = userdb_by_name(name, nss_glue_userdb_flags(), &hr);
assert(pwd);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
r = userdb_by_uid(uid, nss_glue_userdb_flags(), &hr);
assert(gr);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
r = groupdb_by_name(name, nss_glue_userdb_flags(), &g);
}
if (!g) {
- _cleanup_close_ int lock_fd = -1;
+ _cleanup_(_nss_systemd_unblockp) bool blocked = false;
if (strv_isempty(members))
return NSS_STATUS_NOTFOUND;
* acquire it, so that we can extend it (that's because glibc's group merging feature will
* merge groups only if both GID and name match and thus we need to have both first). It
* sucks behaving recursively likely this, but it's apparently what everybody does. We break
- * the recursion for ourselves via the userdb_nss_compat_disable() lock. */
+ * the recursion for ourselves via the _nss_systemd_block_nss() lock. */
+
+ r = _nss_systemd_block(true);
+ if (r < 0)
+ return r;
- lock_fd = userdb_nss_compat_disable();
- if (lock_fd < 0 && lock_fd != -EBUSY)
- return lock_fd;
+ blocked = true;
r = nss_group_record_by_name(name, false, &g);
if (r == -ESRCH)
assert(gr);
assert(errnop);
- r = userdb_nss_compat_is_enabled();
- if (r < 0) {
- *errnop = -r;
- return NSS_STATUS_UNAVAIL;
- }
- if (!r)
+ if (_nss_systemd_is_blocked())
return NSS_STATUS_NOTFOUND;
r = groupdb_by_gid(gid, nss_glue_userdb_flags(), &g);
}
if (!g) {
- _cleanup_close_ int lock_fd = -1;
+ _cleanup_(_nss_systemd_unblockp) bool blocked = false;
/* So, quite possibly we have to extend an existing group record with additional members. But
* to do this we need to know the group name first. The group didn't exist via non-NSS
* queries though, hence let's try to acquire it here recursively via NSS. */
- lock_fd = userdb_nss_compat_disable();
- if (lock_fd < 0 && lock_fd != -EBUSY)
- return lock_fd;
+ r = _nss_systemd_block(true);
+ if (r < 0)
+ return r;
+
+ blocked = true;
r = nss_group_record_by_gid(gid, false, &g);
if (r == -ESRCH)
return NSS_STATUS_NOTFOUND;
-
if (r < 0) {
*errnop = -r;
return NSS_STATUS_UNAVAIL;
sd_bus_error *error) {
_cleanup_(lookup_paths_free) LookupPaths paths = {};
- _cleanup_set_free_free_ Set *unit_files = NULL, *markers = NULL;
+ _cleanup_set_free_ Set *unit_files = NULL, *markers = NULL;
_cleanup_closedir_ DIR *d = NULL;
const char *where, *item;
Iterator iterator;
return log_debug_errno(errno, "Failed to open '%s' directory: %m", where);
}
- markers = set_new(&path_hash_ops);
- if (!markers)
- return -ENOMEM;
-
FOREACH_DIRENT(de, d, return log_debug_errno(errno, "Failed to enumerate '%s' directory: %m", where)) {
_cleanup_free_ char *marker = NULL;
UnitFileState state;
if (path_is_absolute(marker) &&
!image_in_search_path(IMAGE_PORTABLE, marker)) {
- r = set_ensure_allocated(&markers, &path_hash_ops);
+ r = set_ensure_consume(&markers, &path_hash_ops_free, TAKE_PTR(marker));
if (r < 0)
return r;
-
- r = set_put(markers, marker);
- if (r >= 0)
- marker = NULL;
- else if (r != -EEXIST)
- return r;
}
}
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
if (streq(program_invocation_short_name, "resolvconf"))
r = resolvconf_parse_argv(argc, argv);
}
static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) {
- DnsTransaction *t;
+ _cleanup_(dns_transaction_gcp) DnsTransaction *t = NULL;
int r;
assert(c);
r = dns_transaction_new(&t, c->scope, key);
if (r < 0)
return r;
- } else {
- if (set_contains(c->transactions, t))
- return 0;
- }
-
- r = set_ensure_allocated(&c->transactions, NULL);
- if (r < 0)
- goto gc;
-
- r = set_ensure_allocated(&t->notify_query_candidates, NULL);
- if (r < 0)
- goto gc;
+ } else if (set_contains(c->transactions, t))
+ return 0;
r = set_ensure_allocated(&t->notify_query_candidates_done, NULL);
if (r < 0)
- goto gc;
+ return r;
- r = set_put(t->notify_query_candidates, c);
+ r = set_ensure_put(&t->notify_query_candidates, NULL, c);
if (r < 0)
- goto gc;
+ return r;
- r = set_put(c->transactions, t);
+ r = set_ensure_put(&c->transactions, NULL, t);
if (r < 0) {
(void) set_remove(t->notify_query_candidates, c);
- goto gc;
+ return r;
}
t->clamp_ttl = c->query->clamp_ttl;
+ TAKE_PTR(t);
return 1;
-
-gc:
- dns_transaction_gc(t);
- return r;
}
static int dns_query_candidate_go(DnsQueryCandidate *c) {
}
static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
- DnsQueryCandidate *c;
+ _cleanup_(dns_query_candidate_freep) DnsQueryCandidate *c = NULL;
int r;
assert(q);
return r;
/* If this a single-label domain on DNS, we might append a suitable search domain first. */
- if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0 &&
- dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna))) {
- /* OK, we need a search domain now. Let's find one for this scope */
+ if (!FLAGS_SET(q->flags, SD_RESOLVED_NO_SEARCH) &&
+ dns_scope_name_wants_search_domain(s, dns_question_first_name(q->question_idna))) {
+ /* OK, we want a search domain now. Let's find one for this scope */
r = dns_query_candidate_next_search_domain(c);
- if (r <= 0) /* if there's no search domain, then we won't add any transaction. */
- goto fail;
+ if (r < 0)
+ return r;
}
r = dns_query_candidate_setup_transactions(c);
if (r < 0)
- goto fail;
+ return r;
+ TAKE_PTR(c);
return 0;
-
-fail:
- dns_query_candidate_free(c);
- return r;
}
static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
};
DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c);
+DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryCandidate*, dns_query_candidate_free);
+
void dns_query_candidate_notify(DnsQueryCandidate *c);
int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question_utf8, DnsQuestion *question_idna, int family, uint64_t flags);
manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */
return DNS_SCOPE_YES_BASE + 1; /* Return +1, as we consider ourselves authoritative
* for single-label names, i.e. one label. This is
- * particular relevant as it means a "." route on some
+ * particularly relevant as it means a "." route on some
* other scope won't pull all traffic away from
* us. (If people actually want to pull traffic away
* from us they should turn off LLMNR on the
if (s->protocol == DNS_PROTOCOL_DNS) {
- /* On classic DNS, looking up non-address RRs is always
- * fine. (Specifically, we want to permit looking up
- * DNSKEY and DS records on the root and top-level
- * domains.) */
+ /* On classic DNS, looking up non-address RRs is always fine. (Specifically, we want to
+ * permit looking up DNSKEY and DS records on the root and top-level domains.) */
if (!dns_resource_key_is_address(key))
return true;
- /* However, we refuse to look up A and AAAA RRs on the
- * root and single-label domains, under the assumption
- * that those should be resolved via LLMNR or search
- * path only, and should not be leaked onto the
- * internet. */
- return !(dns_name_is_single_label(dns_resource_key_name(key)) ||
- dns_name_is_root(dns_resource_key_name(key)));
+ /* Unless explicitly overridden, we refuse to look up A and AAAA RRs on the root and
+ * single-label domains, under the assumption that those should be resolved via LLMNR or
+ * search path only, and should not be leaked onto the internet. */
+ const char* name = dns_resource_key_name(key);
+
+ if (!s->manager->resolve_unicast_single_label &&
+ dns_name_is_single_label(name))
+ return false;
+
+ return !dns_name_is_root(name);
}
/* On mDNS and LLMNR, send A and AAAA queries only on the
return s->manager->search_domains;
}
-bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name) {
+bool dns_scope_name_wants_search_domain(DnsScope *s, const char *name) {
assert(s);
if (s->protocol != DNS_PROTOCOL_DNS)
if (!scope->announced &&
dns_resource_key_is_dnssd_ptr(z->rr->key)) {
if (!set_contains(types, dns_resource_key_name(z->rr->key))) {
- r = set_ensure_allocated(&types, &dns_name_hash_ops);
- if (r < 0)
- return log_debug_errno(r, "Failed to allocate set: %m");
-
- r = set_put(types, dns_resource_key_name(z->rr->key));
+ r = set_ensure_put(&types, &dns_name_hash_ops, dns_resource_key_name(z->rr->key));
if (r < 0)
return log_debug_errno(r, "Failed to add item to set: %m");
}
DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s);
-bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name);
+bool dns_scope_name_wants_search_domain(DnsScope *s, const char *name);
bool dns_scope_network_good(DnsScope *s);
}
static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) {
- DnsQuery *q = NULL;
+ _cleanup_(dns_query_freep) DnsQuery *q = NULL;
int r;
assert(m);
in_addr_is_localhost(p->family, &p->destination) <= 0) {
log_error("Got packet on unexpected IP range, refusing.");
dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
- goto fail;
+ return;
}
r = dns_packet_extract(p);
if (r < 0) {
log_debug_errno(r, "Failed to extract resources from incoming packet, ignoring packet: %m");
dns_stub_send_failure(m, s, p, DNS_RCODE_FORMERR, false);
- goto fail;
+ return;
}
if (!DNS_PACKET_VERSION_SUPPORTED(p)) {
log_debug("Got EDNS OPT field with unsupported version number.");
dns_stub_send_failure(m, s, p, DNS_RCODE_BADVERS, false);
- goto fail;
+ return;
}
if (dns_type_is_obsolete(p->question->keys[0]->type)) {
log_debug("Got message with obsolete key type, refusing.");
dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP, false);
- goto fail;
+ return;
}
if (dns_type_is_zone_transer(p->question->keys[0]->type)) {
log_debug("Got request for zone transfer, refusing.");
dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP, false);
- goto fail;
+ return;
}
if (!DNS_PACKET_RD(p)) {
/* If the "rd" bit is off (i.e. recursion was not requested), then refuse operation */
log_debug("Got request with recursion disabled, refusing.");
dns_stub_send_failure(m, s, p, DNS_RCODE_REFUSED, false);
- goto fail;
+ return;
}
if (DNS_PACKET_DO(p) && DNS_PACKET_CD(p)) {
log_debug("Got request with DNSSEC CD bit set, refusing.");
dns_stub_send_failure(m, s, p, DNS_RCODE_NOTIMP, false);
- goto fail;
+ return;
}
r = dns_query_new(m, &q, p->question, p->question, 0, SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_SEARCH);
if (r < 0) {
log_error_errno(r, "Failed to generate query object: %m");
dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
- goto fail;
+ return;
}
/* Request that the TTL is corrected by the cached time for this lookup, so that we return vaguely useful TTLs */
/* Remember which queries belong to this stream, so that we can cancel them when the stream
* is disconnected early */
- r = set_ensure_allocated(&s->queries, &trivial_hash_ops);
+ r = set_ensure_put(&s->queries, NULL, q);
if (r < 0) {
log_oom();
- goto fail;
- }
-
- if (set_put(s->queries, q) < 0) {
- log_oom();
- goto fail;
+ return;
}
+ assert(r > 0);
}
r = dns_query_go(q);
if (r < 0) {
log_error_errno(r, "Failed to start query: %m");
dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
- goto fail;
+ return;
}
log_debug("Processing query...");
- return;
-
-fail:
- dns_query_free(q);
+ TAKE_PTR(q);
}
static int on_dns_stub_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
add_known_answers = true;
if (t->key->type == DNS_TYPE_ANY) {
- r = set_ensure_allocated(&keys, &dns_resource_key_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(keys, t->key);
+ r = set_ensure_put(&keys, &dns_resource_key_hash_ops, t->key);
if (r < 0)
return r;
}
add_known_answers = true;
if (other->key->type == DNS_TYPE_ANY) {
- r = set_ensure_allocated(&keys, &dns_resource_key_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(keys, other->key);
+ r = set_ensure_put(&keys, &dns_resource_key_hash_ops, other->key);
if (r < 0)
return r;
}
}
static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResourceKey *key, DnsTransaction **ret) {
- DnsTransaction *aux;
+ _cleanup_(dns_transaction_gcp) DnsTransaction *aux = NULL;
int r;
assert(t);
}
}
- r = set_ensure_allocated(&t->dnssec_transactions, NULL);
- if (r < 0)
- goto gc;
-
- r = set_ensure_allocated(&aux->notify_transactions, NULL);
- if (r < 0)
- goto gc;
-
r = set_ensure_allocated(&aux->notify_transactions_done, NULL);
if (r < 0)
- goto gc;
+ return r;
- r = set_put(t->dnssec_transactions, aux);
+ r = set_ensure_put(&t->dnssec_transactions, NULL, aux);
if (r < 0)
- goto gc;
+ return r;;
- r = set_put(aux->notify_transactions, t);
+ r = set_ensure_put(&aux->notify_transactions, NULL, t);
if (r < 0) {
(void) set_remove(t->dnssec_transactions, aux);
- goto gc;
+ return r;
}
- *ret = aux;
+ *ret = TAKE_PTR(aux);
return 1;
-
-gc:
- dns_transaction_gc(aux);
- return r;
}
static int dns_transaction_request_dnssec_rr(DnsTransaction *t, DnsResourceKey *key) {
DnsTransaction* dns_transaction_free(DnsTransaction *t);
bool dns_transaction_gc(DnsTransaction *t);
+DEFINE_TRIVIAL_CLEANUP_FUNC(DnsTransaction*, dns_transaction_gc);
+
int dns_transaction_go(DnsTransaction *t);
void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p);
return -EINVAL;
}
- r = set_ensure_allocated(&d->negative_by_name, &dns_name_hash_ops);
- if (r < 0)
- return log_oom();
-
- r = set_put(d->negative_by_name, domain);
+ r = set_ensure_consume(&d->negative_by_name, &dns_name_hash_ops, TAKE_PTR(domain));
if (r < 0)
return log_oom();
- if (r > 0)
- domain = NULL;
return 0;
}
assert(d);
- r = set_ensure_allocated(&d->revoked_by_rr, &dns_resource_record_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put(d->revoked_by_rr, rr);
+ r = set_ensure_put(&d->revoked_by_rr, &dns_resource_record_hash_ops, rr);
if (r < 0)
return r;
if (r > 0)
}
static int dns_zone_item_probe_start(DnsZoneItem *i) {
- DnsTransaction *t;
+ _cleanup_(dns_transaction_gcp) DnsTransaction *t = NULL;
int r;
assert(i);
return r;
}
- r = set_ensure_allocated(&t->notify_zone_items, NULL);
- if (r < 0)
- goto gc;
-
r = set_ensure_allocated(&t->notify_zone_items_done, NULL);
if (r < 0)
- goto gc;
+ return r;
- r = set_put(t->notify_zone_items, i);
+ r = set_ensure_put(&t->notify_zone_items, NULL, i);
if (r < 0)
- goto gc;
+ return r;
- i->probe_transaction = t;
t->probing = true;
+ i->probe_transaction = TAKE_PTR(t);
- if (t->state == DNS_TRANSACTION_NULL) {
-
+ if (i->probe_transaction->state == DNS_TRANSACTION_NULL) {
i->block_ready++;
- r = dns_transaction_go(t);
+ r = dns_transaction_go(i->probe_transaction);
i->block_ready--;
if (r < 0) {
dns_zone_item_notify(i);
return 0;
-
-gc:
- dns_transaction_gc(t);
- return r;
}
int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe) {
/* Optimize the case where we don't need to store any addresses, by storing
* only the name in a dedicated Set instead of the hashmap */
- r = set_ensure_allocated(&hosts->no_address, &dns_name_hash_ops);
- if (r < 0)
- return log_oom();
-
- r = set_put(hosts->no_address, name);
+ r = set_ensure_consume(&hosts->no_address, &dns_name_hash_ops, TAKE_PTR(name));
if (r < 0)
return r;
- TAKE_PTR(name);
continue;
}
%struct-type
%includes
%%
-Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0
-Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0
-Resolve.Domains, config_parse_search_domains, 0, 0
-Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support)
-Resolve.MulticastDNS, config_parse_resolve_support, 0, offsetof(Manager, mdns_support)
-Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode)
-Resolve.DNSOverTLS, config_parse_dns_over_tls_mode, 0, offsetof(Manager, dns_over_tls_mode)
-Resolve.Cache, config_parse_dns_cache_mode, DNS_CACHE_MODE_YES, offsetof(Manager, enable_cache)
-Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, offsetof(Manager, dns_stub_listener_mode)
-Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts)
+Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0
+Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0
+Resolve.Domains, config_parse_search_domains, 0, 0
+Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support)
+Resolve.MulticastDNS, config_parse_resolve_support, 0, offsetof(Manager, mdns_support)
+Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode)
+Resolve.DNSOverTLS, config_parse_dns_over_tls_mode, 0, offsetof(Manager, dns_over_tls_mode)
+Resolve.Cache, config_parse_dns_cache_mode, DNS_CACHE_MODE_YES, offsetof(Manager, enable_cache)
+Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, offsetof(Manager, dns_stub_listener_mode)
+Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts)
+Resolve.ResolveUnicastSingleLabel, config_parse_bool, 0, offsetof(Manager, resolve_unicast_single_label)
LIST_HEAD(DnsSearchDomain, search_domains);
unsigned n_search_domains;
- bool need_builtin_fallbacks:1;
+ bool need_builtin_fallbacks;
+ bool read_resolv_conf;
+ bool resolve_unicast_single_label;
- bool read_resolv_conf:1;
struct stat resolv_conf_stat;
DnsTrustAnchor trust_anchor;
r = mac_selinux_init();
if (r < 0)
- return log_error_errno(r, "SELinux setup failed: %m");
+ return r;
/* Drop privileges, but only if we have been started as root. If we are not running as root we assume most
* privileges are already dropped and we can't create our directory. */
#Cache=yes
#DNSStubListener=yes
#ReadEtcHosts=yes
+#ResolveUnicastSingleLabel=no
#include "escape.h"
#include "exec-util.h"
#include "exit-status.h"
+#include "fileio.h"
#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
#include "nsflags.h"
#include "numa-util.h"
#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "securebits-util.h"
if (r < 0)
return bus_log_create_error(r);
return 1;
- } else if (isempty(eq) && STR_IN_SET(field, "DefaultMemoryLow",
- "DefaultMemoryMin",
- "MemoryLow",
- "MemoryMin")) {
- /* We can't use CGROUP_LIMIT_MIN nor CGROUP_LIMIT_MAX to convey the empty assignment
- * so marshall specially as a boolean. */
- r = sd_bus_message_append(m, "(sv)", field, "b", 0);
- if (r < 0)
- return bus_log_create_error(r);
- return 1;
} else if (isempty(eq)) {
- r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
+ uint64_t empty_value = STR_IN_SET(field,
+ "DefaultMemoryLow",
+ "DefaultMemoryMin",
+ "MemoryLow",
+ "MemoryMin") ?
+ CGROUP_LIMIT_MIN :
+ CGROUP_LIMIT_MAX;
+
+ r = sd_bus_message_append(m, "(sv)", field, "t", empty_value);
if (r < 0)
return bus_log_create_error(r);
return 1;
"ProtectHome",
"SELinuxContext",
"RootImage",
+ "RootVerity",
"RuntimeDirectoryPreserve",
"Personality",
"KeyringMode",
return 1;
}
+ if (streq(field, "RootHash")) {
+ _cleanup_free_ void *roothash_decoded = NULL;
+ size_t roothash_decoded_size = 0;
+
+ /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
+ if (path_is_absolute(eq))
+ return bus_append_string(m, "RootHashPath", eq);
+
+ /* We have a roothash to decode, eg: RootHash=012345789abcdef */
+ r = unhexmem(eq, strlen(eq), &roothash_decoded, &roothash_decoded_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
+ if (roothash_decoded_size < sizeof(sd_id128_t))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short: %m", eq);
+
+ return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
+ }
+
return 0;
}
return r;
if (found_properties) {
- r = set_ensure_allocated(found_properties, &string_hash_ops);
+ r = set_ensure_put(found_properties, &string_hash_ops, name);
if (r < 0)
return log_oom();
-
- r = set_put(*found_properties, name);
- if (r < 0 && r != -EEXIST)
- return log_oom();
}
name_with_equal = strjoin(name, "=");
return 0;
}
-int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) {
+int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) {
_cleanup_free_ char *verity_filename = NULL;
_cleanup_free_ void *roothash_decoded = NULL;
size_t roothash_decoded_size = 0;
_cleanup_free_ char *text = NULL;
assert(ret_roothash_size);
- r = getxattr_malloc(image, "user.verity.roothash", &text, true);
- if (r < 0) {
- char *fn, *e, *n;
-
- if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
+ if (root_hash_path) {
+ /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
+ r = read_one_line_file(root_hash_path, &text);
+ if (r < 0)
return r;
+ } else {
+ r = getxattr_malloc(image, "user.verity.roothash", &text, true);
+ if (r < 0) {
+ char *fn, *e, *n;
+
+ if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
+ return r;
- fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
- n = stpcpy(fn, image);
- e = endswith(fn, ".raw");
- if (e)
- n = e;
+ fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
+ n = stpcpy(fn, image);
+ e = endswith(fn, ".raw");
+ if (e)
+ n = e;
- strcpy(n, ".roothash");
+ strcpy(n, ".roothash");
- r = read_one_line_file(fn, &text);
- if (r < 0 && r != -ENOENT)
- return r;
+ r = read_one_line_file(fn, &text);
+ if (r < 0 && r != -ENOENT)
+ return r;
+ }
}
if (text) {
const char* partition_designator_to_string(int i) _const_;
int partition_designator_from_string(const char *name) _pure_;
-int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data);
+int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data);
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
return 0;
}
-int parse_syscall_archs(char **l, Set **archs) {
- _cleanup_set_free_ Set *_archs = NULL;
+int parse_syscall_archs(char **l, Set **ret_archs) {
+ _cleanup_set_free_ Set *archs = NULL;
char **s;
int r;
assert(l);
- assert(archs);
-
- r = set_ensure_allocated(&_archs, NULL);
- if (r < 0)
- return r;
+ assert(ret_archs);
STRV_FOREACH(s, l) {
uint32_t a;
if (r < 0)
return -EINVAL;
- r = set_put(_archs, UINT32_TO_PTR(a + 1));
+ r = set_ensure_put(&archs, NULL, UINT32_TO_PTR(a + 1));
if (r < 0)
return -ENOMEM;
}
- *archs = TAKE_PTR(_archs);
-
+ *ret_archs = TAKE_PTR(archs);
return 0;
}
DEFINE_TRIVIAL_CLEANUP_FUNC(scmp_filter_ctx, seccomp_release);
-int parse_syscall_archs(char **l, Set **archs);
+int parse_syscall_archs(char **l, Set **ret_archs);
uint32_t scmp_act_kill_process(void);
#include <sys/auxv.h>
#include "dirent-util.h"
+#include "dlfcn-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "group-record-nss.h"
bool nss_iterating:1;
bool synthesize_root:1;
bool synthesize_nobody:1;
+ bool nss_systemd_blocked:1;
int error;
- int nss_lock;
unsigned n_found;
sd_event *event;
UserRecord *found_user; /* when .what == LOOKUP_USER */
}
sd_event_unref(iterator->event);
- safe_close(iterator->nss_lock);
+
+ if (iterator->nss_systemd_blocked)
+ assert_se(userdb_block_nss_systemd(false) >= 0);
return mfree(iterator);
}
*i = (UserDBIterator) {
.what = what,
- .nss_lock = -1,
};
return i;
}
+static int userdb_iterator_block_nss_systemd(UserDBIterator *iterator) {
+ int r;
+
+ assert(iterator);
+
+ if (iterator->nss_systemd_blocked)
+ return 0;
+
+ r = userdb_block_nss_systemd(true);
+ if (r < 0)
+ return r;
+
+ iterator->nss_systemd_blocked = true;
+ return 1;
+}
+
struct user_group_data {
JsonVariant *record;
bool incomplete;
if (r < 0)
return log_debug_errno(r, "Failed to invoke varlink method: %m");
- r = set_ensure_allocated(&iterator->links, &link_hash_ops);
- if (r < 0)
- return log_debug_errno(r, "Failed to allocate set: %m");
-
- r = set_put(iterator->links, vl);
+ r = set_ensure_consume(&iterator->links, &link_hash_ops, TAKE_PTR(vl));
if (r < 0)
return log_debug_errno(r, "Failed to add varlink connection to set: %m");
-
- TAKE_PTR(vl);
return r;
}
return r;
}
- if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
- /* Make sure the NSS lookup doesn't recurse back to us. (EBUSY is fine here, it just means we
- * already took the lock from our thread, which is totally OK.) */
- r = userdb_nss_compat_disable();
- if (r >= 0 || r == -EBUSY) {
- iterator->nss_lock = r;
+ if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) {
+ /* Make sure the NSS lookup doesn't recurse back to us. */
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r >= 0) {
/* Client-side NSS fallback */
r = nss_user_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0)
return r;
}
- if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
- r = userdb_nss_compat_disable();
- if (r >= 0 || r == -EBUSY) {
- iterator->nss_lock = r;
-
+ if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) {
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r >= 0) {
/* Client-side NSS fallback */
r = nss_user_record_by_uid(uid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0)
r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetUserRecord", true, NULL, flags);
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) {
- iterator->nss_lock = userdb_nss_compat_disable();
- if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
- return iterator->nss_lock;
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r < 0)
+ return r;
setpwent();
iterator->nss_iterating = true;
}
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
- r = userdb_nss_compat_disable();
- if (r >= 0 || r == -EBUSY) {
- iterator->nss_lock = r;
-
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r >= 0) {
r = nss_group_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0)
return r;
}
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
- r = userdb_nss_compat_disable();
- if (r >= 0 || r == -EBUSY) {
- iterator->nss_lock = r;
-
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r >= 0) {
r = nss_group_record_by_gid(gid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0)
return r;
r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetGroupRecord", true, NULL, flags);
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) {
- iterator->nss_lock = userdb_nss_compat_disable();
- if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
- return iterator->nss_lock;
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r < 0)
+ return r;
setgrent();
iterator->nss_iterating = true;
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
goto finish;
- iterator->nss_lock = userdb_nss_compat_disable();
- if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
- return iterator->nss_lock;
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r < 0)
+ return r;
iterator->filter_user_name = strdup(name);
if (!iterator->filter_user_name)
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
goto finish;
- iterator->nss_lock = userdb_nss_compat_disable();
- if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
- return iterator->nss_lock;
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r < 0)
+ return r;
/* We ignore all errors here, since the group might be defined by a userdb native service, and we queried them already above. */
(void) nss_group_record_by_name(name, false, &gr);
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
goto finish;
- iterator->nss_lock = userdb_nss_compat_disable();
- if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
- return iterator->nss_lock;
+ r = userdb_iterator_block_nss_systemd(iterator);
+ if (r < 0)
+ return r;
setgrent();
iterator->nss_iterating = true;
return 0;
}
-static int userdb_thread_sockaddr(struct sockaddr_un *ret_sa, socklen_t *ret_salen) {
- static const uint8_t
- k1[16] = { 0x35, 0xc1, 0x1f, 0x41, 0x59, 0xc6, 0xa0, 0xf9, 0x33, 0x4b, 0x17, 0x3d, 0xb9, 0xf6, 0x14, 0xd9 },
- k2[16] = { 0x6a, 0x11, 0x4c, 0x37, 0xe5, 0xa3, 0x8c, 0xa6, 0x93, 0x55, 0x64, 0x8c, 0x93, 0xee, 0xa1, 0x7b };
-
- struct siphash sh;
- uint64_t x, y;
- pid_t tid;
- void *p;
-
- assert(ret_sa);
- assert(ret_salen);
-
- /* This calculates an AF_UNIX socket address in the abstract namespace whose existence works as an
- * indicator whether to emulate NSS records for complex user records that are also available via the
- * varlink protocol. The name of the socket is picked in a way so that:
- *
- * → it is per-thread (by hashing from the TID)
- *
- * → is not guessable for foreign processes (by hashing from the — hopefully secret — AT_RANDOM
- * value every process gets passed from the kernel
- *
- * By using a socket the NSS emulation can be nicely turned off for limited amounts of time only,
- * simply controlled by the lifetime of the fd itself. By using an AF_UNIX socket in the abstract
- * namespace the lock is automatically cleaned up when the process dies abnormally.
- *
- */
-
- p = ULONG_TO_PTR(getauxval(AT_RANDOM));
- if (!p)
- return -EIO;
-
- tid = gettid();
-
- siphash24_init(&sh, k1);
- siphash24_compress(p, 16, &sh);
- siphash24_compress(&tid, sizeof(tid), &sh);
- x = siphash24_finalize(&sh);
-
- siphash24_init(&sh, k2);
- siphash24_compress(p, 16, &sh);
- siphash24_compress(&tid, sizeof(tid), &sh);
- y = siphash24_finalize(&sh);
-
- *ret_sa = (struct sockaddr_un) {
- .sun_family = AF_UNIX,
- };
-
- sprintf(ret_sa->sun_path + 1, "userdb-%016" PRIx64 "%016" PRIx64, x, y);
- *ret_salen = offsetof(struct sockaddr_un, sun_path) + 1 + 7 + 32;
-
- return 0;
-}
-
-int userdb_nss_compat_is_enabled(void) {
- _cleanup_close_ int fd = -1;
- union sockaddr_union sa;
- socklen_t salen;
- int r;
-
- /* Tests whether the NSS compatibility logic is currently turned on for the invoking thread. Returns
- * true if NSS compatibility is turned on, i.e. whether NSS records shall be synthesized from complex
- * user records. */
-
- r = userdb_thread_sockaddr(&sa.un, &salen);
- if (r < 0)
- return r;
-
- fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
- if (fd < 0)
- return -errno;
+int userdb_block_nss_systemd(int b) {
+ _cleanup_(dlclosep) void *dl = NULL;
+ int (*call)(bool b);
- /* Try to connect(). This doesn't do anything really, except that it checks whether the socket
- * address is bound at all. */
- if (connect(fd, &sa.sa, salen) < 0) {
- if (errno == ECONNREFUSED) /* the socket is not bound, hence NSS emulation shall be done */
- return true;
+ /* Note that we might be called from libnss_systemd.so.2 itself, but that should be fine, really. */
- return -errno;
+ dl = dlopen(ROOTLIBDIR "libnss_systemd.so.2", RTLD_LAZY|RTLD_NODELETE);
+ if (!dl) {
+ /* If the file isn't installed, don't complain loudly */
+ log_debug("Failed to dlopen(libnss_systemd.so.2), ignoring: %s", dlerror());
+ return 0;
}
- return false;
-}
-
-int userdb_nss_compat_disable(void) {
- _cleanup_close_ int fd = -1;
- union sockaddr_union sa;
- socklen_t salen;
- int r;
-
- /* Turn off the NSS compatibility logic for the invoking thread. By default NSS records are
- * synthesized for all complex user records looked up via NSS. If this call is invoked this is
- * disabled for the invoking thread, but only for it. A caller that natively supports the varlink
- * user record protocol may use that to turn off the compatibility for NSS lookups. */
-
- r = userdb_thread_sockaddr(&sa.un, &salen);
- if (r < 0)
- return r;
-
- fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0)
- return -errno;
-
- if (bind(fd, &sa.sa, salen) < 0) {
- if (errno == EADDRINUSE) /* lock already taken, convert this into a recognizable error */
- return -EBUSY;
-
- return -errno;
- }
+ call = (int (*)(bool b)) dlsym(dl, "_nss_systemd_block");
+ if (!call)
+ /* If the file is is installed but lacks the symbol we expect, things are weird, let's complain */
+ return log_debug_errno(SYNTHETIC_ERRNO(ELIBBAD),
+ "Unable to find symbol _nss_systemd_block in libnss_systemd.so.2: %s", dlerror());
- return TAKE_FD(fd);
+ return call(b);
}
int membershipdb_iterator_get(UserDBIterator *iterator, char **user, char **group);
int membershipdb_by_group_strv(const char *name, UserDBFlags flags, char ***ret);
-int userdb_nss_compat_is_enabled(void);
-int userdb_nss_compat_disable(void);
+int userdb_block_nss_systemd(int b);
log_warning_errno(r, "Unable to disable idle timer, continuing: %m");
}
- r = set_ensure_allocated(&context->connections, NULL);
- if (r < 0) {
- log_oom();
- return 0;
- }
-
- c = new0(Connection, 1);
+ c = new(Connection, 1);
if (!c) {
log_oom();
return 0;
}
- c->context = context;
- c->server_fd = fd;
- c->client_fd = -1;
- c->server_to_client_buffer[0] = c->server_to_client_buffer[1] = -1;
- c->client_to_server_buffer[0] = c->client_to_server_buffer[1] = -1;
+ *c = (Connection) {
+ .context = context,
+ .server_fd = fd,
+ .client_fd = -1,
+ .server_to_client_buffer = {-1, -1},
+ .client_to_server_buffer = {-1, -1},
+ };
- r = set_put(context->connections, c);
+ r = set_ensure_put(&context->connections, NULL, c);
if (r < 0) {
free(c);
log_oom();
assert(context);
assert(fd >= 0);
- r = set_ensure_allocated(&context->listen, NULL);
- if (r < 0) {
- log_oom();
- return r;
- }
-
r = sd_is_socket(fd, 0, SOCK_STREAM, 1);
if (r < 0)
return log_error_errno(r, "Failed to determine socket type: %m");
if (r < 0)
return log_error_errno(r, "Failed to add event source: %m");
- r = set_put(context->listen, source);
+ r = set_ensure_put(&context->listen, NULL, source);
if (r < 0) {
log_error_errno(r, "Failed to add source to set: %m");
sd_event_source_unref(source);
int r;
setlocale(LC_ALL, "");
- log_parse_environment();
+ log_parse_environment_cli();
log_open();
/* The journal merging logic potentially needs a lot of fds. */
* IP addresses */
int sd_network_link_get_dns(int ifindex, char ***ret);
-/* Get DHCP4 address for a given link. This is string representations of
- * IPv4 address */
-int sd_network_link_get_dhcp4_address(int ifindex, char **ret);
-
/* Get NTP entries for a given link. These are domain names or string
* representations of IP addresses */
int sd_network_link_get_ntp(int ifindex, char ***ret);
/* Get the CARRIERS that are bound to current link. */
int sd_network_link_get_carrier_bound_by(int ifindex, int **ifindexes);
-/* Get the timezone that was learnt on a specific link. */
-int sd_network_link_get_timezone(int ifindex, char **timezone);
-
-/* Get DHCPv4 client id for a given link. */
-int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id);
-
/* Get DHCPv6 client IAID for a given link. */
int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **iaid);
r = mac_selinux_init();
if (r < 0)
- return log_error_errno(r, "SELinux setup failed: %m");
+ return r;
/* If command line arguments are specified along with --replace, read all
* configuration files and insert the positional arguments at the specified
Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {};
_cleanup_strv_free_ char **sysvrcnd_path = NULL;
SysvStub *service;
- unsigned i;
Iterator j;
char **p;
int r;
if (r < 0)
return r;
- STRV_FOREACH(p, sysvrcnd_path) {
- for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
-
+ STRV_FOREACH(p, sysvrcnd_path)
+ for (unsigned i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
_cleanup_closedir_ DIR *d = NULL;
_cleanup_free_ char *path = NULL;
struct dirent *de;
service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority);
- r = set_ensure_allocated(&runlevel_services[i], NULL);
- if (r < 0) {
- log_oom();
- goto finish;
- }
-
- r = set_put(runlevel_services[i], service);
+ r = set_ensure_put(&runlevel_services[i], NULL, service);
if (r < 0) {
log_oom();
goto finish;
}
}
}
- }
- for (i = 0; i < ELEMENTSOF(rcnd_table); i ++)
+ for (unsigned i = 0; i < ELEMENTSOF(rcnd_table); i++)
SET_FOREACH(service, runlevel_services[i], j) {
r = strv_extend(&service->before, rcnd_table[i].target);
if (r < 0) {
r = 0;
finish:
- for (i = 0; i < ELEMENTSOF(rcnd_table); i++)
+ for (unsigned i = 0; i < ELEMENTSOF(rcnd_table); i++)
set_free(runlevel_services[i]);
return r;
static int run(int argc, char **argv) {
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
PROTECT_HOME_NO,
PROTECT_SYSTEM_NO,
0,
+ NULL,
+ 0,
+ NULL,
+ NULL,
0,
NULL);
assert_se(r == 0);
PROTECT_HOME_NO,
PROTECT_SYSTEM_NO,
0,
+ NULL,
+ 0,
+ NULL,
+ NULL,
0,
NULL);
if (r < 0) {
assert_se(set_size(m) == 3);
}
+static void test_set_ensure_allocated(void) {
+ _cleanup_set_free_ Set *m = NULL;
+
+ assert_se(set_ensure_allocated(&m, &string_hash_ops) == 1);
+ assert_se(set_ensure_allocated(&m, &string_hash_ops) == 0);
+ assert_se(set_ensure_allocated(&m, NULL) == 0);
+ assert_se(set_size(m) == 0);
+}
+
+static void test_set_ensure_put(void) {
+ _cleanup_set_free_ Set *m = NULL;
+
+ assert_se(set_ensure_put(&m, &string_hash_ops, "a") == 1);
+ assert_se(set_ensure_put(&m, &string_hash_ops, "a") == 0);
+ assert_se(set_ensure_put(&m, NULL, "a") == 0);
+ assert_se(set_ensure_put(&m, &string_hash_ops, "b") == 1);
+ assert_se(set_ensure_put(&m, &string_hash_ops, "b") == 0);
+ assert_se(set_ensure_put(&m, &string_hash_ops, "a") == 0);
+ assert_se(set_size(m) == 2);
+}
+
+static void test_set_ensure_consume(void) {
+ _cleanup_set_free_ Set *m = NULL;
+ char *s, *t;
+
+ assert_se(s = strdup("a"));
+ assert_se(set_ensure_consume(&m, &string_hash_ops_free, s) == 1);
+
+ assert_se(t = strdup("a"));
+ assert_se(set_ensure_consume(&m, &string_hash_ops_free, t) == 0);
+
+ assert_se(t = strdup("a"));
+ assert_se(set_ensure_consume(&m, &string_hash_ops_free, t) == 0);
+
+ assert_se(t = strdup("b"));
+ assert_se(set_ensure_consume(&m, &string_hash_ops_free, t) == 1);
+
+ assert_se(t = strdup("b"));
+ assert_se(set_ensure_consume(&m, &string_hash_ops_free, t) == 0);
+
+ assert_se(set_size(m) == 2);
+}
+
int main(int argc, const char *argv[]) {
test_set_steal_first();
test_set_free_with_destructor();
test_set_put();
test_set_put_strdup();
test_set_put_strdupv();
+ test_set_ensure_allocated();
+ test_set_ensure_put();
+ test_set_ensure_consume();
return 0;
}
int r;
setlocale(LC_ALL, "");
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
}
}
- mac_selinux_init();
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
+
return write_string_file_atomic_label("/etc/adjtime", w);
}
if (!j)
j = ordered_hashmap_get(globs, prefix);
if (j) {
- r = set_ensure_allocated(&j->children, NULL);
- if (r < 0)
- return log_oom();
-
- r = set_put(j->children, a);
+ r = set_ensure_put(&j->children, NULL, a);
if (r < 0)
return log_oom();
umask(0022);
- mac_selinux_init();
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
items = ordered_hashmap_new(&item_array_hash_ops);
globs = ordered_hashmap_new(&item_array_hash_ops);
subsystem = devtype = NULL;
break;
}
- case 't': {
- _cleanup_free_ char *tag = NULL;
-
- r = set_ensure_allocated(&arg_tag_filter, &string_hash_ops);
+ case 't':
+ /* optarg is stored in argv[], so we don't need to copy it */
+ r = set_ensure_put(&arg_tag_filter, &string_hash_ops, optarg);
if (r < 0)
return r;
-
- tag = strdup(optarg);
- if (!tag)
- return -ENOMEM;
-
- r = set_put(arg_tag_filter, tag);
- if (r < 0)
- return r;
-
- tag = NULL;
break;
- }
+
case 'V':
return print_version();
case 'h':
finalize:
hashmap_free_free_free(arg_subsystem_filter);
- set_free_free(arg_tag_filter);
+ set_free(arg_tag_filter);
return r;
}
log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level());
- mac_selinux_init();
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
+
return udevadm_main(argc, argv);
}
r = mac_selinux_init();
if (r < 0)
- return log_error_errno(r, "Could not initialize labelling: %m");
+ return r;
r = mkdir_errno_wrapper("/run/udev", 0755);
if (r < 0 && r != -EEXIST)
}
r = mac_selinux_init();
- if (r < 0) {
- log_error_errno(r, "SELinux setup failed: %m");
+ if (r < 0)
return EXIT_FAILURE;
- }
r = apply_timestamp("/etc/.updated", &st.st_mtim);
q = apply_timestamp("/var/.updated", &st.st_mtim);
umask(0022);
- mac_selinux_init();
+ r = mac_selinux_init();
+ if (r < 0)
+ return r;
if (streq(argv[1], "start")) {
r = unlink_or_warn("/run/nologin");
int r;
- log_show_color(true);
- log_parse_environment();
- log_open();
+ log_setup_cli();
r = parse_argv(argc, argv);
if (r <= 0)
static int run(int argc, char *argv[]) {
usec_t start_time, listen_idle_usec, last_busy_usec = USEC_INFINITY;
_cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL;
- _cleanup_close_ int lock = -1;
unsigned n_iterations = 0;
int m, listen_fd, r;
return log_error_errno(r, "Failed to parse USERDB_FIXED_WORKER: %m");
listen_idle_usec = r ? USEC_INFINITY : LISTEN_IDLE_USEC;
- lock = userdb_nss_compat_disable();
- if (lock < 0)
+ r = userdb_block_nss_systemd(true);
+ if (r < 0)
return log_error_errno(r, "Failed to disable userdb NSS compatibility: %m");
start_time = now(CLOCK_MONOTONIC);
/* Nothing to do if type is not Application. */
if (!streq_ptr(service->type, "Application")) {
- log_info("Not generating service for XDG autostart %s, it is hidden.", service->name);
+ log_info("Not generating service for XDG autostart %s, only Type=Application is supported.", service->name);
return 0;
}
return 0;
}
- if (streq_ptr(service->gnome_autostart_phase, "EarlyInitialization")) {
- log_info("Not generating service for XDG autostart %s, EarlyInitialization needs to be handled separately.",
+ if (service->gnome_autostart_phase) {
+ /* There is no explicit value for the "Application" phase. */
+ log_info("Not generating service for XDG autostart %s, startup phases are not supported.",
service->name);
return 0;
}
fprintf(f, "Description=%s\n", t);
}
- /* Only start after the session is ready.
- * XXX: GNOME has an autostart order which we may want to support.
- * It is not clear how this can be implemented reliably, which
- * is why it is skipped for now. */
+ /* Only start after the session is ready. */
fprintf(f,
"After=graphical-session.target\n");
echo "*** Running test $f"
prepare_testdir ${f%.input}
cp $f $TESTDIR/usr/lib/sysusers.d/test.conf
- systemd-sysusers --root=$TESTDIR 2> /dev/null
- journalctl --sync
- journalctl -t systemd-sysusers -o cat | tail -n1 > $TESTDIR/tmp/err
+ systemd-sysusers --root=$TESTDIR 2>&1 | tail -n1 > $TESTDIR/tmp/err
if ! diff -u $TESTDIR/tmp/err ${f%.*}.expected-err; then
echo "**** Unexpected error output for $f"
cat $TESTDIR/tmp/err
--- /dev/null
+BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
+
+all setup run clean clean-again:
+ @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
+
+# finish option is used to run checks that can only be run outside of
+# the test execution. Example case, honor first shutdown, proof is obtained
+# from the console output as the image shuts down. This does not show up in
+# the journal so the output from the do_test is captured in a file in /tmp.
+# Without the use of finish the test will still pass because if it fails
+# the test will loop and will be terminated via a command timeout.
+# This just provides concrete confirmation.
+finish:
+ @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./fini.sh --$@
+
+.PHONY: all setup run clean clean-again
--- /dev/null
+#!/bin/bash
+TEST_DESCRIPTION="test honor first shutdown"
+
+if grep -q "Shutdown is already active. Skipping emergency action request" /tmp/honorfirstshutdown.log; then
+ echo "$TEST_DESCRIPTION [pass]"
+ exit 0
+else
+ echo "$TEST_DESCRIPTION [fail]"
+ exit 1
+fi
--- /dev/null
+#!/bin/bash
+set -e
+. $TEST_BASE_DIR/test-functions
+TEST_REQUIRE_INSTALL_TESTS=0
+TEST_DESCRIPTION="testing honor first shutdown"
+#INTERACTIVE_DEBUG=1
+TEST_NO_QEMU=1
+
+#Using timeout because if the test fails it can loop.
+# The reason is because the poweroff executed by end.service
+# could turn into a reboot if the test fails.
+NSPAWN_TIMEOUT=20
+
+#Remove this file if it exists. this is used along with
+# the make target "finish". Since concrete confirmaion is
+# only found from the console during the poweroff.
+rm -f /tmp/honorfirstshutdown.log >/dev/null
+
+do_test "$@" 52 > /tmp/honorfirstshutdown.log
--- /dev/null
+[NetDev]
+Name=w
+Kind=wireguard
+[WireGuardPeer]
+Endpoint=:0
+Endpoint=:8
\ No newline at end of file
--- /dev/null
+[Network]
+DNSSECNegativeTrustAnchors=i i
\ No newline at end of file
RootDirectory=
RootDirectoryStartOnly=
RootImage=
+RootHash=
+RootVerity=
RuntimeMaxSec=
SELinuxContextFromNet=
SecureBits=
install_dir : testdata_dir)
install_subdir('testsuite-30.units',
install_dir : testdata_dir)
+install_subdir('testsuite-52.units',
+ install_dir : testdata_dir)
testsuite08_dir = testdata_dir + '/testsuite-08.units'
install_data('testsuite-08.units/-.mount',
inst /etc/login.defs
inst /etc/group
inst /etc/shells
- inst /etc/nsswitch.conf
+ inst_any /etc/nsswitch.conf /usr/etc/nsswitch.conf
inst /etc/pam.conf || :
inst /etc/os-release
inst /etc/localtime
--- /dev/null
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/usr/lib/systemd/tests/testdata/%N.units/%N.sh
+Type=oneshot
--- /dev/null
+#!/bin/bash
+set -ex
+set -o pipefail
+
+if ! test -x /usr/lib/systemd/tests/testdata/units/test-honor-first-shutdown.sh ; then
+ echo "honor-first-shutdown script not found - FAIL" > /testok
+ exit 0
+fi
+
+systemd-analyze log-level debug
+systemd-analyze log-target console
+
+systemctl enable test-honor-first-shutdown.service
+systemctl start test-honor-first-shutdown.service
+
+echo OK > /testok
+
+exit 0
--- /dev/null
+[Unit]
+Description=Honor First Shutdown feature
+After=multi-user.target
+
+[Service]
+ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
+ExecStop=sh -c 'kill -SIGKILL $MAINPID'
+FailureAction=reboot
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+echo "Honor first shutdown test script"
+sleep infinity;
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1+
-# Generate autosuspend rules for devices that have been whitelisted (IE tested)
-# by the Chromium OS team. Please keep this script in sync with:
+# Generate autosuspend rules for devices that have been tested to work properly
+# with autosuspend by the Chromium OS team. Based on
# https://chromium.googlesource.com/chromiumos/platform2/+/master/power_manager/udev/gen_autosuspend_rules.py
-import sys
import chromiumos.gen_autosuspend_rules
-if __name__ == '__main__':
- if len(sys.argv) > 1:
- sys.stdout = open(sys.argv[1], 'w')
- chromiumos.gen_autosuspend_rules.main()
+print('# pci:v<00VENDOR>d<00DEVICE> (8 uppercase hexadecimal digits twice)')
+for entry in chromiumos.gen_autosuspend_rules.PCI_IDS:
+ vendor, device = entry.split(':')
+ vendor = int(vendor, 16)
+ device = int(device, 16)
+ print('pci:v{:08X}d{:08X}*'.format(vendor, device))
+
+print('# usb:v<VEND>p<PROD> (4 uppercase hexadecimal digits twice')
+for entry in chromiumos.gen_autosuspend_rules.USB_IDS:
+ vendor, product = entry.split(':')
+ vendor = int(vendor, 16)
+ product = int(product, 16)
+ print('usb:v{:04X}p{:04X}*'.format(vendor, product))
+
+print(' ID_AUTOSUSPEND=1')
# export CONT_NAME="my-fancy-container"
# travis-ci/managers/debian.sh SETUP RUN CLEANUP
-PHASES=(${@:-SETUP RUN RUN_ASAN CLEANUP})
+PHASES=(${@:-SETUP RUN RUN_ASAN_UBSAN CLEANUP})
DEBIAN_RELEASE="${DEBIAN_RELEASE:-testing}"
-CONT_NAME="${CONT_NAME:-debian-$DEBIAN_RELEASE-$RANDOM}"
+CONT_NAME="${CONT_NAME:-systemd-debian-$DEBIAN_RELEASE}"
DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
DOCKER_RUN="${DOCKER_RUN:-docker run}"
REPO_ROOT="${REPO_ROOT:-$PWD}"
-ADDITIONAL_DEPS=(python3-libevdev
- python3-pyparsing
- clang
- perl
- libpwquality-dev
- fdisk
- libfdisk-dev
- libp11-kit-dev
- libssl-dev
- libzstd-dev
- zstd)
+ADDITIONAL_DEPS=(
+ clang
+ fdisk
+ libfdisk-dev
+ libp11-kit-dev
+ libpwquality-dev
+ libssl-dev
+ libzstd-dev
+ perl
+ python3-libevdev
+ python3-pyparsing
+ zstd
+)
function info() {
echo -e "\033[33;1m$1\033[0m"
$DOCKER_EXEC apt-get -y build-dep systemd
$DOCKER_EXEC apt-get -y install "${ADDITIONAL_DEPS[@]}"
;;
- RUN|RUN_CLANG)
+ RUN|RUN_GCC|RUN_CLANG)
if [[ "$phase" = "RUN_CLANG" ]]; then
ENV_VARS="-e CC=clang -e CXX=clang++"
fi
$DOCKER_EXEC ninja -v -C build
docker exec -e "TRAVIS=$TRAVIS" -it $CONT_NAME ninja -C build test
;;
- RUN_ASAN|RUN_CLANG_ASAN)
- if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
+ RUN_ASAN_UBSAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN)
+ if [[ "$phase" = "RUN_CLANG_ASAN_UBSAN" ]]; then
ENV_VARS="-e CC=clang -e CXX=clang++"
# Build fuzzer regression tests only with clang (for now),
# see: https://github.com/systemd/systemd/pull/15886#issuecomment-632689604
# export CONT_NAME="my-fancy-container"
# travis-ci/managers/fedora.sh SETUP RUN CLEANUP
-PHASES=(${@:-SETUP RUN RUN_ASAN CLEANUP})
+PHASES=(${@:-SETUP RUN RUN_ASAN_UBSAN CLEANUP})
FEDORA_RELEASE="${FEDORA_RELEASE:-rawhide}"
-CONT_NAME="${CONT_NAME:-fedora-$FEDORA_RELEASE-$RANDOM}"
+CONT_NAME="${CONT_NAME:-systemd-fedora-$FEDORA_RELEASE}"
DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
DOCKER_RUN="${DOCKER_RUN:-docker run}"
REPO_ROOT="${REPO_ROOT:-$PWD}"
-ADDITIONAL_DEPS=(dnf-plugins-core
- jq iputils
- hostname libasan
- python3-pyparsing
- python3-evdev
- libubsan
- clang
- llvm
- perl
- libfdisk-devel
- libpwquality-devel
- openssl-devel
- p11-kit-devel)
+ADDITIONAL_DEPS=(
+ clang
+ dnf-plugins-core
+ hostname libasan
+ jq iputils
+ libfdisk-devel
+ libpwquality-devel
+ libubsan
+ llvm
+ openssl-devel
+ p11-kit-devel
+ perl
+ python3-evdev
+ python3-pyparsing
+)
info() {
echo -e "\033[33;1m$1\033[0m"
}
-error() {
- echo >&2 -e "\033[31;1m$1\033[0m"
-}
-
-success() {
- echo >&2 -e "\033[32;1m$1\033[0m"
-}
-
# Simple wrapper which retries given command up to five times
_retry() {
local EC=1
$DOCKER_EXEC ninja -v -C build
$DOCKER_EXEC ninja -C build test
;;
- RUN_ASAN|RUN_CLANG_ASAN)
- if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
+ RUN_ASAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN)
+ if [[ "$phase" = "RUN_CLANG_ASAN_UBSAN" ]]; then
ENV_VARS="-e CC=clang -e CXX=clang++"
MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764
fi
-t $CONT_NAME \
meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs
;;
- RUN_BUILD_CHECK_GCC|RUN_BUILD_CHECK_CLANG)
- ARGS=(
- "--optimization=0"
- "--optimization=2"
- "--optimization=3"
- "--optimization=s"
- "-Db_lto=true"
- "-Db_ndebug=true"
- )
-
- if [[ "$phase" = "RUN_BUILD_CHECK_CLANG" ]]; then
- ENV_VARS="-e CC=clang -e CXX=clang++"
- $DOCKER_EXEC clang --version
- else
- $DOCKER_EXEC gcc --version
- fi
-
- for args in "${ARGS[@]}"; do
- SECONDS=0
- info "Checking build with $args"
- # Redirect meson/ninja logs into separate files, otherwise we
- # would trip over Travis' log size limit
- if ! docker exec $ENV_VARS -it $CONT_NAME meson --werror $args build &> meson.log; then
- cat meson.log
- error "meson failed with $args"
- exit 1
- fi
-
- if ! $DOCKER_EXEC ninja -v -C build &> ninja.log; then
- cat ninja.log
- error "ninja failed with $args"
- exit 1
- fi
-
- $DOCKER_EXEC rm -fr build
- rm -f meson.log ninja.log
- success "Build with $args passed in $SECONDS seconds"
- done
-
- ;;
CLEANUP)
info "Cleanup phase"
docker stop $CONT_NAME