topdir=$(dirname $0)
cd $topdir
-if [ -f .git/hooks/pre-commit.sample ] && [ ! -f .git/hooks/pre-commit ]; then
- # This part is allowed to fail
- cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \
- chmod +x .git/hooks/pre-commit && \
- echo "Activated pre-commit hook." || :
-fi
-
+# We do not need this, we are not systemd upstream!
+#if [ -f .git/hooks/pre-commit.sample ] && [ ! -f .git/hooks/pre-commit ]; then
+# # This part is allowed to fail
+# cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \
+# chmod +x .git/hooks/pre-commit && \
+# echo "Activated pre-commit hook." || :
+#fi
intltoolize --force --automake
autoreconf --force --install --symlink
-libdir() {
- echo $(cd "$1/$(gcc -print-multi-os-directory)"; pwd)
-}
-
-args="\
---sysconfdir=/etc \
---localstatedir=/var \
---libdir=$(libdir /usr/lib) \
-"
-
-if [ -f "$topdir/.config.args" ]; then
- args="$args $(cat $topdir/.config.args)"
-fi
-
-if [ ! -L /bin ]; then
-args="$args \
---with-rootprefix=/ \
---with-rootlibdir=$(libdir /lib) \
-"
-fi
-
cd $oldpwd
-
-if [ "x$1" = "xc" ]; then
- $topdir/configure CFLAGS='-g -O0 -ftrapv' --enable-compat-libs --enable-kdbus $args
- make clean
-elif [ "x$1" = "xt" ]; then
- $topdir/configure CFLAGS='-g -O0 -ftrapv' --enable-compat-libs --enable-kdbus --enable-terminal $args
- make clean
-elif [ "x$1" = "xg" ]; then
- $topdir/configure CFLAGS='-g -Og -ftrapv' --enable-compat-libs --enable-kdbus $args
- make clean
-elif [ "x$1" = "xa" ]; then
- $topdir/configure CFLAGS='-g -O0 -Wsuggest-attribute=pure -Wsuggest-attribute=const -ftrapv' --enable-compat-libs --enable-kdbus $args
- make clean
-elif [ "x$1" = "xl" ]; then
- $topdir/configure CC=clang CFLAGS='-g -O0 -ftrapv' --enable-compat-libs --enable-kdbus $args
- make clean
-elif [ "x$1" = "xs" ]; then
- scan-build $topdir/configure CFLAGS='-std=gnu99 -g -O0 -ftrapv' --enable-kdbus $args
- scan-build make
-else
- echo
- echo "----------------------------------------------------------------"
- echo "Initialized build system. For a common configuration please run:"
- echo "----------------------------------------------------------------"
- echo
- echo "$topdir/configure CFLAGS='-g -O0 -ftrapv' --enable-compat-libs --enable-kdbus $args"
- echo
-fi
--- /dev/null
+../src/Makefile
\ No newline at end of file
+++ /dev/null
-# This file is part of systemd.
-#
-# The lookup keys are composed in:
-# 60-evdev.rules
-#
-# Note: The format of the "evdev:" prefix match key is a
-# contract between the rules file and the hardware data, it might
-# change in later revisions to support more or better matches, it
-# is not necessarily expected to be a stable ABI.
-#
-# Match string formats:
-# evdev:<modalias>
-# evdev:name:<device name>:dmi:<dmi string>
-#
-# To add local entries, create a new file
-# /etc/udev/hwdb.d/61-evdev-local.hwdb
-# and add your rules there. To load the new rules execute (as root):
-# udevadm hwdb --update
-# udevadm trigger /dev/input/eventXX
-# where /dev/input/eventXX is the device in question. If in
-# doubt, simply use /dev/input/event* to reload all input rules.
-#
-# If your changes are generally applicable, open a bug report on
-# http://bugs.freedesktop.org/enter_bug.cgi?product=systemd
-# and include your new rules, a description of the device, and the
-# output of
-# udevadm info /dev/input/eventXX
-# (or /dev/input/event*).
-#
-# Allowed properties are:
-# EVDEV_ABS_<axis>=<min>:<max>:<res>:<fuzz>:<flat>
-#
-# where <axis> is the hexadecimal EV_ABS code as listed in linux/input.h
-# and min, max, res, fuzz, flat are the decimal values to the respective
-# fields of the struct input_absinfo as listed in linux/input.h.
-# If a field is missing the field will be left as-is. Not all fields need to
-# be present. e.g. ::45 sets the resolution to 45 units/mm.
-
-#
-# Sort by brand, model
-
-#########################################
-# Apple
-#########################################
-
-# Macbook2,1 (late 2006), single-button touchpad
-evdev:input:b0003v05ACp021B*
- EVDEV_ABS_00=256:1471:12
- EVDEV_ABS_01=256:831:12
-
-# Macbook5,1 (unibody), aka wellspring3
-evdev:input:b0003v05ACp0236*
-evdev:input:b0003v05ACp0237*
-evdev:input:b0003v05ACp0238*
- EVDEV_ABS_00=::92
- EVDEV_ABS_01=::90
- EVDEV_ABS_35=::92
- EVDEV_ABS_36=::90
-
-# Macbook8 (unibody, March 2011)
-evdev:input:b0003v05ACp0245*
-evdev:input:b0003v05ACp0246*
-evdev:input:b0003v05ACp0247*
- EVDEV_ABS_00=::92
- EVDEV_ABS_01=::91
- EVDEV_ABS_35=::92
- EVDEV_ABS_36=::91
-
-# Macbook8,2 (unibody)
-evdev:input:b0003v05ACp0252*
-evdev:input:b0003v05ACp0253*
-evdev:input:b0003v05ACp0254*
- EVDEV_ABS_00=::94
- EVDEV_ABS_01=::92
- EVDEV_ABS_35=::94
- EVDEV_ABS_36=::92
-
-# MacbookPro10,1 (unibody, June 2012)
-evdev:input:b0003v05ACp0259*
-evdev:input:b0003v05ACp025a*
-evdev:input:b0003v05ACp025b*
-# MacbookPro10,2 (unibody, October 2012)
-evdev:input:b0003v05ACp0259*
-evdev:input:b0003v05ACp025a*
-evdev:input:b0003v05ACp025b*
- EVDEV_ABS_00=::94
- EVDEV_ABS_01=::92
- EVDEV_ABS_35=::94
- EVDEV_ABS_36=::92
-
-#########################################
-# ASUS
-#########################################
-# Asus K52JT
-evdev:name:ETPS/2 Elantech Touchpad:dmi:bvn*:bvr*:bd*:svnASUSTeKComputerInc.:pnK52JT:*
- EVDEV_ABS_00=::18
- EVDEV_ABS_01=::16
- EVDEV_ABS_35=::18
- EVDEV_ABS_36=::16
-
-#########################################
-# Google
-#########################################
-
-# Chromebook Pixel (2015) - Samus
-evdev:name:Atmel maXTouch Touch*:dmi:bvn*:bvr*:bd*:svnGOOGLE:pnSamus*
- EVDEV_ABS_00=::10
- EVDEV_ABS_01=::10
- EVDEV_ABS_35=::10
- EVDEV_ABS_36=::10
-
-#########################################
-# Lenovo
-#########################################
-
-# Lenovo X230 series
-evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*X230*
- EVDEV_ABS_01=::100
- EVDEV_ABS_36=::100
<xsl:text>elogind.directives.html</xsl:text>
</xsl:attribute>
<xsl:text>Directives </xsl:text>
- </a>·
- <a>
- <xsl:attribute name="href">
- <xsl:text>../python-elogind/index.html</xsl:text>
- </xsl:attribute>
- <xsl:text>Python </xsl:text>
</a>
<span style="float:right">
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<refsect1>
+ <title>Environment</title>
+
+ <variablelist class='environment-variables'>
+ <varlistentry id='pager'>
+ <term><varname>$SYSTEMD_PAGER</varname></term>
+
+ <listitem><para>Pager to use when
+ <option>--no-pager</option> is not given;
+ overrides <varname>$PAGER</varname>. Setting
+ this to an empty string or the value
+ <literal>cat</literal> is equivalent to passing
+ <option>--no-pager</option>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry id='less'>
+ <term><varname>$SYSTEMD_LESS</varname></term>
+
+ <listitem><para>Override the default
+ options passed to
+ <command>less</command>
+ (<literal>FRSXMK</literal>).</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+++ /dev/null
-<?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
--->
-
-<refentry id="sd_pid_get_session" conditional='HAVE_PAM'>
-
- <refentryinfo>
- <title>sd_pid_get_session</title>
- <productname>systemd</productname>
-
- <authorgroup>
- <author>
- <contrib>Developer</contrib>
- <firstname>Lennart</firstname>
- <surname>Poettering</surname>
- <email>lennart@poettering.net</email>
- </author>
- </authorgroup>
- </refentryinfo>
-
- <refmeta>
- <refentrytitle>sd_pid_get_session</refentrytitle>
- <manvolnum>3</manvolnum>
- </refmeta>
-
- <refnamediv>
- <refname>sd_pid_get_session</refname>
- <refname>sd_pid_get_unit</refname>
- <refname>sd_pid_get_user_unit</refname>
- <refname>sd_pid_get_owner_uid</refname>
- <refname>sd_pid_get_machine_name</refname>
- <refname>sd_pid_get_slice</refname>
- <refname>sd_peer_get_session</refname>
- <refname>sd_peer_get_unit</refname>
- <refname>sd_peer_get_user_unit</refname>
- <refname>sd_peer_get_owner_uid</refname>
- <refname>sd_peer_get_machine_name</refname>
- <refname>sd_peer_get_slice</refname>
- <refpurpose>Determine session, service, owner of a
- session, container/VM or slice of a specific
- PID or socket peer</refpurpose>
- </refnamediv>
-
- <refsynopsisdiv>
- <funcsynopsis>
- <funcsynopsisinfo>#include <systemd/sd-login.h></funcsynopsisinfo>
-
- <funcprototype>
- <funcdef>int <function>sd_pid_get_session</function></funcdef>
- <paramdef>pid_t <parameter>pid</parameter></paramdef>
- <paramdef>char **<parameter>session</parameter></paramdef>
- </funcprototype>
-
- <funcprototype>
- <funcdef>int <function>sd_pid_get_unit</function></funcdef>
- <paramdef>pid_t <parameter>pid</parameter></paramdef>
- <paramdef>char **<parameter>unit</parameter></paramdef>
- </funcprototype>
-
- <funcprototype>
- <funcdef>int <function>sd_pid_get_user_unit</function></funcdef>
- <paramdef>pid_t <parameter>pid</parameter></paramdef>
- <paramdef>char **<parameter>unit</parameter></paramdef>
- </funcprototype>
-
- <funcprototype>
- <funcdef>int <function>sd_pid_get_owner_uid</function></funcdef>
- <paramdef>pid_t <parameter>pid</parameter></paramdef>
- <paramdef>uid_t *<parameter>uid</parameter></paramdef>
- </funcprototype>
-
- <funcprototype>
- <funcdef>int <function>sd_pid_get_machine_name</function></funcdef>
- <paramdef>pid_t <parameter>pid</parameter></paramdef>
- <paramdef>char **<parameter>name</parameter></paramdef>
- </funcprototype>
-
- <funcprototype>
- <funcdef>int <function>sd_pid_get_slice</function></funcdef>
- <paramdef>pid_t <parameter>pid</parameter></paramdef>
- <paramdef>char **<parameter>slice</parameter></paramdef>
- </funcprototype>
-
- <funcprototype>
- <funcdef>int <function>sd_peer_get_session</function></funcdef>
- <paramdef>int <parameter>fd</parameter></paramdef>
- <paramdef>char **<parameter>session</parameter></paramdef>
- </funcprototype>
-
- <funcprototype>
- <funcdef>int <function>sd_peer_get_unit</function></funcdef>
- <paramdef>int <parameter>fd</parameter></paramdef>
- <paramdef>char **<parameter>unit</parameter></paramdef>
- </funcprototype>
-
- <funcprototype>
- <funcdef>int <function>sd_peer_get_user_unit</function></funcdef>
- <paramdef>int <parameter>fd</parameter></paramdef>
- <paramdef>char **<parameter>unit</parameter></paramdef>
- </funcprototype>
-
- <funcprototype>
- <funcdef>int <function>sd_peer_get_owner_uid</function></funcdef>
- <paramdef>int <parameter>fd</parameter></paramdef>
- <paramdef>uid_t *<parameter>uid</parameter></paramdef>
- </funcprototype>
-
- <funcprototype>
- <funcdef>int <function>sd_peer_get_machine_name</function></funcdef>
- <paramdef>int <parameter>fd</parameter></paramdef>
- <paramdef>char **<parameter>name</parameter></paramdef>
- </funcprototype>
-
- <funcprototype>
- <funcdef>int <function>sd_peer_get_slice</function></funcdef>
- <paramdef>int <parameter>fd</parameter></paramdef>
- <paramdef>char **<parameter>slice</parameter></paramdef>
- </funcprototype>
- </funcsynopsis>
- </refsynopsisdiv>
-
- <refsect1>
- <title>Description</title>
-
- <para><function>sd_pid_get_session()</function> may be used to
- determine the login session identifier of a process identified by
- the specified process identifier. The session identifier is a
- short string, suitable for usage in file system paths. Note that
- not all processes are part of a login session (e.g. system service
- processes, user processes that are shared between multiple
- sessions of the same user, or kernel threads). For processes not
- being part of a login session this function will fail with
- -ENXIO. The returned string needs to be freed with the libc
- <citerefentry
- project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- call after use.</para>
-
- <para><function>sd_pid_get_unit()</function> may be used to
- determine the systemd system unit (i.e. system service) identifier
- of a process identified by the specified PID. The unit name is a
- short string, suitable for usage in file system paths. Note that
- not all processes are part of a system unit/service (e.g. user
- processes, or kernel threads). For processes not being part of a
- systemd system unit this function will fail with -ENXIO (More
- specifically: this call will not work for processes that are part
- of user units, use <function>sd_pid_get_user_unit()</function> for
- that.) The returned string needs to be freed with the libc
- <citerefentry
- project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- call after use.</para>
-
- <para><function>sd_pid_get_user_unit()</function> may be used to
- determine the systemd user unit (i.e. user service) identifier of
- a process identified by the specified PID. This is similar to
- <function>sd_pid_get_unit()</function> but applies to user units
- instead of system units.</para>
-
- <para><function>sd_pid_get_owner_uid()</function> may be used to
- determine the Unix user identifier of the owner of the session of
- a process identified the specified PID. Note that this function
- will succeed for user processes which are shared between multiple
- login sessions of the same user, where
- <function>sd_pid_get_session()</function> will fail. For processes
- not being part of a login session and not being a shared process
- of a user this function will fail with -ENXIO.</para>
-
- <para><function>sd_pid_get_machine_name()</function> may be used
- to determine the name of the VM or container is a member of. The
- machine name is a short string, suitable for usage in file system
- paths. The returned string needs to be freed with the libc
- <citerefentry
- project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- call after use. For processes not part of a VM or containers this
- function fails with -ENXIO.</para>
-
- <para><function>sd_pid_get_slice()</function> may be used to
- determine the slice unit the process is a member of. See
- <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for details about slices. The returned string needs to be freed
- with the libc
- <citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- call after use.</para>
-
- <para>If the <varname>pid</varname> parameter of any of these
- functions is passed as 0, the operation is executed for the
- calling process.</para>
-
- <para>The <function>sd_peer_get_session()</function>,
- <function>sd_peer_get_unit()</function>,
- <function>sd_peer_get_user_unit()</function>,
- <function>sd_peer_get_owner_uid()</function>,
- <function>sd_peer_get_machine_name()</function> and
- <function>sd_peer_get_slice()</function> calls operate similar to
- their PID counterparts, but operate on a connected AF_UNIX socket
- and retrieve information about the connected peer process.</para>
- </refsect1>
-
- <refsect1>
- <title>Return Value</title>
-
- <para>On success, these calls return 0 or a positive integer. On
- failure, these calls return a negative errno-style error
- code.</para>
- </refsect1>
-
- <refsect1>
- <title>Errors</title>
-
- <para>Returned errors may indicate the following problems:</para>
-
- <variablelist>
-
- <varlistentry>
- <term><constant>-ENXIO</constant></term>
-
- <listitem><para>Given field is not specified for the described
- process or peer.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><constant>-ESRCH</constant></term>
-
- <listitem><para>The specified PID does not refer to a running
- process.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><constant>-ENOMEM</constant></term>
-
- <listitem><para>Memory allocation failed.</para></listitem>
- </varlistentry>
- </variablelist>
- </refsect1>
-
- <refsect1>
- <title>Notes</title>
-
- <para>The <function>sd_pid_get_session()</function>,
- <function>sd_pid_get_unit()</function>,
- <function>sd_pid_get_user_unit()</function>,
- <function>sd_pid_get_owner_uid()</function>,
- <function>sd_pid_get_machine_name()</function>,
- <function>sd_pid_get_slice()</function>,
- <function>sd_peer_get_session()</function>,
- <function>sd_peer_get_unit()</function>,
- <function>sd_peer_get_user_unit()</function>,
- <function>sd_peer_get_owner_uid()</function>,
- <function>sd_peer_get_machine_name()</function> and
- <function>sd_peer_get_slice()</function> interfaces are
- available as a shared library, which can be compiled
- and linked to with the
- <constant>libelogind</constant>Â <citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
- file.</para>
-
- <para>Note that the login session identifier as
- returned by <function>sd_pid_get_session()</function>
- is completely unrelated to the process session
- identifier as returned by
- <citerefentry><refentrytitle>getsid</refentrytitle><manvolnum>2</manvolnum></citerefentry>.</para>
- </refsect1>
-
- <refsect1>
- <title>See Also</title>
-
- <para>
- <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd-login</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_session_is_active</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>getsid</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- </para>
- </refsect1>
-
-</refentry>
--- /dev/null
+<?xml version="1.0"?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
+<!DOCTYPE refsection PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<refsection>
+ <refsection id='confd'>
+ <title>Configuration Directories and Precedence</title>
+
+ <para>Configuration files are read from directories in
+ <filename>/etc/</filename>, <filename>/run/</filename>, and
+ <filename>/usr/lib/</filename>, in order of precedence.
+ Each configuration file in these configuration directories shall be named in
+ the style of <filename><replaceable>filename</replaceable>.conf</filename>.
+ Files in <filename>/etc/</filename> override files with the same name in
+ <filename>/run/</filename> and <filename>/usr/lib/</filename>. Files in
+ <filename>/run/</filename> override files with the same name in
+ <filename>/usr/lib/</filename>.</para>
+
+ <para>Packages should install their configuration files in
+ <filename>/usr/lib/</filename>. Files in <filename>/etc/</filename> are
+ reserved for the local administrator, who may use this logic to override the
+ configuration files installed by vendor packages. All configuration files
+ are sorted by their filename in lexicographic order, regardless of which of
+ the directories they reside in. If multiple files specify the same option,
+ the entry in the file with the lexicographically latest name will take
+ precedence. It is recommended to prefix all filenames with a two-digit number
+ and a dash, to simplify the ordering of the files.</para>
+
+ <para>If the administrator wants to disable a configuration file supplied by
+ the vendor, the recommended way is to place a symlink to
+ <filename>/dev/null</filename> in the configuration directory in
+ <filename>/etc/</filename>, with the same filename as the vendor
+ configuration file. If the vendor configuration file is included in
+ the initrd image, the image has to be regenerated.</para>
+
+ </refsection>
+
+ <refsection id='main-conf'>
+ <title>Configuration Directories and Precedence</title>
+
+ <para>Default configuration is defined during compilation, so a
+ configuration file is only needed when it is necessary to deviate
+ from those defaults. By default the configuration file in
+ <filename>/etc/elogind/</filename> contains commented out entries
+ showing the defaults as a guide to the administrator. This file
+ can be edited to create local overrides.
+ </para>
+
+ <para>When packages need to customize the configuration, they can
+ install configuration snippets in
+ <filename>/usr/lib/elogind/*.conf.d/</filename>. Files in
+ <filename>/etc/</filename> are reserved for the local
+ administrator, who may use this logic to override the
+ configuration files installed by vendor packages. The main
+ configuration file is read before any of the configuration
+ directories, and has the lowest precedence; entries in a file in
+ any configuration directory override entries in the single
+ configuration file. Files in the
+ <filename>*.conf.d/</filename> configuration subdirectories
+ are sorted by their filename in lexicographic order, regardless of
+ which of the subdirectories they reside in. If multiple files
+ specify the same option, the entry in the file with the
+ lexicographically latest name takes precedence. It is recommended
+ to prefix all filenames in those subdirectories with a two-digit
+ number and a dash, to simplify the ordering of the files.</para>
+
+ <para>To disable a configuration file supplied by the vendor, the
+ recommended way is to place a symlink to
+ <filename>/dev/null</filename> in the configuration directory in
+ <filename>/etc/</filename>, with the same filename as the vendor
+ configuration file.</para>
+ </refsection>
+</refsection>
--- /dev/null
+<?xml version="1.0"?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<variablelist>
+ <varlistentry id='help'>
+ <term><option>-h</option></term>
+ <term><option>--help</option></term>
+
+ <listitem id='help-text'>
+ <para>Print a short help text and exit.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry id='version'>
+ <term><option>--version</option></term>
+
+ <listitem id='version-text'>
+ <para>Print a short version string and exit.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='no-pager'>
+ <term><option>--no-pager</option></term>
+
+ <listitem>
+ <para>Do not pipe output into a pager.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='no-legend'>
+ <term><option>--no-legend</option></term>
+
+ <listitem>
+ <para>Do not print the legend, i.e. column headers and the
+ footer with hints.</para>
+ </listitem>
+ </varlistentry>
+</variablelist>
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<variablelist>
+ <varlistentry id='user'>
+ <term><option>--user</option></term>
+
+ <listitem id='user-text'>
+ <para>Talk to the service manager of the calling user,
+ rather than the service manager of the system.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='system'>
+ <term><option>--system</option></term>
+
+ <listitem id='system-text'>
+ <para>Talk to the service manager of the system. This is the
+ implied default.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='host'>
+ <term><option>-H</option></term>
+ <term><option>--host=</option></term>
+
+ <listitem id='host-text'>
+ <para>Execute the operation remotely. Specify a hostname, or a
+ username and hostname separated by <literal>@</literal>, to
+ connect to. The hostname may optionally be suffixed by a
+ container name, separated by <literal>:</literal>, which
+ connects directly to a specific container on the specified
+ host. This will use SSH to talk to the remote machine manager
+ instance. Container names may be enumerated with
+ <command>machinectl -H
+ <replaceable>HOST</replaceable></command>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id='machine'>
+ <term><option>-M</option></term>
+ <term><option>--machine=</option></term>
+
+ <listitem id='machine-text'>
+ <para>Execute operation on a local container. Specify a
+ container name to connect to.</para>
+ </listitem>
+ </varlistentry>
+</variablelist>
{-h,--help}'[Show this help]' \
'--version[Show package version]' \
'--what=[Operations to inhibit]:options:_inhibit_what' \
- '--who=[A descriptive string who is inhibiting]' \
- '--why=[A descriptive string why is being inhibited]' \
- '--mode=[One of block or delay]' \
+ '--who=[A descriptive string who is inhibiting]:who is inhibiting:' \
+ '--why=[A descriptive string why is being inhibited]:reason for the lock:' \
+ '--mode=[One of block or delay]:lock mode:( block delay )' \
'--list[List active inhibitors]' \
'*:commands:_systemd_inhibit_command'
snprintf(c, sizeof(c), PID_FMT"\n", pid);
- return write_string_file_no_create(fs, c);
+ return write_string_file(fs, c, 0);
}
int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
sc = strstrip(contents);
if (isempty(sc)) {
- r = write_string_file_no_create(fs, agent);
+ r = write_string_file(fs, agent, 0);
if (r < 0)
return r;
} else if (!path_equal(sc, agent))
sc = strstrip(contents);
if (streq(sc, "0")) {
- r = write_string_file_no_create(fs, "1");
+ r = write_string_file(fs, "1", 0);
if (r < 0)
return r;
if (r < 0)
return r;
- r = write_string_file_no_create(fs, "0");
+ r = write_string_file(fs, "0", 0);
if (r < 0)
return r;
if (r < 0)
return r;
- r = write_string_file_no_create(fs, "");
+ r = write_string_file(fs, "", 0);
if (r < 0)
return r;
if (r < 0)
return r;
- return write_string_file_no_create(p, value);
+ return write_string_file(p, value, 0);
}
/// UNNEEDED by elogind
#define BTRFS_FIRST_FREE_OBJECTID 256
#endif
+#ifndef BTRFS_LAST_FREE_OBJECTID
+#define BTRFS_LAST_FREE_OBJECTID -256ULL
+#endif
+
#ifndef BTRFS_ROOT_TREE_OBJECTID
#define BTRFS_ROOT_TREE_OBJECTID 1
#endif
#define BTRFS_QGROUP_LIMIT_KEY 244
#endif
+#ifndef BTRFS_ROOT_BACKREF_KEY
+#define BTRFS_ROOT_BACKREF_KEY 144
+#endif
+
#ifndef BTRFS_SUPER_MAGIC
#define BTRFS_SUPER_MAGIC 0x9123683E
#endif
#define LOOPBACK_IFINDEX 1
#endif
+#if !HAVE_DECL_IFA_FLAGS
+#define IFA_FLAGS 8
+#endif
+
+#ifndef IFA_F_NOPREFIXROUTE
+#define IFA_F_NOPREFIXROUTE 0x200
+#endif
+
#ifndef MAX_AUDIT_MESSAGE_LENGTH
#define MAX_AUDIT_MESSAGE_LENGTH 8970
#endif
#ifndef RENAME_NOREPLACE
#define RENAME_NOREPLACE (1 << 0)
#endif
+
+#if !HAVE_DECL_KCMP
+static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
+ return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
+}
+#endif
+
+#ifndef KCMP_FILE
+#define KCMP_FILE 0
+#endif
+
+#ifndef INPUT_PROP_POINTING_STICK
+#define INPUT_PROP_POINTING_STICK 0x05
+#endif
+
+#ifndef INPUT_PROP_ACCELEROMETER
+#define INPUT_PROP_ACCELEROMETER 0x06
+#endif
REMOVE_ONLY_DIRECTORIES = 1,
REMOVE_ROOT = 2,
REMOVE_PHYSICAL = 4, /* if not set, only removes files on tmpfs, never physical file systems */
+ REMOVE_SUBVOLUME = 8,
} RemoveFlags;
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "in-addr-util.h"
+#define VERB_ANY ((unsigned) -1)
+#define VERB_DEFAULT 1
-typedef struct DnsServer DnsServer;
-typedef enum DnsServerSource DnsServerSource;
+typedef struct {
+ const char *verb;
+ unsigned min_args, max_args;
+ unsigned flags;
+ int (* const dispatch)(int argc, char *argv[], void *userdata);
+} Verb;
-typedef enum DnsServerType {
- DNS_SERVER_SYSTEM,
- DNS_SERVER_FALLBACK,
- DNS_SERVER_LINK,
-} DnsServerType;
-
-#include "resolved-link.h"
-
-struct DnsServer {
- Manager *manager;
-
- unsigned n_ref;
-
- DnsServerType type;
-
- Link *link;
-
- int family;
- union in_addr_union address;
-
- bool marked:1;
-
- LIST_FIELDS(DnsServer, servers);
-};
-
-int dns_server_new(
- Manager *m,
- DnsServer **s,
- DnsServerType type,
- Link *l,
- int family,
- const union in_addr_union *address);
-
-DnsServer* dns_server_ref(DnsServer *s);
-DnsServer* dns_server_unref(DnsServer *s);
-
-extern const struct hash_ops dns_server_hash_ops;
+int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata);
+++ /dev/null
-../Makefile
\ No newline at end of file
LIBSYSTEMD_209 {
global:
/* sd-journal */
- sd_journal_print;
- sd_journal_printv;
- sd_journal_send;
- sd_journal_sendv;
- sd_journal_stream_fd;
- sd_journal_open;
- sd_journal_close;
- sd_journal_previous;
- sd_journal_next;
- sd_journal_previous_skip;
- sd_journal_next_skip;
- sd_journal_get_realtime_usec;
- sd_journal_get_monotonic_usec;
- sd_journal_get_data;
- sd_journal_enumerate_data;
- sd_journal_restart_data;
- sd_journal_add_match;
- sd_journal_flush_matches;
- sd_journal_seek_head;
- sd_journal_seek_tail;
- sd_journal_seek_monotonic_usec;
- sd_journal_seek_realtime_usec;
- sd_journal_seek_cursor;
- sd_journal_get_cursor;
- sd_journal_get_fd;
- sd_journal_process;
- sd_journal_print_with_location;
- sd_journal_printv_with_location;
- sd_journal_send_with_location;
- sd_journal_sendv_with_location;
- sd_journal_get_cutoff_realtime_usec;
- sd_journal_get_cutoff_monotonic_usec;
- sd_journal_wait;
- sd_journal_open_directory;
- sd_journal_add_disjunction;
- sd_journal_perror;
- sd_journal_perror_with_location;
- sd_journal_get_usage;
- sd_journal_test_cursor;
- sd_journal_query_unique;
- sd_journal_enumerate_unique;
- sd_journal_restart_unique;
- sd_journal_get_catalog;
- sd_journal_get_catalog_for_message_id;
- sd_journal_set_data_threshold;
- sd_journal_get_data_threshold;
- sd_journal_reliable_fd;
- sd_journal_get_events;
- sd_journal_get_timeout;
- sd_journal_add_conjunction;
- sd_journal_open_files;
- sd_journal_open_container;
+ /* sd_journal_print; */
+ /* sd_journal_printv; */
+ /* sd_journal_send; */
+ /* sd_journal_sendv; */
+ /* sd_journal_stream_fd; */
+ /* sd_journal_open; */
+ /* sd_journal_close; */
+ /* sd_journal_previous; */
+ /* sd_journal_next; */
+ /* sd_journal_previous_skip; */
+ /* sd_journal_next_skip; */
+ /* sd_journal_get_realtime_usec; */
+ /* sd_journal_get_monotonic_usec; */
+ /* sd_journal_get_data; */
+ /* sd_journal_enumerate_data; */
+ /* sd_journal_restart_data; */
+ /* sd_journal_add_match; */
+ /* sd_journal_flush_matches; */
+ /* sd_journal_seek_head; */
+ /* sd_journal_seek_tail; */
+ /* sd_journal_seek_monotonic_usec; */
+ /* sd_journal_seek_realtime_usec; */
+ /* sd_journal_seek_cursor; */
+ /* sd_journal_get_cursor; */
+ /* sd_journal_get_fd; */
+ /* sd_journal_process; */
+ /* sd_journal_print_with_location; */
+ /* sd_journal_printv_with_location; */
+ /* sd_journal_send_with_location; */
+ /* sd_journal_sendv_with_location; */
+ /* sd_journal_get_cutoff_realtime_usec; */
+ /* sd_journal_get_cutoff_monotonic_usec; */
+ /* sd_journal_wait; */
+ /* sd_journal_open_directory; */
+ /* sd_journal_add_disjunction; */
+ /* sd_journal_perror; */
+ /* sd_journal_perror_with_location; */
+ /* sd_journal_get_usage; */
+ /* sd_journal_test_cursor; */
+ /* sd_journal_query_unique; */
+ /* sd_journal_enumerate_unique; */
+ /* sd_journal_restart_unique; */
+ /* sd_journal_get_catalog; */
+ /* sd_journal_get_catalog_for_message_id; */
+ /* sd_journal_set_data_threshold; */
+ /* sd_journal_get_data_threshold; */
+ /* sd_journal_reliable_fd; */
+ /* sd_journal_get_events; */
+ /* sd_journal_get_timeout; */
+ /* sd_journal_add_conjunction; */
+ /* sd_journal_open_files; */
+ /* sd_journal_open_container; */
/* sd-daemon */
/* sd_booted; */
sd_bus_new;
sd_bus_set_address;
sd_bus_set_fd;
- sd_bus_set_exec;
- sd_bus_get_address;
- sd_bus_set_bus_client;
- sd_bus_is_bus_client;
+ /* sd_bus_set_exec; */
+ /* sd_bus_get_address; */
+ /* sd_bus_set_bus_client; */
+ /* sd_bus_is_bus_client; */
sd_bus_set_server;
- sd_bus_is_server;
- sd_bus_set_anonymous;
- sd_bus_is_anonymous;
- sd_bus_set_trusted;
- sd_bus_is_trusted;
- sd_bus_set_monitor;
- sd_bus_is_monitor;
- sd_bus_set_description;
- sd_bus_get_description;
+ /* sd_bus_is_server; */
+ /* sd_bus_set_anonymous; */
+ /* sd_bus_is_anonymous; */
+ /* sd_bus_set_trusted; */
+ /* sd_bus_is_trusted; */
+ /* sd_bus_set_monitor; */
+ /* sd_bus_is_monitor; */
+ /* sd_bus_set_description; */
+ /* sd_bus_get_description; */
sd_bus_negotiate_creds;
- sd_bus_negotiate_timestamp;
- sd_bus_negotiate_fds;
+ /* sd_bus_negotiate_timestamp; */
+ /* sd_bus_negotiate_fds; */
sd_bus_can_send;
- sd_bus_get_creds_mask;
+ /* sd_bus_get_creds_mask; */
sd_bus_set_allow_interactive_authorization;
- sd_bus_get_allow_interactive_authorization;
+ /* sd_bus_get_allow_interactive_authorization; */
sd_bus_start;
sd_bus_close;
sd_bus_try_close;
sd_bus_ref;
sd_bus_unref;
- sd_bus_is_open;
- sd_bus_get_bus_id;
- sd_bus_get_scope;
- sd_bus_get_tid;
+ /* sd_bus_is_open; */
+ /* sd_bus_get_bus_id; */
+ /* sd_bus_get_scope; */
+ /* sd_bus_get_tid; */
sd_bus_get_owner_creds;
sd_bus_send;
sd_bus_send_to;
sd_bus_get_events;
sd_bus_get_timeout;
sd_bus_process;
- sd_bus_process_priority;
+ /* sd_bus_process_priority; */
sd_bus_wait;
sd_bus_flush;
- sd_bus_get_current_slot;
+ /* sd_bus_get_current_slot; */
sd_bus_get_current_message;
sd_bus_get_current_handler;
sd_bus_get_current_userdata;
sd_bus_add_object_vtable;
sd_bus_add_fallback_vtable;
sd_bus_add_node_enumerator;
- sd_bus_add_object_manager;
+ /* sd_bus_add_object_manager; */
sd_bus_slot_ref;
sd_bus_slot_unref;
- sd_bus_slot_get_bus;
- sd_bus_slot_get_userdata;
- sd_bus_slot_set_userdata;
- sd_bus_slot_get_description;
- sd_bus_slot_set_description;
- sd_bus_slot_get_current_message;
- sd_bus_slot_get_current_handler;
- sd_bus_slot_get_current_userdata;
+ /* sd_bus_slot_get_bus; */
+ /* sd_bus_slot_get_userdata; */
+ /* sd_bus_slot_set_userdata; */
+ /* sd_bus_slot_get_description; */
+ /* sd_bus_slot_set_description; */
+ /* sd_bus_slot_get_current_message; */
+ /* sd_bus_slot_get_current_handler; */
+ /* sd_bus_slot_get_current_userdata; */
sd_bus_message_new_signal;
sd_bus_message_new_method_call;
sd_bus_message_new_method_return;
sd_bus_message_new_method_error;
sd_bus_message_new_method_errorf;
sd_bus_message_new_method_errno;
- sd_bus_message_new_method_errnof;
+ /* sd_bus_message_new_method_errnof; */
sd_bus_message_ref;
sd_bus_message_unref;
- sd_bus_message_get_type;
- sd_bus_message_get_cookie;
- sd_bus_message_get_reply_cookie;
- sd_bus_message_get_priority;
- sd_bus_message_get_expect_reply;
- sd_bus_message_get_auto_start;
+ /* sd_bus_message_get_type; */
+ /* sd_bus_message_get_cookie; */
+ /* sd_bus_message_get_reply_cookie; */
+ /* sd_bus_message_get_priority; */
+ /* sd_bus_message_get_expect_reply; */
+ /* sd_bus_message_get_auto_start; */
sd_bus_message_get_allow_interactive_authorization;
sd_bus_message_get_signature;
sd_bus_message_get_path;
sd_bus_message_get_sender;
sd_bus_message_get_error;
sd_bus_message_get_errno;
- sd_bus_message_get_monotonic_usec;
- sd_bus_message_get_realtime_usec;
- sd_bus_message_get_seqnum;
+ /* sd_bus_message_get_monotonic_usec; */
+ /* sd_bus_message_get_realtime_usec; */
+ /* sd_bus_message_get_seqnum; */
sd_bus_message_get_bus;
sd_bus_message_get_creds;
- sd_bus_message_is_signal;
+ /* sd_bus_message_is_signal; */
sd_bus_message_is_method_call;
sd_bus_message_is_method_error;
- sd_bus_message_is_empty;
- sd_bus_message_has_signature;
- sd_bus_message_set_expect_reply;
+ /* sd_bus_message_is_empty; */
+ /* sd_bus_message_has_signature; */
+ /* sd_bus_message_set_expect_reply; */
sd_bus_message_set_auto_start;
- sd_bus_message_set_allow_interactive_authorization;
+ /* sd_bus_message_set_allow_interactive_authorization; */
sd_bus_message_set_destination;
- sd_bus_message_set_priority;
+ /* sd_bus_message_set_priority; */
sd_bus_message_append;
sd_bus_message_append_basic;
sd_bus_message_append_array;
sd_bus_message_append_array_space;
- sd_bus_message_append_array_iovec;
- sd_bus_message_append_array_memfd;
+ /* sd_bus_message_append_array_iovec; */
+ /* sd_bus_message_append_array_memfd; */
sd_bus_message_append_string_space;
- sd_bus_message_append_string_iovec;
- sd_bus_message_append_string_memfd;
+ /* sd_bus_message_append_string_iovec; */
+ /* sd_bus_message_append_string_memfd; */
sd_bus_message_append_strv;
sd_bus_message_open_container;
sd_bus_message_close_container;
sd_bus_message_enter_container;
sd_bus_message_exit_container;
sd_bus_message_peek_type;
- sd_bus_message_verify_type;
- sd_bus_message_at_end;
+ /* sd_bus_message_verify_type; */
+ /* sd_bus_message_at_end; */
sd_bus_message_rewind;
sd_bus_get_unique_name;
sd_bus_request_name;
sd_bus_release_name;
sd_bus_list_names;
sd_bus_get_name_creds;
- sd_bus_get_name_machine_id;
+ /* sd_bus_get_name_machine_id; */
sd_bus_call_method;
- sd_bus_call_method_async;
+ /* sd_bus_call_method_async; */
sd_bus_get_property;
- sd_bus_get_property_trivial;
+ /* sd_bus_get_property_trivial; */
sd_bus_get_property_string;
- sd_bus_get_property_strv;
- sd_bus_set_property;
+ /* sd_bus_get_property_strv; */
+ /* sd_bus_set_property; */
sd_bus_reply_method_return;
sd_bus_reply_method_error;
sd_bus_reply_method_errorf;
sd_bus_reply_method_errno;
- sd_bus_reply_method_errnof;
+ /* sd_bus_reply_method_errnof; */
sd_bus_emit_signal;
sd_bus_emit_properties_changed_strv;
sd_bus_emit_properties_changed;
sd_bus_emit_interfaces_removed;
sd_bus_query_sender_creds;
sd_bus_query_sender_privilege;
- sd_bus_creds_new_from_pid;
+ /* sd_bus_creds_new_from_pid; */
sd_bus_creds_ref;
sd_bus_creds_unref;
- sd_bus_creds_get_mask;
+ /* sd_bus_creds_get_mask; */
sd_bus_creds_get_augmented_mask;
sd_bus_creds_get_pid;
- sd_bus_creds_get_ppid;
+ /* sd_bus_creds_get_ppid; */
sd_bus_creds_get_tid;
sd_bus_creds_get_uid;
sd_bus_creds_get_euid;
- sd_bus_creds_get_suid;
- sd_bus_creds_get_fsuid;
- sd_bus_creds_get_gid;
+ /* sd_bus_creds_get_suid; */
+ /* sd_bus_creds_get_fsuid; */
+ /* sd_bus_creds_get_gid; */
sd_bus_creds_get_egid;
- sd_bus_creds_get_sgid;
- sd_bus_creds_get_fsgid;
- sd_bus_creds_get_supplementary_gids;
- sd_bus_creds_get_comm;
- sd_bus_creds_get_tid_comm;
- sd_bus_creds_get_exe;
+ /* sd_bus_creds_get_sgid; */
+ /* sd_bus_creds_get_fsgid; */
+ /* sd_bus_creds_get_supplementary_gids; */
+ /* sd_bus_creds_get_comm; */
+ /* sd_bus_creds_get_tid_comm; */
+ /* sd_bus_creds_get_exe; */
sd_bus_creds_get_cmdline;
- sd_bus_creds_get_cgroup;
- sd_bus_creds_get_unit;
- sd_bus_creds_get_slice;
- sd_bus_creds_get_user_unit;
- sd_bus_creds_get_user_slice;
+ /* sd_bus_creds_get_cgroup; */
+ /* sd_bus_creds_get_unit; */
+ /* sd_bus_creds_get_slice; */
+ /* sd_bus_creds_get_user_unit; */
+ /* sd_bus_creds_get_user_slice; */
sd_bus_creds_get_session;
sd_bus_creds_get_owner_uid;
sd_bus_creds_has_effective_cap;
- sd_bus_creds_has_permitted_cap;
- sd_bus_creds_has_inheritable_cap;
- sd_bus_creds_has_bounding_cap;
+ /* sd_bus_creds_has_permitted_cap; */
+ /* sd_bus_creds_has_inheritable_cap; */
+ /* sd_bus_creds_has_bounding_cap; */
sd_bus_creds_get_selinux_context;
- sd_bus_creds_get_audit_session_id;
+ /* sd_bus_creds_get_audit_session_id; */
sd_bus_creds_get_audit_login_uid;
sd_bus_creds_get_tty;
- sd_bus_creds_get_unique_name;
- sd_bus_creds_get_well_known_names;
- sd_bus_creds_get_description;
+ /* sd_bus_creds_get_unique_name; */
+ /* sd_bus_creds_get_well_known_names; */
+ /* sd_bus_creds_get_description; */
sd_bus_error_free;
sd_bus_error_set;
sd_bus_error_setf;
sd_bus_error_is_set;
sd_bus_error_has_name;
sd_bus_error_add_map;
- sd_bus_path_encode;
- sd_bus_path_decode;
+ /* sd_bus_path_encode; */
+ /* sd_bus_path_decode; */
sd_bus_track_new;
sd_bus_track_ref;
sd_bus_track_unref;
sd_bus_track_get_bus;
- sd_bus_track_get_userdata;
- sd_bus_track_set_userdata;
+ /* sd_bus_track_get_userdata; */
+ /* sd_bus_track_set_userdata; */
sd_bus_track_add_sender;
sd_bus_track_remove_sender;
sd_bus_track_add_name;
sd_event_wait;
sd_event_dispatch;
sd_event_run;
- sd_event_loop;
+ /* sd_event_loop; */
sd_event_exit;
- sd_event_now;
- sd_event_get_fd;
+ /* sd_event_now; */
+ /* sd_event_get_fd; */
sd_event_get_state;
sd_event_get_tid;
sd_event_get_exit_code;
sd_event_set_watchdog;
- sd_event_get_watchdog;
- sd_event_source_ref;
+ /* sd_event_get_watchdog; */
+ /* sd_event_source_ref; */
sd_event_source_unref;
sd_event_source_get_event;
- sd_event_source_get_userdata;
- sd_event_source_set_userdata;
+ /* sd_event_source_get_userdata; */
+ /* sd_event_source_set_userdata; */
sd_event_source_set_description;
- sd_event_source_get_description;
+ /* sd_event_source_get_description; */
sd_event_source_set_prepare;
- sd_event_source_get_pending;
- sd_event_source_get_priority;
+ /* sd_event_source_get_pending; */
+ /* sd_event_source_get_priority; */
sd_event_source_set_priority;
- sd_event_source_get_enabled;
+ /* sd_event_source_get_enabled; */
sd_event_source_set_enabled;
- sd_event_source_get_io_fd;
+ /* sd_event_source_get_io_fd; */
sd_event_source_set_io_fd;
- sd_event_source_get_io_events;
+ /* sd_event_source_get_io_events; */
sd_event_source_set_io_events;
- sd_event_source_get_io_revents;
+ /* sd_event_source_get_io_revents; */
sd_event_source_get_time;
sd_event_source_set_time;
- sd_event_source_set_time_accuracy;
- sd_event_source_get_time_accuracy;
- sd_event_source_get_time_clock;
- sd_event_source_get_signal;
- sd_event_source_get_child_pid;
+ /* sd_event_source_set_time_accuracy; */
+ /* sd_event_source_get_time_accuracy; */
+ /* sd_event_source_get_time_clock; */
+ /* sd_event_source_get_signal; */
+ /* sd_event_source_get_child_pid; */
} LIBSYSTEMD_220;
LIBSYSTEMD_222 {
global:
/* sd-bus */
sd_bus_emit_object_added;
- sd_bus_emit_object_removed;
+ /* sd_bus_emit_object_removed; */
sd_bus_flush_close_unref;
} LIBSYSTEMD_221;
+++ /dev/null
-/***
- This file is part of systemd.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-***/
-
-LIBSYSTEMD_209 {
-global:
- /* sd-journal */
- sd_journal_print;
- sd_journal_printv;
- sd_journal_send;
- sd_journal_sendv;
- sd_journal_stream_fd;
- sd_journal_open;
- sd_journal_close;
- sd_journal_previous;
- sd_journal_next;
- sd_journal_previous_skip;
- sd_journal_next_skip;
- sd_journal_get_realtime_usec;
- sd_journal_get_monotonic_usec;
- sd_journal_get_data;
- sd_journal_enumerate_data;
- sd_journal_restart_data;
- sd_journal_add_match;
- sd_journal_flush_matches;
- sd_journal_seek_head;
- sd_journal_seek_tail;
- sd_journal_seek_monotonic_usec;
- sd_journal_seek_realtime_usec;
- sd_journal_seek_cursor;
- sd_journal_get_cursor;
- sd_journal_get_fd;
- sd_journal_process;
- sd_journal_print_with_location;
- sd_journal_printv_with_location;
- sd_journal_send_with_location;
- sd_journal_sendv_with_location;
- sd_journal_get_cutoff_realtime_usec;
- sd_journal_get_cutoff_monotonic_usec;
- sd_journal_wait;
- sd_journal_open_directory;
- sd_journal_add_disjunction;
- sd_journal_perror;
- sd_journal_perror_with_location;
- sd_journal_get_usage;
- sd_journal_test_cursor;
- sd_journal_query_unique;
- sd_journal_enumerate_unique;
- sd_journal_restart_unique;
- sd_journal_get_catalog;
- sd_journal_get_catalog_for_message_id;
- sd_journal_set_data_threshold;
- sd_journal_get_data_threshold;
- sd_journal_reliable_fd;
- sd_journal_get_events;
- sd_journal_get_timeout;
- sd_journal_add_conjunction;
- sd_journal_open_files;
- sd_journal_open_container;
-
- /* sd-daemon */
- sd_booted;
- sd_is_fifo;
- sd_is_mq;
- sd_is_socket;
- sd_is_socket_inet;
- sd_is_socket_unix;
- sd_is_special;
- sd_listen_fds;
- sd_notify;
- sd_notifyf;
- sd_watchdog_enabled;
-
- /* sd-id128 */
- sd_id128_to_string;
- sd_id128_from_string;
- sd_id128_randomize;
- sd_id128_get_machine;
- sd_id128_get_boot;
-
- /* sd-login */
- sd_get_seats;
- sd_get_sessions;
- sd_get_uids;
- sd_login_monitor_flush;
- sd_login_monitor_get_fd;
- sd_login_monitor_new;
- sd_login_monitor_unref;
- sd_pid_get_owner_uid;
- sd_pid_get_session;
- sd_seat_can_multi_session;
- sd_seat_get_active;
- sd_seat_get_sessions;
- sd_session_get_seat;
- sd_session_get_uid;
- sd_session_is_active;
- sd_uid_get_seats;
- sd_uid_get_sessions;
- sd_uid_get_state;
- sd_uid_is_on_seat;
- sd_pid_get_unit;
- sd_session_get_service;
- sd_session_get_type;
- sd_session_get_class;
- sd_session_get_display;
- sd_session_get_state;
- sd_seat_can_tty;
- sd_seat_can_graphical;
- sd_session_get_tty;
- sd_login_monitor_get_events;
- sd_login_monitor_get_timeout;
- sd_pid_get_user_unit;
- sd_pid_get_machine_name;
- sd_get_machine_names;
- sd_pid_get_slice;
- sd_session_get_vt;
- sd_session_is_remote;
- sd_session_get_remote_user;
- sd_session_get_remote_host;
-local:
- *;
-};
-
-LIBSYSTEMD_211 {
-global:
- sd_machine_get_class;
- sd_peer_get_session;
- sd_peer_get_owner_uid;
- sd_peer_get_unit;
- sd_peer_get_user_unit;
- sd_peer_get_machine_name;
- sd_peer_get_slice;
-} LIBSYSTEMD_209;
-
-LIBSYSTEMD_213 {
-global:
- sd_uid_get_display;
-} LIBSYSTEMD_211;
-
-LIBSYSTEMD_214 {
-global:
- sd_pid_notify;
- sd_pid_notifyf;
-} LIBSYSTEMD_213;
-
-LIBSYSTEMD_216 {
-global:
- sd_machine_get_ifindices;
-} LIBSYSTEMD_214;
-
-LIBSYSTEMD_217 {
-global:
- sd_session_get_desktop;
-} LIBSYSTEMD_216;
-
-LIBSYSTEMD_219 {
-global:
- sd_pid_notify_with_fds;
-} LIBSYSTEMD_217;
-
-LIBSYSTEMD_220 {
-global:
- sd_pid_get_user_slice;
- sd_peer_get_user_slice;
-} LIBSYSTEMD_219;
-
-LIBSYSTEMD_221 {
-global:
- /* sd-bus */
- sd_bus_default;
- sd_bus_default_user;
- sd_bus_default_system;
- sd_bus_open;
- sd_bus_open_user;
- sd_bus_open_system;
- sd_bus_open_system_remote;
- sd_bus_open_system_machine;
- sd_bus_new;
- sd_bus_set_address;
- sd_bus_set_fd;
- sd_bus_set_exec;
- sd_bus_get_address;
- sd_bus_set_bus_client;
- sd_bus_is_bus_client;
- sd_bus_set_server;
- sd_bus_is_server;
- sd_bus_set_anonymous;
- sd_bus_is_anonymous;
- sd_bus_set_trusted;
- sd_bus_is_trusted;
- sd_bus_set_monitor;
- sd_bus_is_monitor;
- sd_bus_set_description;
- sd_bus_get_description;
- sd_bus_negotiate_creds;
- sd_bus_negotiate_timestamp;
- sd_bus_negotiate_fds;
- sd_bus_can_send;
- sd_bus_get_creds_mask;
- sd_bus_set_allow_interactive_authorization;
- sd_bus_get_allow_interactive_authorization;
- sd_bus_start;
- sd_bus_close;
- sd_bus_try_close;
- sd_bus_ref;
- sd_bus_unref;
- sd_bus_is_open;
- sd_bus_get_bus_id;
- sd_bus_get_scope;
- sd_bus_get_tid;
- sd_bus_get_owner_creds;
- sd_bus_send;
- sd_bus_send_to;
- sd_bus_call;
- sd_bus_call_async;
- sd_bus_get_fd;
- sd_bus_get_events;
- sd_bus_get_timeout;
- sd_bus_process;
- sd_bus_process_priority;
- sd_bus_wait;
- sd_bus_flush;
- sd_bus_get_current_slot;
- sd_bus_get_current_message;
- sd_bus_get_current_handler;
- sd_bus_get_current_userdata;
- sd_bus_attach_event;
- sd_bus_detach_event;
- sd_bus_get_event;
- sd_bus_add_filter;
- sd_bus_add_match;
- sd_bus_add_object;
- sd_bus_add_fallback;
- sd_bus_add_object_vtable;
- sd_bus_add_fallback_vtable;
- sd_bus_add_node_enumerator;
- sd_bus_add_object_manager;
- sd_bus_slot_ref;
- sd_bus_slot_unref;
- sd_bus_slot_get_bus;
- sd_bus_slot_get_userdata;
- sd_bus_slot_set_userdata;
- sd_bus_slot_get_description;
- sd_bus_slot_set_description;
- sd_bus_slot_get_current_message;
- sd_bus_slot_get_current_handler;
- sd_bus_slot_get_current_userdata;
- sd_bus_message_new_signal;
- sd_bus_message_new_method_call;
- sd_bus_message_new_method_return;
- sd_bus_message_new_method_error;
- sd_bus_message_new_method_errorf;
- sd_bus_message_new_method_errno;
- sd_bus_message_new_method_errnof;
- sd_bus_message_ref;
- sd_bus_message_unref;
- sd_bus_message_get_type;
- sd_bus_message_get_cookie;
- sd_bus_message_get_reply_cookie;
- sd_bus_message_get_priority;
- sd_bus_message_get_expect_reply;
- sd_bus_message_get_auto_start;
- sd_bus_message_get_allow_interactive_authorization;
- sd_bus_message_get_signature;
- sd_bus_message_get_path;
- sd_bus_message_get_interface;
- sd_bus_message_get_member;
- sd_bus_message_get_destination;
- sd_bus_message_get_sender;
- sd_bus_message_get_error;
- sd_bus_message_get_errno;
- sd_bus_message_get_monotonic_usec;
- sd_bus_message_get_realtime_usec;
- sd_bus_message_get_seqnum;
- sd_bus_message_get_bus;
- sd_bus_message_get_creds;
- sd_bus_message_is_signal;
- sd_bus_message_is_method_call;
- sd_bus_message_is_method_error;
- sd_bus_message_is_empty;
- sd_bus_message_has_signature;
- sd_bus_message_set_expect_reply;
- sd_bus_message_set_auto_start;
- sd_bus_message_set_allow_interactive_authorization;
- sd_bus_message_set_destination;
- sd_bus_message_set_priority;
- sd_bus_message_append;
- sd_bus_message_append_basic;
- sd_bus_message_append_array;
- sd_bus_message_append_array_space;
- sd_bus_message_append_array_iovec;
- sd_bus_message_append_array_memfd;
- sd_bus_message_append_string_space;
- sd_bus_message_append_string_iovec;
- sd_bus_message_append_string_memfd;
- sd_bus_message_append_strv;
- sd_bus_message_open_container;
- sd_bus_message_close_container;
- sd_bus_message_copy;
- sd_bus_message_read;
- sd_bus_message_read_basic;
- sd_bus_message_read_array;
- sd_bus_message_read_strv;
- sd_bus_message_skip;
- sd_bus_message_enter_container;
- sd_bus_message_exit_container;
- sd_bus_message_peek_type;
- sd_bus_message_verify_type;
- sd_bus_message_at_end;
- sd_bus_message_rewind;
- sd_bus_get_unique_name;
- sd_bus_request_name;
- sd_bus_release_name;
- sd_bus_list_names;
- sd_bus_get_name_creds;
- sd_bus_get_name_machine_id;
- sd_bus_call_method;
- sd_bus_call_method_async;
- sd_bus_get_property;
- sd_bus_get_property_trivial;
- sd_bus_get_property_string;
- sd_bus_get_property_strv;
- sd_bus_set_property;
- sd_bus_reply_method_return;
- sd_bus_reply_method_error;
- sd_bus_reply_method_errorf;
- sd_bus_reply_method_errno;
- sd_bus_reply_method_errnof;
- sd_bus_emit_signal;
- sd_bus_emit_properties_changed_strv;
- sd_bus_emit_properties_changed;
- sd_bus_emit_interfaces_added_strv;
- sd_bus_emit_interfaces_added;
- sd_bus_emit_interfaces_removed_strv;
- sd_bus_emit_interfaces_removed;
- sd_bus_query_sender_creds;
- sd_bus_query_sender_privilege;
- sd_bus_creds_new_from_pid;
- sd_bus_creds_ref;
- sd_bus_creds_unref;
- sd_bus_creds_get_mask;
- sd_bus_creds_get_augmented_mask;
- sd_bus_creds_get_pid;
- sd_bus_creds_get_ppid;
- sd_bus_creds_get_tid;
- sd_bus_creds_get_uid;
- sd_bus_creds_get_euid;
- sd_bus_creds_get_suid;
- sd_bus_creds_get_fsuid;
- sd_bus_creds_get_gid;
- sd_bus_creds_get_egid;
- sd_bus_creds_get_sgid;
- sd_bus_creds_get_fsgid;
- sd_bus_creds_get_supplementary_gids;
- sd_bus_creds_get_comm;
- sd_bus_creds_get_tid_comm;
- sd_bus_creds_get_exe;
- sd_bus_creds_get_cmdline;
- sd_bus_creds_get_cgroup;
- sd_bus_creds_get_unit;
- sd_bus_creds_get_slice;
- sd_bus_creds_get_user_unit;
- sd_bus_creds_get_user_slice;
- sd_bus_creds_get_session;
- sd_bus_creds_get_owner_uid;
- sd_bus_creds_has_effective_cap;
- sd_bus_creds_has_permitted_cap;
- sd_bus_creds_has_inheritable_cap;
- sd_bus_creds_has_bounding_cap;
- sd_bus_creds_get_selinux_context;
- sd_bus_creds_get_audit_session_id;
- sd_bus_creds_get_audit_login_uid;
- sd_bus_creds_get_tty;
- sd_bus_creds_get_unique_name;
- sd_bus_creds_get_well_known_names;
- sd_bus_creds_get_description;
- sd_bus_error_free;
- sd_bus_error_set;
- sd_bus_error_setf;
- sd_bus_error_set_const;
- sd_bus_error_set_errno;
- sd_bus_error_set_errnof;
- sd_bus_error_set_errnofv;
- sd_bus_error_get_errno;
- sd_bus_error_copy;
- sd_bus_error_is_set;
- sd_bus_error_has_name;
- sd_bus_error_add_map;
- sd_bus_path_encode;
- sd_bus_path_decode;
- sd_bus_track_new;
- sd_bus_track_ref;
- sd_bus_track_unref;
- sd_bus_track_get_bus;
- sd_bus_track_get_userdata;
- sd_bus_track_set_userdata;
- sd_bus_track_add_sender;
- sd_bus_track_remove_sender;
- sd_bus_track_add_name;
- sd_bus_track_remove_name;
- sd_bus_track_count;
- sd_bus_track_contains;
- sd_bus_track_first;
- sd_bus_track_next;
-
- /* sd-event */
- sd_event_default;
- sd_event_new;
- sd_event_ref;
- sd_event_unref;
- sd_event_add_io;
- sd_event_add_time;
- sd_event_add_signal;
- sd_event_add_child;
- sd_event_add_defer;
- sd_event_add_post;
- sd_event_add_exit;
- sd_event_prepare;
- sd_event_wait;
- sd_event_dispatch;
- sd_event_run;
- sd_event_loop;
- sd_event_exit;
- sd_event_now;
- sd_event_get_fd;
- sd_event_get_state;
- sd_event_get_tid;
- sd_event_get_exit_code;
- sd_event_set_watchdog;
- sd_event_get_watchdog;
- sd_event_source_ref;
- sd_event_source_unref;
- sd_event_source_get_event;
- sd_event_source_get_userdata;
- sd_event_source_set_userdata;
- sd_event_source_set_description;
- sd_event_source_get_description;
- sd_event_source_set_prepare;
- sd_event_source_get_pending;
- sd_event_source_get_priority;
- sd_event_source_set_priority;
- sd_event_source_get_enabled;
- sd_event_source_set_enabled;
- sd_event_source_get_io_fd;
- sd_event_source_set_io_fd;
- sd_event_source_get_io_events;
- sd_event_source_set_io_events;
- sd_event_source_get_io_revents;
- sd_event_source_get_time;
- sd_event_source_set_time;
- sd_event_source_set_time_accuracy;
- sd_event_source_get_time_accuracy;
- sd_event_source_get_time_clock;
- sd_event_source_get_signal;
- sd_event_source_get_child_pid;
-} LIBSYSTEMD_220;
-
-m4_ifdef(`ENABLE_KDBUS',
-LIBSYSTEMD_FUTURE {
-global:
- /* sd-utf8 */
- sd_utf8_is_valid;
- sd_ascii_is_valid;
-
- /* sd-resolve */
- sd_resolve_default;
- sd_resolve_new;
- sd_resolve_ref;
- sd_resolve_unref;
- sd_resolve_get_fd;
- sd_resolve_get_events;
- sd_resolve_get_timeout;
- sd_resolve_process;
- sd_resolve_wait;
- sd_resolve_get_tid;
- sd_resolve_attach_event;
- sd_resolve_detach_event;
- sd_resolve_get_event;
- sd_resolve_getaddrinfo;
- sd_resolve_getnameinfo;
- sd_resolve_res_query;
- sd_resolve_res_search;
- sd_resolve_query_ref;
- sd_resolve_query_unref;
- sd_resolve_query_is_done;
- sd_resolve_query_get_userdata;
- sd_resolve_query_set_userdata;
- sd_resolve_query_get_resolve;
-
- /* sd-path */
- sd_path_home;
- sd_path_search;
-} LIBSYSTEMD_220;
-)
+++ /dev/null
-../../Makefile
\ No newline at end of file
/***
This file is part of systemd.
- Copyright 2014 David Herrmann
+ Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-bus.h"
-#include "bus-xml-policy.h"
-
-typedef struct Proxy Proxy;
-typedef struct ProxyActivation ProxyActivation;
-
-#define PROXY_ACTIVATIONS_MAX (16) /* max parallel activation requests */
-
-struct Proxy {
- sd_bus *local_bus;
- struct ucred local_creds;
- int local_in;
- int local_out;
-
- sd_bus *destination_bus;
-
- Set *owned_names;
- SharedPolicy *policy;
+#include <stdio.h>
- LIST_HEAD(ProxyActivation, activations);
- size_t n_activations;
-
- bool got_hello : 1;
- bool queue_overflow : 1;
- bool message_matched : 1;
- bool synthetic_matched : 1;
-};
+#include "sd-bus.h"
+#include "set.h"
-struct ProxyActivation {
- LIST_FIELDS(ProxyActivation, activations_by_proxy);
- Proxy *proxy;
- sd_bus_message *request;
- sd_bus_slot *slot;
+struct introspect {
+ FILE *f;
+ char *introspection;
+ size_t size;
+ bool trusted;
};
-int proxy_new(Proxy **out, int in_fd, int out_fd, const char *dest);
-Proxy *proxy_free(Proxy *p);
-
-int proxy_set_policy(Proxy *p, SharedPolicy *policy, char **configuration);
-int proxy_hello_policy(Proxy *p, uid_t original_uid);
-int proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error);
-int proxy_run(Proxy *p);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(Proxy*, proxy_free);
+int introspect_begin(struct introspect *i, bool trusted);
+int introspect_write_default_interfaces(struct introspect *i, bool object_manager);
+int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix);
+int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v);
+int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply);
+void introspect_free(struct introspect *i);
***/
#include "sd-bus.h"
-#include "bus-xml-policy.h"
-#include "proxy.h"
+#include "bus-internal.h"
-int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names);
+sd_bus_slot *bus_slot_allocate(sd_bus *bus, bool floating, BusSlotType type, size_t extra, void *userdata);
+
+void bus_slot_disconnect(sd_bus_slot *slot);
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <getopt.h>
-
-#include "strv.h"
-#include "util.h"
-#include "log.h"
-#include "build.h"
-#include "pager.h"
-#include "path-util.h"
-#include "set.h"
-
-#include "sd-bus.h"
-#include "bus-internal.h"
-#include "bus-util.h"
-#include "bus-dump.h"
-#include "bus-signature.h"
-#include "bus-type.h"
-#include "busctl-introspect.h"
-#include "terminal-util.h"
-
-static bool arg_no_pager = false;
-static bool arg_legend = true;
-static char *arg_address = NULL;
-static bool arg_unique = false;
-static bool arg_acquired = false;
-static bool arg_activatable = false;
-static bool arg_show_machine = false;
-static char **arg_matches = NULL;
-static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
-static char *arg_host = NULL;
-static bool arg_user = false;
-static size_t arg_snaplen = 4096;
-static bool arg_list = false;
-static bool arg_quiet = false;
-static bool arg_verbose = false;
-static bool arg_expect_reply = true;
-static bool arg_auto_start = true;
-static bool arg_allow_interactive_authorization = true;
-static bool arg_augment_creds = true;
-static usec_t arg_timeout = 0;
-
-static void pager_open_if_enabled(void) {
-
- /* Cache result before we open the pager */
- if (arg_no_pager)
- return;
-
- pager_open(false);
-}
-
-#define NAME_IS_ACQUIRED INT_TO_PTR(1)
-#define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
-
-static int list_bus_names(sd_bus *bus, char **argv) {
- _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
- _cleanup_free_ char **merged = NULL;
- _cleanup_hashmap_free_ Hashmap *names = NULL;
- char **i;
- int r;
- size_t max_i = 0;
- unsigned n = 0;
- void *v;
- char *k;
- Iterator iterator;
-
- assert(bus);
-
- if (!arg_unique && !arg_acquired && !arg_activatable)
- arg_unique = arg_acquired = arg_activatable = true;
-
- r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to list names: %m");
-
- pager_open_if_enabled();
-
- names = hashmap_new(&string_hash_ops);
- if (!names)
- return log_oom();
-
- STRV_FOREACH(i, acquired) {
- max_i = MAX(max_i, strlen(*i));
-
- r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
- if (r < 0)
- return log_error_errno(r, "Failed to add to hashmap: %m");
- }
-
- STRV_FOREACH(i, activatable) {
- max_i = MAX(max_i, strlen(*i));
-
- r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
- if (r < 0 && r != -EEXIST)
- return log_error_errno(r, "Failed to add to hashmap: %m");
- }
-
- merged = new(char*, hashmap_size(names) + 1);
- HASHMAP_FOREACH_KEY(v, k, names, iterator)
- merged[n++] = k;
-
- merged[n] = NULL;
- strv_sort(merged);
-
- if (arg_legend) {
- printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
- (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
-
- if (arg_show_machine)
- puts(" MACHINE");
- else
- putchar('\n');
- }
-
- STRV_FOREACH(i, merged) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
- sd_id128_t mid;
-
- if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) {
- /* Activatable */
-
- printf("%-*s", (int) max_i, *i);
- printf(" - - - (activatable) - - ");
- if (arg_show_machine)
- puts(" -");
- else
- putchar('\n');
- continue;
-
- }
-
- if (!arg_unique && (*i)[0] == ':')
- continue;
-
- if (!arg_acquired && (*i)[0] != ':')
- continue;
-
- printf("%-*s", (int) max_i, *i);
-
- r = sd_bus_get_name_creds(
- bus, *i,
- (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
- SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
- SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
- SD_BUS_CREDS_DESCRIPTION, &creds);
- if (r >= 0) {
- const char *unique, *session, *unit, *cn;
- pid_t pid;
- uid_t uid;
-
- r = sd_bus_creds_get_pid(creds, &pid);
- if (r >= 0) {
- const char *comm = NULL;
-
- sd_bus_creds_get_comm(creds, &comm);
-
- printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
- } else
- fputs(" - - ", stdout);
-
- r = sd_bus_creds_get_euid(creds, &uid);
- if (r >= 0) {
- _cleanup_free_ char *u = NULL;
-
- u = uid_to_name(uid);
- if (!u)
- return log_oom();
-
- if (strlen(u) > 16)
- u[16] = 0;
-
- printf(" %-16s", u);
- } else
- fputs(" - ", stdout);
-
- r = sd_bus_creds_get_unique_name(creds, &unique);
- if (r >= 0)
- printf(" %-13s", unique);
- else
- fputs(" - ", stdout);
-
- r = sd_bus_creds_get_unit(creds, &unit);
- if (r >= 0) {
- _cleanup_free_ char *e;
-
- e = ellipsize(unit, 25, 100);
- if (!e)
- return log_oom();
-
- printf(" %-25s", e);
- } else
- fputs(" - ", stdout);
-
- r = sd_bus_creds_get_session(creds, &session);
- if (r >= 0)
- printf(" %-10s", session);
- else
- fputs(" - ", stdout);
-
- r = sd_bus_creds_get_description(creds, &cn);
- if (r >= 0)
- printf(" %-19s", cn);
- else
- fputs(" - ", stdout);
-
- } else
- printf(" - - - - - - - ");
-
- if (arg_show_machine) {
- r = sd_bus_get_name_machine_id(bus, *i, &mid);
- if (r >= 0) {
- char m[SD_ID128_STRING_MAX];
- printf(" %s\n", sd_id128_to_string(mid, m));
- } else
- puts(" -");
- } else
- putchar('\n');
- }
-
- return 0;
-}
-
-static void print_subtree(const char *prefix, const char *path, char **l) {
- const char *vertical, *space;
- char **n;
-
- /* We assume the list is sorted. Let's first skip over the
- * entry we are looking at. */
- for (;;) {
- if (!*l)
- return;
-
- if (!streq(*l, path))
- break;
-
- l++;
- }
-
- vertical = strjoina(prefix, draw_special_char(DRAW_TREE_VERTICAL));
- space = strjoina(prefix, draw_special_char(DRAW_TREE_SPACE));
-
- for (;;) {
- bool has_more = false;
-
- if (!*l || !path_startswith(*l, path))
- break;
-
- n = l + 1;
- for (;;) {
- if (!*n || !path_startswith(*n, path))
- break;
-
- if (!path_startswith(*n, *l)) {
- has_more = true;
- break;
- }
-
- n++;
- }
-
- printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
-
- print_subtree(has_more ? vertical : space, *l, l);
- l = n;
- }
-}
-
-static void print_tree(const char *prefix, char **l) {
-
- pager_open_if_enabled();
-
- prefix = strempty(prefix);
-
- if (arg_list) {
- char **i;
-
- STRV_FOREACH(i, l)
- printf("%s%s\n", prefix, *i);
- return;
- }
-
- if (strv_isempty(l)) {
- printf("No objects discovered.\n");
- return;
- }
-
- if (streq(l[0], "/") && !l[1]) {
- printf("Only root object discovered.\n");
- return;
- }
-
- print_subtree(prefix, "/", l);
-}
-
-static int on_path(const char *path, void *userdata) {
- Set *paths = userdata;
- int r;
-
- assert(paths);
-
- r = set_put_strdup(paths, path);
- if (r < 0)
- return log_oom();
-
- return 0;
-}
-
-static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
- static const XMLIntrospectOps ops = {
- .on_path = on_path,
- };
-
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *xml;
- int r;
-
- r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
- if (r < 0) {
- if (many)
- printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
- else
- log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
- return r;
- }
-
- r = sd_bus_message_read(reply, "s", &xml);
- if (r < 0)
- return bus_log_parse_error(r);
-
- return parse_xml_introspect(path, xml, &ops, paths);
-}
-
-static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
- _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
- _cleanup_free_ char **l = NULL;
- char *m;
- int r;
-
- paths = set_new(&string_hash_ops);
- if (!paths)
- return log_oom();
-
- done = set_new(&string_hash_ops);
- if (!done)
- return log_oom();
-
- failed = set_new(&string_hash_ops);
- if (!failed)
- return log_oom();
-
- m = strdup("/");
- if (!m)
- return log_oom();
-
- r = set_put(paths, m);
- if (r < 0) {
- free(m);
- return log_oom();
- }
-
- for (;;) {
- _cleanup_free_ char *p = NULL;
- int q;
-
- p = set_steal_first(paths);
- if (!p)
- break;
-
- if (set_contains(done, p) ||
- set_contains(failed, p))
- continue;
-
- q = find_nodes(bus, service, p, paths, many);
- if (q < 0) {
- if (r >= 0)
- r = q;
-
- q = set_put(failed, p);
- } else
- q = set_put(done, p);
-
- if (q < 0)
- return log_oom();
-
- assert(q != 0);
- p = NULL;
- }
-
- pager_open_if_enabled();
-
- l = set_get_strv(done);
- if (!l)
- return log_oom();
-
- strv_sort(l);
- print_tree(prefix, l);
-
- fflush(stdout);
-
- return r;
-}
-
-static int tree(sd_bus *bus, char **argv) {
- char **i;
- int r = 0;
-
- if (!arg_unique && !arg_acquired)
- arg_acquired = true;
-
- if (strv_length(argv) <= 1) {
- _cleanup_strv_free_ char **names = NULL;
- bool not_first = false;
-
- r = sd_bus_list_names(bus, &names, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to get name list: %m");
-
- pager_open_if_enabled();
-
- STRV_FOREACH(i, names) {
- int q;
-
- if (!arg_unique && (*i)[0] == ':')
- continue;
-
- if (!arg_acquired && (*i)[0] == ':')
- continue;
-
- if (not_first)
- printf("\n");
-
- printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
-
- q = tree_one(bus, *i, NULL, true);
- if (q < 0 && r >= 0)
- r = q;
-
- not_first = true;
- }
- } else {
- STRV_FOREACH(i, argv+1) {
- int q;
-
- if (i > argv+1)
- printf("\n");
-
- if (argv[2]) {
- pager_open_if_enabled();
- printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
- }
-
- q = tree_one(bus, *i, NULL, !!argv[2]);
- if (q < 0 && r >= 0)
- r = q;
- }
- }
-
- return r;
-}
-
-static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
- int r;
-
- for (;;) {
- const char *contents = NULL;
- char type;
- union {
- uint8_t u8;
- uint16_t u16;
- int16_t s16;
- uint32_t u32;
- int32_t s32;
- uint64_t u64;
- int64_t s64;
- double d64;
- const char *string;
- int i;
- } basic;
-
- r = sd_bus_message_peek_type(m, &type, &contents);
- if (r <= 0)
- return r;
-
- if (bus_type_is_container(type) > 0) {
-
- r = sd_bus_message_enter_container(m, type, contents);
- if (r < 0)
- return r;
-
- if (type == SD_BUS_TYPE_ARRAY) {
- unsigned n = 0;
-
- /* count array entries */
- for (;;) {
-
- r = sd_bus_message_skip(m, contents);
- if (r < 0)
- return r;
- if (r == 0)
- break;
-
- n++;
- }
-
- r = sd_bus_message_rewind(m, false);
- if (r < 0)
- return r;
-
- if (needs_space)
- fputc(' ', f);
-
- fprintf(f, "%u", n);
- } else if (type == SD_BUS_TYPE_VARIANT) {
-
- if (needs_space)
- fputc(' ', f);
-
- fprintf(f, "%s", contents);
- }
-
- r = format_cmdline(m, f, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT));
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(m);
- if (r < 0)
- return r;
-
- continue;
- }
-
- r = sd_bus_message_read_basic(m, type, &basic);
- if (r < 0)
- return r;
-
- if (needs_space)
- fputc(' ', f);
-
- switch (type) {
- case SD_BUS_TYPE_BYTE:
- fprintf(f, "%u", basic.u8);
- break;
-
- case SD_BUS_TYPE_BOOLEAN:
- fputs(true_false(basic.i), f);
- break;
-
- case SD_BUS_TYPE_INT16:
- fprintf(f, "%i", basic.s16);
- break;
-
- case SD_BUS_TYPE_UINT16:
- fprintf(f, "%u", basic.u16);
- break;
-
- case SD_BUS_TYPE_INT32:
- fprintf(f, "%i", basic.s32);
- break;
-
- case SD_BUS_TYPE_UINT32:
- fprintf(f, "%u", basic.u32);
- break;
-
- case SD_BUS_TYPE_INT64:
- fprintf(f, "%" PRIi64, basic.s64);
- break;
-
- case SD_BUS_TYPE_UINT64:
- fprintf(f, "%" PRIu64, basic.u64);
- break;
-
- case SD_BUS_TYPE_DOUBLE:
- fprintf(f, "%g", basic.d64);
- break;
-
- case SD_BUS_TYPE_STRING:
- case SD_BUS_TYPE_OBJECT_PATH:
- case SD_BUS_TYPE_SIGNATURE: {
- _cleanup_free_ char *b = NULL;
-
- b = cescape(basic.string);
- if (!b)
- return -ENOMEM;
-
- fprintf(f, "\"%s\"", b);
- break;
- }
-
- case SD_BUS_TYPE_UNIX_FD:
- fprintf(f, "%i", basic.i);
- break;
-
- default:
- assert_not_reached("Unknown basic type.");
- }
-
- needs_space = true;
- }
-}
-
-typedef struct Member {
- const char *type;
- char *interface;
- char *name;
- char *signature;
- char *result;
- char *value;
- bool writable;
- uint64_t flags;
-} Member;
-
-static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
- const Member *m = p;
- unsigned long ul;
-
- assert(m);
- assert(m->type);
-
- ul = string_hash_func(m->type, hash_key);
-
- if (m->name)
- ul ^= string_hash_func(m->name, hash_key);
-
- if (m->interface)
- ul ^= string_hash_func(m->interface, hash_key);
-
- return ul;
-}
-
-static int member_compare_func(const void *a, const void *b) {
- const Member *x = a, *y = b;
- int d;
-
- assert(x);
- assert(y);
- assert(x->type);
- assert(y->type);
-
- if (!x->interface && y->interface)
- return -1;
- if (x->interface && !y->interface)
- return 1;
- if (x->interface && y->interface) {
- d = strcmp(x->interface, y->interface);
- if (d != 0)
- return d;
- }
-
- d = strcmp(x->type, y->type);
- if (d != 0)
- return d;
-
- if (!x->name && y->name)
- return -1;
- if (x->name && !y->name)
- return 1;
- if (x->name && y->name)
- return strcmp(x->name, y->name);
-
- return 0;
-}
-
-static int member_compare_funcp(const void *a, const void *b) {
- const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
-
- return member_compare_func(*x, *y);
-}
-
-static void member_free(Member *m) {
- if (!m)
- return;
-
- free(m->interface);
- free(m->name);
- free(m->signature);
- free(m->result);
- free(m->value);
- free(m);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
-
-static void member_set_free(Set *s) {
- Member *m;
-
- while ((m = set_steal_first(s)))
- member_free(m);
-
- set_free(s);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
-
-static int on_interface(const char *interface, uint64_t flags, void *userdata) {
- _cleanup_(member_freep) Member *m;
- Set *members = userdata;
- int r;
-
- assert(interface);
- assert(members);
-
- m = new0(Member, 1);
- if (!m)
- return log_oom();
-
- m->type = "interface";
- m->flags = flags;
-
- r = free_and_strdup(&m->interface, interface);
- if (r < 0)
- return log_oom();
-
- r = set_put(members, m);
- if (r <= 0) {
- log_error("Duplicate interface");
- return -EINVAL;
- }
-
- m = NULL;
- return 0;
-}
-
-static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
- _cleanup_(member_freep) Member *m;
- Set *members = userdata;
- int r;
-
- assert(interface);
- assert(name);
-
- m = new0(Member, 1);
- if (!m)
- return log_oom();
-
- m->type = "method";
- m->flags = flags;
-
- r = free_and_strdup(&m->interface, interface);
- if (r < 0)
- return log_oom();
-
- r = free_and_strdup(&m->name, name);
- if (r < 0)
- return log_oom();
-
- r = free_and_strdup(&m->signature, signature);
- if (r < 0)
- return log_oom();
-
- r = free_and_strdup(&m->result, result);
- if (r < 0)
- return log_oom();
-
- r = set_put(members, m);
- if (r <= 0) {
- log_error("Duplicate method");
- return -EINVAL;
- }
-
- m = NULL;
- return 0;
-}
-
-static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
- _cleanup_(member_freep) Member *m;
- Set *members = userdata;
- int r;
-
- assert(interface);
- assert(name);
-
- m = new0(Member, 1);
- if (!m)
- return log_oom();
-
- m->type = "signal";
- m->flags = flags;
-
- r = free_and_strdup(&m->interface, interface);
- if (r < 0)
- return log_oom();
-
- r = free_and_strdup(&m->name, name);
- if (r < 0)
- return log_oom();
-
- r = free_and_strdup(&m->signature, signature);
- if (r < 0)
- return log_oom();
-
- r = set_put(members, m);
- if (r <= 0) {
- log_error("Duplicate signal");
- return -EINVAL;
- }
-
- m = NULL;
- return 0;
-}
-
-static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
- _cleanup_(member_freep) Member *m;
- Set *members = userdata;
- int r;
-
- assert(interface);
- assert(name);
-
- m = new0(Member, 1);
- if (!m)
- return log_oom();
-
- m->type = "property";
- m->flags = flags;
- m->writable = writable;
-
- r = free_and_strdup(&m->interface, interface);
- if (r < 0)
- return log_oom();
-
- r = free_and_strdup(&m->name, name);
- if (r < 0)
- return log_oom();
-
- r = free_and_strdup(&m->signature, signature);
- if (r < 0)
- return log_oom();
-
- r = set_put(members, m);
- if (r <= 0) {
- log_error("Duplicate property");
- return -EINVAL;
- }
-
- m = NULL;
- return 0;
-}
-
-static const char *strdash(const char *x) {
- return isempty(x) ? "-" : x;
-}
-
-static int introspect(sd_bus *bus, char **argv) {
- static const struct hash_ops member_hash_ops = {
- .hash = member_hash_func,
- .compare = member_compare_func,
- };
-
- static const XMLIntrospectOps ops = {
- .on_interface = on_interface,
- .on_method = on_method,
- .on_signal = on_signal,
- .on_property = on_property,
- };
-
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(member_set_freep) Set *members = NULL;
- Iterator i;
- Member *m;
- const char *xml;
- int r;
- unsigned name_width, type_width, signature_width, result_width;
- Member **sorted = NULL;
- unsigned k = 0, j, n_args;
-
- n_args = strv_length(argv);
- if (n_args < 3) {
- log_error("Requires service and object path argument.");
- return -EINVAL;
- }
-
- if (n_args > 4) {
- log_error("Too many arguments.");
- return -EINVAL;
- }
-
- members = set_new(&member_hash_ops);
- if (!members)
- return log_oom();
-
- r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
- if (r < 0) {
- log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
- return r;
- }
-
- r = sd_bus_message_read(reply, "s", &xml);
- if (r < 0)
- return bus_log_parse_error(r);
-
- /* First, get list of all properties */
- r = parse_xml_introspect(argv[2], xml, &ops, members);
- if (r < 0)
- return r;
-
- /* Second, find the current values for them */
- SET_FOREACH(m, members, i) {
-
- if (!streq(m->type, "property"))
- continue;
-
- if (m->value)
- continue;
-
- if (argv[3] && !streq(argv[3], m->interface))
- continue;
-
- r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
- if (r < 0) {
- log_error("%s", bus_error_message(&error, r));
- return r;
- }
-
- r = sd_bus_message_enter_container(reply, 'a', "{sv}");
- if (r < 0)
- return bus_log_parse_error(r);
-
- for (;;) {
- Member *z;
- _cleanup_free_ char *buf = NULL;
- _cleanup_fclose_ FILE *mf = NULL;
- size_t sz = 0;
- const char *name;
-
- r = sd_bus_message_enter_container(reply, 'e', "sv");
- if (r < 0)
- return bus_log_parse_error(r);
-
- if (r == 0)
- break;
-
- r = sd_bus_message_read(reply, "s", &name);
- if (r < 0)
- return bus_log_parse_error(r);
-
- r = sd_bus_message_enter_container(reply, 'v', NULL);
- if (r < 0)
- return bus_log_parse_error(r);
-
- mf = open_memstream(&buf, &sz);
- if (!mf)
- return log_oom();
-
- r = format_cmdline(reply, mf, false);
- if (r < 0)
- return bus_log_parse_error(r);
-
- fclose(mf);
- mf = NULL;
-
- z = set_get(members, &((Member) {
- .type = "property",
- .interface = m->interface,
- .name = (char*) name }));
- if (z) {
- free(z->value);
- z->value = buf;
- buf = NULL;
- }
-
- r = sd_bus_message_exit_container(reply);
- if (r < 0)
- return bus_log_parse_error(r);
-
- r = sd_bus_message_exit_container(reply);
- if (r < 0)
- return bus_log_parse_error(r);
- }
-
- r = sd_bus_message_exit_container(reply);
- if (r < 0)
- return bus_log_parse_error(r);
- }
-
- pager_open_if_enabled();
-
- name_width = strlen("NAME");
- type_width = strlen("TYPE");
- signature_width = strlen("SIGNATURE");
- result_width = strlen("RESULT/VALUE");
-
- sorted = newa(Member*, set_size(members));
-
- SET_FOREACH(m, members, i) {
-
- if (argv[3] && !streq(argv[3], m->interface))
- continue;
-
- if (m->interface)
- name_width = MAX(name_width, strlen(m->interface));
- if (m->name)
- name_width = MAX(name_width, strlen(m->name) + 1);
- if (m->type)
- type_width = MAX(type_width, strlen(m->type));
- if (m->signature)
- signature_width = MAX(signature_width, strlen(m->signature));
- if (m->result)
- result_width = MAX(result_width, strlen(m->result));
- if (m->value)
- result_width = MAX(result_width, strlen(m->value));
-
- sorted[k++] = m;
- }
-
- if (result_width > 40)
- result_width = 40;
-
- qsort(sorted, k, sizeof(Member*), member_compare_funcp);
-
- if (arg_legend) {
- printf("%-*s %-*s %-*s %-*s %s\n",
- (int) name_width, "NAME",
- (int) type_width, "TYPE",
- (int) signature_width, "SIGNATURE",
- (int) result_width, "RESULT/VALUE",
- "FLAGS");
- }
-
- for (j = 0; j < k; j++) {
- _cleanup_free_ char *ellipsized = NULL;
- const char *rv;
- bool is_interface;
-
- m = sorted[j];
-
- if (argv[3] && !streq(argv[3], m->interface))
- continue;
-
- is_interface = streq(m->type, "interface");
-
- if (argv[3] && is_interface)
- continue;
-
- if (m->value) {
- ellipsized = ellipsize(m->value, result_width, 100);
- if (!ellipsized)
- return log_oom();
-
- rv = ellipsized;
- } else
- rv = strdash(m->result);
-
- printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
- is_interface ? ansi_highlight() : "",
- is_interface ? "" : ".",
- - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
- is_interface ? ansi_highlight_off() : "",
- (int) type_width, strdash(m->type),
- (int) signature_width, strdash(m->signature),
- (int) result_width, rv,
- (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
- (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
- (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
- (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
- (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
- m->writable ? " writable" : "");
- }
-
- return 0;
-}
-
-static int message_dump(sd_bus_message *m, FILE *f) {
- return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
-}
-
-static int message_pcap(sd_bus_message *m, FILE *f) {
- return bus_message_pcap_frame(m, arg_snaplen, f);
-}
-
-static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
- bool added_something = false;
- char **i;
- int r;
-
- STRV_FOREACH(i, argv+1) {
- _cleanup_free_ char *m = NULL;
-
- if (!service_name_is_valid(*i)) {
- log_error("Invalid service name '%s'", *i);
- return -EINVAL;
- }
-
- m = strjoin("sender='", *i, "'", NULL);
- if (!m)
- return log_oom();
-
- r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
-
- added_something = true;
- }
-
- STRV_FOREACH(i, arg_matches) {
- r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
-
- added_something = true;
- }
-
- if (!added_something) {
- r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
- }
-
- log_info("Monitoring bus message stream.");
-
- for (;;) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-
- r = sd_bus_process(bus, &m);
- if (r < 0)
- return log_error_errno(r, "Failed to process bus: %m");
-
- if (m) {
- dump(m, stdout);
- fflush(stdout);
-
- if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
- log_info("Connection terminated, exiting.");
- return 0;
- }
-
- continue;
- }
-
- if (r > 0)
- continue;
-
- r = sd_bus_wait(bus, (uint64_t) -1);
- if (r < 0)
- return log_error_errno(r, "Failed to wait for bus: %m");
- }
-}
-
-static int capture(sd_bus *bus, char *argv[]) {
- int r;
-
- if (isatty(fileno(stdout)) > 0) {
- log_error("Refusing to write message data to console, please redirect output to a file.");
- return -EINVAL;
- }
-
- bus_pcap_header(arg_snaplen, stdout);
-
- r = monitor(bus, argv, message_pcap);
- if (r < 0)
- return r;
-
- if (ferror(stdout)) {
- log_error("Couldn't write capture file.");
- return -EIO;
- }
-
- return r;
-}
-
-static int status(sd_bus *bus, char *argv[]) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
- pid_t pid;
- int r;
-
- assert(bus);
-
- if (strv_length(argv) > 2) {
- log_error("Expects no or one argument.");
- return -EINVAL;
- }
-
- if (argv[1]) {
- r = parse_pid(argv[1], &pid);
- if (r < 0)
- r = sd_bus_get_name_creds(
- bus,
- argv[1],
- (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
- &creds);
- else
- r = sd_bus_creds_new_from_pid(
- &creds,
- pid,
- _SD_BUS_CREDS_ALL);
- } else {
- const char *scope, *address;
- sd_id128_t bus_id;
-
- r = sd_bus_get_address(bus, &address);
- if (r >= 0)
- printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_highlight_off());
-
- r = sd_bus_get_scope(bus, &scope);
- if (r >= 0)
- printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off());
-
- r = sd_bus_get_bus_id(bus, &bus_id);
- if (r >= 0)
- printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off());
-
- r = sd_bus_get_owner_creds(
- bus,
- (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
- &creds);
- }
-
- if (r < 0)
- return log_error_errno(r, "Failed to get credentials: %m");
-
- bus_creds_dump(creds, NULL, false);
- return 0;
-}
-
-static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
- char **p;
- int r;
-
- assert(m);
- assert(signature);
- assert(x);
-
- p = *x;
-
- for (;;) {
- const char *v;
- char t;
-
- t = *signature;
- v = *p;
-
- if (t == 0)
- break;
- if (!v) {
- log_error("Too few parameters for signature.");
- return -EINVAL;
- }
-
- signature++;
- p++;
-
- switch (t) {
-
- case SD_BUS_TYPE_BOOLEAN:
-
- r = parse_boolean(v);
- if (r < 0) {
- log_error("Failed to parse as boolean: %s", v);
- return r;
- }
-
- r = sd_bus_message_append_basic(m, t, &r);
- break;
-
- case SD_BUS_TYPE_BYTE: {
- uint8_t z;
-
- r = safe_atou8(v, &z);
- if (r < 0) {
- log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
- return r;
- }
-
- r = sd_bus_message_append_basic(m, t, &z);
- break;
- }
-
- case SD_BUS_TYPE_INT16: {
- int16_t z;
-
- r = safe_atoi16(v, &z);
- if (r < 0) {
- log_error("Failed to parse as signed 16bit integer: %s", v);
- return r;
- }
-
- r = sd_bus_message_append_basic(m, t, &z);
- break;
- }
-
- case SD_BUS_TYPE_UINT16: {
- uint16_t z;
-
- r = safe_atou16(v, &z);
- if (r < 0) {
- log_error("Failed to parse as unsigned 16bit integer: %s", v);
- return r;
- }
-
- r = sd_bus_message_append_basic(m, t, &z);
- break;
- }
-
- case SD_BUS_TYPE_INT32: {
- int32_t z;
-
- r = safe_atoi32(v, &z);
- if (r < 0) {
- log_error("Failed to parse as signed 32bit integer: %s", v);
- return r;
- }
-
- r = sd_bus_message_append_basic(m, t, &z);
- break;
- }
-
- case SD_BUS_TYPE_UINT32: {
- uint32_t z;
-
- r = safe_atou32(v, &z);
- if (r < 0) {
- log_error("Failed to parse as unsigned 32bit integer: %s", v);
- return r;
- }
-
- r = sd_bus_message_append_basic(m, t, &z);
- break;
- }
-
- case SD_BUS_TYPE_INT64: {
- int64_t z;
-
- r = safe_atoi64(v, &z);
- if (r < 0) {
- log_error("Failed to parse as signed 64bit integer: %s", v);
- return r;
- }
-
- r = sd_bus_message_append_basic(m, t, &z);
- break;
- }
-
- case SD_BUS_TYPE_UINT64: {
- uint64_t z;
-
- r = safe_atou64(v, &z);
- if (r < 0) {
- log_error("Failed to parse as unsigned 64bit integer: %s", v);
- return r;
- }
-
- r = sd_bus_message_append_basic(m, t, &z);
- break;
- }
-
-
- case SD_BUS_TYPE_DOUBLE: {
- double z;
-
- r = safe_atod(v, &z);
- if (r < 0) {
- log_error("Failed to parse as double precision floating point: %s", v);
- return r;
- }
-
- r = sd_bus_message_append_basic(m, t, &z);
- break;
- }
-
- case SD_BUS_TYPE_STRING:
- case SD_BUS_TYPE_OBJECT_PATH:
- case SD_BUS_TYPE_SIGNATURE:
-
- r = sd_bus_message_append_basic(m, t, v);
- break;
-
- case SD_BUS_TYPE_ARRAY: {
- uint32_t n;
- size_t k;
-
- r = safe_atou32(v, &n);
- if (r < 0) {
- log_error("Failed to parse number of array entries: %s", v);
- return r;
- }
-
- r = signature_element_length(signature, &k);
- if (r < 0) {
- log_error("Invalid array signature.");
- return r;
- }
-
- {
- unsigned i;
- char s[k + 1];
- memcpy(s, signature, k);
- s[k] = 0;
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
- if (r < 0)
- return bus_log_create_error(r);
-
- for (i = 0; i < n; i++) {
- r = message_append_cmdline(m, s, &p);
- if (r < 0)
- return r;
- }
- }
-
- signature += k;
-
- r = sd_bus_message_close_container(m);
- break;
- }
-
- case SD_BUS_TYPE_VARIANT:
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = message_append_cmdline(m, v, &p);
- if (r < 0)
- return r;
-
- r = sd_bus_message_close_container(m);
- break;
-
- case SD_BUS_TYPE_STRUCT_BEGIN:
- case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
- size_t k;
-
- signature--;
- p--;
-
- r = signature_element_length(signature, &k);
- if (r < 0) {
- log_error("Invalid struct/dict entry signature.");
- return r;
- }
-
- {
- char s[k-1];
- memcpy(s, signature + 1, k - 2);
- s[k - 2] = 0;
-
- r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = message_append_cmdline(m, s, &p);
- if (r < 0)
- return r;
- }
-
- signature += k;
-
- r = sd_bus_message_close_container(m);
- break;
- }
-
- case SD_BUS_TYPE_UNIX_FD:
- log_error("UNIX file descriptor not supported as type.");
- return -EINVAL;
-
- default:
- log_error("Unknown signature type %c.", t);
- return -EINVAL;
- }
-
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- *x = p;
- return 0;
-}
-
-static int call(sd_bus *bus, char *argv[]) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
- int r;
-
- assert(bus);
-
- if (strv_length(argv) < 5) {
- log_error("Expects at least four arguments.");
- return -EINVAL;
- }
-
- r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_set_auto_start(m, arg_auto_start);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
- if (r < 0)
- return bus_log_create_error(r);
-
- if (!isempty(argv[5])) {
- char **p;
-
- p = argv+6;
-
- r = message_append_cmdline(m, argv[5], &p);
- if (r < 0)
- return r;
-
- if (*p) {
- log_error("Too many parameters for signature.");
- return -EINVAL;
- }
- }
-
- if (!arg_expect_reply) {
- r = sd_bus_send(bus, m, NULL);
- if (r < 0) {
- log_error("Failed to send message.");
- return r;
- }
-
- return 0;
- }
-
- r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
- if (r < 0) {
- log_error("%s", bus_error_message(&error, r));
- return r;
- }
-
- r = sd_bus_message_is_empty(reply);
- if (r < 0)
- return bus_log_parse_error(r);
-
- if (r == 0 && !arg_quiet) {
-
- if (arg_verbose) {
- pager_open_if_enabled();
-
- r = bus_message_dump(reply, stdout, 0);
- if (r < 0)
- return r;
- } else {
-
- fputs(sd_bus_message_get_signature(reply, true), stdout);
- fputc(' ', stdout);
-
- r = format_cmdline(reply, stdout, false);
- if (r < 0)
- return bus_log_parse_error(r);
-
- fputc('\n', stdout);
- }
- }
-
- return 0;
-}
-
-static int get_property(sd_bus *bus, char *argv[]) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- unsigned n;
- char **i;
- int r;
-
- assert(bus);
-
- n = strv_length(argv);
- if (n < 5) {
- log_error("Expects at least four arguments.");
- return -EINVAL;
- }
-
- STRV_FOREACH(i, argv + 4) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- const char *contents = NULL;
- char type;
-
- r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
- if (r < 0) {
- log_error("%s", bus_error_message(&error, r));
- return r;
- }
-
- r = sd_bus_message_peek_type(reply, &type, &contents);
- if (r < 0)
- return bus_log_parse_error(r);
-
- r = sd_bus_message_enter_container(reply, 'v', contents);
- if (r < 0)
- return bus_log_parse_error(r);
-
- if (arg_verbose) {
- pager_open_if_enabled();
-
- r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
- if (r < 0)
- return r;
- } else {
- fputs(contents, stdout);
- fputc(' ', stdout);
-
- r = format_cmdline(reply, stdout, false);
- if (r < 0)
- return bus_log_parse_error(r);
-
- fputc('\n', stdout);
- }
-
- r = sd_bus_message_exit_container(reply);
- if (r < 0)
- return bus_log_parse_error(r);
- }
-
- return 0;
-}
-
-static int set_property(sd_bus *bus, char *argv[]) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- unsigned n;
- char **p;
- int r;
-
- assert(bus);
-
- n = strv_length(argv);
- if (n < 6) {
- log_error("Expects at least five arguments.");
- return -EINVAL;
- }
-
- r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'v', argv[5]);
- if (r < 0)
- return bus_log_create_error(r);
-
- p = argv+6;
- r = message_append_cmdline(m, argv[5], &p);
- if (r < 0)
- return r;
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- if (*p) {
- log_error("Too many parameters for signature.");
- return -EINVAL;
- }
-
- r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
- if (r < 0) {
- log_error("%s", bus_error_message(&error, r));
- return r;
- }
-
- return 0;
-}
-
-static int help(void) {
- printf("%s [OPTIONS...] {COMMAND} ...\n\n"
- "Introspect the bus.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " --no-pager Do not pipe output into a pager\n"
- " --no-legend Do not show the headers and footers\n"
- " --system Connect to system bus\n"
- " --user Connect to user bus\n"
- " -H --host=[USER@]HOST Operate on remote host\n"
- " -M --machine=CONTAINER Operate on local container\n"
- " --address=ADDRESS Connect to bus specified by address\n"
- " --show-machine Show machine ID column in list\n"
- " --unique Only show unique names\n"
- " --acquired Only show acquired names\n"
- " --activatable Only show activatable names\n"
- " --match=MATCH Only show matching messages\n"
- " --list Don't show tree, but simple object path list\n"
- " --quiet Don't show method call reply\n"
- " --verbose Show result values in long format\n"
- " --expect-reply=BOOL Expect a method call reply\n"
- " --auto-start=BOOL Auto-start destination service\n"
- " --allow-interactive-authorization=BOOL\n"
- " Allow interactive authorization for operation\n"
- " --timeout=SECS Maximum time to wait for method call completion\n"
- " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
- "Commands:\n"
- " list List bus names\n"
- " status [SERVICE] Show bus service, process or bus owner credentials\n"
- " monitor [SERVICE...] Show bus traffic\n"
- " capture [SERVICE...] Capture bus traffic as pcap\n"
- " tree [SERVICE...] Show object tree of service\n"
- " introspect SERVICE OBJECT [INTERFACE]\n"
- " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
- " Call a method\n"
- " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
- " Get property value\n"
- " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
- " Set property value\n"
- " help Show this help\n"
- , program_invocation_short_name);
-
- return 0;
-}
-
-static int parse_argv(int argc, char *argv[]) {
-
- enum {
- ARG_VERSION = 0x100,
- ARG_NO_PAGER,
- ARG_NO_LEGEND,
- ARG_SYSTEM,
- ARG_USER,
- ARG_ADDRESS,
- ARG_MATCH,
- ARG_SHOW_MACHINE,
- ARG_UNIQUE,
- ARG_ACQUIRED,
- ARG_ACTIVATABLE,
- ARG_SIZE,
- ARG_LIST,
- ARG_VERBOSE,
- ARG_EXPECT_REPLY,
- ARG_AUTO_START,
- ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
- ARG_TIMEOUT,
- ARG_AUGMENT_CREDS,
- };
-
- static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
- { "system", no_argument, NULL, ARG_SYSTEM },
- { "user", no_argument, NULL, ARG_USER },
- { "address", required_argument, NULL, ARG_ADDRESS },
- { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
- { "unique", no_argument, NULL, ARG_UNIQUE },
- { "acquired", no_argument, NULL, ARG_ACQUIRED },
- { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
- { "match", required_argument, NULL, ARG_MATCH },
- { "host", required_argument, NULL, 'H' },
- { "machine", required_argument, NULL, 'M' },
- { "size", required_argument, NULL, ARG_SIZE },
- { "list", no_argument, NULL, ARG_LIST },
- { "quiet", no_argument, NULL, 'q' },
- { "verbose", no_argument, NULL, ARG_VERBOSE },
- { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
- { "auto-start", required_argument, NULL, ARG_AUTO_START },
- { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
- { "timeout", required_argument, NULL, ARG_TIMEOUT },
- { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
- {},
- };
-
- int c, r;
-
- assert(argc >= 0);
- assert(argv);
-
- while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
-
- switch (c) {
-
- case 'h':
- return help();
-
- case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
-
- case ARG_NO_PAGER:
- arg_no_pager = true;
- break;
-
- case ARG_NO_LEGEND:
- arg_legend = false;
- break;
-
- case ARG_USER:
- arg_user = true;
- break;
-
- case ARG_SYSTEM:
- arg_user = false;
- break;
-
- case ARG_ADDRESS:
- arg_address = optarg;
- break;
-
- case ARG_SHOW_MACHINE:
- arg_show_machine = true;
- break;
-
- case ARG_UNIQUE:
- arg_unique = true;
- break;
-
- case ARG_ACQUIRED:
- arg_acquired = true;
- break;
-
- case ARG_ACTIVATABLE:
- arg_activatable = true;
- break;
-
- case ARG_MATCH:
- if (strv_extend(&arg_matches, optarg) < 0)
- return log_oom();
- break;
-
- case ARG_SIZE: {
- off_t o;
-
- r = parse_size(optarg, 0, &o);
- if (r < 0) {
- log_error("Failed to parse size: %s", optarg);
- return r;
- }
-
- if ((off_t) (size_t) o != o) {
- log_error("Size out of range.");
- return -E2BIG;
- }
-
- arg_snaplen = (size_t) o;
- break;
- }
-
- case ARG_LIST:
- arg_list = true;
- break;
-
- case 'H':
- arg_transport = BUS_TRANSPORT_REMOTE;
- arg_host = optarg;
- break;
-
- case 'M':
- arg_transport = BUS_TRANSPORT_MACHINE;
- arg_host = optarg;
- break;
-
- case 'q':
- arg_quiet = true;
- break;
-
- case ARG_VERBOSE:
- arg_verbose = true;
- break;
-
- case ARG_EXPECT_REPLY:
- r = parse_boolean(optarg);
- if (r < 0) {
- log_error("Failed to parse --expect-reply= parameter.");
- return r;
- }
-
- arg_expect_reply = !!r;
- break;
-
-
- case ARG_AUTO_START:
- r = parse_boolean(optarg);
- if (r < 0) {
- log_error("Failed to parse --auto-start= parameter.");
- return r;
- }
-
- arg_auto_start = !!r;
- break;
-
-
- case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
- r = parse_boolean(optarg);
- if (r < 0) {
- log_error("Failed to parse --allow-interactive-authorization= parameter.");
- return r;
- }
-
- arg_allow_interactive_authorization = !!r;
- break;
-
- case ARG_TIMEOUT:
- r = parse_sec(optarg, &arg_timeout);
- if (r < 0) {
- log_error("Failed to parse --timeout= parameter.");
- return r;
- }
-
- break;
-
- case ARG_AUGMENT_CREDS:
- r = parse_boolean(optarg);
- if (r < 0) {
- log_error("Failed to parse --augment-creds= parameter.");
- return r;
- }
-
- arg_augment_creds = !!r;
- break;
-
- case '?':
- return -EINVAL;
-
- default:
- assert_not_reached("Unhandled option");
- }
-
- return 1;
-}
-
-static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
- assert(bus);
-
- if (optind >= argc ||
- streq(argv[optind], "list"))
- return list_bus_names(bus, argv + optind);
-
- if (streq(argv[optind], "monitor"))
- return monitor(bus, argv + optind, message_dump);
-
- if (streq(argv[optind], "capture"))
- return capture(bus, argv + optind);
-
- if (streq(argv[optind], "status"))
- return status(bus, argv + optind);
-
- if (streq(argv[optind], "tree"))
- return tree(bus, argv + optind);
-
- if (streq(argv[optind], "introspect"))
- return introspect(bus, argv + optind);
-
- if (streq(argv[optind], "call"))
- return call(bus, argv + optind);
-
- if (streq(argv[optind], "get-property"))
- return get_property(bus, argv + optind);
-
- if (streq(argv[optind], "set-property"))
- return set_property(bus, argv + optind);
-
- if (streq(argv[optind], "help"))
- return help();
-
- log_error("Unknown command '%s'", argv[optind]);
- return -EINVAL;
-}
-
-int main(int argc, char *argv[]) {
- _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
- int r;
-
- log_parse_environment();
- log_open();
-
- r = parse_argv(argc, argv);
- if (r <= 0)
- goto finish;
-
- r = sd_bus_new(&bus);
- if (r < 0) {
- log_error_errno(r, "Failed to allocate bus: %m");
- goto finish;
- }
-
- if (streq_ptr(argv[optind], "monitor") ||
- streq_ptr(argv[optind], "capture")) {
-
- r = sd_bus_set_monitor(bus, true);
- if (r < 0) {
- log_error_errno(r, "Failed to set monitor mode: %m");
- goto finish;
- }
-
- r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
- if (r < 0) {
- log_error_errno(r, "Failed to enable credentials: %m");
- goto finish;
- }
-
- r = sd_bus_negotiate_timestamp(bus, true);
- if (r < 0) {
- log_error_errno(r, "Failed to enable timestamps: %m");
- goto finish;
- }
-
- r = sd_bus_negotiate_fds(bus, true);
- if (r < 0) {
- log_error_errno(r, "Failed to enable fds: %m");
- goto finish;
- }
- }
-
- if (arg_address)
- r = sd_bus_set_address(bus, arg_address);
- else {
- r = sd_bus_set_bus_client(bus, true);
- if (r < 0) {
- log_error_errno(r, "Failed to set bus client: %m");
- goto finish;
- }
-
- switch (arg_transport) {
-
- case BUS_TRANSPORT_LOCAL:
- if (arg_user) {
- bus->is_user = true;
- r = bus_set_address_user(bus);
- } else {
- bus->is_system = true;
- r = bus_set_address_system(bus);
- }
- break;
-
- case BUS_TRANSPORT_REMOTE:
- r = bus_set_address_system_remote(bus, arg_host);
- break;
-
- case BUS_TRANSPORT_MACHINE:
- r = bus_set_address_system_machine(bus, arg_host);
- break;
-
- default:
- assert_not_reached("Hmm, unknown transport type.");
- }
- }
- if (r < 0) {
- log_error_errno(r, "Failed to set address: %m");
- goto finish;
- }
-
- r = sd_bus_start(bus);
- if (r < 0) {
- log_error_errno(r, "Failed to connect to bus: %m");
- goto finish;
- }
-
- r = busctl_main(bus, argc, argv);
-
-finish:
- pager_close();
-
- strv_free(arg_matches);
-
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "formats-util.h"
-
-#include "sd-bus.h"
-#include "bus-error.h"
-#include "bus-match.h"
-#include "bus-internal.h"
-#include "bus-util.h"
-
-static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
- return 0;
-}
-
-static int object_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- int r;
-
- if (sd_bus_message_is_method_error(m, NULL))
- return 0;
-
- if (sd_bus_message_is_method_call(m, "org.object.test", "Foobar")) {
- log_info("Invoked Foobar() on %s", sd_bus_message_get_path(m));
-
- r = sd_bus_reply_method_return(m, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to send reply: %m");
-
- return 1;
- }
-
- return 0;
-}
-
-static int server_init(sd_bus **_bus) {
- sd_bus *bus = NULL;
- sd_id128_t id;
- int r;
- const char *unique;
-
- assert_se(_bus);
-
- r = sd_bus_open_user(&bus);
- if (r < 0) {
- log_error_errno(r, "Failed to connect to user bus: %m");
- goto fail;
- }
-
- r = sd_bus_get_bus_id(bus, &id);
- if (r < 0) {
- log_error_errno(r, "Failed to get server ID: %m");
- goto fail;
- }
-
- r = sd_bus_get_unique_name(bus, &unique);
- if (r < 0) {
- log_error_errno(r, "Failed to get unique name: %m");
- goto fail;
- }
-
- log_info("Peer ID is " SD_ID128_FORMAT_STR ".", SD_ID128_FORMAT_VAL(id));
- log_info("Unique ID: %s", unique);
- log_info("Can send file handles: %i", sd_bus_can_send(bus, 'h'));
-
- r = sd_bus_request_name(bus, "org.freedesktop.systemd.test", 0);
- if (r < 0) {
- log_error_errno(r, "Failed to acquire name: %m");
- goto fail;
- }
-
- r = sd_bus_add_fallback(bus, NULL, "/foo/bar", object_callback, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to add object: %m");
- goto fail;
- }
-
- r = sd_bus_add_match(bus, NULL, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to add match: %m");
- goto fail;
- }
-
- r = sd_bus_add_match(bus, NULL, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to add match: %m");
- goto fail;
- }
-
- bus_match_dump(&bus->match_callbacks, 0);
-
- *_bus = bus;
- return 0;
-
-fail:
- if (bus)
- sd_bus_unref(bus);
-
- return r;
-}
-
-static int server(sd_bus *bus) {
- int r;
- bool client1_gone = false, client2_gone = false;
-
- while (!client1_gone || !client2_gone) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- pid_t pid = 0;
- const char *label = NULL;
-
- r = sd_bus_process(bus, &m);
- if (r < 0) {
- log_error_errno(r, "Failed to process requests: %m");
- goto fail;
- }
-
- if (r == 0) {
- r = sd_bus_wait(bus, (uint64_t) -1);
- if (r < 0) {
- log_error_errno(r, "Failed to wait: %m");
- goto fail;
- }
-
- continue;
- }
-
- if (!m)
- continue;
-
- sd_bus_creds_get_pid(sd_bus_message_get_creds(m), &pid);
- sd_bus_creds_get_selinux_context(sd_bus_message_get_creds(m), &label);
- log_info("Got message! member=%s pid="PID_FMT" label=%s",
- strna(sd_bus_message_get_member(m)),
- pid,
- strna(label));
- /* bus_message_dump(m); */
- /* sd_bus_message_rewind(m, true); */
-
- if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "LowerCase")) {
- const char *hello;
- _cleanup_free_ char *lowercase = NULL;
-
- r = sd_bus_message_read(m, "s", &hello);
- if (r < 0) {
- log_error_errno(r, "Failed to get parameter: %m");
- goto fail;
- }
-
- lowercase = strdup(hello);
- if (!lowercase) {
- r = log_oom();
- goto fail;
- }
-
- ascii_strlower(lowercase);
-
- r = sd_bus_reply_method_return(m, "s", lowercase);
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) {
-
- r = sd_bus_reply_method_return(m, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
-
- client1_gone = true;
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient2")) {
-
- r = sd_bus_reply_method_return(m, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
-
- client2_gone = true;
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Slow")) {
-
- sleep(1);
-
- r = sd_bus_reply_method_return(m, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "FileDescriptor")) {
- int fd;
- static const char x = 'X';
-
- r = sd_bus_message_read(m, "h", &fd);
- if (r < 0) {
- log_error_errno(r, "Failed to get parameter: %m");
- goto fail;
- }
-
- log_info("Received fd=%d", fd);
-
- if (write(fd, &x, 1) < 0) {
- log_error_errno(errno, "Failed to write to fd: %m");
- safe_close(fd);
- goto fail;
- }
-
- r = sd_bus_reply_method_return(m, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
-
- } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
-
- r = sd_bus_reply_method_error(
- m,
- &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."));
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
- }
- }
-
- r = 0;
-
-fail:
- if (bus) {
- sd_bus_flush(bus);
- sd_bus_unref(bus);
- }
-
- return r;
-}
-
-static void* client1(void*p) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *hello;
- int r;
- _cleanup_close_pair_ int pp[2] = { -1, -1 };
- char x;
-
- r = sd_bus_open_user(&bus);
- if (r < 0) {
- log_error_errno(r, "Failed to connect to user bus: %m");
- goto finish;
- }
-
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd.test",
- "/",
- "org.freedesktop.systemd.test",
- "LowerCase",
- &error,
- &reply,
- "s",
- "HELLO");
- if (r < 0) {
- log_error_errno(r, "Failed to issue method call: %m");
- goto finish;
- }
-
- r = sd_bus_message_read(reply, "s", &hello);
- if (r < 0) {
- log_error_errno(r, "Failed to get string: %m");
- goto finish;
- }
-
- assert_se(streq(hello, "hello"));
-
- if (pipe2(pp, O_CLOEXEC|O_NONBLOCK) < 0) {
- log_error_errno(errno, "Failed to allocate pipe: %m");
- r = -errno;
- goto finish;
- }
-
- log_info("Sending fd=%d", pp[1]);
-
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd.test",
- "/",
- "org.freedesktop.systemd.test",
- "FileDescriptor",
- &error,
- NULL,
- "h",
- pp[1]);
- if (r < 0) {
- log_error_errno(r, "Failed to issue method call: %m");
- goto finish;
- }
-
- errno = 0;
- if (read(pp[0], &x, 1) <= 0) {
- log_error("Failed to read from pipe: %s", errno ? strerror(errno) : "early read");
- goto finish;
- }
-
- r = 0;
-
-finish:
- if (bus) {
- _cleanup_bus_message_unref_ sd_bus_message *q;
-
- r = sd_bus_message_new_method_call(
- bus,
- &q,
- "org.freedesktop.systemd.test",
- "/",
- "org.freedesktop.systemd.test",
- "ExitClient1");
- if (r < 0)
- log_error_errno(r, "Failed to allocate method call: %m");
- else
- sd_bus_send(bus, q, NULL);
-
- }
-
- return INT_TO_PTR(r);
-}
-
-static int quit_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- bool *x = userdata;
-
- log_error("Quit callback: %s", strerror(sd_bus_message_get_errno(m)));
-
- *x = 1;
- return 1;
-}
-
-static void* client2(void*p) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
- _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- bool quit = false;
- const char *mid;
- int r;
-
- r = sd_bus_open_user(&bus);
- if (r < 0) {
- log_error_errno(r, "Failed to connect to user bus: %m");
- goto finish;
- }
-
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd.test",
- "/foo/bar/waldo/piep",
- "org.object.test",
- "Foobar");
- if (r < 0) {
- log_error_errno(r, "Failed to allocate method call: %m");
- goto finish;
- }
-
- r = sd_bus_send(bus, m, NULL);
- if (r < 0) {
- log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
- goto finish;
- }
-
- m = sd_bus_message_unref(m);
-
- r = sd_bus_message_new_signal(
- bus,
- &m,
- "/foobar",
- "foo.bar",
- "Notify");
- if (r < 0) {
- log_error_errno(r, "Failed to allocate signal: %m");
- goto finish;
- }
-
- r = sd_bus_send(bus, m, NULL);
- if (r < 0) {
- log_error("Failed to issue signal: %s", bus_error_message(&error, -r));
- goto finish;
- }
-
- m = sd_bus_message_unref(m);
-
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd.test",
- "/",
- "org.freedesktop.DBus.Peer",
- "GetMachineId");
- if (r < 0) {
- log_error_errno(r, "Failed to allocate method call: %m");
- goto finish;
- }
-
- r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
- goto finish;
- }
-
- r = sd_bus_message_read(reply, "s", &mid);
- if (r < 0) {
- log_error_errno(r, "Failed to parse machine ID: %m");
- goto finish;
- }
-
- log_info("Machine ID is %s.", mid);
-
- m = sd_bus_message_unref(m);
-
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd.test",
- "/",
- "org.freedesktop.systemd.test",
- "Slow");
- if (r < 0) {
- log_error_errno(r, "Failed to allocate method call: %m");
- goto finish;
- }
-
- reply = sd_bus_message_unref(reply);
-
- r = sd_bus_call(bus, m, 200 * USEC_PER_MSEC, &error, &reply);
- if (r < 0)
- log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
- else
- log_info("Slow call succeed.");
-
- m = sd_bus_message_unref(m);
-
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd.test",
- "/",
- "org.freedesktop.systemd.test",
- "Slow");
- if (r < 0) {
- log_error_errno(r, "Failed to allocate method call: %m");
- goto finish;
- }
-
- r = sd_bus_call_async(bus, NULL, m, quit_callback, &quit, 200 * USEC_PER_MSEC);
- if (r < 0) {
- log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
- goto finish;
- }
-
- while (!quit) {
- r = sd_bus_process(bus, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to process requests: %m");
- goto finish;
- }
- if (r == 0) {
- r = sd_bus_wait(bus, (uint64_t) -1);
- if (r < 0) {
- log_error_errno(r, "Failed to wait: %m");
- goto finish;
- }
- }
- }
-
- r = 0;
-
-finish:
- if (bus) {
- _cleanup_bus_message_unref_ sd_bus_message *q;
-
- r = sd_bus_message_new_method_call(
- bus,
- &q,
- "org.freedesktop.systemd.test",
- "/",
- "org.freedesktop.systemd.test",
- "ExitClient2");
- if (r < 0) {
- log_error_errno(r, "Failed to allocate method call: %m");
- goto finish;
- }
-
- (void) sd_bus_send(bus, q, NULL);
- }
-
- return INT_TO_PTR(r);
-}
-
-int main(int argc, char *argv[]) {
- pthread_t c1, c2;
- sd_bus *bus;
- void *p;
- int q, r;
-
- r = server_init(&bus);
- if (r < 0) {
- log_info("Failed to connect to bus, skipping tests.");
- return EXIT_TEST_SKIP;
- }
-
- log_info("Initialized...");
-
- r = pthread_create(&c1, NULL, client1, bus);
- if (r != 0)
- return EXIT_FAILURE;
-
- r = pthread_create(&c2, NULL, client2, bus);
- if (r != 0)
- return EXIT_FAILURE;
-
- r = server(bus);
-
- q = pthread_join(c1, &p);
- if (q != 0)
- return EXIT_FAILURE;
- if (PTR_TO_INT(p) < 0)
- return EXIT_FAILURE;
-
- q = pthread_join(c2, &p);
- if (q != 0)
- return EXIT_FAILURE;
- if (PTR_TO_INT(p) < 0)
- return EXIT_FAILURE;
-
- if (r < 0)
- return EXIT_FAILURE;
-
- return EXIT_SUCCESS;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#ifdef HAVE_GLIB
-#include <glib.h>
-#endif
-
-#include "util.h"
-#include "macro.h"
-#include "sd-bus.h"
-#include "bus-gvariant.h"
-#include "bus-util.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-dump.h"
-
-static void test_bus_gvariant_is_fixed_size(void) {
- assert_se(bus_gvariant_is_fixed_size("") > 0);
- assert_se(bus_gvariant_is_fixed_size("()") > 0);
- assert_se(bus_gvariant_is_fixed_size("y") > 0);
- assert_se(bus_gvariant_is_fixed_size("u") > 0);
- assert_se(bus_gvariant_is_fixed_size("b") > 0);
- assert_se(bus_gvariant_is_fixed_size("n") > 0);
- assert_se(bus_gvariant_is_fixed_size("q") > 0);
- assert_se(bus_gvariant_is_fixed_size("i") > 0);
- assert_se(bus_gvariant_is_fixed_size("t") > 0);
- assert_se(bus_gvariant_is_fixed_size("d") > 0);
- assert_se(bus_gvariant_is_fixed_size("s") == 0);
- assert_se(bus_gvariant_is_fixed_size("o") == 0);
- assert_se(bus_gvariant_is_fixed_size("g") == 0);
- assert_se(bus_gvariant_is_fixed_size("h") > 0);
- assert_se(bus_gvariant_is_fixed_size("ay") == 0);
- assert_se(bus_gvariant_is_fixed_size("v") == 0);
- assert_se(bus_gvariant_is_fixed_size("(u)") > 0);
- assert_se(bus_gvariant_is_fixed_size("(uuuuy)") > 0);
- assert_se(bus_gvariant_is_fixed_size("(uusuuy)") == 0);
- assert_se(bus_gvariant_is_fixed_size("a{ss}") == 0);
- assert_se(bus_gvariant_is_fixed_size("((u)yyy(b(iiii)))") > 0);
- assert_se(bus_gvariant_is_fixed_size("((u)yyy(b(iiivi)))") == 0);
-}
-
-static void test_bus_gvariant_get_size(void) {
- assert_se(bus_gvariant_get_size("") == 0);
- assert_se(bus_gvariant_get_size("()") == 1);
- assert_se(bus_gvariant_get_size("y") == 1);
- assert_se(bus_gvariant_get_size("u") == 4);
- assert_se(bus_gvariant_get_size("b") == 1);
- assert_se(bus_gvariant_get_size("n") == 2);
- assert_se(bus_gvariant_get_size("q") == 2);
- assert_se(bus_gvariant_get_size("i") == 4);
- assert_se(bus_gvariant_get_size("t") == 8);
- assert_se(bus_gvariant_get_size("d") == 8);
- assert_se(bus_gvariant_get_size("s") < 0);
- assert_se(bus_gvariant_get_size("o") < 0);
- assert_se(bus_gvariant_get_size("g") < 0);
- assert_se(bus_gvariant_get_size("h") == 4);
- assert_se(bus_gvariant_get_size("ay") < 0);
- assert_se(bus_gvariant_get_size("v") < 0);
- assert_se(bus_gvariant_get_size("(u)") == 4);
- assert_se(bus_gvariant_get_size("(uuuuy)") == 20);
- assert_se(bus_gvariant_get_size("(uusuuy)") < 0);
- assert_se(bus_gvariant_get_size("a{ss}") < 0);
- assert_se(bus_gvariant_get_size("((u)yyy(b(iiii)))") == 28);
- assert_se(bus_gvariant_get_size("((u)yyy(b(iiivi)))") < 0);
- assert_se(bus_gvariant_get_size("((b)(t))") == 16);
- assert_se(bus_gvariant_get_size("((b)(b)(t))") == 16);
- assert_se(bus_gvariant_get_size("(bt)") == 16);
- assert_se(bus_gvariant_get_size("((t)(b))") == 16);
- assert_se(bus_gvariant_get_size("(tb)") == 16);
- assert_se(bus_gvariant_get_size("((b)(b))") == 2);
- assert_se(bus_gvariant_get_size("((t)(t))") == 16);
-}
-
-static void test_bus_gvariant_get_alignment(void) {
- assert_se(bus_gvariant_get_alignment("") == 1);
- assert_se(bus_gvariant_get_alignment("()") == 1);
- assert_se(bus_gvariant_get_alignment("y") == 1);
- assert_se(bus_gvariant_get_alignment("b") == 1);
- assert_se(bus_gvariant_get_alignment("u") == 4);
- assert_se(bus_gvariant_get_alignment("s") == 1);
- assert_se(bus_gvariant_get_alignment("o") == 1);
- assert_se(bus_gvariant_get_alignment("g") == 1);
- assert_se(bus_gvariant_get_alignment("v") == 8);
- assert_se(bus_gvariant_get_alignment("h") == 4);
- assert_se(bus_gvariant_get_alignment("i") == 4);
- assert_se(bus_gvariant_get_alignment("t") == 8);
- assert_se(bus_gvariant_get_alignment("x") == 8);
- assert_se(bus_gvariant_get_alignment("q") == 2);
- assert_se(bus_gvariant_get_alignment("n") == 2);
- assert_se(bus_gvariant_get_alignment("d") == 8);
- assert_se(bus_gvariant_get_alignment("ay") == 1);
- assert_se(bus_gvariant_get_alignment("as") == 1);
- assert_se(bus_gvariant_get_alignment("au") == 4);
- assert_se(bus_gvariant_get_alignment("an") == 2);
- assert_se(bus_gvariant_get_alignment("ans") == 2);
- assert_se(bus_gvariant_get_alignment("ant") == 8);
- assert_se(bus_gvariant_get_alignment("(ss)") == 1);
- assert_se(bus_gvariant_get_alignment("(ssu)") == 4);
- assert_se(bus_gvariant_get_alignment("a(ssu)") == 4);
- assert_se(bus_gvariant_get_alignment("(u)") == 4);
- assert_se(bus_gvariant_get_alignment("(uuuuy)") == 4);
- assert_se(bus_gvariant_get_alignment("(uusuuy)") == 4);
- assert_se(bus_gvariant_get_alignment("a{ss}") == 1);
- assert_se(bus_gvariant_get_alignment("((u)yyy(b(iiii)))") == 4);
- assert_se(bus_gvariant_get_alignment("((u)yyy(b(iiivi)))") == 8);
- assert_se(bus_gvariant_get_alignment("((b)(t))") == 8);
- assert_se(bus_gvariant_get_alignment("((b)(b)(t))") == 8);
- assert_se(bus_gvariant_get_alignment("(bt)") == 8);
- assert_se(bus_gvariant_get_alignment("((t)(b))") == 8);
- assert_se(bus_gvariant_get_alignment("(tb)") == 8);
- assert_se(bus_gvariant_get_alignment("((b)(b))") == 1);
- assert_se(bus_gvariant_get_alignment("((t)(t))") == 8);
-}
-
-static void test_marshal(void) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *n = NULL;
- _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
- _cleanup_free_ void *blob;
- size_t sz;
- int r;
-
- r = sd_bus_open_system(&bus);
- if (r < 0)
- exit(EXIT_TEST_SKIP);
-
- bus->message_version = 2; /* dirty hack to enable gvariant */
-
- assert_se(sd_bus_message_new_method_call(bus, &m, "a.service.name", "/an/object/path/which/is/really/really/long/so/that/we/hit/the/eight/bit/boundary/by/quite/some/margin/to/test/this/stuff/that/it/really/works", "an.interface.name", "AMethodName") >= 0);
-
- assert_cc(sizeof(struct bus_header) == 16);
-
- assert_se(sd_bus_message_append(m,
- "a(usv)", 3,
- 4711, "first-string-parameter", "(st)", "X", (uint64_t) 1111,
- 4712, "second-string-parameter", "(a(si))", 2, "Y", 5, "Z", 6,
- 4713, "third-string-parameter", "(uu)", 1, 2) >= 0);
-
- assert_se(bus_message_seal(m, 4711, 0) >= 0);
-
-#ifdef HAVE_GLIB
- {
- GVariant *v;
- char *t;
-
-#if !defined(GLIB_VERSION_2_36)
- g_type_init();
-#endif
-
- v = g_variant_new_from_data(G_VARIANT_TYPE("(yyyyuta{tv})"), m->header, sizeof(struct bus_header) + m->fields_size, false, NULL, NULL);
- assert_se(g_variant_is_normal_form(v));
- t = g_variant_print(v, TRUE);
- printf("%s\n", t);
- g_free(t);
- g_variant_unref(v);
-
- v = g_variant_new_from_data(G_VARIANT_TYPE("(a(usv))"), m->body.data, m->user_body_size, false, NULL, NULL);
- assert_se(g_variant_is_normal_form(v));
- t = g_variant_print(v, TRUE);
- printf("%s\n", t);
- g_free(t);
- g_variant_unref(v);
- }
-#endif
-
- assert_se(bus_message_dump(m, NULL, BUS_MESSAGE_DUMP_WITH_HEADER) >= 0);
-
- assert_se(bus_message_get_blob(m, &blob, &sz) >= 0);
-
-#ifdef HAVE_GLIB
- {
- GVariant *v;
- char *t;
-
- v = g_variant_new_from_data(G_VARIANT_TYPE("(yyyyuta{tv}v)"), blob, sz, false, NULL, NULL);
- assert_se(g_variant_is_normal_form(v));
- t = g_variant_print(v, TRUE);
- printf("%s\n", t);
- g_free(t);
- g_variant_unref(v);
- }
-#endif
-
- assert_se(bus_message_from_malloc(bus, blob, sz, NULL, 0, NULL, &n) >= 0);
- blob = NULL;
-
- assert_se(bus_message_dump(n, NULL, BUS_MESSAGE_DUMP_WITH_HEADER) >= 0);
-
- m = sd_bus_message_unref(m);
-
- assert_se(sd_bus_message_new_method_call(bus, &m, "a.x", "/a/x", "a.x", "Ax") >= 0);
-
- assert_se(sd_bus_message_append(m, "as", 0) >= 0);
-
- assert_se(bus_message_seal(m, 4712, 0) >= 0);
- assert_se(bus_message_dump(m, NULL, BUS_MESSAGE_DUMP_WITH_HEADER) >= 0);
-}
-
-int main(int argc, char *argv[]) {
-
- test_bus_gvariant_is_fixed_size();
- test_bus_gvariant_get_size();
- test_bus_gvariant_get_alignment();
- test_marshal();
-
- return 0;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "util.h"
-#include "log.h"
-
-#include "sd-bus.h"
-#include "bus-kernel.h"
-#include "bus-util.h"
-
-static int test_match(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- int *found = userdata;
-
- *found = 1;
-
- return 0;
-}
-
-static void test_one(
- const char *path,
- const char *interface,
- const char *member,
- bool as_list,
- const char *arg0,
- const char *match,
- bool good) {
-
- _cleanup_close_ int bus_ref = -1;
- _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- sd_bus *a, *b;
- int r, found = 0;
-
- assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
-
- bus_ref = bus_kernel_create_bus(name, false, &bus_name);
- if (bus_ref == -ENOENT)
- exit(EXIT_TEST_SKIP);
-
- assert_se(bus_ref >= 0);
-
- address = strappend("kernel:path=", bus_name);
- assert_se(address);
-
- r = sd_bus_new(&a);
- assert_se(r >= 0);
-
- r = sd_bus_new(&b);
- assert_se(r >= 0);
-
- r = sd_bus_set_address(a, address);
- assert_se(r >= 0);
-
- r = sd_bus_set_address(b, address);
- assert_se(r >= 0);
-
- r = sd_bus_start(a);
- assert_se(r >= 0);
-
- r = sd_bus_start(b);
- assert_se(r >= 0);
-
- log_debug("match");
- r = sd_bus_add_match(b, NULL, match, test_match, &found);
- assert_se(r >= 0);
-
- log_debug("signal");
-
- if (as_list)
- r = sd_bus_emit_signal(a, path, interface, member, "as", 1, arg0);
- else
- r = sd_bus_emit_signal(a, path, interface, member, "s", arg0);
- assert_se(r >= 0);
-
- r = sd_bus_process(b, &m);
- assert_se(r >= 0 && good == !!found);
-
- sd_bus_unref(a);
- sd_bus_unref(b);
-}
-
-int main(int argc, char *argv[]) {
- log_set_max_level(LOG_DEBUG);
-
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo/tuut'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "interface='waldo.com'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "member='Piep'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "member='Pi_ep'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foobar'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foo_bar'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foobar'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foo_bar'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar2'", false);
-
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo/quux'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/bar/waldo'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/bar'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/quux'", false);
- test_one("/", "waldo.com", "Piep", false, "foobar", "path_namespace='/'", true);
-
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo/'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/bar/waldo/'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/'", true);
-
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo/bar/waldo", "arg0path='/foo/'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo", "arg0path='/foo'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo", "arg0path='/foo/bar/waldo'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo/", "arg0path='/foo/bar/waldo'", true);
-
- return 0;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <fcntl.h>
-
-#include "util.h"
-#include "log.h"
-
-#include "sd-bus.h"
-#include "bus-kernel.h"
-#include "bus-util.h"
-#include "bus-dump.h"
-
-int main(int argc, char *argv[]) {
- _cleanup_close_ int bus_ref = -1;
- _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL, *bname = NULL;
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *ua = NULL, *ub = NULL, *the_string = NULL;
- sd_bus *a, *b;
- int r, pipe_fds[2];
- const char *nn;
-
- log_set_max_level(LOG_DEBUG);
-
- assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
-
- bus_ref = bus_kernel_create_bus(name, false, &bus_name);
- if (bus_ref == -ENOENT)
- return EXIT_TEST_SKIP;
-
- assert_se(bus_ref >= 0);
-
- address = strappend("kernel:path=", bus_name);
- assert_se(address);
-
- r = sd_bus_new(&a);
- assert_se(r >= 0);
-
- r = sd_bus_new(&b);
- assert_se(r >= 0);
-
- r = sd_bus_set_description(a, "a");
- assert_se(r >= 0);
-
- r = sd_bus_set_address(a, address);
- assert_se(r >= 0);
-
- r = sd_bus_set_address(b, address);
- assert_se(r >= 0);
-
- assert_se(sd_bus_negotiate_timestamp(a, 1) >= 0);
- assert_se(sd_bus_negotiate_creds(a, true, _SD_BUS_CREDS_ALL) >= 0);
-
- assert_se(sd_bus_negotiate_timestamp(b, 0) >= 0);
- assert_se(sd_bus_negotiate_creds(b, true, 0) >= 0);
-
- r = sd_bus_start(a);
- assert_se(r >= 0);
-
- r = sd_bus_start(b);
- assert_se(r >= 0);
-
- assert_se(sd_bus_negotiate_timestamp(b, 1) >= 0);
- assert_se(sd_bus_negotiate_creds(b, true, _SD_BUS_CREDS_ALL) >= 0);
-
- r = sd_bus_get_unique_name(a, &ua);
- assert_se(r >= 0);
- printf("unique a: %s\n", ua);
-
- r = sd_bus_get_description(a, &nn);
- assert_se(r >= 0);
- printf("name of a: %s\n", nn);
-
- r = sd_bus_get_unique_name(b, &ub);
- assert_se(r >= 0);
- printf("unique b: %s\n", ub);
-
- r = sd_bus_get_description(b, &nn);
- assert_se(r >= 0);
- printf("name of b: %s\n", nn);
-
- assert_se(bus_kernel_get_bus_name(b, &bname) >= 0);
- assert_se(endswith(bname, name));
-
- r = sd_bus_call_method(a, "this.doesnt.exist", "/foo", "meh.mah", "muh", &error, NULL, "s", "yayayay");
- assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_SERVICE_UNKNOWN));
- assert_se(r == -EHOSTUNREACH);
-
- r = sd_bus_add_match(b, NULL, "interface='waldo.com',member='Piep'", NULL, NULL);
- assert_se(r >= 0);
-
- r = sd_bus_emit_signal(a, "/foo/bar/waldo", "waldo.com", "Piep", "sss", "I am a string", "/this/is/a/path", "and.this.a.domain.name");
- assert_se(r >= 0);
-
- r = sd_bus_try_close(b);
- assert_se(r == -EBUSY);
-
- r = sd_bus_process_priority(b, -10, &m);
- assert_se(r == 0);
-
- r = sd_bus_process(b, &m);
- assert_se(r > 0);
- assert_se(m);
-
- bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
- assert_se(sd_bus_message_rewind(m, true) >= 0);
-
- r = sd_bus_message_read(m, "s", &the_string);
- assert_se(r >= 0);
- assert_se(streq(the_string, "I am a string"));
-
- sd_bus_message_unref(m);
- m = NULL;
-
- r = sd_bus_request_name(a, "net.x0pointer.foobar", 0);
- assert_se(r >= 0);
-
- r = sd_bus_message_new_method_call(b, &m, "net.x0pointer.foobar", "/a/path", "an.inter.face", "AMethod");
- assert_se(r >= 0);
-
- assert_se(pipe2(pipe_fds, O_CLOEXEC) >= 0);
-
- assert_se(write(pipe_fds[1], "x", 1) == 1);
-
- pipe_fds[1] = safe_close(pipe_fds[1]);
-
- r = sd_bus_message_append(m, "h", pipe_fds[0]);
- assert_se(r >= 0);
-
- pipe_fds[0] = safe_close(pipe_fds[0]);
-
- r = sd_bus_send(b, m, NULL);
- assert_se(r >= 0);
-
- for (;;) {
- sd_bus_message_unref(m);
- m = NULL;
- r = sd_bus_process(a, &m);
- assert_se(r > 0);
- assert_se(m);
-
- bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
- assert_se(sd_bus_message_rewind(m, true) >= 0);
-
- if (sd_bus_message_is_method_call(m, "an.inter.face", "AMethod")) {
- int fd;
- char x;
-
- r = sd_bus_message_read(m, "h", &fd);
- assert_se(r >= 0);
-
- assert_se(read(fd, &x, 1) == 1);
- assert_se(x == 'x');
- break;
- }
- }
-
- r = sd_bus_release_name(a, "net.x0pointer.foobar");
- assert_se(r >= 0);
-
- r = sd_bus_release_name(a, "net.x0pointer.foobar");
- assert_se(r == -ESRCH);
-
- r = sd_bus_try_close(a);
- assert_se(r >= 0);
-
- sd_bus_unref(a);
- sd_bus_unref(b);
-
- return 0;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-#include <math.h>
-
-#ifdef HAVE_GLIB
-#include <gio/gio.h>
-#endif
-
-#ifdef HAVE_DBUS
-#include <dbus/dbus.h>
-#endif
-
-#include "log.h"
-#include "util.h"
-
-#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-util.h"
-#include "bus-dump.h"
-#include "bus-label.h"
-
-static void test_bus_path_encode_unique(void) {
- _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL;
-
- assert_se(bus_path_encode_unique(NULL, "/foo/bar", "some.sender", "a.suffix", &a) >= 0 && streq_ptr(a, "/foo/bar/some_2esender/a_2esuffix"));
- assert_se(bus_path_decode_unique(a, "/foo/bar", &b, &c) > 0 && streq_ptr(b, "some.sender") && streq_ptr(c, "a.suffix"));
- assert_se(bus_path_decode_unique(a, "/bar/foo", &d, &d) == 0 && !d);
- assert_se(bus_path_decode_unique("/foo/bar/onlyOneSuffix", "/foo/bar", &d, &d) == 0 && !d);
- assert_se(bus_path_decode_unique("/foo/bar/_/_", "/foo/bar", &d, &e) > 0 && streq_ptr(d, "") && streq_ptr(e, ""));
-}
-
-static void test_bus_path_encode(void) {
- _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL;
-
- assert_se(sd_bus_path_encode("/foo/bar", "waldo", &a) >= 0 && streq(a, "/foo/bar/waldo"));
- assert_se(sd_bus_path_decode(a, "/waldo", &b) == 0 && b == NULL);
- assert_se(sd_bus_path_decode(a, "/foo/bar", &b) > 0 && streq(b, "waldo"));
-
- assert_se(sd_bus_path_encode("xxxx", "waldo", &c) < 0);
- assert_se(sd_bus_path_encode("/foo/", "waldo", &c) < 0);
-
- assert_se(sd_bus_path_encode("/foo/bar", "", &c) >= 0 && streq(c, "/foo/bar/_"));
- assert_se(sd_bus_path_decode(c, "/foo/bar", &d) > 0 && streq(d, ""));
-
- assert_se(sd_bus_path_encode("/foo/bar", "foo.bar", &e) >= 0 && streq(e, "/foo/bar/foo_2ebar"));
- assert_se(sd_bus_path_decode(e, "/foo/bar", &f) > 0 && streq(f, "foo.bar"));
-}
-
-static void test_bus_label_escape_one(const char *a, const char *b) {
- _cleanup_free_ char *t = NULL, *x = NULL, *y = NULL;
-
- assert_se(t = bus_label_escape(a));
- assert_se(streq(t, b));
-
- assert_se(x = bus_label_unescape(t));
- assert_se(streq(a, x));
-
- assert_se(y = bus_label_unescape(b));
- assert_se(streq(a, y));
-}
-
-static void test_bus_label_escape(void) {
- test_bus_label_escape_one("foo123bar", "foo123bar");
- test_bus_label_escape_one("foo.bar", "foo_2ebar");
- test_bus_label_escape_one("foo_2ebar", "foo_5f2ebar");
- test_bus_label_escape_one("", "_");
- test_bus_label_escape_one("_", "_5f");
- test_bus_label_escape_one("1", "_31");
- test_bus_label_escape_one(":1", "_3a1");
-}
-
-int main(int argc, char *argv[]) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *copy = NULL;
- int r, boolean;
- const char *x, *x2, *y, *z, *a, *b, *c, *d, *a_signature;
- uint8_t u, v;
- void *buffer = NULL;
- size_t sz;
- char *h;
- const int32_t integer_array[] = { -1, -2, 0, 1, 2 }, *return_array;
- char *s;
- _cleanup_free_ char *first = NULL, *second = NULL, *third = NULL;
- _cleanup_fclose_ FILE *ms = NULL;
- size_t first_size = 0, second_size = 0, third_size = 0;
- _cleanup_bus_unref_ sd_bus *bus = NULL;
- double dbl;
- uint64_t u64;
-
- r = sd_bus_default_system(&bus);
- if (r < 0)
- return EXIT_TEST_SKIP;
-
- r = sd_bus_message_new_method_call(bus, &m, "foobar.waldo", "/", "foobar.waldo", "Piep");
- assert_se(r >= 0);
-
- r = sd_bus_message_append(m, "");
- assert_se(r >= 0);
-
- r = sd_bus_message_append(m, "s", "a string");
- assert_se(r >= 0);
-
- r = sd_bus_message_append(m, "s", NULL);
- assert_se(r >= 0);
-
- r = sd_bus_message_append(m, "asg", 2, "string #1", "string #2", "sba(tt)ss");
- assert_se(r >= 0);
-
- r = sd_bus_message_append(m, "sass", "foobar", 5, "foo", "bar", "waldo", "piep", "pap", "after");
- assert_se(r >= 0);
-
- r = sd_bus_message_append(m, "a{yv}", 2, 3, "s", "foo", 5, "s", "waldo");
- assert_se(r >= 0);
-
- r = sd_bus_message_append(m, "y(ty)y(yt)y", 8, 777ULL, 7, 9, 77, 7777ULL, 10);
- assert_se(r >= 0);
-
- r = sd_bus_message_append(m, "()");
- assert_se(r >= 0);
-
- r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3");
- assert_se(r >= 0);
-
- r = sd_bus_message_open_container(m, 'a', "s");
- assert_se(r >= 0);
-
- r = sd_bus_message_append_basic(m, 's', "foobar");
- assert_se(r >= 0);
-
- r = sd_bus_message_append_basic(m, 's', "waldo");
- assert_se(r >= 0);
-
- r = sd_bus_message_close_container(m);
- assert_se(r >= 0);
-
- r = sd_bus_message_append_string_space(m, 5, &s);
- assert_se(r >= 0);
- strcpy(s, "hallo");
-
- r = sd_bus_message_append_array(m, 'i', integer_array, sizeof(integer_array));
- assert_se(r >= 0);
-
- r = sd_bus_message_append_array(m, 'u', NULL, 0);
- assert_se(r >= 0);
-
- r = sd_bus_message_append(m, "a(stdo)", 1, "foo", 815ULL, 47.0, "/");
- assert_se(r >= 0);
-
- r = bus_message_seal(m, 4711, 0);
- assert_se(r >= 0);
-
- bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
-
- ms = open_memstream(&first, &first_size);
- bus_message_dump(m, ms, 0);
- fflush(ms);
- assert_se(!ferror(ms));
-
- r = bus_message_get_blob(m, &buffer, &sz);
- assert_se(r >= 0);
-
- h = hexmem(buffer, sz);
- assert_se(h);
-
- log_info("message size = %zu, contents =\n%s", sz, h);
- free(h);
-
-#ifdef HAVE_GLIB
- {
- GDBusMessage *g;
- char *p;
-
-#if !defined(GLIB_VERSION_2_36)
- g_type_init();
-#endif
-
- g = g_dbus_message_new_from_blob(buffer, sz, 0, NULL);
- p = g_dbus_message_print(g, 0);
- log_info("%s", p);
- g_free(p);
- g_object_unref(g);
- }
-#endif
-
-#ifdef HAVE_DBUS
- {
- DBusMessage *w;
- DBusError error;
-
- dbus_error_init(&error);
-
- w = dbus_message_demarshal(buffer, sz, &error);
- if (!w)
- log_error("%s", error.message);
- else
- dbus_message_unref(w);
- }
-#endif
-
- m = sd_bus_message_unref(m);
-
- r = bus_message_from_malloc(bus, buffer, sz, NULL, 0, NULL, &m);
- assert_se(r >= 0);
-
- bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
-
- fclose(ms);
- ms = open_memstream(&second, &second_size);
- bus_message_dump(m, ms, 0);
- fflush(ms);
- assert_se(!ferror(ms));
- assert_se(first_size == second_size);
- assert_se(memcmp(first, second, first_size) == 0);
-
- assert_se(sd_bus_message_rewind(m, true) >= 0);
-
- r = sd_bus_message_read(m, "ssasg", &x, &x2, 2, &y, &z, &a_signature);
- assert_se(r > 0);
- assert_se(streq(x, "a string"));
- assert_se(streq(x2, ""));
- assert_se(streq(y, "string #1"));
- assert_se(streq(z, "string #2"));
- assert_se(streq(a_signature, "sba(tt)ss"));
-
- r = sd_bus_message_read(m, "sass", &x, 5, &y, &z, &a, &b, &c, &d);
- assert_se(r > 0);
- assert_se(streq(x, "foobar"));
- assert_se(streq(y, "foo"));
- assert_se(streq(z, "bar"));
- assert_se(streq(a, "waldo"));
- assert_se(streq(b, "piep"));
- assert_se(streq(c, "pap"));
- assert_se(streq(d, "after"));
-
- r = sd_bus_message_read(m, "a{yv}", 2, &u, "s", &x, &v, "s", &y);
- assert_se(r > 0);
- assert_se(u == 3);
- assert_se(streq(x, "foo"));
- assert_se(v == 5);
- assert_se(streq(y, "waldo"));
-
- r = sd_bus_message_read(m, "y(ty)", &v, &u64, &u);
- assert_se(r > 0);
- assert_se(v == 8);
- assert_se(u64 == 777);
- assert_se(u == 7);
-
- r = sd_bus_message_read(m, "y(yt)", &v, &u, &u64);
- assert_se(r > 0);
- assert_se(v == 9);
- assert_se(u == 77);
- assert_se(u64 == 7777);
-
- r = sd_bus_message_read(m, "y", &v);
- assert_se(r > 0);
- assert_se(v == 10);
-
- r = sd_bus_message_read(m, "()");
- assert_se(r > 0);
-
- r = sd_bus_message_read(m, "ba(ss)", &boolean, 3, &x, &y, &a, &b, &c, &d);
- assert_se(r > 0);
- assert_se(boolean);
- assert_se(streq(x, "aaa"));
- assert_se(streq(y, "1"));
- assert_se(streq(a, "bbb"));
- assert_se(streq(b, "2"));
- assert_se(streq(c, "ccc"));
- assert_se(streq(d, "3"));
-
- assert_se(sd_bus_message_verify_type(m, 'a', "s") > 0);
-
- r = sd_bus_message_read(m, "as", 2, &x, &y);
- assert_se(r > 0);
- assert_se(streq(x, "foobar"));
- assert_se(streq(y, "waldo"));
-
- r = sd_bus_message_read_basic(m, 's', &s);
- assert_se(r > 0);
- assert_se(streq(s, "hallo"));
-
- r = sd_bus_message_read_array(m, 'i', (const void**) &return_array, &sz);
- assert_se(r > 0);
- assert_se(sz == sizeof(integer_array));
- assert_se(memcmp(integer_array, return_array, sz) == 0);
-
- r = sd_bus_message_read_array(m, 'u', (const void**) &return_array, &sz);
- assert_se(r > 0);
- assert_se(sz == 0);
-
- r = sd_bus_message_read(m, "a(stdo)", 1, &x, &u64, &dbl, &y);
- assert_se(r > 0);
- assert_se(streq(x, "foo"));
- assert_se(u64 == 815ULL);
- assert_se(fabs(dbl - 47.0) < 0.1);
- assert_se(streq(y, "/"));
-
- r = sd_bus_message_peek_type(m, NULL, NULL);
- assert_se(r == 0);
-
- r = sd_bus_message_new_method_call(bus, ©, "foobar.waldo", "/", "foobar.waldo", "Piep");
- assert_se(r >= 0);
-
- r = sd_bus_message_rewind(m, true);
- assert_se(r >= 0);
-
- r = sd_bus_message_copy(copy, m, true);
- assert_se(r >= 0);
-
- r = bus_message_seal(copy, 4712, 0);
- assert_se(r >= 0);
-
- fclose(ms);
- ms = open_memstream(&third, &third_size);
- bus_message_dump(copy, ms, 0);
- fflush(ms);
- assert_se(!ferror(ms));
-
- printf("<%.*s>\n", (int) first_size, first);
- printf("<%.*s>\n", (int) third_size, third);
-
- assert_se(first_size == third_size);
- assert_se(memcmp(first, third, third_size) == 0);
-
- r = sd_bus_message_rewind(m, true);
- assert_se(r >= 0);
-
- assert_se(sd_bus_message_verify_type(m, 's', NULL) > 0);
-
- r = sd_bus_message_skip(m, "ssasg");
- assert_se(r > 0);
-
- assert_se(sd_bus_message_verify_type(m, 's', NULL) > 0);
-
- r = sd_bus_message_skip(m, "sass");
- assert_se(r >= 0);
-
- assert_se(sd_bus_message_verify_type(m, 'a', "{yv}") > 0);
-
- r = sd_bus_message_skip(m, "a{yv}y(ty)y(yt)y()");
- assert_se(r >= 0);
-
- assert_se(sd_bus_message_verify_type(m, 'b', NULL) > 0);
-
- r = sd_bus_message_read(m, "b", &boolean);
- assert_se(r > 0);
- assert_se(boolean);
-
- r = sd_bus_message_enter_container(m, 0, NULL);
- assert_se(r > 0);
-
- r = sd_bus_message_read(m, "(ss)", &x, &y);
- assert_se(r > 0);
-
- r = sd_bus_message_read(m, "(ss)", &a, &b);
- assert_se(r > 0);
-
- r = sd_bus_message_read(m, "(ss)", &c, &d);
- assert_se(r > 0);
-
- r = sd_bus_message_read(m, "(ss)", &x, &y);
- assert_se(r == 0);
-
- r = sd_bus_message_exit_container(m);
- assert_se(r >= 0);
-
- assert_se(streq(x, "aaa"));
- assert_se(streq(y, "1"));
- assert_se(streq(a, "bbb"));
- assert_se(streq(b, "2"));
- assert_se(streq(c, "ccc"));
- assert_se(streq(d, "3"));
-
- test_bus_label_escape();
- test_bus_path_encode();
- test_bus_path_encode_unique();
-
- return 0;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "log.h"
-#include "macro.h"
-
-#include "bus-match.h"
-#include "bus-message.h"
-#include "bus-util.h"
-#include "bus-slot.h"
-
-static bool mask[32];
-
-static int filter(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- log_info("Ran %u", PTR_TO_UINT(userdata));
- assert_se(PTR_TO_UINT(userdata) < ELEMENTSOF(mask));
- mask[PTR_TO_UINT(userdata)] = true;
- return 0;
-}
-
-static bool mask_contains(unsigned a[], unsigned n) {
- unsigned i, j;
-
- for (i = 0; i < ELEMENTSOF(mask); i++) {
- bool found = false;
-
- for (j = 0; j < n; j++)
- if (a[j] == i) {
- found = true;
- break;
- }
-
- if (found != mask[i])
- return false;
- }
-
- return true;
-}
-
-static int match_add(sd_bus_slot *slots, struct bus_match_node *root, const char *match, int value) {
- struct bus_match_component *components = NULL;
- unsigned n_components = 0;
- sd_bus_slot *s;
- int r;
-
- s = slots + value;
- zero(*s);
-
- r = bus_match_parse(match, &components, &n_components);
- if (r < 0)
- return r;
-
- s->userdata = INT_TO_PTR(value);
- s->match_callback.callback = filter;
-
- r = bus_match_add(root, components, n_components, &s->match_callback);
- bus_match_parse_free(components, n_components);
-
- return r;
-}
-
-static void test_match_scope(const char *match, enum bus_match_scope scope) {
- struct bus_match_component *components = NULL;
- unsigned n_components = 0;
-
- assert_se(bus_match_parse(match, &components, &n_components) >= 0);
- assert_se(bus_match_get_scope(components, n_components) == scope);
- bus_match_parse_free(components, n_components);
-}
-
-int main(int argc, char *argv[]) {
- struct bus_match_node root = {
- .type = BUS_MATCH_ROOT,
- };
-
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
- enum bus_match_node_type i;
- sd_bus_slot slots[19];
- int r;
-
- r = sd_bus_open_system(&bus);
- if (r < 0)
- return EXIT_TEST_SKIP;
-
- assert_se(match_add(slots, &root, "arg2='wal\\'do',sender='foo',type='signal',interface='bar.x',", 1) >= 0);
- assert_se(match_add(slots, &root, "arg2='wal\\'do2',sender='foo',type='signal',interface='bar.x',", 2) >= 0);
- assert_se(match_add(slots, &root, "arg3='test',sender='foo',type='signal',interface='bar.x',", 3) >= 0);
- assert_se(match_add(slots, &root, "arg3='test',sender='foo',type='method_call',interface='bar.x',", 4) >= 0);
- assert_se(match_add(slots, &root, "", 5) >= 0);
- assert_se(match_add(slots, &root, "interface='quux.x'", 6) >= 0);
- assert_se(match_add(slots, &root, "interface='bar.x'", 7) >= 0);
- assert_se(match_add(slots, &root, "member='waldo',path='/foo/bar'", 8) >= 0);
- assert_se(match_add(slots, &root, "path='/foo/bar'", 9) >= 0);
- assert_se(match_add(slots, &root, "path_namespace='/foo'", 10) >= 0);
- assert_se(match_add(slots, &root, "path_namespace='/foo/quux'", 11) >= 0);
- assert_se(match_add(slots, &root, "arg1='two'", 12) >= 0);
- assert_se(match_add(slots, &root, "member='waldo',arg2path='/prefix/'", 13) >= 0);
- assert_se(match_add(slots, &root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0);
- assert_se(match_add(slots, &root, "arg4='pi'", 15) >= 0);
- assert_se(match_add(slots, &root, "arg4='pa'", 16) >= 0);
- assert_se(match_add(slots, &root, "arg4='po'", 17) >= 0);
- assert_se(match_add(slots, &root, "arg4='pu'", 18) >= 0);
-
- bus_match_dump(&root, 0);
-
- assert_se(sd_bus_message_new_signal(bus, &m, "/foo/bar", "bar.x", "waldo") >= 0);
- assert_se(sd_bus_message_append(m, "ssssas", "one", "two", "/prefix/three", "prefix.four", 3, "pi", "pa", "po") >= 0);
- assert_se(bus_message_seal(m, 1, 0) >= 0);
-
- zero(mask);
- assert_se(bus_match_run(NULL, &root, m) == 0);
- assert_se(mask_contains((unsigned[]) { 9, 8, 7, 5, 10, 12, 13, 14, 15, 16, 17 }, 11));
-
- assert_se(bus_match_remove(&root, &slots[8].match_callback) >= 0);
- assert_se(bus_match_remove(&root, &slots[13].match_callback) >= 0);
-
- bus_match_dump(&root, 0);
-
- zero(mask);
- assert_se(bus_match_run(NULL, &root, m) == 0);
- assert_se(mask_contains((unsigned[]) { 9, 5, 10, 12, 14, 7, 15, 16, 17 }, 9));
-
- for (i = 0; i < _BUS_MATCH_NODE_TYPE_MAX; i++) {
- char buf[32];
- const char *x;
-
- assert_se(x = bus_match_node_type_to_string(i, buf, sizeof(buf)));
-
- if (i >= BUS_MATCH_MESSAGE_TYPE)
- assert_se(bus_match_node_type_from_string(x, strlen(x)) == i);
- }
-
- bus_match_free(&root);
-
- test_match_scope("interface='foobar'", BUS_MATCH_GENERIC);
- test_match_scope("", BUS_MATCH_GENERIC);
- test_match_scope("interface='org.freedesktop.DBus.Local'", BUS_MATCH_LOCAL);
- test_match_scope("sender='org.freedesktop.DBus.Local'", BUS_MATCH_LOCAL);
- test_match_scope("member='gurke',path='/org/freedesktop/DBus/Local'", BUS_MATCH_LOCAL);
- test_match_scope("arg2='piep',sender='org.freedesktop.DBus',member='waldo'", BUS_MATCH_DRIVER);
-
- return 0;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-#include <pthread.h>
-
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
-
-#include "sd-bus.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-util.h"
-#include "bus-dump.h"
-
-struct context {
- int fds[2];
- bool quit;
- char *something;
- char *automatic_string_property;
- uint32_t automatic_integer_property;
-};
-
-static int something_handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- struct context *c = userdata;
- const char *s;
- char *n = NULL;
- int r;
-
- r = sd_bus_message_read(m, "s", &s);
- assert_se(r > 0);
-
- n = strjoin("<<<", s, ">>>", NULL);
- assert_se(n);
-
- free(c->something);
- c->something = n;
-
- log_info("AlterSomething() called, got %s, returning %s", s, n);
-
- /* This should fail, since the return type doesn't match */
- assert_se(sd_bus_reply_method_return(m, "u", 4711) == -ENOMSG);
-
- r = sd_bus_reply_method_return(m, "s", n);
- assert_se(r >= 0);
-
- return 1;
-}
-
-static int exit_handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- struct context *c = userdata;
- int r;
-
- c->quit = true;
-
- log_info("Exit called");
-
- r = sd_bus_reply_method_return(m, "");
- assert_se(r >= 0);
-
- return 1;
-}
-
-static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
- struct context *c = userdata;
- int r;
-
- log_info("property get for %s called, returning \"%s\".", property, c->something);
-
- r = sd_bus_message_append(reply, "s", c->something);
- assert_se(r >= 0);
-
- return 1;
-}
-
-static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error) {
- struct context *c = userdata;
- const char *s;
- char *n;
- int r;
-
- log_info("property set for %s called", property);
-
- r = sd_bus_message_read(value, "s", &s);
- assert_se(r >= 0);
-
- n = strdup(s);
- assert_se(n);
-
- free(c->something);
- c->something = n;
-
- return 1;
-}
-
-static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *s = NULL;
- int r;
-
- assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
- r = sd_bus_message_append(reply, "s", s);
- assert_se(r >= 0);
-
- assert_se(startswith(path, "/value/") != NULL || strcmp(path, "/value") == 0);
-
- assert_se(PTR_TO_UINT(userdata) == 30);
-
- return 1;
-}
-
-static int notify_test(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- int r;
-
- assert_se(sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
-
- r = sd_bus_reply_method_return(m, NULL);
- assert_se(r >= 0);
-
- return 1;
-}
-
-static int notify_test2(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- int r;
-
- assert_se(sd_bus_emit_properties_changed_strv(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
-
- r = sd_bus_reply_method_return(m, NULL);
- assert_se(r >= 0);
-
- return 1;
-}
-
-static int emit_interfaces_added(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- int r;
-
- assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL) >= 0);
-
- r = sd_bus_reply_method_return(m, NULL);
- assert_se(r >= 0);
-
- return 1;
-}
-
-static int emit_interfaces_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- int r;
-
- assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL) >= 0);
-
- r = sd_bus_reply_method_return(m, NULL);
- assert_se(r >= 0);
-
- return 1;
-}
-
-static int emit_object_added(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- int r;
-
- assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m), "/value/a/x") >= 0);
-
- r = sd_bus_reply_method_return(m, NULL);
- assert_se(r >= 0);
-
- return 1;
-}
-
-static int emit_object_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- int r;
-
- assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m), "/value/a/x") >= 0);
-
- r = sd_bus_reply_method_return(m, NULL);
- assert_se(r >= 0);
-
- return 1;
-}
-
-static const sd_bus_vtable vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
- SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
- SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
- SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
- SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
- SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
- SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
- SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
- SD_BUS_METHOD("EmitObjectAdded", NULL, NULL, emit_object_added, 0),
- SD_BUS_METHOD("EmitObjectRemoved", NULL, NULL, emit_object_removed, 0),
- SD_BUS_VTABLE_END
-};
-
-static const sd_bus_vtable vtable2[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
- SD_BUS_METHOD("NotifyTest2", "", "", notify_test2, 0),
- SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
- SD_BUS_VTABLE_END
-};
-
-static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
-
- if (object_path_startswith("/value", path))
- assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
-
- return 1;
-}
-
-static int enumerator2_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
-
- if (object_path_startswith("/value/a", path))
- assert_se(*nodes = strv_new("/value/a/x", "/value/a/y", "/value/a/z", NULL));
-
- return 1;
-}
-
-static void *server(void *p) {
- struct context *c = p;
- sd_bus *bus = NULL;
- sd_id128_t id;
- int r;
-
- c->quit = false;
-
- assert_se(sd_id128_randomize(&id) >= 0);
-
- assert_se(sd_bus_new(&bus) >= 0);
- assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
- assert_se(sd_bus_set_server(bus, 1, id) >= 0);
-
- assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
- assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
- assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
- assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
- assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value/a", enumerator2_callback, NULL) >= 0);
- assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
- assert_se(sd_bus_add_object_manager(bus, NULL, "/value/a") >= 0);
-
- assert_se(sd_bus_start(bus) >= 0);
-
- log_error("Entering event loop on server");
-
- while (!c->quit) {
- log_error("Loop!");
-
- r = sd_bus_process(bus, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to process requests: %m");
- goto fail;
- }
-
- if (r == 0) {
- r = sd_bus_wait(bus, (uint64_t) -1);
- if (r < 0) {
- log_error_errno(r, "Failed to wait: %m");
- goto fail;
- }
-
- continue;
- }
- }
-
- r = 0;
-
-fail:
- if (bus) {
- sd_bus_flush(bus);
- sd_bus_unref(bus);
- }
-
- return INT_TO_PTR(r);
-}
-
-static int client(struct context *c) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_bus_unref_ sd_bus *bus = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *s;
- int r;
-
- assert_se(sd_bus_new(&bus) >= 0);
- assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
- assert_se(sd_bus_start(bus) >= 0);
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
- assert_se(r >= 0);
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
- assert_se(r >= 0);
-
- r = sd_bus_message_read(reply, "s", &s);
- assert_se(r >= 0);
- assert_se(streq(s, "<<<hallo>>>"));
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
- assert_se(r < 0);
- assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
-
- sd_bus_error_free(&error);
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
- assert_se(r < 0);
- assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
-
- sd_bus_error_free(&error);
-
- r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
- assert_se(r >= 0);
-
- r = sd_bus_message_read(reply, "s", &s);
- assert_se(r >= 0);
- assert_se(streq(s, "<<<hallo>>>"));
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
- assert_se(r >= 0);
-
- r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
- assert_se(r >= 0);
-
- r = sd_bus_message_read(reply, "s", &s);
- assert_se(r >= 0);
- assert_se(streq(s, "test"));
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
- assert_se(r >= 0);
-
- assert_se(c->automatic_integer_property == 815);
-
- r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
- assert_se(r >= 0);
-
- assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
- assert_se(r >= 0);
-
- r = sd_bus_message_read(reply, "s", &s);
- assert_se(r >= 0);
- fputs(s, stdout);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
- assert_se(r >= 0);
-
- r = sd_bus_message_read(reply, "s", &s);
- assert_se(r >= 0);
- log_info("read %s", s);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
- assert_se(r >= 0);
-
- r = sd_bus_message_read(reply, "s", &s);
- assert_se(r >= 0);
- fputs(s, stdout);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
- assert_se(r >= 0);
-
- r = sd_bus_message_read(reply, "s", &s);
- assert_se(r >= 0);
- fputs(s, stdout);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
- assert_se(r >= 0);
-
- r = sd_bus_message_read(reply, "s", &s);
- assert_se(r >= 0);
- fputs(s, stdout);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
- assert_se(r >= 0);
-
- bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
- assert_se(r < 0);
- assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
- sd_bus_error_free(&error);
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
- assert_se(r < 0);
- assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
- sd_bus_error_free(&error);
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
- assert_se(r >= 0);
-
- bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
- assert_se(r >= 0);
-
- r = sd_bus_process(bus, &reply);
- assert_se(r > 0);
-
- assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
- bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
- assert_se(r >= 0);
-
- r = sd_bus_process(bus, &reply);
- assert_se(r > 0);
-
- assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
- bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
- assert_se(r >= 0);
-
- r = sd_bus_process(bus, &reply);
- assert_se(r > 0);
-
- assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
- bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
- assert_se(r >= 0);
-
- r = sd_bus_process(bus, &reply);
- assert_se(r > 0);
-
- assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
- bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, "");
- assert_se(r >= 0);
-
- r = sd_bus_process(bus, &reply);
- assert_se(r > 0);
-
- assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
- bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, "");
- assert_se(r >= 0);
-
- r = sd_bus_process(bus, &reply);
- assert_se(r > 0);
-
- assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
- bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
-
- sd_bus_message_unref(reply);
- reply = NULL;
-
- r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
- assert_se(r >= 0);
-
- sd_bus_flush(bus);
-
- return 0;
-}
-
-int main(int argc, char *argv[]) {
- struct context c = {};
- pthread_t s;
- void *p;
- int r, q;
-
- zero(c);
-
- c.automatic_integer_property = 4711;
- assert_se(c.automatic_string_property = strdup("dudeldu"));
-
- assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
-
- r = pthread_create(&s, NULL, server, &c);
- if (r != 0)
- return -r;
-
- r = client(&c);
-
- q = pthread_join(s, &p);
- if (q != 0)
- return -q;
-
- if (r < 0)
- return r;
-
- if (PTR_TO_INT(p) < 0)
- return PTR_TO_INT(p);
-
- free(c.something);
- free(c.automatic_string_property);
-
- return EXIT_SUCCESS;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-
-#include "log.h"
-#include "bus-signature.h"
-#include "bus-internal.h"
-
-int main(int argc, char *argv[]) {
- char prefix[256];
- int r;
-
- assert_se(signature_is_single("y", false));
- assert_se(signature_is_single("u", false));
- assert_se(signature_is_single("v", false));
- assert_se(signature_is_single("as", false));
- assert_se(signature_is_single("(ss)", false));
- assert_se(signature_is_single("()", false));
- assert_se(signature_is_single("(()()()()())", false));
- assert_se(signature_is_single("(((())))", false));
- assert_se(signature_is_single("((((s))))", false));
- assert_se(signature_is_single("{ss}", true));
- assert_se(signature_is_single("a{ss}", false));
- assert_se(!signature_is_single("uu", false));
- assert_se(!signature_is_single("", false));
- assert_se(!signature_is_single("(", false));
- assert_se(!signature_is_single(")", false));
- assert_se(!signature_is_single("())", false));
- assert_se(!signature_is_single("((())", false));
- assert_se(!signature_is_single("{)", false));
- assert_se(!signature_is_single("{}", true));
- assert_se(!signature_is_single("{sss}", true));
- assert_se(!signature_is_single("{s}", true));
- assert_se(!signature_is_single("{ss}", false));
- assert_se(!signature_is_single("{ass}", true));
- assert_se(!signature_is_single("a}", true));
-
- assert_se(signature_is_pair("yy"));
- assert_se(signature_is_pair("ss"));
- assert_se(signature_is_pair("sas"));
- assert_se(signature_is_pair("sv"));
- assert_se(signature_is_pair("sa(vs)"));
- assert_se(!signature_is_pair(""));
- assert_se(!signature_is_pair("va"));
- assert_se(!signature_is_pair("sss"));
- assert_se(!signature_is_pair("{s}ss"));
-
- assert_se(signature_is_valid("ssa{ss}sssub", true));
- assert_se(signature_is_valid("ssa{ss}sssub", false));
- assert_se(signature_is_valid("{ss}", true));
- assert_se(!signature_is_valid("{ss}", false));
- assert_se(signature_is_valid("", true));
- assert_se(signature_is_valid("", false));
-
- assert_se(signature_is_valid("sssusa(uuubbba(uu)uuuu)a{u(uuuvas)}", false));
-
- assert_se(!signature_is_valid("a", false));
- assert_se(signature_is_valid("as", false));
- assert_se(signature_is_valid("aas", false));
- assert_se(signature_is_valid("aaas", false));
- assert_se(signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaad", false));
- assert_se(signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaas", false));
- assert_se(!signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaau", false));
-
- assert_se(signature_is_valid("(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))", false));
- assert_se(!signature_is_valid("((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))", false));
-
- assert_se(namespace_complex_pattern("", ""));
- assert_se(namespace_complex_pattern("foobar", "foobar"));
- assert_se(namespace_complex_pattern("foobar.waldo", "foobar.waldo"));
- assert_se(namespace_complex_pattern("foobar.", "foobar.waldo"));
- assert_se(namespace_complex_pattern("foobar.waldo", "foobar."));
- assert_se(!namespace_complex_pattern("foobar.waldo", "foobar"));
- assert_se(!namespace_complex_pattern("foobar", "foobar.waldo"));
- assert_se(!namespace_complex_pattern("", "foo"));
- assert_se(!namespace_complex_pattern("foo", ""));
- assert_se(!namespace_complex_pattern("foo.", ""));
-
- assert_se(path_complex_pattern("", ""));
- assert_se(!path_complex_pattern("", "/"));
- assert_se(!path_complex_pattern("/", ""));
- assert_se(path_complex_pattern("/", "/"));
- assert_se(path_complex_pattern("/foobar/", "/"));
- assert_se(!path_complex_pattern("/foobar/", "/foobar"));
- assert_se(path_complex_pattern("/foobar", "/foobar"));
- assert_se(!path_complex_pattern("/foobar", "/foobar/"));
- assert_se(!path_complex_pattern("/foobar", "/foobar/waldo"));
- assert_se(path_complex_pattern("/foobar/", "/foobar/waldo"));
- assert_se(path_complex_pattern("/foobar/waldo", "/foobar/"));
-
- assert_se(path_simple_pattern("/foo/", "/foo/bar/waldo"));
-
- assert_se(namespace_simple_pattern("", ""));
- assert_se(namespace_simple_pattern("", ".foobar"));
- assert_se(namespace_simple_pattern("foobar", "foobar"));
- assert_se(namespace_simple_pattern("foobar.waldo", "foobar.waldo"));
- assert_se(namespace_simple_pattern("foobar", "foobar.waldo"));
- assert_se(!namespace_simple_pattern("foobar.waldo", "foobar"));
- assert_se(!namespace_simple_pattern("", "foo"));
- assert_se(!namespace_simple_pattern("foo", ""));
- assert_se(namespace_simple_pattern("foo.", "foo.bar.waldo"));
-
- assert_se(streq(object_path_startswith("/foo/bar", "/foo"), "bar"));
- assert_se(streq(object_path_startswith("/foo", "/foo"), ""));
- assert_se(streq(object_path_startswith("/foo", "/"), "foo"));
- assert_se(streq(object_path_startswith("/", "/"), ""));
- assert_se(!object_path_startswith("/foo", "/bar"));
- assert_se(!object_path_startswith("/", "/bar"));
- assert_se(!object_path_startswith("/foo", ""));
-
- assert_se(object_path_is_valid("/foo/bar"));
- assert_se(object_path_is_valid("/foo"));
- assert_se(object_path_is_valid("/"));
- assert_se(object_path_is_valid("/foo5"));
- assert_se(object_path_is_valid("/foo_5"));
- assert_se(!object_path_is_valid(""));
- assert_se(!object_path_is_valid("/foo/"));
- assert_se(!object_path_is_valid("//"));
- assert_se(!object_path_is_valid("//foo"));
- assert_se(!object_path_is_valid("/foo//bar"));
- assert_se(!object_path_is_valid("/foo/aaaäöä"));
-
- OBJECT_PATH_FOREACH_PREFIX(prefix, "/") {
- log_info("<%s>", prefix);
- assert_not_reached("???");
- }
-
- r = 0;
- OBJECT_PATH_FOREACH_PREFIX(prefix, "/xxx") {
- log_info("<%s>", prefix);
- assert_se(streq(prefix, "/"));
- assert_se(r == 0);
- r++;
- }
- assert_se(r == 1);
-
- r = 0;
- OBJECT_PATH_FOREACH_PREFIX(prefix, "/xxx/yyy/zzz") {
- log_info("<%s>", prefix);
- assert_se(r != 0 || streq(prefix, "/xxx/yyy"));
- assert_se(r != 1 || streq(prefix, "/xxx"));
- assert_se(r != 2 || streq(prefix, "/"));
- r++;
- }
- assert_se(r == 3);
-
- return 0;
-}
-../Makefile
\ No newline at end of file
+../../Makefile
\ No newline at end of file
+++ /dev/null
-/***
- This file is part of systemd.
-
- Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
- Copyright 2014 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <ctype.h>
-#include <sys/types.h>
-#include <net/if.h>
-
-#include "util.h"
-#include "macro.h"
-#include "path-util.h"
-#include "strxcpyx.h"
-#include "fileio.h"
-#include "hashmap.h"
-#include "set.h"
-#include "strv.h"
-
-#include "sd-device.h"
-
-#include "device-util.h"
-#include "device-private.h"
-#include "device-internal.h"
-
-int device_new_aux(sd_device **ret) {
- _cleanup_device_unref_ sd_device *device = NULL;
-
- assert(ret);
-
- device = new0(sd_device, 1);
- if (!device)
- return -ENOMEM;
-
- device->n_ref = 1;
- device->watch_handle = -1;
-
- *ret = device;
- device = NULL;
-
- return 0;
-}
-
-_public_ sd_device *sd_device_ref(sd_device *device) {
- if (device)
- assert_se(++ device->n_ref >= 2);
-
- return device;
-}
-
-_public_ sd_device *sd_device_unref(sd_device *device) {
- if (device && -- device->n_ref == 0) {
- sd_device_unref(device->parent);
- free(device->syspath);
- free(device->sysname);
- free(device->devtype);
- free(device->devname);
- free(device->subsystem);
- free(device->driver);
- free(device->id_filename);
- free(device->properties_strv);
- free(device->properties_nulstr);
-
- ordered_hashmap_free_free_free(device->properties);
- ordered_hashmap_free_free_free(device->properties_db);
- hashmap_free_free_free(device->sysattr_values);
- set_free_free(device->sysattrs);
- set_free_free(device->tags);
- set_free_free(device->devlinks);
-
- free(device);
- }
-
- return NULL;
-}
-
-int device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
- OrderedHashmap **properties;
-
- assert(device);
- assert(_key);
-
- if (db)
- properties = &device->properties_db;
- else
- properties = &device->properties;
-
- if (_value) {
- _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
- int r;
-
- r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
- if (r < 0)
- return r;
-
- key = strdup(_key);
- if (!key)
- return -ENOMEM;
-
- value = strdup(_value);
- if (!value)
- return -ENOMEM;
-
- old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
-
- r = ordered_hashmap_replace(*properties, key, value);
- if (r < 0)
- return r;
-
- key = NULL;
- value = NULL;
- } else {
- _cleanup_free_ char *key = NULL;
- _cleanup_free_ char *value = NULL;
-
- value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
- }
-
- if (!db) {
- device->properties_generation ++;
- device->properties_buf_outdated = true;
- }
-
- return 0;
-}
-
-int device_add_property_internal(sd_device *device, const char *key, const char *value) {
- return device_add_property_aux(device, key, value, false);
-}
-
-int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
- _cleanup_free_ char *syspath = NULL;
- const char *devpath;
- int r;
-
- assert(device);
- assert(_syspath);
-
- /* must be a subdirectory of /sys */
- if (!path_startswith(_syspath, "/sys/")) {
- log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
- return -EINVAL;
- }
-
- if (verify) {
- r = readlink_and_canonicalize(_syspath, &syspath);
- if (r == -ENOENT)
- /* the device does not exist (any more?) */
- return -ENODEV;
- else if (r == -EINVAL) {
- /* not a symlink */
- syspath = canonicalize_file_name(_syspath);
- if (!syspath) {
- if (errno == ENOENT)
- /* the device does not exist (any more?) */
- return -ENODEV;
-
- log_debug("sd-device: could not canonicalize '%s': %m", _syspath);
- return -errno;
- }
- } else if (r < 0) {
- log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r));
- return r;
- }
-
- if (path_startswith(syspath, "/sys/devices/")) {
- char *path;
-
- /* all 'devices' require an 'uevent' file */
- path = strjoina(syspath, "/uevent");
- r = access(path, F_OK);
- if (r < 0) {
- if (errno == ENOENT)
- /* this is not a valid device */
- return -ENODEV;
-
- log_debug("sd-device: %s does not have an uevent file: %m", syspath);
- return -errno;
- }
- } else {
- /* everything else just just needs to be a directory */
- if (!is_dir(syspath, false))
- return -ENODEV;
- }
- } else {
- syspath = strdup(_syspath);
- if (!syspath)
- return -ENOMEM;
- }
-
- devpath = syspath + strlen("/sys");
-
- r = device_add_property_internal(device, "DEVPATH", devpath);
- if (r < 0)
- return r;
-
- free(device->syspath);
- device->syspath = syspath;
- syspath = NULL;
-
- device->devpath = devpath;
-
- return 0;
-}
-
-_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
- _cleanup_device_unref_ sd_device *device = NULL;
- int r;
-
- assert_return(ret, -EINVAL);
- assert_return(syspath, -EINVAL);
-
- r = device_new_aux(&device);
- if (r < 0)
- return r;
-
- r = device_set_syspath(device, syspath, true);
- if (r < 0)
- return r;
-
- *ret = device;
- device = NULL;
-
- return 0;
-}
-
-_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
- char *syspath;
- char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
-
- assert_return(ret, -EINVAL);
- assert_return(type == 'b' || type == 'c', -EINVAL);
-
- /* use /sys/dev/{block,char}/<maj>:<min> link */
- snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
-
- syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
-
- return sd_device_new_from_syspath(ret, syspath);
-}
-
-_public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
- char *syspath;
-
- assert_return(ret, -EINVAL);
- assert_return(subsystem, -EINVAL);
- assert_return(sysname, -EINVAL);
-
- if (streq(subsystem, "subsystem")) {
- syspath = strjoina("/sys/subsystem/", sysname);
- if (access(syspath, F_OK) >= 0)
- return sd_device_new_from_syspath(ret, syspath);
-
- syspath = strjoina("/sys/bus/", sysname);
- if (access(syspath, F_OK) >= 0)
- return sd_device_new_from_syspath(ret, syspath);
-
- syspath = strjoina("/sys/class/", sysname);
- if (access(syspath, F_OK) >= 0)
- return sd_device_new_from_syspath(ret, syspath);
- } else if (streq(subsystem, "module")) {
- syspath = strjoina("/sys/module/", sysname);
- if (access(syspath, F_OK) >= 0)
- return sd_device_new_from_syspath(ret, syspath);
- } else if (streq(subsystem, "drivers")) {
- char subsys[PATH_MAX];
- char *driver;
-
- strscpy(subsys, sizeof(subsys), sysname);
- driver = strchr(subsys, ':');
- if (driver) {
- driver[0] = '\0';
- driver++;
-
- syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
- if (access(syspath, F_OK) >= 0)
- return sd_device_new_from_syspath(ret, syspath);
-
- syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
- if (access(syspath, F_OK) >= 0)
- return sd_device_new_from_syspath(ret, syspath);
- } else
- return -EINVAL;
- } else {
- syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname);
- if (access(syspath, F_OK) >= 0)
- return sd_device_new_from_syspath(ret, syspath);
-
- syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname);
- if (access(syspath, F_OK) >= 0)
- return sd_device_new_from_syspath(ret, syspath);
-
- syspath = strjoina("/sys/class/", subsystem, "/", sysname);
- if (access(syspath, F_OK) >= 0)
- return sd_device_new_from_syspath(ret, syspath);
- }
-
- return -ENODEV;
-}
-
-int device_set_devtype(sd_device *device, const char *_devtype) {
- _cleanup_free_ char *devtype = NULL;
- int r;
-
- assert(device);
- assert(_devtype);
-
- devtype = strdup(_devtype);
- if (!devtype)
- return -ENOMEM;
-
- r = device_add_property_internal(device, "DEVTYPE", devtype);
- if (r < 0)
- return r;
-
- free(device->devtype);
- device->devtype = devtype;
- devtype = NULL;
-
- return 0;
-}
-
-int device_set_ifindex(sd_device *device, const char *_ifindex) {
- int ifindex, r;
-
- assert(device);
- assert(_ifindex);
-
- r = safe_atoi(_ifindex, &ifindex);
- if (r < 0)
- return r;
-
- if (ifindex <= 0)
- return -EINVAL;
-
- r = device_add_property_internal(device, "IFINDEX", _ifindex);
- if (r < 0)
- return r;
-
- device->ifindex = ifindex;
-
- return 0;
-}
-
-int device_set_devname(sd_device *device, const char *_devname) {
- _cleanup_free_ char *devname = NULL;
- int r;
-
- assert(device);
- assert(_devname);
-
- if (_devname[0] != '/') {
- r = asprintf(&devname, "/dev/%s", _devname);
- if (r < 0)
- return -ENOMEM;
- } else {
- devname = strdup(_devname);
- if (!devname)
- return -ENOMEM;
- }
-
- r = device_add_property_internal(device, "DEVNAME", devname);
- if (r < 0)
- return r;
-
- free(device->devname);
- device->devname = devname;
- devname = NULL;
-
- return 0;
-}
-
-int device_set_devmode(sd_device *device, const char *_devmode) {
- unsigned devmode;
- int r;
-
- assert(device);
- assert(_devmode);
-
- r = safe_atou(_devmode, &devmode);
- if (r < 0)
- return r;
-
- if (devmode > 07777)
- return -EINVAL;
-
- r = device_add_property_internal(device, "DEVMODE", _devmode);
- if (r < 0)
- return r;
-
- device->devmode = devmode;
-
- return 0;
-}
-
-int device_set_devnum(sd_device *device, const char *major, const char *minor) {
- unsigned maj = 0, min = 0;
- int r;
-
- assert(device);
- assert(major);
-
- r = safe_atou(major, &maj);
- if (r < 0)
- return r;
- if (!maj)
- return 0;
-
- if (minor) {
- r = safe_atou(minor, &min);
- if (r < 0)
- return r;
- }
-
- r = device_add_property_internal(device, "MAJOR", major);
- if (r < 0)
- return r;
-
- if (minor) {
- r = device_add_property_internal(device, "MINOR", minor);
- if (r < 0)
- return r;
- }
-
- device->devnum = makedev(maj, min);
-
- return 0;
-}
-
-static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
- int r;
-
- assert(device);
- assert(key);
- assert(value);
- assert(major);
- assert(minor);
-
- if (streq(key, "DEVTYPE")) {
- r = device_set_devtype(device, value);
- if (r < 0)
- return r;
- } else if (streq(key, "IFINDEX")) {
- r = device_set_ifindex(device, value);
- if (r < 0)
- return r;
- } else if (streq(key, "DEVNAME")) {
- r = device_set_devname(device, value);
- if (r < 0)
- return r;
- } else if (streq(key, "DEVMODE")) {
- r = device_set_devmode(device, value);
- if (r < 0)
- return r;
- } else if (streq(key, "MAJOR"))
- *major = value;
- else if (streq(key, "MINOR"))
- *minor = value;
- else {
- r = device_add_property_internal(device, key, value);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int device_read_uevent_file(sd_device *device) {
- _cleanup_free_ char *uevent = NULL;
- const char *syspath, *key, *value, *major = NULL, *minor = NULL;
- char *path;
- size_t uevent_len;
- unsigned i;
- int r;
-
- enum {
- PRE_KEY,
- KEY,
- PRE_VALUE,
- VALUE,
- INVALID_LINE,
- } state = PRE_KEY;
-
- assert(device);
-
- if (device->uevent_loaded || device->sealed)
- return 0;
-
- device->uevent_loaded = true;
-
- r = sd_device_get_syspath(device, &syspath);
- if (r < 0)
- return r;
-
- path = strjoina(syspath, "/uevent");
-
- r = read_full_file(path, &uevent, &uevent_len);
- if (r == -EACCES)
- /* empty uevent files may be write-only */
- return 0;
- else if (r == -ENOENT)
- /* some devices may not have uevent files, see set_syspath() */
- return 0;
- else if (r < 0) {
- log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
- return r;
- }
-
- for (i = 0; i < uevent_len; i++) {
- switch (state) {
- case PRE_KEY:
- if (!strchr(NEWLINE, uevent[i])) {
- key = &uevent[i];
-
- state = KEY;
- }
-
- break;
- case KEY:
- if (uevent[i] == '=') {
- uevent[i] = '\0';
-
- state = PRE_VALUE;
- } else if (strchr(NEWLINE, uevent[i])) {
- uevent[i] = '\0';
- log_debug("sd-device: ignoring invalid uevent line '%s'", key);
-
- state = PRE_KEY;
- }
-
- break;
- case PRE_VALUE:
- value = &uevent[i];
-
- state = VALUE;
-
- break;
- case VALUE:
- if (strchr(NEWLINE, uevent[i])) {
- uevent[i] = '\0';
-
- r = handle_uevent_line(device, key, value, &major, &minor);
- if (r < 0)
- log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
-
- state = PRE_KEY;
- }
-
- break;
- default:
- assert_not_reached("invalid state when parsing uevent file");
- }
- }
-
- if (major) {
- r = device_set_devnum(device, major, minor);
- if (r < 0)
- log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
- }
-
- return 0;
-}
-
-_public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
- int r;
-
- assert_return(device, -EINVAL);
- assert_return(ifindex, -EINVAL);
-
- r = device_read_uevent_file(device);
- if (r < 0)
- return r;
-
- *ifindex = device->ifindex;
-
- return 0;
-}
-
-_public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
- int r;
-
- assert_return(ret, -EINVAL);
- assert_return(id, -EINVAL);
-
- switch (id[0]) {
- case 'b':
- case 'c':
- {
- char type;
- int maj, min;
-
- r = sscanf(id, "%c%i:%i", &type, &maj, &min);
- if (r != 3)
- return -EINVAL;
-
- return sd_device_new_from_devnum(ret, type, makedev(maj, min));
- }
- case 'n':
- {
- _cleanup_device_unref_ sd_device *device = NULL;
- _cleanup_close_ int sk = -1;
- struct ifreq ifr = {};
- int ifindex;
-
- r = safe_atoi(&id[1], &ifr.ifr_ifindex);
- if (r < 0)
- return r;
- else if (ifr.ifr_ifindex <= 0)
- return -EINVAL;
-
- sk = socket(PF_INET, SOCK_DGRAM, 0);
- if (sk < 0)
- return -errno;
-
- r = ioctl(sk, SIOCGIFNAME, &ifr);
- if (r < 0)
- return -errno;
-
- r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
- if (r < 0)
- return r;
-
- r = sd_device_get_ifindex(device, &ifindex);
- if (r < 0)
- return r;
-
- /* this is racey, so we might end up with the wrong device */
- if (ifr.ifr_ifindex != ifindex)
- return -ENODEV;
-
- *ret = device;
- device = NULL;
-
- return 0;
- }
- case '+':
- {
- char subsys[PATH_MAX];
- char *sysname;
-
- (void)strscpy(subsys, sizeof(subsys), id + 1);
- sysname = strchr(subsys, ':');
- if (!sysname)
- return -EINVAL;
-
- sysname[0] = '\0';
- sysname ++;
-
- return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
- }
- default:
- return -EINVAL;
- }
-}
-
-_public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
- assert_return(device, -EINVAL);
- assert_return(ret, -EINVAL);
-
- assert(path_startswith(device->syspath, "/sys/"));
-
- *ret = device->syspath;
-
- return 0;
-}
-
-static int device_new_from_child(sd_device **ret, sd_device *child) {
- _cleanup_free_ char *path = NULL;
- const char *subdir, *syspath;
- int r;
-
- assert(ret);
- assert(child);
-
- r = sd_device_get_syspath(child, &syspath);
- if (r < 0)
- return r;
-
- path = strdup(syspath);
- if (!path)
- return -ENOMEM;
- subdir = path + strlen("/sys");
-
- for (;;) {
- char *pos;
-
- pos = strrchr(subdir, '/');
- if (!pos || pos < subdir + 2)
- break;
-
- *pos = '\0';
-
- r = sd_device_new_from_syspath(ret, path);
- if (r < 0)
- continue;
-
- return 0;
- }
-
- return -ENODEV;
-}
-
-_public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
-
- assert_return(ret, -EINVAL);
- assert_return(child, -EINVAL);
-
- if (!child->parent_set) {
- child->parent_set = true;
-
- (void)device_new_from_child(&child->parent, child);
- }
-
- if (!child->parent)
- return -ENOENT;
-
- *ret = child->parent;
-
- return 0;
-}
-
-int device_set_subsystem(sd_device *device, const char *_subsystem) {
- _cleanup_free_ char *subsystem = NULL;
- int r;
-
- assert(device);
- assert(_subsystem);
-
- subsystem = strdup(_subsystem);
- if (!subsystem)
- return -ENOMEM;
-
- r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
- if (r < 0)
- return r;
-
- free(device->subsystem);
- device->subsystem = subsystem;
- subsystem = NULL;
-
- device->subsystem_set = true;
-
- return 0;
-}
-
-_public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
- assert_return(ret, -EINVAL);
- assert_return(device, -EINVAL);
-
- if (!device->subsystem_set) {
- _cleanup_free_ char *subsystem = NULL;
- const char *syspath;
- char *path;
- int r;
-
- /* read 'subsystem' link */
- r = sd_device_get_syspath(device, &syspath);
- if (r < 0)
- return r;
-
- path = strjoina(syspath, "/subsystem");
- r = readlink_value(path, &subsystem);
- if (r >= 0)
- r = device_set_subsystem(device, subsystem);
- /* use implicit names */
- else if (path_startswith(device->devpath, "/module/"))
- r = device_set_subsystem(device, "module");
- else if (strstr(device->devpath, "/drivers/"))
- r = device_set_subsystem(device, "drivers");
- else if (path_startswith(device->devpath, "/subsystem/") ||
- path_startswith(device->devpath, "/class/") ||
- path_startswith(device->devpath, "/bus/"))
- r = device_set_subsystem(device, "subsystem");
- if (r < 0 && r != -ENOENT)
- return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
-
- device->subsystem_set = true;
- }
-
- if (!device->subsystem)
- return -ENOENT;
-
- *ret = device->subsystem;
-
- return 0;
-}
-
-_public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
- int r;
-
- assert(devtype);
- assert(device);
-
- r = device_read_uevent_file(device);
- if (r < 0)
- return r;
-
- *devtype = device->devtype;
-
- return 0;
-}
-
-_public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
- sd_device *parent = NULL;
- int r;
-
- assert_return(child, -EINVAL);
- assert_return(subsystem, -EINVAL);
-
- r = sd_device_get_parent(child, &parent);
- while (r >= 0) {
- const char *parent_subsystem = NULL;
- const char *parent_devtype = NULL;
-
- (void)sd_device_get_subsystem(parent, &parent_subsystem);
- if (streq_ptr(parent_subsystem, subsystem)) {
- if (!devtype)
- break;
-
- (void)sd_device_get_devtype(parent, &parent_devtype);
- if (streq_ptr(parent_devtype, devtype))
- break;
- }
- r = sd_device_get_parent(parent, &parent);
- }
-
- if (r < 0)
- return r;
-
- *ret = parent;
-
- return 0;
-}
-
-_public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
- int r;
-
- assert_return(device, -EINVAL);
- assert_return(devnum, -EINVAL);
-
- r = device_read_uevent_file(device);
- if (r < 0)
- return r;
-
- *devnum = device->devnum;
-
- return 0;
-}
-
-int device_set_driver(sd_device *device, const char *_driver) {
- _cleanup_free_ char *driver = NULL;
- int r;
-
- assert(device);
- assert(_driver);
-
- driver = strdup(_driver);
- if (!driver)
- return -ENOMEM;
-
- r = device_add_property_internal(device, "DRIVER", driver);
- if (r < 0)
- return r;
-
- free(device->driver);
- device->driver = driver;
- driver = NULL;
-
- device->driver_set = true;
-
- return 0;
-}
-
-_public_ int sd_device_get_driver(sd_device *device, const char **ret) {
- assert_return(device, -EINVAL);
- assert_return(ret, -EINVAL);
-
- if (!device->driver_set) {
- _cleanup_free_ char *driver = NULL;
- const char *syspath;
- char *path;
- int r;
-
- r = sd_device_get_syspath(device, &syspath);
- if (r < 0)
- return r;
-
- path = strjoina(syspath, "/driver");
- r = readlink_value(path, &driver);
- if (r >= 0) {
- r = device_set_driver(device, driver);
- if (r < 0)
- return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
- } else if (r == -ENOENT)
- device->driver_set = true;
- else
- return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
- }
-
- if (!device->driver)
- return -ENOENT;
-
- *ret = device->driver;
-
- return 0;
-}
-
-_public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
- assert_return(device, -EINVAL);
- assert_return(devpath, -EINVAL);
-
- assert(device->devpath);
- assert(device->devpath[0] == '/');
-
- *devpath = device->devpath;
-
- return 0;
-}
-
-_public_ int sd_device_get_devname(sd_device *device, const char **devname) {
- int r;
-
- assert_return(device, -EINVAL);
- assert_return(devname, -EINVAL);
-
- r = device_read_uevent_file(device);
- if (r < 0)
- return r;
-
- if (!device->devname)
- return -ENOENT;
-
- assert(path_startswith(device->devname, "/dev/"));
-
- *devname = device->devname;
-
- return 0;
-}
-
-static int device_set_sysname(sd_device *device) {
- _cleanup_free_ char *sysname = NULL;
- const char *sysnum = NULL;
- const char *pos;
- size_t len = 0;
-
- pos = strrchr(device->devpath, '/');
- if (!pos)
- return -EINVAL;
- pos ++;
-
- /* devpath is not a root directory */
- if (*pos == '\0' || pos <= device->devpath)
- return -EINVAL;
-
- sysname = strdup(pos);
- if (!sysname)
- return -ENOMEM;
-
- /* some devices have '!' in their name, change that to '/' */
- while (sysname[len] != '\0') {
- if (sysname[len] == '!')
- sysname[len] = '/';
-
- len ++;
- }
-
- /* trailing number */
- while (len > 0 && isdigit(sysname[--len]))
- sysnum = &sysname[len];
-
- if (len == 0)
- sysnum = NULL;
-
- free(device->sysname);
- device->sysname = sysname;
- sysname = NULL;
-
- device->sysnum = sysnum;
-
- device->sysname_set = true;
-
- return 0;
-}
-
-_public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
- int r;
-
- assert_return(device, -EINVAL);
- assert_return(ret, -EINVAL);
-
- if (!device->sysname_set) {
- r = device_set_sysname(device);
- if (r < 0)
- return r;
- }
-
- assert_return(device->sysname, -ENOENT);
-
- *ret = device->sysname;
-
- return 0;
-}
-
-_public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
- int r;
-
- assert_return(device, -EINVAL);
- assert_return(ret, -EINVAL);
-
- if (!device->sysname_set) {
- r = device_set_sysname(device);
- if (r < 0)
- return r;
- }
-
- *ret = device->sysnum;
-
- return 0;
-}
-
-static bool is_valid_tag(const char *tag) {
- assert(tag);
-
- return !strchr(tag, ':') && !strchr(tag, ' ');
-}
-
-int device_add_tag(sd_device *device, const char *tag) {
- int r;
-
- assert(device);
- assert(tag);
-
- if (!is_valid_tag(tag))
- return -EINVAL;
-
- r = set_ensure_allocated(&device->tags, &string_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put_strdup(device->tags, tag);
- if (r < 0)
- return r;
-
- device->tags_generation ++;
- device->property_tags_outdated = true;
-
- return 0;
-}
-
-int device_add_devlink(sd_device *device, const char *devlink) {
- int r;
-
- assert(device);
- assert(devlink);
-
- r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
- if (r < 0)
- return r;
-
- r = set_put_strdup(device->devlinks, devlink);
- if (r < 0)
- return r;
-
- device->devlinks_generation ++;
- device->property_devlinks_outdated = true;
-
- return 0;
-}
-
-static int device_add_property_internal_from_string(sd_device *device, const char *str) {
- _cleanup_free_ char *key = NULL;
- char *value;
-
- assert(device);
- assert(str);
-
- key = strdup(str);
- if (!key)
- return -ENOMEM;
-
- value = strchr(key, '=');
- if (!value)
- return -EINVAL;
-
- *value = '\0';
-
- if (isempty(++value))
- value = NULL;
-
- return device_add_property_internal(device, key, value);
-}
-
-int device_set_usec_initialized(sd_device *device, const char *initialized) {
- uint64_t usec_initialized;
- int r;
-
- assert(device);
- assert(initialized);
-
- r = safe_atou64(initialized, &usec_initialized);
- if (r < 0)
- return r;
-
- r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
- if (r < 0)
- return r;
-
- device->usec_initialized = usec_initialized;
-
- return 0;
-}
-
-static int handle_db_line(sd_device *device, char key, const char *value) {
- char *path;
- int r;
-
- assert(device);
- assert(value);
-
- switch (key) {
- case 'G':
- r = device_add_tag(device, value);
- if (r < 0)
- return r;
-
- break;
- case 'S':
- path = strjoina("/dev/", value);
- r = device_add_devlink(device, path);
- if (r < 0)
- return r;
-
- break;
- case 'E':
- r = device_add_property_internal_from_string(device, value);
- if (r < 0)
- return r;
-
- break;
- case 'I':
- r = device_set_usec_initialized(device, value);
- if (r < 0)
- return r;
-
- break;
- case 'L':
- r = safe_atoi(value, &device->devlink_priority);
- if (r < 0)
- return r;
-
- break;
- case 'W':
- r = safe_atoi(value, &device->watch_handle);
- if (r < 0)
- return r;
-
- break;
- default:
- log_debug("device db: unknown key '%c'", key);
- }
-
- return 0;
-}
-
-int device_get_id_filename(sd_device *device, const char **ret) {
- assert(device);
- assert(ret);
-
- if (!device->id_filename) {
- _cleanup_free_ char *id = NULL;
- const char *subsystem;
- dev_t devnum;
- int ifindex, r;
-
- r = sd_device_get_subsystem(device, &subsystem);
- if (r < 0)
- return r;
-
- r = sd_device_get_devnum(device, &devnum);
- if (r < 0)
- return r;
-
- r = sd_device_get_ifindex(device, &ifindex);
- if (r < 0)
- return r;
-
- if (major(devnum) > 0) {
- assert(subsystem);
-
- /* use dev_t -- b259:131072, c254:0 */
- r = asprintf(&id, "%c%u:%u",
- streq(subsystem, "block") ? 'b' : 'c',
- major(devnum), minor(devnum));
- if (r < 0)
- return -ENOMEM;
- } else if (ifindex > 0) {
- /* use netdev ifindex -- n3 */
- r = asprintf(&id, "n%u", ifindex);
- if (r < 0)
- return -ENOMEM;
- } else {
- /* use $subsys:$sysname -- pci:0000:00:1f.2
- * sysname() has '!' translated, get it from devpath
- */
- const char *sysname;
-
- sysname = basename(device->devpath);
- if (!sysname)
- return -EINVAL;
-
- if (!subsystem)
- return -EINVAL;
-
- r = asprintf(&id, "+%s:%s", subsystem, sysname);
- if (r < 0)
- return -ENOMEM;
- }
-
- device->id_filename = id;
- id = NULL;
- }
-
- *ret = device->id_filename;
-
- return 0;
-}
-
-int device_read_db_aux(sd_device *device, bool force) {
- _cleanup_free_ char *db = NULL;
- char *path;
- const char *id, *value;
- char key;
- size_t db_len;
- unsigned i;
- int r;
-
- enum {
- PRE_KEY,
- KEY,
- PRE_VALUE,
- VALUE,
- INVALID_LINE,
- } state = PRE_KEY;
-
- if (device->db_loaded || (!force && device->sealed))
- return 0;
-
- device->db_loaded = true;
-
- r = device_get_id_filename(device, &id);
- if (r < 0)
- return r;
-
- path = strjoina("/run/udev/data/", id);
-
- r = read_full_file(path, &db, &db_len);
- if (r < 0) {
- if (r == -ENOENT)
- return 0;
- else {
- log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
- return r;
- }
- }
-
- /* devices with a database entry are initialized */
- device->is_initialized = true;
-
- for (i = 0; i < db_len; i++) {
- switch (state) {
- case PRE_KEY:
- if (!strchr(NEWLINE, db[i])) {
- key = db[i];
-
- state = KEY;
- }
-
- break;
- case KEY:
- if (db[i] != ':') {
- log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
-
- state = INVALID_LINE;
- } else {
- db[i] = '\0';
-
- state = PRE_VALUE;
- }
-
- break;
- case PRE_VALUE:
- value = &db[i];
-
- state = VALUE;
-
- break;
- case INVALID_LINE:
- if (strchr(NEWLINE, db[i]))
- state = PRE_KEY;
-
- break;
- case VALUE:
- if (strchr(NEWLINE, db[i])) {
- db[i] = '\0';
- r = handle_db_line(device, key, value);
- if (r < 0)
- log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
-
- state = PRE_KEY;
- }
-
- break;
- default:
- assert_not_reached("invalid state when parsing db");
- }
- }
-
- return 0;
-}
-
-static int device_read_db(sd_device *device) {
- return device_read_db_aux(device, false);
-}
-
-_public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
- int r;
-
- assert_return(device, -EINVAL);
- assert_return(initialized, -EINVAL);
-
- r = device_read_db(device);
- if (r < 0)
- return r;
-
- *initialized = device->is_initialized;
-
- return 0;
-}
-
-_public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
- usec_t now_ts;
- int r;
-
- assert_return(device, -EINVAL);
- assert_return(usec, -EINVAL);
-
- r = device_read_db(device);
- if (r < 0)
- return r;
-
- if (!device->is_initialized)
- return -EBUSY;
-
- if (!device->usec_initialized)
- return -ENODATA;
-
- now_ts = now(clock_boottime_or_monotonic());
-
- if (now_ts < device->usec_initialized)
- return -EIO;
-
- *usec = now_ts - device->usec_initialized;
-
- return 0;
-}
-
-_public_ const char *sd_device_get_tag_first(sd_device *device) {
- void *v;
-
- assert_return(device, NULL);
-
- (void) device_read_db(device);
-
- device->tags_iterator_generation = device->tags_generation;
- device->tags_iterator = ITERATOR_FIRST;
-
- set_iterate(device->tags, &device->tags_iterator, &v);
- return v;
-}
-
-_public_ const char *sd_device_get_tag_next(sd_device *device) {
- void *v;
-
- assert_return(device, NULL);
-
- (void) device_read_db(device);
-
- if (device->tags_iterator_generation != device->tags_generation)
- return NULL;
-
- set_iterate(device->tags, &device->tags_iterator, &v);
- return v;
-}
-
-_public_ const char *sd_device_get_devlink_first(sd_device *device) {
- void *v;
-
- assert_return(device, NULL);
-
- (void) device_read_db(device);
-
- device->devlinks_iterator_generation = device->devlinks_generation;
- device->devlinks_iterator = ITERATOR_FIRST;
-
- set_iterate(device->devlinks, &device->devlinks_iterator, &v);
- return v;
-}
-
-_public_ const char *sd_device_get_devlink_next(sd_device *device) {
- void *v;
-
- assert_return(device, NULL);
-
- (void) device_read_db(device);
-
- if (device->devlinks_iterator_generation != device->devlinks_generation)
- return NULL;
-
- set_iterate(device->devlinks, &device->devlinks_iterator, &v);
- return v;
-}
-
-static int device_properties_prepare(sd_device *device) {
- int r;
-
- assert(device);
-
- r = device_read_uevent_file(device);
- if (r < 0)
- return r;
-
- r = device_read_db(device);
- if (r < 0)
- return r;
-
- if (device->property_devlinks_outdated) {
- char *devlinks = NULL;
- const char *devlink;
-
- devlink = sd_device_get_devlink_first(device);
- if (devlink)
- devlinks = strdupa(devlink);
-
- while ((devlink = sd_device_get_devlink_next(device)))
- devlinks = strjoina(devlinks, " ", devlink);
-
- r = device_add_property_internal(device, "DEVLINKS", devlinks);
- if (r < 0)
- return r;
-
- device->property_devlinks_outdated = false;
- }
-
- if (device->property_tags_outdated) {
- char *tags = NULL;
- const char *tag;
-
- tag = sd_device_get_tag_first(device);
- if (tag)
- tags = strjoina(":", tag);
-
- while ((tag = sd_device_get_tag_next(device)))
- tags = strjoina(tags, ":", tag);
-
- tags = strjoina(tags, ":");
-
- r = device_add_property_internal(device, "TAGS", tags);
- if (r < 0)
- return r;
-
- device->property_tags_outdated = false;
- }
-
- return 0;
-}
-
-_public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
- const char *key;
- const char *value;
- int r;
-
- assert_return(device, NULL);
-
- r = device_properties_prepare(device);
- if (r < 0)
- return NULL;
-
- device->properties_iterator_generation = device->properties_generation;
- device->properties_iterator = ITERATOR_FIRST;
-
- ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
-
- if (_value)
- *_value = value;
-
- return key;
-}
-
-_public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
- const char *key;
- const char *value;
- int r;
-
- assert_return(device, NULL);
-
- r = device_properties_prepare(device);
- if (r < 0)
- return NULL;
-
- if (device->properties_iterator_generation != device->properties_generation)
- return NULL;
-
- ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
-
- if (_value)
- *_value = value;
-
- return key;
-}
-
-static int device_sysattrs_read_all(sd_device *device) {
- _cleanup_closedir_ DIR *dir = NULL;
- const char *syspath;
- struct dirent *dent;
- int r;
-
- assert(device);
-
- if (device->sysattrs_read)
- return 0;
-
- r = sd_device_get_syspath(device, &syspath);
- if (r < 0)
- return r;
-
- dir = opendir(syspath);
- if (!dir)
- return -errno;
-
- r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
- if (r < 0)
- return r;
-
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
- char *path;
- struct stat statbuf;
-
- /* only handle symlinks and regular files */
- if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
- continue;
-
- path = strjoina(syspath, "/", dent->d_name);
-
- if (lstat(path, &statbuf) != 0)
- continue;
-
- if (!(statbuf.st_mode & S_IRUSR))
- continue;
-
- r = set_put_strdup(device->sysattrs, dent->d_name);
- if (r < 0)
- return r;
- }
-
- device->sysattrs_read = true;
-
- return 0;
-}
-
-_public_ const char *sd_device_get_sysattr_first(sd_device *device) {
- void *v;
- int r;
-
- assert_return(device, NULL);
-
- if (!device->sysattrs_read) {
- r = device_sysattrs_read_all(device);
- if (r < 0) {
- errno = -r;
- return NULL;
- }
- }
-
- device->sysattrs_iterator = ITERATOR_FIRST;
-
- set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
- return v;
-}
-
-_public_ const char *sd_device_get_sysattr_next(sd_device *device) {
- void *v;
-
- assert_return(device, NULL);
-
- if (!device->sysattrs_read)
- return NULL;
-
- set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
- return v;
-}
-
-_public_ int sd_device_has_tag(sd_device *device, const char *tag) {
- assert_return(device, -EINVAL);
- assert_return(tag, -EINVAL);
-
- (void) device_read_db(device);
-
- return !!set_contains(device->tags, tag);
-}
-
-_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
- char *value;
- int r;
-
- assert_return(device, -EINVAL);
- assert_return(key, -EINVAL);
- assert_return(_value, -EINVAL);
-
- r = device_properties_prepare(device);
- if (r < 0)
- return r;
-
- value = ordered_hashmap_get(device->properties, key);
- if (!value)
- return -ENOENT;
-
- *_value = value;
-
- return 0;
-}
-
-/* replaces the value if it already exists */
-static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
- _cleanup_free_ char *key = NULL;
- _cleanup_free_ char *value_old = NULL;
- int r;
-
- assert(device);
- assert(_key);
-
- r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
- if (r < 0)
- return r;
-
- value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
- if (!key) {
- key = strdup(_key);
- if (!key)
- return -ENOMEM;
- }
-
- r = hashmap_put(device->sysattr_values, key, value);
- if (r < 0)
- return r;
-
- key = NULL;
-
- return 0;
-}
-
-static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
- const char *key = NULL, *value;
-
- assert(device);
- assert(_key);
-
- value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
- if (!key)
- return -ENOENT;
-
- if (_value)
- *_value = value;
-
- return 0;
-}
-
-/* We cache all sysattr lookups. If an attribute does not exist, it is stored
- * with a NULL value in the cache, otherwise the returned string is stored */
-_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
- _cleanup_free_ char *value = NULL;
- const char *syspath, *cached_value = NULL;
- char *path;
- struct stat statbuf;
- int r;
-
- assert_return(device, -EINVAL);
- assert_return(sysattr, -EINVAL);
-
- /* look for possibly already cached result */
- r = device_get_sysattr_value(device, sysattr, &cached_value);
- if (r != -ENOENT) {
- if (r < 0)
- return r;
-
- if (!cached_value)
- /* we looked up the sysattr before and it did not exist */
- return -ENOENT;
-
- if (_value)
- *_value = cached_value;
-
- return 0;
- }
-
- r = sd_device_get_syspath(device, &syspath);
- if (r < 0)
- return r;
-
- path = strjoina(syspath, "/", sysattr);
- r = lstat(path, &statbuf);
- if (r < 0) {
- /* remember that we could not access the sysattr */
- r = device_add_sysattr_value(device, sysattr, NULL);
- if (r < 0)
- return r;
-
- return -ENOENT;
- } else if (S_ISLNK(statbuf.st_mode)) {
- /* Some core links return only the last element of the target path,
- * these are just values, the paths should not be exposed. */
- if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
- r = readlink_value(path, &value);
- if (r < 0)
- return r;
- } else
- return -EINVAL;
- } else if (S_ISDIR(statbuf.st_mode)) {
- /* skip directories */
- return -EINVAL;
- } else if (!(statbuf.st_mode & S_IRUSR)) {
- /* skip non-readable files */
- return -EPERM;
- } else {
- size_t size;
-
- /* read attribute value */
- r = read_full_file(path, &value, &size);
- if (r < 0)
- return r;
-
- /* drop trailing newlines */
- while (size > 0 && value[--size] == '\n')
- value[size] = '\0';
- }
-
- r = device_add_sysattr_value(device, sysattr, value);
- if (r < 0)
- return r;
-
- *_value = value;
- value = NULL;
-
- return 0;
-}
-
-static void device_remove_sysattr_value(sd_device *device, const char *_key) {
- _cleanup_free_ char *key = NULL;
- _cleanup_free_ char *value = NULL;
-
- assert(device);
- assert(_key);
-
- value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
-
- return;
-}
-
-/* set the attribute and save it in the cache. If a NULL value is passed the
- * attribute is cleared from the cache */
-_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
- _cleanup_close_ int fd = -1;
- _cleanup_free_ char *value = NULL;
- const char *syspath;
- char *path;
- struct stat statbuf;
- size_t value_len = 0;
- ssize_t size;
- int r;
-
- assert_return(device, -EINVAL);
- assert_return(sysattr, -EINVAL);
-
- if (!_value) {
- device_remove_sysattr_value(device, sysattr);
-
- return 0;
- }
-
- r = sd_device_get_syspath(device, &syspath);
- if (r < 0)
- return r;
-
- path = strjoina(syspath, "/", sysattr);
- r = lstat(path, &statbuf);
- if (r < 0) {
- value = strdup("");
- if (!value)
- return -ENOMEM;
-
- r = device_add_sysattr_value(device, sysattr, value);
- if (r < 0)
- return r;
-
- return -ENXIO;
- }
-
- if (S_ISLNK(statbuf.st_mode))
- return -EINVAL;
-
- /* skip directories */
- if (S_ISDIR(statbuf.st_mode))
- return -EISDIR;
-
- /* skip non-readable files */
- if ((statbuf.st_mode & S_IRUSR) == 0)
- return -EACCES;
-
- value_len = strlen(_value);
-
- /* drop trailing newlines */
- while (value_len > 0 && _value[value_len - 1] == '\n')
- _value[--value_len] = '\0';
-
- /* value length is limited to 4k */
- if (value_len > 4096)
- return -EINVAL;
-
- fd = open(path, O_WRONLY | O_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- value = strdup(_value);
- if (!value)
- return -ENOMEM;
-
- size = write(fd, value, value_len);
- if (size < 0)
- return -errno;
-
- if ((size_t)size != value_len)
- return -EIO;
-
- r = device_add_sysattr_value(device, sysattr, value);
- if (r < 0)
- return r;
-
- value = NULL;
-
- return 0;
-}
+++ /dev/null
-../../Makefile
\ No newline at end of file
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "sd-event.h"
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "signal-util.h"
-
-static int prepare_handler(sd_event_source *s, void *userdata) {
- log_info("preparing %c", PTR_TO_INT(userdata));
- return 1;
-}
-
-static bool got_a, got_b, got_c, got_unref;
-static unsigned got_d;
-
-static int unref_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- sd_event_source_unref(s);
- got_unref = true;
- return 0;
-}
-
-static int io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-
- log_info("got IO on %c", PTR_TO_INT(userdata));
-
- if (userdata == INT_TO_PTR('a')) {
- assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
- assert_se(!got_a);
- got_a = true;
- } else if (userdata == INT_TO_PTR('b')) {
- assert_se(!got_b);
- got_b = true;
- } else if (userdata == INT_TO_PTR('d')) {
- got_d++;
- if (got_d < 2)
- assert_se(sd_event_source_set_enabled(s, SD_EVENT_ONESHOT) >= 0);
- else
- assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
- } else
- assert_not_reached("Yuck!");
-
- return 1;
-}
-
-static int child_handler(sd_event_source *s, const siginfo_t *si, void *userdata) {
-
- assert_se(s);
- assert_se(si);
-
- log_info("got child on %c", PTR_TO_INT(userdata));
-
- assert_se(userdata == INT_TO_PTR('f'));
-
- assert_se(sd_event_exit(sd_event_source_get_event(s), 0) >= 0);
- sd_event_source_unref(s);
-
- return 1;
-}
-
-static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
- sd_event_source *p = NULL;
- pid_t pid;
-
- assert_se(s);
- assert_se(si);
-
- log_info("got signal on %c", PTR_TO_INT(userdata));
-
- assert_se(userdata == INT_TO_PTR('e'));
-
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
-
- pid = fork();
- assert_se(pid >= 0);
-
- if (pid == 0)
- _exit(0);
-
- assert_se(sd_event_add_child(sd_event_source_get_event(s), &p, pid, WEXITED, child_handler, INT_TO_PTR('f')) >= 0);
- assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
-
- sd_event_source_unref(s);
-
- return 1;
-}
-
-static int defer_handler(sd_event_source *s, void *userdata) {
- sd_event_source *p = NULL;
-
- assert_se(s);
-
- log_info("got defer on %c", PTR_TO_INT(userdata));
-
- assert_se(userdata == INT_TO_PTR('d'));
-
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGUSR1, -1) >= 0);
-
- assert_se(sd_event_add_signal(sd_event_source_get_event(s), &p, SIGUSR1, signal_handler, INT_TO_PTR('e')) >= 0);
- assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
- raise(SIGUSR1);
-
- sd_event_source_unref(s);
-
- return 1;
-}
-
-static bool do_quit = false;
-
-static int time_handler(sd_event_source *s, uint64_t usec, void *userdata) {
- log_info("got timer on %c", PTR_TO_INT(userdata));
-
- if (userdata == INT_TO_PTR('c')) {
-
- if (do_quit) {
- sd_event_source *p;
-
- assert_se(sd_event_add_defer(sd_event_source_get_event(s), &p, defer_handler, INT_TO_PTR('d')) >= 0);
- assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
- } else {
- assert_se(!got_c);
- got_c = true;
- }
- } else
- assert_not_reached("Huh?");
-
- return 2;
-}
-
-static bool got_exit = false;
-
-static int exit_handler(sd_event_source *s, void *userdata) {
- log_info("got quit handler on %c", PTR_TO_INT(userdata));
-
- got_exit = true;
-
- return 3;
-}
-
-int main(int argc, char *argv[]) {
- sd_event *e = NULL;
- sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL;
- static const char ch = 'x';
- int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 };
-
- assert_se(pipe(a) >= 0);
- assert_se(pipe(b) >= 0);
- assert_se(pipe(d) >= 0);
- assert_se(pipe(k) >= 0);
-
- assert_se(sd_event_default(&e) >= 0);
-
- assert_se(sd_event_set_watchdog(e, true) >= 0);
-
- /* Test whether we cleanly can destroy an io event source from its own handler */
- got_unref = false;
- assert_se(sd_event_add_io(e, &t, k[0], EPOLLIN, unref_handler, NULL) >= 0);
- assert_se(write(k[1], &ch, 1) == 1);
- assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
- assert_se(got_unref);
-
- got_a = false, got_b = false, got_c = false, got_d = 0;
-
- /* Add a oneshot handler, trigger it, re-enable it, and trigger
- * it again. */
- assert_se(sd_event_add_io(e, &w, d[0], EPOLLIN, io_handler, INT_TO_PTR('d')) >= 0);
- assert_se(sd_event_source_set_enabled(w, SD_EVENT_ONESHOT) >= 0);
- assert_se(write(d[1], &ch, 1) >= 0);
- assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
- assert_se(got_d == 1);
- assert_se(write(d[1], &ch, 1) >= 0);
- assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
- assert_se(got_d == 2);
-
- assert_se(sd_event_add_io(e, &x, a[0], EPOLLIN, io_handler, INT_TO_PTR('a')) >= 0);
- assert_se(sd_event_add_io(e, &y, b[0], EPOLLIN, io_handler, INT_TO_PTR('b')) >= 0);
- assert_se(sd_event_add_time(e, &z, CLOCK_MONOTONIC, 0, 0, time_handler, INT_TO_PTR('c')) >= 0);
- assert_se(sd_event_add_exit(e, &q, exit_handler, INT_TO_PTR('g')) >= 0);
-
- assert_se(sd_event_source_set_priority(x, 99) >= 0);
- assert_se(sd_event_source_set_enabled(y, SD_EVENT_ONESHOT) >= 0);
- assert_se(sd_event_source_set_prepare(x, prepare_handler) >= 0);
- assert_se(sd_event_source_set_priority(z, 50) >= 0);
- assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
- assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0);
-
- /* Test for floating event sources */
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+1, -1) >= 0);
- assert_se(sd_event_add_signal(e, NULL, SIGRTMIN+1, NULL, NULL) >= 0);
-
- assert_se(write(a[1], &ch, 1) >= 0);
- assert_se(write(b[1], &ch, 1) >= 0);
-
- assert_se(!got_a && !got_b && !got_c);
-
- assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
-
- assert_se(!got_a && got_b && !got_c);
-
- assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
-
- assert_se(!got_a && got_b && got_c);
-
- assert_se(sd_event_run(e, (uint64_t) -1) >= 1);
-
- assert_se(got_a && got_b && got_c);
-
- sd_event_source_unref(x);
- sd_event_source_unref(y);
-
- do_quit = true;
- assert_se(sd_event_source_set_time(z, now(CLOCK_MONOTONIC) + 200 * USEC_PER_MSEC) >= 0);
- assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0);
-
- assert_se(sd_event_loop(e) >= 0);
-
- sd_event_source_unref(z);
- sd_event_source_unref(q);
-
- sd_event_source_unref(w);
-
- sd_event_unref(e);
-
- safe_close_pair(a);
- safe_close_pair(b);
- safe_close_pair(d);
- safe_close_pair(k);
-
- return 0;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#pragma once
-
-#include "sd-event.h"
-#include "sd-netlink.h"
-#include "sd-network.h"
-
-#include "hashmap.h"
-
-typedef struct Manager Manager;
-
-#include "networkd-wait-online-link.h"
-
-struct Manager {
- Hashmap *links;
- Hashmap *links_by_name;
-
- char **interfaces;
- char **ignore;
-
- sd_netlink *rtnl;
- sd_event_source *rtnl_event_source;
-
- sd_network_monitor *network_monitor;
- sd_event_source *network_monitor_event_source;
-
- sd_event *event;
-};
-
-void manager_free(Manager *m);
-int manager_new(Manager **ret, char **interfaces, char **ignore, usec_t timeout);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
-
-bool manager_all_configured(Manager *m);
-bool manager_ignore_link(Manager *m, Link *link);
+++ /dev/null
-# This file is part of systemd.
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: elogind
-Description: elogind 128 Bit ID Utility Library
-URL: @PACKAGE_URL@
-Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -lelogind-id128
-Cflags: -I${includedir}
-../Makefile
\ No newline at end of file
+../../Makefile
\ No newline at end of file
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-enum {
- NETLINK_TYPE_UNSPEC,
- NETLINK_TYPE_U8, /* NLA_U8 */
- NETLINK_TYPE_U16, /* NLA_U16 */
- NETLINK_TYPE_U32, /* NLA_U32 */
- NETLINK_TYPE_U64, /* NLA_U64 */
- NETLINK_TYPE_STRING, /* NLA_STRING */
- NETLINK_TYPE_FLAG, /* NLA_FLAG */
- NETLINK_TYPE_IN_ADDR,
- NETLINK_TYPE_ETHER_ADDR,
- NETLINK_TYPE_CACHE_INFO,
- NETLINK_TYPE_NESTED, /* NLA_NESTED */
- NETLINK_TYPE_UNION,
-};
-
-typedef enum NLMatchType {
- NL_MATCH_SIBLING,
- NL_MATCH_PROTOCOL,
-} NLMatchType;
-
-typedef struct NLTypeSystemUnion NLTypeSystemUnion;
-typedef struct NLTypeSystem NLTypeSystem;
-typedef struct NLType NLType;
-
-struct NLTypeSystemUnion {
- int num;
- NLMatchType match_type;
- uint16_t match;
- int (*lookup)(const char *);
- const NLTypeSystem *type_systems;
-};
-
-extern const NLTypeSystem type_system_root;
-
-uint16_t type_get_type(const NLType *type);
-size_t type_get_size(const NLType *type);
-void type_get_type_system(const NLType *type, const NLTypeSystem **ret);
-void type_get_type_system_union(const NLType *type, const NLTypeSystemUnion **ret);
-
-uint16_t type_system_get_count(const NLTypeSystem *type_system);
-int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type);
-int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type);
-int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type);
-int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key);
-int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol);
-
-typedef enum NLUnionLinkInfoData {
- NL_UNION_LINK_INFO_DATA_BOND,
- NL_UNION_LINK_INFO_DATA_BRIDGE,
- NL_UNION_LINK_INFO_DATA_VLAN,
- NL_UNION_LINK_INFO_DATA_VETH,
- NL_UNION_LINK_INFO_DATA_DUMMY,
- NL_UNION_LINK_INFO_DATA_MACVLAN,
- NL_UNION_LINK_INFO_DATA_MACVTAP,
- NL_UNION_LINK_INFO_DATA_IPVLAN,
- NL_UNION_LINK_INFO_DATA_VXLAN,
- NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL,
- NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL,
- NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL,
- NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL,
- NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL,
- NL_UNION_LINK_INFO_DATA_SIT_TUNNEL,
- NL_UNION_LINK_INFO_DATA_VTI_TUNNEL,
- NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL,
- NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL,
- _NL_UNION_LINK_INFO_DATA_MAX,
- _NL_UNION_LINK_INFO_DATA_INVALID = -1
-} NLUnionLinkInfoData;
-
-const char *nl_union_link_info_data_to_string(NLUnionLinkInfoData p) _const_;
-NLUnionLinkInfoData nl_union_link_info_data_from_string(const char *p) _pure_;
+++ /dev/null
-../Makefile
\ No newline at end of file
+++ /dev/null
-../Makefile
\ No newline at end of file
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2008-2011 Lennart Poettering
- Copyright 2014 Tom Gundersen
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "sd-rtnl.h"
-#include "rtnl-util.h"
-#include "macro.h"
-#include "local-addresses.h"
-
-static int address_compare(const void *_a, const void *_b) {
- const struct local_address *a = _a, *b = _b;
-
- /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
-
- if (a->family == AF_INET && b->family == AF_INET6)
- return -1;
- if (a->family == AF_INET6 && b->family == AF_INET)
- return 1;
-
- if (a->scope < b->scope)
- return -1;
- if (a->scope > b->scope)
- return 1;
-
- if (a->metric < b->metric)
- return -1;
- if (a->metric > b->metric)
- return 1;
-
- if (a->ifindex < b->ifindex)
- return -1;
- if (a->ifindex > b->ifindex)
- return 1;
-
- return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
-}
-
-int local_addresses(sd_rtnl *context, int ifindex, int af, struct local_address **ret) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
- _cleanup_free_ struct local_address *list = NULL;
- size_t n_list = 0, n_allocated = 0;
- sd_rtnl_message *m;
- int r;
-
- assert(ret);
-
- if (context)
- rtnl = sd_rtnl_ref(context);
- else {
- r = sd_rtnl_open(&rtnl);
- if (r < 0)
- return r;
- }
-
- r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, af);
- if (r < 0)
- return r;
-
- r = sd_rtnl_call(rtnl, req, 0, &reply);
- if (r < 0)
- return r;
-
- for (m = reply; m; m = sd_rtnl_message_next(m)) {
- struct local_address *a;
- unsigned char flags;
- uint16_t type;
- int ifi, family;
-
- r = sd_rtnl_message_get_errno(m);
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_get_type(m, &type);
- if (r < 0)
- return r;
- if (type != RTM_NEWADDR)
- continue;
-
- r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
- if (r < 0)
- return r;
- if (ifindex > 0 && ifi != ifindex)
- continue;
-
- r = sd_rtnl_message_addr_get_family(m, &family);
- if (r < 0)
- return r;
- if (af != AF_UNSPEC && af != family)
- continue;
-
- r = sd_rtnl_message_addr_get_flags(m, &flags);
- if (r < 0)
- return r;
- if (flags & IFA_F_DEPRECATED)
- continue;
-
- if (!GREEDY_REALLOC0(list, n_allocated, n_list+1))
- return -ENOMEM;
-
- a = list + n_list;
-
- r = sd_rtnl_message_addr_get_scope(m, &a->scope);
- if (r < 0)
- return r;
-
- if (ifindex == 0 && (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE))
- continue;
-
- switch (family) {
-
- case AF_INET:
- r = sd_rtnl_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
- if (r < 0) {
- r = sd_rtnl_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
- if (r < 0)
- continue;
- }
- break;
-
- case AF_INET6:
- r = sd_rtnl_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
- if (r < 0) {
- r = sd_rtnl_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
- if (r < 0)
- continue;
- }
- break;
-
- default:
- continue;
- }
-
- a->ifindex = ifi;
- a->family = family;
-
- n_list++;
- };
-
- if (n_list > 0)
- qsort(list, n_list, sizeof(struct local_address), address_compare);
-
- *ret = list;
- list = NULL;
-
- return (int) n_list;
-}
-
-int local_gateways(sd_rtnl *context, int ifindex, int af, struct local_address **ret) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
- _cleanup_free_ struct local_address *list = NULL;
- sd_rtnl_message *m = NULL;
- size_t n_list = 0, n_allocated = 0;
- int r;
-
- assert(ret);
-
- if (context)
- rtnl = sd_rtnl_ref(context);
- else {
- r = sd_rtnl_open(&rtnl);
- if (r < 0)
- return r;
- }
-
- r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC);
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_request_dump(req, true);
- if (r < 0)
- return r;
-
- r = sd_rtnl_call(rtnl, req, 0, &reply);
- if (r < 0)
- return r;
-
- for (m = reply; m; m = sd_rtnl_message_next(m)) {
- struct local_address *a;
- uint16_t type;
- unsigned char dst_len, src_len;
- uint32_t ifi;
- int family;
-
- r = sd_rtnl_message_get_errno(m);
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_get_type(m, &type);
- if (r < 0)
- return r;
- if (type != RTM_NEWROUTE)
- continue;
-
- /* We only care for default routes */
- r = sd_rtnl_message_route_get_dst_prefixlen(m, &dst_len);
- if (r < 0)
- return r;
- if (dst_len != 0)
- continue;
-
- r = sd_rtnl_message_route_get_src_prefixlen(m, &src_len);
- if (r < 0)
- return r;
- if (src_len != 0)
- continue;
-
- r = sd_rtnl_message_read_u32(m, RTA_OIF, &ifi);
- if (r < 0)
- return r;
- if (ifindex > 0 && (int) ifi != ifindex)
- continue;
-
- r = sd_rtnl_message_route_get_family(m, &family);
- if (r < 0)
- return r;
- if (af != AF_UNSPEC && af != family)
- continue;
-
- if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
- return -ENOMEM;
-
- a = list + n_list;
-
- switch (family) {
- case AF_INET:
- r = sd_rtnl_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
- if (r < 0)
- continue;
-
- break;
- case AF_INET6:
- r = sd_rtnl_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
- if (r < 0)
- continue;
-
- break;
- default:
- continue;
- }
-
- sd_rtnl_message_read_u32(m, RTA_PRIORITY, &a->metric);
-
- a->ifindex = ifi;
- a->family = family;
-
- n_list++;
- }
-
- if (n_list > 0)
- qsort(list, n_list, sizeof(struct local_address), address_compare);
-
- *ret = list;
- list = NULL;
-
- return (int) n_list;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <netinet/in.h>
-#include <stdbool.h>
-#include <unistd.h>
-
-#include "util.h"
-#include "formats-util.h"
-#include "refcnt.h"
-#include "missing.h"
-
-#include "sd-rtnl.h"
-#include "rtnl-util.h"
-#include "rtnl-internal.h"
-#include "rtnl-types.h"
-
-#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
-#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
-
-#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
-
-static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret) {
- sd_rtnl_message *m;
-
- assert_return(ret, -EINVAL);
-
- /* Note that 'rtnl' is currently unused, if we start using it internally
- we must take care to avoid problems due to mutual references between
- buses and their queued messages. See sd-bus.
- */
-
- m = new0(sd_rtnl_message, 1);
- if (!m)
- return -ENOMEM;
-
- m->n_ref = REFCNT_INIT;
-
- m->sealed = false;
-
- *ret = m;
-
- return 0;
-}
-
-int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t type) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
- const NLType *nl_type;
- size_t size;
- int r;
-
- r = type_system_get_type(NULL, &nl_type, type);
- if (r < 0)
- return r;
-
- r = message_new_empty(rtnl, &m);
- if (r < 0)
- return r;
-
- size = NLMSG_SPACE(nl_type->size);
-
- assert(size >= sizeof(struct nlmsghdr));
- m->hdr = malloc0(size);
- if (!m->hdr)
- return -ENOMEM;
-
- m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-
- m->container_type_system[0] = nl_type->type_system;
- m->hdr->nlmsg_len = size;
- m->hdr->nlmsg_type = type;
-
- *ret = m;
- m = NULL;
-
- return 0;
-}
-
-int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
- struct rtmsg *rtm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-
- rtm = NLMSG_DATA(m->hdr);
-
- if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
- (rtm->rtm_family == AF_INET6 && prefixlen > 128))
- return -ERANGE;
-
- rtm->rtm_dst_len = prefixlen;
-
- return 0;
-}
-
-int sd_rtnl_message_route_set_src_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
- struct rtmsg *rtm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-
- rtm = NLMSG_DATA(m->hdr);
-
- if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
- (rtm->rtm_family == AF_INET6 && prefixlen > 128))
- return -ERANGE;
-
- rtm->rtm_src_len = prefixlen;
-
- return 0;
-}
-
-int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) {
- struct rtmsg *rtm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
-
- rtm = NLMSG_DATA(m->hdr);
-
- rtm->rtm_scope = scope;
-
- return 0;
-}
-
-int sd_rtnl_message_route_get_family(sd_rtnl_message *m, int *family) {
- struct rtmsg *rtm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
- assert_return(family, -EINVAL);
-
- rtm = NLMSG_DATA(m->hdr);
-
- *family = rtm->rtm_family;
-
- return 0;
-}
-
-int sd_rtnl_message_route_get_dst_prefixlen(sd_rtnl_message *m, unsigned char *dst_len) {
- struct rtmsg *rtm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
- assert_return(dst_len, -EINVAL);
-
- rtm = NLMSG_DATA(m->hdr);
-
- *dst_len = rtm->rtm_dst_len;
-
- return 0;
-}
-
-int sd_rtnl_message_route_get_src_prefixlen(sd_rtnl_message *m, unsigned char *src_len) {
- struct rtmsg *rtm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
- assert_return(src_len, -EINVAL);
-
- rtm = NLMSG_DATA(m->hdr);
-
- *src_len = rtm->rtm_src_len;
-
- return 0;
-}
-
-int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret,
- uint16_t nlmsg_type, int rtm_family,
- unsigned char rtm_protocol) {
- struct rtmsg *rtm;
- int r;
-
- assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
- assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
- rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
- assert_return(ret, -EINVAL);
-
- r = message_new(rtnl, ret, nlmsg_type);
- if (r < 0)
- return r;
-
- if (nlmsg_type == RTM_NEWROUTE)
- (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
-
- rtm = NLMSG_DATA((*ret)->hdr);
-
- rtm->rtm_family = rtm_family;
- rtm->rtm_scope = RT_SCOPE_UNIVERSE;
- rtm->rtm_type = RTN_UNICAST;
- rtm->rtm_table = RT_TABLE_MAIN;
- rtm->rtm_protocol = rtm_protocol;
-
- return 0;
-}
-
-int sd_rtnl_message_neigh_set_flags(sd_rtnl_message *m, uint8_t flags) {
- struct ndmsg *ndm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
- ndm = NLMSG_DATA(m->hdr);
- ndm->ndm_flags |= flags;
-
- return 0;
-}
-
-int sd_rtnl_message_neigh_set_state(sd_rtnl_message *m, uint16_t state) {
- struct ndmsg *ndm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
- ndm = NLMSG_DATA(m->hdr);
- ndm->ndm_state |= state;
-
- return 0;
-}
-
-int sd_rtnl_message_neigh_get_flags(sd_rtnl_message *m, uint8_t *flags) {
- struct ndmsg *ndm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
- ndm = NLMSG_DATA(m->hdr);
- *flags = ndm->ndm_flags;
-
- return 0;
-}
-
-int sd_rtnl_message_neigh_get_state(sd_rtnl_message *m, uint16_t *state) {
- struct ndmsg *ndm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
-
- ndm = NLMSG_DATA(m->hdr);
- *state = ndm->ndm_state;
-
- return 0;
-}
-
-int sd_rtnl_message_neigh_get_family(sd_rtnl_message *m, int *family) {
- struct ndmsg *ndm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
- assert_return(family, -EINVAL);
-
- ndm = NLMSG_DATA(m->hdr);
-
- *family = ndm->ndm_family;
-
- return 0;
-}
-
-int sd_rtnl_message_neigh_get_ifindex(sd_rtnl_message *m, int *index) {
- struct ndmsg *ndm;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
- assert_return(index, -EINVAL);
-
- ndm = NLMSG_DATA(m->hdr);
-
- *index = ndm->ndm_ifindex;
-
- return 0;
-}
-
-int sd_rtnl_message_new_neigh(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type, int index, int ndm_family) {
- struct ndmsg *ndm;
- int r;
-
- assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
- assert_return(ndm_family == AF_INET ||
- ndm_family == AF_INET6 ||
- ndm_family == PF_BRIDGE, -EINVAL);
- assert_return(ret, -EINVAL);
-
- r = message_new(rtnl, ret, nlmsg_type);
- if (r < 0)
- return r;
-
- if (nlmsg_type == RTM_NEWNEIGH)
- (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
-
- ndm = NLMSG_DATA((*ret)->hdr);
-
- ndm->ndm_family = ndm_family;
- ndm->ndm_ifindex = index;
-
- return 0;
-}
-
-int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
- struct ifinfomsg *ifi;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
- assert_return(change, -EINVAL);
-
- ifi = NLMSG_DATA(m->hdr);
-
- ifi->ifi_flags = flags;
- ifi->ifi_change = change;
-
- return 0;
-}
-
-int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
- struct ifinfomsg *ifi;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-
- ifi = NLMSG_DATA(m->hdr);
-
- ifi->ifi_type = type;
-
- return 0;
-}
-
-int sd_rtnl_message_link_set_family(sd_rtnl_message *m, unsigned family) {
- struct ifinfomsg *ifi;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
-
- ifi = NLMSG_DATA(m->hdr);
-
- ifi->ifi_family = family;
-
- return 0;
-}
-
-int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret,
- uint16_t nlmsg_type, int index) {
- struct ifinfomsg *ifi;
- int r;
-
- assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
- assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
- assert_return(ret, -EINVAL);
-
- r = message_new(rtnl, ret, nlmsg_type);
- if (r < 0)
- return r;
-
- if (nlmsg_type == RTM_NEWLINK)
- (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
-
- ifi = NLMSG_DATA((*ret)->hdr);
-
- ifi->ifi_family = AF_UNSPEC;
- ifi->ifi_index = index;
-
- return 0;
-}
-
-int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump) {
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
- m->hdr->nlmsg_type == RTM_GETADDR ||
- m->hdr->nlmsg_type == RTM_GETROUTE ||
- m->hdr->nlmsg_type == RTM_GETNEIGH,
- -EINVAL);
-
- if (dump)
- m->hdr->nlmsg_flags |= NLM_F_DUMP;
- else
- m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
-
- return 0;
-}
-
-int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
- struct ifaddrmsg *ifa;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-
- ifa = NLMSG_DATA(m->hdr);
-
- if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
- (ifa->ifa_family == AF_INET6 && prefixlen > 128))
- return -ERANGE;
-
- ifa->ifa_prefixlen = prefixlen;
-
- return 0;
-}
-
-int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
- struct ifaddrmsg *ifa;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-
- ifa = NLMSG_DATA(m->hdr);
-
- ifa->ifa_flags = flags;
-
- return 0;
-}
-
-int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
- struct ifaddrmsg *ifa;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
-
- ifa = NLMSG_DATA(m->hdr);
-
- ifa->ifa_scope = scope;
-
- return 0;
-}
-
-int sd_rtnl_message_addr_get_family(sd_rtnl_message *m, int *family) {
- struct ifaddrmsg *ifa;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
- assert_return(family, -EINVAL);
-
- ifa = NLMSG_DATA(m->hdr);
-
- *family = ifa->ifa_family;
-
- return 0;
-}
-
-int sd_rtnl_message_addr_get_prefixlen(sd_rtnl_message *m, unsigned char *prefixlen) {
- struct ifaddrmsg *ifa;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
- assert_return(prefixlen, -EINVAL);
-
- ifa = NLMSG_DATA(m->hdr);
-
- *prefixlen = ifa->ifa_prefixlen;
-
- return 0;
-}
-
-int sd_rtnl_message_addr_get_scope(sd_rtnl_message *m, unsigned char *scope) {
- struct ifaddrmsg *ifa;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
- assert_return(scope, -EINVAL);
-
- ifa = NLMSG_DATA(m->hdr);
-
- *scope = ifa->ifa_scope;
-
- return 0;
-}
-
-int sd_rtnl_message_addr_get_flags(sd_rtnl_message *m, unsigned char *flags) {
- struct ifaddrmsg *ifa;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
- assert_return(flags, -EINVAL);
-
- ifa = NLMSG_DATA(m->hdr);
-
- *flags = ifa->ifa_flags;
-
- return 0;
-}
-
-int sd_rtnl_message_addr_get_ifindex(sd_rtnl_message *m, int *ifindex) {
- struct ifaddrmsg *ifa;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
- assert_return(ifindex, -EINVAL);
-
- ifa = NLMSG_DATA(m->hdr);
-
- *ifindex = ifa->ifa_index;
-
- return 0;
-}
-
-int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
- uint16_t nlmsg_type, int index,
- int family) {
- struct ifaddrmsg *ifa;
- int r;
-
- assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
- assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
- index > 0, -EINVAL);
- assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
- family == AF_INET || family == AF_INET6, -EINVAL);
- assert_return(ret, -EINVAL);
-
- r = message_new(rtnl, ret, nlmsg_type);
- if (r < 0)
- return r;
-
- if (nlmsg_type == RTM_GETADDR)
- (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
-
- ifa = NLMSG_DATA((*ret)->hdr);
-
- ifa->ifa_index = index;
- ifa->ifa_family = family;
- if (family == AF_INET)
- ifa->ifa_prefixlen = 32;
- else if (family == AF_INET6)
- ifa->ifa_prefixlen = 128;
-
- return 0;
-}
-
-int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret,
- int index, int family) {
- int r;
-
- r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
- if (r < 0)
- return r;
-
- (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
-
- return 0;
-}
-
-sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
- if (m)
- assert_se(REFCNT_INC(m->n_ref) >= 2);
-
- return m;
-}
-
-sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
- if (m && REFCNT_DEC(m->n_ref) == 0) {
- unsigned i;
-
- free(m->hdr);
-
- for (i = 0; i <= m->n_containers; i++)
- free(m->rta_offset_tb[i]);
-
- sd_rtnl_message_unref(m->next);
-
- free(m);
- }
-
- return NULL;
-}
-
-int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
- assert_return(m, -EINVAL);
- assert_return(type, -EINVAL);
-
- *type = m->hdr->nlmsg_type;
-
- return 0;
-}
-
-int sd_rtnl_message_get_family(sd_rtnl_message *m, int *family) {
- assert_return(m, -EINVAL);
- assert_return(family, -EINVAL);
-
- assert(m->hdr);
-
- if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) {
- struct ifinfomsg *ifi;
-
- ifi = NLMSG_DATA(m->hdr);
-
- *family = ifi->ifi_family;
-
- return 0;
- } else if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) {
- struct rtmsg *rtm;
-
- rtm = NLMSG_DATA(m->hdr);
-
- *family = rtm->rtm_family;
-
- return 0;
- } else if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) {
- struct ndmsg *ndm;
-
- ndm = NLMSG_DATA(m->hdr);
-
- *family = ndm->ndm_family;
-
- return 0;
- } else if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) {
- struct ifaddrmsg *ifa;
-
- ifa = NLMSG_DATA(m->hdr);
-
- *family = ifa->ifa_family;
-
- return 0;
- }
-
- return -EOPNOTSUPP;
-}
-
-int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
- assert_return(m, -EINVAL);
-
- return m->broadcast;
-}
-
-int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
- struct ifinfomsg *ifi;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
- assert_return(ifindex, -EINVAL);
-
- ifi = NLMSG_DATA(m->hdr);
-
- *ifindex = ifi->ifi_index;
-
- return 0;
-}
-
-int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
- struct ifinfomsg *ifi;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
- assert_return(flags, -EINVAL);
-
- ifi = NLMSG_DATA(m->hdr);
-
- *flags = ifi->ifi_flags;
-
- return 0;
-}
-
-int sd_rtnl_message_link_get_type(sd_rtnl_message *m, unsigned *type) {
- struct ifinfomsg *ifi;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
- assert_return(type, -EINVAL);
-
- ifi = NLMSG_DATA(m->hdr);
-
- *type = ifi->ifi_type;
-
- return 0;
-}
-
-/* If successful the updated message will be correctly aligned, if
- unsuccessful the old message is untouched. */
-static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
- uint32_t rta_length;
- size_t message_length, padding_length;
- struct nlmsghdr *new_hdr;
- struct rtattr *rta;
- char *padding;
- unsigned i;
- int offset;
-
- assert(m);
- assert(m->hdr);
- assert(!m->sealed);
- assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
- assert(!data || data_length);
-
- /* get offset of the new attribute */
- offset = m->hdr->nlmsg_len;
-
- /* get the size of the new rta attribute (with padding at the end) */
- rta_length = RTA_LENGTH(data_length);
-
- /* get the new message size (with padding at the end) */
- message_length = offset + RTA_ALIGN(rta_length);
-
- /* realloc to fit the new attribute */
- new_hdr = realloc(m->hdr, message_length);
- if (!new_hdr)
- return -ENOMEM;
- m->hdr = new_hdr;
-
- /* get pointer to the attribute we are about to add */
- rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
-
- /* if we are inside containers, extend them */
- for (i = 0; i < m->n_containers; i++)
- GET_CONTAINER(m, i)->rta_len += message_length - offset;
-
- /* fill in the attribute */
- rta->rta_type = type;
- rta->rta_len = rta_length;
- if (data)
- /* we don't deal with the case where the user lies about the type
- * and gives us too little data (so don't do that)
- */
- padding = mempcpy(RTA_DATA(rta), data, data_length);
- else {
- /* if no data was passed, make sure we still initialize the padding
- note that we can have data_length > 0 (used by some containers) */
- padding = RTA_DATA(rta);
- }
-
- /* make sure also the padding at the end of the message is initialized */
- padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
- memzero(padding, padding_length);
-
- /* update message size */
- m->hdr->nlmsg_len = message_length;
-
- return offset;
-}
-
-static int message_attribute_has_type(sd_rtnl_message *m, uint16_t attribute_type, uint16_t data_type) {
- const NLType *type;
- int r;
-
- r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
- if (r < 0)
- return r;
-
- if (type->type != data_type)
- return -EINVAL;
-
- return type->size;
-}
-
-int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
- size_t length, size;
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(data, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_STRING);
- if (r < 0)
- return r;
- else
- size = (size_t)r;
-
- if (size) {
- length = strnlen(data, size+1);
- if (length > size)
- return -EINVAL;
- } else
- length = strlen(data);
-
- r = add_rtattr(m, type, data, length + 1);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
-
- r = message_attribute_has_type(m, type, NLA_U8);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, &data, sizeof(uint8_t));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-
-int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
-
- r = message_attribute_has_type(m, type, NLA_U16);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, &data, sizeof(uint16_t));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
-
- r = message_attribute_has_type(m, type, NLA_U32);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, &data, sizeof(uint32_t));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(data, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_IN_ADDR);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, data, sizeof(struct in_addr));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(data, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_IN_ADDR);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, data, sizeof(struct in6_addr));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(data, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, data, ETH_ALEN);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(info, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
- size_t size;
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
-
- r = message_attribute_has_type(m, type, NLA_NESTED);
- if (r < 0) {
- const NLTypeSystemUnion *type_system_union;
- int family;
-
- r = message_attribute_has_type(m, type, NLA_UNION);
- if (r < 0)
- return r;
- size = (size_t) r;
-
- r = sd_rtnl_message_get_family(m, &family);
- if (r < 0)
- return r;
-
- r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
- if (r < 0)
- return r;
-
- r = type_system_union_protocol_get_type_system(type_system_union,
- &m->container_type_system[m->n_containers + 1],
- family);
- if (r < 0)
- return r;
- } else {
- size = (size_t)r;
-
- r = type_system_get_type_system(m->container_type_system[m->n_containers],
- &m->container_type_system[m->n_containers + 1],
- type);
- if (r < 0)
- return r;
- }
-
- r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
- if (r < 0)
- return r;
-
- m->container_offsets[m->n_containers ++] = r;
-
- return 0;
-}
-
-int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key) {
- const NLTypeSystemUnion *type_system_union;
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
-
- r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
- if (r < 0)
- return r;
-
- r = type_system_union_get_type_system(type_system_union,
- &m->container_type_system[m->n_containers + 1],
- key);
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_append_string(m, type_system_union->match, key);
- if (r < 0)
- return r;
-
- /* do we evere need non-null size */
- r = add_rtattr(m, type, NULL, 0);
- if (r < 0)
- return r;
-
- m->container_offsets[m->n_containers ++] = r;
-
- return 0;
-}
-
-
-int sd_rtnl_message_close_container(sd_rtnl_message *m) {
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(m->n_containers > 0, -EINVAL);
-
- m->container_type_system[m->n_containers] = NULL;
- m->n_containers --;
-
- return 0;
-}
-
-int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
- struct rtattr *rta;
-
- assert_return(m, -EINVAL);
- assert_return(m->sealed, -EPERM);
- assert_return(data, -EINVAL);
- assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
- assert(m->rta_offset_tb[m->n_containers]);
- assert(type < m->rta_tb_size[m->n_containers]);
-
- if(!m->rta_offset_tb[m->n_containers][type])
- return -ENODATA;
-
- rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
-
- *data = RTA_DATA(rta);
-
- return RTA_PAYLOAD(rta);
-}
-
-int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const char **data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_STRING);
- if (r < 0)
- return r;
-
- r = rtnl_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if (strnlen(attr_data, r) >= (size_t) r)
- return -EIO;
-
- if (data)
- *data = (const char *) attr_data;
-
- return 0;
-}
-
-int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_U8);
- if (r < 0)
- return r;
-
- r = rtnl_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t) r < sizeof(uint8_t))
- return -EIO;
-
- if (data)
- *data = *(uint8_t *) attr_data;
-
- return 0;
-}
-
-int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_U16);
- if (r < 0)
- return r;
-
- r = rtnl_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t) r < sizeof(uint16_t))
- return -EIO;
-
- if (data)
- *data = *(uint16_t *) attr_data;
-
- return 0;
-}
-
-int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_U32);
- if (r < 0)
- return r;
-
- r = rtnl_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t)r < sizeof(uint32_t))
- return -EIO;
-
- if (data)
- *data = *(uint32_t *) attr_data;
-
- return 0;
-}
-
-int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
- if (r < 0)
- return r;
-
- r = rtnl_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t)r < sizeof(struct ether_addr))
- return -EIO;
-
- if (data)
- memcpy(data, attr_data, sizeof(struct ether_addr));
-
- return 0;
-}
-
-int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
- if (r < 0)
- return r;
-
- r = rtnl_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t)r < sizeof(struct ifa_cacheinfo))
- return -EIO;
-
- if (info)
- memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
-
- return 0;
-}
-
-int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_IN_ADDR);
- if (r < 0)
- return r;
-
- r = rtnl_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t)r < sizeof(struct in_addr))
- return -EIO;
-
- if (data)
- memcpy(data, attr_data, sizeof(struct in_addr));
-
- return 0;
-}
-
-int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, type, NLA_IN_ADDR);
- if (r < 0)
- return r;
-
- r = rtnl_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t)r < sizeof(struct in6_addr))
- return -EIO;
-
- if (data)
- memcpy(data, attr_data, sizeof(struct in6_addr));
-
- return 0;
-}
-
-int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
- const NLType *nl_type;
- const NLTypeSystem *type_system;
- void *container;
- size_t size;
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
-
- r = type_system_get_type(m->container_type_system[m->n_containers],
- &nl_type,
- type);
- if (r < 0)
- return r;
-
- if (nl_type->type == NLA_NESTED) {
- r = type_system_get_type_system(m->container_type_system[m->n_containers],
- &type_system,
- type);
- if (r < 0)
- return r;
- } else if (nl_type->type == NLA_UNION) {
- const NLTypeSystemUnion *type_system_union;
-
- r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
- &type_system_union,
- type);
- if (r < 0)
- return r;
-
- switch (type_system_union->match_type) {
- case NL_MATCH_SIBLING:
- {
- const char *key;
-
- r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
- if (r < 0)
- return r;
-
- r = type_system_union_get_type_system(type_system_union,
- &type_system,
- key);
- if (r < 0)
- return r;
-
- break;
- }
- case NL_MATCH_PROTOCOL:
- {
- int family;
-
- r = sd_rtnl_message_get_family(m, &family);
- if (r < 0)
- return r;
-
- r = type_system_union_protocol_get_type_system(type_system_union,
- &type_system,
- family);
- if (r < 0)
- return r;
-
- break;
- }
- default:
- assert_not_reached("sd-rtnl: invalid type system union type");
- }
- } else
- return -EINVAL;
-
- r = rtnl_message_read_internal(m, type, &container);
- if (r < 0)
- return r;
- else
- size = (size_t)r;
-
- m->n_containers ++;
-
- r = rtnl_message_parse(m,
- &m->rta_offset_tb[m->n_containers],
- &m->rta_tb_size[m->n_containers],
- type_system->max,
- container,
- size);
- if (r < 0) {
- m->n_containers --;
- return r;
- }
-
- m->container_type_system[m->n_containers] = type_system;
-
- return 0;
-}
-
-int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
- assert_return(m, -EINVAL);
- assert_return(m->sealed, -EINVAL);
- assert_return(m->n_containers > 0, -EINVAL);
-
- free(m->rta_offset_tb[m->n_containers]);
- m->rta_offset_tb[m->n_containers] = NULL;
- m->container_type_system[m->n_containers] = NULL;
-
- m->n_containers --;
-
- return 0;
-}
-
-uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
- assert(m);
- assert(m->hdr);
-
- return m->hdr->nlmsg_seq;
-}
-
-int sd_rtnl_message_is_error(sd_rtnl_message *m) {
- assert_return(m, 0);
- assert_return(m->hdr, 0);
-
- return m->hdr->nlmsg_type == NLMSG_ERROR;
-}
-
-int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
- struct nlmsgerr *err;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
-
- if (!sd_rtnl_message_is_error(m))
- return 0;
-
- err = NLMSG_DATA(m->hdr);
-
- return err->error;
-}
-
-int rtnl_message_parse(sd_rtnl_message *m,
- size_t **rta_offset_tb,
- unsigned short *rta_tb_size,
- int max,
- struct rtattr *rta,
- unsigned int rt_len) {
- unsigned short type;
- size_t *tb;
-
- tb = new0(size_t, max + 1);
- if(!tb)
- return -ENOMEM;
-
- *rta_tb_size = max + 1;
-
- for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
- type = RTA_TYPE(rta);
-
- /* if the kernel is newer than the headers we used
- when building, we ignore out-of-range attributes
- */
- if (type > max)
- continue;
-
- if (tb[type])
- log_debug("rtnl: message parse - overwriting repeated attribute");
-
- tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
- }
-
- *rta_offset_tb = tb;
-
- return 0;
-}
-
-/* returns the number of bytes sent, or a negative error code */
-int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
- union {
- struct sockaddr sa;
- struct sockaddr_nl nl;
- } addr = {
- .nl.nl_family = AF_NETLINK,
- };
- ssize_t k;
-
- assert(nl);
- assert(m);
- assert(m->hdr);
-
- k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
- 0, &addr.sa, sizeof(addr));
- if (k < 0)
- return (errno == EAGAIN) ? 0 : -errno;
-
- return k;
-}
-
-static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
- uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(sizeof(struct nl_pktinfo))];
- struct msghdr msg = {
- .msg_iov = iov,
- .msg_iovlen = 1,
- .msg_control = cred_buffer,
- .msg_controllen = sizeof(cred_buffer),
- };
- struct cmsghdr *cmsg;
- uint32_t group = 0;
- bool auth = false;
- int r;
-
- assert(fd >= 0);
- assert(iov);
-
- r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
- if (r < 0) {
- /* no data */
- if (errno == ENOBUFS)
- log_debug("rtnl: kernel receive buffer overrun");
- else if (errno == EAGAIN)
- log_debug("rtnl: no data in socket");
-
- return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
- }
-
- CMSG_FOREACH(cmsg, &msg) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
- struct ucred *ucred = (void *)CMSG_DATA(cmsg);
-
- /* from the kernel */
- if (ucred->pid == 0)
- auth = true;
- else
- log_debug("rtnl: ignoring message from PID "PID_FMT, ucred->pid);
- } else if (cmsg->cmsg_level == SOL_NETLINK &&
- cmsg->cmsg_type == NETLINK_PKTINFO &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
- struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
-
- /* multi-cast group */
- group = pktinfo->group;
- }
- }
-
- if (!auth) {
- /* not from the kernel, ignore */
- if (peek) {
- /* drop the message */
- r = recvmsg(fd, &msg, 0);
- if (r < 0)
- return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
- }
-
- return 0;
- }
-
- if (_group)
- *_group = group;
-
- return r;
-}
-
-/* On success, the number of bytes received is returned and *ret points to the received message
- * which has a valid header and the correct size.
- * If nothing useful was received 0 is returned.
- * On failure, a negative error code is returned.
- */
-int socket_read_message(sd_rtnl *rtnl) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
- struct iovec iov = {};
- uint32_t group = 0;
- bool multi_part = false, done = false;
- struct nlmsghdr *new_msg;
- size_t len;
- int r;
- unsigned i = 0;
-
- assert(rtnl);
- assert(rtnl->rbuffer);
- assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
-
- /* read nothing, just get the pending message size */
- r = socket_recv_message(rtnl->fd, &iov, NULL, true);
- if (r <= 0)
- return r;
- else
- len = (size_t)r;
-
- /* make room for the pending message */
- if (!greedy_realloc((void **)&rtnl->rbuffer,
- &rtnl->rbuffer_allocated,
- len, sizeof(uint8_t)))
- return -ENOMEM;
-
- iov.iov_base = rtnl->rbuffer;
- iov.iov_len = rtnl->rbuffer_allocated;
-
- /* read the pending message */
- r = socket_recv_message(rtnl->fd, &iov, &group, false);
- if (r <= 0)
- return r;
- else
- len = (size_t)r;
-
- if (len > rtnl->rbuffer_allocated)
- /* message did not fit in read buffer */
- return -EIO;
-
- if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
- multi_part = true;
-
- for (i = 0; i < rtnl->rqueue_partial_size; i++) {
- if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
- rtnl->rbuffer->nlmsg_seq) {
- first = rtnl->rqueue_partial[i];
- break;
- }
- }
- }
-
- for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
- const NLType *nl_type;
-
- if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
- /* not broadcast and not for us */
- continue;
-
- if (new_msg->nlmsg_type == NLMSG_NOOP)
- /* silently drop noop messages */
- continue;
-
- if (new_msg->nlmsg_type == NLMSG_DONE) {
- /* finished reading multi-part message */
- done = true;
-
- /* if first is not defined, put NLMSG_DONE into the receive queue. */
- if (first)
- continue;
- }
-
- /* check that we support this message type */
- r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
- if (r < 0) {
- if (r == -EOPNOTSUPP)
- log_debug("sd-rtnl: ignored message with unknown type: %i",
- new_msg->nlmsg_type);
-
- continue;
- }
-
- /* check that the size matches the message type */
- if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size)) {
- log_debug("sd-rtnl: message larger than expected, dropping");
- continue;
- }
-
- r = message_new_empty(rtnl, &m);
- if (r < 0)
- return r;
-
- m->broadcast = !!group;
-
- m->hdr = memdup(new_msg, new_msg->nlmsg_len);
- if (!m->hdr)
- return -ENOMEM;
-
- /* seal and parse the top-level message */
- r = sd_rtnl_message_rewind(m);
- if (r < 0)
- return r;
-
- /* push the message onto the multi-part message stack */
- if (first)
- m->next = first;
- first = m;
- m = NULL;
- }
-
- if (len)
- log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
-
- if (!first)
- return 0;
-
- if (!multi_part || done) {
- /* we got a complete message, push it on the read queue */
- r = rtnl_rqueue_make_room(rtnl);
- if (r < 0)
- return r;
-
- rtnl->rqueue[rtnl->rqueue_size ++] = first;
- first = NULL;
-
- if (multi_part && (i < rtnl->rqueue_partial_size)) {
- /* remove the message form the partial read queue */
- memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
- sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1));
- rtnl->rqueue_partial_size --;
- }
-
- return 1;
- } else {
- /* we only got a partial multi-part message, push it on the
- partial read queue */
- if (i < rtnl->rqueue_partial_size) {
- rtnl->rqueue_partial[i] = first;
- } else {
- r = rtnl_rqueue_partial_make_room(rtnl);
- if (r < 0)
- return r;
-
- rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
- }
- first = NULL;
-
- return 0;
- }
-}
-
-int sd_rtnl_message_rewind(sd_rtnl_message *m) {
- const NLType *type;
- unsigned i;
- int r;
-
- assert_return(m, -EINVAL);
-
- /* don't allow appending to message once parsed */
- if (!m->sealed)
- rtnl_message_seal(m);
-
- for (i = 1; i <= m->n_containers; i++) {
- free(m->rta_offset_tb[i]);
- m->rta_offset_tb[i] = NULL;
- m->rta_tb_size[i] = 0;
- m->container_type_system[i] = NULL;
- }
-
- m->n_containers = 0;
-
- if (m->rta_offset_tb[0]) {
- /* top-level attributes have already been parsed */
- return 0;
- }
-
- assert(m->hdr);
-
- r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
- if (r < 0)
- return r;
-
- if (type->type == NLA_NESTED) {
- const NLTypeSystem *type_system = type->type_system;
-
- assert(type_system);
-
- m->container_type_system[0] = type_system;
-
- r = rtnl_message_parse(m,
- &m->rta_offset_tb[m->n_containers],
- &m->rta_tb_size[m->n_containers],
- type_system->max,
- (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
- NLMSG_ALIGN(type->size)),
- NLMSG_PAYLOAD(m->hdr, type->size));
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-void rtnl_message_seal(sd_rtnl_message *m) {
- assert(m);
- assert(!m->sealed);
-
- m->sealed = true;
-}
-
-sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) {
- assert_return(m, NULL);
-
- return m->next;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-
-#include "sd-rtnl.h"
-
-#include "rtnl-util.h"
-#include "rtnl-internal.h"
-
-int rtnl_set_link_name(sd_rtnl **rtnl, int ifindex, const char *name) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL;
- int r;
-
- assert(rtnl);
- assert(ifindex > 0);
- assert(name);
-
- if (!*rtnl) {
- r = sd_rtnl_open(rtnl);
- if (r < 0)
- return r;
- }
-
- r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_append_string(message, IFLA_IFNAME, name);
- if (r < 0)
- return r;
-
- r = sd_rtnl_call(*rtnl, message, 0, NULL);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int rtnl_set_link_properties(sd_rtnl **rtnl, int ifindex, const char *alias,
- const struct ether_addr *mac, unsigned mtu) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL;
- int r;
-
- assert(rtnl);
- assert(ifindex > 0);
-
- if (!alias && !mac && mtu == 0)
- return 0;
-
- if (!*rtnl) {
- r = sd_rtnl_open(rtnl);
- if (r < 0)
- return r;
- }
-
- r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
- if (r < 0)
- return r;
-
- if (alias) {
- r = sd_rtnl_message_append_string(message, IFLA_IFALIAS, alias);
- if (r < 0)
- return r;
- }
-
- if (mac) {
- r = sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, mac);
- if (r < 0)
- return r;
- }
-
- if (mtu > 0) {
- r = sd_rtnl_message_append_u32(message, IFLA_MTU, mtu);
- if (r < 0)
- return r;
- }
-
- r = sd_rtnl_call(*rtnl, message, 0, NULL);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
- struct nlmsgerr *err;
- int r;
-
- assert(error <= 0);
-
- r = message_new(NULL, ret, NLMSG_ERROR);
- if (r < 0)
- return r;
-
- (*ret)->hdr->nlmsg_seq = serial;
-
- err = NLMSG_DATA((*ret)->hdr);
-
- err->error = error;
-
- return 0;
-}
-
-bool rtnl_message_type_is_neigh(uint16_t type) {
- switch (type) {
- case RTM_NEWNEIGH:
- case RTM_GETNEIGH:
- case RTM_DELNEIGH:
- return true;
- default:
- return false;
- }
-}
-
-bool rtnl_message_type_is_route(uint16_t type) {
- switch (type) {
- case RTM_NEWROUTE:
- case RTM_GETROUTE:
- case RTM_DELROUTE:
- return true;
- default:
- return false;
- }
-}
-
-bool rtnl_message_type_is_link(uint16_t type) {
- switch (type) {
- case RTM_NEWLINK:
- case RTM_SETLINK:
- case RTM_GETLINK:
- case RTM_DELLINK:
- return true;
- default:
- return false;
- }
-}
-
-bool rtnl_message_type_is_addr(uint16_t type) {
- switch (type) {
- case RTM_NEWADDR:
- case RTM_GETADDR:
- case RTM_DELADDR:
- return true;
- default:
- return false;
- }
-}
-
-int rtnl_log_parse_error(int r) {
- return log_error_errno(r, "Failed to parse netlink message: %m");
-}
-
-int rtnl_log_create_error(int r) {
- return log_error_errno(r, "Failed to create netlink message: %m");
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/socket.h>
-#include <poll.h>
-
-#include "missing.h"
-#include "macro.h"
-#include "util.h"
-#include "hashmap.h"
-
-#include "sd-rtnl.h"
-#include "rtnl-internal.h"
-#include "rtnl-util.h"
-
-static int sd_rtnl_new(sd_rtnl **ret) {
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
-
- assert_return(ret, -EINVAL);
-
- rtnl = new0(sd_rtnl, 1);
- if (!rtnl)
- return -ENOMEM;
-
- rtnl->n_ref = REFCNT_INIT;
-
- rtnl->fd = -1;
-
- rtnl->sockaddr.nl.nl_family = AF_NETLINK;
-
- rtnl->original_pid = getpid();
-
- LIST_HEAD_INIT(rtnl->match_callbacks);
-
- /* We guarantee that wqueue always has space for at least
- * one entry */
- if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1))
- return -ENOMEM;
-
- /* We guarantee that the read buffer has at least space for
- * a message header */
- if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
- sizeof(struct nlmsghdr), sizeof(uint8_t)))
- return -ENOMEM;
-
- /* Change notification responses have sequence 0, so we must
- * start our request sequence numbers at 1, or we may confuse our
- * responses with notifications from the kernel */
- rtnl->serial = 1;
-
- *ret = rtnl;
- rtnl = NULL;
-
- return 0;
-}
-
-int sd_rtnl_new_from_netlink(sd_rtnl **ret, int fd) {
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
- socklen_t addrlen;
- int r;
-
- assert_return(ret, -EINVAL);
-
- r = sd_rtnl_new(&rtnl);
- if (r < 0)
- return r;
-
- addrlen = sizeof(rtnl->sockaddr);
-
- r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
- if (r < 0)
- return -errno;
-
- rtnl->fd = fd;
-
- *ret = rtnl;
- rtnl = NULL;
-
- return 0;
-}
-
-static bool rtnl_pid_changed(sd_rtnl *rtnl) {
- assert(rtnl);
-
- /* We don't support people creating an rtnl connection and
- * keeping it around over a fork(). Let's complain. */
-
- return rtnl->original_pid != getpid();
-}
-
-int sd_rtnl_open_fd(sd_rtnl **ret, int fd) {
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
- socklen_t addrlen;
- int r, one = 1;
-
- assert_return(ret, -EINVAL);
- assert_return(fd >= 0, -EINVAL);
-
- r = sd_rtnl_new(&rtnl);
- if (r < 0)
- return r;
-
- r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
- if (r < 0)
- return -errno;
-
- r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
- if (r < 0)
- return -errno;
-
- addrlen = sizeof(rtnl->sockaddr);
-
- r = bind(fd, &rtnl->sockaddr.sa, addrlen);
- /* ignore EINVAL to allow opening an already bound socket */
- if (r < 0 && errno != EINVAL)
- return -errno;
-
- r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
- if (r < 0)
- return -errno;
-
- rtnl->fd = fd;
-
- *ret = rtnl;
- rtnl = NULL;
-
- return 0;
-}
-
-int sd_rtnl_open(sd_rtnl **ret) {
- _cleanup_close_ int fd = -1;
- int r;
-
- fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
- if (fd < 0)
- return -errno;
-
- r = sd_rtnl_open_fd(ret, fd);
- if (r < 0)
- return r;
-
- fd = -1;
-
- return 0;
-}
-
-static int rtnl_join_broadcast_group(sd_rtnl *rtnl, unsigned group) {
- int r;
-
- assert(rtnl);
- assert(rtnl->fd >= 0);
- assert(group > 0);
-
- r = setsockopt(rtnl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
- if (r < 0)
- return -errno;
-
- return 0;
-}
-
-int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
- return fd_inc_rcvbuf(rtnl->fd, size);
-}
-
-sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
- assert_return(rtnl, NULL);
- assert_return(!rtnl_pid_changed(rtnl), NULL);
-
- if (rtnl)
- assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
-
- return rtnl;
-}
-
-sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
- if (!rtnl)
- return NULL;
-
- assert_return(!rtnl_pid_changed(rtnl), NULL);
-
- if (REFCNT_DEC(rtnl->n_ref) == 0) {
- struct match_callback *f;
- unsigned i;
-
- for (i = 0; i < rtnl->rqueue_size; i++)
- sd_rtnl_message_unref(rtnl->rqueue[i]);
- free(rtnl->rqueue);
-
- for (i = 0; i < rtnl->rqueue_partial_size; i++)
- sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
- free(rtnl->rqueue_partial);
-
- for (i = 0; i < rtnl->wqueue_size; i++)
- sd_rtnl_message_unref(rtnl->wqueue[i]);
- free(rtnl->wqueue);
-
- free(rtnl->rbuffer);
-
- hashmap_free_free(rtnl->reply_callbacks);
- prioq_free(rtnl->reply_callbacks_prioq);
-
- sd_event_source_unref(rtnl->io_event_source);
- sd_event_source_unref(rtnl->time_event_source);
- sd_event_source_unref(rtnl->exit_event_source);
- sd_event_unref(rtnl->event);
-
- while ((f = rtnl->match_callbacks)) {
- LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
- free(f);
- }
-
- safe_close(rtnl->fd);
- free(rtnl);
- }
-
- return NULL;
-}
-
-static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
- assert(rtnl);
- assert(!rtnl_pid_changed(rtnl));
- assert(m);
- assert(m->hdr);
-
- /* don't use seq == 0, as that is used for broadcasts, so we
- would get confused by replies to such messages */
- m->hdr->nlmsg_seq = rtnl->serial++ ? : rtnl->serial++;
-
- rtnl_message_seal(m);
-
- return;
-}
-
-int sd_rtnl_send(sd_rtnl *nl,
- sd_rtnl_message *message,
- uint32_t *serial) {
- int r;
-
- assert_return(nl, -EINVAL);
- assert_return(!rtnl_pid_changed(nl), -ECHILD);
- assert_return(message, -EINVAL);
- assert_return(!message->sealed, -EPERM);
-
- rtnl_seal_message(nl, message);
-
- if (nl->wqueue_size <= 0) {
- /* send directly */
- r = socket_write_message(nl, message);
- if (r < 0)
- return r;
- else if (r == 0) {
- /* nothing was sent, so let's put it on
- * the queue */
- nl->wqueue[0] = sd_rtnl_message_ref(message);
- nl->wqueue_size = 1;
- }
- } else {
- /* append to queue */
- if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
- log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
- return -ENOBUFS;
- }
-
- if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
- return -ENOMEM;
-
- nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
- }
-
- if (serial)
- *serial = rtnl_message_get_serial(message);
-
- return 1;
-}
-
-int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
- assert(rtnl);
-
- if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
- log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
- return -ENOBUFS;
- }
-
- if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
- return -ENOMEM;
-
- return 0;
-}
-
-int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
- assert(rtnl);
-
- if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
- log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
- return -ENOBUFS;
- }
-
- if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
- rtnl->rqueue_partial_size + 1))
- return -ENOMEM;
-
- return 0;
-}
-
-static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
- int r;
-
- assert(rtnl);
- assert(message);
-
- if (rtnl->rqueue_size <= 0) {
- /* Try to read a new message */
- r = socket_read_message(rtnl);
- if (r <= 0)
- return r;
- }
-
- /* Dispatch a queued message */
- *message = rtnl->rqueue[0];
- rtnl->rqueue_size --;
- memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
-
- return 1;
-}
-
-static int dispatch_wqueue(sd_rtnl *rtnl) {
- int r, ret = 0;
-
- assert(rtnl);
-
- while (rtnl->wqueue_size > 0) {
- r = socket_write_message(rtnl, rtnl->wqueue[0]);
- if (r < 0)
- return r;
- else if (r == 0)
- /* Didn't do anything this time */
- return ret;
- else {
- /* see equivalent in sd-bus.c */
- sd_rtnl_message_unref(rtnl->wqueue[0]);
- rtnl->wqueue_size --;
- memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
-
- ret = 1;
- }
- }
-
- return ret;
-}
-
-static int process_timeout(sd_rtnl *rtnl) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
- struct reply_callback *c;
- usec_t n;
- int r;
-
- assert(rtnl);
-
- c = prioq_peek(rtnl->reply_callbacks_prioq);
- if (!c)
- return 0;
-
- n = now(CLOCK_MONOTONIC);
- if (c->timeout > n)
- return 0;
-
- r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
- if (r < 0)
- return r;
-
- assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
- hashmap_remove(rtnl->reply_callbacks, &c->serial);
-
- r = c->callback(rtnl, m, c->userdata);
- if (r < 0)
- log_debug_errno(r, "sd-rtnl: timedout callback failed: %m");
-
- free(c);
-
- return 1;
-}
-
-static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
- _cleanup_free_ struct reply_callback *c = NULL;
- uint64_t serial;
- uint16_t type;
- int r;
-
- assert(rtnl);
- assert(m);
-
- serial = rtnl_message_get_serial(m);
- c = hashmap_remove(rtnl->reply_callbacks, &serial);
- if (!c)
- return 0;
-
- if (c->timeout != 0)
- prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
-
- r = sd_rtnl_message_get_type(m, &type);
- if (r < 0)
- return 0;
-
- if (type == NLMSG_DONE)
- m = NULL;
-
- r = c->callback(rtnl, m, c->userdata);
- if (r < 0)
- log_debug_errno(r, "sd-rtnl: callback failed: %m");
-
- return 1;
-}
-
-static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
- struct match_callback *c;
- uint16_t type;
- int r;
-
- assert(rtnl);
- assert(m);
-
- r = sd_rtnl_message_get_type(m, &type);
- if (r < 0)
- return r;
-
- LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
- if (type == c->type) {
- r = c->callback(rtnl, m, c->userdata);
- if (r != 0) {
- if (r < 0)
- log_debug_errno(r, "sd-rtnl: match callback failed: %m");
-
- break;
- }
- }
- }
-
- return 1;
-}
-
-static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
- int r;
-
- assert(rtnl);
-
- r = process_timeout(rtnl);
- if (r != 0)
- goto null_message;
-
- r = dispatch_wqueue(rtnl);
- if (r != 0)
- goto null_message;
-
- r = dispatch_rqueue(rtnl, &m);
- if (r < 0)
- return r;
- if (!m)
- goto null_message;
-
- if (sd_rtnl_message_is_broadcast(m)) {
- r = process_match(rtnl, m);
- if (r != 0)
- goto null_message;
- } else {
- r = process_reply(rtnl, m);
- if (r != 0)
- goto null_message;
- }
-
- if (ret) {
- *ret = m;
- m = NULL;
-
- return 1;
- }
-
- return 1;
-
-null_message:
- if (r >= 0 && ret)
- *ret = NULL;
-
- return r;
-}
-
-int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
- RTNL_DONT_DESTROY(rtnl);
- int r;
-
- assert_return(rtnl, -EINVAL);
- assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
- assert_return(!rtnl->processing, -EBUSY);
-
- rtnl->processing = true;
- r = process_running(rtnl, ret);
- rtnl->processing = false;
-
- return r;
-}
-
-static usec_t calc_elapse(uint64_t usec) {
- if (usec == (uint64_t) -1)
- return 0;
-
- if (usec == 0)
- usec = RTNL_DEFAULT_TIMEOUT;
-
- return now(CLOCK_MONOTONIC) + usec;
-}
-
-static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
- struct pollfd p[1] = {};
- struct timespec ts;
- usec_t m = USEC_INFINITY;
- int r, e;
-
- assert(rtnl);
-
- e = sd_rtnl_get_events(rtnl);
- if (e < 0)
- return e;
-
- if (need_more)
- /* Caller wants more data, and doesn't care about
- * what's been read or any other timeouts. */
- e |= POLLIN;
- else {
- usec_t until;
- /* Caller wants to process if there is something to
- * process, but doesn't care otherwise */
-
- r = sd_rtnl_get_timeout(rtnl, &until);
- if (r < 0)
- return r;
- if (r > 0) {
- usec_t nw;
- nw = now(CLOCK_MONOTONIC);
- m = until > nw ? until - nw : 0;
- }
- }
-
- if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
- m = timeout_usec;
-
- p[0].fd = rtnl->fd;
- p[0].events = e;
-
- r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
- if (r < 0)
- return -errno;
-
- return r > 0 ? 1 : 0;
-}
-
-int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
- assert_return(nl, -EINVAL);
- assert_return(!rtnl_pid_changed(nl), -ECHILD);
-
- if (nl->rqueue_size > 0)
- return 0;
-
- return rtnl_poll(nl, false, timeout_usec);
-}
-
-static int timeout_compare(const void *a, const void *b) {
- const struct reply_callback *x = a, *y = b;
-
- if (x->timeout != 0 && y->timeout == 0)
- return -1;
-
- if (x->timeout == 0 && y->timeout != 0)
- return 1;
-
- if (x->timeout < y->timeout)
- return -1;
-
- if (x->timeout > y->timeout)
- return 1;
-
- return 0;
-}
-
-int sd_rtnl_call_async(sd_rtnl *nl,
- sd_rtnl_message *m,
- sd_rtnl_message_handler_t callback,
- void *userdata,
- uint64_t usec,
- uint32_t *serial) {
- struct reply_callback *c;
- uint32_t s;
- int r, k;
-
- assert_return(nl, -EINVAL);
- assert_return(m, -EINVAL);
- assert_return(callback, -EINVAL);
- assert_return(!rtnl_pid_changed(nl), -ECHILD);
-
- r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
- if (r < 0)
- return r;
-
- if (usec != (uint64_t) -1) {
- r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
- if (r < 0)
- return r;
- }
-
- c = new0(struct reply_callback, 1);
- if (!c)
- return -ENOMEM;
-
- c->callback = callback;
- c->userdata = userdata;
- c->timeout = calc_elapse(usec);
-
- k = sd_rtnl_send(nl, m, &s);
- if (k < 0) {
- free(c);
- return k;
- }
-
- c->serial = s;
-
- r = hashmap_put(nl->reply_callbacks, &c->serial, c);
- if (r < 0) {
- free(c);
- return r;
- }
-
- if (c->timeout != 0) {
- r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
- if (r > 0) {
- c->timeout = 0;
- sd_rtnl_call_async_cancel(nl, c->serial);
- return r;
- }
- }
-
- if (serial)
- *serial = s;
-
- return k;
-}
-
-int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
- struct reply_callback *c;
- uint64_t s = serial;
-
- assert_return(nl, -EINVAL);
- assert_return(serial != 0, -EINVAL);
- assert_return(!rtnl_pid_changed(nl), -ECHILD);
-
- c = hashmap_remove(nl->reply_callbacks, &s);
- if (!c)
- return 0;
-
- if (c->timeout != 0)
- prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
-
- free(c);
- return 1;
-}
-
-int sd_rtnl_call(sd_rtnl *rtnl,
- sd_rtnl_message *message,
- uint64_t usec,
- sd_rtnl_message **ret) {
- usec_t timeout;
- uint32_t serial;
- int r;
-
- assert_return(rtnl, -EINVAL);
- assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
- assert_return(message, -EINVAL);
-
- r = sd_rtnl_send(rtnl, message, &serial);
- if (r < 0)
- return r;
-
- timeout = calc_elapse(usec);
-
- for (;;) {
- usec_t left;
- unsigned i;
-
- for (i = 0; i < rtnl->rqueue_size; i++) {
- uint32_t received_serial;
-
- received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
-
- if (received_serial == serial) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
- uint16_t type;
-
- incoming = rtnl->rqueue[i];
-
- /* found a match, remove from rqueue and return it */
- memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
- sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
- rtnl->rqueue_size--;
-
- r = sd_rtnl_message_get_errno(incoming);
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_get_type(incoming, &type);
- if (r < 0)
- return r;
-
- if (type == NLMSG_DONE) {
- *ret = NULL;
- return 0;
- }
-
- if (ret) {
- *ret = incoming;
- incoming = NULL;
- }
-
- return 1;
- }
- }
-
- r = socket_read_message(rtnl);
- if (r < 0)
- return r;
- if (r > 0)
- /* received message, so try to process straight away */
- continue;
-
- if (timeout > 0) {
- usec_t n;
-
- n = now(CLOCK_MONOTONIC);
- if (n >= timeout)
- return -ETIMEDOUT;
-
- left = timeout - n;
- } else
- left = (uint64_t) -1;
-
- r = rtnl_poll(rtnl, true, left);
- if (r < 0)
- return r;
- else if (r == 0)
- return -ETIMEDOUT;
-
- r = dispatch_wqueue(rtnl);
- if (r < 0)
- return r;
- }
-}
-
-int sd_rtnl_flush(sd_rtnl *rtnl) {
- int r;
-
- assert_return(rtnl, -EINVAL);
- assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
- if (rtnl->wqueue_size <= 0)
- return 0;
-
- for (;;) {
- r = dispatch_wqueue(rtnl);
- if (r < 0)
- return r;
-
- if (rtnl->wqueue_size <= 0)
- return 0;
-
- r = rtnl_poll(rtnl, false, (uint64_t) -1);
- if (r < 0)
- return r;
- }
-}
-
-int sd_rtnl_get_events(sd_rtnl *rtnl) {
- int flags = 0;
-
- assert_return(rtnl, -EINVAL);
- assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
- if (rtnl->rqueue_size <= 0)
- flags |= POLLIN;
- if (rtnl->wqueue_size > 0)
- flags |= POLLOUT;
-
- return flags;
-}
-
-int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
- struct reply_callback *c;
-
- assert_return(rtnl, -EINVAL);
- assert_return(timeout_usec, -EINVAL);
- assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
- if (rtnl->rqueue_size > 0) {
- *timeout_usec = 0;
- return 1;
- }
-
- c = prioq_peek(rtnl->reply_callbacks_prioq);
- if (!c) {
- *timeout_usec = (uint64_t) -1;
- return 0;
- }
-
- *timeout_usec = c->timeout;
-
- return 1;
-}
-
-static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- sd_rtnl *rtnl = userdata;
- int r;
-
- assert(rtnl);
-
- r = sd_rtnl_process(rtnl, NULL);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
- sd_rtnl *rtnl = userdata;
- int r;
-
- assert(rtnl);
-
- r = sd_rtnl_process(rtnl, NULL);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int prepare_callback(sd_event_source *s, void *userdata) {
- sd_rtnl *rtnl = userdata;
- int r, e;
- usec_t until;
-
- assert(s);
- assert(rtnl);
-
- e = sd_rtnl_get_events(rtnl);
- if (e < 0)
- return e;
-
- r = sd_event_source_set_io_events(rtnl->io_event_source, e);
- if (r < 0)
- return r;
-
- r = sd_rtnl_get_timeout(rtnl, &until);
- if (r < 0)
- return r;
- if (r > 0) {
- int j;
-
- j = sd_event_source_set_time(rtnl->time_event_source, until);
- if (j < 0)
- return j;
- }
-
- r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int exit_callback(sd_event_source *event, void *userdata) {
- sd_rtnl *rtnl = userdata;
-
- assert(event);
-
- sd_rtnl_flush(rtnl);
-
- return 1;
-}
-
-int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
- int r;
-
- assert_return(rtnl, -EINVAL);
- assert_return(!rtnl->event, -EBUSY);
-
- assert(!rtnl->io_event_source);
- assert(!rtnl->time_event_source);
-
- if (event)
- rtnl->event = sd_event_ref(event);
- else {
- r = sd_event_default(&rtnl->event);
- if (r < 0)
- return r;
- }
-
- r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_priority(rtnl->io_event_source, priority);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
- if (r < 0)
- goto fail;
-
- r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_priority(rtnl->time_event_source, priority);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
- if (r < 0)
- goto fail;
-
- r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
- if (r < 0)
- goto fail;
-
- return 0;
-
-fail:
- sd_rtnl_detach_event(rtnl);
- return r;
-}
-
-int sd_rtnl_detach_event(sd_rtnl *rtnl) {
- assert_return(rtnl, -EINVAL);
- assert_return(rtnl->event, -ENXIO);
-
- if (rtnl->io_event_source)
- rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
-
- if (rtnl->time_event_source)
- rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
-
- if (rtnl->exit_event_source)
- rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
-
- if (rtnl->event)
- rtnl->event = sd_event_unref(rtnl->event);
-
- return 0;
-}
-
-int sd_rtnl_add_match(sd_rtnl *rtnl,
- uint16_t type,
- sd_rtnl_message_handler_t callback,
- void *userdata) {
- _cleanup_free_ struct match_callback *c = NULL;
- int r;
-
- assert_return(rtnl, -EINVAL);
- assert_return(callback, -EINVAL);
- assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
- c = new0(struct match_callback, 1);
- if (!c)
- return -ENOMEM;
-
- c->callback = callback;
- c->type = type;
- c->userdata = userdata;
-
- switch (type) {
- case RTM_NEWLINK:
- case RTM_SETLINK:
- case RTM_GETLINK:
- case RTM_DELLINK:
- r = rtnl_join_broadcast_group(rtnl, RTNLGRP_LINK);
- if (r < 0)
- return r;
-
- break;
- case RTM_NEWADDR:
- case RTM_GETADDR:
- case RTM_DELADDR:
- r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
- if (r < 0)
- return r;
-
- r = rtnl_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR);
- if (r < 0)
- return r;
-
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
-
- c = NULL;
-
- return 0;
-}
-
-int sd_rtnl_remove_match(sd_rtnl *rtnl,
- uint16_t type,
- sd_rtnl_message_handler_t callback,
- void *userdata) {
- struct match_callback *c;
-
- assert_return(rtnl, -EINVAL);
- assert_return(callback, -EINVAL);
- assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
-
- /* we should unsubscribe from the broadcast groups at this point, but it is not so
- trivial for a few reasons: the refcounting is a bit of a mess and not obvious
- how it will look like after we add genetlink support, and it is also not possible
- to query what broadcast groups were subscribed to when we inherit the socket to get
- the initial refcount. The latter could indeed be done for the first 32 broadcast
- groups (which incidentally is all we currently support in .socket units anyway),
- but we better not rely on only ever using 32 groups. */
- LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
- if (c->callback == callback && c->type == type && c->userdata == userdata) {
- LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
- free(c);
-
- return 1;
- }
-
- return 0;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <netinet/ether.h>
-#include <net/if.h>
-
-#include "util.h"
-#include "macro.h"
-#include "sd-rtnl.h"
-#include "socket-util.h"
-#include "rtnl-util.h"
-#include "event-util.h"
-#include "missing.h"
-
-static void test_message_link_bridge(sd_rtnl *rtnl) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL;
- uint32_t cost;
-
- assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0);
- assert_se(sd_rtnl_message_link_set_family(message, PF_BRIDGE) >= 0);
- assert_se(sd_rtnl_message_open_container(message, IFLA_PROTINFO) >= 0);
- assert_se(sd_rtnl_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0);
- assert_se(sd_rtnl_message_close_container(message) >= 0);
-
- assert_se(sd_rtnl_message_rewind(message) >= 0);
-
- assert_se(sd_rtnl_message_enter_container(message, IFLA_PROTINFO) >= 0);
- assert_se(sd_rtnl_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0);
- assert_se(cost == 10);
- assert_se(sd_rtnl_message_exit_container(message) >= 0);
-}
-
-static void test_link_configure(sd_rtnl *rtnl, int ifindex) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL;
- const char *mac = "98:fe:94:3f:c6:18", *name = "test";
- char buffer[ETHER_ADDR_TO_STRING_MAX];
- unsigned int mtu = 1450, mtu_out;
- const char *name_out;
- struct ether_addr mac_out;
-
- /* we'd really like to test NEWLINK, but let's not mess with the running kernel */
- assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_GETLINK, ifindex) >= 0);
- assert_se(sd_rtnl_message_append_string(message, IFLA_IFNAME, name) >= 0);
- assert_se(sd_rtnl_message_append_ether_addr(message, IFLA_ADDRESS, ether_aton(mac)) >= 0);
- assert_se(sd_rtnl_message_append_u32(message, IFLA_MTU, mtu) >= 0);
-
- assert_se(sd_rtnl_call(rtnl, message, 0, NULL) == 1);
- assert_se(sd_rtnl_message_rewind(message) >= 0);
-
- assert_se(sd_rtnl_message_read_string(message, IFLA_IFNAME, &name_out) >= 0);
- assert_se(streq(name, name_out));
-
- assert_se(sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &mac_out) >= 0);
- assert_se(streq(mac, ether_addr_to_string(&mac_out, buffer)));
-
- assert_se(sd_rtnl_message_read_u32(message, IFLA_MTU, &mtu_out) >= 0);
- assert_se(mtu == mtu_out);
-}
-
-static void test_link_get(sd_rtnl *rtnl, int ifindex) {
- sd_rtnl_message *m;
- sd_rtnl_message *r;
- unsigned int mtu = 1500;
- const char *str_data;
- uint8_t u8_data;
- uint32_t u32_data;
- struct ether_addr eth_data;
-
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
- assert_se(m);
-
- /* u8 test cases */
- assert_se(sd_rtnl_message_append_u8(m, IFLA_CARRIER, 0) >= 0);
- assert_se(sd_rtnl_message_append_u8(m, IFLA_OPERSTATE, 0) >= 0);
- assert_se(sd_rtnl_message_append_u8(m, IFLA_LINKMODE, 0) >= 0);
-
- /* u32 test cases */
- assert_se(sd_rtnl_message_append_u32(m, IFLA_MTU, mtu) >= 0);
- assert_se(sd_rtnl_message_append_u32(m, IFLA_GROUP, 0) >= 0);
- assert_se(sd_rtnl_message_append_u32(m, IFLA_TXQLEN, 0) >= 0);
- assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_TX_QUEUES, 0) >= 0);
- assert_se(sd_rtnl_message_append_u32(m, IFLA_NUM_RX_QUEUES, 0) >= 0);
-
- assert_se(sd_rtnl_call(rtnl, m, -1, &r) == 1);
-
- assert_se(sd_rtnl_message_read_string(r, IFLA_IFNAME, &str_data) == 0);
-
- assert_se(sd_rtnl_message_read_u8(r, IFLA_CARRIER, &u8_data) == 0);
- assert_se(sd_rtnl_message_read_u8(r, IFLA_OPERSTATE, &u8_data) == 0);
- assert_se(sd_rtnl_message_read_u8(r, IFLA_LINKMODE, &u8_data) == 0);
-
- assert_se(sd_rtnl_message_read_u32(r, IFLA_MTU, &u32_data) == 0);
- assert_se(sd_rtnl_message_read_u32(r, IFLA_GROUP, &u32_data) == 0);
- assert_se(sd_rtnl_message_read_u32(r, IFLA_TXQLEN, &u32_data) == 0);
- assert_se(sd_rtnl_message_read_u32(r, IFLA_NUM_TX_QUEUES, &u32_data) == 0);
- assert_se(sd_rtnl_message_read_u32(r, IFLA_NUM_RX_QUEUES, &u32_data) == 0);
-
- assert_se(sd_rtnl_message_read_ether_addr(r, IFLA_ADDRESS, ð_data) == 0);
-
- assert_se(sd_rtnl_flush(rtnl) >= 0);
- assert_se((m = sd_rtnl_message_unref(m)) == NULL);
- assert_se((r = sd_rtnl_message_unref(r)) == NULL);
-}
-
-
-static void test_address_get(sd_rtnl *rtnl, int ifindex) {
- sd_rtnl_message *m;
- sd_rtnl_message *r;
- struct in_addr in_data;
- struct ifa_cacheinfo cache;
- const char *label;
-
- assert_se(sd_rtnl_message_new_addr(rtnl, &m, RTM_GETADDR, ifindex, AF_INET) >= 0);
- assert_se(m);
-
- assert_se(sd_rtnl_call(rtnl, m, -1, &r) == 1);
-
- assert_se(sd_rtnl_message_read_in_addr(r, IFA_LOCAL, &in_data) == 0);
- assert_se(sd_rtnl_message_read_in_addr(r, IFA_ADDRESS, &in_data) == 0);
- assert_se(sd_rtnl_message_read_string(r, IFA_LABEL, &label) == 0);
- assert_se(sd_rtnl_message_read_cache_info(r, IFA_CACHEINFO, &cache) == 0);
-
- assert_se(sd_rtnl_flush(rtnl) >= 0);
- assert_se((m = sd_rtnl_message_unref(m)) == NULL);
- assert_se((r = sd_rtnl_message_unref(r)) == NULL);
-
-}
-
-static void test_route(void) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *req;
- struct in_addr addr, addr_data;
- uint32_t index = 2, u32_data;
- int r;
-
- r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
- if (r < 0) {
- log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
- return;
- }
-
- addr.s_addr = htonl(INADDR_LOOPBACK);
-
- r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
- if (r < 0) {
- log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
- return;
- }
-
- r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
- if (r < 0) {
- log_error_errno(r, "Could not append RTA_OIF attribute: %m");
- return;
- }
-
- assert_se(sd_rtnl_message_rewind(req) >= 0);
-
- assert_se(sd_rtnl_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0);
- assert_se(addr_data.s_addr == addr.s_addr);
-
- assert_se(sd_rtnl_message_read_u32(req, RTA_OIF, &u32_data) >= 0);
- assert_se(u32_data == index);
-
- assert_se((req = sd_rtnl_message_unref(req)) == NULL);
-}
-
-static void test_multiple(void) {
- sd_rtnl *rtnl1, *rtnl2;
-
- assert_se(sd_rtnl_open(&rtnl1) >= 0);
- assert_se(sd_rtnl_open(&rtnl2) >= 0);
-
- rtnl1 = sd_rtnl_unref(rtnl1);
- rtnl2 = sd_rtnl_unref(rtnl2);
-}
-
-static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
- char *ifname = userdata;
- const char *data;
-
- assert_se(rtnl);
- assert_se(m);
-
- log_info("got link info about %s", ifname);
- free(ifname);
-
- assert_se(sd_rtnl_message_read_string(m, IFLA_IFNAME, &data) >= 0);
- assert_se(streq(data, "lo"));
-
- return 1;
-}
-
-static void test_event_loop(int ifindex) {
- _cleanup_event_unref_ sd_event *event = NULL;
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
- _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
- char *ifname;
-
- ifname = strdup("lo2");
- assert_se(ifname);
-
- assert_se(sd_rtnl_open(&rtnl) >= 0);
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
-
- assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
-
- assert_se(sd_event_default(&event) >= 0);
-
- assert_se(sd_rtnl_attach_event(rtnl, event, 0) >= 0);
-
- assert_se(sd_event_run(event, 0) >= 0);
-
- assert_se(sd_rtnl_detach_event(rtnl) >= 0);
-
- assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-}
-
-static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
- int *counter = userdata;
- int r;
-
- (*counter) --;
-
- r = sd_rtnl_message_get_errno(m);
-
- log_info_errno(r, "%d left in pipe. got reply: %m", *counter);
-
- assert_se(r >= 0);
-
- return 1;
-}
-
-static void test_async(int ifindex) {
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
- _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL, *r = NULL;
- uint32_t serial;
- char *ifname;
-
- ifname = strdup("lo");
- assert_se(ifname);
-
- assert_se(sd_rtnl_open(&rtnl) >= 0);
-
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
-
- assert_se(sd_rtnl_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
-
- assert_se(sd_rtnl_wait(rtnl, 0) >= 0);
- assert_se(sd_rtnl_process(rtnl, &r) >= 0);
-
- assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-}
-
-static void test_pipe(int ifindex) {
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
- _cleanup_rtnl_message_unref_ sd_rtnl_message *m1 = NULL, *m2 = NULL;
- int counter = 0;
-
- assert_se(sd_rtnl_open(&rtnl) >= 0);
-
- assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
- assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
-
- counter ++;
- assert_se(sd_rtnl_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
-
- counter ++;
- assert_se(sd_rtnl_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
-
- while (counter > 0) {
- assert_se(sd_rtnl_wait(rtnl, 0) >= 0);
- assert_se(sd_rtnl_process(rtnl, NULL) >= 0);
- }
-
- assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-}
-
-static void test_container(void) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
- uint16_t u16_data;
- uint32_t u32_data;
- const char *string_data;
-
- assert_se(sd_rtnl_message_new_link(NULL, &m, RTM_NEWLINK, 0) >= 0);
-
- assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
- assert_se(sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "vlan") >= 0);
- assert_se(sd_rtnl_message_append_u16(m, IFLA_VLAN_ID, 100) >= 0);
- assert_se(sd_rtnl_message_close_container(m) >= 0);
- assert_se(sd_rtnl_message_append_string(m, IFLA_INFO_KIND, "vlan") >= 0);
- assert_se(sd_rtnl_message_close_container(m) >= 0);
- assert_se(sd_rtnl_message_close_container(m) == -EINVAL);
-
- assert_se(sd_rtnl_message_rewind(m) >= 0);
-
- assert_se(sd_rtnl_message_enter_container(m, IFLA_LINKINFO) >= 0);
- assert_se(sd_rtnl_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
- assert_se(streq("vlan", string_data));
-
- assert_se(sd_rtnl_message_enter_container(m, IFLA_INFO_DATA) >= 0);
- assert_se(sd_rtnl_message_read_u16(m, IFLA_VLAN_ID, &u16_data) >= 0);
- assert_se(sd_rtnl_message_exit_container(m) >= 0);
-
- assert_se(sd_rtnl_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
- assert_se(streq("vlan", string_data));
- assert_se(sd_rtnl_message_exit_container(m) >= 0);
-
- assert_se(sd_rtnl_message_read_u32(m, IFLA_LINKINFO, &u32_data) < 0);
-
- assert_se(sd_rtnl_message_exit_container(m) == -EINVAL);
-}
-
-static void test_match(void) {
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
-
- assert_se(sd_rtnl_open(&rtnl) >= 0);
-
- assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
- assert_se(sd_rtnl_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
-
- assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
- assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
- assert_se(sd_rtnl_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
-
- assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-}
-
-static void test_get_addresses(sd_rtnl *rtnl) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
- sd_rtnl_message *m;
-
- assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0);
-
- assert_se(sd_rtnl_call(rtnl, req, 0, &reply) >= 0);
-
- for (m = reply; m; m = sd_rtnl_message_next(m)) {
- uint16_t type;
- unsigned char scope, flags;
- int family, ifindex;
-
- assert_se(sd_rtnl_message_get_type(m, &type) >= 0);
- assert_se(type == RTM_NEWADDR);
-
- assert_se(sd_rtnl_message_addr_get_ifindex(m, &ifindex) >= 0);
- assert_se(sd_rtnl_message_addr_get_family(m, &family) >= 0);
- assert_se(sd_rtnl_message_addr_get_scope(m, &scope) >= 0);
- assert_se(sd_rtnl_message_addr_get_flags(m, &flags) >= 0);
-
- assert_se(ifindex > 0);
- assert_se(family == AF_INET || family == AF_INET6);
-
- log_info("got IPv%u address on ifindex %i", family == AF_INET ? 4: 6, ifindex);
- }
-}
-
-static void test_message(void) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-
- assert_se(rtnl_message_new_synthetic_error(-ETIMEDOUT, 1, &m) >= 0);
- assert_se(sd_rtnl_message_get_errno(m) == -ETIMEDOUT);
-}
-
-int main(void) {
- sd_rtnl *rtnl;
- sd_rtnl_message *m;
- sd_rtnl_message *r;
- const char *string_data;
- int if_loopback;
- uint16_t type;
-
- test_message();
-
- test_match();
-
- test_multiple();
-
- test_route();
-
- test_container();
-
- assert_se(sd_rtnl_open(&rtnl) >= 0);
- assert_se(rtnl);
-
- if_loopback = (int) if_nametoindex("lo");
- assert_se(if_loopback > 0);
-
- test_async(if_loopback);
-
- test_pipe(if_loopback);
-
- test_event_loop(if_loopback);
-
- test_link_configure(rtnl, if_loopback);
-
- test_get_addresses(rtnl);
-
- test_message_link_bridge(rtnl);
-
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);
- assert_se(m);
-
- assert_se(sd_rtnl_message_get_type(m, &type) >= 0);
- assert_se(type == RTM_GETLINK);
-
- assert_se(sd_rtnl_message_read_string(m, IFLA_IFNAME, &string_data) == -EPERM);
-
- assert_se(sd_rtnl_call(rtnl, m, 0, &r) == 1);
- assert_se(sd_rtnl_message_get_type(r, &type) >= 0);
- assert_se(type == RTM_NEWLINK);
-
- assert_se((r = sd_rtnl_message_unref(r)) == NULL);
-
- assert_se(sd_rtnl_call(rtnl, m, -1, &r) == -EPERM);
- assert_se((m = sd_rtnl_message_unref(m)) == NULL);
- assert_se((r = sd_rtnl_message_unref(r)) == NULL);
-
- test_link_get(rtnl, if_loopback);
- test_address_get(rtnl, if_loopback);
-
- assert_se(sd_rtnl_flush(rtnl) >= 0);
- assert_se((m = sd_rtnl_message_unref(m)) == NULL);
- assert_se((r = sd_rtnl_message_unref(r)) == NULL);
- assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
-
- return EXIT_SUCCESS;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2015 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "libudev-private.h"
-#include "sd-device.h"
-
-int device_enumerator_scan_devices(sd_device_enumerator *enumeartor);
-int device_enumerator_scan_subsystems(sd_device_enumerator *enumeartor);
-int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device);
-int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator);
-sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator);
-sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator);
- bool properties_read:1;
- bool tags_read:1;
- bool devlinks_read:1;
-
-#define FOREACH_DEVICE_AND_SUBSYSTEM(enumerator, device) \
- for (device = device_enumerator_get_first(enumerator); \
- device; \
- device = device_enumerator_get_next(enumerator))
+++ /dev/null
-/***
- This file is part of systemd.
-
- Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
- Copyright 2014-2015 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "util.h"
-#include "prioq.h"
-#include "strv.h"
-#include "set.h"
-
-#include "sd-device.h"
-
-#include "device-util.h"
-#include "device-enumerator-private.h"
-
-#define DEVICE_ENUMERATE_MAX_DEPTH 256
-
-typedef enum DeviceEnumerationType {
- DEVICE_ENUMERATION_TYPE_DEVICES,
- DEVICE_ENUMERATION_TYPE_SUBSYSTEMS,
- _DEVICE_ENUMERATION_TYPE_MAX,
- _DEVICE_ENUMERATION_TYPE_INVALID = -1,
-} DeviceEnumerationType;
-
-struct sd_device_enumerator {
- unsigned n_ref;
-
- DeviceEnumerationType type;
- Prioq *devices;
- bool scan_uptodate;
-
- Set *match_subsystem;
- Set *nomatch_subsystem;
- Hashmap *match_sysattr;
- Hashmap *nomatch_sysattr;
- Hashmap *match_property;
- Set *match_sysname;
- Set *match_tag;
- sd_device *match_parent;
- bool match_allow_uninitialized;
-};
-
-_public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
- _cleanup_device_enumerator_unref_ sd_device_enumerator *enumerator = NULL;
-
- assert(ret);
-
- enumerator = new0(sd_device_enumerator, 1);
- if (!enumerator)
- return -ENOMEM;
-
- enumerator->n_ref = 1;
- enumerator->type = _DEVICE_ENUMERATION_TYPE_INVALID;
-
- *ret = enumerator;
- enumerator = NULL;
-
- return 0;
-}
-
-_public_ sd_device_enumerator *sd_device_enumerator_ref(sd_device_enumerator *enumerator) {
- assert_return(enumerator, NULL);
-
- assert_se((++ enumerator->n_ref) >= 2);
-
- return enumerator;
-}
-
-_public_ sd_device_enumerator *sd_device_enumerator_unref(sd_device_enumerator *enumerator) {
- if (enumerator && (-- enumerator->n_ref) == 0) {
- sd_device *device;
-
- while ((device = prioq_pop(enumerator->devices)))
- sd_device_unref(device);
-
- prioq_free(enumerator->devices);
-
- set_free_free(enumerator->match_subsystem);
- set_free_free(enumerator->nomatch_subsystem);
- hashmap_free_free_free(enumerator->match_sysattr);
- hashmap_free_free_free(enumerator->nomatch_sysattr);
- hashmap_free_free_free(enumerator->match_property);
- set_free_free(enumerator->match_sysname);
- set_free_free(enumerator->match_tag);
- sd_device_unref(enumerator->match_parent);
-
- free(enumerator);
- }
-
- return NULL;
-}
-
-_public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match) {
- Set **set;
- int r;
-
- assert_return(enumerator, -EINVAL);
- assert_return(subsystem, -EINVAL);
-
- if (match)
- set = &enumerator->match_subsystem;
- else
- set = &enumerator->nomatch_subsystem;
-
- r = set_ensure_allocated(set, NULL);
- if (r < 0)
- return r;
-
- r = set_put_strdup(*set, subsystem);
- if (r < 0)
- return r;
-
- enumerator->scan_uptodate = false;
-
- return 0;
-}
-
-_public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *_sysattr, const char *_value, int match) {
- _cleanup_free_ char *sysattr = NULL, *value = NULL;
- Hashmap **hashmap;
- int r;
-
- assert_return(enumerator, -EINVAL);
- assert_return(_sysattr, -EINVAL);
-
- if (match)
- hashmap = &enumerator->match_sysattr;
- else
- hashmap = &enumerator->nomatch_sysattr;
-
- r = hashmap_ensure_allocated(hashmap, NULL);
- if (r < 0)
- return r;
-
- sysattr = strdup(_sysattr);
- if (!sysattr)
- return -ENOMEM;
-
- if (_value) {
- value = strdup(_value);
- if (!value)
- return -ENOMEM;
- }
-
- r = hashmap_put(*hashmap, sysattr, value);
- if (r < 0)
- return r;
-
- sysattr = NULL;
- value = NULL;
-
- enumerator->scan_uptodate = false;
-
- return 0;
-}
-
-_public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *_property, const char *_value) {
- _cleanup_free_ char *property = NULL, *value = NULL;
- int r;
-
- assert_return(enumerator, -EINVAL);
- assert_return(_property, -EINVAL);
-
- r = hashmap_ensure_allocated(&enumerator->match_property, NULL);
- if (r < 0)
- return r;
-
- property = strdup(_property);
- if (!property)
- return -ENOMEM;
-
- if (_value) {
- value = strdup(_value);
- if (!value)
- return -ENOMEM;
- }
-
- r = hashmap_put(enumerator->match_property, property, value);
- if (r < 0)
- return r;
-
- property = NULL;
- value = NULL;
-
- enumerator->scan_uptodate = false;
-
- return 0;
-}
-
-_public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
- int r;
-
- assert_return(enumerator, -EINVAL);
- assert_return(sysname, -EINVAL);
-
- r = set_ensure_allocated(&enumerator->match_sysname, NULL);
- if (r < 0)
- return r;
-
- r = set_put_strdup(enumerator->match_sysname, sysname);
- if (r < 0)
- return r;
-
- enumerator->scan_uptodate = false;
-
- return 0;
-}
-
-_public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag) {
- int r;
-
- assert_return(enumerator, -EINVAL);
- assert_return(tag, -EINVAL);
-
- r = set_ensure_allocated(&enumerator->match_tag, NULL);
- if (r < 0)
- return r;
-
- r = set_put_strdup(enumerator->match_tag, tag);
- if (r < 0)
- return r;
-
- enumerator->scan_uptodate = false;
-
- return 0;
-}
-
-_public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
- assert_return(enumerator, -EINVAL);
- assert_return(parent, -EINVAL);
-
- sd_device_unref(enumerator->match_parent);
- enumerator->match_parent = sd_device_ref(parent);
-
- enumerator->scan_uptodate = false;
-
- return 0;
-}
-
-_public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator) {
- assert_return(enumerator, -EINVAL);
-
- enumerator->match_allow_uninitialized = true;
-
- enumerator->scan_uptodate = false;
-
- return 0;
-}
-
-int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator) {
- assert_return(enumerator, -EINVAL);
-
- enumerator->match_allow_uninitialized = false;
-
- enumerator->scan_uptodate = false;
-
- return 0;
-}
-
-static int device_compare(const void *_a, const void *_b) {
- sd_device *a = (sd_device *)_a, *b = (sd_device *)_b;
- const char *devpath_a, *devpath_b, *sound_a;
- bool delay_a = false, delay_b = false;
-
- assert_se(sd_device_get_devpath(a, &devpath_a) >= 0);
- assert_se(sd_device_get_devpath(b, &devpath_b) >= 0);
-
- sound_a = strstr(devpath_a, "/sound/card");
- if (sound_a) {
- /* For sound cards the control device must be enumerated last to
- * make sure it's the final device node that gets ACLs applied.
- * Applications rely on this fact and use ACL changes on the
- * control node as an indicator that the ACL change of the
- * entire sound card completed. The kernel makes this guarantee
- * when creating those devices, and hence we should too when
- * enumerating them. */
- sound_a += strlen("/sound/card");
- sound_a = strchr(sound_a, '/');
-
- if (sound_a) {
- unsigned prefix_len;
-
- prefix_len = sound_a - devpath_a;
-
- if (strncmp(devpath_a, devpath_b, prefix_len) == 0) {
- const char *sound_b;
-
- sound_b = devpath_b + prefix_len;
-
- if (startswith(sound_a, "/controlC") &&
- !startswith(sound_b, "/contolC"))
- return 1;
-
- if (!startswith(sound_a, "/controlC") &&
- startswith(sound_b, "/controlC"))
- return -1;
- }
- }
- }
-
- /* md and dm devices are enumerated after all other devices */
- if (strstr(devpath_a, "/block/md") || strstr(devpath_a, "/block/dm-"))
- delay_a = true;
-
- if (strstr(devpath_b, "/block/md") || strstr(devpath_b, "/block/dm-"))
- delay_b = true;
-
- if (delay_a && !delay_b)
- return 1;
-
- if (!delay_a && delay_b)
- return -1;
-
- return strcmp(devpath_a, devpath_b);
-}
-
-int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
- int r;
-
- assert_return(enumerator, -EINVAL);
- assert_return(device, -EINVAL);
-
- r = prioq_ensure_allocated(&enumerator->devices, device_compare);
- if (r < 0)
- return r;
-
- r = prioq_put(enumerator->devices, device, NULL);
- if (r < 0)
- return r;
-
- sd_device_ref(device);
-
- return 0;
-}
-
-static bool match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) {
- const char *value;
- int r;
-
- assert(device);
- assert(sysattr);
-
- r = sd_device_get_sysattr_value(device, sysattr, &value);
- if (r < 0)
- return false;
-
- if (!match_value)
- return true;
-
- if (fnmatch(match_value, value, 0) == 0)
- return true;
-
- return false;
-}
-
-static bool match_sysattr(sd_device_enumerator *enumerator, sd_device *device) {
- const char *sysattr;
- const char *value;
- Iterator i;
-
- assert(enumerator);
- assert(device);
-
- HASHMAP_FOREACH_KEY(value, sysattr, enumerator->nomatch_sysattr, i)
- if (match_sysattr_value(device, sysattr, value))
- return false;
-
- HASHMAP_FOREACH_KEY(value, sysattr, enumerator->match_sysattr, i)
- if (!match_sysattr_value(device, sysattr, value))
- return false;
-
- return true;
-}
-
-static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
- const char *property;
- const char *value;
- Iterator i;
-
- assert(enumerator);
- assert(device);
-
- if (hashmap_isempty(enumerator->match_property))
- return true;
-
- HASHMAP_FOREACH_KEY(value, property, enumerator->match_property, i) {
- const char *property_dev, *value_dev;
-
- FOREACH_DEVICE_PROPERTY(device, property_dev, value_dev) {
- if (fnmatch(property, property_dev, 0) != 0)
- continue;
-
- if (!value && !value_dev)
- return true;
-
- if (!value || !value_dev)
- continue;
-
- if (fnmatch(value, value_dev, 0) == 0)
- return true;
- }
- }
-
- return false;
-}
-
-static bool match_tag(sd_device_enumerator *enumerator, sd_device *device) {
- const char *tag;
- Iterator i;
-
- assert(enumerator);
- assert(device);
-
- SET_FOREACH(tag, enumerator->match_tag, i)
- if (!sd_device_has_tag(device, tag))
- return false;
-
- return true;
-}
-
-static bool match_parent(sd_device_enumerator *enumerator, sd_device *device) {
- const char *devpath, *devpath_dev;
- int r;
-
- assert(enumerator);
- assert(device);
-
- if (!enumerator->match_parent)
- return true;
-
- r = sd_device_get_devpath(enumerator->match_parent, &devpath);
- assert(r >= 0);
-
- r = sd_device_get_devpath(device, &devpath_dev);
- assert(r >= 0);
-
- return startswith(devpath_dev, devpath);
-}
-
-static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
- const char *sysname_match;
- Iterator i;
-
- assert(enumerator);
- assert(sysname);
-
- if (set_isempty(enumerator->match_sysname))
- return true;
-
- SET_FOREACH(sysname_match, enumerator->match_sysname, i)
- if (fnmatch(sysname_match, sysname, 0) == 0)
- return true;
-
- return false;
-}
-
-static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, const char *basedir, const char *subdir1, const char *subdir2) {
- _cleanup_closedir_ DIR *dir = NULL;
- char *path;
- struct dirent *dent;
- int r = 0;
-
- assert(enumerator);
- assert(basedir);
-
- path = strjoina("/sys/", basedir, "/");
-
- if (subdir1)
- path = strjoina(path, subdir1, "/");
-
- if (subdir2)
- path = strjoina(path, subdir2, "/");
-
- dir = opendir(path);
- if (!dir)
- return -errno;
-
- FOREACH_DIRENT_ALL(dent, dir, return -errno) {
- _cleanup_device_unref_ sd_device *device = NULL;
- char syspath[strlen(path) + 1 + strlen(dent->d_name) + 1];
- dev_t devnum;
- int ifindex, initialized, k;
-
- if (dent->d_name[0] == '.')
- continue;
-
- if (!match_sysname(enumerator, dent->d_name))
- continue;
-
- (void)sprintf(syspath, "%s%s", path, dent->d_name);
-
- k = sd_device_new_from_syspath(&device, syspath);
- if (k < 0) {
- if (k != -ENODEV)
- /* this is necessarily racey, so ignore missing devices */
- r = k;
-
- continue;
- }
-
- k = sd_device_get_devnum(device, &devnum);
- if (k < 0) {
- r = k;
- continue;
- }
-
- k = sd_device_get_ifindex(device, &ifindex);
- if (k < 0) {
- r = k;
- continue;
- }
-
- k = sd_device_get_is_initialized(device, &initialized);
- if (k < 0) {
- r = k;
- continue;
- }
-
- /*
- * All devices with a device node or network interfaces
- * possibly need udev to adjust the device node permission
- * or context, or rename the interface before it can be
- * reliably used from other processes.
- *
- * For now, we can only check these types of devices, we
- * might not store a database, and have no way to find out
- * for all other types of devices.
- */
- if (!enumerator->match_allow_uninitialized &&
- !initialized &&
- (major(devnum) > 0 || ifindex > 0))
- continue;
-
- if (!match_parent(enumerator, device))
- continue;
-
- if (!match_tag(enumerator, device))
- continue;
-
- if (!match_property(enumerator, device))
- continue;
-
- if (!match_sysattr(enumerator, device))
- continue;
-
- k = device_enumerator_add_device(enumerator, device);
- if (k < 0)
- r = k;
- }
-
- return r;
-}
-
-static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
- const char *subsystem_match;
- Iterator i;
-
- assert(enumerator);
-
- if (!subsystem)
- return false;
-
- SET_FOREACH(subsystem_match, enumerator->nomatch_subsystem, i)
- if (fnmatch(subsystem_match, subsystem, 0) == 0)
- return false;
-
- if (set_isempty(enumerator->match_subsystem))
- return true;
-
- SET_FOREACH(subsystem_match, enumerator->match_subsystem, i)
- if (fnmatch(subsystem_match, subsystem, 0) == 0)
- return true;
-
- return false;
-}
-
-static int enumerator_scan_dir(sd_device_enumerator *enumerator, const char *basedir, const char *subdir, const char *subsystem) {
- _cleanup_closedir_ DIR *dir = NULL;
- char *path;
- struct dirent *dent;
- int r = 0;
-
- path = strjoina("/sys/", basedir);
-
- dir = opendir(path);
- if (!dir)
- return -errno;
-
- log_debug(" device-enumerator: scanning %s", path);
-
- FOREACH_DIRENT_ALL(dent, dir, return -errno) {
- int k;
-
- if (dent->d_name[0] == '.')
- continue;
-
- if (!match_subsystem(enumerator, subsystem ? : dent->d_name))
- continue;
-
- k = enumerator_scan_dir_and_add_devices(enumerator, basedir, dent->d_name, subdir);
- if (k < 0)
- r = k;
- }
-
- return r;
-}
-
-static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const char *tag) {
- _cleanup_closedir_ DIR *dir = NULL;
- char *path;
- struct dirent *dent;
- int r = 0;
-
- assert(enumerator);
- assert(tag);
-
- path = strjoina("/run/udev/tags/", tag);
-
- dir = opendir(path);
- if (!dir) {
- if (errno == ENOENT)
- return 0;
- else {
- log_error("sd-device-enumerator: could not open tags directory %s: %m", path);
- return -errno;
- }
- }
-
- /* TODO: filter away subsystems? */
-
- FOREACH_DIRENT_ALL(dent, dir, return -errno) {
- _cleanup_device_unref_ sd_device *device = NULL;
- const char *subsystem, *sysname;
- int k;
-
- if (dent->d_name[0] == '.')
- continue;
-
- k = sd_device_new_from_device_id(&device, dent->d_name);
- if (k < 0) {
- if (k != -ENODEV)
- /* this is necessarily racy, so ignore missing devices */
- r = k;
-
- continue;
- }
-
- k = sd_device_get_subsystem(device, &subsystem);
- if (k < 0) {
- r = k;
- continue;
- }
-
- if (!match_subsystem(enumerator, subsystem))
- continue;
-
- k = sd_device_get_sysname(device, &sysname);
- if (k < 0) {
- r = k;
- continue;
- }
-
- if (!match_sysname(enumerator, sysname))
- continue;
-
- if (!match_parent(enumerator, device))
- continue;
-
- if (!match_property(enumerator, device))
- continue;
-
- if (!match_sysattr(enumerator, device))
- continue;
-
- k = device_enumerator_add_device(enumerator, device);
- if (k < 0) {
- r = k;
- continue;
- }
- }
-
- return r;
-}
-
-static int enumerator_scan_devices_tags(sd_device_enumerator *enumerator) {
- const char *tag;
- Iterator i;
- int r;
-
- assert(enumerator);
-
- SET_FOREACH(tag, enumerator->match_tag, i) {
- r = enumerator_scan_devices_tag(enumerator, tag);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int parent_add_child(sd_device_enumerator *enumerator, const char *path) {
- _cleanup_device_unref_ sd_device *device = NULL;
- const char *subsystem, *sysname;
- int r;
-
- r = sd_device_new_from_syspath(&device, path);
- if (r == -ENODEV)
- /* this is necessarily racy, so ignore missing devices */
- return 0;
- else if (r < 0)
- return r;
-
- r = sd_device_get_subsystem(device, &subsystem);
- if (r < 0)
- return r;
-
- if (!match_subsystem(enumerator, subsystem))
- return 0;
-
- r = sd_device_get_sysname(device, &sysname);
- if (r < 0)
- return r;
-
- if (!match_sysname(enumerator, sysname))
- return 0;
-
- if (!match_property(enumerator, device))
- return 0;
-
- if (!match_sysattr(enumerator, device))
- return 0;
-
- r = device_enumerator_add_device(enumerator, device);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int parent_crawl_children(sd_device_enumerator *enumerator, const char *path, unsigned maxdepth) {
- _cleanup_closedir_ DIR *dir = NULL;
- struct dirent *dent;
- int r = 0;
-
- dir = opendir(path);
- if (!dir) {
- log_debug("sd-device-enumerate: could not open parent directory %s: %m", path);
- return -errno;
- }
-
- FOREACH_DIRENT_ALL(dent, dir, return -errno) {
- _cleanup_free_ char *child = NULL;
- int k;
-
- if (dent->d_name[0] == '.')
- continue;
-
- if (dent->d_type != DT_DIR)
- continue;
-
- child = strjoin(path, "/", dent->d_name, NULL);
- if (!child)
- return -ENOMEM;
-
- k = parent_add_child(enumerator, child);
- if (k < 0)
- r = k;
-
- if (maxdepth > 0)
- parent_crawl_children(enumerator, child, maxdepth - 1);
- else
- log_debug("device-enumerate: max depth reached, %s: ignoring devices", child);
- }
-
- return r;
-}
-
-static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
- const char *path;
- int r = 0, k;
-
- r = sd_device_get_syspath(enumerator->match_parent, &path);
- if (r < 0)
- return r;
-
- k = parent_add_child(enumerator, path);
- if (k < 0)
- r = k;
-
- k = parent_crawl_children(enumerator, path, DEVICE_ENUMERATE_MAX_DEPTH);
- if (k < 0)
- r = k;
-
- return r;
-}
-
-static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
- int r = 0;
-
- log_debug("device-enumerator: scan all dirs");
-
- if (access("/sys/subsystem", F_OK) >= 0) {
- /* we have /subsystem/, forget all the old stuff */
- r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL);
- if (r < 0) {
- log_debug("device-enumerator: failed to scan /sys/subsystem: %s", strerror(-r));
- return r;
- }
- } else {
- int k;
-
- k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
- if (k < 0) {
- log_debug_errno(k, "device-enumerator: failed to scan /sys/bus: %m");
- r = k;
- }
-
- k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
- if (k < 0) {
- log_debug_errno(k, "device-enumerator: failed to scan /sys/class: %m");
- r = k;
- }
- }
-
- return r;
-}
-
-int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
- sd_device *device;
- int r;
-
- assert(enumerator);
-
- if (enumerator->scan_uptodate &&
- enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
- return 0;
-
- while ((device = prioq_pop(enumerator->devices)))
- sd_device_unref(device);
-
- if (!set_isempty(enumerator->match_tag)) {
- r = enumerator_scan_devices_tags(enumerator);
- if (r < 0)
- return r;
- } else if (enumerator->match_parent) {
- r = enumerator_scan_devices_children(enumerator);
- if (r < 0)
- return r;
- } else {
- r = enumerator_scan_devices_all(enumerator);
- if (r < 0)
- return r;
- }
-
- enumerator->scan_uptodate = true;
-
- return 0;
-}
-
-_public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) {
- int r;
-
- assert_return(enumerator, NULL);
-
- r = device_enumerator_scan_devices(enumerator);
- if (r < 0)
- return NULL;
-
- enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
-
- return prioq_peek(enumerator->devices);
-}
-
-_public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator) {
- assert_return(enumerator, NULL);
-
- if (!enumerator->scan_uptodate ||
- enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES)
- return NULL;
-
- sd_device_unref(prioq_pop(enumerator->devices));
-
- return prioq_peek(enumerator->devices);
-}
-
-int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
- sd_device *device;
- const char *subsysdir;
- int r = 0, k;
-
- assert(enumerator);
-
- if (enumerator->scan_uptodate &&
- enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
- return 0;
-
- while ((device = prioq_pop(enumerator->devices)))
- sd_device_unref(device);
-
- /* modules */
- if (match_subsystem(enumerator, "module")) {
- k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
- if (k < 0) {
- log_debug_errno(k, "device-enumerator: failed to scan modules: %m");
- r = k;
- }
- }
-
- if (access("/sys/subsystem", F_OK) >= 0)
- subsysdir = "subsystem";
- else
- subsysdir = "bus";
-
- /* subsystems (only buses support coldplug) */
- if (match_subsystem(enumerator, "subsystem")) {
- k = enumerator_scan_dir_and_add_devices(enumerator, subsysdir, NULL, NULL);
- if (k < 0) {
- log_debug_errno(k, "device-enumerator: failed to scan subsystems: %m");
- r = k;
- }
- }
-
- /* subsystem drivers */
- if (match_subsystem(enumerator, "drivers")) {
- k = enumerator_scan_dir(enumerator, subsysdir, "drivers", "drivers");
- if (k < 0) {
- log_debug_errno(k, "device-enumerator: failed to scan drivers: %m");
- r = k;
- }
- }
-
- enumerator->scan_uptodate = true;
-
- return r;
-}
-
-_public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) {
- int r;
-
- assert_return(enumerator, NULL);
-
- r = device_enumerator_scan_subsystems(enumerator);
- if (r < 0)
- return NULL;
-
- enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
-
- return prioq_peek(enumerator->devices);
-}
-
-_public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator) {
- assert_return(enumerator, NULL);
-
- if (enumerator->scan_uptodate ||
- enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
- return NULL;
-
- sd_device_unref(prioq_pop(enumerator->devices));
-
- return prioq_peek(enumerator->devices);
-}
-
-sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
- assert_return(enumerator, NULL);
-
- return prioq_peek(enumerator->devices);
-}
-
-sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
- assert_return(enumerator, NULL);
-
- sd_device_unref(prioq_pop(enumerator->devices));
-
- return prioq_peek(enumerator->devices);
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <linux/netlink.h>
-
-#include "refcnt.h"
-#include "prioq.h"
-#include "list.h"
-
-#include "sd-netlink.h"
-
-#include "netlink-types.h"
-
-#define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
-
-#define RTNL_WQUEUE_MAX 1024
-#define RTNL_RQUEUE_MAX 64*1024
-
-#define RTNL_CONTAINER_DEPTH 32
-
-struct reply_callback {
- sd_netlink_message_handler_t callback;
- void *userdata;
- usec_t timeout;
- uint64_t serial;
- unsigned prioq_idx;
-};
-
-struct match_callback {
- sd_netlink_message_handler_t callback;
- uint16_t type;
- void *userdata;
-
- LIST_FIELDS(struct match_callback, match_callbacks);
-};
-
-struct sd_netlink {
- RefCount n_ref;
-
- int fd;
-
- union {
- struct sockaddr sa;
- struct sockaddr_nl nl;
- } sockaddr;
-
- sd_netlink_message **rqueue;
- unsigned rqueue_size;
- size_t rqueue_allocated;
-
- sd_netlink_message **rqueue_partial;
- unsigned rqueue_partial_size;
- size_t rqueue_partial_allocated;
-
- sd_netlink_message **wqueue;
- unsigned wqueue_size;
- size_t wqueue_allocated;
-
- struct nlmsghdr *rbuffer;
- size_t rbuffer_allocated;
-
- bool processing:1;
-
- uint32_t serial;
-
- struct Prioq *reply_callbacks_prioq;
- Hashmap *reply_callbacks;
-
- LIST_HEAD(struct match_callback, match_callbacks);
-
- pid_t original_pid;
-
- sd_event_source *io_event_source;
- sd_event_source *time_event_source;
- sd_event_source *exit_event_source;
- sd_event *event;
-};
-
-struct netlink_attribute {
- size_t offset; /* offset from hdr to attribute */
-};
-
-struct netlink_container {
- const struct NLTypeSystem *type_system; /* the type system of the container */
- size_t offset; /* offset from hdr to the start of the container */
- struct netlink_attribute *attributes;
- unsigned short n_attributes; /* number of attributes in container */
-};
-
-struct sd_netlink_message {
- RefCount n_ref;
-
- sd_netlink *rtnl;
-
- struct nlmsghdr *hdr;
- struct netlink_container containers[RTNL_CONTAINER_DEPTH];
- unsigned n_containers; /* number of containers */
- bool sealed:1;
- bool broadcast:1;
-
- sd_netlink_message *next; /* next in a chain of multi-part messages */
-};
-
-int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type);
-
-int socket_write_message(sd_netlink *nl, sd_netlink_message *m);
-int socket_read_message(sd_netlink *nl);
-
-int rtnl_rqueue_make_room(sd_netlink *rtnl);
-int rtnl_rqueue_partial_make_room(sd_netlink *rtnl);
-
-/* Make sure callbacks don't destroy the rtnl connection */
-#define RTNL_DONT_DESTROY(rtnl) \
- _cleanup_netlink_unref_ _unused_ sd_netlink *_dont_destroy_##rtnl = sd_netlink_ref(rtnl)
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <netinet/in.h>
-#include <stdbool.h>
-#include <unistd.h>
-
-#include "util.h"
-#include "socket-util.h"
-#include "formats-util.h"
-#include "refcnt.h"
-#include "missing.h"
-
-#include "sd-netlink.h"
-#include "netlink-util.h"
-#include "netlink-internal.h"
-#include "netlink-types.h"
-
-#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
-#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
-
-#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
-
-int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
- sd_netlink_message *m;
-
- assert_return(ret, -EINVAL);
-
- /* Note that 'rtnl' is currently unused, if we start using it internally
- we must take care to avoid problems due to mutual references between
- buses and their queued messages. See sd-bus.
- */
-
- m = new0(sd_netlink_message, 1);
- if (!m)
- return -ENOMEM;
-
- m->n_ref = REFCNT_INIT;
-
- m->sealed = false;
-
- *ret = m;
-
- return 0;
-}
-
-int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
- _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
- const NLType *nl_type;
- size_t size;
- int r;
-
- r = type_system_get_type(&type_system_root, &nl_type, type);
- if (r < 0)
- return r;
-
- if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
- return -EINVAL;
-
- r = message_new_empty(rtnl, &m);
- if (r < 0)
- return r;
-
- size = NLMSG_SPACE(type_get_size(nl_type));
-
- assert(size >= sizeof(struct nlmsghdr));
- m->hdr = malloc0(size);
- if (!m->hdr)
- return -ENOMEM;
-
- m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-
- type_get_type_system(nl_type, &m->container_type_system[0]);
- m->hdr->nlmsg_len = size;
- m->hdr->nlmsg_type = type;
-
- *ret = m;
- m = NULL;
-
- return 0;
-}
-
-int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
- assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
- m->hdr->nlmsg_type == RTM_GETADDR ||
- m->hdr->nlmsg_type == RTM_GETROUTE ||
- m->hdr->nlmsg_type == RTM_GETNEIGH,
- -EINVAL);
-
- if (dump)
- m->hdr->nlmsg_flags |= NLM_F_DUMP;
- else
- m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
-
- return 0;
-}
-
-sd_netlink_message *sd_netlink_message_ref(sd_netlink_message *m) {
- if (m)
- assert_se(REFCNT_INC(m->n_ref) >= 2);
-
- return m;
-}
-
-sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
- if (m && REFCNT_DEC(m->n_ref) == 0) {
- unsigned i;
-
- free(m->hdr);
-
- for (i = 0; i <= m->n_containers; i++)
- free(m->rta_offset_tb[i]);
-
- sd_netlink_message_unref(m->next);
-
- free(m);
- }
-
- return NULL;
-}
-
-int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
- assert_return(m, -EINVAL);
- assert_return(type, -EINVAL);
-
- *type = m->hdr->nlmsg_type;
-
- return 0;
-}
-
-int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
- assert_return(m, -EINVAL);
-
- return m->broadcast;
-}
-
-/* If successful the updated message will be correctly aligned, if
- unsuccessful the old message is untouched. */
-static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
- uint32_t rta_length;
- size_t message_length, padding_length;
- struct nlmsghdr *new_hdr;
- struct rtattr *rta;
- char *padding;
- unsigned i;
- int offset;
-
- assert(m);
- assert(m->hdr);
- assert(!m->sealed);
- assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
- assert(!data || data_length);
-
- /* get offset of the new attribute */
- offset = m->hdr->nlmsg_len;
-
- /* get the size of the new rta attribute (with padding at the end) */
- rta_length = RTA_LENGTH(data_length);
-
- /* get the new message size (with padding at the end) */
- message_length = offset + RTA_ALIGN(rta_length);
-
- /* realloc to fit the new attribute */
- new_hdr = realloc(m->hdr, message_length);
- if (!new_hdr)
- return -ENOMEM;
- m->hdr = new_hdr;
-
- /* get pointer to the attribute we are about to add */
- rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
-
- /* if we are inside containers, extend them */
- for (i = 0; i < m->n_containers; i++)
- GET_CONTAINER(m, i)->rta_len += message_length - offset;
-
- /* fill in the attribute */
- rta->rta_type = type;
- rta->rta_len = rta_length;
- if (data)
- /* we don't deal with the case where the user lies about the type
- * and gives us too little data (so don't do that)
- */
- padding = mempcpy(RTA_DATA(rta), data, data_length);
- else {
- /* if no data was passed, make sure we still initialize the padding
- note that we can have data_length > 0 (used by some containers) */
- padding = RTA_DATA(rta);
- }
-
- /* make sure also the padding at the end of the message is initialized */
- padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
- memzero(padding, padding_length);
-
- /* update message size */
- m->hdr->nlmsg_len = message_length;
-
- return offset;
-}
-
-static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
- const NLType *type;
- int r;
-
- assert(m);
-
- r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
- if (r < 0)
- return r;
-
- if (type_get_type(type) != data_type)
- return -EINVAL;
-
- if (out_size)
- *out_size = type_get_size(type);
- return 0;
-}
-
-int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
- size_t length, size;
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(data, -EINVAL);
-
- r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
- if (r < 0)
- return r;
-
- if (size) {
- length = strnlen(data, size+1);
- if (length > size)
- return -EINVAL;
- } else
- length = strlen(data);
-
- r = add_rtattr(m, type, data, length + 1);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type) {
- size_t size;
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
-
- r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_FLAG);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, NULL, 0);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, &data, sizeof(uint8_t));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-
-int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, &data, sizeof(uint16_t));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, &data, sizeof(uint32_t));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(data, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, data, sizeof(struct in_addr));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(data, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, data, sizeof(struct in6_addr));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(data, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, data, ETH_ALEN);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(info, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
- if (r < 0)
- return r;
-
- r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
- size_t size;
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
-
- r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
- if (r < 0) {
- const NLTypeSystemUnion *type_system_union;
- int family;
-
- r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_get_family(m, &family);
- if (r < 0)
- return r;
-
- r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
- if (r < 0)
- return r;
-
- r = type_system_union_protocol_get_type_system(type_system_union,
- &m->container_type_system[m->n_containers + 1],
- family);
- if (r < 0)
- return r;
- } else {
- r = type_system_get_type_system(m->container_type_system[m->n_containers],
- &m->container_type_system[m->n_containers + 1],
- type);
- if (r < 0)
- return r;
- }
-
- r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
- if (r < 0)
- return r;
-
- m->container_offsets[m->n_containers ++] = r;
-
- return 0;
-}
-
-int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
- const NLTypeSystemUnion *type_system_union;
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
-
- r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
- if (r < 0)
- return r;
-
- r = type_system_union_get_type_system(type_system_union,
- &m->container_type_system[m->n_containers + 1],
- key);
- if (r < 0)
- return r;
-
- r = sd_netlink_message_append_string(m, type_system_union->match, key);
- if (r < 0)
- return r;
-
- /* do we evere need non-null size */
- r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
- if (r < 0)
- return r;
-
- m->container_offsets[m->n_containers ++] = r;
-
- return 0;
-}
-
-
-int sd_netlink_message_close_container(sd_netlink_message *m) {
- assert_return(m, -EINVAL);
- assert_return(!m->sealed, -EPERM);
- assert_return(m->n_containers > 0, -EINVAL);
-
- m->container_type_system[m->n_containers] = NULL;
- m->n_containers --;
-
- return 0;
-}
-
-static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data) {
- struct rtattr *rta;
-
- assert_return(m, -EINVAL);
- assert_return(m->sealed, -EPERM);
- assert_return(data, -EINVAL);
- assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
- assert(m->rta_offset_tb[m->n_containers]);
- assert(type < m->rta_tb_size[m->n_containers]);
-
- if(!m->rta_offset_tb[m->n_containers][type])
- return -ENODATA;
-
- rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
-
- *data = RTA_DATA(rta);
-
- return RTA_PAYLOAD(rta);
-}
-
-int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
- if (r < 0)
- return r;
-
- r = netlink_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if (strnlen(attr_data, r) >= (size_t) r)
- return -EIO;
-
- if (data)
- *data = (const char *) attr_data;
-
- return 0;
-}
-
-int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
- if (r < 0)
- return r;
-
- r = netlink_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t) r < sizeof(uint8_t))
- return -EIO;
-
- if (data)
- *data = *(uint8_t *) attr_data;
-
- return 0;
-}
-
-int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
- if (r < 0)
- return r;
-
- r = netlink_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t) r < sizeof(uint16_t))
- return -EIO;
-
- if (data)
- *data = *(uint16_t *) attr_data;
-
- return 0;
-}
-
-int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
- if (r < 0)
- return r;
-
- r = netlink_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t)r < sizeof(uint32_t))
- return -EIO;
-
- if (data)
- *data = *(uint32_t *) attr_data;
-
- return 0;
-}
-
-int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
- if (r < 0)
- return r;
-
- r = netlink_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t)r < sizeof(struct ether_addr))
- return -EIO;
-
- if (data)
- memcpy(data, attr_data, sizeof(struct ether_addr));
-
- return 0;
-}
-
-int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
- if (r < 0)
- return r;
-
- r = netlink_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t)r < sizeof(struct ifa_cacheinfo))
- return -EIO;
-
- if (info)
- memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
-
- return 0;
-}
-
-int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
- if (r < 0)
- return r;
-
- r = netlink_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t)r < sizeof(struct in_addr))
- return -EIO;
-
- if (data)
- memcpy(data, attr_data, sizeof(struct in_addr));
-
- return 0;
-}
-
-int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
- int r;
- void *attr_data;
-
- assert_return(m, -EINVAL);
-
- r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
- if (r < 0)
- return r;
-
- r = netlink_message_read_internal(m, type, &attr_data);
- if (r < 0)
- return r;
- else if ((size_t)r < sizeof(struct in6_addr))
- return -EIO;
-
- if (data)
- memcpy(data, attr_data, sizeof(struct in6_addr));
-
- return 0;
-}
-
-static int netlink_message_parse(sd_netlink_message *m,
- size_t **rta_offset_tb,
- unsigned short *rta_tb_size,
- int count,
- struct rtattr *rta,
- unsigned int rt_len) {
- unsigned short type;
- size_t *tb;
-
- tb = new0(size_t, count);
- if(!tb)
- return -ENOMEM;
-
- *rta_tb_size = count;
-
- for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
- type = RTA_TYPE(rta);
-
- /* if the kernel is newer than the headers we used
- when building, we ignore out-of-range attributes
- */
- if (type >= count)
- continue;
-
- if (tb[type])
- log_debug("rtnl: message parse - overwriting repeated attribute");
-
- tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
- }
-
- *rta_offset_tb = tb;
-
- return 0;
-}
-
-int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
- const NLType *nl_type;
- const NLTypeSystem *type_system;
- void *container;
- uint16_t type;
- size_t size;
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
-
- r = type_system_get_type(m->container_type_system[m->n_containers],
- &nl_type,
- type_id);
- if (r < 0)
- return r;
-
- type = type_get_type(nl_type);
-
- if (type == NETLINK_TYPE_NESTED) {
- r = type_system_get_type_system(m->container_type_system[m->n_containers],
- &type_system,
- type_id);
- if (r < 0)
- return r;
- } else if (type == NETLINK_TYPE_UNION) {
- const NLTypeSystemUnion *type_system_union;
-
- r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
- &type_system_union,
- type_id);
- if (r < 0)
- return r;
-
- switch (type_system_union->match_type) {
- case NL_MATCH_SIBLING:
- {
- const char *key;
-
- r = sd_netlink_message_read_string(m, type_system_union->match, &key);
- if (r < 0)
- return r;
-
- r = type_system_union_get_type_system(type_system_union,
- &type_system,
- key);
- if (r < 0)
- return r;
-
- break;
- }
- case NL_MATCH_PROTOCOL:
- {
- int family;
-
- r = sd_rtnl_message_get_family(m, &family);
- if (r < 0)
- return r;
-
- r = type_system_union_protocol_get_type_system(type_system_union,
- &type_system,
- family);
- if (r < 0)
- return r;
-
- break;
- }
- default:
- assert_not_reached("sd-netlink: invalid type system union type");
- }
- } else
- return -EINVAL;
-
- r = netlink_message_read_internal(m, type_id, &container);
- if (r < 0)
- return r;
- else
- size = (size_t)r;
-
- m->n_containers ++;
-
- r = netlink_message_parse(m,
- &m->rta_offset_tb[m->n_containers],
- &m->rta_tb_size[m->n_containers],
- type_system_get_count(type_system),
- container,
- size);
- if (r < 0) {
- m->n_containers --;
- return r;
- }
-
- m->container_type_system[m->n_containers] = type_system;
-
- return 0;
-}
-
-int sd_netlink_message_exit_container(sd_netlink_message *m) {
- assert_return(m, -EINVAL);
- assert_return(m->sealed, -EINVAL);
- assert_return(m->n_containers > 0, -EINVAL);
-
- free(m->rta_offset_tb[m->n_containers]);
- m->rta_offset_tb[m->n_containers] = NULL;
- m->container_type_system[m->n_containers] = NULL;
-
- m->n_containers --;
-
- return 0;
-}
-
-uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
- assert(m);
- assert(m->hdr);
-
- return m->hdr->nlmsg_seq;
-}
-
-int sd_netlink_message_is_error(sd_netlink_message *m) {
- assert_return(m, 0);
- assert_return(m->hdr, 0);
-
- return m->hdr->nlmsg_type == NLMSG_ERROR;
-}
-
-int sd_netlink_message_get_errno(sd_netlink_message *m) {
- struct nlmsgerr *err;
-
- assert_return(m, -EINVAL);
- assert_return(m->hdr, -EINVAL);
-
- if (!sd_netlink_message_is_error(m))
- return 0;
-
- err = NLMSG_DATA(m->hdr);
-
- return err->error;
-}
-
-int sd_netlink_message_rewind(sd_netlink_message *m) {
- const NLType *nl_type;
- uint16_t type;
- size_t size;
- unsigned i;
- int r;
-
- assert_return(m, -EINVAL);
-
- /* don't allow appending to message once parsed */
- if (!m->sealed)
- rtnl_message_seal(m);
-
- for (i = 1; i <= m->n_containers; i++) {
- free(m->rta_offset_tb[i]);
- m->rta_offset_tb[i] = NULL;
- m->rta_tb_size[i] = 0;
- m->container_type_system[i] = NULL;
- }
-
- m->n_containers = 0;
-
- if (m->rta_offset_tb[0]) {
- /* top-level attributes have already been parsed */
- return 0;
- }
-
- assert(m->hdr);
-
- r = type_system_get_type(&type_system_root, &nl_type, m->hdr->nlmsg_type);
- if (r < 0)
- return r;
-
- type = type_get_type(nl_type);
- size = type_get_size(nl_type);
-
- if (type == NETLINK_TYPE_NESTED) {
- const NLTypeSystem *type_system;
-
- type_get_type_system(nl_type, &type_system);
-
- m->container_type_system[0] = type_system;
-
- r = netlink_message_parse(m,
- &m->rta_offset_tb[m->n_containers],
- &m->rta_tb_size[m->n_containers],
- type_system_get_count(type_system),
- (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
- NLMSG_PAYLOAD(m->hdr, size));
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-void rtnl_message_seal(sd_netlink_message *m) {
- assert(m);
- assert(!m->sealed);
-
- m->sealed = true;
-}
-
-sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
- assert_return(m, NULL);
-
- return m->next;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdint.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/in6.h>
-#include <linux/veth.h>
-#include <linux/if_bridge.h>
-#include <linux/if_addr.h>
-#include <linux/if.h>
-
-#include <linux/ip.h>
-#include <linux/if_link.h>
-#include <linux/if_tunnel.h>
-
-#include "macro.h"
-#include "util.h"
-
-#include "netlink-types.h"
-#include "missing.h"
-
-/* Maximum ARP IP target defined in kernel */
-#define BOND_MAX_ARP_TARGETS 16
-
-typedef enum {
- BOND_ARP_TARGETS_0,
- BOND_ARP_TARGETS_1,
- BOND_ARP_TARGETS_2,
- BOND_ARP_TARGETS_3,
- BOND_ARP_TARGETS_4,
- BOND_ARP_TARGETS_5,
- BOND_ARP_TARGETS_6,
- BOND_ARP_TARGETS_7,
- BOND_ARP_TARGETS_8,
- BOND_ARP_TARGETS_9,
- BOND_ARP_TARGETS_10,
- BOND_ARP_TARGETS_11,
- BOND_ARP_TARGETS_12,
- BOND_ARP_TARGETS_13,
- BOND_ARP_TARGETS_14,
- BOND_ARP_TARGETS_MAX = BOND_MAX_ARP_TARGETS,
-} BondArpTargets;
-
-struct NLType {
- uint16_t type;
- size_t size;
- const NLTypeSystem *type_system;
- const NLTypeSystemUnion *type_system_union;
-};
-
-struct NLTypeSystem {
- uint16_t count;
- const NLType *types;
-};
-
-static const NLTypeSystem rtnl_link_type_system;
-
-static const NLType empty_types[1] = {
- /* fake array to avoid .types==NULL, which denotes invalid type-systems */
-};
-
-static const NLTypeSystem empty_type_system = {
- .count = 0,
- .types = empty_types,
-};
-
-static const NLType rtnl_link_info_data_veth_types[VETH_INFO_MAX + 1] = {
- [VETH_INFO_PEER] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
-};
-
-static const NLType rtnl_link_info_data_ipvlan_types[IFLA_IPVLAN_MAX + 1] = {
- [IFLA_IPVLAN_MODE] = { .type = NETLINK_TYPE_U16 },
-};
-
-static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
- [IFLA_MACVLAN_MODE] = { .type = NETLINK_TYPE_U32 },
- [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
-};
-
-static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
- [IFLA_BRIDGE_FLAGS] = { .type = NETLINK_TYPE_U16 },
- [IFLA_BRIDGE_MODE] = { .type = NETLINK_TYPE_U16 },
-/*
- [IFLA_BRIDGE_VLAN_INFO] = { .type = NETLINK_TYPE_BINARY,
- .len = sizeof(struct bridge_vlan_info), },
-*/
-};
-
-static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
- [IFLA_VLAN_ID] = { .type = NETLINK_TYPE_U16 },
-/*
- [IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) },
- [IFLA_VLAN_EGRESS_QOS] = { .type = NETLINK_TYPE_NESTED },
- [IFLA_VLAN_INGRESS_QOS] = { .type = NETLINK_TYPE_NESTED },
-*/
- [IFLA_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 },
-};
-
-static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
- [IFLA_VXLAN_ID] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VXLAN_GROUP] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_VXLAN_LINK] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VXLAN_LOCAL] = { .type = NETLINK_TYPE_U32},
- [IFLA_VXLAN_TTL] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_TOS] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_LEARNING] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_AGEING] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VXLAN_LIMIT] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VXLAN_PORT_RANGE] = { .type = NETLINK_TYPE_U32},
- [IFLA_VXLAN_PROXY] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_RSC] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_L2MISS] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_L3MISS] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_PORT] = { .type = NETLINK_TYPE_U16 },
- [IFLA_VXLAN_GROUP6] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_VXLAN_LOCAL6] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_VXLAN_UDP_CSUM] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_REMCSUM_TX] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_REMCSUM_RX] = { .type = NETLINK_TYPE_U8 },
- [IFLA_VXLAN_GBP] = { .type = NETLINK_TYPE_FLAG },
- [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NETLINK_TYPE_FLAG },
-};
-
-static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = {
- [BOND_ARP_TARGETS_0] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_1] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_2] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_3] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_4] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_5] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_6] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_7] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_8] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_9] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_10] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_11] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_12] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_13] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_14] = { .type = NETLINK_TYPE_U32 },
- [BOND_ARP_TARGETS_MAX] = { .type = NETLINK_TYPE_U32 },
-};
-
-static const NLTypeSystem rtnl_bond_arp_type_system = {
- .count = ELEMENTSOF(rtnl_bond_arp_target_types),
- .types = rtnl_bond_arp_target_types,
-};
-
-static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
- [IFLA_BOND_MODE] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BOND_ACTIVE_SLAVE] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_MIIMON] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_UPDELAY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_DOWNDELAY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_USE_CARRIER] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BOND_ARP_INTERVAL] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_ARP_IP_TARGET] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_bond_arp_type_system },
- [IFLA_BOND_ARP_VALIDATE] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_ARP_ALL_TARGETS] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_PRIMARY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_PRIMARY_RESELECT] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BOND_FAIL_OVER_MAC] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BOND_XMIT_HASH_POLICY] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BOND_RESEND_IGMP] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_NUM_PEER_NOTIF] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BOND_ALL_SLAVES_ACTIVE] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BOND_MIN_LINKS] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_LP_INTERVAL] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_PACKETS_PER_SLAVE] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BOND_AD_LACP_RATE] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BOND_AD_SELECT] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BOND_AD_INFO] = { .type = NETLINK_TYPE_NESTED },
-};
-
-static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
- [IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 },
- [IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_IPTUN_TTL] = { .type = NETLINK_TYPE_U8 },
- [IFLA_IPTUN_TOS] = { .type = NETLINK_TYPE_U8 },
- [IFLA_IPTUN_PMTUDISC] = { .type = NETLINK_TYPE_U8 },
- [IFLA_IPTUN_FLAGS] = { .type = NETLINK_TYPE_U16 },
- [IFLA_IPTUN_PROTO] = { .type = NETLINK_TYPE_U8 },
- [IFLA_IPTUN_6RD_PREFIX] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NETLINK_TYPE_U32 },
- [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NETLINK_TYPE_U16 },
- [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NETLINK_TYPE_U16 },
- [IFLA_IPTUN_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 },
- [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 },
- [IFLA_IPTUN_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 },
- [IFLA_IPTUN_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 },
-};
-
-static const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
- [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 },
- [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 },
- [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 },
- [IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 },
- [IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 },
- [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 },
- [IFLA_GRE_FLOWINFO] = { .type = NETLINK_TYPE_U32 },
- [IFLA_GRE_FLAGS] = { .type = NETLINK_TYPE_U32 },
- [IFLA_GRE_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 },
- [IFLA_GRE_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 },
- [IFLA_GRE_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 },
- [IFLA_GRE_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 },
-};
-
-static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
- [IFLA_VTI_LINK] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VTI_IKEY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VTI_OKEY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_VTI_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_VTI_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
-};
-
-static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
- [IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 },
- [IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_IPTUN_TTL] = { .type = NETLINK_TYPE_U8 },
- [IFLA_IPTUN_FLAGS] = { .type = NETLINK_TYPE_U32 },
- [IFLA_IPTUN_PROTO] = { .type = NETLINK_TYPE_U8 },
- [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NETLINK_TYPE_U8 },
- [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32 },
-};
-
-/* these strings must match the .kind entries in the kernel */
-static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = {
- [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
- [NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge",
- [NL_UNION_LINK_INFO_DATA_VLAN] = "vlan",
- [NL_UNION_LINK_INFO_DATA_VETH] = "veth",
- [NL_UNION_LINK_INFO_DATA_DUMMY] = "dummy",
- [NL_UNION_LINK_INFO_DATA_MACVLAN] = "macvlan",
- [NL_UNION_LINK_INFO_DATA_MACVTAP] = "macvtap",
- [NL_UNION_LINK_INFO_DATA_IPVLAN] = "ipvlan",
- [NL_UNION_LINK_INFO_DATA_VXLAN] = "vxlan",
- [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = "ipip",
- [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = "gre",
- [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = "gretap",
- [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] = "ip6gre",
- [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = "ip6gretap",
- [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = "sit",
- [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti",
- [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6",
- [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
-
-static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = {
- [NL_UNION_LINK_INFO_DATA_BOND] = { .count = ELEMENTSOF(rtnl_link_info_data_bond_types),
- .types = rtnl_link_info_data_bond_types },
- [NL_UNION_LINK_INFO_DATA_BRIDGE] = { .count = ELEMENTSOF(rtnl_link_info_data_bridge_types),
- .types = rtnl_link_info_data_bridge_types },
- [NL_UNION_LINK_INFO_DATA_VLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_vlan_types),
- .types = rtnl_link_info_data_vlan_types },
- [NL_UNION_LINK_INFO_DATA_VETH] = { .count = ELEMENTSOF(rtnl_link_info_data_veth_types),
- .types = rtnl_link_info_data_veth_types },
- [NL_UNION_LINK_INFO_DATA_MACVLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_macvlan_types),
- .types = rtnl_link_info_data_macvlan_types },
- [NL_UNION_LINK_INFO_DATA_MACVTAP] = { .count = ELEMENTSOF(rtnl_link_info_data_macvlan_types),
- .types = rtnl_link_info_data_macvlan_types },
- [NL_UNION_LINK_INFO_DATA_IPVLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvlan_types),
- .types = rtnl_link_info_data_ipvlan_types },
- [NL_UNION_LINK_INFO_DATA_VXLAN] = { .count = ELEMENTSOF(rtnl_link_info_data_vxlan_types),
- .types = rtnl_link_info_data_vxlan_types },
- [NL_UNION_LINK_INFO_DATA_IPIP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_iptun_types),
- .types = rtnl_link_info_data_iptun_types },
- [NL_UNION_LINK_INFO_DATA_IPGRE_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
- .types = rtnl_link_info_data_ipgre_types },
- [NL_UNION_LINK_INFO_DATA_IPGRETAP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
- .types = rtnl_link_info_data_ipgre_types },
- [NL_UNION_LINK_INFO_DATA_IP6GRE_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
- .types = rtnl_link_info_data_ipgre_types },
- [NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipgre_types),
- .types = rtnl_link_info_data_ipgre_types },
- [NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_iptun_types),
- .types = rtnl_link_info_data_iptun_types },
- [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvti_types),
- .types = rtnl_link_info_data_ipvti_types },
- [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ipvti_types),
- .types = rtnl_link_info_data_ipvti_types },
- [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types),
- .types = rtnl_link_info_data_ip6tnl_types },
-
-};
-
-static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
- .num = _NL_UNION_LINK_INFO_DATA_MAX,
- .lookup = nl_union_link_info_data_from_string,
- .type_systems = rtnl_link_info_data_type_systems,
- .match_type = NL_MATCH_SIBLING,
- .match = IFLA_INFO_KIND,
-};
-
-static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = {
- [IFLA_INFO_KIND] = { .type = NETLINK_TYPE_STRING },
- [IFLA_INFO_DATA] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
-/*
- [IFLA_INFO_XSTATS],
- [IFLA_INFO_SLAVE_KIND] = { .type = NETLINK_TYPE_STRING },
- [IFLA_INFO_SLAVE_DATA] = { .type = NETLINK_TYPE_NESTED },
-*/
-};
-
-static const NLTypeSystem rtnl_link_info_type_system = {
- .count = ELEMENTSOF(rtnl_link_info_types),
- .types = rtnl_link_info_types,
-};
-
-static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
- [IFLA_BRPORT_STATE] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BRPORT_COST] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BRPORT_PRIORITY] = { .type = NETLINK_TYPE_U16 },
- [IFLA_BRPORT_MODE] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BRPORT_GUARD] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BRPORT_PROTECT] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BRPORT_FAST_LEAVE] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BRPORT_LEARNING] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BRPORT_PROXYARP] = { .type = NETLINK_TYPE_U8 },
- [IFLA_BRPORT_LEARNING_SYNC] = { .type = NETLINK_TYPE_U8 },
-};
-
-static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
- [AF_BRIDGE] = { .count = ELEMENTSOF(rtnl_prot_info_bridge_port_types),
- .types = rtnl_prot_info_bridge_port_types },
-};
-
-static const NLTypeSystemUnion rtnl_prot_info_type_system_union = {
- .num = AF_MAX,
- .type_systems = rtnl_prot_info_type_systems,
- .match_type = NL_MATCH_PROTOCOL,
-};
-
-static const struct NLType rtnl_af_spec_inet6_types[IFLA_INET6_MAX + 1] = {
- [IFLA_INET6_FLAGS] = { .type = NETLINK_TYPE_U32 },
-/*
- IFLA_INET6_CONF,
- IFLA_INET6_STATS,
- IFLA_INET6_MCAST,
- IFLA_INET6_CACHEINFO,
- IFLA_INET6_ICMP6STATS,
-*/
- [IFLA_INET6_TOKEN] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFLA_INET6_ADDR_GEN_MODE] = { .type = NETLINK_TYPE_U8 },
-};
-
-static const NLTypeSystem rtnl_af_spec_inet6_type_system = {
- .count = ELEMENTSOF(rtnl_af_spec_inet6_types),
- .types = rtnl_af_spec_inet6_types,
-};
-
-static const NLType rtnl_af_spec_types[AF_MAX + 1] = {
- [AF_INET6] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_inet6_type_system },
-};
-
-static const NLTypeSystem rtnl_af_spec_type_system = {
- .count = ELEMENTSOF(rtnl_af_spec_types),
- .types = rtnl_af_spec_types,
-};
-
-static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
- [IFLA_ADDRESS] = { .type = NETLINK_TYPE_ETHER_ADDR },
- [IFLA_BROADCAST] = { .type = NETLINK_TYPE_ETHER_ADDR },
- [IFLA_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
- [IFLA_MTU] = { .type = NETLINK_TYPE_U32 },
- [IFLA_LINK] = { .type = NETLINK_TYPE_U32 },
-/*
- [IFLA_QDISC],
- [IFLA_STATS],
- [IFLA_COST],
- [IFLA_PRIORITY],
-*/
- [IFLA_MASTER] = { .type = NETLINK_TYPE_U32 },
-/*
- [IFLA_WIRELESS],
-*/
- [IFLA_PROTINFO] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_prot_info_type_system_union },
- [IFLA_TXQLEN] = { .type = NETLINK_TYPE_U32 },
-/*
- [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) },
-*/
- [IFLA_WEIGHT] = { .type = NETLINK_TYPE_U32 },
- [IFLA_OPERSTATE] = { .type = NETLINK_TYPE_U8 },
- [IFLA_LINKMODE] = { .type = NETLINK_TYPE_U8 },
- [IFLA_LINKINFO] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_info_type_system },
- [IFLA_NET_NS_PID] = { .type = NETLINK_TYPE_U32 },
- [IFLA_IFALIAS] = { .type = NETLINK_TYPE_STRING, .size = IFALIASZ - 1 },
-/*
- [IFLA_NUM_VF],
- [IFLA_VFINFO_LIST] = {. type = NETLINK_TYPE_NESTED, },
- [IFLA_STATS64],
- [IFLA_VF_PORTS] = { .type = NETLINK_TYPE_NESTED },
- [IFLA_PORT_SELF] = { .type = NETLINK_TYPE_NESTED },
-*/
- [IFLA_AF_SPEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_type_system },
-/*
- [IFLA_VF_PORTS],
- [IFLA_PORT_SELF],
- [IFLA_AF_SPEC],
-*/
- [IFLA_GROUP] = { .type = NETLINK_TYPE_U32 },
- [IFLA_NET_NS_FD] = { .type = NETLINK_TYPE_U32 },
- [IFLA_EXT_MASK] = { .type = NETLINK_TYPE_U32 },
- [IFLA_PROMISCUITY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_NUM_TX_QUEUES] = { .type = NETLINK_TYPE_U32 },
- [IFLA_NUM_RX_QUEUES] = { .type = NETLINK_TYPE_U32 },
- [IFLA_CARRIER] = { .type = NETLINK_TYPE_U8 },
-/*
- [IFLA_PHYS_PORT_ID] = { .type = NETLINK_TYPE_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
-*/
-};
-
-static const NLTypeSystem rtnl_link_type_system = {
- .count = ELEMENTSOF(rtnl_link_types),
- .types = rtnl_link_types,
-};
-
-/* IFA_FLAGS was defined in kernel 3.14, but we still support older
- * kernels where IFA_MAX is lower. */
-static const NLType rtnl_address_types[CONST_MAX(IFA_MAX, IFA_FLAGS) + 1] = {
- [IFA_ADDRESS] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFA_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR },
- [IFA_LABEL] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
- [IFA_BROADCAST] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
- [IFA_CACHEINFO] = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct ifa_cacheinfo) },
-/*
- [IFA_ANYCAST],
- [IFA_MULTICAST],
-*/
- [IFA_FLAGS] = { .type = NETLINK_TYPE_U32 },
-};
-
-static const NLTypeSystem rtnl_address_type_system = {
- .count = ELEMENTSOF(rtnl_address_types),
- .types = rtnl_address_types,
-};
-
-static const NLType rtnl_route_types[RTA_MAX + 1] = {
- [RTA_DST] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
- [RTA_SRC] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
- [RTA_IIF] = { .type = NETLINK_TYPE_U32 },
- [RTA_OIF] = { .type = NETLINK_TYPE_U32 },
- [RTA_GATEWAY] = { .type = NETLINK_TYPE_IN_ADDR },
- [RTA_PRIORITY] = { .type = NETLINK_TYPE_U32 },
- [RTA_PREFSRC] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
-/*
- [RTA_METRICS] = { .type = NETLINK_TYPE_NESTED },
- [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
-*/
- [RTA_FLOW] = { .type = NETLINK_TYPE_U32 }, /* 6? */
-/*
- RTA_CACHEINFO,
- RTA_TABLE,
- RTA_MARK,
- RTA_MFC_STATS,
-*/
-};
-
-static const NLTypeSystem rtnl_route_type_system = {
- .count = ELEMENTSOF(rtnl_route_types),
- .types = rtnl_route_types,
-};
-
-static const NLType rtnl_neigh_types[NDA_MAX + 1] = {
- [NDA_DST] = { .type = NETLINK_TYPE_IN_ADDR },
- [NDA_LLADDR] = { .type = NETLINK_TYPE_ETHER_ADDR },
- [NDA_CACHEINFO] = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
- [NDA_PROBES] = { .type = NETLINK_TYPE_U32 },
- [NDA_VLAN] = { .type = NETLINK_TYPE_U16 },
- [NDA_PORT] = { .type = NETLINK_TYPE_U16 },
- [NDA_VNI] = { .type = NETLINK_TYPE_U32 },
- [NDA_IFINDEX] = { .type = NETLINK_TYPE_U32 },
-};
-
-static const NLTypeSystem rtnl_neigh_type_system = {
- .count = ELEMENTSOF(rtnl_neigh_types),
- .types = rtnl_neigh_types,
-};
-
-static const NLType rtnl_types[RTM_MAX + 1] = {
- [NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 },
- [NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
- [RTM_NEWLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
- [RTM_DELLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
- [RTM_GETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
- [RTM_SETLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
- [RTM_NEWADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
- [RTM_DELADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
- [RTM_GETADDR] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_address_type_system, .size = sizeof(struct ifaddrmsg) },
- [RTM_NEWROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
- [RTM_DELROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
- [RTM_GETROUTE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
- [RTM_NEWNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
- [RTM_DELNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
- [RTM_GETNEIGH] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
-};
-
-const NLTypeSystem type_system_root = {
- .count = ELEMENTSOF(rtnl_types),
- .types = rtnl_types,
-};
-
-uint16_t type_get_type(const NLType *type) {
- assert(type);
- return type->type;
-}
-
-size_t type_get_size(const NLType *type) {
- assert(type);
- return type->size;
-}
-
-void type_get_type_system(const NLType *nl_type, const NLTypeSystem **ret) {
- assert(nl_type);
- assert(ret);
- assert(nl_type->type == NETLINK_TYPE_NESTED);
- assert(nl_type->type_system);
-
- *ret = nl_type->type_system;
-}
-
-void type_get_type_system_union(const NLType *nl_type, const NLTypeSystemUnion **ret) {
- assert(nl_type);
- assert(ret);
- assert(nl_type->type == NETLINK_TYPE_UNION);
- assert(nl_type->type_system_union);
-
- *ret = nl_type->type_system_union;
-}
-
-uint16_t type_system_get_count(const NLTypeSystem *type_system) {
- assert(type_system);
- return type_system->count;
-}
-
-int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
- const NLType *nl_type;
-
- assert(ret);
- assert(type_system);
- assert(type_system->types);
-
- if (type >= type_system->count)
- return -EOPNOTSUPP;
-
- nl_type = &type_system->types[type];
-
- if (nl_type->type == NETLINK_TYPE_UNSPEC)
- return -EOPNOTSUPP;
-
- *ret = nl_type;
-
- return 0;
-}
-
-int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type) {
- const NLType *nl_type;
- int r;
-
- assert(ret);
-
- r = type_system_get_type(type_system, &nl_type, type);
- if (r < 0)
- return r;
-
- type_get_type_system(nl_type, ret);
- return 0;
-}
-
-int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type) {
- const NLType *nl_type;
- int r;
-
- assert(ret);
-
- r = type_system_get_type(type_system, &nl_type, type);
- if (r < 0)
- return r;
-
- type_get_type_system_union(nl_type, ret);
- return 0;
-}
-
-int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, const char *key) {
- int type;
-
- assert(type_system_union);
- assert(type_system_union->match_type == NL_MATCH_SIBLING);
- assert(type_system_union->lookup);
- assert(type_system_union->type_systems);
- assert(ret);
- assert(key);
-
- type = type_system_union->lookup(key);
- if (type < 0)
- return -EOPNOTSUPP;
-
- assert(type < type_system_union->num);
-
- *ret = &type_system_union->type_systems[type];
-
- return 0;
-}
-
-int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_system_union, const NLTypeSystem **ret, uint16_t protocol) {
- const NLTypeSystem *type_system;
-
- assert(type_system_union);
- assert(type_system_union->type_systems);
- assert(type_system_union->match_type == NL_MATCH_PROTOCOL);
- assert(ret);
-
- if (protocol >= type_system_union->num)
- return -EOPNOTSUPP;
-
- type_system = &type_system_union->type_systems[protocol];
- if (!type_system->types)
- return -EOPNOTSUPP;
-
- *ret = type_system;
-
- return 0;
-}
/***
This file is part of systemd.
- Copyright 2014 Daniel Mack
+ Copyright 2012 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-typedef struct BusEndpoint BusEndpoint;
-typedef struct BusEndpointPolicy BusEndpointPolicy;
+typedef struct Button Button;
-#include "hashmap.h"
-#include "bus-policy.h"
+#include "logind.h"
-struct BusEndpointPolicy {
- char *name;
- BusPolicyAccess access;
-};
+struct Button {
+ Manager *manager;
-struct BusEndpoint {
- Hashmap *policy_hash;
-};
+ sd_event_source *io_event_source;
+ sd_event_source *check_event_source;
-// UNNEEDED int bus_endpoint_new(BusEndpoint **ep);
-void bus_endpoint_free(BusEndpoint *endpoint);
+ char *name;
+ char *seat;
+ int fd;
-// UNNEEDED int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access);
+ bool lid_closed;
+ bool docked;
+};
-int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep);
+Button* button_new(Manager *m, const char *name);
+void button_free(Button*b);
+int button_open(Button *b);
+int button_set_seat(Button *b, const char *sn);
+int button_check_switches(Button *b);
int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
Session *s;
bool idle_hint;
- dual_timestamp ts = { 0, 0 };
+ dual_timestamp ts = DUAL_TIMESTAMP_NULL;
Iterator i;
assert(m);
}
#endif // 0
-bool manager_is_docked(Manager *m) {
+static bool manager_is_docked(Manager *m) {
Iterator i;
Button *b;
return false;
}
-int manager_count_displays(Manager *m) {
+static int manager_count_external_displays(Manager *m) {
_cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
struct udev_list_entry *item = NULL, *first = NULL;
int r;
udev_list_entry_foreach(item, first) {
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
struct udev_device *p;
- const char *status;
+ const char *status, *enabled, *dash, *nn, *i;
+ bool external = false;
d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
if (!d)
if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
continue;
+ nn = udev_device_get_sysname(d);
+ if (!nn)
+ continue;
+
+ /* Ignore internal displays: the type is encoded in
+ * the sysfs name, as the second dash seperated item
+ * (the first is the card name, the last the connector
+ * number). We implement a whitelist of external
+ * displays here, rather than a whitelist, to ensure
+ * we don't block suspends too eagerly. */
+ dash = strchr(nn, '-');
+ if (!dash)
+ continue;
+
+ dash++;
+ FOREACH_STRING(i, "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
+ "Composite-", "SVIDEO-", "Component-",
+ "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-") {
+
+ if (startswith(dash, i)) {
+ external = true;
+ break;
+ }
+ }
+ if (!external)
+ continue;
+
+ /* Ignore ports that are not enabled */
+ enabled = udev_device_get_sysattr_value(d, "enabled");
+ if (!enabled)
+ continue;
+ if (!streq_ptr(enabled, "enabled"))
+ continue;
+
/* We count any connector which is not explicitly
* "disconnected" as connected. */
status = udev_device_get_sysattr_value(d, "status");
return n;
}
-bool manager_is_docked_or_multiple_displays(Manager *m) {
+bool manager_is_docked_or_external_displays(Manager *m) {
int n;
/* If we are docked don't react to lid closing */
/* If we have more than one display connected,
* assume that we are docked. */
- n = manager_count_displays(m);
+ n = manager_count_external_displays(m);
if (n < 0)
log_warning_errno(n, "Display counting failed: %m");
- else if (n > 1) {
- log_debug("Multiple (%i) displays connected.", n);
+ else if (n >= 1) {
+ log_debug("External (%i) displays connected.", n);
return true;
}
sd_bus_error *error) {
Manager *m = userdata;
- dual_timestamp t;
+ dual_timestamp t = DUAL_TIMESTAMP_NULL;
assert(bus);
assert(reply);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction);
+static int property_get_docked(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(m);
+
+ return sd_bus_message_append(reply, "b", manager_is_docked_or_external_displays(m));
+}
+
static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Manager *m = userdata;
return r;
}
- manager_get_session_by_pid(m, leader, &session);
- if (session) {
- _cleanup_free_ char *path = NULL;
- _cleanup_close_ int fifo_fd = -1;
-
- /* Session already exists, client is probably
- * something like "su" which changes uid but is still
- * the same session */
-
- fifo_fd = session_create_fifo(session);
- if (fifo_fd < 0)
- return fifo_fd;
-
- path = session_bus_path(session);
- if (!path)
- return -ENOMEM;
-
- log_debug("Sending reply about an existing session: "
- "id=%s object_path=%s uid=%u runtime_path=%s "
- "session_fd=%d seat=%s vtnr=%u",
- session->id,
- path,
- (uint32_t) session->user->uid,
- session->user->runtime_path,
- fifo_fd,
- session->seat ? session->seat->id : "",
- (uint32_t) session->vtnr);
-
- return sd_bus_reply_method_return(
- message, "soshusub",
- session->id,
- path,
- session->user->runtime_path,
- fifo_fd,
- (uint32_t) session->user->uid,
- session->seat ? session->seat->id : "",
- (uint32_t) session->vtnr,
- true);
- }
+ r = manager_get_session_by_pid(m, leader, NULL);
+ if (r > 0)
+ return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already running in a session");
+
+ /*
+ * Old gdm and lightdm start the user-session on the same VT as
+ * the greeter session. But they destroy the greeter session
+ * after the user-session and want the user-session to take
+ * over the VT. We need to support this for
+ * backwards-compatibility, so make sure we allow new sessions
+ * on a VT that a greeter is running on. Furthermore, to allow
+ * re-logins, we have to allow a greeter to take over a used VT for
+ * the exact same reasons.
+ */
+ if (c != SESSION_GREETER &&
+ vtnr > 0 &&
+ vtnr < m->seat0->position_count &&
+ m->seat0->positions[vtnr] &&
+ m->seat0->positions[vtnr]->class != SESSION_GREETER)
+ return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session");
audit_session_from_pid(leader, &audit_id);
if (audit_id > 0) {
if (r < 0)
goto fail;
- session_save(session);
-
return 1;
fail:
if (!t)
return -ENOMEM;
- write_string_file(t, "change");
+ write_string_file(t, "change", WRITE_STRING_FILE_CREATE);
}
return 0;
return 0;
}
-static int manager_inhibit_timeout_handler(
- sd_event_source *s,
- uint64_t usec,
- void *userdata) {
+int manager_dispatch_delayed(Manager *manager, bool timeout) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
Inhibitor *offending = NULL;
- Manager *manager = userdata;
int r;
assert(manager);
- assert(manager->inhibit_timeout_source == s);
if (manager->action_what == 0)
return 0;
if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
_cleanup_free_ char *comm = NULL, *u = NULL;
+ if (!timeout)
+ return 0;
+
(void) get_process_comm(offending->pid, &comm);
u = uid_to_name(offending->uid);
manager->pending_action = HANDLE_IGNORE;
manager->action_what = 0;
+ return r;
}
- return 0;
+ return 1;
+}
+
+static int manager_inhibit_timeout_handler(
+ sd_event_source *s,
+ uint64_t usec,
+ void *userdata) {
+
+ Manager *manager = userdata;
+ int r;
+
+ assert(manager);
+ assert(manager->inhibit_timeout_source == s);
+
+ r = manager_dispatch_delayed(manager, true);
+ return (r < 0) ? r : 0;
}
static int delay_shutdown_or_sleep(
log_info("Creating /run/nologin, blocking further logins...");
- r = write_string_file_atomic("/run/nologin", "System is going down.");
+ r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
if (r < 0)
log_error_errno(r, "Failed to create /run/nologin: %m");
else
m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type);
m->scheduled_shutdown_timeout = 0;
+ if (m->unlink_nologin) {
+ (void) unlink("/run/nologin");
+ m->unlink_nologin = false;
+ }
+
if (cancelled) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
const char *tty = NULL;
SD_BUS_PROPERTY("PreparingForShutdown", "b", property_get_preparing, 0, 0),
SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0),
SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0),
+ SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0),
SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
session_jobs_reply(session, unit, result);
session_save(session);
+ user_save(session->user);
session_add_to_gc_queue(session);
}
if (fifo_fd < 0)
return fifo_fd;
- /* Update the session state file before we notify the client
- * about the result. */
+ /* Update the session and user state files before we notify
+ * the client about the result. */
session_save(s);
+ user_save(s->user);
p = session_bus_path(s);
if (!p)
#include "conf-parser.h"
#include "bus-util.h"
#include "bus-error.h"
-#include "logind.h"
#include "udev-util.h"
#include "formats-util.h"
+#include "signal-util.h"
#include "label.h"
-#include "label.h"
+#include "logind.h"
#include "cgroup.h"
#include "mount-setup.h"
#include "virt.h"
udev_unref(m->udev);
if (m->unlink_nologin)
- unlink("/run/nologin");
+ (void) unlink("/run/nologin");
bus_verify_polkit_async_registry_free(m->polkit_registry);
return -EINVAL;
}
- r = ignore_signals(SIGRTMIN + 1, -1);
- if (r < 0)
- return log_error_errno(r, "Cannot ignore SIGRTMIN + 1: %m");
-
- r = sigprocmask_many(SIG_BLOCK, SIGRTMIN, -1);
- if (r < 0)
- return log_error_errno(r, "Cannot block SIGRTMIN: %m");
+ assert_se(ignore_signals(SIGRTMIN + 1, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN, -1) >= 0);
r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m);
if (r < 0)
manager_gc(m, true);
+ r = manager_dispatch_delayed(m, false);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ continue;
+
r = sd_event_run(m->event, (uint64_t) -1);
if (r < 0)
return r;
int manager_get_user_by_pid(Manager *m, pid_t pid, User **user);
int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session);
-bool manager_is_docked(Manager *m);
-int manager_count_displays(Manager *m);
-bool manager_is_docked_or_multiple_displays(Manager *m);
+bool manager_is_docked_or_external_displays(Manager *m);
extern const sd_bus_vtable manager_vtable[];
int manager_setup_wall_message_timer(Manager *m);
bool logind_wall_tty_filter(const char *tty, void *userdata);
+
+int manager_dispatch_delayed(Manager *manager, bool timeout);
send_interface="org.freedesktop.login1.Session"
send_member="SetIdleHint"/>
- <allow send_destination="org.freedesktop.login1"
- send_interface="org.freedesktop.login1.Session"
- send_member="SetLockedHint"/>
-
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Session"
send_member="Kill"/>
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
-# See tmpfiles.d(5), systemd-user-session.service(5) and pam_nologin(8).
-# This file has special suffix so it is not run by mistake.
-
-F! /run/nologin 0644 - - - "System is booting up. See pam_nologin(8)"
+[D-BUS Service]
+Name=org.freedesktop.login1
+Exec=/bin/false
+User=root
+SystemdService=dbus-org.freedesktop.login1.service
global:
pam_sm_close_session;
pam_sm_open_session;
- _nss_mymachines_getpwnam_r;
- _nss_mymachines_getpwuid_r;
- _nss_mymachines_getgrnam_r;
- _nss_mymachines_getgrgid_r;
local: *;
};
/***
This file is part of systemd
- Copyright 2014 Zbigniew Jędrzejewski-Szmek
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "set.h"
+#include "logind-action.h"
+#include "logind-session.h"
-static void test_set_steal_first(void) {
- _cleanup_set_free_ Set *m = NULL;
- int seen[3] = {};
- char *val;
+#include "test-tables.h"
- m = set_new(&string_hash_ops);
- assert_se(m);
+int main(int argc, char **argv) {
+ test_table(handle_action, HANDLE_ACTION);
+ test_table(inhibit_mode, INHIBIT_MODE);
+ test_table(kill_who, KILL_WHO);
+ test_table(session_class, SESSION_CLASS);
+ test_table(session_state, SESSION_STATE);
+ test_table(session_type, SESSION_TYPE);
+ test_table(user_state, USER_STATE);
- assert_se(set_put(m, (void*) "1") == 1);
- assert_se(set_put(m, (void*) "22") == 1);
- assert_se(set_put(m, (void*) "333") == 1);
-
- while ((val = set_steal_first(m)))
- seen[strlen(val) - 1]++;
-
- assert_se(seen[0] == 1 && seen[1] == 1 && seen[2] == 1);
-
- assert_se(set_isempty(m));
-}
-
-static void test_set_put(void) {
- _cleanup_set_free_ Set *m = NULL;
-
- m = set_new(&string_hash_ops);
- assert_se(m);
-
- assert_se(set_put(m, (void*) "1") == 1);
- assert_se(set_put(m, (void*) "22") == 1);
- assert_se(set_put(m, (void*) "333") == 1);
- assert_se(set_put(m, (void*) "333") == 0);
- assert_se(set_remove(m, (void*) "333"));
- assert_se(set_put(m, (void*) "333") == 1);
- assert_se(set_put(m, (void*) "333") == 0);
- assert_se(set_put(m, (void*) "22") == 0);
-}
-
-int main(int argc, const char *argv[]) {
- test_set_steal_first();
- test_set_put();
-
- return 0;
+ return EXIT_SUCCESS;
}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Zbigniew Jędrzejewski-Szmek
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#pragma once
-
-#include <stdbool.h>
-
-#include "path-lookup.h"
-
-int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man);
-
-/* XXX: find an authoritative list of all pseudo types? */
-bool dns_type_is_pseudo(int n) {
- return IN_SET(n, DNS_TYPE_ANY, DNS_TYPE_AXFR, DNS_TYPE_IXFR, DNS_TYPE_OPT);
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-#include <stdbool.h>
-#include <termios.h>
-#include <unistd.h>
-#include <poll.h>
-#include <sys/inotify.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <sys/un.h>
-#include <stddef.h>
-#include <sys/signalfd.h>
-
-#include "util.h"
-#include "formats-util.h"
-#include "mkdir.h"
-#include "strv.h"
-#include "random-util.h"
-#include "terminal-util.h"
-#include "signal-util.h"
-#include "ask-password-api.h"
-
-static void backspace_chars(int ttyfd, size_t p) {
-
- if (ttyfd < 0)
- return;
-
- while (p > 0) {
- p--;
-
- loop_write(ttyfd, "\b \b", 3, false);
- }
-}
-
-int ask_password_tty(
- const char *message,
- usec_t until,
- bool echo,
- const char *flag_file,
- char **_passphrase) {
-
- struct termios old_termios, new_termios;
- char passphrase[LINE_MAX], *x;
- size_t p = 0;
- int r;
- _cleanup_close_ int ttyfd = -1, notify = -1;
- struct pollfd pollfd[2];
- bool reset_tty = false;
- bool silent_mode = false;
- bool dirty = false;
- enum {
- POLL_TTY,
- POLL_INOTIFY
- };
-
- assert(message);
- assert(_passphrase);
-
- if (flag_file) {
- notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
- if (notify < 0) {
- r = -errno;
- goto finish;
- }
-
- if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) {
- r = -errno;
- goto finish;
- }
- }
-
- ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (ttyfd >= 0) {
-
- if (tcgetattr(ttyfd, &old_termios) < 0) {
- r = -errno;
- goto finish;
- }
-
- loop_write(ttyfd, ANSI_HIGHLIGHT_ON, sizeof(ANSI_HIGHLIGHT_ON)-1, false);
- loop_write(ttyfd, message, strlen(message), false);
- loop_write(ttyfd, " ", 1, false);
- loop_write(ttyfd, ANSI_HIGHLIGHT_OFF, sizeof(ANSI_HIGHLIGHT_OFF)-1, false);
-
- new_termios = old_termios;
- new_termios.c_lflag &= ~(ICANON|ECHO);
- new_termios.c_cc[VMIN] = 1;
- new_termios.c_cc[VTIME] = 0;
-
- if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) {
- r = -errno;
- goto finish;
- }
-
- reset_tty = true;
- }
-
- zero(pollfd);
- pollfd[POLL_TTY].fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO;
- pollfd[POLL_TTY].events = POLLIN;
- pollfd[POLL_INOTIFY].fd = notify;
- pollfd[POLL_INOTIFY].events = POLLIN;
-
- for (;;) {
- char c;
- int sleep_for = -1, k;
- ssize_t n;
-
- if (until > 0) {
- usec_t y;
-
- y = now(CLOCK_MONOTONIC);
-
- if (y > until) {
- r = -ETIME;
- goto finish;
- }
-
- sleep_for = (int) ((until - y) / USEC_PER_MSEC);
- }
-
- if (flag_file)
- if (access(flag_file, F_OK) < 0) {
- r = -errno;
- goto finish;
- }
-
- k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for);
- if (k < 0) {
- if (errno == EINTR)
- continue;
-
- r = -errno;
- goto finish;
- } else if (k == 0) {
- r = -ETIME;
- goto finish;
- }
-
- if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
- flush_fd(notify);
-
- if (pollfd[POLL_TTY].revents == 0)
- continue;
-
- n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1);
- if (n < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
-
- r = -errno;
- goto finish;
-
- } else if (n == 0)
- break;
-
- if (c == '\n')
- break;
- else if (c == 21) { /* C-u */
-
- if (!silent_mode)
- backspace_chars(ttyfd, p);
- p = 0;
-
- } else if (c == '\b' || c == 127) {
-
- if (p > 0) {
-
- if (!silent_mode)
- backspace_chars(ttyfd, 1);
-
- p--;
- } else if (!dirty && !silent_mode) {
-
- silent_mode = true;
-
- /* There are two ways to enter silent
- * mode. Either by pressing backspace
- * as first key (and only as first key),
- * or ... */
- if (ttyfd >= 0)
- loop_write(ttyfd, "(no echo) ", 10, false);
-
- } else if (ttyfd >= 0)
- loop_write(ttyfd, "\a", 1, false);
-
- } else if (c == '\t' && !silent_mode) {
-
- backspace_chars(ttyfd, p);
- silent_mode = true;
-
- /* ... or by pressing TAB at any time. */
-
- if (ttyfd >= 0)
- loop_write(ttyfd, "(no echo) ", 10, false);
- } else {
- if (p >= sizeof(passphrase)-1) {
- loop_write(ttyfd, "\a", 1, false);
- continue;
- }
-
- passphrase[p++] = c;
-
- if (!silent_mode && ttyfd >= 0)
- loop_write(ttyfd, echo ? &c : "*", 1, false);
-
- dirty = true;
- }
- }
-
- x = strndup(passphrase, p);
- if (!x) {
- r = -ENOMEM;
- goto finish;
- }
-
- *_passphrase = x;
- r = 0;
-
-finish:
- if (ttyfd >= 0 && reset_tty) {
- loop_write(ttyfd, "\n", 1, false);
- tcsetattr(ttyfd, TCSADRAIN, &old_termios);
- }
-
- return r;
-}
-
-static int create_socket(char **name) {
- int fd;
- union {
- struct sockaddr sa;
- struct sockaddr_un un;
- } sa = {
- .un.sun_family = AF_UNIX,
- };
- int one = 1;
- int r = 0;
- char *c;
-
- assert(name);
-
- fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0)
- return log_error_errno(errno, "socket() failed: %m");
-
- snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64());
-
- RUN_WITH_UMASK(0177) {
- r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
- }
-
- if (r < 0) {
- r = -errno;
- log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
- goto fail;
- }
-
- if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
- r = -errno;
- log_error_errno(errno, "SO_PASSCRED failed: %m");
- goto fail;
- }
-
- c = strdup(sa.un.sun_path);
- if (!c) {
- r = log_oom();
- goto fail;
- }
-
- *name = c;
- return fd;
-
-fail:
- safe_close(fd);
-
- return r;
-}
-
-int ask_password_agent(
- const char *message,
- const char *icon,
- const char *id,
- usec_t until,
- bool echo,
- bool accept_cached,
- char ***_passphrases) {
-
- enum {
- FD_SOCKET,
- FD_SIGNAL,
- _FD_MAX
- };
-
- char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
- char final[sizeof(temp)] = "";
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *socket_name = NULL;
- _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1;
- sigset_t mask, oldmask;
- struct pollfd pollfd[_FD_MAX];
- int r;
-
- assert(_passphrases);
-
- assert_se(sigemptyset(&mask) >= 0);
- assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
- assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
-
- mkdir_p_label("/run/systemd/ask-password", 0755);
-
- fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
- if (fd < 0) {
- log_error_errno(errno, "Failed to create password file: %m");
- r = -errno;
- goto finish;
- }
-
- fchmod(fd, 0644);
-
- f = fdopen(fd, "w");
- if (!f) {
- log_error_errno(errno, "Failed to allocate FILE: %m");
- r = -errno;
- goto finish;
- }
-
- fd = -1;
-
- signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
- if (signal_fd < 0) {
- log_error_errno(errno, "signalfd(): %m");
- r = -errno;
- goto finish;
- }
-
- socket_fd = create_socket(&socket_name);
- if (socket_fd < 0) {
- r = socket_fd;
- goto finish;
- }
-
- fprintf(f,
- "[Ask]\n"
- "PID="PID_FMT"\n"
- "Socket=%s\n"
- "AcceptCached=%i\n"
- "Echo=%i\n"
- "NotAfter="USEC_FMT"\n",
- getpid(),
- socket_name,
- accept_cached ? 1 : 0,
- echo ? 1 : 0,
- until);
-
- if (message)
- fprintf(f, "Message=%s\n", message);
-
- if (icon)
- fprintf(f, "Icon=%s\n", icon);
-
- if (id)
- fprintf(f, "Id=%s\n", id);
-
- fflush(f);
-
- if (ferror(f)) {
- log_error_errno(errno, "Failed to write query file: %m");
- r = -errno;
- goto finish;
- }
-
- memcpy(final, temp, sizeof(temp));
-
- final[sizeof(final)-11] = 'a';
- final[sizeof(final)-10] = 's';
- final[sizeof(final)-9] = 'k';
-
- if (rename(temp, final) < 0) {
- log_error_errno(errno, "Failed to rename query file: %m");
- r = -errno;
- goto finish;
- }
-
- zero(pollfd);
- pollfd[FD_SOCKET].fd = socket_fd;
- pollfd[FD_SOCKET].events = POLLIN;
- pollfd[FD_SIGNAL].fd = signal_fd;
- pollfd[FD_SIGNAL].events = POLLIN;
-
- for (;;) {
- char passphrase[LINE_MAX+1];
- struct msghdr msghdr;
- struct iovec iovec;
- struct ucred *ucred;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
- } control;
- ssize_t n;
- int k;
- usec_t t;
-
- t = now(CLOCK_MONOTONIC);
-
- if (until > 0 && until <= t) {
- log_notice("Timed out");
- r = -ETIME;
- goto finish;
- }
-
- k = poll(pollfd, _FD_MAX, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1);
- if (k < 0) {
- if (errno == EINTR)
- continue;
-
- log_error_errno(errno, "poll() failed: %m");
- r = -errno;
- goto finish;
- }
-
- if (k <= 0) {
- log_notice("Timed out");
- r = -ETIME;
- goto finish;
- }
-
- if (pollfd[FD_SIGNAL].revents & POLLIN) {
- r = -EINTR;
- goto finish;
- }
-
- if (pollfd[FD_SOCKET].revents != POLLIN) {
- log_error("Unexpected poll() event.");
- r = -EIO;
- goto finish;
- }
-
- zero(iovec);
- iovec.iov_base = passphrase;
- iovec.iov_len = sizeof(passphrase);
-
- zero(control);
- zero(msghdr);
- msghdr.msg_iov = &iovec;
- msghdr.msg_iovlen = 1;
- msghdr.msg_control = &control;
- msghdr.msg_controllen = sizeof(control);
-
- n = recvmsg(socket_fd, &msghdr, 0);
- if (n < 0) {
- if (errno == EAGAIN ||
- errno == EINTR)
- continue;
-
- log_error_errno(errno, "recvmsg() failed: %m");
- r = -errno;
- goto finish;
- }
-
- cmsg_close_all(&msghdr);
-
- if (n <= 0) {
- log_error("Message too short");
- continue;
- }
-
- if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
- control.cmsghdr.cmsg_level != SOL_SOCKET ||
- control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
- control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
- log_warning("Received message without credentials. Ignoring.");
- continue;
- }
-
- ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
- if (ucred->uid != 0) {
- log_warning("Got request from unprivileged user. Ignoring.");
- continue;
- }
-
- if (passphrase[0] == '+') {
- char **l;
-
- if (n == 1)
- l = strv_new("", NULL);
- else
- l = strv_parse_nulstr(passphrase+1, n-1);
- /* An empty message refers to the empty password */
-
- if (!l) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (strv_length(l) <= 0) {
- strv_free(l);
- log_error("Invalid packet");
- continue;
- }
-
- *_passphrases = l;
-
- } else if (passphrase[0] == '-') {
- r = -ECANCELED;
- goto finish;
- } else {
- log_error("Invalid packet");
- continue;
- }
-
- break;
- }
-
- r = 0;
-
-finish:
- if (socket_name)
- unlink(socket_name);
-
- unlink(temp);
-
- if (final[0])
- unlink(final);
-
- assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
-
- return r;
-}
-
-int ask_password_auto(const char *message, const char *icon, const char *id,
- usec_t until, bool accept_cached, char ***_passphrases) {
- assert(message);
- assert(_passphrases);
-
- if (isatty(STDIN_FILENO)) {
- int r;
- char *s = NULL, **l = NULL;
-
- r = ask_password_tty(message, until, false, NULL, &s);
- if (r < 0)
- return r;
-
- r = strv_consume(&l, s);
- if (r < 0)
- return r;
-
- *_passphrases = l;
- return r;
- } else
- return ask_password_agent(message, icon, id, until, false, accept_cached, _passphrases);
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-
-int ask_password_tty(const char *message, usec_t until, bool echo, const char *flag_file, char **_passphrase);
-
-int ask_password_agent(const char *message, const char *icon, const char *id,
- usec_t until, bool echo, bool accept_cached, char ***_passphrases);
-
-int ask_password_auto(const char *message, const char *icon, const char *id,
- usec_t until, bool accept_cached, char ***_passphrases);
- SD_BUS_PROPERTY("TimeoutIdleUSec", "t", bus_property_get_usec, offsetof(Automount, timeout_idle_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "sd-bus.h"
-#include "proxy.h"
-
-int synthetic_driver_send(sd_bus *b, sd_bus_message *m);
-
-int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...);
-int synthetic_reply_method_return_strv(sd_bus_message *call, char **l);
-
-int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e);
-int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) _sd_printf_(3, 4);
-int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p);
-int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) _sd_printf_(3, 4);
-
-int synthesize_name_acquired(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m);
return set_put_strdup(d->jobs, path);
}
+int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
+ int r;
+
+ r = bus_wait_for_jobs_add(d, path);
+ if (r < 0)
+ return log_oom();
+
+ return bus_wait_for_jobs(d, quiet);
+}
+
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
const char *type, *path, *source;
int r;
#include "util.h"
#include "formats-util.h"
+#include "process-util.h"
#include "macro.h"
#include "path-util.h"
#include "cgroup-util.h"
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <fnmatch.h>
-
-#include "sd-id128.h"
-#include "util.h"
-#include "virt.h"
-#include "path-util.h"
-#include "architecture.h"
-#include "smack-util.h"
-#include "apparmor-util.h"
-#include "ima-util.h"
-#include "selinux-util.h"
-#include "audit.h"
-#include "cap-list.h"
-#include "hostname-util.h"
-#include "condition.h"
-
-Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
- Condition *c;
- int r;
-
- assert(type >= 0);
- assert(type < _CONDITION_TYPE_MAX);
- assert((!parameter) == (type == CONDITION_NULL));
-
- c = new0(Condition, 1);
- if (!c)
- return NULL;
-
- c->type = type;
- c->trigger = trigger;
- c->negate = negate;
-
- r = free_and_strdup(&c->parameter, parameter);
- if (r < 0) {
- free(c);
- return NULL;
- }
-
- return c;
-}
-
-void condition_free(Condition *c) {
- assert(c);
-
- free(c->parameter);
- free(c);
-}
-
-Condition* condition_free_list(Condition *first) {
- Condition *c, *n;
-
- LIST_FOREACH_SAFE(conditions, c, n, first)
- condition_free(c);
-
- return NULL;
-}
-
-static int condition_test_kernel_command_line(Condition *c) {
- _cleanup_free_ char *line = NULL;
- const char *p;
- bool equal;
- int r;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_KERNEL_COMMAND_LINE);
-
- r = proc_cmdline(&line);
- if (r < 0)
- return r;
-
- equal = !!strchr(c->parameter, '=');
- p = line;
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
- bool found;
-
- r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
- if (r < 0)
- return r;
- if (r == 0)
- break;
-
- if (equal)
- found = streq(word, c->parameter);
- else {
- const char *f;
-
- f = startswith(word, c->parameter);
- found = f && (*f == '=' || *f == 0);
- }
-
- if (found)
- return true;
- }
-
- return false;
-}
-
-static int condition_test_virtualization(Condition *c) {
- int b, v;
- const char *id;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_VIRTUALIZATION);
-
- v = detect_virtualization(&id);
- if (v < 0)
- return v;
-
- /* First, compare with yes/no */
- b = parse_boolean(c->parameter);
-
- if (v > 0 && b > 0)
- return true;
-
- if (v == 0 && b == 0)
- return true;
-
- /* Then, compare categorization */
- if (v == VIRTUALIZATION_VM && streq(c->parameter, "vm"))
- return true;
-
- if (v == VIRTUALIZATION_CONTAINER && streq(c->parameter, "container"))
- return true;
-
- /* Finally compare id */
- return v > 0 && streq(c->parameter, id);
-}
-
-static int condition_test_architecture(Condition *c) {
- int a, b;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_ARCHITECTURE);
-
- a = uname_architecture();
- if (a < 0)
- return a;
-
- if (streq(c->parameter, "native"))
- b = native_architecture();
- else
- b = architecture_from_string(c->parameter);
- if (b < 0)
- return b;
-
- return a == b;
-}
-
-static int condition_test_host(Condition *c) {
- _cleanup_free_ char *h = NULL;
- sd_id128_t x, y;
- int r;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_HOST);
-
- if (sd_id128_from_string(c->parameter, &x) >= 0) {
-
- r = sd_id128_get_machine(&y);
- if (r < 0)
- return r;
-
- return sd_id128_equal(x, y);
- }
-
- h = gethostname_malloc();
- if (!h)
- return -ENOMEM;
-
- return fnmatch(c->parameter, h, FNM_CASEFOLD) == 0;
-}
-
-static int condition_test_ac_power(Condition *c) {
- int r;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_AC_POWER);
-
- r = parse_boolean(c->parameter);
- if (r < 0)
- return r;
-
- return (on_ac_power() != 0) == !!r;
-}
-
-static int condition_test_security(Condition *c) {
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_SECURITY);
-
- if (streq(c->parameter, "selinux"))
- return mac_selinux_use();
- if (streq(c->parameter, "smack"))
- return mac_smack_use();
- if (streq(c->parameter, "apparmor"))
- return mac_apparmor_use();
- if (streq(c->parameter, "audit"))
- return use_audit();
- if (streq(c->parameter, "ima"))
- return use_ima();
-
- return false;
-}
-
-static int condition_test_capability(Condition *c) {
- _cleanup_fclose_ FILE *f = NULL;
- int value;
- char line[LINE_MAX];
- unsigned long long capabilities = -1;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_CAPABILITY);
-
- /* If it's an invalid capability, we don't have it */
- value = capability_from_name(c->parameter);
- if (value < 0)
- return -EINVAL;
-
- /* If it's a valid capability we default to assume
- * that we have it */
-
- f = fopen("/proc/self/status", "re");
- if (!f)
- return -errno;
-
- while (fgets(line, sizeof(line), f)) {
- truncate_nl(line);
-
- if (startswith(line, "CapBnd:")) {
- (void) sscanf(line+7, "%llx", &capabilities);
- break;
- }
- }
-
- return !!(capabilities & (1ULL << value));
-}
-
-static int condition_test_needs_update(Condition *c) {
- const char *p;
- struct stat usr, other;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_NEEDS_UPDATE);
-
- /* If the file system is read-only we shouldn't suggest an update */
- if (path_is_read_only_fs(c->parameter) > 0)
- return false;
-
- /* Any other failure means we should allow the condition to be true,
- * so that we rather invoke too many update tools then too
- * few. */
-
- if (!path_is_absolute(c->parameter))
- return true;
-
- p = strjoina(c->parameter, "/.updated");
- if (lstat(p, &other) < 0)
- return true;
-
- if (lstat("/usr/", &usr) < 0)
- return true;
-
- return usr.st_mtim.tv_sec > other.st_mtim.tv_sec ||
- (usr.st_mtim.tv_sec == other.st_mtim.tv_sec && usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec);
-}
-
-static int condition_test_first_boot(Condition *c) {
- int r;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_FIRST_BOOT);
-
- r = parse_boolean(c->parameter);
- if (r < 0)
- return r;
-
- return (access("/run/systemd/first-boot", F_OK) >= 0) == !!r;
-}
-
-static int condition_test_path_exists(Condition *c) {
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_PATH_EXISTS);
-
- return access(c->parameter, F_OK) >= 0;
-}
-
-static int condition_test_path_exists_glob(Condition *c) {
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_PATH_EXISTS_GLOB);
-
- return glob_exists(c->parameter) > 0;
-}
-
-static int condition_test_path_is_directory(Condition *c) {
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_PATH_IS_DIRECTORY);
-
- return is_dir(c->parameter, true) > 0;
-}
-
-static int condition_test_path_is_symbolic_link(Condition *c) {
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_PATH_IS_SYMBOLIC_LINK);
-
- return is_symlink(c->parameter) > 0;
-}
-
-static int condition_test_path_is_mount_point(Condition *c) {
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_PATH_IS_MOUNT_POINT);
-
- return path_is_mount_point(c->parameter, AT_SYMLINK_FOLLOW) > 0;
-}
-
-static int condition_test_path_is_read_write(Condition *c) {
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_PATH_IS_READ_WRITE);
-
- return path_is_read_only_fs(c->parameter) <= 0;
-}
-
-static int condition_test_directory_not_empty(Condition *c) {
- int r;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_DIRECTORY_NOT_EMPTY);
-
- r = dir_is_empty(c->parameter);
- return r <= 0 && r != -ENOENT;
-}
-
-static int condition_test_file_not_empty(Condition *c) {
- struct stat st;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_FILE_NOT_EMPTY);
-
- return (stat(c->parameter, &st) >= 0 &&
- S_ISREG(st.st_mode) &&
- st.st_size > 0);
-}
-
-static int condition_test_file_is_executable(Condition *c) {
- struct stat st;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_FILE_IS_EXECUTABLE);
-
- return (stat(c->parameter, &st) >= 0 &&
- S_ISREG(st.st_mode) &&
- (st.st_mode & 0111));
-}
-
-static int condition_test_null(Condition *c) {
- assert(c);
- assert(c->type == CONDITION_NULL);
-
- /* Note that during parsing we already evaluate the string and
- * store it in c->negate */
- return true;
-}
-
-int condition_test(Condition *c) {
-
- static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c) = {
- [CONDITION_PATH_EXISTS] = condition_test_path_exists,
- [CONDITION_PATH_EXISTS_GLOB] = condition_test_path_exists_glob,
- [CONDITION_PATH_IS_DIRECTORY] = condition_test_path_is_directory,
- [CONDITION_PATH_IS_SYMBOLIC_LINK] = condition_test_path_is_symbolic_link,
- [CONDITION_PATH_IS_MOUNT_POINT] = condition_test_path_is_mount_point,
- [CONDITION_PATH_IS_READ_WRITE] = condition_test_path_is_read_write,
- [CONDITION_DIRECTORY_NOT_EMPTY] = condition_test_directory_not_empty,
- [CONDITION_FILE_NOT_EMPTY] = condition_test_file_not_empty,
- [CONDITION_FILE_IS_EXECUTABLE] = condition_test_file_is_executable,
- [CONDITION_KERNEL_COMMAND_LINE] = condition_test_kernel_command_line,
- [CONDITION_VIRTUALIZATION] = condition_test_virtualization,
- [CONDITION_SECURITY] = condition_test_security,
- [CONDITION_CAPABILITY] = condition_test_capability,
- [CONDITION_HOST] = condition_test_host,
- [CONDITION_AC_POWER] = condition_test_ac_power,
- [CONDITION_ARCHITECTURE] = condition_test_architecture,
- [CONDITION_NEEDS_UPDATE] = condition_test_needs_update,
- [CONDITION_FIRST_BOOT] = condition_test_first_boot,
- [CONDITION_NULL] = condition_test_null,
- };
-
- int r, b;
-
- assert(c);
- assert(c->type >= 0);
- assert(c->type < _CONDITION_TYPE_MAX);
-
- r = condition_tests[c->type](c);
- if (r < 0) {
- c->result = CONDITION_ERROR;
- return r;
- }
-
- b = (r > 0) == !c->negate;
- c->result = b ? CONDITION_SUCCEEDED : CONDITION_FAILED;
- return b;
-}
-
-void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
- assert(c);
- assert(f);
-
- if (!prefix)
- prefix = "";
-
- fprintf(f,
- "%s\t%s: %s%s%s %s\n",
- prefix,
- to_string(c->type),
- c->trigger ? "|" : "",
- c->negate ? "!" : "",
- c->parameter,
- condition_result_to_string(c->result));
-}
-
-void condition_dump_list(Condition *first, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
- Condition *c;
-
- LIST_FOREACH(conditions, c, first)
- condition_dump(c, f, prefix, to_string);
-}
-
-static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
- [CONDITION_ARCHITECTURE] = "ConditionArchitecture",
- [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
- [CONDITION_HOST] = "ConditionHost",
- [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
- [CONDITION_SECURITY] = "ConditionSecurity",
- [CONDITION_CAPABILITY] = "ConditionCapability",
- [CONDITION_AC_POWER] = "ConditionACPower",
- [CONDITION_NEEDS_UPDATE] = "ConditionNeedsUpdate",
- [CONDITION_FIRST_BOOT] = "ConditionFirstBoot",
- [CONDITION_PATH_EXISTS] = "ConditionPathExists",
- [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
- [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
- [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
- [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
- [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
- [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
- [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
- [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
- [CONDITION_NULL] = "ConditionNull"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
-
-static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
- [CONDITION_ARCHITECTURE] = "AssertArchitecture",
- [CONDITION_VIRTUALIZATION] = "AssertVirtualization",
- [CONDITION_HOST] = "AssertHost",
- [CONDITION_KERNEL_COMMAND_LINE] = "AssertKernelCommandLine",
- [CONDITION_SECURITY] = "AssertSecurity",
- [CONDITION_CAPABILITY] = "AssertCapability",
- [CONDITION_AC_POWER] = "AssertACPower",
- [CONDITION_NEEDS_UPDATE] = "AssertNeedsUpdate",
- [CONDITION_FIRST_BOOT] = "AssertFirstBoot",
- [CONDITION_PATH_EXISTS] = "AssertPathExists",
- [CONDITION_PATH_EXISTS_GLOB] = "AssertPathExistsGlob",
- [CONDITION_PATH_IS_DIRECTORY] = "AssertPathIsDirectory",
- [CONDITION_PATH_IS_SYMBOLIC_LINK] = "AssertPathIsSymbolicLink",
- [CONDITION_PATH_IS_MOUNT_POINT] = "AssertPathIsMountPoint",
- [CONDITION_PATH_IS_READ_WRITE] = "AssertPathIsReadWrite",
- [CONDITION_DIRECTORY_NOT_EMPTY] = "AssertDirectoryNotEmpty",
- [CONDITION_FILE_NOT_EMPTY] = "AssertFileNotEmpty",
- [CONDITION_FILE_IS_EXECUTABLE] = "AssertFileIsExecutable",
- [CONDITION_NULL] = "AssertNull"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(assert_type, ConditionType);
-
-static const char* const condition_result_table[_CONDITION_RESULT_MAX] = {
- [CONDITION_UNTESTED] = "untested",
- [CONDITION_SUCCEEDED] = "succeeded",
- [CONDITION_FAILED] = "failed",
- [CONDITION_ERROR] = "error",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(condition_result, ConditionResult);
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/sendfile.h>
-#include <sys/xattr.h>
-
-#include "util.h"
-#include "btrfs-util.h"
-#include "copy.h"
-
-#define COPY_BUFFER_SIZE (16*1024)
-
-int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
- bool try_sendfile = true;
- int r;
-
- assert(fdf >= 0);
- assert(fdt >= 0);
-
- /* Try btrfs reflinks first. */
- if (try_reflink && max_bytes == (off_t) -1) {
- r = btrfs_reflink(fdf, fdt);
- if (r >= 0)
- return r;
- }
-
- for (;;) {
- size_t m = COPY_BUFFER_SIZE;
- ssize_t n;
-
- if (max_bytes != (off_t) -1) {
-
- if (max_bytes <= 0)
- return -EFBIG;
-
- if ((off_t) m > max_bytes)
- m = (size_t) max_bytes;
- }
-
- /* First try sendfile(), unless we already tried */
- if (try_sendfile) {
-
- n = sendfile(fdt, fdf, NULL, m);
- if (n < 0) {
- if (errno != EINVAL && errno != ENOSYS)
- return -errno;
-
- try_sendfile = false;
- /* use fallback below */
- } else if (n == 0) /* EOF */
- break;
- else if (n > 0)
- /* Succcess! */
- goto next;
- }
-
- /* As a fallback just copy bits by hand */
- {
- char buf[m];
-
- n = read(fdf, buf, m);
- if (n < 0)
- return -errno;
- if (n == 0) /* EOF */
- break;
-
- r = loop_write(fdt, buf, (size_t) n, false);
- if (r < 0)
- return r;
- }
-
- next:
- if (max_bytes != (off_t) -1) {
- assert(max_bytes >= n);
- max_bytes -= n;
- }
- }
-
- return 0;
-}
-
-static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
- _cleanup_free_ char *target = NULL;
- int r;
-
- assert(from);
- assert(st);
- assert(to);
-
- r = readlinkat_malloc(df, from, &target);
- if (r < 0)
- return r;
-
- if (symlinkat(target, dt, to) < 0)
- return -errno;
-
- if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
- return -errno;
-
- return 0;
-}
-
-static int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to) {
- _cleanup_close_ int fdf = -1, fdt = -1;
- struct timespec ts[2];
- int r, q;
-
- assert(from);
- assert(st);
- assert(to);
-
- fdf = openat(df, from, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
- if (fdf < 0)
- return -errno;
-
- fdt = openat(dt, to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, st->st_mode & 07777);
- if (fdt < 0)
- return -errno;
-
- r = copy_bytes(fdf, fdt, (off_t) -1, true);
- if (r < 0) {
- unlinkat(dt, to, 0);
- return r;
- }
-
- if (fchown(fdt, st->st_uid, st->st_gid) < 0)
- r = -errno;
-
- if (fchmod(fdt, st->st_mode & 07777) < 0)
- r = -errno;
-
- ts[0] = st->st_atim;
- ts[1] = st->st_mtim;
- (void) futimens(fdt, ts);
-
- (void) copy_xattr(fdf, fdt);
-
- q = close(fdt);
- fdt = -1;
-
- if (q < 0) {
- r = -errno;
- unlinkat(dt, to, 0);
- }
-
- return r;
-}
-
-static int fd_copy_fifo(int df, const char *from, const struct stat *st, int dt, const char *to) {
- int r;
-
- assert(from);
- assert(st);
- assert(to);
-
- r = mkfifoat(dt, to, st->st_mode & 07777);
- if (r < 0)
- return -errno;
-
- if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
- r = -errno;
-
- if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
- r = -errno;
-
- return r;
-}
-
-static int fd_copy_node(int df, const char *from, const struct stat *st, int dt, const char *to) {
- int r;
-
- assert(from);
- assert(st);
- assert(to);
-
- r = mknodat(dt, to, st->st_mode, st->st_rdev);
- if (r < 0)
- return -errno;
-
- if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
- r = -errno;
-
- if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
- r = -errno;
-
- return r;
-}
-
-static int fd_copy_directory(
- int df,
- const char *from,
- const struct stat *st,
- int dt,
- const char *to,
- dev_t original_device,
- bool merge) {
-
- _cleanup_close_ int fdf = -1, fdt = -1;
- _cleanup_closedir_ DIR *d = NULL;
- struct dirent *de;
- bool created;
- int r;
-
- assert(st);
- assert(to);
-
- if (from)
- fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
- else
- fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
-
- d = fdopendir(fdf);
- if (!d)
- return -errno;
- fdf = -1;
-
- r = mkdirat(dt, to, st->st_mode & 07777);
- if (r >= 0)
- created = true;
- else if (errno == EEXIST && merge)
- created = false;
- else
- return -errno;
-
- fdt = openat(dt, to, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
- if (fdt < 0)
- return -errno;
-
- r = 0;
-
- if (created) {
- struct timespec ut[2] = {
- st->st_atim,
- st->st_mtim
- };
-
- if (fchown(fdt, st->st_uid, st->st_gid) < 0)
- r = -errno;
-
- if (fchmod(fdt, st->st_mode & 07777) < 0)
- r = -errno;
-
- (void) futimens(fdt, ut);
- (void) copy_xattr(dirfd(d), fdt);
- }
-
- FOREACH_DIRENT(de, d, return -errno) {
- struct stat buf;
- int q;
-
- if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
- r = -errno;
- continue;
- }
-
- if (buf.st_dev != original_device)
- continue;
-
- if (S_ISREG(buf.st_mode))
- q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name);
- else if (S_ISDIR(buf.st_mode))
- q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, merge);
- else if (S_ISLNK(buf.st_mode))
- q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
- else if (S_ISFIFO(buf.st_mode))
- q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
- else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
- q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
- else
- q = -EOPNOTSUPP;
-
- if (q == -EEXIST && merge)
- q = 0;
-
- if (q < 0)
- r = q;
- }
-
- return r;
-}
-
-int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) {
- struct stat st;
-
- assert(from);
- assert(to);
-
- if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0)
- return -errno;
-
- if (S_ISREG(st.st_mode))
- return fd_copy_regular(fdf, from, &st, fdt, to);
- else if (S_ISDIR(st.st_mode))
- return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, merge);
- else if (S_ISLNK(st.st_mode))
- return fd_copy_symlink(fdf, from, &st, fdt, to);
- else if (S_ISFIFO(st.st_mode))
- return fd_copy_fifo(fdf, from, &st, fdt, to);
- else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
- return fd_copy_node(fdf, from, &st, fdt, to);
- else
- return -EOPNOTSUPP;
-}
-
-int copy_tree(const char *from, const char *to, bool merge) {
- return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, merge);
-}
-
-int copy_directory_fd(int dirfd, const char *to, bool merge) {
-
- struct stat st;
-
- assert(dirfd >= 0);
- assert(to);
-
- if (fstat(dirfd, &st) < 0)
- return -errno;
-
- if (!S_ISDIR(st.st_mode))
- return -ENOTDIR;
-
- return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
-}
-
-int copy_file_fd(const char *from, int fdt, bool try_reflink) {
- _cleanup_close_ int fdf = -1;
- int r;
-
- assert(from);
- assert(fdt >= 0);
-
- fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fdf < 0)
- return -errno;
-
- r = copy_bytes(fdf, fdt, (off_t) -1, try_reflink);
-
- (void) copy_times(fdf, fdt);
- (void) copy_xattr(fdf, fdt);
-
- return r;
-}
-
-int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) {
- int fdt = -1, r;
-
- assert(from);
- assert(to);
-
- RUN_WITH_UMASK(0000) {
- fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode);
- if (fdt < 0)
- return -errno;
- }
-
- if (chattr_flags != 0)
- (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
-
- r = copy_file_fd(from, fdt, true);
- if (r < 0) {
- close(fdt);
- unlink(to);
- return r;
- }
-
- if (close(fdt) < 0) {
- unlink_noerrno(to);
- return -errno;
- }
-
- return 0;
-}
-
-int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) {
- _cleanup_free_ char *t = NULL;
- int r;
-
- assert(from);
- assert(to);
-
- r = tempfn_random(to, NULL, &t);
- if (r < 0)
- return r;
-
- r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags);
- if (r < 0)
- return r;
-
- if (replace) {
- r = renameat(AT_FDCWD, t, AT_FDCWD, to);
- if (r < 0)
- r = -errno;
- } else
- r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to);
- if (r < 0) {
- (void) unlink_noerrno(t);
- return r;
- }
-
- return 0;
-}
-
-int copy_times(int fdf, int fdt) {
- struct timespec ut[2];
- struct stat st;
- usec_t crtime = 0;
-
- assert(fdf >= 0);
- assert(fdt >= 0);
-
- if (fstat(fdf, &st) < 0)
- return -errno;
-
- ut[0] = st.st_atim;
- ut[1] = st.st_mtim;
-
- if (futimens(fdt, ut) < 0)
- return -errno;
-
- if (fd_getcrtime(fdf, &crtime) >= 0)
- (void) fd_setcrtime(fdt, crtime);
-
- return 0;
-}
-
-int copy_xattr(int fdf, int fdt) {
- _cleanup_free_ char *bufa = NULL, *bufb = NULL;
- size_t sza = 100, szb = 100;
- ssize_t n;
- int ret = 0;
- const char *p;
-
- for (;;) {
- bufa = malloc(sza);
- if (!bufa)
- return -ENOMEM;
-
- n = flistxattr(fdf, bufa, sza);
- if (n == 0)
- return 0;
- if (n > 0)
- break;
- if (errno != ERANGE)
- return -errno;
-
- sza *= 2;
-
- free(bufa);
- bufa = NULL;
- }
-
- p = bufa;
- while (n > 0) {
- size_t l;
-
- l = strlen(p);
- assert(l < (size_t) n);
-
- if (startswith(p, "user.")) {
- ssize_t m;
-
- if (!bufb) {
- bufb = malloc(szb);
- if (!bufb)
- return -ENOMEM;
- }
-
- m = fgetxattr(fdf, p, bufb, szb);
- if (m < 0) {
- if (errno == ERANGE) {
- szb *= 2;
- free(bufb);
- bufb = NULL;
- continue;
- }
-
- return -errno;
- }
-
- if (fsetxattr(fdt, p, bufb, m, 0) < 0)
- ret = -errno;
- }
-
- p += l + 1;
- n -= l + 1;
- }
-
- return ret;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
- ***/
-
-#ifdef HAVE_LIBIDN
-#include <idna.h>
-#include <stringprep.h>
-#endif
-
-#include "dns-domain.h"
-
-int dns_label_unescape(const char **name, char *dest, size_t sz) {
- const char *n;
- char *d;
- int r = 0;
-
- assert(name);
- assert(*name);
- assert(dest);
-
- n = *name;
- d = dest;
-
- for (;;) {
- if (*n == '.') {
- n++;
- break;
- }
-
- if (*n == 0)
- break;
-
- if (sz <= 0)
- return -ENOSPC;
-
- if (r >= DNS_LABEL_MAX)
- return -EINVAL;
-
- if (*n == '\\') {
- /* Escaped character */
-
- n++;
-
- if (*n == 0)
- /* Ending NUL */
- return -EINVAL;
-
- else if (*n == '\\' || *n == '.') {
- /* Escaped backslash or dot */
- *(d++) = *(n++);
- sz--;
- r++;
-
- } else if (n[0] >= '0' && n[0] <= '9') {
- unsigned k;
-
- /* Escaped literal ASCII character */
-
- if (!(n[1] >= '0' && n[1] <= '9') ||
- !(n[2] >= '0' && n[2] <= '9'))
- return -EINVAL;
-
- k = ((unsigned) (n[0] - '0') * 100) +
- ((unsigned) (n[1] - '0') * 10) +
- ((unsigned) (n[2] - '0'));
-
- /* Don't allow CC characters or anything that doesn't fit in 8bit */
- if (k < ' ' || k > 255 || k == 127)
- return -EINVAL;
-
- *(d++) = (char) k;
- sz--;
- r++;
-
- n += 3;
- } else
- return -EINVAL;
-
- } else if ((uint8_t) *n >= (uint8_t) ' ' && *n != 127) {
-
- /* Normal character */
- *(d++) = *(n++);
- sz--;
- r++;
- } else
- return -EINVAL;
- }
-
- /* Empty label that is not at the end? */
- if (r == 0 && *n)
- return -EINVAL;
-
- if (sz >= 1)
- *d = 0;
-
- *name = n;
- return r;
-}
-
-/* @label_terminal: terminal character of a label, updated to point to the terminal character of
- * the previous label (always skipping one dot) or to NULL if there are no more
- * labels. */
-int dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) {
- const char *terminal;
- int r;
-
- assert(name);
- assert(label_terminal);
- assert(dest);
-
- /* no more labels */
- if (!*label_terminal) {
- if (sz >= 1)
- *dest = 0;
-
- return 0;
- }
-
- assert(**label_terminal == '.' || **label_terminal == 0);
-
- /* skip current terminal character */
- terminal = *label_terminal - 1;
-
- /* point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
- for (;;) {
- if (terminal < name) {
- /* reached the first label, so indicate that there are no more */
- terminal = NULL;
- break;
- }
-
- /* find the start of the last label */
- if (*terminal == '.') {
- const char *y;
- unsigned slashes = 0;
-
- for (y = terminal - 1; y >= name && *y == '\\'; y--)
- slashes ++;
-
- if (slashes % 2 == 0) {
- /* the '.' was not escaped */
- name = terminal + 1;
- break;
- } else {
- terminal = y;
- continue;
- }
- }
-
- terminal --;
- }
-
- r = dns_label_unescape(&name, dest, sz);
- if (r < 0)
- return r;
-
- *label_terminal = terminal;
-
- return r;
-}
-
-int dns_label_escape(const char *p, size_t l, char **ret) {
- _cleanup_free_ char *s = NULL;
- char *q;
- int r;
-
- assert(p);
- assert(ret);
-
- if (l > DNS_LABEL_MAX)
- return -EINVAL;
-
- s = malloc(l * 4 + 1);
- if (!s)
- return -ENOMEM;
-
- q = s;
- while (l > 0) {
-
- if (*p == '.' || *p == '\\') {
-
- /* Dot or backslash */
- *(q++) = '\\';
- *(q++) = *p;
-
- } else if (*p == '_' ||
- *p == '-' ||
- (*p >= '0' && *p <= '9') ||
- (*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z')) {
-
- /* Proper character */
- *(q++) = *p;
- } else if ((uint8_t) *p >= (uint8_t) ' ' && *p != 127) {
-
- /* Everything else */
- *(q++) = '\\';
- *(q++) = '0' + (char) ((uint8_t) *p / 100);
- *(q++) = '0' + (char) (((uint8_t) *p / 10) % 10);
- *(q++) = '0' + (char) ((uint8_t) *p % 10);
-
- } else
- return -EINVAL;
-
- p++;
- l--;
- }
-
- *q = 0;
- *ret = s;
- r = q - s;
- s = NULL;
-
- return r;
-}
-
-int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
-#ifdef HAVE_LIBIDN
- _cleanup_free_ uint32_t *input = NULL;
- size_t input_size;
- const char *p;
- bool contains_8bit = false;
-
- assert(encoded);
- assert(decoded);
- assert(decoded_max >= DNS_LABEL_MAX);
-
- if (encoded_size <= 0)
- return 0;
-
- for (p = encoded; p < encoded + encoded_size; p++)
- if ((uint8_t) *p > 127)
- contains_8bit = true;
-
- if (!contains_8bit)
- return 0;
-
- input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
- if (!input)
- return -ENOMEM;
-
- if (idna_to_ascii_4i(input, input_size, decoded, 0) != 0)
- return -EINVAL;
-
- return strlen(decoded);
-#else
- return 0;
-#endif
-}
-
-int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
-#ifdef HAVE_LIBIDN
- size_t input_size, output_size;
- _cleanup_free_ uint32_t *input = NULL;
- _cleanup_free_ char *result = NULL;
- uint32_t *output = NULL;
- size_t w;
-
- /* To be invoked after unescaping */
-
- assert(encoded);
- assert(decoded);
-
- if (encoded_size < sizeof(IDNA_ACE_PREFIX)-1)
- return 0;
-
- if (memcmp(encoded, IDNA_ACE_PREFIX, sizeof(IDNA_ACE_PREFIX) -1) != 0)
- return 0;
-
- input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
- if (!input)
- return -ENOMEM;
-
- output_size = input_size;
- output = newa(uint32_t, output_size);
-
- idna_to_unicode_44i(input, input_size, output, &output_size, 0);
-
- result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
- if (!result)
- return -ENOMEM;
- if (w <= 0)
- return 0;
- if (w+1 > decoded_max)
- return -EINVAL;
-
- memcpy(decoded, result, w+1);
- return w;
-#else
- return 0;
-#endif
-}
-
-int dns_name_normalize(const char *s, char **_ret) {
- _cleanup_free_ char *ret = NULL;
- size_t n = 0, allocated = 0;
- const char *p = s;
- bool first = true;
- int r;
-
- assert(s);
-
- for (;;) {
- _cleanup_free_ char *t = NULL;
- char label[DNS_LABEL_MAX];
- int k;
-
- r = dns_label_unescape(&p, label, sizeof(label));
- if (r < 0)
- return r;
- if (r == 0) {
- if (*p != 0)
- return -EINVAL;
- break;
- }
-
- k = dns_label_undo_idna(label, r, label, sizeof(label));
- if (k < 0)
- return k;
- if (k > 0)
- r = k;
-
- r = dns_label_escape(label, r, &t);
- if (r < 0)
- return r;
-
- if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1))
- return -ENOMEM;
-
- if (!first)
- ret[n++] = '.';
- else
- first = false;
-
- memcpy(ret + n, t, r);
- n += r;
- }
-
- if (n > DNS_NAME_MAX)
- return -EINVAL;
-
- if (!GREEDY_REALLOC(ret, allocated, n + 1))
- return -ENOMEM;
-
- ret[n] = 0;
-
- if (_ret) {
- *_ret = ret;
- ret = NULL;
- }
-
- return 0;
-}
-
-unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]) {
- const char *p = s;
- unsigned long ul = hash_key[0];
- int r;
-
- assert(p);
-
- while (*p) {
- char label[DNS_LABEL_MAX+1];
- int k;
-
- r = dns_label_unescape(&p, label, sizeof(label));
- if (r < 0)
- break;
-
- k = dns_label_undo_idna(label, r, label, sizeof(label));
- if (k < 0)
- break;
- if (k > 0)
- r = k;
-
- label[r] = 0;
- ascii_strlower(label);
-
- ul = ul * hash_key[1] + ul + string_hash_func(label, hash_key);
- }
-
- return ul;
-}
-
-int dns_name_compare_func(const void *a, const void *b) {
- const char *x, *y;
- int r, q, k, w;
-
- assert(a);
- assert(b);
-
- x = (const char *) a + strlen(a);
- y = (const char *) b + strlen(b);
-
- for (;;) {
- char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
-
- if (x == NULL && y == NULL)
- return 0;
-
- r = dns_label_unescape_suffix(a, &x, la, sizeof(la));
- q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb));
- if (r < 0 || q < 0)
- return r - q;
-
- k = dns_label_undo_idna(la, r, la, sizeof(la));
- w = dns_label_undo_idna(lb, q, lb, sizeof(lb));
- if (k < 0 || w < 0)
- return k - w;
- if (k > 0)
- r = k;
- if (w > 0)
- r = w;
-
- la[r] = lb[q] = 0;
- r = strcasecmp(la, lb);
- if (r != 0)
- return r;
- }
-}
-
-const struct hash_ops dns_name_hash_ops = {
- .hash = dns_name_hash_func,
- .compare = dns_name_compare_func
-};
-
-int dns_name_equal(const char *x, const char *y) {
- int r, q, k, w;
-
- assert(x);
- assert(y);
-
- for (;;) {
- char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
-
- if (*x == 0 && *y == 0)
- return true;
-
- r = dns_label_unescape(&x, la, sizeof(la));
- if (r < 0)
- return r;
-
- k = dns_label_undo_idna(la, r, la, sizeof(la));
- if (k < 0)
- return k;
- if (k > 0)
- r = k;
-
- q = dns_label_unescape(&y, lb, sizeof(lb));
- if (q < 0)
- return q;
- w = dns_label_undo_idna(lb, q, lb, sizeof(lb));
- if (w < 0)
- return w;
- if (w > 0)
- q = w;
-
- la[r] = lb[q] = 0;
- if (strcasecmp(la, lb))
- return false;
- }
-}
-
-int dns_name_endswith(const char *name, const char *suffix) {
- const char *n, *s, *saved_n = NULL;
- int r, q, k, w;
-
- assert(name);
- assert(suffix);
-
- n = name;
- s = suffix;
-
- for (;;) {
- char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1];
-
- r = dns_label_unescape(&n, ln, sizeof(ln));
- if (r < 0)
- return r;
- k = dns_label_undo_idna(ln, r, ln, sizeof(ln));
- if (k < 0)
- return k;
- if (k > 0)
- r = k;
-
- if (!saved_n)
- saved_n = n;
-
- q = dns_label_unescape(&s, ls, sizeof(ls));
- if (q < 0)
- return q;
- w = dns_label_undo_idna(ls, q, ls, sizeof(ls));
- if (w < 0)
- return w;
- if (w > 0)
- q = w;
-
- if (r == 0 && q == 0)
- return true;
- if (r == 0 && saved_n == n)
- return false;
-
- ln[r] = ls[q] = 0;
-
- if (r != q || strcasecmp(ln, ls)) {
-
- /* Not the same, let's jump back, and try with the next label again */
- s = suffix;
- n = saved_n;
- saved_n = NULL;
- }
- }
-}
-
-int dns_name_between(const char *a, const char *b, const char *c) {
- int n;
-
- /* Determine if b is strictly greater than a and strictly smaller than c.
- We consider the order of names to be circular, so that if a is
- strictly greater than c, we consider b to be between them if it is
- either greater than a or smaller than c. This is how the canonical
- DNS name order used in NSEC records work. */
-
- n = dns_name_compare_func(a, c);
- if (n == 0)
- return -EINVAL;
- else if (n < 0)
- /* a<---b--->c */
- return dns_name_compare_func(a, b) < 0 &&
- dns_name_compare_func(b, c) < 0;
- else
- /* <--b--c a--b--> */
- return dns_name_compare_func(b, c) < 0 ||
- dns_name_compare_func(a, b) < 0;
-}
-
-int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
- const uint8_t *p;
- int r;
-
- assert(a);
- assert(ret);
-
- p = (const uint8_t*) a;
-
- if (family == AF_INET)
- r = asprintf(ret, "%u.%u.%u.%u.in-addr.arpa", p[3], p[2], p[1], p[0]);
- else if (family == AF_INET6)
- r = asprintf(ret, "%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.ip6.arpa",
- hexchar(p[15] & 0xF), hexchar(p[15] >> 4), hexchar(p[14] & 0xF), hexchar(p[14] >> 4),
- hexchar(p[13] & 0xF), hexchar(p[13] >> 4), hexchar(p[12] & 0xF), hexchar(p[12] >> 4),
- hexchar(p[11] & 0xF), hexchar(p[11] >> 4), hexchar(p[10] & 0xF), hexchar(p[10] >> 4),
- hexchar(p[ 9] & 0xF), hexchar(p[ 9] >> 4), hexchar(p[ 8] & 0xF), hexchar(p[ 8] >> 4),
- hexchar(p[ 7] & 0xF), hexchar(p[ 7] >> 4), hexchar(p[ 6] & 0xF), hexchar(p[ 6] >> 4),
- hexchar(p[ 5] & 0xF), hexchar(p[ 5] >> 4), hexchar(p[ 4] & 0xF), hexchar(p[ 4] >> 4),
- hexchar(p[ 3] & 0xF), hexchar(p[ 3] >> 4), hexchar(p[ 2] & 0xF), hexchar(p[ 2] >> 4),
- hexchar(p[ 1] & 0xF), hexchar(p[ 1] >> 4), hexchar(p[ 0] & 0xF), hexchar(p[ 0] >> 4));
- else
- return -EAFNOSUPPORT;
- if (r < 0)
- return -ENOMEM;
-
- return 0;
-}
-
-int dns_name_address(const char *p, int *family, union in_addr_union *address) {
- int r;
-
- assert(p);
- assert(family);
- assert(address);
-
- r = dns_name_endswith(p, "in-addr.arpa");
- if (r < 0)
- return r;
- if (r > 0) {
- uint8_t a[4];
- unsigned i;
-
- for (i = 0; i < ELEMENTSOF(a); i++) {
- char label[DNS_LABEL_MAX+1];
-
- r = dns_label_unescape(&p, label, sizeof(label));
- if (r < 0)
- return r;
- if (r == 0)
- return -EINVAL;
- if (r > 3)
- return -EINVAL;
-
- r = safe_atou8(label, &a[i]);
- if (r < 0)
- return r;
- }
-
- r = dns_name_equal(p, "in-addr.arpa");
- if (r <= 0)
- return r;
-
- *family = AF_INET;
- address->in.s_addr = htobe32(((uint32_t) a[3] << 24) |
- ((uint32_t) a[2] << 16) |
- ((uint32_t) a[1] << 8) |
- (uint32_t) a[0]);
-
- return 1;
- }
-
- r = dns_name_endswith(p, "ip6.arpa");
- if (r < 0)
- return r;
- if (r > 0) {
- struct in6_addr a;
- unsigned i;
-
- for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
- char label[DNS_LABEL_MAX+1];
- int x, y;
-
- r = dns_label_unescape(&p, label, sizeof(label));
- if (r <= 0)
- return r;
- if (r != 1)
- return -EINVAL;
- x = unhexchar(label[0]);
- if (x < 0)
- return -EINVAL;
-
- r = dns_label_unescape(&p, label, sizeof(label));
- if (r <= 0)
- return r;
- if (r != 1)
- return -EINVAL;
- y = unhexchar(label[0]);
- if (y < 0)
- return -EINVAL;
-
- a.s6_addr[ELEMENTSOF(a.s6_addr) - i - 1] = (uint8_t) y << 4 | (uint8_t) x;
- }
-
- r = dns_name_equal(p, "ip6.arpa");
- if (r <= 0)
- return r;
-
- *family = AF_INET6;
- address->in6 = a;
- return 1;
- }
-
- return 0;
-}
-
-int dns_name_root(const char *name) {
- char label[DNS_LABEL_MAX+1];
- int r;
-
- assert(name);
-
- r = dns_label_unescape(&name, label, sizeof(label));
- if (r < 0)
- return r;
-
- return r == 0 && *name == 0;
-}
-
-int dns_name_single_label(const char *name) {
- char label[DNS_LABEL_MAX+1];
- int r;
-
- assert(name);
-
- r = dns_label_unescape(&name, label, sizeof(label));
- if (r < 0)
- return r;
- if (r == 0)
- return 0;
-
- r = dns_label_unescape(&name, label, sizeof(label));
- if (r < 0)
- return r;
-
- return r == 0 && *name == 0;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
- ***/
-
-#pragma once
-
-
-#include "hashmap.h"
-#include "in-addr-util.h"
-
-#define DNS_LABEL_MAX 63
-#define DNS_NAME_MAX 255
-
-int dns_label_unescape(const char **name, char *dest, size_t sz);
-int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz);
-int dns_label_escape(const char *p, size_t l, char **ret);
-
-int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
-int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
-
-int dns_name_normalize(const char *s, char **_ret);
-
-unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]);
-int dns_name_compare_func(const void *a, const void *b);
-extern const struct hash_ops dns_name_hash_ops;
-
-int dns_name_between(const char *a, const char *b, const char *c);
-int dns_name_equal(const char *x, const char *y);
-int dns_name_endswith(const char *name, const char *suffix);
-
-int dns_name_reverse(int family, const union in_addr_union *a, char **ret);
-int dns_name_address(const char *p, int *family, union in_addr_union *a);
-
-int dns_name_root(const char *name);
-int dns_name_single_label(const char *name);
--- /dev/null
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+#include "sd-id128.h"
+#include "time-util.h"
+
+#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
+#define EFI_VENDOR_GLOBAL SD_ID128_MAKE(8b,e4,df,61,93,ca,11,d2,aa,0d,00,e0,98,03,2b,8c)
+#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004
+
+#ifdef ENABLE_EFI
+
+bool is_efi_boot(void);
+bool is_efi_secure_boot(void);
+bool is_efi_secure_boot_setup_mode(void);
+int efi_reboot_to_firmware_supported(void);
+int efi_get_reboot_to_firmware(void);
+int efi_set_reboot_to_firmware(bool value);
+
+int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size);
+int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size);
+int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p);
+
+int efi_get_boot_option(uint16_t nr, char **title, sd_id128_t *part_uuid, char **path, bool *active);
+int efi_add_boot_option(uint16_t id, const char *title, uint32_t part, uint64_t pstart, uint64_t psize, sd_id128_t part_uuid, const char *path);
+int efi_remove_boot_option(uint16_t id);
+int efi_get_boot_order(uint16_t **order);
+int efi_set_boot_order(uint16_t *order, size_t n);
+int efi_get_boot_options(uint16_t **options);
+
+int efi_loader_get_device_part_uuid(sd_id128_t *u);
+int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader);
+
+#else
+
+static inline bool is_efi_boot(void) {
+ return false;
+}
+
+static inline bool is_efi_secure_boot(void) {
+ return false;
+}
+
+static inline bool is_efi_secure_boot_setup_mode(void) {
+ return false;
+}
+
+static inline int efi_reboot_to_firmware_supported(void) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_reboot_to_firmware(void) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_set_reboot_to_firmware(bool value) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_boot_option(uint16_t nr, char **title, sd_id128_t *part_uuid, char **path, bool *active) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_add_boot_option(uint16_t id, const char *title, uint32_t part, uint64_t pstart, uint64_t psize, sd_id128_t part_uuid, const char *path) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_remove_boot_option(uint16_t id) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_boot_order(uint16_t **order) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_set_boot_order(uint16_t *order, size_t n) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_boot_options(uint16_t **options) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_loader_get_device_part_uuid(sd_id128_t *u) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
+ return -EOPNOTSUPP;
+}
+
+#endif
+
+char *efi_tilt_backslashes(char *s);
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <unistd.h>
-
-#include "util.h"
-#include "special.h"
-#include "mkdir.h"
-#include "unit-name.h"
-#include "generator.h"
-#include "path-util.h"
-#include "fstab-util.h"
-#include "fileio.h"
-#include "dropin.h"
-
-static int write_fsck_sysroot_service(const char *dir, const char *what) {
- const char *unit;
- _cleanup_free_ char *device = NULL;
- _cleanup_free_ char *escaped;
- _cleanup_fclose_ FILE *f = NULL;
- int r;
-
- escaped = cescape(what);
- if (!escaped)
- return log_oom();
-
- unit = strjoina(dir, "/systemd-fsck-root.service");
- log_debug("Creating %s", unit);
-
- r = unit_name_from_path(what, ".device", &device);
- if (r < 0)
- return log_error_errno(r, "Failed to convert device \"%s\" to unit name: %m", what);
-
- f = fopen(unit, "wxe");
- if (!f)
- return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
-
- fprintf(f,
- "# Automatically generated by %1$s\n\n"
- "[Unit]\n"
- "Documentation=man:systemd-fsck-root.service(8)\n"
- "Description=File System Check on %2$s\n"
- "DefaultDependencies=no\n"
- "BindsTo=%3$s\n"
- "After=%3$s\n"
- "Before=shutdown.target\n"
- "\n"
- "[Service]\n"
- "Type=oneshot\n"
- "RemainAfterExit=yes\n"
- "ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n"
- "TimeoutSec=0\n",
- program_invocation_short_name,
- what,
- device,
- escaped);
-
- r = fflush_and_check(f);
- if (r < 0)
- return log_error_errno(r, "Failed to write unit file %s: %m", unit);
-
- return 0;
-}
-
-int generator_write_fsck_deps(
- FILE *f,
- const char *dir,
- const char *what,
- const char *where,
- const char *fstype) {
-
- int r;
-
- assert(f);
- assert(dir);
- assert(what);
- assert(where);
-
- if (!is_device_path(what)) {
- log_warning("Checking was requested for \"%s\", but it is not a device.", what);
- return 0;
- }
-
- if (!isempty(fstype) && !streq(fstype, "auto")) {
- r = fsck_exists(fstype);
- if (r == -ENOENT) {
- /* treat missing check as essentially OK */
- log_debug_errno(r, "Checking was requested for %s, but fsck.%s does not exist: %m", what, fstype);
- return 0;
- } else if (r < 0)
- return log_warning_errno(r, "Checking was requested for %s, but fsck.%s cannot be used: %m", what, fstype);
- }
-
- if (path_equal(where, "/")) {
- char *lnk;
-
- lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
-
- mkdir_parents(lnk, 0755);
- if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
-
- } else {
- _cleanup_free_ char *_fsck = NULL;
- const char *fsck;
-
- if (in_initrd() && path_equal(where, "/sysroot")) {
- r = write_fsck_sysroot_service(dir, what);
- if (r < 0)
- return r;
-
- fsck = "systemd-fsck-root.service";
- } else {
- r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck);
- if (r < 0)
- return log_error_errno(r, "Failed to create fsck service name: %m");
-
- fsck = _fsck;
- }
-
- fprintf(f,
- "RequiresOverridable=%1$s\n"
- "After=%1$s\n",
- fsck);
- }
-
- return 0;
-}
-
-int generator_write_timeouts(
- const char *dir,
- const char *what,
- const char *where,
- const char *opts,
- char **filtered) {
-
- /* Allow configuration how long we wait for a device that
- * backs a mount point to show up. This is useful to support
- * endless device timeouts for devices that show up only after
- * user input, like crypto devices. */
-
- _cleanup_free_ char *node = NULL, *unit = NULL, *timeout = NULL;
- usec_t u;
- int r;
-
- r = fstab_filter_options(opts, "comment=systemd.device-timeout\0" "x-systemd.device-timeout\0",
- NULL, &timeout, filtered);
- if (r <= 0)
- return r;
-
- r = parse_sec(timeout, &u);
- if (r < 0) {
- log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
- return 0;
- }
-
- node = fstab_node_to_udev_node(what);
- if (!node)
- return log_oom();
-
- r = unit_name_from_path(node, ".device", &unit);
- if (r < 0)
- return log_error_errno(r, "Failed to make unit name from path: %m");
-
- return write_drop_in_format(dir, unit, 50, "device-timeout",
- "# Automatically generated by %s\n\n"
- "[Unit]\nJobTimeoutSec=" USEC_FMT,
- program_invocation_short_name,
- u / USEC_PER_SEC);
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2011 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty <of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <fnmatch.h>
-
-#include "util.h"
-#include "mkdir.h"
-#include "hashmap.h"
-#include "set.h"
-#include "path-util.h"
-#include "path-lookup.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "install.h"
-#include "conf-parser.h"
-#include "conf-files.h"
-#include "install-printf.h"
-#include "special.h"
-
-typedef struct {
- OrderedHashmap *will_install;
- OrderedHashmap *have_installed;
-} InstallContext;
-
-static int in_search_path(const char *path, char **search) {
- _cleanup_free_ char *parent = NULL;
- int r;
-
- assert(path);
-
- r = path_get_parent(path, &parent);
- if (r < 0)
- return r;
-
- return strv_contains(search, parent);
-}
-
-static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
- char *p = NULL;
- int r;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(ret);
-
- switch (scope) {
-
- case UNIT_FILE_SYSTEM:
-
- if (runtime)
- p = path_join(root_dir, "/run/systemd/system", NULL);
- else
- p = path_join(root_dir, SYSTEM_CONFIG_UNIT_PATH, NULL);
- break;
-
- case UNIT_FILE_GLOBAL:
-
- if (root_dir)
- return -EINVAL;
-
- if (runtime)
- p = strdup("/run/systemd/user");
- else
- p = strdup(USER_CONFIG_UNIT_PATH);
- break;
-
- case UNIT_FILE_USER:
-
- if (root_dir)
- return -EINVAL;
-
- if (runtime)
- r = user_runtime_dir(&p);
- else
- r = user_config_home(&p);
-
- if (r <= 0)
- return r < 0 ? r : -ENOENT;
-
- break;
-
- default:
- assert_not_reached("Bad scope");
- }
-
- if (!p)
- return -ENOMEM;
-
- *ret = p;
- return 0;
-}
-
-static int mark_symlink_for_removal(
- Set **remove_symlinks_to,
- const char *p) {
-
- char *n;
- int r;
-
- assert(p);
-
- r = set_ensure_allocated(remove_symlinks_to, &string_hash_ops);
- if (r < 0)
- return r;
-
- n = strdup(p);
- if (!n)
- return -ENOMEM;
-
- path_kill_slashes(n);
-
- r = set_consume(*remove_symlinks_to, n);
- if (r < 0)
- return r == -EEXIST ? 0 : r;
-
- return 0;
-}
-
-static int remove_marked_symlinks_fd(
- Set *remove_symlinks_to,
- int fd,
- const char *path,
- const char *config_path,
- bool *deleted,
- UnitFileChange **changes,
- unsigned *n_changes,
- char** instance_whitelist) {
-
- _cleanup_closedir_ DIR *d = NULL;
- int r = 0;
-
- assert(remove_symlinks_to);
- assert(fd >= 0);
- assert(path);
- assert(config_path);
- assert(deleted);
-
- d = fdopendir(fd);
- if (!d) {
- safe_close(fd);
- return -errno;
- }
-
- rewinddir(d);
-
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0) {
- r = -errno;
- break;
- }
-
- if (!de)
- break;
-
- if (hidden_file(de->d_name))
- continue;
-
- dirent_ensure_type(d, de);
-
- if (de->d_type == DT_DIR) {
- int nfd, q;
- _cleanup_free_ char *p = NULL;
-
- nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
- if (nfd < 0) {
- if (errno == ENOENT)
- continue;
-
- if (r == 0)
- r = -errno;
- continue;
- }
-
- p = path_make_absolute(de->d_name, path);
- if (!p) {
- safe_close(nfd);
- return -ENOMEM;
- }
-
- /* This will close nfd, regardless whether it succeeds or not */
- q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, instance_whitelist);
- if (q < 0 && r == 0)
- r = q;
-
- } else if (de->d_type == DT_LNK) {
- _cleanup_free_ char *p = NULL, *dest = NULL;
- int q;
- bool found;
-
- if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
- continue;
-
- if (unit_name_is_valid(de->d_name, UNIT_NAME_INSTANCE) &&
- instance_whitelist &&
- !strv_contains(instance_whitelist, de->d_name)) {
-
- _cleanup_free_ char *w = NULL;
-
- /* OK, the file is not listed directly
- * in the whitelist, so let's check if
- * the template of it might be
- * listed. */
-
- r = unit_name_template(de->d_name, &w);
- if (r < 0)
- return r;
-
- if (!strv_contains(instance_whitelist, w))
- continue;
- }
-
- p = path_make_absolute(de->d_name, path);
- if (!p)
- return -ENOMEM;
-
- q = readlink_and_canonicalize(p, &dest);
- if (q < 0) {
- if (q == -ENOENT)
- continue;
-
- if (r == 0)
- r = q;
- continue;
- }
-
- found =
- set_get(remove_symlinks_to, dest) ||
- set_get(remove_symlinks_to, basename(dest));
-
- if (!found)
- continue;
-
- if (unlink(p) < 0 && errno != ENOENT) {
- if (r == 0)
- r = -errno;
- continue;
- }
-
- path_kill_slashes(p);
- rmdir_parents(p, config_path);
- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
-
- if (!set_get(remove_symlinks_to, p)) {
-
- q = mark_symlink_for_removal(&remove_symlinks_to, p);
- if (q < 0) {
- if (r == 0)
- r = q;
- } else
- *deleted = true;
- }
- }
- }
-
- return r;
-}
-
-static int remove_marked_symlinks(
- Set *remove_symlinks_to,
- const char *config_path,
- UnitFileChange **changes,
- unsigned *n_changes,
- char** instance_whitelist) {
-
- _cleanup_close_ int fd = -1;
- int r = 0;
- bool deleted;
-
- assert(config_path);
-
- if (set_size(remove_symlinks_to) <= 0)
- return 0;
-
- fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
- if (fd < 0)
- return -errno;
-
- do {
- int q, cfd;
- deleted = false;
-
- cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
- if (cfd < 0) {
- r = -errno;
- break;
- }
-
- /* This takes possession of cfd and closes it */
- q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, instance_whitelist);
- if (r == 0)
- r = q;
- } while (deleted);
-
- return r;
-}
-
-static int find_symlinks_fd(
- const char *name,
- int fd,
- const char *path,
- const char *config_path,
- bool *same_name_link) {
-
- int r = 0;
- _cleanup_closedir_ DIR *d = NULL;
-
- assert(name);
- assert(fd >= 0);
- assert(path);
- assert(config_path);
- assert(same_name_link);
-
- d = fdopendir(fd);
- if (!d) {
- safe_close(fd);
- return -errno;
- }
-
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0)
- return -errno;
-
- if (!de)
- return r;
-
- if (hidden_file(de->d_name))
- continue;
-
- dirent_ensure_type(d, de);
-
- if (de->d_type == DT_DIR) {
- int nfd, q;
- _cleanup_free_ char *p = NULL;
-
- nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
- if (nfd < 0) {
- if (errno == ENOENT)
- continue;
-
- if (r == 0)
- r = -errno;
- continue;
- }
-
- p = path_make_absolute(de->d_name, path);
- if (!p) {
- safe_close(nfd);
- return -ENOMEM;
- }
-
- /* This will close nfd, regardless whether it succeeds or not */
- q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
- if (q > 0)
- return 1;
- if (r == 0)
- r = q;
-
- } else if (de->d_type == DT_LNK) {
- _cleanup_free_ char *p = NULL, *dest = NULL;
- bool found_path, found_dest, b = false;
- int q;
-
- /* Acquire symlink name */
- p = path_make_absolute(de->d_name, path);
- if (!p)
- return -ENOMEM;
-
- /* Acquire symlink destination */
- q = readlink_and_canonicalize(p, &dest);
- if (q < 0) {
- if (q == -ENOENT)
- continue;
-
- if (r == 0)
- r = q;
- continue;
- }
-
- /* Check if the symlink itself matches what we
- * are looking for */
- if (path_is_absolute(name))
- found_path = path_equal(p, name);
- else
- found_path = streq(de->d_name, name);
-
- /* Check if what the symlink points to
- * matches what we are looking for */
- if (path_is_absolute(name))
- found_dest = path_equal(dest, name);
- else
- found_dest = streq(basename(dest), name);
-
- if (found_path && found_dest) {
- _cleanup_free_ char *t = NULL;
-
- /* Filter out same name links in the main
- * config path */
- t = path_make_absolute(name, config_path);
- if (!t)
- return -ENOMEM;
-
- b = path_equal(t, p);
- }
-
- if (b)
- *same_name_link = true;
- else if (found_path || found_dest)
- return 1;
- }
- }
-}
-
-static int find_symlinks(
- const char *name,
- const char *config_path,
- bool *same_name_link) {
-
- int fd;
-
- assert(name);
- assert(config_path);
- assert(same_name_link);
-
- fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
- if (fd < 0) {
- if (errno == ENOENT)
- return 0;
- return -errno;
- }
-
- /* This takes possession of fd and closes it */
- return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
-}
-
-static int find_symlinks_in_scope(
- UnitFileScope scope,
- const char *root_dir,
- const char *name,
- UnitFileState *state) {
-
- int r;
- _cleanup_free_ char *normal_path = NULL, *runtime_path = NULL;
- bool same_name_link_runtime = false, same_name_link = false;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(name);
-
- /* First look in runtime config path */
- r = get_config_path(scope, true, root_dir, &normal_path);
- if (r < 0)
- return r;
-
- r = find_symlinks(name, normal_path, &same_name_link_runtime);
- if (r < 0)
- return r;
- else if (r > 0) {
- *state = UNIT_FILE_ENABLED_RUNTIME;
- return r;
- }
-
- /* Then look in the normal config path */
- r = get_config_path(scope, false, root_dir, &runtime_path);
- if (r < 0)
- return r;
-
- r = find_symlinks(name, runtime_path, &same_name_link);
- if (r < 0)
- return r;
- else if (r > 0) {
- *state = UNIT_FILE_ENABLED;
- return r;
- }
-
- /* Hmm, we didn't find it, but maybe we found the same name
- * link? */
- if (same_name_link_runtime) {
- *state = UNIT_FILE_LINKED_RUNTIME;
- return 1;
- } else if (same_name_link) {
- *state = UNIT_FILE_LINKED;
- return 1;
- }
-
- return 0;
-}
-
-int unit_file_mask(
- UnitFileScope scope,
- bool runtime,
- const char *root_dir,
- char **files,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- char **i;
- _cleanup_free_ char *prefix = NULL;
- int r;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
-
- r = get_config_path(scope, runtime, root_dir, &prefix);
- if (r < 0)
- return r;
-
- STRV_FOREACH(i, files) {
- _cleanup_free_ char *path = NULL;
-
- if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
- if (r == 0)
- r = -EINVAL;
- continue;
- }
-
- path = path_make_absolute(*i, prefix);
- if (!path) {
- r = -ENOMEM;
- break;
- }
-
- if (symlink("/dev/null", path) >= 0) {
- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
- continue;
- }
-
- if (errno == EEXIST) {
-
- if (null_or_empty_path(path) > 0)
- continue;
-
- if (force) {
- if (symlink_atomic("/dev/null", path) >= 0) {
- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
- continue;
- }
- }
-
- if (r == 0)
- r = -EEXIST;
- } else {
- if (r == 0)
- r = -errno;
- }
- }
-
- return r;
-}
-
-int unit_file_unmask(
- UnitFileScope scope,
- bool runtime,
- const char *root_dir,
- char **files,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- char **i, *config_path = NULL;
- int r, q;
- Set *remove_symlinks_to = NULL;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
-
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- goto finish;
-
- STRV_FOREACH(i, files) {
- _cleanup_free_ char *path = NULL;
-
- if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
- if (r == 0)
- r = -EINVAL;
- continue;
- }
-
- path = path_make_absolute(*i, config_path);
- if (!path) {
- r = -ENOMEM;
- break;
- }
-
- q = null_or_empty_path(path);
- if (q > 0) {
- if (unlink(path) < 0)
- q = -errno;
- else {
- q = mark_symlink_for_removal(&remove_symlinks_to, path);
- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
- }
- }
-
- if (q != -ENOENT && r == 0)
- r = q;
- }
-
-
-finish:
- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
- if (r == 0)
- r = q;
-
- set_free_free(remove_symlinks_to);
- free(config_path);
-
- return r;
-}
-
-int unit_file_link(
- UnitFileScope scope,
- bool runtime,
- const char *root_dir,
- char **files,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- _cleanup_lookup_paths_free_ LookupPaths paths = {};
- char **i;
- _cleanup_free_ char *config_path = NULL;
- int r, q;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
-
- STRV_FOREACH(i, files) {
- _cleanup_free_ char *path = NULL;
- char *fn;
- struct stat st;
-
- fn = basename(*i);
-
- if (!path_is_absolute(*i) ||
- !unit_name_is_valid(fn, UNIT_NAME_ANY)) {
- if (r == 0)
- r = -EINVAL;
- continue;
- }
-
- if (lstat(*i, &st) < 0) {
- if (r == 0)
- r = -errno;
- continue;
- }
-
- if (!S_ISREG(st.st_mode)) {
- r = -ENOENT;
- continue;
- }
-
- q = in_search_path(*i, paths.unit_path);
- if (q < 0)
- return q;
-
- if (q > 0)
- continue;
-
- path = path_make_absolute(fn, config_path);
- if (!path)
- return -ENOMEM;
-
- if (symlink(*i, path) >= 0) {
- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
- continue;
- }
-
- if (errno == EEXIST) {
- _cleanup_free_ char *dest = NULL;
-
- q = readlink_and_make_absolute(path, &dest);
- if (q < 0 && errno != ENOENT) {
- if (r == 0)
- r = q;
- continue;
- }
-
- if (q >= 0 && path_equal(dest, *i))
- continue;
-
- if (force) {
- if (symlink_atomic(*i, path) >= 0) {
- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
- continue;
- }
- }
-
- if (r == 0)
- r = -EEXIST;
- } else {
- if (r == 0)
- r = -errno;
- }
- }
-
- return r;
-}
-
-void unit_file_list_free(Hashmap *h) {
- UnitFileList *i;
-
- while ((i = hashmap_steal_first(h))) {
- free(i->path);
- free(i);
- }
-
- hashmap_free(h);
-}
-
-int unit_file_changes_add(
- UnitFileChange **changes,
- unsigned *n_changes,
- UnitFileChangeType type,
- const char *path,
- const char *source) {
-
- UnitFileChange *c;
- unsigned i;
-
- assert(path);
- assert(!changes == !n_changes);
-
- if (!changes)
- return 0;
-
- c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
- if (!c)
- return -ENOMEM;
-
- *changes = c;
- i = *n_changes;
-
- c[i].type = type;
- c[i].path = strdup(path);
- if (!c[i].path)
- return -ENOMEM;
-
- path_kill_slashes(c[i].path);
-
- if (source) {
- c[i].source = strdup(source);
- if (!c[i].source) {
- free(c[i].path);
- return -ENOMEM;
- }
-
- path_kill_slashes(c[i].path);
- } else
- c[i].source = NULL;
-
- *n_changes = i+1;
- return 0;
-}
-
-void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
- unsigned i;
-
- assert(changes || n_changes == 0);
-
- if (!changes)
- return;
-
- for (i = 0; i < n_changes; i++) {
- free(changes[i].path);
- free(changes[i].source);
- }
-
- free(changes);
-}
-
-static void install_info_free(UnitFileInstallInfo *i) {
- assert(i);
-
- free(i->name);
- free(i->path);
- strv_free(i->aliases);
- strv_free(i->wanted_by);
- strv_free(i->required_by);
- strv_free(i->also);
- free(i->default_instance);
- free(i);
-}
-
-static void install_info_hashmap_free(OrderedHashmap *m) {
- UnitFileInstallInfo *i;
-
- if (!m)
- return;
-
- while ((i = ordered_hashmap_steal_first(m)))
- install_info_free(i);
-
- ordered_hashmap_free(m);
-}
-
-static void install_context_done(InstallContext *c) {
- assert(c);
-
- install_info_hashmap_free(c->will_install);
- install_info_hashmap_free(c->have_installed);
-
- c->will_install = c->have_installed = NULL;
-}
-
-static int install_info_add(
- InstallContext *c,
- const char *name,
- const char *path) {
- UnitFileInstallInfo *i = NULL;
- int r;
-
- assert(c);
- assert(name || path);
-
- if (!name)
- name = basename(path);
-
- if (!unit_name_is_valid(name, UNIT_NAME_ANY))
- return -EINVAL;
-
- if (ordered_hashmap_get(c->have_installed, name) ||
- ordered_hashmap_get(c->will_install, name))
- return 0;
-
- r = ordered_hashmap_ensure_allocated(&c->will_install, &string_hash_ops);
- if (r < 0)
- return r;
-
- i = new0(UnitFileInstallInfo, 1);
- if (!i)
- return -ENOMEM;
-
- i->name = strdup(name);
- if (!i->name) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (path) {
- i->path = strdup(path);
- if (!i->path) {
- r = -ENOMEM;
- goto fail;
- }
- }
-
- r = ordered_hashmap_put(c->will_install, i->name, i);
- if (r < 0)
- goto fail;
-
- return 0;
-
-fail:
- if (i)
- install_info_free(i);
-
- return r;
-}
-
-static int install_info_add_auto(
- InstallContext *c,
- const char *name_or_path) {
-
- assert(c);
- assert(name_or_path);
-
- if (path_is_absolute(name_or_path))
- return install_info_add(c, NULL, name_or_path);
- else
- return install_info_add(c, name_or_path, NULL);
-}
-
-static int config_parse_also(
- 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) {
-
- size_t l;
- const char *word, *state;
- InstallContext *c = data;
- UnitFileInstallInfo *i = userdata;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *n;
- int r;
-
- n = strndup(word, l);
- if (!n)
- return -ENOMEM;
-
- r = install_info_add(c, n, NULL);
- if (r < 0)
- return r;
-
- r = strv_extend(&i->also, n);
- if (r < 0)
- return r;
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-static int config_parse_user(
- 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) {
-
- UnitFileInstallInfo *i = data;
- char *printed;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- r = install_full_printf(i, rvalue, &printed);
- if (r < 0)
- return r;
-
- free(i->user);
- i->user = printed;
-
- return 0;
-}
-
-static int config_parse_default_instance(
- 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) {
-
- UnitFileInstallInfo *i = data;
- char *printed;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- r = install_full_printf(i, rvalue, &printed);
- if (r < 0)
- return r;
-
- if (!unit_instance_is_valid(printed)) {
- free(printed);
- return -EINVAL;
- }
-
- free(i->default_instance);
- i->default_instance = printed;
-
- return 0;
-}
-
-static int unit_file_load(
- InstallContext *c,
- UnitFileInstallInfo *info,
- const char *path,
- const char *root_dir,
- bool allow_symlink,
- bool load,
- bool *also) {
-
- const ConfigTableItem items[] = {
- { "Install", "Alias", config_parse_strv, 0, &info->aliases },
- { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
- { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
- { "Install", "DefaultInstance", config_parse_default_instance, 0, info },
- { "Install", "Also", config_parse_also, 0, c },
- { "Exec", "User", config_parse_user, 0, info },
- {}
- };
-
- _cleanup_fclose_ FILE *f = NULL;
- int fd, r;
-
- assert(c);
- assert(info);
- assert(path);
-
- if (!isempty(root_dir))
- path = strjoina(root_dir, "/", path);
-
- if (!load) {
- r = access(path, F_OK) ? -errno : 0;
- return r;
- }
-
- fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
- if (fd < 0)
- return -errno;
-
- f = fdopen(fd, "re");
- if (!f) {
- safe_close(fd);
- return -ENOMEM;
- }
-
- r = config_parse(NULL, path, f,
- NULL,
- config_item_table_lookup, items,
- true, true, false, info);
- if (r < 0)
- return r;
-
- if (also)
- *also = !strv_isempty(info->also);
-
- return
- (int) strv_length(info->aliases) +
- (int) strv_length(info->wanted_by) +
- (int) strv_length(info->required_by);
-}
-
-static int unit_file_search(
- InstallContext *c,
- UnitFileInstallInfo *info,
- const LookupPaths *paths,
- const char *root_dir,
- bool allow_symlink,
- bool load,
- bool *also) {
-
- char **p;
- int r;
-
- assert(c);
- assert(info);
- assert(paths);
-
- if (info->path)
- return unit_file_load(c, info, info->path, root_dir, allow_symlink, load, also);
-
- assert(info->name);
-
- STRV_FOREACH(p, paths->unit_path) {
- _cleanup_free_ char *path = NULL;
-
- path = strjoin(*p, "/", info->name, NULL);
- if (!path)
- return -ENOMEM;
-
- r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also);
- if (r >= 0) {
- info->path = path;
- path = NULL;
- return r;
- }
- if (r != -ENOENT && r != -ELOOP)
- return r;
- }
-
- if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
-
- /* Unit file doesn't exist, however instance
- * enablement was requested. We will check if it is
- * possible to load template unit file. */
-
- _cleanup_free_ char *template = NULL;
-
- r = unit_name_template(info->name, &template);
- if (r < 0)
- return r;
-
- STRV_FOREACH(p, paths->unit_path) {
- _cleanup_free_ char *path = NULL;
-
- path = strjoin(*p, "/", template, NULL);
- if (!path)
- return -ENOMEM;
-
- r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also);
- if (r >= 0) {
- info->path = path;
- path = NULL;
- return r;
- }
- if (r != -ENOENT && r != -ELOOP)
- return r;
- }
- }
-
- return -ENOENT;
-}
-
-static int unit_file_can_install(
- const LookupPaths *paths,
- const char *root_dir,
- const char *name,
- bool allow_symlink,
- bool *also) {
-
- _cleanup_(install_context_done) InstallContext c = {};
- UnitFileInstallInfo *i;
- int r;
-
- assert(paths);
- assert(name);
-
- r = install_info_add_auto(&c, name);
- if (r < 0)
- return r;
-
- assert_se(i = ordered_hashmap_first(c.will_install));
-
- r = unit_file_search(&c, i, paths, root_dir, allow_symlink, true, also);
-
- if (r >= 0)
- r =
- (int) strv_length(i->aliases) +
- (int) strv_length(i->wanted_by) +
- (int) strv_length(i->required_by);
-
- return r;
-}
-
-static int create_symlink(
- const char *old_path,
- const char *new_path,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- _cleanup_free_ char *dest = NULL;
- int r;
-
- assert(old_path);
- assert(new_path);
-
- mkdir_parents_label(new_path, 0755);
-
- if (symlink(old_path, new_path) >= 0) {
- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
- return 0;
- }
-
- if (errno != EEXIST)
- return -errno;
-
- r = readlink_and_make_absolute(new_path, &dest);
- if (r < 0)
- return r;
-
- if (path_equal(dest, old_path))
- return 0;
-
- if (!force)
- return -EEXIST;
-
- r = symlink_atomic(old_path, new_path);
- if (r < 0)
- return r;
-
- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
-
- return 0;
-}
-
-static int install_info_symlink_alias(
- UnitFileInstallInfo *i,
- const char *config_path,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- char **s;
- int r = 0, q;
-
- assert(i);
- assert(config_path);
-
- STRV_FOREACH(s, i->aliases) {
- _cleanup_free_ char *alias_path = NULL, *dst = NULL;
-
- q = install_full_printf(i, *s, &dst);
- if (q < 0)
- return q;
-
- alias_path = path_make_absolute(dst, config_path);
- if (!alias_path)
- return -ENOMEM;
-
- q = create_symlink(i->path, alias_path, force, changes, n_changes);
- if (r == 0)
- r = q;
- }
-
- return r;
-}
-
-static int install_info_symlink_wants(
- UnitFileInstallInfo *i,
- const char *config_path,
- char **list,
- const char *suffix,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- _cleanup_free_ char *buf = NULL;
- const char *n;
- char **s;
- int r = 0, q;
-
- assert(i);
- assert(config_path);
-
- if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
-
- /* Don't install any symlink if there's no default
- * instance configured */
-
- if (!i->default_instance)
- return 0;
-
- r = unit_name_replace_instance(i->name, i->default_instance, &buf);
- if (r < 0)
- return r;
-
- n = buf;
- } else
- n = i->name;
-
- STRV_FOREACH(s, list) {
- _cleanup_free_ char *path = NULL, *dst = NULL;
-
- q = install_full_printf(i, *s, &dst);
- if (q < 0)
- return q;
-
- if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
- r = -EINVAL;
- continue;
- }
-
- path = strjoin(config_path, "/", dst, suffix, n, NULL);
- if (!path)
- return -ENOMEM;
-
- q = create_symlink(i->path, path, force, changes, n_changes);
- if (r == 0)
- r = q;
- }
-
- return r;
-}
-
-static int install_info_symlink_link(
- UnitFileInstallInfo *i,
- const LookupPaths *paths,
- const char *config_path,
- const char *root_dir,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- _cleanup_free_ char *path = NULL;
- int r;
-
- assert(i);
- assert(paths);
- assert(config_path);
- assert(i->path);
-
- r = in_search_path(i->path, paths->unit_path);
- if (r != 0)
- return r;
-
- path = strjoin(config_path, "/", i->name, NULL);
- if (!path)
- return -ENOMEM;
-
- return create_symlink(i->path, path, force, changes, n_changes);
-}
-
-static int install_info_apply(
- UnitFileInstallInfo *i,
- const LookupPaths *paths,
- const char *config_path,
- const char *root_dir,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- int r, q;
-
- assert(i);
- assert(paths);
- assert(config_path);
-
- r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
-
- q = install_info_symlink_wants(i, config_path, i->wanted_by, ".wants/", force, changes, n_changes);
- if (r == 0)
- r = q;
-
- q = install_info_symlink_wants(i, config_path, i->required_by, ".requires/", force, changes, n_changes);
- if (r == 0)
- r = q;
-
- q = install_info_symlink_link(i, paths, config_path, root_dir, force, changes, n_changes);
- if (r == 0)
- r = q;
-
- return r;
-}
-
-static int install_context_apply(
- InstallContext *c,
- const LookupPaths *paths,
- const char *config_path,
- const char *root_dir,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- UnitFileInstallInfo *i;
- int r, q;
-
- assert(c);
- assert(paths);
- assert(config_path);
-
- if (!ordered_hashmap_isempty(c->will_install)) {
- r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops);
- if (r < 0)
- return r;
-
- r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install));
- if (r < 0)
- return r;
- }
-
- r = 0;
- while ((i = ordered_hashmap_first(c->will_install))) {
- assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
-
- q = unit_file_search(c, i, paths, root_dir, false, true, NULL);
- if (q < 0) {
- if (r >= 0)
- r = q;
-
- return r;
- } else if (r >= 0)
- r += q;
-
- q = install_info_apply(i, paths, config_path, root_dir, force, changes, n_changes);
- if (r >= 0 && q < 0)
- r = q;
- }
-
- return r;
-}
-
-static int install_context_mark_for_removal(
- InstallContext *c,
- const LookupPaths *paths,
- Set **remove_symlinks_to,
- const char *config_path,
- const char *root_dir) {
-
- UnitFileInstallInfo *i;
- int r, q;
-
- assert(c);
- assert(paths);
- assert(config_path);
-
- /* Marks all items for removal */
-
- if (!ordered_hashmap_isempty(c->will_install)) {
- r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops);
- if (r < 0)
- return r;
-
- r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install));
- if (r < 0)
- return r;
- }
-
- r = 0;
- while ((i = ordered_hashmap_first(c->will_install))) {
- assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
-
- q = unit_file_search(c, i, paths, root_dir, false, true, NULL);
- if (q == -ENOENT) {
- /* do nothing */
- } else if (q < 0) {
- if (r >= 0)
- r = q;
-
- return r;
- } else if (r >= 0)
- r += q;
-
- if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
- char *unit_file;
-
- if (i->path) {
- unit_file = basename(i->path);
-
- if (unit_name_is_valid(unit_file, UNIT_NAME_INSTANCE))
- /* unit file named as instance exists, thus all symlinks
- * pointing to it will be removed */
- q = mark_symlink_for_removal(remove_symlinks_to, i->name);
- else
- /* does not exist, thus we will mark for removal symlinks
- * to template unit file */
- q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
- } else {
- /* If i->path is not set, it means that we didn't actually find
- * the unit file. But we can still remove symlinks to the
- * nonexistent template. */
- r = unit_name_template(i->name, &unit_file);
- if (r < 0)
- return r;
-
- q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
- free(unit_file);
- }
- } else
- q = mark_symlink_for_removal(remove_symlinks_to, i->name);
-
- if (r >= 0 && q < 0)
- r = q;
- }
-
- return r;
-}
-
-int unit_file_add_dependency(
- UnitFileScope scope,
- bool runtime,
- const char *root_dir,
- char **files,
- char *target,
- UnitDependency dep,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- _cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_(install_context_done) InstallContext c = {};
- _cleanup_free_ char *config_path = NULL;
- char **i;
- int r;
- UnitFileInstallInfo *info;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
-
- STRV_FOREACH(i, files) {
- UnitFileState state;
-
- state = unit_file_get_state(scope, root_dir, *i);
- if (state < 0)
- return log_error_errno(state, "Failed to get unit file state for %s: %m", *i);
-
- if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) {
- log_error("Failed to enable unit: Unit %s is masked", *i);
- return -EOPNOTSUPP;
- }
-
- r = install_info_add_auto(&c, *i);
- if (r < 0)
- return r;
- }
-
- if (!ordered_hashmap_isempty(c.will_install)) {
- r = ordered_hashmap_ensure_allocated(&c.have_installed, &string_hash_ops);
- if (r < 0)
- return r;
-
- r = ordered_hashmap_reserve(c.have_installed, ordered_hashmap_size(c.will_install));
- if (r < 0)
- return r;
- }
-
- while ((info = ordered_hashmap_first(c.will_install))) {
- assert_se(ordered_hashmap_move_one(c.have_installed, c.will_install, info->name) == 0);
-
- r = unit_file_search(&c, info, &paths, root_dir, false, false, NULL);
- if (r < 0)
- return r;
-
- if (dep == UNIT_WANTS)
- r = strv_extend(&info->wanted_by, target);
- else if (dep == UNIT_REQUIRES)
- r = strv_extend(&info->required_by, target);
- else
- r = -EINVAL;
-
- if (r < 0)
- return r;
-
- r = install_info_apply(info, &paths, config_path, root_dir, force, changes, n_changes);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int unit_file_enable(
- UnitFileScope scope,
- bool runtime,
- const char *root_dir,
- char **files,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- _cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_(install_context_done) InstallContext c = {};
- char **i;
- _cleanup_free_ char *config_path = NULL;
- int r;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
-
- STRV_FOREACH(i, files) {
- UnitFileState state;
-
- /* We only want to know if this unit is masked, so we ignore
- * errors from unit_file_get_state, deferring other checks.
- * This allows templated units to be enabled on the fly. */
- state = unit_file_get_state(scope, root_dir, *i);
- if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) {
- log_error("Failed to enable unit: Unit %s is masked", *i);
- return -EOPNOTSUPP;
- }
-
- r = install_info_add_auto(&c, *i);
- if (r < 0)
- return r;
- }
-
- /* This will return the number of symlink rules that were
- supposed to be created, not the ones actually created. This is
- useful to determine whether the passed files had any
- installation data at all. */
-
- return install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
-}
-
-int unit_file_disable(
- UnitFileScope scope,
- bool runtime,
- const char *root_dir,
- char **files,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- _cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_(install_context_done) InstallContext c = {};
- char **i;
- _cleanup_free_ char *config_path = NULL;
- _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- int r, q;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
-
- STRV_FOREACH(i, files) {
- r = install_info_add_auto(&c, *i);
- if (r < 0)
- return r;
- }
-
- r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
-
- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
- if (r >= 0)
- r = q;
-
- return r;
-}
-
-int unit_file_reenable(
- UnitFileScope scope,
- bool runtime,
- const char *root_dir,
- char **files,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
- int r;
-
- r = unit_file_disable(scope, runtime, root_dir, files,
- changes, n_changes);
- if (r < 0)
- return r;
-
- return unit_file_enable(scope, runtime, root_dir, files, force,
- changes, n_changes);
-}
-
-int unit_file_set_default(
- UnitFileScope scope,
- const char *root_dir,
- const char *file,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- _cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_(install_context_done) InstallContext c = {};
- _cleanup_free_ char *config_path = NULL;
- char *path;
- int r;
- UnitFileInstallInfo *i = NULL;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(file);
-
- if (unit_name_to_type(file) != UNIT_TARGET)
- return -EINVAL;
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- r = get_config_path(scope, false, root_dir, &config_path);
- if (r < 0)
- return r;
-
- r = install_info_add_auto(&c, file);
- if (r < 0)
- return r;
-
- assert_se(i = ordered_hashmap_first(c.will_install));
-
- r = unit_file_search(&c, i, &paths, root_dir, false, true, NULL);
- if (r < 0)
- return r;
-
- path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET);
-
- r = create_symlink(i->path, path, force, changes, n_changes);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int unit_file_get_default(
- UnitFileScope scope,
- const char *root_dir,
- char **name) {
-
- _cleanup_lookup_paths_free_ LookupPaths paths = {};
- char **p;
- int r;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(name);
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- STRV_FOREACH(p, paths.unit_path) {
- _cleanup_free_ char *path = NULL, *tmp = NULL;
- char *n;
-
- path = path_join(root_dir, *p, SPECIAL_DEFAULT_TARGET);
- if (!path)
- return -ENOMEM;
-
- r = readlink_malloc(path, &tmp);
- if (r == -ENOENT)
- continue;
- else if (r == -EINVAL)
- /* not a symlink */
- n = strdup(SPECIAL_DEFAULT_TARGET);
- else if (r < 0)
- return r;
- else
- n = strdup(basename(tmp));
-
- if (!n)
- return -ENOMEM;
-
- *name = n;
- return 0;
- }
-
- return -ENOENT;
-}
-
-UnitFileState unit_file_lookup_state(
- UnitFileScope scope,
- const char *root_dir,
- const LookupPaths *paths,
- const char *name) {
-
- UnitFileState state = _UNIT_FILE_STATE_INVALID;
- char **i;
- _cleanup_free_ char *path = NULL;
- int r = 0;
-
- assert(paths);
-
- if (!unit_name_is_valid(name, UNIT_NAME_ANY))
- return -EINVAL;
-
- STRV_FOREACH(i, paths->unit_path) {
- struct stat st;
- char *partial;
- bool also = false;
-
- free(path);
- path = path_join(root_dir, *i, name);
- if (!path)
- return -ENOMEM;
-
- if (root_dir)
- partial = path + strlen(root_dir);
- else
- partial = path;
-
- /*
- * Search for a unit file in our default paths, to
- * be sure, that there are no broken symlinks.
- */
- if (lstat(path, &st) < 0) {
- r = -errno;
- if (errno != ENOENT)
- return r;
-
- if (!unit_name_is_valid(name, UNIT_NAME_INSTANCE))
- continue;
- } else {
- if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
- return -ENOENT;
-
- r = null_or_empty_path(path);
- if (r < 0 && r != -ENOENT)
- return r;
- else if (r > 0) {
- state = path_startswith(*i, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
- return state;
- }
- }
-
- r = find_symlinks_in_scope(scope, root_dir, name, &state);
- if (r < 0)
- return r;
- else if (r > 0)
- return state;
-
- r = unit_file_can_install(paths, root_dir, partial, true, &also);
- if (r < 0 && errno != ENOENT)
- return r;
- else if (r > 0)
- return UNIT_FILE_DISABLED;
- else if (r == 0) {
- if (also)
- return UNIT_FILE_INDIRECT;
- return UNIT_FILE_STATIC;
- }
- }
-
- return r < 0 ? r : state;
-}
-
-UnitFileState unit_file_get_state(
- UnitFileScope scope,
- const char *root_dir,
- const char *name) {
-
- _cleanup_lookup_paths_free_ LookupPaths paths = {};
- int r;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(name);
-
- if (root_dir && scope != UNIT_FILE_SYSTEM)
- return -EINVAL;
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- return unit_file_lookup_state(scope, root_dir, &paths, name);
-}
-
-int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
- _cleanup_strv_free_ char **files = NULL;
- char **p;
- int r;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(name);
-
- if (scope == UNIT_FILE_SYSTEM)
- r = conf_files_list(&files, ".preset", root_dir,
- "/etc/systemd/system-preset",
- "/usr/local/lib/systemd/system-preset",
- "/usr/lib/systemd/system-preset",
-#ifdef HAVE_SPLIT_USR
- "/lib/systemd/system-preset",
-#endif
- NULL);
- else if (scope == UNIT_FILE_GLOBAL)
- r = conf_files_list(&files, ".preset", root_dir,
- "/etc/systemd/user-preset",
- "/usr/local/lib/systemd/user-preset",
- "/usr/lib/systemd/user-preset",
- NULL);
- else
- return 1;
-
- if (r < 0)
- return r;
-
- STRV_FOREACH(p, files) {
- _cleanup_fclose_ FILE *f;
-
- f = fopen(*p, "re");
- if (!f) {
- if (errno == ENOENT)
- continue;
-
- return -errno;
- }
-
- for (;;) {
- char line[LINE_MAX], *l;
-
- if (!fgets(line, sizeof(line), f))
- break;
-
- l = strstrip(line);
- if (!*l)
- continue;
-
- if (strchr(COMMENTS "\n", *l))
- continue;
-
- if (first_word(l, "enable")) {
- l += 6;
- l += strspn(l, WHITESPACE);
-
- if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
- log_debug("Preset file says enable %s.", name);
- return 1;
- }
-
- } else if (first_word(l, "disable")) {
- l += 7;
- l += strspn(l, WHITESPACE);
-
- if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
- log_debug("Preset file says disable %s.", name);
- return 0;
- }
-
- } else
- log_debug("Couldn't parse line '%s'", l);
- }
- }
-
- /* Default is "enable" */
- log_debug("Preset file doesn't say anything about %s, enabling.", name);
- return 1;
-}
-
-int unit_file_preset(
- UnitFileScope scope,
- bool runtime,
- const char *root_dir,
- char **files,
- UnitFilePresetMode mode,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
- _cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_free_ char *config_path = NULL;
- char **i;
- int r, q;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(mode < _UNIT_FILE_PRESET_MAX);
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
-
- STRV_FOREACH(i, files) {
-
- if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
- return -EINVAL;
-
- r = unit_file_query_preset(scope, root_dir, *i);
- if (r < 0)
- return r;
-
- if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY)
- r = install_info_add_auto(&plus, *i);
- else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY)
- r = install_info_add_auto(&minus, *i);
- else
- r = 0;
- if (r < 0)
- return r;
- }
-
- r = 0;
-
- if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
- _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
-
- r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
-
- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
- if (r == 0)
- r = q;
- }
-
- if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
- /* Returns number of symlinks that where supposed to be installed. */
- q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
- if (r == 0)
- r = q;
- }
-
- return r;
-}
-
-int unit_file_preset_all(
- UnitFileScope scope,
- bool runtime,
- const char *root_dir,
- UnitFilePresetMode mode,
- bool force,
- UnitFileChange **changes,
- unsigned *n_changes) {
-
- _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
- _cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_free_ char *config_path = NULL;
- char **i;
- int r, q;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(mode < _UNIT_FILE_PRESET_MAX);
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
-
- STRV_FOREACH(i, paths.unit_path) {
- _cleanup_closedir_ DIR *d = NULL;
- _cleanup_free_ char *units_dir;
-
- units_dir = path_join(root_dir, *i, NULL);
- if (!units_dir)
- return -ENOMEM;
-
- d = opendir(units_dir);
- if (!d) {
- if (errno == ENOENT)
- continue;
-
- return -errno;
- }
-
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0)
- return -errno;
-
- if (!de)
- break;
-
- if (hidden_file(de->d_name))
- continue;
-
- if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
- continue;
-
- dirent_ensure_type(d, de);
-
- if (de->d_type != DT_REG)
- continue;
-
- r = unit_file_query_preset(scope, root_dir, de->d_name);
- if (r < 0)
- return r;
-
- if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY)
- r = install_info_add_auto(&plus, de->d_name);
- else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY)
- r = install_info_add_auto(&minus, de->d_name);
- else
- r = 0;
- if (r < 0)
- return r;
- }
- }
-
- r = 0;
-
- if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
- _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
-
- r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
-
- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, NULL);
- if (r == 0)
- r = q;
- }
-
- if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
- q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
- if (r == 0)
- r = q;
- }
-
- return r;
-}
-
-static void unit_file_list_free_one(UnitFileList *f) {
- if (!f)
- return;
-
- free(f->path);
- free(f);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
-
-int unit_file_get_list(
- UnitFileScope scope,
- const char *root_dir,
- Hashmap *h) {
-
- _cleanup_lookup_paths_free_ LookupPaths paths = {};
- char **i;
- int r;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(h);
-
- if (root_dir && scope != UNIT_FILE_SYSTEM)
- return -EINVAL;
-
- if (root_dir) {
- r = access(root_dir, F_OK);
- if (r < 0)
- return -errno;
- }
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- STRV_FOREACH(i, paths.unit_path) {
- _cleanup_closedir_ DIR *d = NULL;
- _cleanup_free_ char *units_dir;
-
- units_dir = path_join(root_dir, *i, NULL);
- if (!units_dir)
- return -ENOMEM;
-
- d = opendir(units_dir);
- if (!d) {
- if (errno == ENOENT)
- continue;
-
- return -errno;
- }
-
- for (;;) {
- _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
- struct dirent *de;
- _cleanup_free_ char *path = NULL;
- bool also = false;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0)
- return -errno;
-
- if (!de)
- break;
-
- if (hidden_file(de->d_name))
- continue;
-
- if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
- continue;
-
- if (hashmap_get(h, de->d_name))
- continue;
-
- dirent_ensure_type(d, de);
-
- if (!IN_SET(de->d_type, DT_LNK, DT_REG))
- continue;
-
- f = new0(UnitFileList, 1);
- if (!f)
- return -ENOMEM;
-
- f->path = path_make_absolute(de->d_name, units_dir);
- if (!f->path)
- return -ENOMEM;
-
- r = null_or_empty_path(f->path);
- if (r < 0 && r != -ENOENT)
- return r;
- else if (r > 0) {
- f->state =
- path_startswith(*i, "/run") ?
- UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
- goto found;
- }
-
- r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
- if (r < 0)
- return r;
- else if (r > 0) {
- f->state = UNIT_FILE_ENABLED;
- goto found;
- }
-
- path = path_make_absolute(de->d_name, *i);
- if (!path)
- return -ENOMEM;
-
- r = unit_file_can_install(&paths, root_dir, path, true, &also);
- if (r == -EINVAL || /* Invalid setting? */
- r == -EBADMSG || /* Invalid format? */
- r == -ENOENT /* Included file not found? */)
- f->state = UNIT_FILE_INVALID;
- else if (r < 0)
- return r;
- else if (r > 0)
- f->state = UNIT_FILE_DISABLED;
- else
- f->state = also ? UNIT_FILE_INDIRECT : UNIT_FILE_STATIC;
-
- found:
- r = hashmap_put(h, basename(f->path), f);
- if (r < 0)
- return r;
- f = NULL; /* prevent cleanup */
- }
- }
-
- return 0;
-}
-
-static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
- [UNIT_FILE_ENABLED] = "enabled",
- [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
- [UNIT_FILE_LINKED] = "linked",
- [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
- [UNIT_FILE_MASKED] = "masked",
- [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
- [UNIT_FILE_STATIC] = "static",
- [UNIT_FILE_DISABLED] = "disabled",
- [UNIT_FILE_INDIRECT] = "indirect",
- [UNIT_FILE_INVALID] = "invalid",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
-
-static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
- [UNIT_FILE_SYMLINK] = "symlink",
- [UNIT_FILE_UNLINK] = "unlink",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
-
-static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
- [UNIT_FILE_PRESET_FULL] = "full",
- [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
- [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode);
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <time.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <fcntl.h>
-
-#include "logs-show.h"
-#include "log.h"
-#include "util.h"
-#include "utf8.h"
-#include "hashmap.h"
-#include "journal-internal.h"
-#include "formats-util.h"
-#include "process-util.h"
-#include "terminal-util.h"
-
-/* up to three lines (each up to 100 characters),
- or 300 characters, whichever is less */
-#define PRINT_LINE_THRESHOLD 3
-#define PRINT_CHAR_THRESHOLD 300
-
-#define JSON_THRESHOLD 4096
-
-static int print_catalog(FILE *f, sd_journal *j) {
- int r;
- _cleanup_free_ char *t = NULL, *z = NULL;
-
-
- r = sd_journal_get_catalog(j, &t);
- if (r < 0)
- return r;
-
- z = strreplace(strstrip(t), "\n", "\n-- ");
- if (!z)
- return log_oom();
-
- fputs("-- ", f);
- fputs(z, f);
- fputc('\n', f);
-
- return 0;
-}
-
-static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
- size_t fl, nl;
- void *buf;
-
- assert(data);
- assert(field);
- assert(target);
- assert(target_size);
-
- fl = strlen(field);
- if (length < fl)
- return 0;
-
- if (memcmp(data, field, fl))
- return 0;
-
- nl = length - fl;
- buf = malloc(nl+1);
- if (!buf)
- return log_oom();
-
- memcpy(buf, (const char*) data + fl, nl);
- ((char*)buf)[nl] = 0;
-
- free(*target);
- *target = buf;
- *target_size = nl;
-
- return 1;
-}
-
-static bool shall_print(const char *p, size_t l, OutputFlags flags) {
- assert(p);
-
- if (flags & OUTPUT_SHOW_ALL)
- return true;
-
- if (l >= PRINT_CHAR_THRESHOLD)
- return false;
-
- if (!utf8_is_printable(p, l))
- return false;
-
- return true;
-}
-
-static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) {
- const char *color_on = "", *color_off = "";
- const char *pos, *end;
- bool ellipsized = false;
- int line = 0;
-
- if (flags & OUTPUT_COLOR) {
- if (priority <= LOG_ERR) {
- color_on = ANSI_HIGHLIGHT_RED_ON;
- color_off = ANSI_HIGHLIGHT_OFF;
- } else if (priority <= LOG_NOTICE) {
- color_on = ANSI_HIGHLIGHT_ON;
- color_off = ANSI_HIGHLIGHT_OFF;
- }
- }
-
- /* A special case: make sure that we print a newline when
- the message is empty. */
- if (message_len == 0)
- fputs("\n", f);
-
- for (pos = message;
- pos < message + message_len;
- pos = end + 1, line++) {
- bool continuation = line > 0;
- bool tail_line;
- int len;
- for (end = pos; end < message + message_len && *end != '\n'; end++)
- ;
- len = end - pos;
- assert(len >= 0);
-
- /* We need to figure out when we are showing not-last line, *and*
- * will skip subsequent lines. In that case, we will put the dots
- * at the end of the line, instead of putting dots in the middle
- * or not at all.
- */
- tail_line =
- line + 1 == PRINT_LINE_THRESHOLD ||
- end + 1 >= message + PRINT_CHAR_THRESHOLD;
-
- if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
- (prefix + len + 1 < n_columns && !tail_line)) {
- fprintf(f, "%*s%s%.*s%s\n",
- continuation * prefix, "",
- color_on, len, pos, color_off);
- continue;
- }
-
- /* Beyond this point, ellipsization will happen. */
- ellipsized = true;
-
- if (prefix < n_columns && n_columns - prefix >= 3) {
- if (n_columns - prefix > (unsigned) len + 3)
- fprintf(f, "%*s%s%.*s...%s\n",
- continuation * prefix, "",
- color_on, len, pos, color_off);
- else {
- _cleanup_free_ char *e;
-
- e = ellipsize_mem(pos, len, n_columns - prefix,
- tail_line ? 100 : 90);
- if (!e)
- fprintf(f, "%*s%s%.*s%s\n",
- continuation * prefix, "",
- color_on, len, pos, color_off);
- else
- fprintf(f, "%*s%s%s%s\n",
- continuation * prefix, "",
- color_on, e, color_off);
- }
- } else
- fputs("...\n", f);
-
- if (tail_line)
- break;
- }
-
- return ellipsized;
-}
-
-static int output_short(
- FILE *f,
- sd_journal *j,
- OutputMode mode,
- unsigned n_columns,
- OutputFlags flags) {
-
- int r;
- const void *data;
- size_t length;
- size_t n = 0;
- _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
- size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0, realtime_len = 0, monotonic_len = 0, priority_len = 0;
- int p = LOG_INFO;
- bool ellipsized = false;
-
- assert(f);
- assert(j);
-
- /* Set the threshold to one bigger than the actual print
- * threshold, so that if the line is actually longer than what
- * we're willing to print, ellipsization will occur. This way
- * we won't output a misleading line without any indication of
- * truncation.
- */
- sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
-
- JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
-
- r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "_COMM=", &comm, &comm_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "_PID=", &pid, &pid_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "MESSAGE=", &message, &message_len);
- if (r < 0)
- return r;
- }
-
- if (r < 0)
- return log_error_errno(r, "Failed to get journal fields: %m");
-
- if (!message) {
- log_debug("Skipping message without MESSAGE= field.");
- return 0;
- }
-
- if (!(flags & OUTPUT_SHOW_ALL))
- strip_tab_ansi(&message, &message_len);
-
- if (priority_len == 1 && *priority >= '0' && *priority <= '7')
- p = *priority - '0';
-
- if (mode == OUTPUT_SHORT_MONOTONIC) {
- uint64_t t;
- sd_id128_t boot_id;
-
- r = -ENOENT;
-
- if (monotonic)
- r = safe_atou64(monotonic, &t);
-
- if (r < 0)
- r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
-
- if (r < 0)
- return log_error_errno(r, "Failed to get monotonic timestamp: %m");
-
- fprintf(f, "[%5llu.%06llu]",
- (unsigned long long) (t / USEC_PER_SEC),
- (unsigned long long) (t % USEC_PER_SEC));
-
- n += 1 + 5 + 1 + 6 + 1;
-
- } else {
- char buf[64];
- uint64_t x;
- time_t t;
- struct tm tm;
- struct tm *(*gettime_r)(const time_t *, struct tm *);
-
- r = -ENOENT;
- gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
-
- if (realtime)
- r = safe_atou64(realtime, &x);
-
- if (r < 0)
- r = sd_journal_get_realtime_usec(j, &x);
-
- if (r < 0)
- return log_error_errno(r, "Failed to get realtime timestamp: %m");
-
- t = (time_t) (x / USEC_PER_SEC);
-
- switch(mode) {
- case OUTPUT_SHORT_ISO:
- r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
- break;
- case OUTPUT_SHORT_PRECISE:
- r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
- if (r > 0) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
- ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
- }
- break;
- default:
- r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
- }
-
- if (r <= 0) {
- log_error("Failed to format time.");
- return -EINVAL;
- }
-
- fputs(buf, f);
- n += strlen(buf);
- }
-
- if (hostname && shall_print(hostname, hostname_len, flags)) {
- fprintf(f, " %.*s", (int) hostname_len, hostname);
- n += hostname_len + 1;
- }
-
- if (identifier && shall_print(identifier, identifier_len, flags)) {
- fprintf(f, " %.*s", (int) identifier_len, identifier);
- n += identifier_len + 1;
- } else if (comm && shall_print(comm, comm_len, flags)) {
- fprintf(f, " %.*s", (int) comm_len, comm);
- n += comm_len + 1;
- } else
- fputs(" unknown", f);
-
- if (pid && shall_print(pid, pid_len, flags)) {
- fprintf(f, "[%.*s]", (int) pid_len, pid);
- n += pid_len + 2;
- } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
- fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
- n += fake_pid_len + 2;
- }
-
- if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
- char bytes[FORMAT_BYTES_MAX];
- fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
- } else {
- fputs(": ", f);
- ellipsized |=
- print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
- }
-
- if (flags & OUTPUT_CATALOG)
- print_catalog(f, j);
-
- return ellipsized;
-}
-
-static int output_verbose(
- FILE *f,
- sd_journal *j,
- OutputMode mode,
- unsigned n_columns,
- OutputFlags flags) {
-
- const void *data;
- size_t length;
- _cleanup_free_ char *cursor = NULL;
- uint64_t realtime;
- char ts[FORMAT_TIMESTAMP_MAX + 7];
- int r;
-
- assert(f);
- assert(j);
-
- sd_journal_set_data_threshold(j, 0);
-
- r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
- if (r == -ENOENT)
- log_debug("Source realtime timestamp not found");
- else if (r < 0)
- return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get source realtime timestamp: %m");
- else {
- _cleanup_free_ char *value = NULL;
- size_t size;
-
- r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
- if (r < 0)
- log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
- else {
- r = safe_atou64(value, &realtime);
- if (r < 0)
- log_debug_errno(r, "Failed to parse realtime timestamp: %m");
- }
- }
-
- if (r < 0) {
- r = sd_journal_get_realtime_usec(j, &realtime);
- if (r < 0)
- return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get realtime timestamp: %m");
- }
-
- r = sd_journal_get_cursor(j, &cursor);
- if (r < 0)
- return log_error_errno(r, "Failed to get cursor: %m");
-
- fprintf(f, "%s [%s]\n",
- flags & OUTPUT_UTC ?
- format_timestamp_us_utc(ts, sizeof(ts), realtime) :
- format_timestamp_us(ts, sizeof(ts), realtime),
- cursor);
-
- JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
- const char *c;
- int fieldlen;
- const char *on = "", *off = "";
-
- c = memchr(data, '=', length);
- if (!c) {
- log_error("Invalid field.");
- return -EINVAL;
- }
- fieldlen = c - (const char*) data;
-
- if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
- on = ANSI_HIGHLIGHT_ON;
- off = ANSI_HIGHLIGHT_OFF;
- }
-
- if (flags & OUTPUT_SHOW_ALL ||
- (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
- && utf8_is_printable(data, length))) {
- fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
- print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
- fputs(off, f);
- } else {
- char bytes[FORMAT_BYTES_MAX];
-
- fprintf(f, " %s%.*s=[%s blob data]%s\n",
- on,
- (int) (c - (const char*) data),
- (const char*) data,
- format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
- off);
- }
- }
-
- if (r < 0)
- return r;
-
- if (flags & OUTPUT_CATALOG)
- print_catalog(f, j);
-
- return 0;
-}
-
-static int output_export(
- FILE *f,
- sd_journal *j,
- OutputMode mode,
- unsigned n_columns,
- OutputFlags flags) {
-
- sd_id128_t boot_id;
- char sid[33];
- int r;
- usec_t realtime, monotonic;
- _cleanup_free_ char *cursor = NULL;
- const void *data;
- size_t length;
-
- assert(j);
-
- sd_journal_set_data_threshold(j, 0);
-
- r = sd_journal_get_realtime_usec(j, &realtime);
- if (r < 0)
- return log_error_errno(r, "Failed to get realtime timestamp: %m");
-
- r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
- if (r < 0)
- return log_error_errno(r, "Failed to get monotonic timestamp: %m");
-
- r = sd_journal_get_cursor(j, &cursor);
- if (r < 0)
- return log_error_errno(r, "Failed to get cursor: %m");
-
- fprintf(f,
- "__CURSOR=%s\n"
- "__REALTIME_TIMESTAMP="USEC_FMT"\n"
- "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
- "_BOOT_ID=%s\n",
- cursor,
- realtime,
- monotonic,
- sd_id128_to_string(boot_id, sid));
-
- JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
-
- /* We already printed the boot id, from the data in
- * the header, hence let's suppress it here */
- if (length >= 9 &&
- startswith(data, "_BOOT_ID="))
- continue;
-
- if (utf8_is_printable_newline(data, length, false))
- fwrite(data, length, 1, f);
- else {
- const char *c;
- uint64_t le64;
-
- c = memchr(data, '=', length);
- if (!c) {
- log_error("Invalid field.");
- return -EINVAL;
- }
-
- fwrite(data, c - (const char*) data, 1, f);
- fputc('\n', f);
- le64 = htole64(length - (c - (const char*) data) - 1);
- fwrite(&le64, sizeof(le64), 1, f);
- fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
- }
-
- fputc('\n', f);
- }
-
- if (r < 0)
- return r;
-
- fputc('\n', f);
-
- return 0;
-}
-
-void json_escape(
- FILE *f,
- const char* p,
- size_t l,
- OutputFlags flags) {
-
- assert(f);
- assert(p);
-
- if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
-
- fputs("null", f);
-
- else if (!utf8_is_printable(p, l)) {
- bool not_first = false;
-
- fputs("[ ", f);
-
- while (l > 0) {
- if (not_first)
- fprintf(f, ", %u", (uint8_t) *p);
- else {
- not_first = true;
- fprintf(f, "%u", (uint8_t) *p);
- }
-
- p++;
- l--;
- }
-
- fputs(" ]", f);
- } else {
- fputc('\"', f);
-
- while (l > 0) {
- if (*p == '"' || *p == '\\') {
- fputc('\\', f);
- fputc(*p, f);
- } else if (*p == '\n')
- fputs("\\n", f);
- else if (*p < ' ')
- fprintf(f, "\\u%04x", *p);
- else
- fputc(*p, f);
-
- p++;
- l--;
- }
-
- fputc('\"', f);
- }
-}
-
-static int output_json(
- FILE *f,
- sd_journal *j,
- OutputMode mode,
- unsigned n_columns,
- OutputFlags flags) {
-
- uint64_t realtime, monotonic;
- _cleanup_free_ char *cursor = NULL;
- const void *data;
- size_t length;
- sd_id128_t boot_id;
- char sid[33], *k;
- int r;
- Hashmap *h = NULL;
- bool done, separator;
-
- assert(j);
-
- sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
-
- r = sd_journal_get_realtime_usec(j, &realtime);
- if (r < 0)
- return log_error_errno(r, "Failed to get realtime timestamp: %m");
-
- r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
- if (r < 0)
- return log_error_errno(r, "Failed to get monotonic timestamp: %m");
-
- r = sd_journal_get_cursor(j, &cursor);
- if (r < 0)
- return log_error_errno(r, "Failed to get cursor: %m");
-
- if (mode == OUTPUT_JSON_PRETTY)
- fprintf(f,
- "{\n"
- "\t\"__CURSOR\" : \"%s\",\n"
- "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
- "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
- "\t\"_BOOT_ID\" : \"%s\"",
- cursor,
- realtime,
- monotonic,
- sd_id128_to_string(boot_id, sid));
- else {
- if (mode == OUTPUT_JSON_SSE)
- fputs("data: ", f);
-
- fprintf(f,
- "{ \"__CURSOR\" : \"%s\", "
- "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
- "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
- "\"_BOOT_ID\" : \"%s\"",
- cursor,
- realtime,
- monotonic,
- sd_id128_to_string(boot_id, sid));
- }
-
- h = hashmap_new(&string_hash_ops);
- if (!h)
- return log_oom();
-
- /* First round, iterate through the entry and count how often each field appears */
- JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
- const char *eq;
- char *n;
- unsigned u;
-
- if (length >= 9 &&
- memcmp(data, "_BOOT_ID=", 9) == 0)
- continue;
-
- eq = memchr(data, '=', length);
- if (!eq)
- continue;
-
- n = strndup(data, eq - (const char*) data);
- if (!n) {
- r = log_oom();
- goto finish;
- }
-
- u = PTR_TO_UINT(hashmap_get(h, n));
- if (u == 0) {
- r = hashmap_put(h, n, UINT_TO_PTR(1));
- if (r < 0) {
- free(n);
- log_oom();
- goto finish;
- }
- } else {
- r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
- free(n);
- if (r < 0) {
- log_oom();
- goto finish;
- }
- }
- }
-
- if (r < 0)
- return r;
-
- separator = true;
- do {
- done = true;
-
- SD_JOURNAL_FOREACH_DATA(j, data, length) {
- const char *eq;
- char *kk, *n;
- size_t m;
- unsigned u;
-
- /* We already printed the boot id, from the data in
- * the header, hence let's suppress it here */
- if (length >= 9 &&
- memcmp(data, "_BOOT_ID=", 9) == 0)
- continue;
-
- eq = memchr(data, '=', length);
- if (!eq)
- continue;
-
- if (separator) {
- if (mode == OUTPUT_JSON_PRETTY)
- fputs(",\n\t", f);
- else
- fputs(", ", f);
- }
-
- m = eq - (const char*) data;
-
- n = strndup(data, m);
- if (!n) {
- r = log_oom();
- goto finish;
- }
-
- u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
- if (u == 0) {
- /* We already printed this, let's jump to the next */
- free(n);
- separator = false;
-
- continue;
- } else if (u == 1) {
- /* Field only appears once, output it directly */
-
- json_escape(f, data, m, flags);
- fputs(" : ", f);
-
- json_escape(f, eq + 1, length - m - 1, flags);
-
- hashmap_remove(h, n);
- free(kk);
- free(n);
-
- separator = true;
-
- continue;
-
- } else {
- /* Field appears multiple times, output it as array */
- json_escape(f, data, m, flags);
- fputs(" : [ ", f);
- json_escape(f, eq + 1, length - m - 1, flags);
-
- /* Iterate through the end of the list */
-
- while (sd_journal_enumerate_data(j, &data, &length) > 0) {
- if (length < m + 1)
- continue;
-
- if (memcmp(data, n, m) != 0)
- continue;
-
- if (((const char*) data)[m] != '=')
- continue;
-
- fputs(", ", f);
- json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
- }
-
- fputs(" ]", f);
-
- hashmap_remove(h, n);
- free(kk);
- free(n);
-
- /* Iterate data fields form the beginning */
- done = false;
- separator = true;
-
- break;
- }
- }
-
- } while (!done);
-
- if (mode == OUTPUT_JSON_PRETTY)
- fputs("\n}\n", f);
- else if (mode == OUTPUT_JSON_SSE)
- fputs("}\n\n", f);
- else
- fputs(" }\n", f);
-
- r = 0;
-
-finish:
- while ((k = hashmap_steal_first_key(h)))
- free(k);
-
- hashmap_free(h);
-
- return r;
-}
-
-static int output_cat(
- FILE *f,
- sd_journal *j,
- OutputMode mode,
- unsigned n_columns,
- OutputFlags flags) {
-
- const void *data;
- size_t l;
- int r;
-
- assert(j);
- assert(f);
-
- sd_journal_set_data_threshold(j, 0);
-
- r = sd_journal_get_data(j, "MESSAGE", &data, &l);
- if (r < 0) {
- /* An entry without MESSAGE=? */
- if (r == -ENOENT)
- return 0;
-
- return log_error_errno(r, "Failed to get data: %m");
- }
-
- assert(l >= 8);
-
- fwrite((const char*) data + 8, 1, l - 8, f);
- fputc('\n', f);
-
- return 0;
-}
-
-static int (*output_funcs[_OUTPUT_MODE_MAX])(
- FILE *f,
- sd_journal*j,
- OutputMode mode,
- unsigned n_columns,
- OutputFlags flags) = {
-
- [OUTPUT_SHORT] = output_short,
- [OUTPUT_SHORT_ISO] = output_short,
- [OUTPUT_SHORT_PRECISE] = output_short,
- [OUTPUT_SHORT_MONOTONIC] = output_short,
- [OUTPUT_VERBOSE] = output_verbose,
- [OUTPUT_EXPORT] = output_export,
- [OUTPUT_JSON] = output_json,
- [OUTPUT_JSON_PRETTY] = output_json,
- [OUTPUT_JSON_SSE] = output_json,
- [OUTPUT_CAT] = output_cat
-};
-
-int output_journal(
- FILE *f,
- sd_journal *j,
- OutputMode mode,
- unsigned n_columns,
- OutputFlags flags,
- bool *ellipsized) {
-
- int ret;
- assert(mode >= 0);
- assert(mode < _OUTPUT_MODE_MAX);
-
- if (n_columns <= 0)
- n_columns = columns();
-
- ret = output_funcs[mode](f, j, mode, n_columns, flags);
- fflush(stdout);
-
- if (ellipsized && ret > 0)
- *ellipsized = true;
-
- return ret;
-}
-
-static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
- assert(f);
- assert(flags);
-
- if (!(*flags & OUTPUT_BEGIN_NEWLINE))
- return 0;
-
- /* Print a beginning new line if that's request, but only once
- * on the first line we print. */
-
- fputc('\n', f);
- *flags &= ~OUTPUT_BEGIN_NEWLINE;
- return 0;
-}
-
-static int show_journal(FILE *f,
- sd_journal *j,
- OutputMode mode,
- unsigned n_columns,
- usec_t not_before,
- unsigned how_many,
- OutputFlags flags,
- bool *ellipsized) {
-
- int r;
- unsigned line = 0;
- bool need_seek = false;
- int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
-
- assert(j);
- assert(mode >= 0);
- assert(mode < _OUTPUT_MODE_MAX);
-
- /* Seek to end */
- r = sd_journal_seek_tail(j);
- if (r < 0)
- return log_error_errno(r, "Failed to seek to tail: %m");
-
- r = sd_journal_previous_skip(j, how_many);
- if (r < 0)
- return log_error_errno(r, "Failed to skip previous: %m");
-
- for (;;) {
- for (;;) {
- usec_t usec;
-
- if (need_seek) {
- r = sd_journal_next(j);
- if (r < 0)
- return log_error_errno(r, "Failed to iterate through journal: %m");
- }
-
- if (r == 0)
- break;
-
- need_seek = true;
-
- if (not_before > 0) {
- r = sd_journal_get_monotonic_usec(j, &usec, NULL);
-
- /* -ESTALE is returned if the
- timestamp is not from this boot */
- if (r == -ESTALE)
- continue;
- else if (r < 0)
- return log_error_errno(r, "Failed to get journal time: %m");
-
- if (usec < not_before)
- continue;
- }
-
- line ++;
- maybe_print_begin_newline(f, &flags);
-
- r = output_journal(f, j, mode, n_columns, flags, ellipsized);
- if (r < 0)
- return r;
- }
-
- if (warn_cutoff && line < how_many && not_before > 0) {
- sd_id128_t boot_id;
- usec_t cutoff = 0;
-
- /* Check whether the cutoff line is too early */
-
- r = sd_id128_get_boot(&boot_id);
- if (r < 0)
- return log_error_errno(r, "Failed to get boot id: %m");
-
- r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to get journal cutoff time: %m");
-
- if (r > 0 && not_before < cutoff) {
- maybe_print_begin_newline(f, &flags);
- fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
- }
-
- warn_cutoff = false;
- }
-
- if (!(flags & OUTPUT_FOLLOW))
- break;
-
- r = sd_journal_wait(j, USEC_INFINITY);
- if (r < 0)
- return log_error_errno(r, "Failed to wait for journal: %m");
-
- }
-
- return 0;
-}
-
-int add_matches_for_unit(sd_journal *j, const char *unit) {
- int r;
- char *m1, *m2, *m3, *m4;
-
- assert(j);
- assert(unit);
-
- m1 = strjoina("_SYSTEMD_UNIT=", unit);
- m2 = strjoina("COREDUMP_UNIT=", unit);
- m3 = strjoina("UNIT=", unit);
- m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
-
- (void)(
- /* Look for messages from the service itself */
- (r = sd_journal_add_match(j, m1, 0)) ||
-
- /* Look for coredumps of the service */
- (r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
- (r = sd_journal_add_match(j, "_UID=0", 0)) ||
- (r = sd_journal_add_match(j, m2, 0)) ||
-
- /* Look for messages from PID 1 about this service */
- (r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, "_PID=1", 0)) ||
- (r = sd_journal_add_match(j, m3, 0)) ||
-
- /* Look for messages from authorized daemons about this service */
- (r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, "_UID=0", 0)) ||
- (r = sd_journal_add_match(j, m4, 0))
- );
-
- if (r == 0 && endswith(unit, ".slice")) {
- char *m5 = strappend("_SYSTEMD_SLICE=", unit);
-
- /* Show all messages belonging to a slice */
- (void)(
- (r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, m5, 0))
- );
- }
-
- return r;
-}
-
-int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
- int r;
- char *m1, *m2, *m3, *m4;
- char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
-
- assert(j);
- assert(unit);
-
- m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
- m2 = strjoina("USER_UNIT=", unit);
- m3 = strjoina("COREDUMP_USER_UNIT=", unit);
- m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
- sprintf(muid, "_UID="UID_FMT, uid);
-
- (void) (
- /* Look for messages from the user service itself */
- (r = sd_journal_add_match(j, m1, 0)) ||
- (r = sd_journal_add_match(j, muid, 0)) ||
-
- /* Look for messages from systemd about this service */
- (r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, m2, 0)) ||
- (r = sd_journal_add_match(j, muid, 0)) ||
-
- /* Look for coredumps of the service */
- (r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, m3, 0)) ||
- (r = sd_journal_add_match(j, muid, 0)) ||
- (r = sd_journal_add_match(j, "_UID=0", 0)) ||
-
- /* Look for messages from authorized daemons about this service */
- (r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, m4, 0)) ||
- (r = sd_journal_add_match(j, muid, 0)) ||
- (r = sd_journal_add_match(j, "_UID=0", 0))
- );
-
- if (r == 0 && endswith(unit, ".slice")) {
- char *m5 = strappend("_SYSTEMD_SLICE=", unit);
-
- /* Show all messages belonging to a slice */
- (void)(
- (r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, m5, 0)) ||
- (r = sd_journal_add_match(j, muid, 0))
- );
- }
-
- return r;
-}
-
-static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
- _cleanup_close_pair_ int pair[2] = { -1, -1 };
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
- pid_t pid, child;
- siginfo_t si;
- char buf[37];
- ssize_t k;
- int r;
-
- assert(machine);
- assert(boot_id);
-
- if (!machine_name_is_valid(machine))
- return -EINVAL;
-
- r = container_get_leader(machine, &pid);
- if (r < 0)
- return r;
-
- r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
- if (r < 0)
- return r;
-
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
- return -errno;
-
- child = fork();
- if (child < 0)
- return -errno;
-
- if (child == 0) {
- int fd;
-
- pair[0] = safe_close(pair[0]);
-
- r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
- if (r < 0)
- _exit(EXIT_FAILURE);
-
- fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- _exit(EXIT_FAILURE);
-
- r = loop_read_exact(fd, buf, 36, false);
- safe_close(fd);
- if (r < 0)
- _exit(EXIT_FAILURE);
-
- k = send(pair[1], buf, 36, MSG_NOSIGNAL);
- if (k != 36)
- _exit(EXIT_FAILURE);
-
- _exit(EXIT_SUCCESS);
- }
-
- pair[1] = safe_close(pair[1]);
-
- r = wait_for_terminate(child, &si);
- if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
- return r < 0 ? r : -EIO;
-
- k = recv(pair[0], buf, 36, 0);
- if (k != 36)
- return -EIO;
-
- buf[36] = 0;
- r = sd_id128_from_string(buf, boot_id);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int add_match_this_boot(sd_journal *j, const char *machine) {
- char match[9+32+1] = "_BOOT_ID=";
- sd_id128_t boot_id;
- int r;
-
- assert(j);
-
- if (machine) {
- r = get_boot_id_for_machine(machine, &boot_id);
- if (r < 0)
- return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
- } else {
- r = sd_id128_get_boot(&boot_id);
- if (r < 0)
- return log_error_errno(r, "Failed to get boot id: %m");
- }
-
- sd_id128_to_string(boot_id, match + 9);
- r = sd_journal_add_match(j, match, strlen(match));
- if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
-
- r = sd_journal_add_conjunction(j);
- if (r < 0)
- return log_error_errno(r, "Failed to add conjunction: %m");
-
- return 0;
-}
-
-int show_journal_by_unit(
- FILE *f,
- const char *unit,
- OutputMode mode,
- unsigned n_columns,
- usec_t not_before,
- unsigned how_many,
- uid_t uid,
- OutputFlags flags,
- int journal_open_flags,
- bool system_unit,
- bool *ellipsized) {
-
- _cleanup_journal_close_ sd_journal*j = NULL;
- int r;
-
- assert(mode >= 0);
- assert(mode < _OUTPUT_MODE_MAX);
- assert(unit);
-
- if (how_many <= 0)
- return 0;
-
- r = sd_journal_open(&j, journal_open_flags);
- if (r < 0)
- return log_error_errno(r, "Failed to open journal: %m");
-
- r = add_match_this_boot(j, NULL);
- if (r < 0)
- return r;
-
- if (system_unit)
- r = add_matches_for_unit(j, unit);
- else
- r = add_matches_for_user_unit(j, unit, uid);
- if (r < 0)
- return log_error_errno(r, "Failed to add unit matches: %m");
-
- if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
- _cleanup_free_ char *filter;
-
- filter = journal_make_match_string(j);
- if (!filter)
- return log_oom();
-
- log_debug("Journal filter: %s", filter);
- }
-
- return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
-}
-
-static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
- [OUTPUT_SHORT] = "short",
- [OUTPUT_SHORT_ISO] = "short-iso",
- [OUTPUT_SHORT_PRECISE] = "short-precise",
- [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
- [OUTPUT_VERBOSE] = "verbose",
- [OUTPUT_EXPORT] = "export",
- [OUTPUT_JSON] = "json",
- [OUTPUT_JSON_PRETTY] = "json-pretty",
- [OUTPUT_JSON_SSE] = "json-sse",
- [OUTPUT_CAT] = "cat"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2015 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/prctl.h>
-#include <sys/vfs.h>
-#include <sys/statvfs.h>
-#include <sys/mount.h>
-
-#include "util.h"
-#include "process-util.h"
-#include "lockfile-util.h"
-#include "mkdir.h"
-#include "btrfs-util.h"
-#include "path-util.h"
-#include "signal-util.h"
-#include "machine-pool.h"
-
-#define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL)
-#define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL)
-
-static int check_btrfs(void) {
- struct statfs sfs;
-
- if (statfs("/var/lib/machines", &sfs) < 0) {
- if (errno != ENOENT)
- return -errno;
-
- if (statfs("/var/lib", &sfs) < 0)
- return -errno;
- }
-
- return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
-}
-
-static int setup_machine_raw(uint64_t size, sd_bus_error *error) {
- _cleanup_free_ char *tmp = NULL;
- _cleanup_close_ int fd = -1;
- struct statvfs ss;
- pid_t pid = 0;
- siginfo_t si;
- int r;
-
- /* We want to be able to make use of btrfs-specific file
- * system features, in particular subvolumes, reflinks and
- * quota. Hence, if we detect that /var/lib/machines.raw is
- * not located on btrfs, let's create a loopback file, place a
- * btrfs file system into it, and mount it to
- * /var/lib/machines. */
-
- fd = open("/var/lib/machines.raw", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
- if (fd >= 0) {
- r = fd;
- fd = -1;
- return r;
- }
-
- if (errno != ENOENT)
- return sd_bus_error_set_errnof(error, errno, "Failed to open /var/lib/machines.raw: %m");
-
- r = tempfn_xxxxxx("/var/lib/machines.raw", NULL, &tmp);
- if (r < 0)
- return r;
-
- (void) mkdir_p_label("/var/lib", 0755);
- fd = open(tmp, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600);
- if (fd < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to create /var/lib/machines.raw: %m");
-
- if (fstatvfs(fd, &ss) < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to determine free space on /var/lib/machines.raw: %m");
- goto fail;
- }
-
- if (ss.f_bsize * ss.f_bavail < VAR_LIB_MACHINES_FREE_MIN) {
- r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Not enough free disk space to set up /var/lib/machines.");
- goto fail;
- }
-
- if (ftruncate(fd, size) < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to enlarge /var/lib/machines.raw: %m");
- goto fail;
- }
-
- pid = fork();
- if (pid < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to fork mkfs.btrfs: %m");
- goto fail;
- }
-
- if (pid == 0) {
-
- /* Child */
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
- fd = safe_close(fd);
-
- execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
- if (errno == ENOENT)
- return 99;
-
- _exit(EXIT_FAILURE);
- }
-
- r = wait_for_terminate(pid, &si);
- if (r < 0) {
- sd_bus_error_set_errnof(error, r, "Failed to wait for mkfs.btrfs: %m");
- goto fail;
- }
-
- pid = 0;
-
- if (si.si_code != CLD_EXITED) {
- r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs died abnormally.");
- goto fail;
- }
- if (si.si_status == 99) {
- r = sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing");
- goto fail;
- }
- if (si.si_status != 0) {
- r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs failed with error code %i", si.si_status);
- goto fail;
- }
-
- r = rename_noreplace(AT_FDCWD, tmp, AT_FDCWD, "/var/lib/machines.raw");
- if (r < 0) {
- sd_bus_error_set_errnof(error, r, "Failed to move /var/lib/machines.raw into place: %m");
- goto fail;
- }
-
- r = fd;
- fd = -1;
-
- return r;
-
-fail:
- unlink_noerrno(tmp);
-
- if (pid > 1)
- kill_and_sigcont(pid, SIGKILL);
-
- return r;
-}
-
-int setup_machine_directory(uint64_t size, sd_bus_error *error) {
- _cleanup_release_lock_file_ LockFile lock_file = LOCK_FILE_INIT;
- struct loop_info64 info = {
- .lo_flags = LO_FLAGS_AUTOCLEAR,
- };
- _cleanup_close_ int fd = -1, control = -1, loop = -1;
- _cleanup_free_ char* loopdev = NULL;
- char tmpdir[] = "/tmp/import-mount.XXXXXX", *mntdir = NULL;
- bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false;
- char buf[FORMAT_BYTES_MAX];
- int r, nr = -1;
-
- /* btrfs cannot handle file systems < 16M, hence use this as minimum */
- if (size == (uint64_t) -1)
- size = VAR_LIB_MACHINES_SIZE_START;
- else if (size < 16*1024*1024)
- size = 16*1024*1024;
-
- /* Make sure we only set the directory up once at a time */
- r = make_lock_file("/run/systemd/machines.lock", LOCK_EX, &lock_file);
- if (r < 0)
- return r;
-
- r = check_btrfs();
- if (r < 0)
- return sd_bus_error_set_errnof(error, r, "Failed to determine whether /var/lib/machines is located on btrfs: %m");
- if (r > 0) {
- (void) btrfs_subvol_make_label("/var/lib/machines");
-
- r = btrfs_quota_enable("/var/lib/machines", true);
- if (r < 0)
- log_warning_errno(r, "Failed to enable quota, ignoring: %m");
-
- return 0;
- }
-
- if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0 ||
- dir_is_empty("/var/lib/machines") == 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "/var/lib/machines is not a btrfs file system. Operation is not supported on legacy file systems.");
-
- fd = setup_machine_raw(size, error);
- if (fd < 0)
- return fd;
-
- control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
- if (control < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to open /dev/loop-control: %m");
-
- nr = ioctl(control, LOOP_CTL_GET_FREE);
- if (nr < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to allocate loop device: %m");
-
- if (asprintf(&loopdev, "/dev/loop%i", nr) < 0) {
- r = -ENOMEM;
- goto fail;
- }
-
- loop = open(loopdev, O_CLOEXEC|O_RDWR|O_NOCTTY|O_NONBLOCK);
- if (loop < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to open loopback device: %m");
- goto fail;
- }
-
- if (ioctl(loop, LOOP_SET_FD, fd) < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to bind loopback device: %m");
- goto fail;
- }
-
- if (ioctl(loop, LOOP_SET_STATUS64, &info) < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to enable auto-clear for loopback device: %m");
- goto fail;
- }
-
- /* We need to make sure the new /var/lib/machines directory
- * has an access mode of 0700 at the time it is first made
- * available. mkfs will create it with 0755 however. Hence,
- * let's mount the directory into an inaccessible directory
- * below /tmp first, fix the access mode, and move it to the
- * public place then. */
-
- if (!mkdtemp(tmpdir)) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount parent directory: %m");
- goto fail;
- }
- tmpdir_made = true;
-
- mntdir = strjoina(tmpdir, "/mnt");
- if (mkdir(mntdir, 0700) < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount directory: %m");
- goto fail;
- }
- mntdir_made = true;
-
- if (mount(loopdev, mntdir, "btrfs", 0, NULL) < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to mount loopback device: %m");
- goto fail;
- }
- mntdir_mounted = true;
-
- r = btrfs_quota_enable(mntdir, true);
- if (r < 0)
- log_warning_errno(r, "Failed to enable quota, ignoring: %m");
-
- if (chmod(mntdir, 0700) < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to fix owner: %m");
- goto fail;
- }
-
- (void) mkdir_p_label("/var/lib/machines", 0700);
-
- if (mount(mntdir, "/var/lib/machines", NULL, MS_BIND, NULL) < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to mount directory into right place: %m");
- goto fail;
- }
-
- (void) syncfs(fd);
-
- log_info("Set up /var/lib/machines as btrfs loopback file system of size %s mounted on /var/lib/machines.raw.", format_bytes(buf, sizeof(buf), size));
-
- (void) umount2(mntdir, MNT_DETACH);
- (void) rmdir(mntdir);
- (void) rmdir(tmpdir);
-
- return 0;
-
-fail:
- if (mntdir_mounted)
- (void) umount2(mntdir, MNT_DETACH);
-
- if (mntdir_made)
- (void) rmdir(mntdir);
- if (tmpdir_made)
- (void) rmdir(tmpdir);
-
- if (loop >= 0) {
- (void) ioctl(loop, LOOP_CLR_FD);
- loop = safe_close(loop);
- }
-
- if (control >= 0 && nr >= 0)
- (void) ioctl(control, LOOP_CTL_REMOVE, nr);
-
- return r;
-}
-
-static int sync_path(const char *p) {
- _cleanup_close_ int fd = -1;
-
- fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- return -errno;
-
- if (syncfs(fd) < 0)
- return -errno;
-
- return 0;
-}
-
-int grow_machine_directory(void) {
- char buf[FORMAT_BYTES_MAX];
- struct statvfs a, b;
- uint64_t old_size, new_size, max_add;
- int r;
-
- /* Ensure the disk space data is accurate */
- sync_path("/var/lib/machines");
- sync_path("/var/lib/machines.raw");
-
- if (statvfs("/var/lib/machines.raw", &a) < 0)
- return -errno;
-
- if (statvfs("/var/lib/machines", &b) < 0)
- return -errno;
-
- /* Don't grow if not enough disk space is available on the host */
- if (((uint64_t) a.f_bavail * (uint64_t) a.f_bsize) <= VAR_LIB_MACHINES_FREE_MIN)
- return 0;
-
- /* Don't grow if at least 1/3th of the fs is still free */
- if (b.f_bavail > b.f_blocks / 3)
- return 0;
-
- /* Calculate how much we are willing to add at maximum */
- max_add = ((uint64_t) a.f_bavail * (uint64_t) a.f_bsize) - VAR_LIB_MACHINES_FREE_MIN;
-
- /* Calculate the old size */
- old_size = (uint64_t) b.f_blocks * (uint64_t) b.f_bsize;
-
- /* Calculate the new size as three times the size of what is used right now */
- new_size = ((uint64_t) b.f_blocks - (uint64_t) b.f_bavail) * (uint64_t) b.f_bsize * 3;
-
- /* Always, grow at least to the start size */
- if (new_size < VAR_LIB_MACHINES_SIZE_START)
- new_size = VAR_LIB_MACHINES_SIZE_START;
-
- /* If the new size is smaller than the old size, don't grow */
- if (new_size < old_size)
- return 0;
-
- /* Ensure we never add more than the maximum */
- if (new_size > old_size + max_add)
- new_size = old_size + max_add;
-
- r = btrfs_resize_loopback("/var/lib/machines", new_size, true);
- if (r <= 0)
- return r;
-
- r = btrfs_quota_limit("/var/lib/machines", new_size);
- if (r < 0)
- return r;
-
- log_info("Grew /var/lib/machines btrfs loopback file system to %s.", format_bytes(buf, sizeof(buf), new_size));
- return 1;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <nss.h>
-#include <netdb.h>
-#include <resolv.h>
-#include <pwd.h>
-#include <grp.h>
-
-
-#define NSS_GETHOSTBYNAME_PROTOTYPES(module) \
-enum nss_status _nss_##module##_gethostbyname4_r( \
- const char *name, \
- struct gaih_addrtuple **pat, \
- char *buffer, size_t buflen, \
- int *errnop, int *h_errnop, \
- int32_t *ttlp) _public_; \
-enum nss_status _nss_##module##_gethostbyname3_r( \
- const char *name, \
- int af, \
- struct hostent *host, \
- char *buffer, size_t buflen, \
- int *errnop, int *h_errnop, \
- int32_t *ttlp, \
- char **canonp) _public_; \
-enum nss_status _nss_##module##_gethostbyname2_r( \
- const char *name, \
- int af, \
- struct hostent *host, \
- char *buffer, size_t buflen, \
- int *errnop, int *h_errnop) _public_; \
-enum nss_status _nss_##module##_gethostbyname_r( \
- const char *name, \
- struct hostent *host, \
- char *buffer, size_t buflen, \
- int *errnop, int *h_errnop) _public_
-
-#define NSS_GETHOSTBYADDR_PROTOTYPES(module) \
-enum nss_status _nss_##module##_gethostbyaddr2_r( \
- const void* addr, socklen_t len, \
- int af, \
- struct hostent *host, \
- char *buffer, size_t buflen, \
- int *errnop, int *h_errnop, \
- int32_t *ttlp) _public_; \
-enum nss_status _nss_##module##_gethostbyaddr_r( \
- const void* addr, socklen_t len, \
- int af, \
- struct hostent *host, \
- char *buffer, size_t buflen, \
- int *errnop, int *h_errnop) _public_
-
-#define NSS_GETHOSTBYNAME_FALLBACKS(module) \
-enum nss_status _nss_##module##_gethostbyname2_r( \
- const char *name, \
- int af, \
- struct hostent *host, \
- char *buffer, size_t buflen, \
- int *errnop, int *h_errnop) { \
- return _nss_##module##_gethostbyname3_r( \
- name, \
- af, \
- host, \
- buffer, buflen, \
- errnop, h_errnop, \
- NULL, \
- NULL); \
-} \
-enum nss_status _nss_##module##_gethostbyname_r( \
- const char *name, \
- struct hostent *host, \
- char *buffer, size_t buflen, \
- int *errnop, int *h_errnop) { \
- enum nss_status ret = NSS_STATUS_NOTFOUND; \
- \
- if (_res.options & RES_USE_INET6) \
- ret = _nss_##module##_gethostbyname3_r( \
- name, \
- AF_INET6, \
- host, \
- buffer, buflen, \
- errnop, h_errnop, \
- NULL, \
- NULL); \
- if (ret == NSS_STATUS_NOTFOUND) \
- ret = _nss_##module##_gethostbyname3_r( \
- name, \
- AF_INET, \
- host, \
- buffer, buflen, \
- errnop, h_errnop, \
- NULL, \
- NULL); \
- return ret; \
-} \
-struct __useless_struct_to_allow_trailing_semicolon__
-
-#define NSS_GETHOSTBYADDR_FALLBACKS(module) \
-enum nss_status _nss_##module##_gethostbyaddr_r( \
- const void* addr, socklen_t len, \
- int af, \
- struct hostent *host, \
- char *buffer, size_t buflen, \
- int *errnop, int *h_errnop) { \
- return _nss_##module##_gethostbyaddr2_r( \
- addr, len, \
- af, \
- host, \
- buffer, buflen, \
- errnop, h_errnop, \
- NULL); \
-} \
-struct __useless_struct_to_allow_trailing_semicolon__
-
-#define NSS_GETPW_PROTOTYPES(module) \
-enum nss_status _nss_##module##_getpwnam_r( \
- const char *name, \
- struct passwd *pwd, \
- char *buffer, size_t buflen, \
- int *errnop) _public_; \
-enum nss_status _nss_mymachines_getpwuid_r( \
- uid_t uid, \
- struct passwd *pwd, \
- char *buffer, size_t buflen, \
- int *errnop) _public_
-
-#define NSS_GETGR_PROTOTYPES(module) \
-enum nss_status _nss_##module##_getgrnam_r( \
- const char *name, \
- struct group *gr, \
- char *buffer, size_t buflen, \
- int *errnop) _public_; \
-enum nss_status _nss_##module##_getgrgid_r( \
- gid_t gid, \
- struct group *gr, \
- char *buffer, size_t buflen, \
- int *errnop) _public_
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <stddef.h>
-
-#include "macro.h"
-#include "util.h"
-#include "mkdir.h"
-#include "missing.h"
-#include "selinux-util.h"
-#include "socket-util.h"
-
-int socket_address_listen(
- const SocketAddress *a,
- int flags,
- int backlog,
- SocketAddressBindIPv6Only only,
- const char *bind_to_device,
- bool reuse_port,
- bool free_bind,
- bool transparent,
- mode_t directory_mode,
- mode_t socket_mode,
- const char *label) {
-
- _cleanup_close_ int fd = -1;
- int r, one;
-
- assert(a);
-
- r = socket_address_verify(a);
- if (r < 0)
- return r;
-
- if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
- return -EAFNOSUPPORT;
-
- if (label) {
- r = mac_selinux_create_socket_prepare(label);
- if (r < 0)
- return r;
- }
-
- fd = socket(socket_address_family(a), a->type | flags, a->protocol);
- r = fd < 0 ? -errno : 0;
-
- if (label)
- mac_selinux_create_socket_clear();
-
- if (r < 0)
- return r;
-
- if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
- int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
-
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
- return -errno;
- }
-
- if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
- if (bind_to_device)
- if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
- return -errno;
-
- if (reuse_port) {
- one = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
- log_warning_errno(errno, "SO_REUSEPORT failed: %m");
- }
-
- if (free_bind) {
- one = 1;
- if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
- log_warning_errno(errno, "IP_FREEBIND failed: %m");
- }
-
- if (transparent) {
- one = 1;
- if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
- log_warning_errno(errno, "IP_TRANSPARENT failed: %m");
- }
- }
-
- one = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
- return -errno;
-
- if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
- mode_t old_mask;
-
- /* Create parents */
- mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);
-
- /* Enforce the right access mode for the socket */
- old_mask = umask(~ socket_mode);
-
- r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
-
- if (r < 0 && errno == EADDRINUSE) {
- /* Unlink and try again */
- unlink(a->sockaddr.un.sun_path);
- r = bind(fd, &a->sockaddr.sa, a->size);
- }
-
- umask(old_mask);
- } else
- r = bind(fd, &a->sockaddr.sa, a->size);
-
- if (r < 0)
- return -errno;
-
- if (socket_address_can_accept(a))
- if (listen(fd, backlog) < 0)
- return -errno;
-
- r = fd;
- fd = -1;
-
- return r;
-}
-
-int make_socket_fd(int log_level, const char* address, int flags) {
- SocketAddress a;
- int fd, r;
-
- r = socket_address_parse(&a, address);
- if (r < 0) {
- log_error("Failed to parse socket address \"%s\": %s",
- address, strerror(-r));
- return r;
- }
-
- fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
- NULL, false, false, false, 0755, 0644, NULL);
- if (fd < 0 || log_get_max_level() >= log_level) {
- _cleanup_free_ char *p = NULL;
-
- r = socket_address_print(&a, &p);
- if (r < 0)
- return log_error_errno(r, "socket_address_print(): %m");
-
- if (fd < 0)
- log_error_errno(fd, "Failed to listen on %s: %m", p);
- else
- log_full(log_level, "Listening on %s", p);
- }
-
- return fd;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <net/if.h>
-#include <sys/types.h>
-#include <stddef.h>
-#include <netdb.h>
-
-#include "macro.h"
-#include "path-util.h"
-#include "util.h"
-#include "socket-util.h"
-#include "missing.h"
-#include "fileio.h"
-#include "formats-util.h"
-
-int socket_address_parse(SocketAddress *a, const char *s) {
- char *e, *n;
- unsigned u;
- int r;
-
- assert(a);
- assert(s);
-
- zero(*a);
- a->type = SOCK_STREAM;
-
- if (*s == '[') {
- /* IPv6 in [x:.....:z]:p notation */
-
- e = strchr(s+1, ']');
- if (!e)
- return -EINVAL;
-
- n = strndupa(s+1, e-s-1);
-
- errno = 0;
- if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
- return errno > 0 ? -errno : -EINVAL;
-
- e++;
- if (*e != ':')
- return -EINVAL;
-
- e++;
- r = safe_atou(e, &u);
- if (r < 0)
- return r;
-
- if (u <= 0 || u > 0xFFFF)
- return -EINVAL;
-
- a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htons((uint16_t) u);
- a->size = sizeof(struct sockaddr_in6);
-
- } else if (*s == '/') {
- /* AF_UNIX socket */
-
- size_t l;
-
- l = strlen(s);
- if (l >= sizeof(a->sockaddr.un.sun_path))
- return -EINVAL;
-
- a->sockaddr.un.sun_family = AF_UNIX;
- memcpy(a->sockaddr.un.sun_path, s, l);
- a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
-
- } else if (*s == '@') {
- /* Abstract AF_UNIX socket */
- size_t l;
-
- l = strlen(s+1);
- if (l >= sizeof(a->sockaddr.un.sun_path) - 1)
- return -EINVAL;
-
- a->sockaddr.un.sun_family = AF_UNIX;
- memcpy(a->sockaddr.un.sun_path+1, s+1, l);
- a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
-
- } else {
- e = strchr(s, ':');
- if (e) {
- r = safe_atou(e+1, &u);
- if (r < 0)
- return r;
-
- if (u <= 0 || u > 0xFFFF)
- return -EINVAL;
-
- n = strndupa(s, e-s);
-
- /* IPv4 in w.x.y.z:p notation? */
- r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
- if (r < 0)
- return -errno;
-
- if (r > 0) {
- /* Gotcha, it's a traditional IPv4 address */
- a->sockaddr.in.sin_family = AF_INET;
- a->sockaddr.in.sin_port = htons((uint16_t) u);
- a->size = sizeof(struct sockaddr_in);
- } else {
- unsigned idx;
-
- if (strlen(n) > IF_NAMESIZE-1)
- return -EINVAL;
-
- /* Uh, our last resort, an interface name */
- idx = if_nametoindex(n);
- if (idx == 0)
- return -EINVAL;
-
- a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htons((uint16_t) u);
- a->sockaddr.in6.sin6_scope_id = idx;
- a->sockaddr.in6.sin6_addr = in6addr_any;
- a->size = sizeof(struct sockaddr_in6);
- }
- } else {
-
- /* Just a port */
- r = safe_atou(s, &u);
- if (r < 0)
- return r;
-
- if (u <= 0 || u > 0xFFFF)
- return -EINVAL;
-
- if (socket_ipv6_is_supported()) {
- a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htons((uint16_t) u);
- a->sockaddr.in6.sin6_addr = in6addr_any;
- a->size = sizeof(struct sockaddr_in6);
- } else {
- a->sockaddr.in.sin_family = AF_INET;
- a->sockaddr.in.sin_port = htons((uint16_t) u);
- a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
- a->size = sizeof(struct sockaddr_in);
- }
- }
- }
-
- return 0;
-}
-
-int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
- SocketAddress b;
- int r;
-
- /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
-
- r = socket_address_parse(&b, s);
- if (r < 0)
- return r;
-
- if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
- log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
- return -EAFNOSUPPORT;
- }
-
- *a = b;
- return 0;
-}
-
-int socket_address_parse_netlink(SocketAddress *a, const char *s) {
- int family;
- unsigned group = 0;
- _cleanup_free_ char *sfamily = NULL;
- assert(a);
- assert(s);
-
- zero(*a);
- a->type = SOCK_RAW;
-
- errno = 0;
- if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
- return errno > 0 ? -errno : -EINVAL;
-
- family = netlink_family_from_string(sfamily);
- if (family < 0)
- return -EINVAL;
-
- a->sockaddr.nl.nl_family = AF_NETLINK;
- a->sockaddr.nl.nl_groups = group;
-
- a->type = SOCK_RAW;
- a->size = sizeof(struct sockaddr_nl);
- a->protocol = family;
-
- return 0;
-}
-
-int socket_address_verify(const SocketAddress *a) {
- assert(a);
-
- switch (socket_address_family(a)) {
-
- case AF_INET:
- if (a->size != sizeof(struct sockaddr_in))
- return -EINVAL;
-
- if (a->sockaddr.in.sin_port == 0)
- return -EINVAL;
-
- if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
- return -EINVAL;
-
- return 0;
-
- case AF_INET6:
- if (a->size != sizeof(struct sockaddr_in6))
- return -EINVAL;
-
- if (a->sockaddr.in6.sin6_port == 0)
- return -EINVAL;
-
- if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
- return -EINVAL;
-
- return 0;
-
- case AF_UNIX:
- if (a->size < offsetof(struct sockaddr_un, sun_path))
- return -EINVAL;
-
- if (a->size > offsetof(struct sockaddr_un, sun_path)) {
-
- if (a->sockaddr.un.sun_path[0] != 0) {
- char *e;
-
- /* path */
- e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
- if (!e)
- return -EINVAL;
-
- if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
- return -EINVAL;
- }
- }
-
- if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
- return -EINVAL;
-
- return 0;
-
- case AF_NETLINK:
-
- if (a->size != sizeof(struct sockaddr_nl))
- return -EINVAL;
-
- if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
- return -EINVAL;
-
- return 0;
-
- default:
- return -EAFNOSUPPORT;
- }
-}
-
-int socket_address_print(const SocketAddress *a, char **ret) {
- int r;
-
- assert(a);
- assert(ret);
-
- r = socket_address_verify(a);
- if (r < 0)
- return r;
-
- if (socket_address_family(a) == AF_NETLINK) {
- _cleanup_free_ char *sfamily = NULL;
-
- r = netlink_family_to_string_alloc(a->protocol, &sfamily);
- if (r < 0)
- return r;
-
- r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
- if (r < 0)
- return -ENOMEM;
-
- return 0;
- }
-
- return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, ret);
-}
-
-bool socket_address_can_accept(const SocketAddress *a) {
- assert(a);
-
- return
- a->type == SOCK_STREAM ||
- a->type == SOCK_SEQPACKET;
-}
-
-bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
- assert(a);
- assert(b);
-
- /* Invalid addresses are unequal to all */
- if (socket_address_verify(a) < 0 ||
- socket_address_verify(b) < 0)
- return false;
-
- if (a->type != b->type)
- return false;
-
- if (socket_address_family(a) != socket_address_family(b))
- return false;
-
- switch (socket_address_family(a)) {
-
- case AF_INET:
- if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
- return false;
-
- if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
- return false;
-
- break;
-
- case AF_INET6:
- if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
- return false;
-
- if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
- return false;
-
- break;
-
- case AF_UNIX:
- if (a->size <= offsetof(struct sockaddr_un, sun_path) ||
- b->size <= offsetof(struct sockaddr_un, sun_path))
- return false;
-
- if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
- return false;
-
- if (a->sockaddr.un.sun_path[0]) {
- if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
- return false;
- } else {
- if (a->size != b->size)
- return false;
-
- if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
- return false;
- }
-
- break;
-
- case AF_NETLINK:
- if (a->protocol != b->protocol)
- return false;
-
- if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
- return false;
-
- break;
-
- default:
- /* Cannot compare, so we assume the addresses are different */
- return false;
- }
-
- return true;
-}
-
-bool socket_address_is(const SocketAddress *a, const char *s, int type) {
- struct SocketAddress b;
-
- assert(a);
- assert(s);
-
- if (socket_address_parse(&b, s) < 0)
- return false;
-
- b.type = type;
-
- return socket_address_equal(a, &b);
-}
-
-bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
- struct SocketAddress b;
-
- assert(a);
- assert(s);
-
- if (socket_address_parse_netlink(&b, s) < 0)
- return false;
-
- return socket_address_equal(a, &b);
-}
-
-const char* socket_address_get_path(const SocketAddress *a) {
- assert(a);
-
- if (socket_address_family(a) != AF_UNIX)
- return NULL;
-
- if (a->sockaddr.un.sun_path[0] == 0)
- return NULL;
-
- return a->sockaddr.un.sun_path;
-}
-
-bool socket_ipv6_is_supported(void) {
- _cleanup_free_ char *l = NULL;
-
- if (access("/sys/module/ipv6", F_OK) != 0)
- return false;
-
- /* If we can't check "disable" parameter, assume enabled */
- if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0)
- return true;
-
- /* If module was loaded with disable=1 no IPv6 available */
- return l[0] == '0';
-}
-
-bool socket_address_matches_fd(const SocketAddress *a, int fd) {
- SocketAddress b;
- socklen_t solen;
-
- assert(a);
- assert(fd >= 0);
-
- b.size = sizeof(b.sockaddr);
- if (getsockname(fd, &b.sockaddr.sa, &b.size) < 0)
- return false;
-
- if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family)
- return false;
-
- solen = sizeof(b.type);
- if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0)
- return false;
-
- if (b.type != a->type)
- return false;
-
- if (a->protocol != 0) {
- solen = sizeof(b.protocol);
- if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0)
- return false;
-
- if (b.protocol != a->protocol)
- return false;
- }
-
- return socket_address_equal(a, &b);
-}
-
-int sockaddr_port(const struct sockaddr *_sa) {
- union sockaddr_union *sa = (union sockaddr_union*) _sa;
-
- assert(sa);
-
- if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6))
- return -EAFNOSUPPORT;
-
- return ntohs(sa->sa.sa_family == AF_INET6 ?
- sa->in6.sin6_port :
- sa->in.sin_port);
-}
-
-int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) {
- union sockaddr_union *sa = (union sockaddr_union*) _sa;
- char *p;
- int r;
-
- assert(sa);
- assert(salen >= sizeof(sa->sa.sa_family));
-
- switch (sa->sa.sa_family) {
-
- case AF_INET: {
- uint32_t a;
-
- a = ntohl(sa->in.sin_addr.s_addr);
-
- if (include_port)
- r = asprintf(&p,
- "%u.%u.%u.%u:%u",
- a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
- ntohs(sa->in.sin_port));
- else
- r = asprintf(&p,
- "%u.%u.%u.%u",
- a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF);
- if (r < 0)
- return -ENOMEM;
- break;
- }
-
- case AF_INET6: {
- static const unsigned char ipv4_prefix[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
- };
-
- if (translate_ipv6 &&
- memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
- const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
- if (include_port)
- r = asprintf(&p,
- "%u.%u.%u.%u:%u",
- a[0], a[1], a[2], a[3],
- ntohs(sa->in6.sin6_port));
- else
- r = asprintf(&p,
- "%u.%u.%u.%u",
- a[0], a[1], a[2], a[3]);
- if (r < 0)
- return -ENOMEM;
- } else {
- char a[INET6_ADDRSTRLEN];
-
- inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
-
- if (include_port) {
- r = asprintf(&p,
- "[%s]:%u",
- a,
- ntohs(sa->in6.sin6_port));
- if (r < 0)
- return -ENOMEM;
- } else {
- p = strdup(a);
- if (!p)
- return -ENOMEM;
- }
- }
-
- break;
- }
-
- case AF_UNIX:
- if (salen <= offsetof(struct sockaddr_un, sun_path)) {
- p = strdup("<unnamed>");
- if (!p)
- return -ENOMEM;
-
- } else if (sa->un.sun_path[0] == 0) {
- /* abstract */
-
- /* FIXME: We assume we can print the
- * socket path here and that it hasn't
- * more than one NUL byte. That is
- * actually an invalid assumption */
-
- p = new(char, sizeof(sa->un.sun_path)+1);
- if (!p)
- return -ENOMEM;
-
- p[0] = '@';
- memcpy(p+1, sa->un.sun_path+1, sizeof(sa->un.sun_path)-1);
- p[sizeof(sa->un.sun_path)] = 0;
-
- } else {
- p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path));
- if (!ret)
- return -ENOMEM;
- }
-
- break;
-
- default:
- return -EOPNOTSUPP;
- }
-
-
- *ret = p;
- return 0;
-}
-
-int getpeername_pretty(int fd, char **ret) {
- union sockaddr_union sa;
- socklen_t salen = sizeof(sa);
- int r;
-
- assert(fd >= 0);
- assert(ret);
-
- if (getpeername(fd, &sa.sa, &salen) < 0)
- return -errno;
-
- if (sa.sa.sa_family == AF_UNIX) {
- struct ucred ucred = {};
-
- /* UNIX connection sockets are anonymous, so let's use
- * PID/UID as pretty credentials instead */
-
- r = getpeercred(fd, &ucred);
- if (r < 0)
- return r;
-
- if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
- return -ENOMEM;
-
- return 0;
- }
-
- /* For remote sockets we translate IPv6 addresses back to IPv4
- * if applicable, since that's nicer. */
-
- return sockaddr_pretty(&sa.sa, salen, true, true, ret);
-}
-
-int getsockname_pretty(int fd, char **ret) {
- union sockaddr_union sa;
- socklen_t salen = sizeof(sa);
-
- assert(fd >= 0);
- assert(ret);
-
- if (getsockname(fd, &sa.sa, &salen) < 0)
- return -errno;
-
- /* For local sockets we do not translate IPv6 addresses back
- * to IPv6 if applicable, since this is usually used for
- * listening sockets where the difference between IPv4 and
- * IPv6 matters. */
-
- return sockaddr_pretty(&sa.sa, salen, false, true, ret);
-}
-
-int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
- int r;
- char host[NI_MAXHOST], *ret;
-
- assert(_ret);
-
- r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
- NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
- if (r != 0) {
- int saved_errno = errno;
-
- r = sockaddr_pretty(&sa->sa, salen, true, true, &ret);
- if (r < 0)
- return r;
-
- log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
- } else {
- ret = strdup(host);
- if (!ret)
- return -ENOMEM;
- }
-
- *_ret = ret;
- return 0;
-}
-
-int getnameinfo_pretty(int fd, char **ret) {
- union sockaddr_union sa;
- socklen_t salen = sizeof(sa);
-
- assert(fd >= 0);
- assert(ret);
-
- if (getsockname(fd, &sa.sa, &salen) < 0)
- return -errno;
-
- return socknameinfo_pretty(&sa, salen, ret);
-}
-
-int socket_address_unlink(SocketAddress *a) {
- assert(a);
-
- if (socket_address_family(a) != AF_UNIX)
- return 0;
-
- if (a->sockaddr.un.sun_path[0] == 0)
- return 0;
-
- if (unlink(a->sockaddr.un.sun_path) < 0)
- return -errno;
-
- return 1;
-}
-
-static const char* const netlink_family_table[] = {
- [NETLINK_ROUTE] = "route",
- [NETLINK_FIREWALL] = "firewall",
- [NETLINK_INET_DIAG] = "inet-diag",
- [NETLINK_NFLOG] = "nflog",
- [NETLINK_XFRM] = "xfrm",
- [NETLINK_SELINUX] = "selinux",
- [NETLINK_ISCSI] = "iscsi",
- [NETLINK_AUDIT] = "audit",
- [NETLINK_FIB_LOOKUP] = "fib-lookup",
- [NETLINK_CONNECTOR] = "connector",
- [NETLINK_NETFILTER] = "netfilter",
- [NETLINK_IP6_FW] = "ip6-fw",
- [NETLINK_DNRTMSG] = "dnrtmsg",
- [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
- [NETLINK_GENERIC] = "generic",
- [NETLINK_SCSITRANSPORT] = "scsitransport",
- [NETLINK_ECRYPTFS] = "ecryptfs"
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
-
-static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
- [SOCKET_ADDRESS_DEFAULT] = "default",
- [SOCKET_ADDRESS_BOTH] = "both",
- [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
-
-bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
- assert(a);
- assert(b);
-
- if (a->sa.sa_family != b->sa.sa_family)
- return false;
-
- if (a->sa.sa_family == AF_INET)
- return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
-
- if (a->sa.sa_family == AF_INET6)
- return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
-
- return false;
-}
-
-char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
- assert(addr);
- assert(buffer);
-
- /* Like ether_ntoa() but uses %02x instead of %x to print
- * ethernet addresses, which makes them look less funny. Also,
- * doesn't use a static buffer. */
-
- sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
- addr->ether_addr_octet[0],
- addr->ether_addr_octet[1],
- addr->ether_addr_octet[2],
- addr->ether_addr_octet[3],
- addr->ether_addr_octet[4],
- addr->ether_addr_octet[5]);
-
- return buffer;
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
-#include <getopt.h>
-
-#include "log.h"
-#include "util.h"
-#include "fileio.h"
-#include "build.h"
-#include "sysctl-util.h"
-
-char *sysctl_normalize(char *s) {
- char *n;
-
- n = strpbrk(s, "/.");
- /* If the first separator is a slash, the path is
- * assumed to be normalized and slashes remain slashes
- * and dots remains dots. */
- if (!n || *n == '/')
- return s;
-
- /* Otherwise, dots become slashes and slashes become
- * dots. Fun. */
- while (n) {
- if (*n == '.')
- *n = '/';
- else
- *n = '.';
-
- n = strpbrk(n + 1, "/.");
- }
-
- return s;
-}
-
-int sysctl_write(const char *property, const char *value) {
- char *p;
-
- assert(property);
- assert(value);
-
- log_debug("Setting '%s' to '%s'", property, value);
-
- p = strjoina("/proc/sys/", property);
- return write_string_file(p, value, 0);
-}
-
-int sysctl_read(const char *property, char **content) {
- char *p;
-
- assert(property);
- assert(content);
-
- p = strjoina("/proc/sys/", property);
- return read_full_file(p, content, NULL);
-}
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <utmpx.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/utsname.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <poll.h>
-
-#include "macro.h"
-#include "path-util.h"
-#include "terminal-util.h"
-#include "hostname-util.h"
-#include "utmp-wtmp.h"
-
-int utmp_get_runlevel(int *runlevel, int *previous) {
- struct utmpx *found, lookup = { .ut_type = RUN_LVL };
- int r;
- const char *e;
-
- assert(runlevel);
-
- /* If these values are set in the environment this takes
- * precedence. Presumably, sysvinit does this to work around a
- * race condition that would otherwise exist where we'd always
- * go to disk and hence might read runlevel data that might be
- * very new and does not apply to the current script being
- * executed. */
-
- e = getenv("RUNLEVEL");
- if (e && e[0] > 0) {
- *runlevel = e[0];
-
- if (previous) {
- /* $PREVLEVEL seems to be an Upstart thing */
-
- e = getenv("PREVLEVEL");
- if (e && e[0] > 0)
- *previous = e[0];
- else
- *previous = 0;
- }
-
- return 0;
- }
-
- if (utmpxname(_PATH_UTMPX) < 0)
- return -errno;
-
- setutxent();
-
- found = getutxid(&lookup);
- if (!found)
- r = -errno;
- else {
- int a, b;
-
- a = found->ut_pid & 0xFF;
- b = (found->ut_pid >> 8) & 0xFF;
-
- *runlevel = a;
- if (previous)
- *previous = b;
-
- r = 0;
- }
-
- endutxent();
-
- return r;
-}
-
-static void init_timestamp(struct utmpx *store, usec_t t) {
- assert(store);
-
- if (t <= 0)
- t = now(CLOCK_REALTIME);
-
- store->ut_tv.tv_sec = t / USEC_PER_SEC;
- store->ut_tv.tv_usec = t % USEC_PER_SEC;
-}
-
-static void init_entry(struct utmpx *store, usec_t t) {
- struct utsname uts = {};
-
- assert(store);
-
- init_timestamp(store, t);
-
- if (uname(&uts) >= 0)
- strncpy(store->ut_host, uts.release, sizeof(store->ut_host));
-
- strncpy(store->ut_line, "~", sizeof(store->ut_line)); /* or ~~ ? */
- strncpy(store->ut_id, "~~", sizeof(store->ut_id));
-}
-
-static int write_entry_utmp(const struct utmpx *store) {
- int r;
-
- assert(store);
-
- /* utmp is similar to wtmp, but there is only one entry for
- * each entry type resp. user; i.e. basically a key/value
- * table. */
-
- if (utmpxname(_PATH_UTMPX) < 0)
- return -errno;
-
- setutxent();
-
- if (!pututxline(store))
- r = -errno;
- else
- r = 0;
-
- endutxent();
-
- return r;
-}
-
-static int write_entry_wtmp(const struct utmpx *store) {
- assert(store);
-
- /* wtmp is a simple append-only file where each entry is
- simply appended to the end; i.e. basically a log. */
-
- errno = 0;
- updwtmpx(_PATH_WTMPX, store);
- return -errno;
-}
-
-static int write_utmp_wtmp(const struct utmpx *store_utmp, const struct utmpx *store_wtmp) {
- int r, s;
-
- r = write_entry_utmp(store_utmp);
- s = write_entry_wtmp(store_wtmp);
-
- if (r >= 0)
- r = s;
-
- /* If utmp/wtmp have been disabled, that's a good thing, hence
- * ignore the errors */
- if (r == -ENOENT)
- r = 0;
-
- return r;
-}
-
-static int write_entry_both(const struct utmpx *store) {
- return write_utmp_wtmp(store, store);
-}
-
-int utmp_put_shutdown(void) {
- struct utmpx store = {};
-
- init_entry(&store, 0);
-
- store.ut_type = RUN_LVL;
- strncpy(store.ut_user, "shutdown", sizeof(store.ut_user));
-
- return write_entry_both(&store);
-}
-
-int utmp_put_reboot(usec_t t) {
- struct utmpx store = {};
-
- init_entry(&store, t);
-
- store.ut_type = BOOT_TIME;
- strncpy(store.ut_user, "reboot", sizeof(store.ut_user));
-
- return write_entry_both(&store);
-}
-
-_pure_ static const char *sanitize_id(const char *id) {
- size_t l;
-
- assert(id);
- l = strlen(id);
-
- if (l <= sizeof(((struct utmpx*) NULL)->ut_id))
- return id;
-
- return id + l - sizeof(((struct utmpx*) NULL)->ut_id);
-}
-
-int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line) {
- struct utmpx store = {
- .ut_type = INIT_PROCESS,
- .ut_pid = pid,
- .ut_session = sid,
- };
-
- assert(id);
-
- init_timestamp(&store, 0);
-
- /* ut_id needs only be nul-terminated if it is shorter than sizeof(ut_id) */
- strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id));
-
- if (line)
- strncpy(store.ut_line, basename(line), sizeof(store.ut_line));
-
- return write_entry_both(&store);
-}
-
-int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
- struct utmpx lookup = {
- .ut_type = INIT_PROCESS /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */
- }, store, store_wtmp, *found;
-
- assert(id);
-
- setutxent();
-
- /* ut_id needs only be nul-terminated if it is shorter than sizeof(ut_id) */
- strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id));
-
- found = getutxid(&lookup);
- if (!found)
- return 0;
-
- if (found->ut_pid != pid)
- return 0;
-
- memcpy(&store, found, sizeof(store));
- store.ut_type = DEAD_PROCESS;
- store.ut_exit.e_termination = code;
- store.ut_exit.e_exit = status;
-
- zero(store.ut_user);
- zero(store.ut_host);
- zero(store.ut_tv);
-
- memcpy(&store_wtmp, &store, sizeof(store_wtmp));
- /* wtmp wants the current time */
- init_timestamp(&store_wtmp, 0);
-
- return write_utmp_wtmp(&store, &store_wtmp);
-}
-
-
-int utmp_put_runlevel(int runlevel, int previous) {
- struct utmpx store = {};
- int r;
-
- assert(runlevel > 0);
-
- if (previous <= 0) {
- /* Find the old runlevel automatically */
-
- r = utmp_get_runlevel(&previous, NULL);
- if (r < 0) {
- if (r != -ESRCH)
- return r;
-
- previous = 0;
- }
- }
-
- if (previous == runlevel)
- return 0;
-
- init_entry(&store, 0);
-
- store.ut_type = RUN_LVL;
- store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8);
- strncpy(store.ut_user, "runlevel", sizeof(store.ut_user));
-
- return write_entry_both(&store);
-}
-
-#define TIMEOUT_MSEC 50
-
-static int write_to_terminal(const char *tty, const char *message) {
- _cleanup_close_ int fd = -1;
- const char *p;
- size_t left;
- usec_t end;
-
- assert(tty);
- assert(message);
-
- fd = open(tty, O_WRONLY|O_NDELAY|O_NOCTTY|O_CLOEXEC);
- if (fd < 0 || !isatty(fd))
- return -errno;
-
- p = message;
- left = strlen(message);
-
- end = now(CLOCK_MONOTONIC) + TIMEOUT_MSEC*USEC_PER_MSEC;
-
- while (left > 0) {
- ssize_t n;
- struct pollfd pollfd = {
- .fd = fd,
- .events = POLLOUT,
- };
- usec_t t;
- int k;
-
- t = now(CLOCK_MONOTONIC);
-
- if (t >= end)
- return -ETIME;
-
- k = poll(&pollfd, 1, (end - t) / USEC_PER_MSEC);
- if (k < 0)
- return -errno;
-
- if (k == 0)
- return -ETIME;
-
- n = write(fd, p, left);
- if (n < 0) {
- if (errno == EAGAIN)
- continue;
-
- return -errno;
- }
-
- assert((size_t) n <= left);
-
- p += n;
- left -= n;
- }
-
- return 0;
-}
-
-int utmp_wall(const char *message, const char *username, bool (*match_tty)(const char *tty)) {
- _cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *tty = NULL;
- char date[FORMAT_TIMESTAMP_MAX];
- struct utmpx *u;
- int r;
-
- hn = gethostname_malloc();
- if (!hn)
- return -ENOMEM;
- if (!username) {
- un = getlogname_malloc();
- if (!un)
- return -ENOMEM;
- }
-
- getttyname_harder(STDIN_FILENO, &tty);
-
- if (asprintf(&text,
- "\a\r\n"
- "Broadcast message from %s@%s%s%s (%s):\r\n\r\n"
- "%s\r\n\r\n",
- un ?: username, hn,
- tty ? " on " : "", strempty(tty),
- format_timestamp(date, sizeof(date), now(CLOCK_REALTIME)),
- message) < 0)
- return -ENOMEM;
-
- setutxent();
-
- r = 0;
-
- while ((u = getutxent())) {
- _cleanup_free_ char *buf = NULL;
- const char *path;
- int q;
-
- if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
- continue;
-
- /* this access is fine, because strlen("/dev/") << 32 (UT_LINESIZE) */
- if (path_startswith(u->ut_line, "/dev/"))
- path = u->ut_line;
- else {
- if (asprintf(&buf, "/dev/%.*s", (int) sizeof(u->ut_line), u->ut_line) < 0)
- return -ENOMEM;
-
- path = buf;
- }
-
- if (!match_tty || match_tty(path)) {
- q = write_to_terminal(path, text);
- if (q < 0)
- r = q;
- }
- }
-
- return r;
-}
--- /dev/null
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+
+#ifdef HAVE_UTMP
+int utmp_get_runlevel(int *runlevel, int *previous);
+
+int utmp_put_shutdown(void);
+int utmp_put_reboot(usec_t timestamp);
+int utmp_put_runlevel(int runlevel, int previous);
+
+int utmp_put_dead_process(const char *id, pid_t pid, int code, int status);
+int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line, int ut_type, const char *user);
+
+int utmp_wall(
+ const char *message,
+ const char *username,
+ const char *origin_tty,
+ bool (*match_tty)(const char *tty, void *userdata),
+ void *userdata);
+
+#else /* HAVE_UTMP */
+
+static inline int utmp_get_runlevel(int *runlevel, int *previous) {
+ return -ESRCH;
+}
+static inline int utmp_put_shutdown(void) {
+ return 0;
+}
+static inline int utmp_put_reboot(usec_t timestamp) {
+ return 0;
+}
+static inline int utmp_put_runlevel(int runlevel, int previous) {
+ return 0;
+}
+static inline int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
+ return 0;
+}
+static inline int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line, int ut_type, const char *user) {
+ return 0;
+}
+static inline int utmp_wall(
+ const char *message,
+ const char *username,
+ const char *origin_tty,
+ bool (*match_tty)(const char *tty, void *userdata),
+ void *userdata) {
+ return 0;
+}
+
+#endif /* HAVE_UTMP */
sd_bus *sd_bus_ref(sd_bus *bus);
sd_bus *sd_bus_unref(sd_bus *bus);
+sd_bus *sd_bus_flush_close_unref(sd_bus *bus);
// UNNEEDED int sd_bus_is_open(sd_bus *bus);
// UNNEEDED void *sd_bus_slot_get_userdata(sd_bus_slot *slot);
// UNNEEDED void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata);
// UNNEEDED int sd_bus_slot_set_description(sd_bus_slot *slot, const char *description);
-// UNNEEDED int sd_bus_slot_get_description(sd_bus_slot *slot, char **description);
+// UNNEEDED int sd_bus_slot_get_description(sd_bus_slot *slot, const char **description);
// UNNEEDED sd_bus_message* sd_bus_slot_get_current_message(sd_bus_slot *slot);
// UNNEEDED sd_bus_message_handler_t sd_bus_slot_get_current_handler(sd_bus_slot *bus);
+++ /dev/null
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
- ***/
-
-#include "macro.h"
-#include "dns-domain.h"
-
-static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret) {
- char buffer[buffer_sz];
- int r;
-
- r = dns_label_unescape(&what, buffer, buffer_sz);
- assert_se(r == ret);
-
- if (r < 0)
- return;
-
- assert_se(streq(buffer, expect));
-}
-
-static void test_dns_label_unescape(void) {
- test_dns_label_unescape_one("hallo", "hallo", 6, 5);
- test_dns_label_unescape_one("hallo", "hallo", 4, -ENOSPC);
- test_dns_label_unescape_one("", "", 10, 0);
- test_dns_label_unescape_one("hallo\\.foobar", "hallo.foobar", 20, 12);
- test_dns_label_unescape_one("hallo.foobar", "hallo", 10, 5);
- test_dns_label_unescape_one("hallo\n.foobar", "hallo", 20, -EINVAL);
- test_dns_label_unescape_one("hallo\\", "hallo", 20, -EINVAL);
- test_dns_label_unescape_one("hallo\\032 ", "hallo ", 20, 7);
- test_dns_label_unescape_one(".", "", 20, 0);
- test_dns_label_unescape_one("..", "", 20, -EINVAL);
- test_dns_label_unescape_one(".foobar", "", 20, -EINVAL);
- test_dns_label_unescape_one("foobar.", "foobar", 20, 6);
-}
-
-static void test_dns_label_unescape_suffix_one(const char *what, const char *expect1, const char *expect2, size_t buffer_sz, int ret1, int ret2) {
- char buffer[buffer_sz];
- const char *label;
- int r;
-
- label = what + strlen(what);
-
- r = dns_label_unescape_suffix(what, &label, buffer, buffer_sz);
- assert_se(r == ret1);
- if (r >= 0)
- assert_se(streq(buffer, expect1));
-
- r = dns_label_unescape_suffix(what, &label, buffer, buffer_sz);
- assert_se(r == ret2);
- if (r >= 0)
- assert_se(streq(buffer, expect2));
-}
-
-static void test_dns_label_unescape_suffix(void) {
- test_dns_label_unescape_suffix_one("hallo", "hallo", "", 6, 5, 0);
- test_dns_label_unescape_suffix_one("hallo", "hallo", "", 4, -ENOSPC, -ENOSPC);
- test_dns_label_unescape_suffix_one("", "", "", 10, 0, 0);
- test_dns_label_unescape_suffix_one("hallo\\.foobar", "hallo.foobar", "", 20, 12, 0);
- test_dns_label_unescape_suffix_one("hallo.foobar", "foobar", "hallo", 10, 6, 5);
- test_dns_label_unescape_suffix_one("hallo.foobar\n", "foobar", "foobar", 20, -EINVAL, -EINVAL);
- test_dns_label_unescape_suffix_one("hallo\\", "hallo", "hallo", 20, -EINVAL, -EINVAL);
- test_dns_label_unescape_suffix_one("hallo\\032 ", "hallo ", "", 20, 7, 0);
- test_dns_label_unescape_suffix_one(".", "", "", 20, 0, 0);
- test_dns_label_unescape_suffix_one("..", "", "", 20, 0, 0);
- test_dns_label_unescape_suffix_one(".foobar", "foobar", "", 20, 6, -EINVAL);
- test_dns_label_unescape_suffix_one("foobar.", "", "foobar", 20, 0, 6);
- test_dns_label_unescape_suffix_one("foo\\\\bar", "foo\\bar", "", 20, 7, 0);
- test_dns_label_unescape_suffix_one("foo.bar", "bar", "foo", 20, 3, 3);
- test_dns_label_unescape_suffix_one("foo..bar", "bar", "", 20, 3, -EINVAL);
- test_dns_label_unescape_suffix_one("foo...bar", "bar", "", 20, 3, -EINVAL);
- test_dns_label_unescape_suffix_one("foo\\.bar", "foo.bar", "", 20, 7, 0);
- test_dns_label_unescape_suffix_one("foo\\\\.bar", "bar", "foo\\", 20, 3, 4);
- test_dns_label_unescape_suffix_one("foo\\\\\\.bar", "foo\\.bar", "", 20, 8, 0);
-}
-
-static void test_dns_label_escape_one(const char *what, size_t l, const char *expect, int ret) {
- _cleanup_free_ char *t = NULL;
- int r;
-
- r = dns_label_escape(what, l, &t);
- assert_se(r == ret);
-
- if (r < 0)
- return;
-
- assert_se(streq_ptr(expect, t));
-}
-
-static void test_dns_label_escape(void) {
- test_dns_label_escape_one("", 0, "", 0);
- test_dns_label_escape_one("hallo", 5, "hallo", 5);
- test_dns_label_escape_one("hallo", 6, NULL, -EINVAL);
- test_dns_label_escape_one("hallo hallo.foobar,waldi", 24, "hallo\\032hallo\\.foobar\\044waldi", 31);
-}
-
-static void test_dns_name_normalize_one(const char *what, const char *expect, int ret) {
- _cleanup_free_ char *t = NULL;
- int r;
-
- r = dns_name_normalize(what, &t);
- assert_se(r == ret);
-
- if (r < 0)
- return;
-
- assert_se(streq_ptr(expect, t));
-}
-
-static void test_dns_name_normalize(void) {
- test_dns_name_normalize_one("", "", 0);
- test_dns_name_normalize_one("f", "f", 0);
- test_dns_name_normalize_one("f.waldi", "f.waldi", 0);
- test_dns_name_normalize_one("f \\032.waldi", "f\\032\\032.waldi", 0);
- test_dns_name_normalize_one("\\000", NULL, -EINVAL);
- test_dns_name_normalize_one("..", NULL, -EINVAL);
- test_dns_name_normalize_one(".foobar", NULL, -EINVAL);
- test_dns_name_normalize_one("foobar.", "foobar", 0);
- test_dns_name_normalize_one(".", "", 0);
-}
-
-static void test_dns_name_equal_one(const char *a, const char *b, int ret) {
- int r;
-
- r = dns_name_equal(a, b);
- assert_se(r == ret);
-
- r = dns_name_equal(b, a);
- assert_se(r == ret);
-}
-
-static void test_dns_name_equal(void) {
- test_dns_name_equal_one("", "", true);
- test_dns_name_equal_one("x", "x", true);
- test_dns_name_equal_one("x", "x.", true);
- test_dns_name_equal_one("abc.def", "abc.def", true);
- test_dns_name_equal_one("abc.def", "ABC.def", true);
- test_dns_name_equal_one("abc.def", "CBA.def", false);
- test_dns_name_equal_one("", "xxx", false);
- test_dns_name_equal_one("ab", "a", false);
- test_dns_name_equal_one("\\000", "xxxx", -EINVAL);
- test_dns_name_equal_one(".", "", true);
- test_dns_name_equal_one(".", ".", true);
- test_dns_name_equal_one("..", "..", -EINVAL);
-}
-
-static void test_dns_name_between_one(const char *a, const char *b, const char *c, int ret) {
- int r;
-
- r = dns_name_between(a, b, c);
- assert_se(r == ret);
-
- r = dns_name_between(c, b, a);
- if (ret >= 0)
- assert_se(r == 0);
- else
- assert_se(r == ret);
-}
-
-static void test_dns_name_between(void) {
- /* see https://tools.ietf.org/html/rfc4034#section-6.1
- Note that we use "\033.z.example" in stead of "\001.z.example" as we
- consider the latter invalid */
- test_dns_name_between_one("example", "a.example", "yljkjljk.a.example", true);
- test_dns_name_between_one("a.example", "yljkjljk.a.example", "Z.a.example", true);
- test_dns_name_between_one("yljkjljk.a.example", "Z.a.example", "zABC.a.EXAMPLE", true);
- test_dns_name_between_one("Z.a.example", "zABC.a.EXAMPLE", "z.example", true);
- test_dns_name_between_one("zABC.a.EXAMPLE", "z.example", "\\033.z.example", true);
- test_dns_name_between_one("z.example", "\\033.z.example", "*.z.example", true);
- test_dns_name_between_one("\\033.z.example", "*.z.example", "\\200.z.example", true);
- test_dns_name_between_one("*.z.example", "\\200.z.example", "example", true);
- test_dns_name_between_one("\\200.z.example", "example", "a.example", true);
-
- test_dns_name_between_one("example", "a.example", "example", -EINVAL);
- test_dns_name_between_one("example", "example", "yljkjljk.a.example", false);
- test_dns_name_between_one("example", "yljkjljk.a.example", "yljkjljk.a.example", false);
-}
-
-static void test_dns_name_endswith_one(const char *a, const char *b, int ret) {
- assert_se(dns_name_endswith(a, b) == ret);
-}
-
-static void test_dns_name_endswith(void) {
- test_dns_name_endswith_one("", "", true);
- test_dns_name_endswith_one("", "xxx", false);
- test_dns_name_endswith_one("xxx", "", true);
- test_dns_name_endswith_one("x", "x", true);
- test_dns_name_endswith_one("x", "y", false);
- test_dns_name_endswith_one("x.y", "y", true);
- test_dns_name_endswith_one("x.y", "Y", true);
- test_dns_name_endswith_one("x.y", "x", false);
- test_dns_name_endswith_one("x.y.z", "Z", true);
- test_dns_name_endswith_one("x.y.z", "y.Z", true);
- test_dns_name_endswith_one("x.y.z", "x.y.Z", true);
- test_dns_name_endswith_one("x.y.z", "waldo", false);
- test_dns_name_endswith_one("x.y.z.u.v.w", "y.z", false);
- test_dns_name_endswith_one("x.y.z.u.v.w", "u.v.w", true);
- test_dns_name_endswith_one("x.y\001.z", "waldo", -EINVAL);
-}
-
-static void test_dns_name_root(void) {
- assert_se(dns_name_root("") == true);
- assert_se(dns_name_root(".") == true);
- assert_se(dns_name_root("xxx") == false);
- assert_se(dns_name_root("xxx.") == false);
- assert_se(dns_name_root("..") == -EINVAL);
-}
-
-static void test_dns_name_single_label(void) {
- assert_se(dns_name_single_label("") == false);
- assert_se(dns_name_single_label(".") == false);
- assert_se(dns_name_single_label("..") == -EINVAL);
- assert_se(dns_name_single_label("x") == true);
- assert_se(dns_name_single_label("x.") == true);
- assert_se(dns_name_single_label("xx.yy") == false);
-}
-
-static void test_dns_name_reverse_one(const char *address, const char *name) {
- _cleanup_free_ char *p = NULL;
- union in_addr_union a, b = {};
- int familya, familyb;
-
- assert_se(in_addr_from_string_auto(address, &familya, &a) >= 0);
- assert_se(dns_name_reverse(familya, &a, &p) >= 0);
- assert_se(streq(p, name));
- assert_se(dns_name_address(p, &familyb, &b) > 0);
- assert_se(familya == familyb);
- assert_se(in_addr_equal(familya, &a, &b));
-}
-
-static void test_dns_name_reverse(void) {
- test_dns_name_reverse_one("47.11.8.15", "15.8.11.47.in-addr.arpa");
- test_dns_name_reverse_one("fe80::47", "7.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa");
- test_dns_name_reverse_one("127.0.0.1", "1.0.0.127.in-addr.arpa");
- test_dns_name_reverse_one("::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa");
-}
-
-int main(int argc, char *argv[]) {
-
- test_dns_label_unescape();
- test_dns_label_unescape_suffix();
- test_dns_label_escape();
- test_dns_name_normalize();
- test_dns_name_equal();
- test_dns_name_endswith();
- test_dns_name_between();
- test_dns_name_root();
- test_dns_name_single_label();
- test_dns_name_reverse();
-
- return 0;
-}
+++ /dev/null
-# This file is part of systemd.
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-
-[Unit]
-Description=Network Service
-Documentation=man:systemd-networkd.service(8)
-ConditionCapability=CAP_NET_ADMIN
-DefaultDependencies=no
-# dbus.service can be dropped once on kdbus, and systemd-udevd.service can be
-# dropped once tuntap is moved to netlink
-After=systemd-udevd.service dbus.service network-pre.target systemd-sysusers.service systemd-sysctl.service
-Before=network.target multi-user.target shutdown.target
-Conflicts=shutdown.target
-Wants=network.target
-
-# On kdbus systems we pull in the busname explicitly, because it
-# carries policy that allows the daemon to acquire its name.
-Wants=org.freedesktop.network1.busname
-After=org.freedesktop.network1.busname
-
-[Service]
-Type=notify
-Restart=on-failure
-RestartSec=0
-ExecStart=@rootlibexecdir@/systemd-networkd
-CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER
-ProtectSystem=full
-ProtectHome=yes
-WatchdogSec=1min
-
-[Install]
-WantedBy=multi-user.target
-Also=systemd-networkd.socket