diff options
108 files changed, 3416 insertions, 1195 deletions
diff --git a/.gitignore b/.gitignore index be44cb60bb..5669d740ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +systemd-hostnamed systemd-binfmt systemd-getty-generator systemd-nspawn diff --git a/Makefile.am b/Makefile.am index 2f08ceb173..0aaa1e45c3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -90,6 +90,12 @@ AM_CPPFLAGS += \ -DKBD_SETFONT=\"/bin/setfont\" \ -DDEFAULT_FONT=\"LatArCyrHeb-16\" else +if TARGET_MEEGO +AM_CPPFLAGS += \ + -DKBD_LOADKEYS=\"/bin/loadkeys\" \ + -DKBD_SETFONT=\"/bin/setfont\" \ + -DDEFAULT_FONT=\"LatArCyrHeb-16\" +else AM_CPPFLAGS += \ -DKBD_LOADKEYS=\"/bin/loadkeys\" \ -DKBD_SETFONT=\"/bin/setfont\" \ @@ -98,6 +104,7 @@ endif endif endif endif +endif rootbin_PROGRAMS = \ systemd \ @@ -144,7 +151,8 @@ rootlibexec_PROGRAMS = \ systemd-ac-power \ systemd-detect-virt \ systemd-sysctl \ - systemd-binfmt + systemd-binfmt \ + systemd-hostnamed systemgenerator_PROGRAMS = \ systemd-getty-generator @@ -177,10 +185,12 @@ dist_pkgsysconf_DATA = \ src/system.conf dist_dbuspolicy_DATA = \ - src/org.freedesktop.systemd1.conf + src/org.freedesktop.systemd1.conf \ + src/org.freedesktop.hostname1.conf dist_dbussystemservice_DATA = \ - src/org.freedesktop.systemd1.service + src/org.freedesktop.systemd1.service \ + src/org.freedesktop.hostname1.service dist_udevrules_DATA = \ src/99-systemd.rules @@ -282,6 +292,7 @@ nodist_systemunit_DATA = \ units/systemd-initctl.service \ units/systemd-logger.service \ units/systemd-shutdownd.service \ + units/systemd-hostnamed.service \ units/systemd-kmsg-syslogd.service \ units/systemd-modules-load.service \ units/systemd-vconsole-setup.service \ @@ -326,6 +337,7 @@ EXTRA_DIST = \ units/systemd-initctl.service.in \ units/systemd-logger.service.in \ units/systemd-shutdownd.service.in \ + units/systemd-hostnamed.service.in \ units/systemd-kmsg-syslogd.service.in \ units/systemd-modules-load.service.in \ units/systemd-vconsole-setup.service.in \ @@ -406,9 +418,12 @@ dist_doc_DATA = \ pkgconfigdata_DATA = \ systemd.pc -polkitpolicy_DATA = \ +nodist_polkitpolicy_DATA = \ src/org.freedesktop.systemd1.policy +dist_polkitpolicy_DATA = \ + src/org.freedesktop.hostname1.policy + noinst_LTLIBRARIES = \ libsystemd-basic.la \ libsystemd-core.la \ @@ -481,7 +496,8 @@ libsystemd_core_la_SOURCES = \ src/namespace.c \ src/tcpwrap.c \ src/cgroup-util.c \ - src/condition.c + src/condition.c \ + src/dbus-common.c libsystemd_core_la_CFLAGS = \ $(AM_CFLAGS) \ @@ -570,9 +586,11 @@ MANPAGES = \ man/vconsole.conf.5 \ man/locale.conf.5 \ man/os-release.5 \ + man/machine-info.5 \ man/modules-load.d.5 \ man/binfmt.d.5 \ - man/sysctl.d.5 + man/sysctl.d.5 \ + man/systemd-ask-password.1 MANPAGES_ALIAS = \ man/reboot.8 \ @@ -752,6 +770,19 @@ systemd_shutdownd_LDADD = \ libsystemd-basic.la \ libsystemd-daemon.la +systemd_hostnamed_SOURCES = \ + src/hostnamed.c \ + src/dbus-common.c + +systemd_hostnamed_CFLAGS = \ + $(AM_CFLAGS) \ + $(DBUS_CFLAGS) + +systemd_hostnamed_LDADD = \ + libsystemd-basic.la \ + libsystemd-daemon.la \ + $(DBUS_LIBS) + systemd_shutdown_SOURCES = \ src/mount-setup.c \ src/umount.c \ @@ -1344,9 +1375,10 @@ install-data-hook: $(LN_S) graphical.target runlevel5.target && \ $(LN_S) reboot.target runlevel6.target ) ( cd $(DESTDIR)$(systemunitdir) && \ - rm -f default.target ctrl-alt-del.target && \ + rm -f default.target ctrl-alt-del.target dbus-org.freedesktop.hostname1.service && \ $(LN_S) graphical.target default.target && \ - $(LN_S) reboot.target ctrl-alt-del.target ) + $(LN_S) reboot.target ctrl-alt-del.target && \ + $(LN_S) systemd-hostnamed.service dbus-org.freedesktop.hostname1.service ) ( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \ rm -f getty.target systemd-user-sessions.service systemd-ask-password-wall.path && \ $(LN_S) ../getty.target getty.target && \ @@ -1429,6 +1461,20 @@ if HAVE_PLYMOUTH rm -f plymouth-halt.service && \ $(LN_S) ../plymouth-halt.service plymouth-halt.service ) endif +if TARGET_MEEGO + $(MKDIR_P) -m 0755 $(DESTDIR)$(systemunitdir)/final.target.wants + ( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \ + rm -f network.target && \ + $(LN_S) $(systemunitdir)/network.target network.target ) + ( cd $(DESTDIR)$(pkgsysconfdir)/system/sysinit.target.wants && \ + rm -f * ) + ( cd $(DESTDIR)$(pkgsysconfdir)/system/local-fs.target.wants && \ + rm -f * ) + ( cd $(DESTDIR)$(pkgsysconfdir)/system/multi-user.target.wants && \ + rm -f * ) + ( cd $(DESTDIR)$(pkgsysconfdir)/system/getty.target.wants && \ + rm -f * ) +endif if TARGET_FEDORA $(MKDIR_P) -m 0755 $(DESTDIR)$(systemunitdir)/final.target.wants @@ -2,46 +2,57 @@ F15: * swap units that are activated by one name but shown in the kernel under another are semi-broken -* isolate multi-user.target doesn't start a getty@tty1 if we run it from graphical.target - https://bugzilla.redhat.com/show_bug.cgi?id=688661 +* Fix assert http://lists.freedesktop.org/archives/systemd-devel/2011-April/001910.html + +* 0595f9a1c182a84581749823ef47c5f292e545f9 is borked, freezes shutdown + (path: after installing inotify watches, recheck file again to fix race) + +F15 External: * NFS, networkmanager ordering issue (PENDING) * NM should pull in network.target (PENDING) https://bugzilla.redhat.com/show_bug.cgi?id=692008 -* ntpd should pull in time-sync.target. (PENDING) +* bluetooth should be possible to disable (PENDING) -* add fstab fields to add wait timeouts, change Wants to Requires by local-fs.target +* get writev() /dev/kmsg support into the F15 kernel + https://lkml.org/lkml/2011/4/6/473 + patched merged into -mm -* hook emergency.target into local-fs.target in some way as OnFailure with isolate +* fix sd_is_socket() invocation in dbus -* bind mounts are ignored - https://bugzilla.redhat.com/show_bug.cgi?id=682662 +* New CK release, with sysinit.target dropping and TTY loop -* 0595f9a1c182a84581749823ef47c5f292e545f9 is borked, freezes shutdown - (path: after installing inotify watches, recheck file again to fix race) +* New Avahi package, enable it by default -* bluetooth should be possible to disable - -* fix alsa mixer restore to not print error when no config is stored +* make anaconda write timeout=0 for encrypted devices Features: -* don't trim empty cgroups - https://bugzilla.redhat.com/show_bug.cgi?id=678555 +* Maybe merge nss-myhostname into systemd? -* serialize used job ids and max job id +* maybe lower default timeout to 2min? -* show enablement status in systemctl status +* GC unreferenced jobs (such as .device jobs) + +* support wildcard expansion in ListeStream= and friends + +* avoid DefaultStandardOutput=syslog to have any effect on StandardInput=socket services + +* use pivot_root on shutdown so that we can unmount the root directory. + +* fix alsa mixer restore to not print error when no config is stored -* expose monotonic timestamps on the bus and make systemd-analyze use it +* show enablement status in systemctl status * write blog stories about: - - chroot, nspawn and friends - - the blame game: systemd-analyze - enabling dbus services - status update + - the new configuration files + - you are a distro: why switch? + +* maybe add tiny dbus services similar to hostnamed for locale and wallclock/timezone? * allow port = 0 in .socket units @@ -49,16 +60,13 @@ Features: * introduce /usr/lib/binfmt.d/, /usr/lib/tmpfiles.d/ -* in pam_systemd: don't rely on /proc/self/loginuid in a container - * take BSD file lock on tty devices when using them? -* tmpfiles should allow two identical lines - https://bugzilla.redhat.com/show_bug.cgi?id=690253 - * avoid any flag files, or readahead files in /, we need to support r/o / or / on tmpfs like Android setups. +* move readahead files into /var, look for them with .path units + * teach dbus to activate all services it finds in /etc/systemd/services/org-*.service * get process transport into dbus for systemctl -P/-H @@ -70,22 +78,25 @@ Features: * Find a way to replace /var/run, /var/lock directories with symlinks during an RPM package upgrade (filesystem.rpm or systemd.rpm). - We soon want to get rid of var-run.mount var-lock.mount units. + (lua code to create symlinks right away for new installations is in filesytem.rpm now) + We soon want to get rid of var-run.mount var-lock.mount units: + if mountpoint /run ; then + umount /var/run || : + else + mount --move /var/run /run || mount --bind /var/run /run + fi + mv /var/run /var/.run.save + ln -s /run /var/run + echo "R /var/.run.save" > /etc/tmpfiles.d/remove-run-save.conf * when key file cannot be found, read it from kbd in cryptsetup -* get rid of random file name in generator directory? - /run/systemd/generator-IH1vFu - * add switch to systemctl to show enabled but not running services. Or another switch that shows service that have been running since booting but aren't running anymore. * reuse mkdtemp namespace dirs in /tmp? -* don't strip facility from kmsg log messages as soon as that is possible: - http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=9d90c8d9cde929cbc575098e825d7c29d9f45054 - * recreate systemd's D-Bus private socket file on SIGUSR2 * be more specific what failed: @@ -105,11 +116,9 @@ Features: about policy loading. Probably check for available selinux in /proc/filesystems, and check for active selinux with getcon_raw() == "kernel" -* optionally create watched directories in .path units - * Support --test based on current system state -* consider services with no [Install] section and stored in /lib enabled by "systemctl is-enabled" +* systemctl enable as D-Bus call * consider services with any kind of link in /etc/systemd/system enabled @@ -120,23 +129,19 @@ Features: * Maybe implement "systemctl mask" and "systemctl unmask", but not document it? When doing that add switch to make this temporary by placing mask links in /dev. - Consider moving the actual fs operations into systemd behind a D-Bus - interface, to make namespaces/containers/remote connections work properly. * detect LXC environment * invoke vhangup() before and after invoking getty http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=3c95c985fa91ecf6a0e29622bbdd13dcfc5ce9f1 -* support "auto" and "comment=systemd.automount" at the same time for an fstab entry - * Maybe store in unit files whether a service should be enabled by default on package installation (belongs into a distro pattern though, not in an upstream package's service file) * perhaps add "systemctl reenable" as combination of "systemctl disable" and "systemctl enable" * need a way to apply mount options of api vfs from systemd unit files - (or some other modern source?) instead of fstab + (or some other modern source?) instead of fstab? * maybe introduce ExecRestartPre= @@ -144,12 +149,11 @@ Features: * Patch systemd-fsck to use -C and pass console fd to it -* support remote/ssh systemctl/systemadm, and local privileged access → dbus patches need to be merged - * configurable jitter for timer events -* Support ProcessNeededForShutdown=true to allow stuff like mdmon - to be killed very late after the rootfs is read only (?) +* Support ProcessNeededForShutdown=true to allow stuff like mdmon to + be killed very late after the rootfs is read only? If implement pass + this to shutdown binary via command line argument. * Integrate "mdadm --wait-clean". Maybe just let SIGTERM to mdmon trigger the needed action @@ -194,8 +198,6 @@ Features: * systemctl list-jobs - show dependencies -* accountsservice is borked - * auditd service files * add systemctl switch to dump transaction without executing it @@ -208,6 +210,8 @@ Features: * allow runtime changing of log level and target +* drop cap bounding set in readahead and other services + External: * udisks should not use udisks-part-id, instead use blkid. also not probe /dev/loopxxx diff --git a/configure.ac b/configure.ac index fa8c8ba6d1..730861f78a 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ AC_PREREQ(2.63) -AC_INIT([systemd],[24],[systemd-devel@lists.freedesktop.org]) +AC_INIT([systemd],[25],[systemd-devel@lists.freedesktop.org]) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([config.h]) @@ -286,6 +286,7 @@ if test "z$with_distro" = "z"; then test -f "/etc/frugalware-release" && with_distro="frugalware" test -f "/etc/altlinux-release" && with_distro="altlinux" test -f "/etc/mandriva-release" && with_distro="mandriva" + test -f "/etc/meego-release" && with_distro="meego" if test "x`lsb_release -is 2>/dev/null`" = "xUbuntu"; then with_distro="ubuntu" fi @@ -360,6 +361,12 @@ case $with_distro in M4_DISTRO_FLAG=-DTARGET_MANDRIVA=1 have_plymouth=true ;; + meego) + SYSTEM_SYSVINIT_PATH= + SYSTEM_SYSVRCND_PATH= + AC_DEFINE(TARGET_MEEGO, [], [Target is MeeGo]) + M4_DISTRO_FLAG=-DTARGET_MEEGO=1 + ;; other) ;; *) @@ -409,6 +416,7 @@ AM_CONDITIONAL(TARGET_SLACKWARE, test x"$with_distro" = xslackware) AM_CONDITIONAL(TARGET_FRUGALWARE, test x"$with_distro" = xfrugalware) AM_CONDITIONAL(TARGET_ALTLINUX, test x"$with_distro" = xaltlinux) AM_CONDITIONAL(TARGET_MANDRIVA, test x"$with_distro" = xmandriva) +AM_CONDITIONAL(TARGET_MEEGO, test x"$with_distro" = xmeego) AM_CONDITIONAL(HAVE_PLYMOUTH, test -n "$have_plymouth") AM_CONDITIONAL(HAVE_SYSV_COMPAT, test "$SYSTEM_SYSV_COMPAT" = "yes") diff --git a/man/daemon.xml b/man/daemon.xml index ab355cd593..bf454fd040 100644 --- a/man/daemon.xml +++ b/man/daemon.xml @@ -869,7 +869,7 @@ fi</programlisting> a fragment like the following:</para> <programlisting>%triggerun -- foobar < 0.47.11-1 -if /sbin/chkconfig --level 3 foobar ; then +if /sbin/chkconfig --level 5 foobar ; then /bin/systemctl --no-reload enable foobar.service foobar.socket >/dev/null 2>&1 || : fi</programlisting> diff --git a/man/hostname.xml b/man/hostname.xml index f226ef05ad..b8b05c8d35 100644 --- a/man/hostname.xml +++ b/man/hostname.xml @@ -44,7 +44,7 @@ <refnamediv> <refname>hostname</refname> - <refpurpose>local host name configuration file</refpurpose> + <refpurpose>Local host name configuration file</refpurpose> </refnamediv> <refsynopsisdiv> @@ -62,10 +62,10 @@ newline-terminated host name string. The host name may be a free-form string up to 64 characters in length, however it is recommended that it consists - only of 7bit ASCII characters and no spaces or dots, - and limit itself to the format allowed for DNS domain + only of 7bit ASCII lower-case characters and no spaces or dots, + and limits itself to the format allowed for DNS domain name labels, even though this is not a - requirement.</para> + strict requirement.</para> <para>Depending on the operating system other configuration files might be checked for configuration @@ -85,7 +85,10 @@ <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>sethostname</refentrytitle><manvolnum>2</manvolnum></citerefentry>, - <citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>1</manvolnum></citerefentry> + <citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/machine-id.xml b/man/machine-id.xml index fefeb66fd6..d0bfbd240d 100644 --- a/man/machine-id.xml +++ b/man/machine-id.xml @@ -64,7 +64,7 @@ random source during system installation and stays constant for all subsequent boots. Optionally, for stateless systems it is generated during runtime at - boot.</para> + boot if it is found to be empty.</para> <para>The machine ID does not change based on user configuration, or when hardware is replaced.</para> @@ -76,7 +76,7 @@ with a globally unique ID in the network, that does not change even if the local network configuration changes. Due to this and its greater length it is - a more useful replacement than the + a more useful replacement for the <citerefentry><refentrytitle>gethostid</refentrytitle><manvolnum>3</manvolnum></citerefentry> call POSIX specifies.</para> </refsect1> @@ -97,7 +97,9 @@ <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>gethostid</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry> + <citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/machine-info.xml b/man/machine-info.xml new file mode 100644 index 0000000000..c6d3e92f9a --- /dev/null +++ b/man/machine-info.xml @@ -0,0 +1,147 @@ +<?xml version='1.0'?> <!--*-nxml-*--> +<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?> +<!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 General Public License as published by + the Free Software Foundation; either version 2 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +--> + +<refentry id="machine-info"> + <refentryinfo> + <title>machine-info</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>machine-info</refentrytitle> + <manvolnum>5</manvolnum> + </refmeta> + + <refnamediv> + <refname>machine-info</refname> + <refpurpose>Local machine information file</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <para><filename>/etc/machine-info</filename></para> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para>The <filename>/etc/machine-info</filename> file + contains machine meta data.</para> + + <para>The basic file format of + <filename>machine-info</filename> is a + newline-separated list of environment-like + shell-compatible variable assignments. It is possible + to source the configuration from shell scripts, + however, beyond mere variable assignments no shell + features are supported, allowing applications to read + the file without implementing a shell compatible + execution engine.</para> + + <para><filename>/etc/machine-info</filename> contains + meta data about the machine that is set by the user or + administrator.</para> + + <para>Depending on the operating system other + configuration files might be checked for machine + information as well, however only as fallback.</para> + </refsect1> + + <refsect1> + <title>Options</title> + + <para>The following machine meta data parameters may + be set using + <filename>/etc/machine-info</filename>:</para> + + <variablelist> + + <varlistentry> + <term><varname>PRETTY_HOSTNAME=</varname></term> + + <listitem><para>A pretty + human-readable UTF8 machine identifier + string. This should contain a name + like <literal>Lennart's + Laptop</literal> which is useful to + present to the user and does not + suffer by the syntax limitations of + internet domain names. If possible the + internet host name as configured in + <filename>/etc/hostname</filename> + should be kept similar to this + one. Example: if this value is + <literal>Lennart's Computer</literal> + an Internet host name of + <literal>lennarts-computer</literal> + might be a good choice. If this + parameter is not set an application + should fall back to the Internet host + name for presentation + purposes.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>ICON_NAME=</varname></term> + + <listitem><para>An icon identifying + this machine according to the <ulink + url="http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html">XDG + Icon Naming Specification</ulink>. If + this parameter is not set an + application should fall back to + <literal>computer</literal> or a + similar icon name.</para></listitem> + </varlistentry> + + </variablelist> + + </refsect1> + + <refsect1> + <title>Example</title> + + <programlisting>PRETTY_NAME="Lennart's Computer" +ICON_NAME=computer-laptop</programlisting> + </refsect1> + + <refsect1> + <title>See Also</title> + <para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/os-release.xml b/man/os-release.xml index 759c04d320..d8a45b303f 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -165,11 +165,11 @@ </varlistentry> </variablelist> - <para>If you interpreting this file from code or a - shell script, use the ID and VERSION_ID fields. When - looking for an OS identification string for - presentation to the user use the PRETTY_STRING - field.</para> + <para>If you are reading this file from code or a + shell script to determine the OS or a specific version + of it, use the ID and VERSION_ID fields. When looking + for an OS identification string for presentation to + the user use the PRETTY_NAME field.</para> <para>Note that operating system vendors may choose not to provide version information, for example to @@ -182,10 +182,10 @@ <title>Example</title> <programlisting>NAME=Fedora -VERSION=15 (Rawhide) +VERSION="15 (Rawhide)" ID=fedora VERSION_ID=15 -PRETTY_NAME=Fedora 15 (Rawhide) +PRETTY_NAME="Fedora 15 (Rawhide)" ANSI_COLOR=0;34</programlisting> </refsect1> @@ -193,7 +193,10 @@ ANSI_COLOR=0;34</programlisting> <title>See Also</title> <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, - <citerefentry><refentrytitle>lsb_release</refentrytitle><manvolnum>1</manvolnum></citerefentry> + <citerefentry><refentrytitle>lsb_release</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/systemd-ask-password.xml b/man/systemd-ask-password.xml new file mode 100644 index 0000000000..50aec3403a --- /dev/null +++ b/man/systemd-ask-password.xml @@ -0,0 +1,183 @@ +<?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 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +--> + +<refentry id="systemd-ask-password"> + + <refentryinfo> + <title>systemd-ask-password</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>systemd-ask-password</refentrytitle> + <manvolnum>1</manvolnum> + </refmeta> + + <refnamediv> + <refname>systemd-ask-password</refname> + <refpurpose>Query the user for a system password</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <cmdsynopsis> + <command>systemd-ask-password <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="opt">MESSAGE</arg></command> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><command>systemd-ask-password</command> may be + used to query a system password or passphrase from the + user, using a question message specified on the + command line. When run from a TTY it will query a + password on the TTY and print it to STDOUT. When run + with no TTY or with <option>--no-tty</option> it will + query the password system-wide and allow active users + to respond via several agents. The latter is + only available to privileged processes.</para> + + <para>The purpose of this tool is to query system-wide + passwords -- that is passwords not attached to a + specific user account. Examples include: unlocking + encrypted hard disks when they are plugged in or at + boot, entering an SSL certificate passphrase for web + and VPN servers.</para> + + <para>Existing agents are: a boot-time password agent + asking the user for passwords using Plymouth; a + boot-time password agent querying the user directly on + the console; an agent requesting password input via a + <citerefentry><refentrytitle>wall</refentrytitle><manvolnum>1</manvolnum></citerefentry> + message; an agent suitable for running in a GNOME + session; a command line agent which can be started + temporarily to process queued password requests; a TTY + agent that is temporarily spawned during + <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> + invocations.</para> + + <para>Additional password agents may be implemented + according to the <ulink + url="http://www.freedesktop.org/wiki/Software/systemd/PasswordAgents">systemd + Password Agent Specification</ulink>.</para> + + <para>If a password is queried on a tty the user may + press TAB to hide the asterisks normally shown for + each character typed. Pressing Backspace as first key + achieves the same effect.</para> + + </refsect1> + + <refsect1> + <title>Options</title> + + <para>The following options are understood:</para> + + <variablelist> + <varlistentry> + <term><option>--h</option></term> + <term><option>--help</option></term> + + <listitem><para>Prints a short help + text and exits.</para></listitem> + </varlistentry> + + <varlistentry> + <term><option>--icon=</option></term> + + <listitem><para>Specify an icon name + alongside the pasword query, which may + be used in all agents supporting + graphical display. The icon name + should follow the <ulink + url="http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html">XDG + Icon Naming + Specification</ulink>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><option>--timeout=</option></term> + + <listitem><para>Specify the query + timeout in seconds. Defaults to + 3min.</para></listitem> + </varlistentry> + + <varlistentry> + <term><option>--no-tty</option></term> + + <listitem><para>Never ask for password + on current TTY even if one is + available. Always use agent + system.</para></listitem> + </varlistentry> + + <varlistentry> + <term><option>--accept-cached</option></term> + + <listitem><para>If passed accept + cached passwords, i.e. passwords + previously typed in.</para></listitem> + </varlistentry> + + <varlistentry> + <term><option>--multiple</option></term> + + <listitem><para>When used in + conjunction with + <option>--accept-cached</option> + accept multiple passwords. This will + output one password per + line.</para></listitem> + </varlistentry> + </variablelist> + + </refsect1> + + <refsect1> + <title>Exit status</title> + + <para>On success 0 is returned, a non-zero failure + code otherwise.</para> + </refsect1> + + <refsect1> + <title>See Also</title> + <para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>plymouth</refentrytitle><manvolnum>8</manvolnum></citerefentry>, + <citerefentry><refentrytitle>wall</refentrytitle><manvolnum>1</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml index dd66d2ad72..40d236b266 100644 --- a/man/systemd.mount.xml +++ b/man/systemd.mount.xml @@ -212,7 +212,7 @@ a time span value such as "5min 20s". Pass 0 to disable the timeout logic. Defaults to - 60s.</para></listitem> + 3min.</para></listitem> </varlistentry> <varlistentry> diff --git a/man/systemd.path.xml b/man/systemd.path.xml index d5495c7cc3..e816c3018c 100644 --- a/man/systemd.path.xml +++ b/man/systemd.path.xml @@ -168,6 +168,28 @@ identical, except for the suffix.</para></listitem> </varlistentry> + <varlistentry> + <term><varname>MakeDirectory=</varname></term> + + <listitem><para>Takes a boolean + argument. If true the directories to + watch are created before + watching. This option is ignored for + <varname>PathExists=</varname> + settings. Defaults to + <option>false</option>.</para></listitem> + </varlistentry> + <varlistentry> + <term><varname>DirectoryMode=</varname></term> + + <listitem><para>If + <varname>MakeDirectory=</varname> is + enabled use the mode specified here to + create the directories in + question. Takes an access mode in + octal notation. Defaults to + <option>0755</option>.</para></listitem> + </varlistentry> </variablelist> </refsect1> diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 7458720a3f..335169a397 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -448,7 +448,7 @@ time span value such as "5min 20s". Pass 0 to disable the timeout logic. Defaults to - 60s.</para></listitem> + 3min.</para></listitem> </varlistentry> <varlistentry> diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 8cbb512ec1..d651c14486 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -219,6 +219,37 @@ </varlistentry> <varlistentry> + <term><varname>ListenSpecial=</varname></term> + <listitem><para>Specifies a special + file in the file system to listen + on. This expects an absolute file + system path as argument. Behaviour + otherwise is very similar to the + <varname>ListenFIFO=</varname> + directive above. Use this to open + character device nodes as well as + special files in + <filename>/proc</filename> and + <filename>/sys</filename>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>ListenNetlink=</varname></term> + <listitem><para>Specifies a Netlink + family to create a socket for to + listen on. This expects a short string + referring to the AF_NETLINK family + name (such as <varname>audit</varname> + or <varname>kobject-uevent</varname>) + as argument, optionally suffixed by a + whitespace followed by a multicast + group integer. Behaviour otherwise is + very similar to the + <varname>ListenDatagram=</varname> + directive above.</para></listitem> + </varlistentry> + + <varlistentry> <term><varname>BindIPv6Only=</varname></term> <listitem><para>Takes a one of <option>default</option>, @@ -510,7 +541,7 @@ a time span value such as "5min 20s". Pass 0 to disable the timeout logic. Defaults to - 60s.</para></listitem> + 3min.</para></listitem> </varlistentry> <varlistentry> diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 5460ebeb2f..65a76be3b7 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -445,6 +445,32 @@ </varlistentry> <varlistentry> + <term><varname>OnFailureIsolate=</varname></term> + + <listitem><para>Takes a boolean + argument. If <option>true</option> the + unit listed in + <varname>OnFailure=</varname> will be + enqueued in isolation mode, i.e. all + units that are not its dependency will + be stopped. If this is set only a + single unit may be listed in + <varname>OnFailure=</varname>. Defaults + to + <option>false</option>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>IgnoreOnIsolate=</varname></term> + + <listitem><para>Takes a boolean + argument. If <option>true</option> + this unit will not be stopped when + isolating another unit. Defaults to + <option>false</option>.</para></listitem> + </varlistentry> + + <varlistentry> <term><varname>StopWhenUnneeded=</varname></term> <listitem><para>Takes a boolean diff --git a/src/ask-password-api.c b/src/ask-password-api.c index da967ab7a1..04d5623d9e 100644 --- a/src/ask-password-api.c +++ b/src/ask-password-api.c @@ -404,13 +404,13 @@ int ask_password_agent( t = now(CLOCK_MONOTONIC); - if (until <= t) { + if (until > 0 && until <= t) { log_notice("Timed out"); r = -ETIME; goto finish; } - if ((k = poll(pollfd, _FD_MAX, (until-t)/USEC_PER_MSEC)) < 0) { + if ((k = poll(pollfd, _FD_MAX, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1)) < 0) { if (errno == EINTR) continue; @@ -481,7 +481,13 @@ int ask_password_agent( if (passphrase[0] == '+') { char **l; - if (!(l = strv_parse_nulstr(passphrase+1, n-1))) { + 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; } diff --git a/src/ask-password.c b/src/ask-password.c index c77376482e..5162f62eee 100644 --- a/src/ask-password.c +++ b/src/ask-password.c @@ -40,11 +40,12 @@ #include "util.h" #include "strv.h" #include "ask-password-api.h" +#include "def.h" static const char *arg_icon = NULL; static const char *arg_message = NULL; static bool arg_use_tty = true; -static usec_t arg_timeout = 60 * USEC_PER_SEC; +static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC; static bool arg_accept_cached = false; static bool arg_multiple = false; @@ -101,7 +102,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_TIMEOUT: - if (parse_usec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) { + if (parse_usec(optarg, &arg_timeout) < 0) { log_error("Failed to parse --timeout parameter %s", optarg); return -EINVAL; } @@ -139,6 +140,7 @@ static int parse_argv(int argc, char *argv[]) { int main(int argc, char *argv[]) { int r; + usec_t timeout; log_parse_environment(); log_open(); @@ -146,10 +148,15 @@ int main(int argc, char *argv[]) { if ((r = parse_argv(argc, argv)) <= 0) goto finish; + if (arg_timeout > 0) + timeout = now(CLOCK_MONOTONIC) + arg_timeout; + else + timeout = 0; + if (arg_use_tty && isatty(STDIN_FILENO)) { char *password = NULL; - if ((r = ask_password_tty(arg_message, now(CLOCK_MONOTONIC) + arg_timeout, NULL, &password)) >= 0) { + if ((r = ask_password_tty(arg_message, timeout, NULL, &password)) >= 0) { puts(password); free(password); } @@ -157,7 +164,7 @@ int main(int argc, char *argv[]) { } else { char **l; - if ((r = ask_password_agent(arg_message, arg_icon, now(CLOCK_MONOTONIC) + arg_timeout, arg_accept_cached, &l)) >= 0) { + if ((r = ask_password_agent(arg_message, arg_icon, timeout, arg_accept_cached, &l)) >= 0) { char **p; STRV_FOREACH(p, l) { diff --git a/src/automount.c b/src/automount.c index f6f83d43b6..33c962e0c0 100644 --- a/src/automount.c +++ b/src/automount.c @@ -58,6 +58,8 @@ static void automount_init(Unit *u) { a->pipe_watch.type = WATCH_INVALID; a->directory_mode = 0755; + + a->meta.ignore_on_isolate = true; } static void repeat_unmout(const char *path) { diff --git a/src/cgroup.c b/src/cgroup.c index 5864858dd7..0c6f20d4b7 100644 --- a/src/cgroup.c +++ b/src/cgroup.c @@ -63,7 +63,7 @@ int cgroup_bonding_realize_list(CGroupBonding *first) { return 0; } -void cgroup_bonding_free(CGroupBonding *b) { +void cgroup_bonding_free(CGroupBonding *b, bool remove_or_trim) { assert(b); if (b->unit) { @@ -82,7 +82,7 @@ void cgroup_bonding_free(CGroupBonding *b) { } } - if (b->realized && b->ours) { + if (b->realized && b->ours && remove_or_trim) { if (cgroup_bonding_is_empty(b) > 0) cg_delete(b->controller, b->path); @@ -95,11 +95,11 @@ void cgroup_bonding_free(CGroupBonding *b) { free(b); } -void cgroup_bonding_free_list(CGroupBonding *first) { +void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) { CGroupBonding *b, *n; LIST_FOREACH_SAFE(by_unit, b, n, first) - cgroup_bonding_free(b); + cgroup_bonding_free(b, remove_or_trim); } void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) { @@ -225,6 +225,12 @@ int manager_setup_cgroup(Manager *m) { assert(m); + /* 0. Be nice to Ingo Molnar #628004 */ + if (path_is_mount_point("/sys/fs/cgroup/systemd") <= 0) { + log_warning("No control group support available, not creating root group."); + return 0; + } + /* 1. Determine hierarchy */ if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, ¤t)) < 0) { log_error("Cannot determine cgroup we are running in: %s", strerror(-r)); diff --git a/src/cgroup.h b/src/cgroup.h index a6ac90fb09..c6dff4313e 100644 --- a/src/cgroup.h +++ b/src/cgroup.h @@ -53,8 +53,8 @@ struct CGroupBonding { int cgroup_bonding_realize(CGroupBonding *b); int cgroup_bonding_realize_list(CGroupBonding *first); -void cgroup_bonding_free(CGroupBonding *b); -void cgroup_bonding_free_list(CGroupBonding *first); +void cgroup_bonding_free(CGroupBonding *b, bool remove_or_trim); +void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim); int cgroup_bonding_install(CGroupBonding *b, pid_t pid); int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid); diff --git a/src/cgroups-agent.c b/src/cgroups-agent.c index e0868b6137..7f001e67d1 100644 --- a/src/cgroups-agent.c +++ b/src/cgroups-agent.c @@ -43,7 +43,6 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - /* We send this event to the private D-Bus socket and then the * system instance will forward this to the system bus. We do * this to avoid an activation loop when we start dbus when we @@ -94,7 +93,6 @@ finish: dbus_connection_unref(bus); } - if (m) dbus_message_unref(m); diff --git a/src/cryptsetup-generator.c b/src/cryptsetup-generator.c index 00f48009ed..696f44ae36 100644 --- a/src/cryptsetup-generator.c +++ b/src/cryptsetup-generator.c @@ -33,6 +33,11 @@ static bool has_option(const char *haystack, const char *needle) { const char *f = haystack; size_t l; + assert(needle); + + if (!haystack) + return false; + l = strlen(needle); while ((f = strstr(f, needle))) { @@ -62,10 +67,14 @@ static int create_disk( char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL, *e = NULL; int r; FILE *f = NULL; + bool noauto, nofail; assert(name); assert(device); + noauto = has_option(options, "noauto"); + nofail = has_option(options, "nofail"); + if (!(n = unit_name_build_escape("cryptsetup", name, ".service"))) { r = -ENOMEM; log_error("Failed to allocate unit name."); @@ -99,12 +108,17 @@ static int create_disk( fprintf(f, "[Unit]\n" "Description=Cryptography Setup for %%I\n" + "Conflicts=umount.target\n" "DefaultDependencies=no\n" "BindTo=%s dev-mapper-%%i.device\n" "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n" - "Before=dev-mapper-%%i.device shutdown.target cryptsetup.target\n", + "Before=umount.target\n", d, d); + if (!nofail) + fprintf(f, + "Before=cryptsetup.target\n"); + if (password && (streq(password, "/dev/urandom") || streq(password, "/dev/random") || streq(password, "/dev/hw_random"))) @@ -115,19 +129,20 @@ static int create_disk( "\n[Service]\n" "Type=oneshot\n" "RemainAfterExit=yes\n" + "TimeoutSec=0\n" /* the binary handles timeouts anyway */ "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n" "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n", name, u, strempty(password), strempty(options), name); - if (options && has_option(options, "tmp")) + if (has_option(options, "tmp")) fprintf(f, - "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'", + "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n", name); - if (options && has_option(options, "swap")) + if (has_option(options, "swap")) fprintf(f, - "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'", + "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n", name); fflush(f); @@ -143,7 +158,7 @@ static int create_disk( goto fail; } - if (!options || !has_option(options, "noauto")) { + if (!noauto) { if (asprintf(&to, "%s/%s.wants/%s", arg_dest, d, n) < 0) { r = -ENOMEM; @@ -161,20 +176,22 @@ static int create_disk( free(to); to = NULL; - if (!options || !has_option(options, "nofail")) { + if (!nofail) + asprintf(&to, "%s/cryptsetup.target.requires/%s", arg_dest, n); + else + asprintf(&to, "%s/cryptsetup.target.wants/%s", arg_dest, n); - if (asprintf(&to, "%s/cryptsetup.target.wants/%s", arg_dest, n) < 0) { - r = -ENOMEM; - goto fail; - } + if (!to) { + r = -ENOMEM; + goto fail; + } - mkdir_parents(to, 0755); + mkdir_parents(to, 0755); - if (symlink(from, to) < 0) { - log_error("Failed to create symlink '%s' to '%s': %m", from, to); - r = -errno; - goto fail; - } + if (symlink(from, to) < 0) { + log_error("Failed to create symlink '%s' to '%s': %m", from, to); + r = -errno; + goto fail; } } diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 3aa822a1d0..4ef9606d39 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -40,7 +40,7 @@ static char *opt_hash = NULL; static unsigned opt_tries = 0; static bool opt_readonly = false; static bool opt_verify = false; -static usec_t opt_timeout = 0; +static usec_t opt_timeout = DEFAULT_TIMEOUT_USEC; /* Options Debian's crypttab knows we don't: @@ -309,7 +309,10 @@ int main(int argc, char *argv[]) { if (opt_readonly) flags |= CRYPT_ACTIVATE_READONLY; - until = now(CLOCK_MONOTONIC) + (opt_timeout > 0 ? opt_timeout : DEFAULT_TIMEOUT_USEC); + if (opt_timeout > 0) + until = now(CLOCK_MONOTONIC) + opt_timeout; + else + until = 0; opt_tries = opt_tries > 0 ? opt_tries : 3; opt_key_size = (opt_key_size > 0 ? opt_key_size : 256); @@ -404,6 +407,8 @@ int main(int argc, char *argv[]) { } } + k = 0; + if (!opt_type || streq(opt_type, CRYPT_LUKS1)) k = crypt_load(cd, CRYPT_LUKS1, NULL); diff --git a/src/dbus-automount.c b/src/dbus-automount.c index eccad37e8b..826842560d 100644 --- a/src/dbus-automount.c +++ b/src/dbus-automount.c @@ -21,6 +21,7 @@ #include "dbus-unit.h" #include "dbus-automount.h" +#include "dbus-common.h" #define BUS_AUTOMOUNT_INTERFACE \ " <interface name=\"org.freedesktop.systemd1.Automount\">\n" \ @@ -52,5 +53,5 @@ DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBus { NULL, NULL, NULL, NULL, NULL } }; - return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties); + return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); } diff --git a/src/dbus-common.c b/src/dbus-common.c index dcce10e552..b23373c5d1 100644 --- a/src/dbus-common.c +++ b/src/dbus-common.c @@ -26,11 +26,13 @@ #include <stdio.h> #include <stdlib.h> #include <dbus/dbus.h> +#include <string.h> #include "log.h" #include "dbus-common.h" #include "util.h" #include "def.h" +#include "strv.h" int bus_check_peercred(DBusConnection *c) { int fd; @@ -232,3 +234,448 @@ const char *bus_error_message(const DBusError *error) { return error->message; } + +DBusHandlerResult bus_default_message_handler( + DBusConnection *c, + DBusMessage *message, + const char *introspection, + const char *interfaces, + const BusProperty *properties) { + + DBusError error; + DBusMessage *reply = NULL; + int r; + + assert(c); + assert(message); + + dbus_error_init(&error); + + if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) { + + if (!(reply = dbus_message_new_method_return(message))) + goto oom; + + if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) + goto oom; + + } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && properties) { + const char *interface, *property; + const BusProperty *p; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &interface, + DBUS_TYPE_STRING, &property, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(c, message, &error, -EINVAL); + + for (p = properties; p->property; p++) + if (streq(p->interface, interface) && streq(p->property, property)) + break; + + if (p->property) { + DBusMessageIter iter, sub; + + if (!(reply = dbus_message_new_method_return(message))) + goto oom; + + dbus_message_iter_init_append(reply, &iter); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub)) + goto oom; + + if ((r = p->append(&sub, property, (void*) p->data)) < 0) { + + if (r == -ENOMEM) + goto oom; + + dbus_message_unref(reply); + return bus_send_error_reply(c, message, NULL, r); + } + + if (!dbus_message_iter_close_container(&iter, &sub)) + goto oom; + } else { + if (!nulstr_contains(interfaces, interface)) + dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); + else + dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); + + return bus_send_error_reply(c, message, &error, -EINVAL); + } + + } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && properties) { + const char *interface; + const BusProperty *p; + DBusMessageIter iter, sub, sub2, sub3; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &interface, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(c, message, &error, -EINVAL); + + if (interface[0] && !nulstr_contains(interfaces, interface)) { + dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); + return bus_send_error_reply(c, message, &error, -EINVAL); + } + + if (!(reply = dbus_message_new_method_return(message))) + goto oom; + + dbus_message_iter_init_append(reply, &iter); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub)) + goto oom; + + for (p = properties; p->property; p++) { + if (interface[0] && !streq(p->interface, interface)) + continue; + + if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) || + !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) || + !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3)) + goto oom; + + if ((r = p->append(&sub3, p->property, (void*) p->data)) < 0) { + + if (r == -ENOMEM) + goto oom; + + dbus_message_unref(reply); + return bus_send_error_reply(c, message, NULL, r); + } + + if (!dbus_message_iter_close_container(&sub2, &sub3) || + !dbus_message_iter_close_container(&sub, &sub2)) + goto oom; + } + + if (!dbus_message_iter_close_container(&iter, &sub)) + goto oom; + + } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && properties) { + const char *interface, *property; + DBusMessageIter iter; + const BusProperty *p; + + if (!dbus_message_iter_init(message, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return bus_send_error_reply(c, message, NULL, -EINVAL); + + dbus_message_iter_get_basic(&iter, &interface); + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return bus_send_error_reply(c, message, NULL, -EINVAL); + + dbus_message_iter_get_basic(&iter, &property); + + if (!dbus_message_iter_next(&iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT || + dbus_message_iter_has_next(&iter)) + return bus_send_error_reply(c, message, NULL, -EINVAL); + + for (p = properties; p->property; p++) + if (streq(p->interface, interface) && streq(p->property, property)) + break; + + if (p->set) { + DBusMessageIter sub; + char *sig; + + dbus_message_iter_recurse(&iter, &sub); + + if (!(sig = dbus_message_iter_get_signature(&sub))) + goto oom; + + if (!streq(sig, p->signature)) { + dbus_free(sig); + return bus_send_error_reply(c, message, NULL, -EINVAL); + } + + dbus_free(sig); + + if ((r = p->set(&sub, property)) < 0) { + if (r == -ENOMEM) + goto oom; + return bus_send_error_reply(c, message, NULL, r); + } + + if (!(reply = dbus_message_new_method_return(message))) + goto oom; + } else { + if (p->property) + dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only"); + else if (!nulstr_contains(interfaces, interface)) + dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); + else + dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); + + return bus_send_error_reply(c, message, &error, -EINVAL); + } + + } else if (!nulstr_contains(interfaces, dbus_message_get_interface(message))) { + dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); + return bus_send_error_reply(c, message, &error, -EINVAL); + } + + if (reply) { + if (!dbus_connection_send(c, reply, NULL)) + goto oom; + + dbus_message_unref(reply); + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + +oom: + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return DBUS_HANDLER_RESULT_NEED_MEMORY; +} + +int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) { + const char *t = data; + + assert(i); + assert(property); + + if (!t) + t = ""; + + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) + return -ENOMEM; + + return 0; +} + +int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) { + DBusMessageIter sub; + char **t = data; + + assert(i); + assert(property); + + if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub)) + return -ENOMEM; + + STRV_FOREACH(t, t) + if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t)) + return -ENOMEM; + + if (!dbus_message_iter_close_container(i, &sub)) + return -ENOMEM; + + return 0; +} + +int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) { + bool *b = data; + dbus_bool_t db; + + assert(i); + assert(property); + assert(b); + + db = *b; + + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db)) + return -ENOMEM; + + return 0; +} + +int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) { + assert(i); + assert(property); + assert(data); + + /* Let's ensure that pid_t is actually 64bit, and hence this + * function can be used for usec_t */ + assert_cc(sizeof(uint64_t) == sizeof(usec_t)); + + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data)) + return -ENOMEM; + + return 0; +} + +int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) { + assert(i); + assert(property); + assert(data); + + /* Let's ensure that pid_t and mode_t is actually 32bit, and + * hence this function can be used for pid_t/mode_t */ + assert_cc(sizeof(uint32_t) == sizeof(pid_t)); + assert_cc(sizeof(uint32_t) == sizeof(mode_t)); + assert_cc(sizeof(uint32_t) == sizeof(unsigned)); + + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data)) + return -ENOMEM; + + return 0; +} + +int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) { + assert(i); + assert(property); + assert(data); + + assert_cc(sizeof(int32_t) == sizeof(int)); + + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data)) + return -ENOMEM; + + return 0; +} + +int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) { + uint64_t u; + + assert(i); + assert(property); + assert(data); + + u = (uint64_t) *(size_t*) data; + + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) + return -ENOMEM; + + return 0; +} + +int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) { + uint64_t u; + + assert(i); + assert(property); + assert(data); + + u = (uint64_t) *(unsigned long*) data; + + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) + return -ENOMEM; + + return 0; +} + +const char *bus_errno_to_dbus(int error) { + + switch(error) { + + case -EINVAL: + return DBUS_ERROR_INVALID_ARGS; + + case -ENOMEM: + return DBUS_ERROR_NO_MEMORY; + + case -EPERM: + case -EACCES: + return DBUS_ERROR_ACCESS_DENIED; + + case -ESRCH: + return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN; + + case -ENOENT: + return DBUS_ERROR_FILE_NOT_FOUND; + + case -EEXIST: + return DBUS_ERROR_FILE_EXISTS; + + case -ETIMEDOUT: + case -ETIME: + return DBUS_ERROR_TIMEOUT; + + case -EIO: + return DBUS_ERROR_IO_ERROR; + + case -ENETRESET: + case -ECONNABORTED: + case -ECONNRESET: + return DBUS_ERROR_DISCONNECTED; + } + + return DBUS_ERROR_FAILED; +} + +DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) { + DBusMessage *reply = NULL; + const char *name, *text; + + if (berror && dbus_error_is_set(berror)) { + name = berror->name; + text = berror->message; + } else { + name = bus_errno_to_dbus(error); + text = strerror(-error); + } + + if (!(reply = dbus_message_new_error(message, name, text))) + goto oom; + + if (!dbus_connection_send(c, reply, NULL)) + goto oom; + + dbus_message_unref(reply); + + if (berror) + dbus_error_free(berror); + + return DBUS_HANDLER_RESULT_HANDLED; + +oom: + if (reply) + dbus_message_unref(reply); + + if (berror) + dbus_error_free(berror); + + return DBUS_HANDLER_RESULT_NEED_MEMORY; +} + +DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) { + DBusMessage *m; + DBusMessageIter iter, sub; + const char *i; + + assert(interface); + assert(properties); + + if (!(m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"))) + goto oom; + + dbus_message_iter_init_append(m, &iter); + + /* We won't send any property values, since they might be + * large and sometimes not cheap to generated */ + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) || + !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) || + !dbus_message_iter_close_container(&iter, &sub) || + !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) + goto oom; + + NULSTR_FOREACH(i, properties) + if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i)) + goto oom; + + if (!dbus_message_iter_close_container(&iter, &sub)) + goto oom; + + return m; + +oom: + if (m) + dbus_message_unref(m); + + return NULL; +} diff --git a/src/dbus-common.h b/src/dbus-common.h index 76333cd4f6..729519c526 100644 --- a/src/dbus-common.h +++ b/src/dbus-common.h @@ -24,6 +24,65 @@ #include <dbus/dbus.h> +#ifndef DBUS_ERROR_UNKNOWN_OBJECT +#define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject" +#endif + +#ifndef DBUS_ERROR_UNKNOWN_INTERFACE +#define DBUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface" +#endif + +#ifndef DBUS_ERROR_UNKNOWN_PROPERTY +#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty" +#endif + +#ifndef DBUS_ERROR_PROPERTY_READ_ONLY +#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly" +#endif + +#define BUS_PROPERTIES_INTERFACE \ + " <interface name=\"org.freedesktop.DBus.Properties\">\n" \ + " <method name=\"Get\">\n" \ + " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ + " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \ + " <arg name=\"value\" direction=\"out\" type=\"v\"/>\n" \ + " </method>\n" \ + " <method name=\"GetAll\">\n" \ + " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ + " <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \ + " </method>\n" \ + " <method name=\"Set\">\n" \ + " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ + " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \ + " <arg name=\"value\" direction=\"in\" type=\"v\"/>\n" \ + " </method>\n" \ + " <signal name=\"PropertiesChanged\">\n" \ + " <arg type=\"s\" name=\"interface\"/>\n" \ + " <arg type=\"a{sv}\" name=\"changed_properties\"/>\n" \ + " <arg type=\"as\" name=\"invalidated_properties\"/>\n" \ + " </signal>\n" \ + " </interface>\n" + +#define BUS_INTROSPECTABLE_INTERFACE \ + " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \ + " <method name=\"Introspect\">\n" \ + " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \ + " </method>\n" \ + " </interface>\n" + +#define BUS_PEER_INTERFACE \ + "<interface name=\"org.freedesktop.DBus.Peer\">\n" \ + " <method name=\"Ping\"/>\n" \ + " <method name=\"GetMachineId\">\n" \ + " <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \ + " </method>\n" \ + "</interface>\n" + +#define BUS_GENERIC_INTERFACES_LIST \ + "org.freedesktop.DBus.Properties\0" \ + "org.freedesktop.DBus.Introspectable\0" \ + "org.freedesktop.DBus.Peer\0" + int bus_check_peercred(DBusConnection *c); int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private_bus, DBusError *error); @@ -33,4 +92,64 @@ int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error); const char *bus_error_message(const DBusError *error); +typedef int (*BusPropertyCallback)(DBusMessageIter *iter, const char *property, void *data); +typedef int (*BusPropertySetCallback)(DBusMessageIter *iter, const char *property); + +typedef struct BusProperty { + const char *interface; /* interface of the property */ + const char *property; /* name of the property */ + BusPropertyCallback append; /* Function that is called to serialize this property */ + const char *signature; + const void *data; /* The data of this property */ + BusPropertySetCallback set; /* Optional: Function that is called to set this property */ +} BusProperty; + +DBusHandlerResult bus_send_error_reply( + DBusConnection *c, + DBusMessage *message, + DBusError *bus_error, + int error); + +DBusHandlerResult bus_default_message_handler( + DBusConnection *c, + DBusMessage *message, + const char *introspection, + const char *interfaces, + const BusProperty *properties); + +int bus_property_append_string(DBusMessageIter *i, const char *property, void *data); +int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data); +int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data); +int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data); +int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data); +int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data); +int bus_property_append_size(DBusMessageIter *i, const char *property, void *data); +int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data); + +#define bus_property_append_int bus_property_append_int32 +#define bus_property_append_pid bus_property_append_uint32 +#define bus_property_append_mode bus_property_append_uint32 +#define bus_property_append_unsigned bus_property_append_uint32 +#define bus_property_append_usec bus_property_append_uint64 + +#define DEFINE_BUS_PROPERTY_APPEND_ENUM(function,name,type) \ + int function(DBusMessageIter *i, const char *property, void *data) { \ + const char *value; \ + type *field = data; \ + \ + assert(i); \ + assert(property); \ + \ + value = name##_to_string(*field); \ + \ + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &value)) \ + return -ENOMEM; \ + \ + return 0; \ + } + +const char *bus_errno_to_dbus(int error); + +DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties); + #endif diff --git a/src/dbus-device.c b/src/dbus-device.c index b046eae9f7..f85ad2daf8 100644 --- a/src/dbus-device.c +++ b/src/dbus-device.c @@ -21,6 +21,7 @@ #include "dbus-unit.h" #include "dbus-device.h" +#include "dbus-common.h" #define BUS_DEVICE_INTERFACE \ " <interface name=\"org.freedesktop.systemd1.Device\">\n" \ @@ -53,5 +54,5 @@ DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMes { NULL, NULL, NULL, NULL, NULL } }; - return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties); + return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); } diff --git a/src/dbus-execute.c b/src/dbus-execute.c index 35e6d377ee..3f8fafe6cd 100644 --- a/src/dbus-execute.c +++ b/src/dbus-execute.c @@ -27,17 +27,17 @@ #include "missing.h" #include "ioprio.h" #include "strv.h" +#include "dbus-common.h" DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_kill_mode, kill_mode, KillMode); DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput); DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput); -int bus_execute_append_env_files(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) { char **env_files = data, **j; DBusMessageIter sub, sub2; - assert(m); assert(i); assert(property); @@ -66,11 +66,10 @@ int bus_execute_append_env_files(Manager *m, DBusMessageIter *i, const char *pro return 0; } -int bus_execute_append_oom_score_adjust(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) { ExecContext *c = data; int32_t n; - assert(m); assert(i); assert(property); assert(c); @@ -101,11 +100,10 @@ int bus_execute_append_oom_score_adjust(Manager *m, DBusMessageIter *i, const ch return 0; } -int bus_execute_append_nice(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) { ExecContext *c = data; int32_t n; - assert(m); assert(i); assert(property); assert(c); @@ -121,11 +119,10 @@ int bus_execute_append_nice(Manager *m, DBusMessageIter *i, const char *property return 0; } -int bus_execute_append_ioprio(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) { ExecContext *c = data; int32_t n; - assert(m); assert(i); assert(property); assert(c); @@ -141,11 +138,10 @@ int bus_execute_append_ioprio(Manager *m, DBusMessageIter *i, const char *proper return 0; } -int bus_execute_append_cpu_sched_policy(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) { ExecContext *c = data; int32_t n; - assert(m); assert(i); assert(property); assert(c); @@ -161,11 +157,10 @@ int bus_execute_append_cpu_sched_policy(Manager *m, DBusMessageIter *i, const ch return 0; } -int bus_execute_append_cpu_sched_priority(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) { ExecContext *c = data; int32_t n; - assert(m); assert(i); assert(property); assert(c); @@ -187,12 +182,11 @@ int bus_execute_append_cpu_sched_priority(Manager *m, DBusMessageIter *i, const return 0; } -int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) { ExecContext *c = data; dbus_bool_t b; DBusMessageIter sub; - assert(m); assert(i); assert(property); assert(c); @@ -214,11 +208,10 @@ int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *prop return 0; } -int bus_execute_append_timer_slack_nsec(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) { ExecContext *c = data; uint64_t u; - assert(m); assert(i); assert(property); assert(c); @@ -234,11 +227,10 @@ int bus_execute_append_timer_slack_nsec(Manager *m, DBusMessageIter *i, const ch return 0; } -int bus_execute_append_capability_bs(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) { ExecContext *c = data; uint64_t normal, inverted; - assert(m); assert(i); assert(property); assert(c); @@ -249,16 +241,15 @@ int bus_execute_append_capability_bs(Manager *m, DBusMessageIter *i, const char normal = *(uint64_t*) data; inverted = ~normal; - return bus_property_append_uint64(m, i, property, &inverted); + return bus_property_append_uint64(i, property, &inverted); } -int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) { ExecContext *c = data; char *t = NULL; const char *s; dbus_bool_t b; - assert(m); assert(i); assert(property); assert(c); @@ -282,12 +273,11 @@ int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char * return 0; } -int bus_execute_append_rlimits(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) { ExecContext *c = data; int r; uint64_t u; - assert(m); assert(i); assert(property); assert(c); @@ -311,11 +301,10 @@ int bus_execute_append_rlimits(Manager *m, DBusMessageIter *i, const char *prope return 0; } -int bus_execute_append_command(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_execute_append_command(DBusMessageIter *i, const char *property, void *data) { ExecCommand *c = data; DBusMessageIter sub, sub2, sub3; - assert(m); assert(i); assert(property); @@ -346,7 +335,9 @@ int bus_execute_append_command(Manager *m, DBusMessageIter *i, const char *prope if (!dbus_message_iter_close_container(&sub2, &sub3) || !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &c->ignore) || !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) || + !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.monotonic) || !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) || + !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.monotonic) || !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid) || !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &code) || !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &status)) diff --git a/src/dbus-execute.h b/src/dbus-execute.h index 8bfaaaf120..ed66390d0b 100644 --- a/src/dbus-execute.h +++ b/src/dbus-execute.h @@ -28,7 +28,9 @@ #define BUS_EXEC_STATUS_INTERFACE(prefix) \ " <property name=\"" prefix "StartTimestamp\" type=\"t\" access=\"read\"/>\n" \ + " <property name=\"" prefix "StartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ " <property name=\"" prefix "ExitTimestamp\" type=\"t\" access=\"read\"/>\n" \ + " <property name=\"" prefix "ExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ " <property name=\"" prefix "PID\" type=\"u\" access=\"read\"/>\n" \ " <property name=\"" prefix "Code\" type=\"i\" access=\"read\"/>\n" \ " <property name=\"" prefix "Status\" type=\"i\" access=\"read\"/>\n" @@ -149,28 +151,30 @@ #define BUS_EXEC_STATUS_PROPERTIES(interface, estatus, prefix) \ { interface, prefix "StartTimestamp", bus_property_append_usec, "t", &(estatus).start_timestamp.realtime }, \ + { interface, prefix "StartTimestampMonotonic",bus_property_append_usec, "t", &(estatus).start_timestamp.monotonic }, \ { interface, prefix "ExitTimestamp", bus_property_append_usec, "t", &(estatus).start_timestamp.realtime }, \ + { interface, prefix "ExitTimestampMonotonic", bus_property_append_usec, "t", &(estatus).start_timestamp.monotonic }, \ { interface, prefix "PID", bus_property_append_pid, "u", &(estatus).pid }, \ { interface, prefix "Code", bus_property_append_int, "i", &(estatus).code }, \ { interface, prefix "Status", bus_property_append_int, "i", &(estatus).status } #define BUS_EXEC_COMMAND_PROPERTY(interface, command, name) \ - { interface, name, bus_execute_append_command, "a(sasbttuii)", (command) } - -int bus_execute_append_output(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_input(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_oom_score_adjust(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_nice(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_ioprio(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_cpu_sched_policy(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_cpu_sched_priority(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_timer_slack_nsec(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_capability_bs(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_rlimits(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_command(Manager *m, DBusMessageIter *u, const char *property, void *data); -int bus_execute_append_kill_mode(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_execute_append_env_files(Manager *m, DBusMessageIter *i, const char *property, void *data); + { interface, name, bus_execute_append_command, "a(sasbttttuii)", (command) } + +int bus_execute_append_output(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_input(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data); +int bus_execute_append_kill_mode(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data); #endif diff --git a/src/dbus-job.c b/src/dbus-job.c index 908ddba537..2308be34fd 100644 --- a/src/dbus-job.c +++ b/src/dbus-job.c @@ -24,6 +24,7 @@ #include "dbus.h" #include "log.h" #include "dbus-job.h" +#include "dbus-common.h" #define BUS_JOB_INTERFACE \ " <interface name=\"org.freedesktop.systemd1.Job\">\n" \ @@ -55,12 +56,11 @@ const char bus_job_interface[] _introspect_("Job") = BUS_JOB_INTERFACE; static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_state, job_state, JobState); static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_type, job_type, JobType); -static int bus_job_append_unit(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_job_append_unit(DBusMessageIter *i, const char *property, void *data) { Job *j = data; DBusMessageIter sub; char *p; - assert(m); assert(i); assert(property); assert(j); @@ -103,7 +103,7 @@ static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusConnection *connec job_finish_and_invalidate(j, JOB_CANCELED); } else - return bus_default_message_handler(j->manager, connection, message, INTROSPECTION, INTERFACES_LIST, properties); + return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); if (reply) { if (!dbus_connection_send(connection, reply, NULL)) @@ -201,10 +201,10 @@ static DBusHandlerResult bus_job_message_handler(DBusConnection *connection, DBu dbus_error_init(&e); dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown job"); - return bus_send_error_reply(m, connection, message, &e, r); + return bus_send_error_reply(connection, message, &e, r); } - return bus_send_error_reply(m, connection, message, NULL, r); + return bus_send_error_reply(connection, message, NULL, r); } return bus_job_message_dispatch(j, connection, message); diff --git a/src/dbus-manager.c b/src/dbus-manager.c index 2f755bcc64..4224afaccb 100644 --- a/src/dbus-manager.c +++ b/src/dbus-manager.c @@ -28,6 +28,7 @@ #include "strv.h" #include "bus-errors.h" #include "build.h" +#include "dbus-common.h" #define BUS_MANAGER_INTERFACE_BEGIN \ " <interface name=\"org.freedesktop.systemd1.Manager\">\n" @@ -155,8 +156,11 @@ " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \ " <property name=\"RunningAs\" type=\"s\" access=\"read\"/>\n" \ " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \ + " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ " <property name=\"StartupTimestamp\" type=\"t\" access=\"read\"/>\n" \ + " <property name=\"StartupTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \ + " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \ " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \ " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \ @@ -216,13 +220,14 @@ const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFA static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as, manager_running_as, ManagerRunningAs); static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput); -static int bus_manager_append_tainted(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) { const char *t; - char buf[64] = "", *e = buf, *p = NULL; + Manager *m = data; + char buf[LINE_MAX] = "", *e = buf, *p = NULL; - assert(m); assert(i); assert(property); + assert(m); if (m->taint_usr) e = stpcpy(e, "usr-separate-fs "); @@ -243,10 +248,9 @@ static int bus_manager_append_tainted(Manager *m, DBusMessageIter *i, const char return 0; } -static int bus_manager_append_log_target(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) { const char *t; - assert(m); assert(i); assert(property); @@ -258,10 +262,9 @@ static int bus_manager_append_log_target(Manager *m, DBusMessageIter *i, const c return 0; } -static int bus_manager_set_log_target(Manager *m, DBusMessageIter *i, const char *property) { +static int bus_manager_set_log_target(DBusMessageIter *i, const char *property) { const char *t; - assert(m); assert(i); assert(property); @@ -270,10 +273,9 @@ static int bus_manager_set_log_target(Manager *m, DBusMessageIter *i, const char return log_set_target_from_string(t); } -static int bus_manager_append_log_level(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) { const char *t; - assert(m); assert(i); assert(property); @@ -285,10 +287,9 @@ static int bus_manager_append_log_level(Manager *m, DBusMessageIter *i, const ch return 0; } -static int bus_manager_set_log_level(Manager *m, DBusMessageIter *i, const char *property) { +static int bus_manager_set_log_level(DBusMessageIter *i, const char *property) { const char *t; - assert(m); assert(i); assert(property); @@ -297,12 +298,13 @@ static int bus_manager_set_log_level(Manager *m, DBusMessageIter *i, const char return log_set_max_level_from_string(t); } -static int bus_manager_append_n_names(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) { + Manager *m = data; uint32_t u; - assert(m); assert(i); assert(property); + assert(m); u = hashmap_size(m->units); @@ -312,12 +314,13 @@ static int bus_manager_append_n_names(Manager *m, DBusMessageIter *i, const char return 0; } -static int bus_manager_append_n_jobs(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) { + Manager *m = data; uint32_t u; - assert(m); assert(i); assert(property); + assert(m); u = hashmap_size(m->jobs); @@ -327,12 +330,13 @@ static int bus_manager_append_n_jobs(Manager *m, DBusMessageIter *i, const char return 0; } -static int bus_manager_append_progress(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) { double d; + Manager *m = data; - assert(m); assert(i); assert(property); + assert(m); if (dual_timestamp_is_set(&m->finish_timestamp)) d = 1.0; @@ -369,15 +373,18 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, { "org.freedesktop.systemd1.Manager", "RunningAs", bus_manager_append_running_as, "s", &m->running_as }, { "org.freedesktop.systemd1.Manager", "Tainted", bus_manager_append_tainted, "s", m }, { "org.freedesktop.systemd1.Manager", "InitRDTimestamp", bus_property_append_uint64, "t", &m->initrd_timestamp.realtime }, + { "org.freedesktop.systemd1.Manager", "InitRDTimestampMonotonic", bus_property_append_uint64, "t", &m->initrd_timestamp.monotonic }, { "org.freedesktop.systemd1.Manager", "StartupTimestamp", bus_property_append_uint64, "t", &m->startup_timestamp.realtime }, + { "org.freedesktop.systemd1.Manager", "StartupTimestampMonotonic", bus_property_append_uint64, "t", &m->startup_timestamp.monotonic }, { "org.freedesktop.systemd1.Manager", "FinishTimestamp", bus_property_append_uint64, "t", &m->finish_timestamp.realtime }, - { "org.freedesktop.systemd1.Manager", "LogLevel", bus_manager_append_log_level, "s", NULL, bus_manager_set_log_level}, - { "org.freedesktop.systemd1.Manager", "LogTarget", bus_manager_append_log_target, "s", NULL, bus_manager_set_log_target}, - { "org.freedesktop.systemd1.Manager", "NNames", bus_manager_append_n_names, "u", NULL }, + { "org.freedesktop.systemd1.Manager", "FinishTimestampMonotonic", bus_property_append_uint64, "t",&m->finish_timestamp.monotonic }, + { "org.freedesktop.systemd1.Manager", "LogLevel", bus_manager_append_log_level, "s", m, bus_manager_set_log_level }, + { "org.freedesktop.systemd1.Manager", "LogTarget", bus_manager_append_log_target, "s", m, bus_manager_set_log_target }, + { "org.freedesktop.systemd1.Manager", "NNames", bus_manager_append_n_names, "u", m }, { "org.freedesktop.systemd1.Manager", "NJobs", bus_manager_append_n_jobs, "u", NULL }, { "org.freedesktop.systemd1.Manager", "NInstalledJobs",bus_property_append_uint32, "u", &m->n_installed_jobs }, { "org.freedesktop.systemd1.Manager", "NFailedJobs", bus_property_append_uint32, "u", &m->n_failed_jobs }, - { "org.freedesktop.systemd1.Manager", "Progress", bus_manager_append_progress, "d", NULL }, + { "org.freedesktop.systemd1.Manager", "Progress", bus_manager_append_progress, "d", m }, { "org.freedesktop.systemd1.Manager", "Environment", bus_property_append_strv, "as", m->environment }, { "org.freedesktop.systemd1.Manager", "ConfirmSpawn", bus_property_append_bool, "b", &m->confirm_spawn }, { "org.freedesktop.systemd1.Manager", "ShowStatus", bus_property_append_bool, "b", &m->show_status }, @@ -419,11 +426,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if (!(u = manager_get_unit(m, name))) { dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - return bus_send_error_reply(m, connection, message, &error, -ENOENT); + return bus_send_error_reply(connection, message, &error, -ENOENT); } if (!(reply = dbus_message_new_method_return(message))) @@ -446,11 +453,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, &error, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID)) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) { dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid); - return bus_send_error_reply(m, connection, message, &error, -ENOENT); + return bus_send_error_reply(connection, message, &error, -ENOENT); } if (!(reply = dbus_message_new_method_return(message))) @@ -473,10 +480,10 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0) - return bus_send_error_reply(m, connection, message, &error, r); + return bus_send_error_reply(connection, message, &error, r); if (!(reply = dbus_message_new_method_return(message))) goto oom; @@ -523,21 +530,21 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBUS_TYPE_STRING, &smode, DBUS_TYPE_INT32, &signo, DBUS_TYPE_INVALID)) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if ((mode = kill_mode_from_string(smode)) < 0 || (who = kill_who_from_string(swho)) < 0 || signo <= 0 || signo >= _NSIG) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if (!(u = manager_get_unit(m, name))) { dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - return bus_send_error_reply(m, connection, message, &error, -ENOENT); + return bus_send_error_reply(connection, message, &error, -ENOENT); } if ((r = unit_kill(u, who, mode, signo, &error)) < 0) - return bus_send_error_reply(m, connection, message, &error, r); + return bus_send_error_reply(connection, message, &error, r); if (!(reply = dbus_message_new_method_return(message))) goto oom; @@ -551,11 +558,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, &error, DBUS_TYPE_UINT32, &id, DBUS_TYPE_INVALID)) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if (!(j = manager_get_job(m, id))) { dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id); - return bus_send_error_reply(m, connection, message, &error, -ENOENT); + return bus_send_error_reply(connection, message, &error, -ENOENT); } if (!(reply = dbus_message_new_method_return(message))) @@ -593,11 +600,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if (!(u = manager_get_unit(m, name))) { dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); - return bus_send_error_reply(m, connection, message, &error, -ENOENT); + return bus_send_error_reply(connection, message, &error, -ENOENT); } unit_reset_failed(u); @@ -759,7 +766,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, if ((r = set_put(s, client)) < 0) { free(client); - return bus_send_error_reply(m, connection, message, NULL, r); + return bus_send_error_reply(connection, message, NULL, r); } if (!(reply = dbus_message_new_method_return(message))) @@ -770,7 +777,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, if (!(client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) { dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed."); - return bus_send_error_reply(m, connection, message, &error, -ENOENT); + return bus_send_error_reply(connection, message, &error, -ENOENT); } free(client); @@ -817,13 +824,13 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBUS_TYPE_STRING, &name, DBUS_TYPE_BOOLEAN, &cleanup, DBUS_TYPE_INVALID)) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if (name && name[0] == 0) name = NULL; if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0) - return bus_send_error_reply(m, connection, message, &error, r); + return bus_send_error_reply(connection, message, &error, r); if (!(reply = dbus_message_new_method_return(message))) goto oom; @@ -924,7 +931,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, if (m->running_as == MANAGER_SYSTEM) { dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers."); - return bus_send_error_reply(m, connection, message, &error, -ENOTSUP); + return bus_send_error_reply(connection, message, &error, -ENOTSUP); } if (!(reply = dbus_message_new_method_return(message))) @@ -936,7 +943,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, if (m->running_as != MANAGER_SYSTEM) { dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers."); - return bus_send_error_reply(m, connection, message, &error, -ENOTSUP); + return bus_send_error_reply(connection, message, &error, -ENOTSUP); } if (!(reply = dbus_message_new_method_return(message))) @@ -948,7 +955,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, if (m->running_as != MANAGER_SYSTEM) { dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers."); - return bus_send_error_reply(m, connection, message, &error, -ENOTSUP); + return bus_send_error_reply(connection, message, &error, -ENOTSUP); } if (!(reply = dbus_message_new_method_return(message))) @@ -960,7 +967,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, if (m->running_as != MANAGER_SYSTEM) { dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers."); - return bus_send_error_reply(m, connection, message, &error, -ENOTSUP); + return bus_send_error_reply(connection, message, &error, -ENOTSUP); } if (!(reply = dbus_message_new_method_return(message))) @@ -972,7 +979,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, if (m->running_as != MANAGER_SYSTEM) { dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers."); - return bus_send_error_reply(m, connection, message, &error, -ENOTSUP); + return bus_send_error_reply(connection, message, &error, -ENOTSUP); } if (!(reply = dbus_message_new_method_return(message))) @@ -987,7 +994,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, if (r == -ENOMEM) goto oom; - return bus_send_error_reply(m, connection, message, NULL, r); + return bus_send_error_reply(connection, message, NULL, r); } e = strv_env_merge(2, m->environment, l); @@ -1011,7 +1018,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, if (r == -ENOMEM) goto oom; - return bus_send_error_reply(m, connection, message, NULL, r); + return bus_send_error_reply(connection, message, NULL, r); } e = strv_env_delete(m->environment, 1, l); @@ -1029,7 +1036,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, m->environment = e; } else - return bus_default_message_handler(m, connection, message, NULL, INTERFACES_LIST, properties); + return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, properties); if (job_type != _JOB_TYPE_INVALID) { const char *name, *smode, *old_name = NULL; @@ -1055,24 +1062,24 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBUS_TYPE_INVALID); if (!b) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if (old_name) if (!(u = manager_get_unit(m, old_name)) || !u->meta.job || u->meta.job->type != JOB_START) { dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name); - return bus_send_error_reply(m, connection, message, &error, -ENOENT); + return bus_send_error_reply(connection, message, &error, -ENOENT); } if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) { dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode); - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); } if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0) - return bus_send_error_reply(m, connection, message, &error, r); + return bus_send_error_reply(connection, message, &error, r); if (reload_if_possible && unit_can_reload(u)) { if (job_type == JOB_RESTART) @@ -1086,11 +1093,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) && (u->meta.refuse_manual_start || u->meta.refuse_manual_stop))) { dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only."); - return bus_send_error_reply(m, connection, message, &error, -EPERM); + return bus_send_error_reply(connection, message, &error, -EPERM); } if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0) - return bus_send_error_reply(m, connection, message, &error, r); + return bus_send_error_reply(connection, message, &error, r); if (!(j->bus_client = strdup(message_get_sender_with_fallback(message)))) goto oom; diff --git a/src/dbus-mount.c b/src/dbus-mount.c index 5fb9a3f071..cfbfd4531c 100644 --- a/src/dbus-mount.c +++ b/src/dbus-mount.c @@ -24,6 +24,7 @@ #include "dbus-unit.h" #include "dbus-mount.h" #include "dbus-execute.h" +#include "dbus-common.h" #define BUS_MOUNT_INTERFACE \ " <interface name=\"org.freedesktop.systemd1.Mount\">\n" \ @@ -65,11 +66,10 @@ const char bus_mount_invalidating_properties[] = "ExecRemount\0" "ControlPID\0"; -static int bus_mount_append_what(Manager *n, DBusMessageIter *i, const char *property, void *data) { +static int bus_mount_append_what(DBusMessageIter *i, const char *property, void *data) { Mount *m = data; const char *d; - assert(n); assert(i); assert(property); assert(m); @@ -89,11 +89,10 @@ static int bus_mount_append_what(Manager *n, DBusMessageIter *i, const char *pro return 0; } -static int bus_mount_append_options(Manager *n, DBusMessageIter *i, const char *property, void *data) { +static int bus_mount_append_options(DBusMessageIter *i, const char *property, void *data) { Mount *m = data; const char *d; - assert(n); assert(i); assert(property); assert(m); @@ -113,11 +112,10 @@ static int bus_mount_append_options(Manager *n, DBusMessageIter *i, const char * return 0; } -static int bus_mount_append_type(Manager *n, DBusMessageIter *i, const char *property, void *data) { +static int bus_mount_append_type(DBusMessageIter *i, const char *property, void *data) { Mount *m = data; const char *d; - assert(n); assert(i); assert(property); assert(m); @@ -138,6 +136,7 @@ static int bus_mount_append_type(Manager *n, DBusMessageIter *i, const char *pro } DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { + const BusProperty properties[] = { BUS_UNIT_PROPERTIES, { "org.freedesktop.systemd1.Mount", "Where", bus_property_append_string, "s", u->mount.where }, @@ -154,5 +153,5 @@ DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMess { NULL, NULL, NULL, NULL, NULL } }; - return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties); + return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); } diff --git a/src/dbus-path.c b/src/dbus-path.c index cb1d4f09cb..15238798ae 100644 --- a/src/dbus-path.c +++ b/src/dbus-path.c @@ -24,11 +24,14 @@ #include "dbus-unit.h" #include "dbus-path.h" #include "dbus-execute.h" +#include "dbus-common.h" #define BUS_PATH_INTERFACE \ " <interface name=\"org.freedesktop.systemd1.Path\">\n" \ " <property name=\"Unit\" type=\"s\" access=\"read\"/>\n" \ " <property name=\"Paths\" type=\"a(ss)\" access=\"read\"/>\n" \ + " <property name=\"MakeDirectory\" type=\"b\" access=\"read\"/>\n" \ + " <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \ " </interface>\n" #define INTROSPECTION \ @@ -47,12 +50,11 @@ const char bus_path_interface[] _introspect_("Path") = BUS_PATH_INTERFACE; -static int bus_path_append_paths(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_path_append_paths(DBusMessageIter *i, const char *property, void *data) { Path *p = data; DBusMessageIter sub, sub2; PathSpec *k; - assert(m); assert(i); assert(property); assert(p); @@ -76,11 +78,10 @@ static int bus_path_append_paths(Manager *m, DBusMessageIter *i, const char *pro return 0; } -static int bus_path_append_unit(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_path_append_unit(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; const char *t; - assert(m); assert(i); assert(property); assert(u); @@ -93,10 +94,12 @@ static int bus_path_append_unit(Manager *m, DBusMessageIter *i, const char *prop DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { const BusProperty properties[] = { BUS_UNIT_PROPERTIES, - { "org.freedesktop.systemd1.Path", "Unit", bus_path_append_unit, "s", u }, - { "org.freedesktop.systemd1.Path", "Paths", bus_path_append_paths, "a(ss)", u }, + { "org.freedesktop.systemd1.Path", "Unit", bus_path_append_unit, "s", u }, + { "org.freedesktop.systemd1.Path", "Paths", bus_path_append_paths, "a(ss)", u }, + { "org.freedesktop.systemd1.Path", "MakeDirectory", bus_property_append_bool, "b", &u->path.make_directory }, + { "org.freedesktop.systemd1.Path", "DirectoryMode", bus_property_append_mode, "u", &u->path.directory_mode }, { NULL, NULL, NULL, NULL, NULL } }; - return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties); + return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); } diff --git a/src/dbus-service.c b/src/dbus-service.c index 9c3d73cbf2..3486623e59 100644 --- a/src/dbus-service.c +++ b/src/dbus-service.c @@ -24,6 +24,7 @@ #include "dbus-unit.h" #include "dbus-execute.h" #include "dbus-service.h" +#include "dbus-common.h" #ifdef HAVE_SYSV_COMPAT #define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT \ @@ -129,5 +130,5 @@ DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connectio { NULL, NULL, NULL, NULL, NULL } }; - return bus_default_message_handler(u->meta.manager, connection, message, INTROSPECTION, INTERFACES_LIST, properties); + return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); } diff --git a/src/dbus-snapshot.c b/src/dbus-snapshot.c index cc12b1bd8b..0c2f349599 100644 --- a/src/dbus-snapshot.c +++ b/src/dbus-snapshot.c @@ -21,6 +21,7 @@ #include "dbus-unit.h" #include "dbus-snapshot.h" +#include "dbus-common.h" #define BUS_SNAPSHOT_INTERFACE \ " <interface name=\"org.freedesktop.systemd1.Snapshot\">\n" \ @@ -45,6 +46,7 @@ const char bus_snapshot_interface[] _introspect_("Snapshot") = BUS_SNAPSHOT_INTERFACE; DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) { + const BusProperty properties[] = { BUS_UNIT_PROPERTIES, { "org.freedesktop.systemd1.Snapshot", "Cleanup", bus_property_append_bool, "b", &u->snapshot.cleanup }, @@ -64,7 +66,7 @@ DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusM goto oom; } else - return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties); + return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); if (reply) { if (!dbus_connection_send(c, reply, NULL)) diff --git a/src/dbus-socket.c b/src/dbus-socket.c index 5b068b45fa..88727bbbc1 100644 --- a/src/dbus-socket.c +++ b/src/dbus-socket.c @@ -24,6 +24,7 @@ #include "dbus-unit.h" #include "dbus-socket.h" #include "dbus-execute.h" +#include "dbus-common.h" #define BUS_SOCKET_INTERFACE \ " <interface name=\"org.freedesktop.systemd1.Socket\">\n" \ @@ -113,5 +114,5 @@ DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMes { NULL, NULL, NULL, NULL, NULL } }; - return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties); + return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); } diff --git a/src/dbus-swap.c b/src/dbus-swap.c index 079912a532..988ca58d4b 100644 --- a/src/dbus-swap.c +++ b/src/dbus-swap.c @@ -25,6 +25,7 @@ #include "dbus-unit.h" #include "dbus-swap.h" #include "dbus-execute.h" +#include "dbus-common.h" #define BUS_SWAP_INTERFACE \ " <interface name=\"org.freedesktop.systemd1.Swap\">\n" \ @@ -60,11 +61,10 @@ const char bus_swap_invalidating_properties[] = "ExecDeactivate\0" "ControlPID\0"; -static int bus_swap_append_priority(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_swap_append_priority(DBusMessageIter *i, const char *property, void *data) { Swap *s = data; dbus_int32_t j; - assert(m); assert(i); assert(property); assert(s); @@ -96,5 +96,5 @@ DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessa { NULL, NULL, NULL, NULL, NULL } }; - return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties); + return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); } diff --git a/src/dbus-target.c b/src/dbus-target.c index 1cbeccb579..1e00f2dbbb 100644 --- a/src/dbus-target.c +++ b/src/dbus-target.c @@ -23,6 +23,7 @@ #include "dbus-unit.h" #include "dbus-target.h" +#include "dbus-common.h" #define BUS_TARGET_INTERFACE \ " <interface name=\"org.freedesktop.systemd1.Target\">\n" \ @@ -50,5 +51,5 @@ DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMes { NULL, NULL, NULL, NULL, NULL } }; - return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties); + return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); } diff --git a/src/dbus-timer.c b/src/dbus-timer.c index e44f4e2fea..abcbe6f9be 100644 --- a/src/dbus-timer.c +++ b/src/dbus-timer.c @@ -24,6 +24,7 @@ #include "dbus-unit.h" #include "dbus-timer.h" #include "dbus-execute.h" +#include "dbus-common.h" #define BUS_TIMER_INTERFACE \ " <interface name=\"org.freedesktop.systemd1.Timer\">\n" \ @@ -52,12 +53,11 @@ const char bus_timer_invalidating_properties[] = "Timers\0" "NextElapseUSec\0"; -static int bus_timer_append_timers(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_timer_append_timers(DBusMessageIter *i, const char *property, void *data) { Timer *p = data; DBusMessageIter sub, sub2; TimerValue *k; - assert(m); assert(i); assert(property); assert(p); @@ -99,11 +99,10 @@ static int bus_timer_append_timers(Manager *m, DBusMessageIter *i, const char *p return 0; } -static int bus_timer_append_unit(Manager *m, DBusMessageIter *i, const char *property, void *data) { +static int bus_timer_append_unit(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; const char *t; - assert(m); assert(i); assert(property); assert(u); @@ -122,5 +121,5 @@ DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMess { NULL, NULL, NULL, NULL, NULL } }; - return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties); + return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, properties); } diff --git a/src/dbus-unit.c b/src/dbus-unit.c index b5daa66b5d..ad8e9a1aef 100644 --- a/src/dbus-unit.c +++ b/src/dbus-unit.c @@ -25,6 +25,7 @@ #include "log.h" #include "dbus-unit.h" #include "bus-errors.h" +#include "dbus-common.h" const char bus_unit_interface[] _introspect_("Unit") = BUS_UNIT_INTERFACE; @@ -39,7 +40,7 @@ const char bus_unit_interface[] _introspect_("Unit") = BUS_UNIT_INTERFACE; "Job\0" \ "NeedDaemonReload\0" -int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_names(DBusMessageIter *i, const char *property, void *data) { char *t; Iterator j; DBusMessageIter sub; @@ -58,11 +59,10 @@ int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property, return 0; } -int bus_unit_append_following(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_following(DBusMessageIter *i, const char *property, void *data) { Unit *u = data, *f; const char *d; - assert(m); assert(i); assert(property); assert(u); @@ -76,7 +76,7 @@ int bus_unit_append_following(Manager *m, DBusMessageIter *i, const char *proper return 0; } -int bus_unit_append_dependencies(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_dependencies(DBusMessageIter *i, const char *property, void *data) { Unit *u; Iterator j; DBusMessageIter sub; @@ -95,11 +95,10 @@ int bus_unit_append_dependencies(Manager *m, DBusMessageIter *i, const char *pro return 0; } -int bus_unit_append_description(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_description(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; const char *d; - assert(m); assert(i); assert(property); assert(u); @@ -114,11 +113,10 @@ int bus_unit_append_description(Manager *m, DBusMessageIter *i, const char *prop DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state, unit_load_state, UnitLoadState); -int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_active_state(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; const char *state; - assert(m); assert(i); assert(property); assert(u); @@ -131,11 +129,10 @@ int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *pro return 0; } -int bus_unit_append_sub_state(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_sub_state(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; const char *state; - assert(m); assert(i); assert(property); assert(u); @@ -148,11 +145,10 @@ int bus_unit_append_sub_state(Manager *m, DBusMessageIter *i, const char *proper return 0; } -int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_can_start(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; dbus_bool_t b; - assert(m); assert(i); assert(property); assert(u); @@ -166,11 +162,10 @@ int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *proper return 0; } -int bus_unit_append_can_stop(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_can_stop(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; dbus_bool_t b; - assert(m); assert(i); assert(property); assert(u); @@ -187,11 +182,10 @@ int bus_unit_append_can_stop(Manager *m, DBusMessageIter *i, const char *propert return 0; } -int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_can_reload(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; dbus_bool_t b; - assert(m); assert(i); assert(property); assert(u); @@ -204,11 +198,10 @@ int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *prope return 0; } -int bus_unit_append_can_isolate(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_can_isolate(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; dbus_bool_t b; - assert(m); assert(i); assert(property); assert(u); @@ -222,12 +215,11 @@ int bus_unit_append_can_isolate(Manager *m, DBusMessageIter *i, const char *prop return 0; } -int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_job(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; DBusMessageIter sub; char *p; - assert(m); assert(i); assert(property); assert(u); @@ -270,13 +262,12 @@ int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, vo return 0; } -int bus_unit_append_default_cgroup(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; char *t; CGroupBonding *cgb; bool success; - assert(m); assert(i); assert(property); assert(u); @@ -295,7 +286,7 @@ int bus_unit_append_default_cgroup(Manager *m, DBusMessageIter *i, const char *p return success ? 0 : -ENOMEM; } -int bus_unit_append_cgroups(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_cgroups(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; CGroupBonding *cgb; DBusMessageIter sub; @@ -323,11 +314,10 @@ int bus_unit_append_cgroups(Manager *m, DBusMessageIter *i, const char *property return 0; } -int bus_unit_append_need_daemon_reload(Manager *m, DBusMessageIter *i, const char *property, void *data) { +int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *property, void *data) { Unit *u = data; dbus_bool_t b; - assert(m); assert(i); assert(property); assert(u); @@ -380,16 +370,16 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn DBUS_TYPE_STRING, &smode, DBUS_TYPE_INT32, &signo, DBUS_TYPE_INVALID)) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if ((mode = kill_mode_from_string(smode)) < 0 || (who = kill_who_from_string(swho)) < 0 || signo <= 0 || signo >= _NSIG) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if ((r = unit_kill(u, who, mode, signo, &error)) < 0) - return bus_send_error_reply(m, connection, message, &error, r); + return bus_send_error_reply(connection, message, &error, r); if (!(reply = dbus_message_new_method_return(message))) goto oom; @@ -417,7 +407,7 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) && (u->meta.refuse_manual_start || u->meta.refuse_manual_stop))) { dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only."); - return bus_send_error_reply(m, connection, message, &error, -EPERM); + return bus_send_error_reply(connection, message, &error, -EPERM); } if (!dbus_message_get_args( @@ -425,7 +415,7 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn &error, DBUS_TYPE_STRING, &smode, DBUS_TYPE_INVALID)) - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); if (reload_if_possible && unit_can_reload(u)) { if (job_type == JOB_RESTART) @@ -436,11 +426,11 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) { dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode); - return bus_send_error_reply(m, connection, message, &error, -EINVAL); + return bus_send_error_reply(connection, message, &error, -EINVAL); } if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0) - return bus_send_error_reply(m, connection, message, &error, r); + return bus_send_error_reply(connection, message, &error, r); if (!(reply = dbus_message_new_method_return(message))) goto oom; @@ -571,10 +561,10 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB dbus_error_init(&e); dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown unit"); - return bus_send_error_reply(m, connection, message, &e, r); + return bus_send_error_reply(connection, message, &e, r); } - return bus_send_error_reply(m, connection, message, NULL, r); + return bus_send_error_reply(connection, message, NULL, r); } return bus_unit_message_dispatch(u, connection, message); diff --git a/src/dbus-unit.h b/src/dbus-unit.h index efb61797f4..a2a93235ee 100644 --- a/src/dbus-unit.h +++ b/src/dbus-unit.h @@ -86,23 +86,31 @@ " <property name=\"SubState\" type=\"s\" access=\"read\"/>\n" \ " <property name=\"FragmentPath\" type=\"s\" access=\"read\"/>\n" \ " <property name=\"InactiveExitTimestamp\" type=\"t\" access=\"read\"/>\n" \ + " <property name=\"InactiveExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ " <property name=\"ActiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \ + " <property name=\"ActiveEnterTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ " <property name=\"ActiveExitTimestamp\" type=\"t\" access=\"read\"/>\n" \ + " <property name=\"ActiveExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ " <property name=\"InactiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \ - " <property name=\"CanReload\" type=\"b\" access=\"read\"/>\n" \ + " <property name=\"InactiveEnterTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ " <property name=\"CanStart\" type=\"b\" access=\"read\"/>\n" \ " <property name=\"CanStop\" type=\"b\" access=\"read\"/>\n" \ + " <property name=\"CanReload\" type=\"b\" access=\"read\"/>\n" \ " <property name=\"CanIsolate\" type=\"b\" access=\"read\"/>\n" \ " <property name=\"Job\" type=\"(uo)\" access=\"read\"/>\n" \ " <property name=\"StopWhenUnneeded\" type=\"b\" access=\"read\"/>\n" \ " <property name=\"RefuseManualStart\" type=\"b\" access=\"read\"/>\n" \ " <property name=\"RefuseManualStop\" type=\"b\" access=\"read\"/>\n" \ + " <property name=\"AllowIsolate\" type=\"b\" access=\"read\"/>\n" \ " <property name=\"DefaultDependencies\" type=\"b\" access=\"read\"/>\n" \ + " <property name=\"OnFailureIsolate\" type=\"b\" access=\"read\"/>\n" \ + " <property name=\"IgnoreOnIsolate\" type=\"b\" access=\"read\"/>\n" \ " <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \ " <property name=\"ControlGroup\" type=\"as\" access=\"read\"/>\n" \ " <property name=\"NeedDaemonReload\" type=\"b\" access=\"read\"/>\n" \ " <property name=\"JobTimeoutUSec\" type=\"t\" access=\"read\"/>\n" \ " <property name=\"ConditionTimestamp\" type=\"t\" access=\"read\"/>\n" \ + " <property name=\"ConditionTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \ " <property name=\"ConditionResult\" type=\"b\" access=\"read\"/>\n" \ " </interface>\n" @@ -134,10 +142,14 @@ { "org.freedesktop.systemd1.Unit", "ActiveState", bus_unit_append_active_state, "s", u }, \ { "org.freedesktop.systemd1.Unit", "SubState", bus_unit_append_sub_state, "s", u }, \ { "org.freedesktop.systemd1.Unit", "FragmentPath", bus_property_append_string, "s", u->meta.fragment_path }, \ - { "org.freedesktop.systemd1.Unit", "InactiveExitTimestamp",bus_property_append_usec, "t", &u->meta.inactive_exit_timestamp.realtime }, \ - { "org.freedesktop.systemd1.Unit", "ActiveEnterTimestamp", bus_property_append_usec, "t", &u->meta.active_enter_timestamp.realtime }, \ - { "org.freedesktop.systemd1.Unit", "ActiveExitTimestamp", bus_property_append_usec, "t", &u->meta.active_exit_timestamp.realtime }, \ + { "org.freedesktop.systemd1.Unit", "InactiveExitTimestamp",bus_property_append_usec, "t", &u->meta.inactive_exit_timestamp.realtime }, \ + { "org.freedesktop.systemd1.Unit", "InactiveExitTimestampMonotonic",bus_property_append_usec, "t", &u->meta.inactive_exit_timestamp.monotonic }, \ + { "org.freedesktop.systemd1.Unit", "ActiveEnterTimestamp", bus_property_append_usec, "t", &u->meta.active_enter_timestamp.realtime }, \ + { "org.freedesktop.systemd1.Unit", "ActiveEnterTimestampMonotonic", bus_property_append_usec, "t", &u->meta.active_enter_timestamp.monotonic }, \ + { "org.freedesktop.systemd1.Unit", "ActiveExitTimestamp", bus_property_append_usec, "t", &u->meta.active_exit_timestamp.realtime }, \ + { "org.freedesktop.systemd1.Unit", "ActiveExitTimestampMonotonic", bus_property_append_usec, "t", &u->meta.active_exit_timestamp.monotonic }, \ { "org.freedesktop.systemd1.Unit", "InactiveEnterTimestamp",bus_property_append_usec, "t", &u->meta.inactive_enter_timestamp.realtime }, \ + { "org.freedesktop.systemd1.Unit", "InactiveEnterTimestampMonotonic",bus_property_append_usec,"t", &u->meta.inactive_enter_timestamp.monotonic }, \ { "org.freedesktop.systemd1.Unit", "CanStart", bus_unit_append_can_start, "b", u }, \ { "org.freedesktop.systemd1.Unit", "CanStop", bus_unit_append_can_stop, "b", u }, \ { "org.freedesktop.systemd1.Unit", "CanReload", bus_unit_append_can_reload, "b", u }, \ @@ -148,28 +160,31 @@ { "org.freedesktop.systemd1.Unit", "RefuseManualStop", bus_property_append_bool, "b", &u->meta.refuse_manual_stop }, \ { "org.freedesktop.systemd1.Unit", "AllowIsolate", bus_property_append_bool, "b", &u->meta.allow_isolate }, \ { "org.freedesktop.systemd1.Unit", "DefaultDependencies", bus_property_append_bool, "b", &u->meta.default_dependencies }, \ + { "org.freedesktop.systemd1.Unit", "OnFailureIsolate", bus_property_append_bool, "b", &u->meta.on_failure_isolate }, \ + { "org.freedesktop.systemd1.Unit", "IgnoreOnIsolate", bus_property_append_bool, "b", &u->meta.ignore_on_isolate }, \ { "org.freedesktop.systemd1.Unit", "DefaultControlGroup", bus_unit_append_default_cgroup, "s", u }, \ { "org.freedesktop.systemd1.Unit", "ControlGroup", bus_unit_append_cgroups, "as", u }, \ { "org.freedesktop.systemd1.Unit", "NeedDaemonReload", bus_unit_append_need_daemon_reload, "b", u }, \ { "org.freedesktop.systemd1.Unit", "JobTimeoutUSec", bus_property_append_usec, "t", &u->meta.job_timeout }, \ { "org.freedesktop.systemd1.Unit", "ConditionTimestamp", bus_property_append_usec, "t", &u->meta.condition_timestamp.realtime }, \ + { "org.freedesktop.systemd1.Unit", "ConditionTimestampMonotonic", bus_property_append_usec,"t", &u->meta.condition_timestamp.monotonic }, \ { "org.freedesktop.systemd1.Unit", "ConditionResult", bus_property_append_bool, "b", &u->meta.condition_result } -int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_following(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_dependencies(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_description(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_load_state(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_sub_state(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_can_stop(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_can_isolate(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_default_cgroup(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_cgroups(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_unit_append_need_daemon_reload(Manager *m, DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_names(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_following(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_dependencies(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_description(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_load_state(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_active_state(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_sub_state(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_can_start(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_can_stop(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_can_reload(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_can_isolate(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_job(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_default_cgroup(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_cgroups(DBusMessageIter *i, const char *property, void *data); +int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *property, void *data); void bus_unit_send_change_signal(Unit *u); void bus_unit_send_removed_signal(Unit *u); diff --git a/src/dbus.c b/src/dbus.c index 6f43c4108e..1907560bc0 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -44,6 +44,7 @@ #include "dbus-path.h" #include "bus-errors.h" #include "special.h" +#include "dbus-common.h" #define CONNECTIONS_MAX 52 @@ -69,7 +70,6 @@ const char *const bus_interface_table[] = { NULL }; -static const char *error_to_dbus(int error); static void bus_done_api(Manager *m); static void bus_done_system(Manager *m); static void bus_done_private(Manager *m); @@ -406,7 +406,7 @@ static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBus if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure"))) goto oom; - id = error.name ? error.name : error_to_dbus(r); + id = error.name ? error.name : bus_errno_to_dbus(r); text = bus_error(&error, r); if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) || @@ -1214,289 +1214,6 @@ oom: return -ENOMEM; } -DBusHandlerResult bus_default_message_handler( - Manager *m, - DBusConnection *c, - DBusMessage *message, - const char *introspection, - const char *interfaces, - const BusProperty *properties) { - - DBusError error; - DBusMessage *reply = NULL; - int r; - - assert(m); - assert(c); - assert(message); - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) { - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && properties) { - const char *interface, *property; - const BusProperty *p; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_STRING, &property, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(m, c, message, &error, -EINVAL); - - for (p = properties; p->property; p++) - if (streq(p->interface, interface) && streq(p->property, property)) - break; - - if (p->property) { - DBusMessageIter iter, sub; - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub)) - goto oom; - - if ((r = p->append(m, &sub, property, (void*) p->data)) < 0) { - - if (r == -ENOMEM) - goto oom; - - dbus_message_unref(reply); - return bus_send_error_reply(m, c, message, NULL, r); - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - } else { - if (!nulstr_contains(interfaces, interface)) - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - else - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); - - return bus_send_error_reply(m, c, message, &error, -EINVAL); - } - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && properties) { - const char *interface; - const BusProperty *p; - DBusMessageIter iter, sub, sub2, sub3; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(m, c, message, &error, -EINVAL); - - if (interface[0] && !nulstr_contains(interfaces, interface)) { - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - return bus_send_error_reply(m, c, message, &error, -EINVAL); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub)) - goto oom; - - for (p = properties; p->property; p++) { - if (interface[0] && !streq(p->interface, interface)) - continue; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) || - !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3)) - goto oom; - - if ((r = p->append(m, &sub3, p->property, (void*) p->data)) < 0) { - - if (r == -ENOMEM) - goto oom; - - dbus_message_unref(reply); - return bus_send_error_reply(m, c, message, NULL, r); - } - - if (!dbus_message_iter_close_container(&sub2, &sub3) || - !dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && properties) { - const char *interface, *property; - DBusMessageIter iter; - const BusProperty *p; - - if (!dbus_message_iter_init(message, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return bus_send_error_reply(m, c, message, NULL, -EINVAL); - - dbus_message_iter_get_basic(&iter, &interface); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return bus_send_error_reply(m, c, message, NULL, -EINVAL); - - dbus_message_iter_get_basic(&iter, &property); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT || - dbus_message_iter_has_next(&iter)) - return bus_send_error_reply(m, c, message, NULL, -EINVAL); - - for (p = properties; p->property; p++) - if (streq(p->interface, interface) && streq(p->property, property)) - break; - - if (p->set) { - DBusMessageIter sub; - char *sig; - - dbus_message_iter_recurse(&iter, &sub); - - if (!(sig = dbus_message_iter_get_signature(&sub))) - goto oom; - - if (!streq(sig, p->signature)) { - dbus_free(sig); - return bus_send_error_reply(m, c, message, NULL, -EINVAL); - } - - dbus_free(sig); - - if ((r = p->set(m, &sub, property)) < 0) { - if (r == -ENOMEM) - goto oom; - return bus_send_error_reply(m, c, message, NULL, r); - } - - if (!(reply = dbus_message_new_method_return(message))) - goto oom; - } else { - if (p->property) - dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only"); - else if (!nulstr_contains(interfaces, interface)) - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - else - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); - - return bus_send_error_reply(m, c, message, &error, -EINVAL); - } - - } else if (!nulstr_contains(interfaces, dbus_message_get_interface(message))) { - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - return bus_send_error_reply(m, c, message, &error, -EINVAL); - } - - if (reply) { - if (!dbus_connection_send(c, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - return DBUS_HANDLER_RESULT_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -static const char *error_to_dbus(int error) { - - switch(error) { - - case -EINVAL: - return DBUS_ERROR_INVALID_ARGS; - - case -ENOMEM: - return DBUS_ERROR_NO_MEMORY; - - case -EPERM: - case -EACCES: - return DBUS_ERROR_ACCESS_DENIED; - - case -ESRCH: - return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN; - - case -ENOENT: - return DBUS_ERROR_FILE_NOT_FOUND; - - case -EEXIST: - return DBUS_ERROR_FILE_EXISTS; - - case -ETIMEDOUT: - case -ETIME: - return DBUS_ERROR_TIMEOUT; - - case -EIO: - return DBUS_ERROR_IO_ERROR; - - case -ENETRESET: - case -ECONNABORTED: - case -ECONNRESET: - return DBUS_ERROR_DISCONNECTED; - } - - return DBUS_ERROR_FAILED; -} - -DBusHandlerResult bus_send_error_reply(Manager *m, DBusConnection *c, DBusMessage *message, DBusError *berror, int error) { - DBusMessage *reply = NULL; - const char *name, *text; - - if (berror && dbus_error_is_set(berror)) { - name = berror->name; - text = berror->message; - } else { - name = error_to_dbus(error); - text = strerror(-error); - } - - if (!(reply = dbus_message_new_error(message, name, text))) - goto oom; - - if (!dbus_connection_send(c, reply, NULL)) - goto oom; - - dbus_message_unref(reply); - - if (berror) - dbus_error_free(berror); - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - if (berror) - dbus_error_free(berror); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - int bus_broadcast(Manager *m, DBusMessage *message) { bool oom = false; Iterator i; @@ -1516,140 +1233,6 @@ int bus_broadcast(Manager *m, DBusMessage *message) { return oom ? -ENOMEM : 0; } -int bus_property_append_string(Manager *m, DBusMessageIter *i, const char *property, void *data) { - const char *t = data; - - assert(m); - assert(i); - assert(property); - - if (!t) - t = ""; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_strv(Manager *m, DBusMessageIter *i, const char *property, void *data) { - DBusMessageIter sub; - char **t = data; - - assert(m); - assert(i); - assert(property); - - if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub)) - return -ENOMEM; - - STRV_FOREACH(t, t) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, t)) - return -ENOMEM; - - if (!dbus_message_iter_close_container(i, &sub)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_bool(Manager *m, DBusMessageIter *i, const char *property, void *data) { - bool *b = data; - dbus_bool_t db; - - assert(m); - assert(i); - assert(property); - assert(b); - - db = *b; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *property, void *data) { - assert(m); - assert(i); - assert(property); - assert(data); - - /* Let's ensure that pid_t is actually 64bit, and hence this - * function can be used for usec_t */ - assert_cc(sizeof(uint64_t) == sizeof(usec_t)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_uint32(Manager *m, DBusMessageIter *i, const char *property, void *data) { - assert(m); - assert(i); - assert(property); - assert(data); - - /* Let's ensure that pid_t and mode_t is actually 32bit, and - * hence this function can be used for pid_t/mode_t */ - assert_cc(sizeof(uint32_t) == sizeof(pid_t)); - assert_cc(sizeof(uint32_t) == sizeof(mode_t)); - assert_cc(sizeof(uint32_t) == sizeof(unsigned)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *property, void *data) { - assert(m); - assert(i); - assert(property); - assert(data); - - assert_cc(sizeof(int32_t) == sizeof(int)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_size(Manager *m, DBusMessageIter *i, const char *property, void *data) { - uint64_t u; - - assert(m); - assert(i); - assert(property); - assert(data); - - u = (uint64_t) *(size_t*) data; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_ul(Manager *m, DBusMessageIter *i, const char *property, void *data) { - uint64_t u; - - assert(m); - assert(i); - assert(property); - assert(data); - - u = (uint64_t) *(unsigned long*) data; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - int bus_parse_strv(DBusMessage *m, char ***_l) { DBusMessageIter iter, sub; unsigned n = 0, i = 0; @@ -1722,41 +1305,3 @@ bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) { return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c)); } - -DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) { - DBusMessage *m; - DBusMessageIter iter, sub; - const char *i; - - assert(interface); - assert(properties); - - if (!(m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"))) - goto oom; - - dbus_message_iter_init_append(m, &iter); - - /* We won't send any property values, since they might be - * large and sometimes not cheap to generated */ - - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) || - !dbus_message_iter_close_container(&iter, &sub) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) - goto oom; - - NULSTR_FOREACH(i, properties) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i)) - goto oom; - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - return m; - -oom: - if (m) - dbus_message_unref(m); - - return NULL; -} diff --git a/src/dbus.h b/src/dbus.h index f93ad6203b..57a2b388ca 100644 --- a/src/dbus.h +++ b/src/dbus.h @@ -24,79 +24,8 @@ #include <dbus/dbus.h> -#ifndef DBUS_ERROR_UNKNOWN_OBJECT -#define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject" -#endif - -#ifndef DBUS_ERROR_UNKNOWN_INTERFACE -#define DBUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface" -#endif - -#ifndef DBUS_ERROR_UNKNOWN_PROPERTY -#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty" -#endif - -#ifndef DBUS_ERROR_PROPERTY_READ_ONLY -#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly" -#endif - #include "manager.h" -typedef int (*BusPropertyCallback)(Manager *m, DBusMessageIter *iter, const char *property, void *data); -typedef int (*BusPropertySetCallback)(Manager *m, DBusMessageIter *iter, const char *property); - -typedef struct BusProperty { - const char *interface; /* interface of the property */ - const char *property; /* name of the property */ - BusPropertyCallback append; /* Function that is called to serialize this property */ - const char *signature; - const void *data; /* The data of this property */ - BusPropertySetCallback set; /* Function that is called to set this property */ -} BusProperty; - -#define BUS_PROPERTIES_INTERFACE \ - " <interface name=\"org.freedesktop.DBus.Properties\">\n" \ - " <method name=\"Get\">\n" \ - " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"value\" direction=\"out\" type=\"v\"/>\n" \ - " </method>\n" \ - " <method name=\"GetAll\">\n" \ - " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \ - " </method>\n" \ - " <method name=\"Set\">\n" \ - " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"value\" direction=\"in\" type=\"v\"/>\n" \ - " </method>\n" \ - " <signal name=\"PropertiesChanged\">\n" \ - " <arg type=\"s\" name=\"interface\"/>\n" \ - " <arg type=\"a{sv}\" name=\"changed_properties\"/>\n" \ - " <arg type=\"as\" name=\"invalidated_properties\"/>\n" \ - " </signal>\n" \ - " </interface>\n" - -#define BUS_INTROSPECTABLE_INTERFACE \ - " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \ - " <method name=\"Introspect\">\n" \ - " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \ - " </method>\n" \ - " </interface>\n" - -#define BUS_PEER_INTERFACE \ - "<interface name=\"org.freedesktop.DBus.Peer\">\n" \ - " <method name=\"Ping\"/>\n" \ - " <method name=\"GetMachineId\">\n" \ - " <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \ - " </method>\n" \ - "</interface>\n" - -#define BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.DBus.Properties\0" \ - "org.freedesktop.DBus.Introspectable\0" \ - "org.freedesktop.DBus.Peer\0" - int bus_init(Manager *m, bool try_bus_connect); void bus_done(Manager *m); @@ -107,50 +36,13 @@ void bus_timeout_event(Manager *m, Watch *w, int events); int bus_query_pid(Manager *m, const char *name); -DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBusMessage *message, const char* introspection, const char *interfaces, const BusProperty *properties); -DBusHandlerResult bus_send_error_reply(Manager *m, DBusConnection *c, DBusMessage *message, DBusError *bus_error, int error); - int bus_broadcast(Manager *m, DBusMessage *message); -int bus_property_append_string(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_property_append_strv(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_property_append_bool(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_property_append_int32(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_property_append_uint32(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_property_append_uint64(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_property_append_size(Manager *m, DBusMessageIter *i, const char *property, void *data); -int bus_property_append_ul(Manager *m, DBusMessageIter *i, const char *property, void *data); - -#define bus_property_append_int bus_property_append_int32 -#define bus_property_append_pid bus_property_append_uint32 -#define bus_property_append_mode bus_property_append_uint32 -#define bus_property_append_unsigned bus_property_append_uint32 -#define bus_property_append_usec bus_property_append_uint64 - -#define DEFINE_BUS_PROPERTY_APPEND_ENUM(function,name,type) \ - int function(Manager *m, DBusMessageIter *i, const char *property, void *data) { \ - const char *value; \ - type *field = data; \ - \ - assert(m); \ - assert(i); \ - assert(property); \ - \ - value = name##_to_string(*field); \ - \ - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &value)) \ - return -ENOMEM; \ - \ - return 0; \ - } - int bus_parse_strv(DBusMessage *m, char ***_l); bool bus_has_subscriber(Manager *m); bool bus_connection_has_subscriber(Manager *m, DBusConnection *c); -DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties); - #define BUS_CONNECTION_SUBSCRIBED(m, c) dbus_connection_get_data((c), (m)->subscribed_data_slot) #define BUS_PENDING_CALL_NAME(m, p) dbus_pending_call_get_data((p), (m)->name_data_slot) @@ -27,6 +27,8 @@ #define DEFAULT_TIMEOUT_USEC (3*USEC_PER_MINUTE) #define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC) +#define DEFAULT_EXIT_USEC (5*USEC_PER_MINUTE) + #define SYSTEMD_CGROUP_CONTROLLER "name=systemd" #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT diff --git a/src/device.c b/src/device.c index 41c96cef03..d507b701f1 100644 --- a/src/device.c +++ b/src/device.c @@ -70,6 +70,8 @@ static void device_init(Unit *u) { * happen for the other units since their operations time out * anyway. */ d->meta.job_timeout = DEFAULT_TIMEOUT_USEC; + + d->meta.ignore_on_isolate = true; } static void device_done(Unit *u) { @@ -583,7 +585,6 @@ const UnitVTable device_vtable = { .no_instances = true, .no_snapshots = true, - .no_isolate = true, .init = device_init, diff --git a/src/execute.c b/src/execute.c index d67916c249..745dcfcdb8 100644 --- a/src/execute.c +++ b/src/execute.c @@ -904,6 +904,68 @@ fail: } #endif +static int do_capability_bounding_set_drop(uint64_t drop) { + unsigned long i; + cap_t old_cap = NULL, new_cap = NULL; + cap_flag_value_t fv; + int r; + + /* If we are run as PID 1 we will lack CAP_SETPCAP by default + * in the effective set (yes, the kernel drops that when + * executing init!), so get it back temporarily so that we can + * call PR_CAPBSET_DROP. */ + + old_cap = cap_get_proc(); + if (!old_cap) + return -errno; + + if (cap_get_flag(old_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) { + r = -errno; + goto finish; + } + + if (fv != CAP_SET) { + static const cap_value_t v = CAP_SETPCAP; + + new_cap = cap_dup(old_cap); + if (!new_cap) { + r = -errno; + goto finish; + } + + if (cap_set_flag(new_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) { + r = -errno; + goto finish; + } + + if (cap_set_proc(new_cap) < 0) { + r = -errno; + goto finish; + } + } + + for (i = 0; i <= CAP_LAST_CAP; i++) + if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { + if (prctl(PR_CAPBSET_DROP, i) < 0) { + r = -errno; + goto finish; + } + } + + r = 0; + +finish: + if (new_cap) + cap_free(new_cap); + + if (old_cap) { + cap_set_proc(old_cap); + cap_free(old_cap); + } + + return r; +} + int exec_spawn(ExecCommand *command, char **argv, const ExecContext *context, @@ -1106,7 +1168,8 @@ int exec_spawn(ExecCommand *command, snprintf(t, sizeof(t), "%i", adj); char_array_0(t); - if (write_one_line_file("/proc/self/oom_adj", t) < 0) { + if (write_one_line_file("/proc/self/oom_adj", t) < 0 + && errno != EACCES) { r = EXIT_OOM_ADJUST; goto fail_child; } @@ -1250,13 +1313,10 @@ int exec_spawn(ExecCommand *command, } if (context->capability_bounding_set_drop) - for (i = 0; i <= CAP_LAST_CAP; i++) - if (context->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) i)) { - if (prctl(PR_CAPBSET_DROP, i) < 0) { - r = EXIT_CAPABILITIES; - goto fail_child; - } - } + if (do_capability_bounding_set_drop(context->capability_bounding_set_drop) < 0) { + r = EXIT_CAPABILITIES; + goto fail_child; + } if (context->user) if (enforce_user(context, uid) < 0) { diff --git a/src/getty-generator.c b/src/getty-generator.c index f49f9eae99..683775a4d5 100644 --- a/src/getty-generator.c +++ b/src/getty-generator.c @@ -86,7 +86,6 @@ int main(int argc, char *argv[]) { if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) { const char *tty; - truncate_nl(active); if ((tty = strrchr(active, ' '))) tty ++; else diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala index 2bfc6a9c83..c31c07e3db 100644 --- a/src/gnome-ask-password-agent.vala +++ b/src/gnome-ask-password-agent.vala @@ -165,7 +165,7 @@ public class MyStatusIcon : StatusIcon { if (not_after_as_string.scanf("%llu", out not_after) != 1) return false; - if (not_after < now) + if (not_after > 0 && not_after < now) return false; socket = key_file.get_string("Ask", "Socket"); diff --git a/src/hostname-setup.c b/src/hostname-setup.c index e9869bb4df..57db9fbf7c 100644 --- a/src/hostname-setup.c +++ b/src/hostname-setup.c @@ -30,7 +30,7 @@ #include "util.h" #include "log.h" -#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) +#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) #define FILENAME "/etc/sysconfig/network" #elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE) || defined(TARGET_FRUGALWARE) #define FILENAME "/etc/HOSTNAME" @@ -40,25 +40,8 @@ #define FILENAME "/etc/conf.d/hostname" #endif -static char* strip_bad_chars(char *s) { - char *p, *d; - - for (p = s, d = s; *p; p++) - if ((*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z') || - (*p >= '0' && *p <= '9') || - *p == '-' || - *p == '_' || - *p == '.') - *(d++) = *p; - - *d = 0; - - return s; -} - static int read_and_strip_hostname(const char *path, char **hn) { - char *s, *k; + char *s; int r; assert(path); @@ -67,27 +50,21 @@ static int read_and_strip_hostname(const char *path, char **hn) { if ((r = read_one_line_file(path, &s)) < 0) return r; - k = strdup(strstrip(s)); - free(s); - - if (!k) - return -ENOMEM; - - strip_bad_chars(k); + hostname_cleanup(s); - if (k[0] == 0) { - free(k); + if (isempty(s)) { + free(s); return -ENOENT; } - *hn = k; + *hn = s; return 0; } static int read_distro_hostname(char **hn) { -#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) +#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) int r; FILE *f; @@ -118,9 +95,9 @@ static int read_distro_hostname(char **hn) { goto finish; } - strip_bad_chars(k); + hostname_cleanup(k); - if (k[0] == 0) { + if (isempty(k)) { free(k); r = -ENOENT; goto finish; diff --git a/src/hostnamed.c b/src/hostnamed.c new file mode 100644 index 0000000000..8c0035a037 --- /dev/null +++ b/src/hostnamed.c @@ -0,0 +1,704 @@ +/*-*- 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 General Public License as published by + the Free Software Foundation; either version 2 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <dbus/dbus.h> + +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include "util.h" +#include "strv.h" +#include "dbus-common.h" + +#define INTROSPECTION \ + DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \ + "<node>\n" \ + " <interface name=\"org.freedesktop.hostname1\">\n" \ + " <property name=\"Hostname\" type=\"s\" access=\"read\"/>\n" \ + " <property name=\"StaticHostname\" type=\"s\" access=\"read\"/>\n" \ + " <property name=\"PrettyHostname\" type=\"s\" access=\"read\"/>\n" \ + " <property name=\"IconName\" type=\"s\" access=\"read\"/>\n" \ + " <method name=\"SetHostname\">\n" \ + " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ + " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \ + " </method>\n" \ + " <method name=\"SetStaticHostname\">\n" \ + " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ + " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \ + " </method>\n" \ + " <method name=\"SetPrettyHostname\">\n" \ + " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ + " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \ + " </method>\n" \ + " <method name=\"SetIconName\">\n" \ + " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \ + " <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \ + " </method>\n" \ + " </interface>\n" \ + BUS_PROPERTIES_INTERFACE \ + BUS_INTROSPECTABLE_INTERFACE \ + BUS_PEER_INTERFACE \ + "</node>\n" + +#define INTERFACES_LIST \ + BUS_GENERIC_INTERFACES_LIST \ + "org.freedesktop.hostname1\0" + +enum { + PROP_HOSTNAME, + PROP_STATIC_HOSTNAME, + PROP_PRETTY_HOSTNAME, + PROP_ICON_NAME, + _PROP_MAX +}; + +static char *data[_PROP_MAX] = { + NULL, + NULL, + NULL, + NULL +}; + +static void free_data(void) { + int p; + + for (p = 0; p < _PROP_MAX; p++) { + free(data[p]); + data[p] = NULL; + } +} + +static int read_data(void) { + int r; + + free_data(); + + data[PROP_HOSTNAME] = gethostname_malloc(); + if (!data[PROP_HOSTNAME]) + return -ENOMEM; + + r = read_one_line_file("/etc/hostname", &data[PROP_STATIC_HOSTNAME]); + if (r < 0 && r != -ENOENT) + return r; + + r = parse_env_file("/etc/machine-info", NEWLINE, + "PRETTY_HOSTNAME", &data[PROP_PRETTY_HOSTNAME], + "ICON_NAME", &data[PROP_ICON_NAME], + NULL); + if (r < 0 && r != -ENOENT) + return r; + + return 0; +} + +static const char* fallback_icon_name(void) { + +#if defined(__i386__) || defined(__x86_64__) + int r; + char *type; + unsigned t; +#endif + + if (detect_virtualization(NULL) > 0) + return "computer-vm"; + +#if defined(__i386__) || defined(__x86_64__) + r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type); + if (r < 0) + return NULL; + + r = safe_atou(type, &t); + free(type); + + if (r < 0) + return NULL; + + /* We only list the really obvious cases here. The DMI data is + unreliable enough, so let's not do any additional guesswork + on top of that. + + See the SMBIOS Specification 2.7.1 section 7.4.1 for + details about the values listed here: + + http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf + */ + + switch (t) { + + case 0x3: + case 0x4: + case 0x6: + case 0x7: + return "computer-desktop"; + + case 0x9: + case 0xA: + case 0xE: + return "computer-laptop"; + + case 0x11: + case 0x1C: + return "computer-server"; + } + +#endif + return NULL; +} + +static int write_data_hostname(void) { + const char *hn; + + if (isempty(data[PROP_HOSTNAME])) + hn = "localhost"; + else + hn = data[PROP_HOSTNAME]; + + if (sethostname(hn, strlen(hn)) < 0) + return -errno; + + return 0; +} + +static int write_data_static_hostname(void) { + + if (isempty(data[PROP_STATIC_HOSTNAME])) { + + if (unlink("/etc/hostname") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + return write_one_line_file("/etc/hostname", data[PROP_STATIC_HOSTNAME]); +} + +static int write_data_other(void) { + + static const char * const name[_PROP_MAX] = { + [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME", + [PROP_ICON_NAME] = "ICON_NAME" + }; + + char **l = NULL; + int r, p; + + r = load_env_file("/etc/machine-info", &l); + if (r < 0 && r != -ENOENT) + return r; + + for (p = 2; p < _PROP_MAX; p++) { + char *t, **u; + + assert(name[p]); + + if (isempty(data[p])) { + l = strv_env_unset(l, name[p]); + continue; + } + + if (asprintf(&t, "%s=%s", name[p], strempty(data[p])) < 0) { + strv_free(l); + return -ENOMEM; + } + + u = strv_env_set(l, t); + free(t); + strv_free(l); + + if (!u) + return -ENOMEM; + l = u; + } + + if (strv_isempty(l)) { + + if (unlink("/etc/machine-info") < 0) + return errno == ENOENT ? 0 : -errno; + + return 0; + } + + r = write_env_file("/etc/machine-info", l); + strv_free(l); + + return r; +} + +/* This mimics dbus_bus_get_unix_user() */ +static pid_t get_unix_process_id( + DBusConnection *connection, + const char *name, + DBusError *error) { + + DBusMessage *m = NULL, *reply = NULL; + uint32_t pid = 0; + + m = dbus_message_new_method_call( + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetConnectionUnixProcessID"); + if (!m) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); + goto finish; + } + + if (!dbus_message_append_args( + m, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) { + dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); + goto finish; + } + + reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error); + if (!reply) + goto finish; + + if (dbus_set_error_from_message(error, reply)) + goto finish; + + if (!dbus_message_get_args( + reply, error, + DBUS_TYPE_UINT32, &pid, + DBUS_TYPE_INVALID)) + goto finish; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + return (pid_t) pid; +} + +static int verify_polkit( + DBusConnection *c, + DBusMessage *request, + const char *action, + bool interactive, + DBusError *error) { + + DBusMessage *m = NULL, *reply = NULL; + const char *unix_process = "unix-process", *pid = "pid", *starttime = "start-time", *cancel_id = ""; + const char *sender; + uint32_t flags = interactive ? 1 : 0; + pid_t pid_raw; + uint32_t pid_u32; + unsigned long long starttime_raw; + uint64_t starttime_u64; + DBusMessageIter iter_msg, iter_struct, iter_array, iter_dict, iter_variant; + int r; + dbus_bool_t authorized = FALSE; + + assert(c); + assert(request); + + sender = dbus_message_get_sender(request); + if (!sender) + return -EINVAL; + + pid_raw = get_unix_process_id(c, sender, error); + if (pid_raw == 0) + return -EINVAL; + + r = get_starttime_of_pid(pid_raw, &starttime_raw); + if (r < 0) + return r; + + m = dbus_message_new_method_call( + "org.freedesktop.PolicyKit1", + "/org/freedesktop/PolicyKit1/Authority", + "org.freedesktop.PolicyKit1.Authority", + "CheckAuthorization"); + if (!m) + return -ENOMEM; + + dbus_message_iter_init_append(m, &iter_msg); + + pid_u32 = (uint32_t) pid_raw; + starttime_u64 = (uint64_t) starttime_raw; + + if (!dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_STRUCT, NULL, &iter_struct) || + !dbus_message_iter_append_basic(&iter_struct, DBUS_TYPE_STRING, &unix_process) || + !dbus_message_iter_open_container(&iter_struct, DBUS_TYPE_ARRAY, "{sv}", &iter_array) || + !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) || + !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &pid) || + !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "u", &iter_variant) || + !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT32, &pid_u32) || + !dbus_message_iter_close_container(&iter_dict, &iter_variant) || + !dbus_message_iter_close_container(&iter_array, &iter_dict) || + !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) || + !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &starttime) || + !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "t", &iter_variant) || + !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT64, &starttime_u64) || + !dbus_message_iter_close_container(&iter_dict, &iter_variant) || + !dbus_message_iter_close_container(&iter_array, &iter_dict) || + !dbus_message_iter_close_container(&iter_struct, &iter_array) || + !dbus_message_iter_close_container(&iter_msg, &iter_struct) || + !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &action) || + !dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_ARRAY, "{ss}", &iter_array) || + !dbus_message_iter_close_container(&iter_msg, &iter_array) || + !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_UINT32, &flags) || + !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &cancel_id)) { + r = -ENOMEM; + goto finish; + } + + reply = dbus_connection_send_with_reply_and_block(c, m, -1, error); + if (!reply) { + r = -EIO; + goto finish; + } + + if (dbus_set_error_from_message(error, reply)) { + r = -EIO; + goto finish; + } + + if (!dbus_message_iter_init(reply, &iter_msg) || + dbus_message_iter_get_arg_type(&iter_msg) != DBUS_TYPE_STRUCT) { + r = -EIO; + goto finish; + } + + dbus_message_iter_recurse(&iter_msg, &iter_struct); + + if (dbus_message_iter_get_arg_type(&iter_struct) != DBUS_TYPE_BOOLEAN) { + r = -EIO; + goto finish; + } + + dbus_message_iter_get_basic(&iter_struct, &authorized); + + r = authorized ? 0 : -EPERM; + +finish: + + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + return r; +} + +static int bus_hostname_append_icon_name(DBusMessageIter *i, const char *property, void *userdata) { + const char *name; + + assert(i); + assert(property); + + if (isempty(data[PROP_ICON_NAME])) + name = fallback_icon_name(); + else + name = data[PROP_ICON_NAME]; + + return bus_property_append_string(i, property, (void*) name); +} + +static DBusHandlerResult hostname_message_handler( + DBusConnection *connection, + DBusMessage *message, + void *userdata) { + + const BusProperty properties[] = { + { "org.freedesktop.hostname1", "Hostname", bus_property_append_string, "s", data[PROP_HOSTNAME]}, + { "org.freedesktop.hostname1", "StaticHostname", bus_property_append_string, "s", data[PROP_STATIC_HOSTNAME]}, + { "org.freedesktop.hostname1", "PrettyHostname", bus_property_append_string, "s", data[PROP_PRETTY_HOSTNAME]}, + { "org.freedesktop.hostname1", "IconName", bus_hostname_append_icon_name, "s", data[PROP_ICON_NAME]}, + { NULL, NULL, NULL, NULL, NULL } + }; + + DBusMessage *reply = NULL, *changed = NULL; + DBusError error; + int r; + + assert(connection); + assert(message); + + dbus_error_init(&error); + + if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetHostname")) { + const char *name; + dbus_bool_t interactive; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + if (isempty(name)) + name = data[PROP_STATIC_HOSTNAME]; + + if (isempty(name)) + name = "localhost"; + + if (!hostname_is_valid(name)) + return bus_send_error_reply(connection, message, NULL, -EINVAL); + + if (!streq_ptr(name, data[PROP_HOSTNAME])) { + char *h; + + r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-hostname", interactive, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + h = strdup(name); + if (!h) + goto oom; + + free(data[PROP_HOSTNAME]); + data[PROP_HOSTNAME] = h; + + r = write_data_hostname(); + if (r < 0) { + log_error("Failed to set host name: %s", strerror(-r)); + return bus_send_error_reply(connection, message, NULL, r); + } + + log_info("Changed host name to '%s'", strempty(data[PROP_HOSTNAME])); + + changed = bus_properties_changed_new( + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + "Hostname\0"); + if (!changed) + goto oom; + } + + } else if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetStaticHostname")) { + const char *name; + dbus_bool_t interactive; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + if (isempty(name)) + name = NULL; + + if (!streq_ptr(name, data[PROP_STATIC_HOSTNAME])) { + + r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-static-hostname", interactive, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + if (isempty(name)) { + free(data[PROP_STATIC_HOSTNAME]); + data[PROP_STATIC_HOSTNAME] = NULL; + } else { + char *h; + + if (!hostname_is_valid(name)) + return bus_send_error_reply(connection, message, NULL, -EINVAL); + + h = strdup(name); + if (!h) + goto oom; + + free(data[PROP_STATIC_HOSTNAME]); + data[PROP_STATIC_HOSTNAME] = h; + } + + r = write_data_static_hostname(); + if (r < 0) { + log_error("Failed to write static host name: %s", strerror(-r)); + return bus_send_error_reply(connection, message, NULL, r); + } + + log_info("Changed static host name to '%s'", strempty(data[PROP_HOSTNAME])); + + changed = bus_properties_changed_new( + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + "StaticHostname\0"); + if (!changed) + goto oom; + } + + } else if (dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetPrettyHostname") || + dbus_message_is_method_call(message, "org.freedesktop.hostname1", "SetIconName")) { + + const char *name; + dbus_bool_t interactive; + int k; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_BOOLEAN, &interactive, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + if (isempty(name)) + name = NULL; + + k = streq(dbus_message_get_member(message), "SetPrettyHostname") ? PROP_PRETTY_HOSTNAME : PROP_ICON_NAME; + + if (!streq_ptr(name, data[k])) { + + r = verify_polkit(connection, message, "org.freedesktop.hostname1.set-machine-info", interactive, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + if (isempty(name)) { + free(data[k]); + data[k] = NULL; + } else { + char *h; + + h = strdup(name); + if (!h) + goto oom; + + free(data[k]); + data[k] = h; + } + + r = write_data_other(); + if (r < 0) { + log_error("Failed to write machine info: %s", strerror(-r)); + return bus_send_error_reply(connection, message, NULL, r); + } + + log_info("Changed %s to '%s'", k == PROP_PRETTY_HOSTNAME ? "pretty host name" : "icon name", strempty(data[k])); + + changed = bus_properties_changed_new( + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + k == PROP_PRETTY_HOSTNAME ? "PrettyHostname\0" : "IconName\0"); + if (!changed) + goto oom; + } + + } else + return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties); + + if (!(reply = dbus_message_new_method_return(message))) + goto oom; + + if (!dbus_connection_send(connection, reply, NULL)) + goto oom; + + dbus_message_unref(reply); + reply = NULL; + + if (changed) { + + if (!dbus_connection_send(connection, changed, NULL)) + goto oom; + + dbus_message_unref(changed); + } + + return DBUS_HANDLER_RESULT_HANDLED; + +oom: + if (reply) + dbus_message_unref(reply); + + if (changed) + dbus_message_unref(changed); + + dbus_error_free(&error); + + return DBUS_HANDLER_RESULT_NEED_MEMORY; +} + +int main(int argc, char *argv[]) { + const DBusObjectPathVTable hostname_vtable = { + .message_function = hostname_message_handler + }; + + DBusConnection *bus = NULL; + DBusError error; + int r; + + dbus_error_init(&error); + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + if (argc != 1) { + log_error("This program takes no arguments."); + r = -EINVAL; + goto finish; + } + + umask(0022); + + r = read_data(); + if (r < 0) { + log_error("Failed to read hostname data: %s", strerror(-r)); + goto finish; + } + + bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); + if (!bus) { + log_error("Failed to get system D-Bus connection: %s", error.message); + r = -ECONNREFUSED; + goto finish; + } + + if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL)) { + log_error("Not enough memory"); + r = -ENOMEM; + goto finish; + } + + if (dbus_bus_request_name(bus, "org.freedesktop.hostname1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) < 0) { + log_error("Failed to register name on bus: %s", error.message); + r = -EEXIST; + goto finish; + } + + while (dbus_connection_read_write_dispatch(bus, -1)) + ; + + r = 0; + +finish: + free_data(); + + if (bus) { + dbus_connection_flush(bus); + dbus_connection_close(bus); + dbus_connection_unref(bus); + } + + dbus_error_free(&error); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/initctl.c b/src/initctl.c index 15da4593d0..dd743142fd 100644 --- a/src/initctl.c +++ b/src/initctl.c @@ -42,9 +42,10 @@ #include "special.h" #include "sd-daemon.h" #include "dbus-common.h" +#include "def.h" #define SERVER_FD_MAX 16 -#define TIMEOUT ((int) (10*MSEC_PER_SEC)) +#define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)) typedef struct Fifo Fifo; @@ -388,7 +389,7 @@ int main(int argc, char *argv[]) { if ((k = epoll_wait(server.epoll_fd, &event, 1, - TIMEOUT)) < 0) { + TIMEOUT_MSEC)) < 0) { if (errno == EINTR) continue; @@ -476,6 +476,52 @@ int job_run_and_invalidate(Job *j) { return r; } +static void job_print_status_message(Unit *u, JobType t, JobResult result) { + assert(u); + + if (t == JOB_START) { + + switch (result) { + + case JOB_DONE: + unit_status_printf(u, "Started %s.\n", unit_description(u)); + break; + + case JOB_FAILED: + unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "failed" ANSI_HIGHLIGHT_OFF ", see 'systemctl status %s' for details.\n", unit_description(u), u->meta.id); + break; + + case JOB_DEPENDENCY: + unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "aborted" ANSI_HIGHLIGHT_OFF " because a dependency failed.\n", unit_description(u)); + break; + + case JOB_TIMEOUT: + unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "timed out" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u), u->meta.id); + break; + + default: + ; + } + + } else if (t == JOB_STOP) { + + switch (result) { + + case JOB_TIMEOUT: + unit_status_printf(u, "Stopping %s " ANSI_HIGHLIGHT_ON "timed out" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u), u->meta.id); + break; + + case JOB_DONE: + case JOB_FAILED: + unit_status_printf(u, "Stopped %s.\n", unit_description(u)); + break; + + default: + ; + } + } +} + int job_finish_and_invalidate(Job *j, JobResult result) { Unit *u; Unit *other; @@ -512,12 +558,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) { t = j->type; job_free(j); - if (result == JOB_FAILED && t == JOB_START) - unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "failed" ANSI_HIGHLIGHT_OFF ", see 'systemctl status %s' for details.\n", unit_description(u), u->meta.id); - else if (result == JOB_TIMEOUT && t == JOB_START) - unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "timed out" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u), u->meta.id); - else if (result == JOB_TIMEOUT && t == JOB_STOP) - unit_status_printf(u, "Stopping %s " ANSI_HIGHLIGHT_ON "timed out" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u), u->meta.id); + job_print_status_message(u, t, result); /* Fail depending jobs on failure */ if (result != JOB_DONE) { @@ -563,8 +604,14 @@ int job_finish_and_invalidate(Job *j, JobResult result) { * the unit itself. We don't tread JOB_CANCELED as failure in * this context. And JOB_FAILURE is already handled by the * unit itself. */ - if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) + if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) { + log_notice("Job %s/%s failed with result '%s'.", + u->meta.id, + job_type_to_string(t), + job_result_to_string(result)); + unit_trigger_on_failure(u); + } /* Try to start the next jobs that can be started */ SET_FOREACH(other, u->meta.dependencies[UNIT_AFTER], i) diff --git a/src/load-fragment.c b/src/load-fragment.c index 8635bdb226..6ec5090197 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -198,7 +198,7 @@ static int config_parse_listen( void *data, void *userdata) { - SocketPort *p; + SocketPort *p, *tail; Socket *s; assert(filename); @@ -220,6 +220,26 @@ static int config_parse_listen( } path_kill_slashes(p->path); + + } else if (streq(lvalue, "ListenSpecial")) { + p->type = SOCKET_SPECIAL; + + if (!(p->path = strdup(rvalue))) { + free(p); + return -ENOMEM; + } + + path_kill_slashes(p->path); + + } else if (streq(lvalue, "ListenNetlink")) { + p->type = SOCKET_SOCKET; + + if (socket_address_parse_netlink(&p->address, rvalue) < 0) { + log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue); + free(p); + return 0; + } + } else { p->type = SOCKET_SOCKET; @@ -246,7 +266,12 @@ static int config_parse_listen( } p->fd = -1; - LIST_PREPEND(SocketPort, port, s->ports, p); + + if (s->ports) { + LIST_FIND_TAIL(SocketPort, port, s->ports, tail); + LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p); + } else + LIST_PREPEND(SocketPort, port, s->ports, p); return 0; } @@ -1851,6 +1876,8 @@ static int load_from_path(Unit *u, const char *path) { { "RefuseManualStop", config_parse_bool, 0, &u->meta.refuse_manual_stop, "Unit" }, { "AllowIsolate", config_parse_bool, 0, &u->meta.allow_isolate, "Unit" }, { "DefaultDependencies", config_parse_bool, 0, &u->meta.default_dependencies, "Unit" }, + { "OnFailureIsolate", config_parse_bool, 0, &u->meta.on_failure_isolate, "Unit" }, + { "IgnoreOnIsolate", config_parse_bool, 0, &u->meta.ignore_on_isolate, "Unit" }, { "JobTimeoutSec", config_parse_usec, 0, &u->meta.job_timeout, "Unit" }, { "ConditionPathExists", config_parse_condition_path, CONDITION_PATH_EXISTS, u, "Unit" }, { "ConditionPathIsDirectory", config_parse_condition_path, CONDITION_PATH_IS_DIRECTORY, u, "Unit" }, @@ -1891,6 +1918,8 @@ static int load_from_path(Unit *u, const char *path) { { "ListenDatagram", config_parse_listen, 0, &u->socket, "Socket" }, { "ListenSequentialPacket", config_parse_listen, 0, &u->socket, "Socket" }, { "ListenFIFO", config_parse_listen, 0, &u->socket, "Socket" }, + { "ListenNetlink", config_parse_listen, 0, &u->socket, "Socket" }, + { "ListenSpecial", config_parse_listen, 0, &u->socket, "Socket" }, { "BindIPv6Only", config_parse_socket_bind, 0, &u->socket, "Socket" }, { "Backlog", config_parse_unsigned, 0, &u->socket.backlog, "Socket" }, { "BindToDevice", config_parse_bindtodevice, 0, &u->socket, "Socket" }, @@ -1943,6 +1972,8 @@ static int load_from_path(Unit *u, const char *path) { { "PathChanged", config_parse_path_spec, 0, &u->path, "Path" }, { "DirectoryNotEmpty", config_parse_path_spec, 0, &u->path, "Path" }, { "Unit", config_parse_path_unit, 0, &u->path, "Path" }, + { "MakeDirectory", config_parse_bool, 0, &u->path.make_directory, "Path" }, + { "DirectoryMode", config_parse_mode, 0, &u->path.directory_mode, "Path" }, /* The [Install] section is ignored here. */ { "Alias", NULL, 0, NULL, "Install" }, diff --git a/src/locale-setup.c b/src/locale-setup.c index 08e289d4ee..d9adfa33f4 100644 --- a/src/locale-setup.c +++ b/src/locale-setup.c @@ -71,7 +71,7 @@ int locale_setup(void) { if (detect_container(NULL) <= 0) if ((r = parse_env_file("/proc/cmdline", WHITESPACE, -#ifdef TARGET_FEDORA +#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO) "LANG", &variables[VARIABLE_LANG], #endif "locale.LANG", &variables[VARIABLE_LANG], @@ -116,7 +116,7 @@ int locale_setup(void) { log_warning("Failed to read /etc/locale.conf: %s", strerror(-r)); } -#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) +#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MEEGO) if (r <= 0 && (r = parse_env_file("/etc/sysconfig/i18n", NEWLINE, "LANG", &variables[VARIABLE_LANG], @@ -238,11 +238,11 @@ void log_set_max_level(int level) { } static int write_to_console( - int level, - const char*file, - int line, - const char *func, - const char *buffer) { + int level, + const char*file, + int line, + const char *func, + const char *buffer) { char location[64]; struct iovec iovec[5]; diff --git a/src/logger.c b/src/logger.c index faa6c9721f..81196dbe00 100644 --- a/src/logger.c +++ b/src/logger.c @@ -37,10 +37,11 @@ #include "list.h" #include "sd-daemon.h" #include "tcpwrap.h" +#include "def.h" #define STREAMS_MAX 4096 #define SERVER_FD_MAX 16 -#define TIMEOUT ((int) (5*60*MSEC_PER_SEC)) +#define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)) typedef struct Stream Stream; @@ -661,7 +662,7 @@ int main(int argc, char *argv[]) { if ((k = epoll_wait(server.epoll_fd, &event, 1, - server.n_streams <= 0 ? TIMEOUT : -1)) < 0) { + server.n_streams <= 0 ? TIMEOUT_MSEC : -1)) < 0) { if (errno == EINTR) continue; diff --git a/src/manager.c b/src/manager.c index 9b561c4cee..9c817b0e41 100644 --- a/src/manager.c +++ b/src/manager.c @@ -1167,13 +1167,13 @@ static void transaction_minimize_impact(Manager *m) { continue; if (stops_running_service) - log_info("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type)); + log_debug("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type)); if (changes_existing_job) - log_info("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type)); + log_debug("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type)); /* Ok, let's get rid of this */ - log_info("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type)); + log_debug("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type)); transaction_delete_job(m, j, true); again = true; @@ -1187,13 +1187,27 @@ static void transaction_minimize_impact(Manager *m) { } while (again); } -static int transaction_apply(Manager *m) { +static int transaction_apply(Manager *m, JobMode mode) { Iterator i; Job *j; int r; /* Moves the transaction jobs to the set of active jobs */ + if (mode == JOB_ISOLATE) { + + /* When isolating first kill all installed jobs which + * aren't part of the new transaction */ + HASHMAP_FOREACH(j, m->jobs, i) { + assert(j->installed); + + if (hashmap_get(m->transaction_jobs, j->unit)) + continue; + + job_finish_and_invalidate(j, JOB_CANCELED); + } + } + HASHMAP_FOREACH(j, m->transaction_jobs, i) { /* Assume merged */ assert(!j->transaction_prev); @@ -1273,7 +1287,8 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) { for (;;) { /* Fourth step: Let's remove unneeded jobs that might * be lurking. */ - transaction_collect_garbage(m); + if (mode != JOB_ISOLATE) + transaction_collect_garbage(m); /* Fifth step: verify order makes sense and correct * cycles if necessary and possible */ @@ -1303,7 +1318,8 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) { /* Seventh step: an entry got dropped, let's garbage * collect its dependencies. */ - transaction_collect_garbage(m); + if (mode != JOB_ISOLATE) + transaction_collect_garbage(m); /* Let's see if the resulting transaction still has * unmergeable entries ... */ @@ -1320,7 +1336,7 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) { } /* Tenth step: apply changes */ - if ((r = transaction_apply(m)) < 0) { + if ((r = transaction_apply(m, mode)) < 0) { log_warning("Failed to apply transaction: %s", strerror(-r)); goto rollback; } @@ -1617,7 +1633,7 @@ static int transaction_add_isolate_jobs(Manager *m) { if (u->meta.id != k) continue; - if (UNIT_VTABLE(u)->no_isolate) + if (u->meta.ignore_on_isolate) continue; /* No need to stop inactive jobs */ @@ -2638,6 +2654,11 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds) { assert(f); assert(fds); + m->n_serializing ++; + + fprintf(f, "current-job-id=%i\n", m->current_job_id); + fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr)); + dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp); dual_timestamp_serialize(f, "startup-timestamp", &m->startup_timestamp); dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp); @@ -2655,10 +2676,15 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds) { fputs(u->meta.id, f); fputc('\n', f); - if ((r = unit_serialize(u, f, fds)) < 0) + if ((r = unit_serialize(u, f, fds)) < 0) { + m->n_serializing --; return r; + } } + assert(m->n_serializing > 0); + m->n_serializing --; + if (ferror(f)) return -EIO; @@ -2676,7 +2702,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { m->n_deserializing ++; for (;;) { - char line[1024], *l; + char line[LINE_MAX], *l; if (!fgets(line, sizeof(line), f)) { if (feof(f)) @@ -2693,7 +2719,21 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { if (l[0] == 0) break; - if (startswith(l, "initrd-timestamp=")) + if (startswith(l, "current-job-id=")) { + uint32_t id; + + if (safe_atou32(l+15, &id) < 0) + log_debug("Failed to parse current job id value %s", l+15); + else + m->current_job_id = MAX(m->current_job_id, id); + } else if (startswith(l, "taint-usr=")) { + int b; + + if ((b = parse_boolean(l+10)) < 0) + log_debug("Failed to parse taint /usr flag %s", l+10); + else + m->taint_usr = m->taint_usr || b; + } else if (startswith(l, "initrd-timestamp=")) dual_timestamp_deserialize(l+17, &m->initrd_timestamp); else if (startswith(l, "startup-timestamp=")) dual_timestamp_deserialize(l+18, &m->startup_timestamp); @@ -2748,15 +2788,21 @@ int manager_reload(Manager *m) { if ((r = manager_open_serialization(m, &f)) < 0) return r; + m->n_serializing ++; + if (!(fds = fdset_new())) { + m->n_serializing --; r = -ENOMEM; goto finish; } - if ((r = manager_serialize(m, f, fds)) < 0) + if ((r = manager_serialize(m, f, fds)) < 0) { + m->n_serializing --; goto finish; + } if (fseeko(f, 0, SEEK_SET) < 0) { + m->n_serializing --; r = -errno; goto finish; } @@ -2765,6 +2811,9 @@ int manager_reload(Manager *m) { manager_clear_jobs_and_units(m); manager_undo_generators(m); + assert(m->n_serializing > 0); + m->n_serializing --; + /* Find new unit paths */ lookup_paths_free(&m->lookup_paths); if ((q = lookup_paths_init(&m->lookup_paths, m->running_as)) < 0) @@ -2901,13 +2950,22 @@ void manager_run_generators(Manager *m) { } if (!m->generator_unit_path) { - char *p; - char system_path[] = "/run/systemd/generator-XXXXXX", - user_path[] = "/tmp/systemd-generator-XXXXXX"; + const char *p; + char user_path[] = "/tmp/systemd-generator-XXXXXX"; - if (!(p = mkdtemp(m->running_as == MANAGER_SYSTEM ? system_path : user_path))) { - log_error("Failed to generate generator directory: %m"); - goto finish; + if (m->running_as == MANAGER_SYSTEM && getpid() == 1) { + p = "/run/systemd/generator"; + + if (mkdir_p(p, 0755) < 0) { + log_error("Failed to create generator directory: %m"); + goto finish; + } + + } else { + if (!(p = mkdtemp(user_path))) { + log_error("Failed to create generator directory: %m"); + goto finish; + } } if (!(m->generator_unit_path = strdup(p))) { diff --git a/src/manager.h b/src/manager.h index 4b405d61c1..07b92c8e4e 100644 --- a/src/manager.h +++ b/src/manager.h @@ -223,6 +223,7 @@ struct Manager { ExecOutput default_std_output, default_std_error; + int n_serializing; int n_deserializing; unsigned n_installed_jobs; diff --git a/src/mount-setup.c b/src/mount-setup.c index a42ed43957..db5c253708 100644 --- a/src/mount-setup.c +++ b/src/mount-setup.c @@ -55,8 +55,8 @@ static const MountPoint mount_table[] = { { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV, true }, { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, false }, { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true }, - { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true }, - { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, true }, + { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, false }, + { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, false }, }; /* These are API file systems that might be mounted by other software, @@ -64,9 +64,7 @@ static const MountPoint mount_table[] = { static const char * const ignore_paths[] = { "/selinux", - "/proc/bus/usb", - "/var/lib/nfs/rpc_pipefs", - "/proc/fs/nfsd" + "/proc/bus/usb" }; bool mount_point_is_api(const char *path) { @@ -97,11 +95,14 @@ static int mount_one(const MountPoint *p) { assert(p); + /* Relabel first, just in case */ + label_fix(p->where, true); + if ((r = path_is_mount_point(p->where)) < 0) return r; if (r > 0) - goto finish; + return 0; /* The access mode here doesn't really matter too much, since * the mounted file system will take precedence anyway. */ @@ -122,7 +123,7 @@ static int mount_one(const MountPoint *p) { return p->fatal ? -errno : 0; } -finish: + /* Relabel again, since we now mounted something fresh here */ label_fix(p->where, false); return 0; @@ -131,7 +132,7 @@ finish: static int mount_cgroup_controllers(void) { int r; FILE *f; - char buf [256]; + char buf[LINE_MAX]; /* Mount all available cgroup controllers that are built into the kernel. */ @@ -239,25 +240,23 @@ int mount_setup(void) { if ((r = mount_one(mount_table+i)) < 0) return r; - /* Nodes in devtmpfs need to be manually updated for the - * appropriate labels, after mounting. The other virtual API - * file systems do not need. */ - + /* Nodes in devtmpfs and /run need to be manually updated for + * the appropriate labels, after mounting. The other virtual + * API file systems like /sys and /proc do not need that, they + * use the same label for all their files. */ if (unlink("/dev/.systemd-relabel-run-dev") >= 0) { nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS); nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS); } /* Create a few default symlinks, which are normally created - * bei udevd, but some scripts might need them before we start + * by udevd, but some scripts might need them before we start * udevd. */ - NULSTR_FOREACH_PAIR(j, k, symlinks) symlink_and_label(j, k); /* Create a few directories we always want around */ mkdir("/run/systemd", 0755); - mkdir("/run/systemd/ask-password", 0755); return mount_cgroup_controllers(); } diff --git a/src/mount.c b/src/mount.c index 49bfd079a6..4b300364af 100644 --- a/src/mount.c +++ b/src/mount.c @@ -65,7 +65,11 @@ static void mount_init(Unit *u) { m->directory_mode = 0755; exec_context_init(&m->exec_context); - m->exec_context.std_output = EXEC_OUTPUT_KMSG; + + /* The stdio/kmsg bridge socket is on /, in order to avoid a + * dep loop, don't use kmsg logging for -.mount */ + if (!unit_has_name(u, "-.mount")) + m->exec_context.std_output = EXEC_OUTPUT_KMSG; /* We need to make sure that /bin/mount is always called in * the same process group as us, so that the autofs kernel @@ -76,6 +80,8 @@ static void mount_init(Unit *u) { m->timer_watch.type = WATCH_INVALID; m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; + + m->meta.ignore_on_isolate = true; } static void mount_unwatch_control_pid(Mount *m) { @@ -317,7 +323,7 @@ static bool needs_quota(MountParameters *p) { mount_test_option(p->options, "grpquota"); } -static int mount_add_target_links(Mount *m) { +static int mount_add_fstab_links(Mount *m) { const char *target, *after = NULL; MountParameters *p; Unit *tu; @@ -326,27 +332,36 @@ static int mount_add_target_links(Mount *m) { assert(m); + if (m->meta.manager->running_as != MANAGER_SYSTEM) + return 0; + if (!(p = get_mount_parameters_configured(m))) return 0; - noauto = !!mount_test_option(p->options, MNTOPT_NOAUTO); + if (p != &m->parameters_etc_fstab) + return 0; + + noauto = !!mount_test_option(p->options, "noauto"); nofail = !!mount_test_option(p->options, "nofail"); + automount = + mount_test_option(p->options, "comment=systemd.automount") || + mount_test_option(p->options, "x-systemd-automount"); handle = + automount || mount_test_option(p->options, "comment=systemd.mount") || mount_test_option(p->options, "x-systemd-mount") || m->meta.manager->mount_auto; - automount = - mount_test_option(p->options, "comment=systemd.automount") || - mount_test_option(p->options, "x-systemd-automount"); if (mount_is_network(p)) { target = SPECIAL_REMOTE_FS_TARGET; - - if (m->meta.manager->running_as == MANAGER_SYSTEM) - after = SPECIAL_NETWORK_TARGET; + after = SPECIAL_NETWORK_TARGET; } else target = SPECIAL_LOCAL_FS_TARGET; + if (!path_equal(m->where, "/")) + if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0) + return r; + if ((r = manager_load_unit(m->meta.manager, target, NULL, NULL, &tu)) < 0) return r; @@ -354,27 +369,36 @@ static int mount_add_target_links(Mount *m) { if ((r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true)) < 0) return r; - if (automount && m->meta.manager->running_as == MANAGER_SYSTEM) { + if (automount) { Unit *am; if ((r = unit_load_related_unit(UNIT(m), ".automount", &am)) < 0) return r; - return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_WANTS, UNIT(am), true); - } else { + /* If auto is configured as well also pull in the + * mount right-away, but don't rely on it. */ + if (!noauto) /* automount + auto */ + if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true)) < 0) + return r; + + /* Install automount unit */ + if (!nofail) /* automount + fail */ + return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_REQUIRES, UNIT(am), true); + else /* automount + nofail */ + return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_WANTS, UNIT(am), true); + + } else if (handle && !noauto) { /* Automatically add mount points that aren't natively * configured to local-fs.target */ - if (!noauto && - !nofail && - handle && - m->from_etc_fstab && - m->meta.manager->running_as == MANAGER_SYSTEM) - if ((r = unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true)) < 0) - return r; - return unit_add_dependency(UNIT(m), UNIT_BEFORE, tu, true); + if (!nofail) /* auto + fail */ + return unit_add_two_dependencies(tu, UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true); + else /* auto + nofail */ + return unit_add_dependency(tu, UNIT_WANTS, UNIT(m), true); } + + return 0; } static int mount_add_device_links(Mount *m) { @@ -389,10 +413,12 @@ static int mount_add_device_links(Mount *m) { if (!p->what) return 0; - if (!mount_is_bind(p) && !path_equal(m->where, "/")) { + if (!mount_is_bind(p) && + !path_equal(m->where, "/") && + p == &m->parameters_etc_fstab) { bool nofail, noauto; - noauto = !!mount_test_option(p->options, MNTOPT_NOAUTO); + noauto = !!mount_test_option(p->options, "noauto"); nofail = !!mount_test_option(p->options, "nofail"); if ((r = unit_add_node_link(UNIT(m), p->what, @@ -454,6 +480,54 @@ static int mount_add_default_dependencies(Mount *m) { return 0; } +static int mount_fix_timeouts(Mount *m) { + MountParameters *p; + const char *timeout = NULL; + Unit *other; + Iterator i; + usec_t u; + char *t; + int r; + + assert(m); + + if (!(p = get_mount_parameters_configured(m))) + return 0; + + /* 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. */ + + if ((timeout = mount_test_option(p->options, "comment=systemd.device-timeout"))) + timeout += 31; + else if ((timeout = mount_test_option(p->options, "x-systemd-device-timeout"))) + timeout += 25; + else + return 0; + + t = strndup(timeout, strcspn(timeout, ",;" WHITESPACE)); + if (!t) + return -ENOMEM; + + r = parse_usec(t, &u); + free(t); + + if (r < 0) { + log_warning("Failed to parse timeout for %s, ignoring: %s", m->where, timeout); + return r; + } + + SET_FOREACH(other, m->meta.dependencies[UNIT_AFTER], i) { + if (other->meta.type != UNIT_DEVICE) + continue; + + other->meta.job_timeout = u; + } + + return 0; +} + static int mount_verify(Mount *m) { bool b; char *e; @@ -511,6 +585,8 @@ static int mount_load(Unit *u) { if (m->meta.fragment_path) m->from_fragment = true; + else if (m->from_etc_fstab) + m->meta.default_dependencies = false; if (!m->where) if (!(m->where = unit_name_to_path(u->meta.id))) @@ -540,15 +616,17 @@ static int mount_load(Unit *u) { if ((r = mount_add_automount_links(m)) < 0) return r; - if ((r = mount_add_target_links(m)) < 0) - return r; - - if ((r = unit_add_default_cgroups(u)) < 0) + if ((r = mount_add_fstab_links(m)) < 0) return r; if (m->meta.default_dependencies) if ((r = mount_add_default_dependencies(m)) < 0) return r; + + if ((r = unit_add_default_cgroups(u)) < 0) + return r; + + mount_fix_timeouts(m); } return mount_verify(m); @@ -1454,7 +1532,7 @@ static int mount_load_etc_fstab(Manager *m) { what, NULL, pri, - !!mount_test_option(me->mnt_opts, MNTOPT_NOAUTO), + !!mount_test_option(me->mnt_opts, "noauto"), !!mount_test_option(me->mnt_opts, "nofail"), !!mount_test_option(me->mnt_opts, "comment=systemd.swapon"), false); @@ -1759,7 +1837,6 @@ const UnitVTable mount_vtable = { .no_alias = true, .no_instances = true, - .no_isolate = true, .show_status = true, .init = mount_init, diff --git a/src/nspawn.c b/src/nspawn.c index 6b0ba4e57f..969c961895 100644 --- a/src/nspawn.c +++ b/src/nspawn.c @@ -374,6 +374,7 @@ static int is_os_tree(const char *path) { #define BUFFER_SIZE 1024 static int process_pty(int master, sigset_t *mask) { + char in_buffer[BUFFER_SIZE], out_buffer[BUFFER_SIZE]; size_t in_buffer_full = 0, out_buffer_full = 0; struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev; @@ -464,11 +465,13 @@ static int process_pty(int master, sigset_t *mask) { if ((n = read(signal_fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) { if (n >= 0) { + log_error("Failed to read from signalfd: invalid block size"); r = -EIO; goto finish; } if (errno != EINTR && errno != EAGAIN) { + log_error("Failed to read from signalfd: %m"); r = -errno; goto finish; } @@ -481,7 +484,7 @@ static int process_pty(int master, sigset_t *mask) { if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0) ioctl(master, TIOCSWINSZ, &ws); } else { - r = -EINTR; + r = 0; goto finish; } } @@ -501,6 +504,7 @@ static int process_pty(int master, sigset_t *mask) { stdin_readable = false; else { log_error("read(): %m"); + r = -errno; goto finish; } } else @@ -515,6 +519,7 @@ static int process_pty(int master, sigset_t *mask) { master_writable = false; else { log_error("write(): %m"); + r = -errno; goto finish; } @@ -533,6 +538,7 @@ static int process_pty(int master, sigset_t *mask) { master_readable = false; else { log_error("read(): %m"); + r = -errno; goto finish; } } else @@ -547,6 +553,7 @@ static int process_pty(int master, sigset_t *mask) { stdout_writable = false; else { log_error("write(): %m"); + r = -errno; goto finish; } diff --git a/src/org.freedesktop.hostname1.conf b/src/org.freedesktop.hostname1.conf new file mode 100644 index 0000000000..eb241c022f --- /dev/null +++ b/src/org.freedesktop.hostname1.conf @@ -0,0 +1,27 @@ +<?xml version="1.0"?> <!--*-nxml-*--> +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> + +<!-- + This file is part of systemd. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +--> + +<busconfig> + + <policy user="root"> + <allow own="org.freedesktop.hostname1"/> + <allow send_destination="org.freedesktop.hostname1"/> + <allow receive_sender="org.freedesktop.hostname1"/> + </policy> + + <policy context="default"> + <allow send_destination="org.freedesktop.hostname1"/> + <allow receive_sender="org.freedesktop.hostname1"/> + </policy> + +</busconfig> diff --git a/src/org.freedesktop.hostname1.policy b/src/org.freedesktop.hostname1.policy new file mode 100644 index 0000000000..148874fc89 --- /dev/null +++ b/src/org.freedesktop.hostname1.policy @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*--> +<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" + "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd"> + +<!-- + This file is part of systemd. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +--> + +<policyconfig> + + <vendor>The systemd Project</vendor> + <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url> + + <action id="org.freedesktop.hostname1.set-hostname"> + <description>Set host name</description> + <message>Authentication is required to set the local host name.</message> + <defaults> + <allow_any>auth_admin_keep</allow_any> + <allow_inactive>auth_admin_keep</allow_inactive> + <allow_active>auth_admin_keep</allow_active> + </defaults> + </action> + + <action id="org.freedesktop.hostname1.set-static-hostname"> + <description>Set static host name</description> + <message>Authentication is required to set the statically configured local host name.</message> + <defaults> + <allow_any>auth_admin_keep</allow_any> + <allow_inactive>auth_admin_keep</allow_inactive> + <allow_active>auth_admin_keep</allow_active> + </defaults> + </action> + + <action id="org.freedesktop.hostname1.set-machine-info"> + <description>Set machine information</description> + <message>Authentication is required to set local machine information.</message> + <defaults> + <allow_any>auth_admin_keep</allow_any> + <allow_inactive>auth_admin_keep</allow_inactive> + <allow_active>auth_admin_keep</allow_active> + </defaults> + </action> + +</policyconfig> diff --git a/src/org.freedesktop.hostname1.service b/src/org.freedesktop.hostname1.service new file mode 100644 index 0000000000..42e4adb2c9 --- /dev/null +++ b/src/org.freedesktop.hostname1.service @@ -0,0 +1,12 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +[D-BUS Service] +Name=org.freedesktop.hostname1 +Exec=/bin/false +User=root +SystemdService=dbus-org.freedesktop.hostname1.service diff --git a/src/org.freedesktop.systemd1.policy.in b/src/org.freedesktop.systemd1.policy.in index b8b354726b..52a28d40ea 100644 --- a/src/org.freedesktop.systemd1.policy.in +++ b/src/org.freedesktop.systemd1.policy.in @@ -16,7 +16,7 @@ <vendor>The systemd Project</vendor> <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url> - <action id="org.freedesktop.systemd1.ReplyPassword"> + <action id="org.freedesktop.systemd1.reply-password"> <description>Send passphrase back to system</description> <message>Authentication is required to send the entered passphrase back to the system.</message> <defaults> @@ -27,7 +27,7 @@ <annotate key="org.freedesktop.policykit.exec.path">@rootlibexecdir@/systemd-reply-password</annotate> </action> - <action id="org.freedesktop.systemd1.BusAccess"> + <action id="org.freedesktop.systemd1.bus-access"> <description>Privileged system and service manager access</description> <message>Authentication is required to access the system and service manager.</message> <defaults> diff --git a/src/pam-module.c b/src/pam-module.c index 6486546e6d..93eb929569 100644 --- a/src/pam-module.c +++ b/src/pam-module.c @@ -24,6 +24,7 @@ #include <sys/file.h> #include <pwd.h> #include <endian.h> +#include <sys/capability.h> #include <security/pam_modules.h> #include <security/_pam_macros.h> @@ -220,18 +221,19 @@ static uint64_t get_session_id(int *mode) { /* First attempt: let's use the session ID of the audit * system, if it is available. */ - if (read_one_line_file("/proc/self/sessionid", &s) >= 0) { - uint32_t u; - int r; + if (have_effective_cap(CAP_AUDIT_CONTROL) > 0) + if (read_one_line_file("/proc/self/sessionid", &s) >= 0) { + uint32_t u; + int r; - r = safe_atou32(s, &u); - free(s); + r = safe_atou32(s, &u); + free(s); - if (r >= 0 && u != (uint32_t) -1 && u > 0) { - *mode = SESSION_ID_AUDIT; - return (uint64_t) u; + if (r >= 0 && u != (uint32_t) -1 && u > 0) { + *mode = SESSION_ID_AUDIT; + return (uint64_t) u; + } } - } /* Second attempt, use our own counter. */ if ((fd = open_file_and_lock(RUNTIME_DIR "/user/.pam-systemd-session")) >= 0) { @@ -288,15 +290,24 @@ static int get_user_data( assert(ret_username); assert(ret_pw); - if (read_one_line_file("/proc/self/loginuid", &s) >= 0) { - uint32_t u; + if (have_effective_cap(CAP_AUDIT_CONTROL) > 0) { + /* Only use audit login uid if we are executed with + * sufficient capabilities so that pam_loginuid could + * do its job. If we are lacking the CAP_AUDIT_CONTROL + * capabality we most likely are being run in a + * container and /proc/self/loginuid is useless since + * it probably contains a uid of the host system. */ - r = safe_atou32(s, &u); - free(s); + if (read_one_line_file("/proc/self/loginuid", &s) >= 0) { + uint32_t u; - if (r >= 0 && u != (uint32_t) -1 && u > 0) { - have_loginuid = true; - pw = pam_modutil_getpwuid(handle, u); + r = safe_atou32(s, &u); + free(s); + + if (r >= 0 && u != (uint32_t) -1 && u > 0) { + have_loginuid = true; + pw = pam_modutil_getpwuid(handle, u); + } } } diff --git a/src/path.c b/src/path.c index f7878b56ae..1a3e28f89f 100644 --- a/src/path.c +++ b/src/path.c @@ -39,6 +39,15 @@ static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = { [PATH_FAILED] = UNIT_FAILED }; +static void path_init(Unit *u) { + Path *p = PATH(u); + + assert(u); + assert(u->meta.load_state == UNIT_STUB); + + p->directory_mode = 0755; +} + static void path_unwatch_one(Path *p, PathSpec *s) { if (s->inotify_fd < 0) @@ -169,9 +178,13 @@ static void path_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%sPath State: %s\n" - "%sUnit: %s\n", + "%sUnit: %s\n" + "%sMakeDirectory: %s\n" + "%sDirectoryMode: %04o\n", prefix, path_state_to_string(p->state), - prefix, p->unit->meta.id); + prefix, p->unit->meta.id, + prefix, yes_no(p->make_directory), + prefix, p->directory_mode); LIST_FOREACH(spec, s, p->specs) fprintf(f, @@ -408,6 +421,25 @@ fail: path_enter_dead(p, false); } +static void path_mkdir(Path *p) { + PathSpec *s; + + assert(p); + + if (!p->make_directory) + return; + + LIST_FOREACH(spec, s, p->specs) { + int r; + + if (s->type == PATH_EXISTS) + continue; + + if ((r = mkdir_p(s->path, p->directory_mode)) < 0) + log_warning("mkdir(%s) failed: %s", s->path, strerror(-r)); + } +} + static int path_start(Unit *u) { Path *p = PATH(u); @@ -417,6 +449,8 @@ static int path_start(Unit *u) { if (p->unit->meta.load_state != UNIT_LOADED) return -ENOENT; + path_mkdir(p); + p->failure = false; path_enter_waiting(p, true, true, false); @@ -639,6 +673,7 @@ DEFINE_STRING_TABLE_LOOKUP(path_type, PathType); const UnitVTable path_vtable = { .suffix = ".path", + .init = path_init, .done = path_done, .load = path_load, diff --git a/src/path.h b/src/path.h index 0dff120331..8ba0ce6890 100644 --- a/src/path.h +++ b/src/path.h @@ -70,6 +70,9 @@ struct Path { bool failure; bool inotify_triggered; + + bool make_directory; + mode_t directory_mode; }; void path_unit_notify(Unit *u, UnitActiveState new_state); diff --git a/src/readahead-common.c b/src/readahead-common.c index fc49a33109..8a75b2e135 100644 --- a/src/readahead-common.c +++ b/src/readahead-common.c @@ -209,7 +209,6 @@ finish: return m; } - #define BUMP_REQUEST_NR (16*1024) int bump_request_nr(const char *p) { diff --git a/src/reply-password.c b/src/reply-password.c index 575a437645..bd55e65f3c 100644 --- a/src/reply-password.c +++ b/src/reply-password.c @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) { } truncate_nl(packet+1); - length = strlen(packet+1) + 1; + length = 1 + strlen(packet+1) + 1; } else if (streq(argv[1], "0")) { packet[0] = '-'; length = 1; diff --git a/src/service.c b/src/service.c index 7f8d005f00..0845d21bad 100644 --- a/src/service.c +++ b/src/service.c @@ -1470,7 +1470,7 @@ static void service_set_state(Service *s, ServiceState state) { /* For the inactive states unit_notify() will trim the cgroup, * but for exit we have to do that ourselves... */ - if (state == SERVICE_EXITED) + if (state == SERVICE_EXITED && s->meta.manager->n_deserializing <= 0) cgroup_bonding_trim_list(s->meta.cgroup_bondings, true); if (old_state != state) diff --git a/src/socket-util.c b/src/socket-util.c index 9b4a1b3b48..779850d37f 100644 --- a/src/socket-util.c +++ b/src/socket-util.c @@ -189,50 +189,102 @@ int socket_address_parse(SocketAddress *a, const char *s) { return 0; } +int socket_address_parse_netlink(SocketAddress *a, const char *s) { + int family; + unsigned group = 0; + 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 ? -errno : -EINVAL; + + if ((family = netlink_family_from_string(sfamily)) < 0) + if (safe_atoi(sfamily, &family) < 0) { + free(sfamily); + return -EINVAL; + } + + free(sfamily); + + 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.in4.sin_port == 0) - return -EINVAL; + case AF_INET: + if (a->size != sizeof(struct sockaddr_in)) + return -EINVAL; - return 0; + if (a->sockaddr.in4.sin_port == 0) + return -EINVAL; - case AF_INET6: - if (a->size != sizeof(struct sockaddr_in6)) - return -EINVAL; + if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM) + return -EINVAL; - if (a->sockaddr.in6.sin6_port == 0) - return -EINVAL; + return 0; + + case AF_INET6: + if (a->size != sizeof(struct sockaddr_in6)) + return -EINVAL; - return 0; + if (a->sockaddr.in6.sin6_port == 0) + return -EINVAL; - case AF_UNIX: - if (a->size < offsetof(struct sockaddr_un, sun_path)) - return -EINVAL; + if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM) + return -EINVAL; - if (a->size > offsetof(struct sockaddr_un, sun_path)) { + return 0; - if (a->sockaddr.un.sun_path[0] != 0) { - char *e; + case AF_UNIX: + if (a->size < offsetof(struct sockaddr_un, sun_path)) + return -EINVAL; - /* path */ - if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path)))) - return -EINVAL; + if (a->size > offsetof(struct sockaddr_un, sun_path)) { - if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1) - return -EINVAL; - } + if (a->sockaddr.un.sun_path[0] != 0) { + char *e; + + /* path */ + if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path)))) + return -EINVAL; + + if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1) + return -EINVAL; } + } - return 0; + if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET) + return -EINVAL; - default: - return -EAFNOSUPPORT; + 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; } } @@ -245,74 +297,89 @@ int socket_address_print(const SocketAddress *a, char **p) { return r; switch (socket_address_family(a)) { - case AF_INET: { - char *ret; - if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1))) - return -ENOMEM; + case AF_INET: { + char *ret; - if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) { - free(ret); - return -errno; - } + if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1))) + return -ENOMEM; - sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port)); - *p = ret; - return 0; + if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) { + free(ret); + return -errno; } - case AF_INET6: { - char *ret; + sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port)); + *p = ret; + return 0; + } - if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1))) - return -ENOMEM; + case AF_INET6: { + char *ret; - ret[0] = '['; - if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) { - free(ret); - return -errno; - } + if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1))) + return -ENOMEM; - sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port)); - *p = ret; - return 0; + ret[0] = '['; + if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) { + free(ret); + return -errno; } - case AF_UNIX: { - char *ret; + sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port)); + *p = ret; + return 0; + } - if (a->size <= offsetof(struct sockaddr_un, sun_path)) { + case AF_UNIX: { + char *ret; - if (!(ret = strdup("<unamed>"))) - return -ENOMEM; + if (a->size <= offsetof(struct sockaddr_un, sun_path)) { - } else if (a->sockaddr.un.sun_path[0] == 0) { - /* abstract */ + if (!(ret = strdup("<unnamed>"))) + return -ENOMEM; - /* 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 */ + } else if (a->sockaddr.un.sun_path[0] == 0) { + /* abstract */ - if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1))) - return -ENOMEM; + /* 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 */ - ret[0] = '@'; - memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1); - ret[sizeof(a->sockaddr.un.sun_path)] = 0; + if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1))) + return -ENOMEM; - } else { + ret[0] = '@'; + memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1); + ret[sizeof(a->sockaddr.un.sun_path)] = 0; - if (!(ret = strdup(a->sockaddr.un.sun_path))) - return -ENOMEM; - } + } else { - *p = ret; - return 0; + if (!(ret = strdup(a->sockaddr.un.sun_path))) + return -ENOMEM; } - default: - return -EINVAL; + *p = ret; + return 0; + } + + case AF_NETLINK: { + const char *sfamily; + + if ((sfamily = netlink_family_to_string(a->protocol))) + r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups); + else + r = asprintf(p, "%i %u", a->protocol, a->sockaddr.nl.nl_groups); + + if (r < 0) + return -ENOMEM; + + return 0; + } + + default: + return -EINVAL; } } @@ -341,7 +408,7 @@ int socket_address_listen( if (r < 0) return r; - fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); + fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, a->protocol); r = fd < 0 ? -errno : 0; label_socket_clear(); @@ -356,14 +423,16 @@ int socket_address_listen( goto fail; } - if (bind_to_device) - if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0) - goto fail; + 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) + goto fail; - if (free_bind) { - one = 1; - if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0) - log_warning("IP_FREEBIND failed: %m"); + if (free_bind) { + one = 1; + if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0) + log_warning("IP_FREEBIND failed: %m"); + } } one = 1; @@ -397,7 +466,7 @@ int socket_address_listen( if (r < 0) goto fail; - if (a->type == SOCK_STREAM) + if (socket_address_can_accept(a)) if (listen(fd, backlog) < 0) goto fail; @@ -471,6 +540,16 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) { 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; @@ -493,6 +572,18 @@ bool socket_address_is(const SocketAddress *a, const char *s, int 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); +} + bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) { assert(a); @@ -523,6 +614,28 @@ bool socket_ipv6_is_supported(void) { return enabled; } +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(netlink_family, int); + static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = { [SOCKET_ADDRESS_DEFAULT] = "default", [SOCKET_ADDRESS_BOTH] = "both", diff --git a/src/socket-util.h b/src/socket-util.h index 4743c37686..0e891ec2b2 100644 --- a/src/socket-util.h +++ b/src/socket-util.h @@ -26,6 +26,8 @@ #include <netinet/in.h> #include <sys/un.h> #include <net/if.h> +#include <asm/types.h> +#include <linux/netlink.h> #include "macro.h" #include "util.h" @@ -35,6 +37,7 @@ union sockaddr_union { struct sockaddr_in in4; struct sockaddr_in6 in6; struct sockaddr_un un; + struct sockaddr_nl nl; struct sockaddr_storage storage; }; @@ -47,6 +50,9 @@ typedef struct SocketAddress { /* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */ int type; + + /* Socket protocol, IPPROTO_xxx, usually 0, except for netlink */ + int protocol; } SocketAddress; typedef enum SocketAddressBindIPv6Only { @@ -60,6 +66,7 @@ typedef enum SocketAddressBindIPv6Only { #define socket_address_family(a) ((a)->sockaddr.sa.sa_family) int socket_address_parse(SocketAddress *a, const char *s); +int socket_address_parse_netlink(SocketAddress *a, const char *s); int socket_address_print(const SocketAddress *a, char **p); int socket_address_verify(const SocketAddress *a); @@ -77,6 +84,7 @@ int socket_address_listen( int *ret); bool socket_address_is(const SocketAddress *a, const char *s, int type); +bool socket_address_is_netlink(const SocketAddress *a, const char *s); bool socket_address_equal(const SocketAddress *a, const SocketAddress *b); @@ -85,6 +93,9 @@ bool socket_address_needs_mount(const SocketAddress *a, const char *prefix); const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b); SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s); +const char* netlink_family_to_string(int b); +int netlink_family_from_string(const char *s); + bool socket_ipv6_is_supported(void); #endif diff --git a/src/socket.c b/src/socket.c index beb328657f..ad67215c1f 100644 --- a/src/socket.c +++ b/src/socket.c @@ -249,7 +249,7 @@ static bool socket_needs_mount(Socket *s, const char *prefix) { if (socket_address_needs_mount(&p->address, prefix)) return true; } else { - assert(p->type == SOCKET_FIFO); + assert(p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL); if (path_startswith(p->path, prefix)) return true; } @@ -366,7 +366,10 @@ static int socket_load(Unit *u) { return socket_verify(s); } -static const char* listen_lookup(int type) { +static const char* listen_lookup(int family, int type) { + + if (family == AF_NETLINK) + return "ListenNetlink"; if (type == SOCK_STREAM) return "ListenStream"; @@ -477,9 +480,11 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { else t = k; - fprintf(f, "%s%s: %s\n", prefix, listen_lookup(p->address.type), t); + fprintf(f, "%s%s: %s\n", prefix, listen_lookup(socket_address_family(&p->address), p->address.type), t); free(k); - } else + } else if (p->type == SOCKET_SPECIAL) + fprintf(f, "%sListenSpecial: %s\n", prefix, p->path); + else fprintf(f, "%sListenFIFO: %s\n", prefix, p->path); } @@ -684,7 +689,6 @@ static void socket_apply_fifo_options(Socket *s, int fd) { log_warning("F_SETPIPE_SZ: %m"); } - static int fifo_address_create( const char *path, mode_t directory_mode, @@ -712,7 +716,7 @@ static int fifo_address_create( r = mkfifo(path, socket_mode); umask(old_mask); - if (r < 0) { + if (r < 0 && errno != EEXIST) { r = -errno; goto fail; } @@ -750,6 +754,42 @@ fail: return r; } +static int special_address_create( + const char *path, + int *_fd) { + + int fd = -1, r = 0; + struct stat st; + + assert(path); + assert(_fd); + + if ((fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) { + r = -errno; + goto fail; + } + + if (fstat(fd, &st) < 0) { + r = -errno; + goto fail; + } + + /* Check whether this is a /proc, /sys or /dev file or char device */ + if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) { + r = -EEXIST; + goto fail; + } + + *_fd = fd; + return 0; + +fail: + if (fd >= 0) + close_nointr_nofail(fd); + + return r; +} + static int socket_open_fds(Socket *s) { SocketPort *p; int r; @@ -771,8 +811,10 @@ static int socket_open_fds(Socket *s) { return r; if (s->service && s->service->exec_command[SERVICE_EXEC_START]) - if ((r = label_get_socket_label_from_exe(s->service->exec_command[SERVICE_EXEC_START]->path, &label)) < 0) - return r; + if ((r = label_get_socket_label_from_exe(s->service->exec_command[SERVICE_EXEC_START]->path, &label)) < 0) { + if (r != -EPERM) + return r; + } know_label = true; } @@ -791,6 +833,13 @@ static int socket_open_fds(Socket *s) { socket_apply_socket_options(s, p->fd); + } else if (p->type == SOCKET_SPECIAL) { + + if ((r = special_address_create( + p->path, + &p->fd)) < 0) + goto rollback; + } else if (p->type == SOCKET_FIFO) { if ((r = fifo_address_create( @@ -1360,15 +1409,19 @@ static int socket_start(Unit *u) { /* Cannot run this without the service being around */ if (s->service) { - if (s->service->meta.load_state != UNIT_LOADED) + if (s->service->meta.load_state != UNIT_LOADED) { + log_error("Socket service %s not loaded, refusing.", s->service->meta.id); return -ENOENT; + } /* If the service is already active we cannot start the * socket */ if (s->service->state != SERVICE_DEAD && s->service->state != SERVICE_FAILED && - s->service->state != SERVICE_AUTO_RESTART) + s->service->state != SERVICE_AUTO_RESTART) { + log_error("Socket service %s already active, refusing.", s->service->meta.id); return -EBUSY; + } #ifdef HAVE_SYSV_COMPAT if (s->service->sysv_path) { @@ -1447,9 +1500,14 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) { if ((r = socket_address_print(&p->address, &t)) < 0) return r; - unit_serialize_item_format(u, f, "socket", "%i %i %s", copy, p->address.type, t); + if (socket_address_family(&p->address) == AF_NETLINK) + unit_serialize_item_format(u, f, "netlink", "%i %s", copy, t); + else + unit_serialize_item_format(u, f, "socket", "%i %i %s", copy, p->address.type, t); free(t); - } else { + } else if (p->type == SOCKET_SPECIAL) + unit_serialize_item_format(u, f, "special", "%i %s", copy, p->path); + else { assert(p->type == SOCKET_FIFO); unit_serialize_item_format(u, f, "fifo", "%i %s", copy, p->path); } @@ -1513,7 +1571,28 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value, else { LIST_FOREACH(port, p, s->ports) - if (streq(p->path, value+skip)) + if (p->type == SOCKET_FIFO && + streq_ptr(p->path, value+skip)) + break; + + if (p) { + if (p->fd >= 0) + close_nointr_nofail(p->fd); + p->fd = fdset_remove(fds, fd); + } + } + + } else if (streq(key, "special")) { + int fd, skip = 0; + SocketPort *p; + + if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd)) + log_debug("Failed to parse special value %s", value); + else { + + LIST_FOREACH(port, p, s->ports) + if (p->type == SOCKET_SPECIAL && + streq_ptr(p->path, value+skip)) break; if (p) { @@ -1542,6 +1621,25 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value, } } + } else if (streq(key, "netlink")) { + int fd, skip = 0; + SocketPort *p; + + if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd)) + log_debug("Failed to parse socket value %s", value); + else { + + LIST_FOREACH(port, p, s->ports) + if (socket_address_is_netlink(&p->address, value+skip)) + break; + + if (p) { + if (p->fd >= 0) + close_nointr_nofail(p->fd); + p->fd = fdset_remove(fds, fd); + } + } + } else log_debug("Unknown serialization key '%s'", key); @@ -1581,7 +1679,7 @@ static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { log_debug("Incoming traffic on %s", u->meta.id); if (events != EPOLLIN) { - log_error("Got invalid poll event on socket."); + log_error("%s: Got invalid poll event (0x%x) on socket.", u->meta.id, events); goto fail; } diff --git a/src/socket.h b/src/socket.h index 9dd9f55fde..b83c34cf61 100644 --- a/src/socket.h +++ b/src/socket.h @@ -58,6 +58,7 @@ typedef enum SocketExecCommand { typedef enum SocketType { SOCKET_SOCKET, SOCKET_FIFO, + SOCKET_SPECIAL, _SOCKET_FIFO_MAX, _SOCKET_FIFO_INVALID = -1 } SocketType; diff --git a/src/strv.c b/src/strv.c index c5f8df06da..71b77c9bbf 100644 --- a/src/strv.c +++ b/src/strv.c @@ -70,9 +70,10 @@ char **strv_copy(char **l) { if (!(r = new(char*, strv_length(l)+1))) return NULL; - for (k = r; *l; k++, l++) - if (!(*k = strdup(*l))) - goto fail; + if (l) + for (k = r; *l; k++, l++) + if (!(*k = strdup(*l))) + goto fail; *k = NULL; return r; @@ -357,7 +358,10 @@ char **strv_remove(char **l, const char *s) { if (!l) return NULL; - /* Drops every occurrence of s in the string list */ + assert(s); + + /* Drops every occurrence of s in the string list, edits + * in-place. */ for (f = t = l; *f; f++) { @@ -386,7 +390,12 @@ static int env_append(char **r, char ***k, char **a) { for (; *a; a++) { char **j; - size_t n = strcspn(*a, "=") + 1; + size_t n; + + n = strcspn(*a, "="); + + if ((*a)[n] == '=') + n++; for (j = r; j < *k; j++) if (strncmp(*j, *a, n) == 0) @@ -516,9 +525,38 @@ char **strv_env_delete(char **x, unsigned n_lists, ...) { return r; } +char **strv_env_unset(char **l, const char *p) { + + char **f, **t; + + if (!l) + return NULL; + + assert(p); + + /* Drops every occurrence of the env var setting p in the + * string list. edits in-place. */ + + for (f = t = l; *f; f++) { + + if (env_match(*f, p)) { + free(*f); + continue; + } + + *(t++) = *f; + } + + *t = NULL; + return l; +} + char **strv_env_set(char **x, const char *p) { char **k, **r; + char* m[2] = { (char*) p, NULL }; + + /* Overrides the env var setting of p, returns a new copy */ if (!(r = new(char*, strv_length(x)+2))) return NULL; @@ -527,7 +565,7 @@ char **strv_env_set(char **x, const char *p) { if (env_append(r, &k, x) < 0) goto fail; - if (!(*(k++) = strdup(p))) + if (env_append(r, &k, m) < 0) goto fail; *k = NULL; diff --git a/src/strv.h b/src/strv.h index 064576ce1e..46436a52d9 100644 --- a/src/strv.h +++ b/src/strv.h @@ -59,6 +59,7 @@ char **strv_env_merge(unsigned n_lists, ...); char **strv_env_delete(char **x, unsigned n_lists, ...); char **strv_env_set(char **x, const char *p); +char **strv_env_unset(char **l, const char *p); char *strv_env_get_with_length(char **l, const char *name, size_t k); char *strv_env_get(char **x, const char *n); diff --git a/src/swap.c b/src/swap.c index c32f60810c..ef001a98bf 100644 --- a/src/swap.c +++ b/src/swap.c @@ -90,6 +90,8 @@ static void swap_unset_proc_swaps(Swap *s) { s->timer_watch.type = WATCH_INVALID; s->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; + + s->meta.ignore_on_isolate = true; } static void swap_unwatch_control_pid(Swap *s) { @@ -1339,7 +1341,6 @@ const UnitVTable swap_vtable = { .no_alias = true, .no_instances = true, - .no_isolate = true, .show_status = true, .init = swap_init, diff --git a/src/systemctl-bash-completion.sh b/src/systemctl-bash-completion.sh index ae0ecb7b70..dc18ab6cce 100644 --- a/src/systemctl-bash-completion.sh +++ b/src/systemctl-bash-completion.sh @@ -81,7 +81,7 @@ _systemctl () { [FAILED_UNITS]='reset-failed' [STARTABLE_UNITS]='start restart reload-or-restart' [STOPPABLE_UNITS]='stop kill try-restart condrestart' - [ISOLATEBLE_UNITS]='isolate' + [ISOLATABLE_UNITS]='isolate' [RELOADABLE_UNITS]='reload reload-or-try-restart force-reload' [JOBS]='cancel' [SNAPSHOTS]='delete' diff --git a/src/systemctl.c b/src/systemctl.c index 00db47f125..d1d73bfa01 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -1735,7 +1735,7 @@ static void exec_status_info_free(ExecStatusInfo *i) { } static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) { - uint64_t start_timestamp, exit_timestamp; + uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic; DBusMessageIter sub2, sub3; const char*path; unsigned n; @@ -1789,7 +1789,9 @@ static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) if (!dbus_message_iter_next(&sub2) || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 || bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0) @@ -2278,7 +2280,7 @@ static int print_property(const char *name, DBusMessageIter *iter) { /* Yes, heuristics! But we can change this check * should it turn out to not be sufficient */ - if (strstr(name, "Timestamp")) { + if (endswith(name, "Timestamp")) { char timestamp[FORMAT_TIMESTAMP_MAX], *t; if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all) @@ -4079,7 +4081,7 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo } if (!f) { -#if (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA)) && defined (HAVE_SYSV_COMPAT) +#if (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA)) || defined(TARGET_MEEGO) && defined (HAVE_SYSV_COMPAT) if (endswith(i->name, ".service")) { char *sysv; @@ -4150,6 +4152,15 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo return -ENOENT; } + /* Consider unit files stored in /lib and /usr always enabled + * if they have no [Install] data. */ + if (streq(verb, "is-enabled") && + strv_isempty(i->aliases) && + strv_isempty(i->wanted_by) && + (path_startswith(filename, "/lib") || + path_startswith(filename, "/usr"))) + return 1; + i->path = filename; if ((r = config_parse(filename, f, NULL, items, true, i)) < 0) { diff --git a/src/systemd-analyze b/src/systemd-analyze index 5e3a087e9d..4f3e478e99 100755 --- a/src/systemd-analyze +++ b/src/systemd-analyze @@ -15,10 +15,10 @@ def acquire_time_data(): properties = dbus.Interface(bus.get_object('org.freedesktop.systemd1', i[6]), 'org.freedesktop.DBus.Properties') - ixt = int(properties.Get('org.freedesktop.systemd1.Unit', 'InactiveExitTimestamp')) - aet = int(properties.Get('org.freedesktop.systemd1.Unit', 'ActiveEnterTimestamp')) - axt = int(properties.Get('org.freedesktop.systemd1.Unit', 'ActiveExitTimestamp')) - iet = int(properties.Get('org.freedesktop.systemd1.Unit', 'InactiveEnterTimestamp')) + ixt = int(properties.Get('org.freedesktop.systemd1.Unit', 'InactiveExitTimestampMonotonic')) + aet = int(properties.Get('org.freedesktop.systemd1.Unit', 'ActiveEnterTimestampMonotonic')) + axt = int(properties.Get('org.freedesktop.systemd1.Unit', 'ActiveExitTimestampMonotonic')) + iet = int(properties.Get('org.freedesktop.systemd1.Unit', 'InactiveEnterTimestampMonotonic')) l.append((str(i[0]), ixt, aet, axt, iet)) @@ -27,12 +27,14 @@ def acquire_time_data(): def acquire_start_time(): properties = dbus.Interface(bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1'), 'org.freedesktop.DBus.Properties') - startup_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'StartupTimestamp')) - finish_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'FinishTimestamp')) + initrd_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'InitRDTimestampMonotonic')) + startup_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'StartupTimestampMonotonic')) + finish_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'FinishTimestampMonotonic')) + assert initrd_time <= startup_time assert startup_time <= finish_time - return startup_time, finish_time + return initrd_time, startup_time, finish_time def draw_box(context, j, k, l, m, r = 0, g = 0, b = 0): context.save() @@ -63,7 +65,8 @@ def draw_text(context, x, y, text, size = 12, r = 0, g = 0, b = 0, vcenter = 0.5 context.restore() def help(): - sys.stdout.write("""systemd-analyze blame + sys.stdout.write("""systemd-analyze time +systemd-analyze blame systemd-analyze plot Process systemd profiling information @@ -74,7 +77,24 @@ Process systemd profiling information bus = dbus.SystemBus() -if len(sys.argv) <= 1 or sys.argv[1] == 'blame': +if len(sys.argv) <= 1 or sys.argv[1] == 'time': + + initrd_time, start_time, finish_time = acquire_start_time() + + if initrd_time > 0: + print "Startup finished in %lums (kernel) + %lums (initrd) + %lums (userspace) = %lums" % ( \ + initrd_time/1000, \ + (start_time - initrd_time)/1000, \ + (finish_time - start_time)/1000, \ + finish_time/1000) + else: + print "Startup finished in %lums (kernel) + %lums (userspace) = %lums" % ( \ + start_time/1000, \ + (finish_time - start_time)/1000, \ + finish_time/1000) + + +elif sys.argv[1] == 'blame': data = acquire_time_data() s = sorted(data, key = lambda i: i[2] - i[1], reverse = True) @@ -92,7 +112,7 @@ if len(sys.argv) <= 1 or sys.argv[1] == 'blame': elif sys.argv[1] == 'plot': import cairo - start_time, finish_time = acquire_start_time() + initrd_time, start_time, finish_time = acquire_start_time() data = acquire_time_data() s = sorted(data, key = lambda i: i[1]) diff --git a/src/tmpfiles.c b/src/tmpfiles.c index b21df95a73..2526d1e915 100644 --- a/src/tmpfiles.c +++ b/src/tmpfiles.c @@ -623,9 +623,39 @@ static void item_free(Item *i) { free(i); } +static bool item_equal(Item *a, Item *b) { + assert(a); + assert(b); + + if (!streq_ptr(a->path, b->path)) + return false; + + if (a->type != b->type) + return false; + + if (a->uid_set != b->uid_set || + (a->uid_set && a->uid != b->uid)) + return false; + + if (a->gid_set != b->gid_set || + (a->gid_set && a->gid != b->gid)) + return false; + + if (a->mode_set != b->mode_set || + (a->mode_set && a->mode != b->mode)) + return false; + + if (a->age_set != b->age_set || + (a->age_set && a->age != b->age)) + return false; + + return true; +} + static int parse_line(const char *fname, unsigned line, const char *buffer) { - Item *i; + Item *i, *existing; char *mode = NULL, *user = NULL, *group = NULL, *age = NULL; + Hashmap *h; int r; assert(fname); @@ -742,13 +772,19 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { i->age_set = true; } - if ((r = hashmap_put(needs_glob(i->type) ? globs : items, i->path, i)) < 0) { - if (r == -EEXIST) { + h = needs_glob(i->type) ? globs : items; + + if ((existing = hashmap_get(h, i->path))) { + + /* Two identical items are fine */ + if (!item_equal(existing, i)) log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path); - r = 0; - goto finish; - } + r = 0; + goto finish; + } + + if ((r = hashmap_put(h, i->path, i)) < 0) { log_error("Failed to insert item %s: %s", i->path, strerror(-r)); goto finish; } diff --git a/src/tty-ask-password-agent.c b/src/tty-ask-password-agent.c index dcf4b332b3..d7e1ebaef6 100644 --- a/src/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent.c @@ -261,7 +261,6 @@ static int parse_password(const char *filename, char **wall) { FILE *f; int r; - usec_t n; assert(filename); @@ -279,14 +278,22 @@ static int parse_password(const char *filename, char **wall) { goto finish; } - if (!socket_name || not_after <= 0) { + if (!socket_name) { log_error("Invalid password file %s", filename); r = -EBADMSG; goto finish; } - n = now(CLOCK_MONOTONIC); - if (n > not_after) { + if (not_after > 0) { + if (now(CLOCK_MONOTONIC) > not_after) { + r = 0; + goto finish; + } + } + + if (pid > 0 && + kill(pid, 0) < 0 && + errno == ESRCH) { r = 0; goto finish; } @@ -369,10 +376,15 @@ static int parse_password(const char *filename, char **wall) { release_terminal(); } - asprintf(&packet, "+%s", password); - free(password); + packet_length = 1+strlen(password)+1; + if (!(packet = new(char, packet_length))) + r = -ENOMEM; + else { + packet[0] = '+'; + strcpy(packet+1, password); + } - packet_length = strlen(packet); + free(password); } if (r == -ETIME || r == -ENOENT) { @@ -382,17 +394,10 @@ static int parse_password(const char *filename, char **wall) { } if (r < 0) { - log_error("Failed to query password: %s", strerror(-r)); goto finish; } - if (!packet) { - log_error("Out of memory"); - r = -ENOMEM; - goto finish; - } - if ((socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { log_error("socket(): %m"); r = -errno; diff --git a/src/unit.c b/src/unit.c index e4345aeffe..aed25e4f21 100644 --- a/src/unit.c +++ b/src/unit.c @@ -368,7 +368,7 @@ void unit_free(Unit *u) { u->meta.manager->n_in_gc_queue--; } - cgroup_bonding_free_list(u->meta.cgroup_bondings); + cgroup_bonding_free_list(u->meta.cgroup_bondings, u->meta.manager->n_serializing <= 0); free(u->meta.description); free(u->meta.fragment_path); @@ -567,11 +567,8 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { /* If syslog or kernel logging is requested, make sure our own * logging daemon is run first. */ - if ((r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0) - return r; - if (u->meta.manager->running_as == MANAGER_SYSTEM) - if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0) + if ((r = unit_add_two_dependencies_by_name(u, UNIT_REQUIRES, UNIT_AFTER, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0) return r; return 0; @@ -666,11 +663,15 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { "%s\tStopWhenUnneeded: %s\n" "%s\tRefuseManualStart: %s\n" "%s\tRefuseManualStop: %s\n" - "%s\tDefaultDependencies: %s\n", + "%s\tDefaultDependencies: %s\n" + "%s\tOnFailureIsolate: %s\n" + "%s\tIgnoreOnIsolate: %s\n", prefix, yes_no(u->meta.stop_when_unneeded), prefix, yes_no(u->meta.refuse_manual_start), prefix, yes_no(u->meta.refuse_manual_stop), - prefix, yes_no(u->meta.default_dependencies)); + prefix, yes_no(u->meta.default_dependencies), + prefix, yes_no(u->meta.on_failure_isolate), + prefix, yes_no(u->meta.ignore_on_isolate)); LIST_FOREACH(by_unit, b, u->meta.cgroup_bondings) fprintf(f, "%s\tControlGroup: %s:%s\n", @@ -815,6 +816,16 @@ int unit_load(Unit *u) { if ((r = unit_add_default_dependencies(u)) < 0) goto fail; + if (u->meta.on_failure_isolate && + set_size(u->meta.dependencies[UNIT_ON_FAILURE]) > 1) { + + log_error("More than one OnFailure= dependencies specified for %s but OnFailureIsolate= enabled. Refusing.", + u->meta.id); + + r = -EINVAL; + goto fail; + } + assert((u->meta.load_state != UNIT_MERGED) == !u->meta.merged_into); unit_add_to_dbus_queue(unit_follow_merge(u)); @@ -1096,8 +1107,17 @@ void unit_trigger_on_failure(Unit *u) { assert(u); - SET_FOREACH(other, u->meta.dependencies[UNIT_ON_FAILURE], i) - manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); + if (set_size(u->meta.dependencies[UNIT_ON_FAILURE]) <= 0) + return; + + log_info("Triggering OnFailure= dependencies of %s.", u->meta.id); + + SET_FOREACH(other, u->meta.dependencies[UNIT_ON_FAILURE], i) { + int r; + + if ((r = manager_add_job(u->meta.manager, JOB_START, other, u->meta.on_failure_isolate ? JOB_ISOLATE : JOB_REPLACE, true, NULL, NULL)) < 0) + log_error("Failed to enqueue OnFailure= job: %s", strerror(-r)); + } } void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) { @@ -1858,6 +1878,9 @@ int unit_add_default_cgroups(Unit *u) { /* Adds in the default cgroups, if they weren't specified * otherwise. */ + if (!u->meta.manager->cgroup_hierarchy) + return 0; + if ((r = unit_add_one_default_cgroup(u, NULL)) < 0) return r; @@ -2134,7 +2157,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { return 0; for (;;) { - char line[1024], *l, *v; + char line[LINE_MAX], *l, *v; size_t k; if (!fgets(line, sizeof(line), f)) { diff --git a/src/unit.h b/src/unit.h index 4245f3cf1c..43bbe67573 100644 --- a/src/unit.h +++ b/src/unit.h @@ -207,6 +207,12 @@ struct Meta { /* Allow isolation requests */ bool allow_isolate; + /* Isolate OnFailure unit */ + bool on_failure_isolate; + + /* Ignore this unit when isolating */ + bool ignore_on_isolate; + /* Did the last condition check suceed? */ bool condition_result; @@ -364,9 +370,6 @@ struct UnitVTable { /* Exclude from automatic gc */ bool no_gc:1; - /* Exclude from stopping on isolation requests */ - bool no_isolate:1; - /* Show status updates on the console */ bool show_status:1; }; diff --git a/src/util.c b/src/util.c index 5daafdf7c2..5a076e6e34 100644 --- a/src/util.c +++ b/src/util.c @@ -50,6 +50,7 @@ #include <linux/kd.h> #include <dlfcn.h> #include <sys/wait.h> +#include <sys/capability.h> #include "macro.h" #include "util.h" @@ -452,14 +453,14 @@ char **split_path_and_make_absolute(const char *p) { int get_parent_of_pid(pid_t pid, pid_t *_ppid) { int r; FILE *f; - char fn[132], line[256], *p; + char fn[PATH_MAX], line[LINE_MAX], *p; long unsigned ppid; - assert(pid >= 0); + assert(pid > 0); assert(_ppid); assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1)); - fn[sizeof(fn)-1] = 0; + char_array_0(fn); if (!(f = fopen(fn, "r"))) return -errno; @@ -495,6 +496,64 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) { return 0; } +int get_starttime_of_pid(pid_t pid, unsigned long long *st) { + int r; + FILE *f; + char fn[PATH_MAX], line[LINE_MAX], *p; + + assert(pid > 0); + assert(st); + + assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1)); + char_array_0(fn); + + if (!(f = fopen(fn, "r"))) + return -errno; + + if (!(fgets(line, sizeof(line), f))) { + r = -errno; + fclose(f); + return r; + } + + fclose(f); + + /* Let's skip the pid and comm fields. The latter is enclosed + * in () but does not escape any () in its value, so let's + * skip over it manually */ + + if (!(p = strrchr(line, ')'))) + return -EIO; + + p++; + + if (sscanf(p, " " + "%*c " /* state */ + "%*d " /* ppid */ + "%*d " /* pgrp */ + "%*d " /* session */ + "%*d " /* tty_nr */ + "%*d " /* tpgid */ + "%*u " /* flags */ + "%*u " /* minflt */ + "%*u " /* cminflt */ + "%*u " /* majflt */ + "%*u " /* cmajflt */ + "%*u " /* utime */ + "%*u " /* stime */ + "%*d " /* cutime */ + "%*d " /* cstime */ + "%*d " /* priority */ + "%*d " /* nice */ + "%*d " /* num_threads */ + "%*d " /* itrealvalue */ + "%llu " /* starttime */, + st) != 1) + return -EIO; + + return 0; +} + int write_one_line_file(const char *fn, const char *line) { FILE *f; int r; @@ -549,6 +608,8 @@ int read_one_line_file(const char *fn, char **line) { goto finish; } + truncate_nl(c); + *line = c; r = 0; @@ -773,6 +834,29 @@ finish: return r; } +int write_env_file(const char *fname, char **l) { + + char **i; + FILE *f; + int r; + + f = fopen(fname, "we"); + if (!f) + return -errno; + + STRV_FOREACH(i, l) { + fputs(*i, f); + fputc('\n', f); + } + + fflush(f); + + r = ferror(f) ? -errno : 0; + fclose(f); + + return r; +} + char *truncate_nl(char *s) { assert(s); @@ -796,7 +880,6 @@ int get_process_name(pid_t pid, char **name) { if (r < 0) return r; - truncate_nl(*name); return 0; } @@ -2063,7 +2146,7 @@ int chvt(int vt) { int read_one_char(FILE *f, char *ret, bool *need_nl) { struct termios old_termios, new_termios; char c; - char line[1024]; + char line[LINE_MAX]; assert(f); assert(ret); @@ -2271,7 +2354,7 @@ int flush_fd(int fd) { pollfd.events = POLLIN; for (;;) { - char buf[1024]; + char buf[LINE_MAX]; ssize_t l; int r; @@ -2897,7 +2980,7 @@ int getttyname_harder(int fd, char **r) { int get_ctty_devnr(dev_t *d) { int k; - char line[256], *p; + char line[LINE_MAX], *p; unsigned long ttynr; FILE *f; @@ -2932,7 +3015,7 @@ int get_ctty_devnr(dev_t *d) { int get_ctty(char **r, dev_t *_devnr) { int k; - char fn[128], *s, *b, *p; + char fn[PATH_MAX], *s, *b, *p; dev_t devnr; assert(r); @@ -3198,8 +3281,7 @@ void status_welcome(void) { if (r != -ENOENT) log_warning("Failed to read /etc/system-release: %s", strerror(-r)); - } else - truncate_nl(pretty_name); + } } if (!ansi_color && pretty_name) { @@ -3220,8 +3302,7 @@ void status_welcome(void) { if (r != -ENOENT) log_warning("Failed to read /etc/SuSE-release: %s", strerror(-r)); - } else - truncate_nl(pretty_name); + } } if (!ansi_color) @@ -3234,8 +3315,7 @@ void status_welcome(void) { if (r != -ENOENT) log_warning("Failed to read /etc/gentoo-release: %s", strerror(-r)); - } else - truncate_nl(pretty_name); + } } if (!ansi_color) @@ -3248,8 +3328,7 @@ void status_welcome(void) { if (r != -ENOENT) log_warning("Failed to read /etc/altlinux-release: %s", strerror(-r)); - } else - truncate_nl(pretty_name); + } } if (!ansi_color) @@ -3266,7 +3345,6 @@ void status_welcome(void) { if (r != -ENOENT) log_warning("Failed to read /etc/debian_version: %s", strerror(-r)); } else { - truncate_nl(version); pretty_name = strappend("Debian ", version); free(version); @@ -3316,7 +3394,18 @@ void status_welcome(void) { free(s); } } +#elif defined(TARGET_MEEGO) + if (!pretty_name) { + if ((r = read_one_line_file("/etc/meego-release", &pretty_name)) < 0) { + + if (r != -ENOENT) + log_warning("Failed to read /etc/meego-release: %s", strerror(-r)); + } + } + + if (!ansi_color) + const_color = "1;35"; /* Bright Magenta for MeeGo */ #endif if (!pretty_name && !const_pretty) @@ -3825,8 +3914,6 @@ const char *default_term_for_tty(const char *tty) { * TERM */ if (streq(tty, "console")) if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) { - truncate_nl(active); - /* If multiple log outputs are configured the * last one is what /dev/console points to */ if ((tty = strrchr(active, ' '))) @@ -4236,6 +4323,76 @@ void parse_syslog_priority(char **p, int *priority) { *p += k; } +int have_effective_cap(int value) { + cap_t cap; + cap_flag_value_t fv; + int r; + + if (!(cap = cap_get_proc())) + return -errno; + + if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0) + r = -errno; + else + r = fv == CAP_SET; + + cap_free(cap); + return r; +} + +char* strshorten(char *s, size_t l) { + assert(s); + + if (l < strlen(s)) + s[l] = 0; + + return s; +} + +static bool hostname_valid_char(char c) { + return + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '-' || + c == '_' || + c == '.'; +} + +bool hostname_is_valid(const char *s) { + const char *p; + + if (isempty(s)) + return false; + + for (p = s; *p; p++) + if (!hostname_valid_char(*p)) + return false; + + if (p-s > HOST_NAME_MAX) + return false; + + return true; +} + +char* hostname_cleanup(char *s) { + char *p, *d; + + for (p = s, d = s; *p; p++) + if ((*p >= 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z') || + (*p >= '0' && *p <= '9') || + *p == '-' || + *p == '_' || + *p == '.') + *(d++) = *p; + + *d = 0; + + strshorten(s, HOST_NAME_MAX); + return s; +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/util.h b/src/util.h index ff38b35804..fcaeac4ab9 100644 --- a/src/util.h +++ b/src/util.h @@ -117,6 +117,10 @@ static inline bool is_path_absolute(const char *p) { return *p == '/'; } +static inline bool isempty(const char *p) { + return !p || !p[0]; +} + bool endswith(const char *s, const char *postfix); bool startswith(const char *s, const char *prefix); bool startswith_no_case(const char *s, const char *prefix); @@ -192,6 +196,7 @@ char *split_quoted(const char *c, size_t *l, char **state); char **split_path_and_make_absolute(const char *p); pid_t get_parent_of_pid(pid_t pid, pid_t *ppid); +int get_starttime_of_pid(pid_t pid, unsigned long long *st); int write_one_line_file(const char *fn, const char *line); int read_one_line_file(const char *fn, char **line); @@ -199,6 +204,7 @@ int read_full_file(const char *fn, char **contents); int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; int load_env_file(const char *fname, char ***l); +int write_env_file(const char *fname, char **l); char *strappend(const char *s, const char *suffix); char *strnappend(const char *s, const char *suffix, size_t length); @@ -396,6 +402,13 @@ bool plymouth_running(void); void parse_syslog_priority(char **p, int *priority); +int have_effective_cap(int value); + +bool hostname_is_valid(const char *s); +char* hostname_cleanup(char *s); + +char* strshorten(char *s, size_t l); + #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) diff --git a/src/vconsole-setup.c b/src/vconsole-setup.c index 67fb7b6100..1be260bc2f 100644 --- a/src/vconsole-setup.c +++ b/src/vconsole-setup.c @@ -83,6 +83,12 @@ static int load_keymap(const char *vc, const char *map, const char *map_toggle, int i = 0; pid_t pid; + if (isempty(map)) { + /* An empty map means kernel map */ + *_pid = 0; + return 0; + } + args[i++] = KBD_LOADKEYS; args[i++] = "-q"; args[i++] = "-C"; @@ -111,6 +117,12 @@ static int load_font(const char *vc, const char *font, const char *map, const ch int i = 0; pid_t pid; + if (isempty(font)) { + /* An empty font means kernel font */ + *_pid = 0; + return 0; + } + args[i++] = KBD_SETFONT; args[i++] = "-C"; args[i++] = vc; @@ -155,7 +167,7 @@ int main(int argc, char **argv) { int r = EXIT_FAILURE; pid_t font_pid = 0, keymap_pid = 0; - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); + log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); @@ -176,9 +188,19 @@ int main(int argc, char **argv) { utf8 = is_locale_utf8(); + vc_keymap = strdup("us"); + vc_font = strdup(DEFAULT_FONT); + + if (!vc_keymap || !vc_font) { + log_error("Failed to allocate strings."); + goto finish; + } + + r = 0; + if (detect_container(NULL) <= 0) if ((r = parse_env_file("/proc/cmdline", WHITESPACE, -#ifdef TARGET_FEDORA +#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO) "SYSFONT", &vc_font, "KEYTABLE", &vc_keymap, #endif @@ -209,7 +231,7 @@ int main(int argc, char **argv) { } if (r <= 0) { -#ifdef TARGET_FEDORA +#if defined(TARGET_FEDORA) || defined(TARGET_MEEGO) if ((r = parse_env_file("/etc/sysconfig/i18n", NEWLINE, "SYSFONT", &vc_font, "SYSFONTACM", &vc_font_map, @@ -410,15 +432,7 @@ int main(int argc, char **argv) { #endif } - if (!vc_keymap) - vc_keymap = strdup("us"); - if (!vc_font) - vc_font = strdup(DEFAULT_FONT); - - if (!vc_keymap || !vc_font) { - log_error("Failed to allocate strings."); - goto finish; - } + r = EXIT_FAILURE; if (!utf8) disable_utf8(fd); diff --git a/tmpfiles.d/systemd.conf b/tmpfiles.d/systemd.conf index 2ab8e2bba5..5e8ed99916 100644 --- a/tmpfiles.d/systemd.conf +++ b/tmpfiles.d/systemd.conf @@ -21,3 +21,5 @@ d /var/cache/man - - - 30d r /forcefsck r /forcequotacheck r /fastboot + +d /run/systemd/ask-password 0755 root root - diff --git a/units/.gitignore b/units/.gitignore index cbf9f255f0..fe23b12266 100644 --- a/units/.gitignore +++ b/units/.gitignore @@ -1,3 +1,4 @@ +systemd-hostnamed.service console-shell.service systemd-sysctl.service systemd-ask-password-console.service diff --git a/units/emergency.service b/units/emergency.service index a97ec5e389..eff5261868 100644 --- a/units/emergency.service +++ b/units/emergency.service @@ -19,7 +19,7 @@ WorkingDirectory=/root ExecStartPre=-/bin/plymouth quit ExecStartPre=-/bin/echo 'Welcome to emergency mode. Use "systemctl default" or ^D to activate default mode.' ExecStart=-/sbin/sulogin -ExecStopPost=/bin/systemctl --fail default +ExecStopPost=/bin/systemctl --fail --no-block default StandardInput=tty-force KillMode=process diff --git a/units/fsck-root.service.in b/units/fsck-root.service.in index 8f4adc48e0..7b3529db07 100644 --- a/units/fsck-root.service.in +++ b/units/fsck-root.service.in @@ -9,7 +9,7 @@ Description=File System Check on Root Device DefaultDependencies=no After=systemd-readahead-collect.service systemd-readahead-replay.service -Before=local-fs.target shutdown.target remount-rootfs.service quotacheck.service +Before=local-fs.target shutdown.target # Dracut informs us with this flag file if the root fsck was already run ConditionPathExists=!/run/initramfs/root-fsck diff --git a/units/fsck@.service.in b/units/fsck@.service.in index ad9ec3bcc9..e1f773639b 100644 --- a/units/fsck@.service.in +++ b/units/fsck@.service.in @@ -10,7 +10,7 @@ Description=File System Check on %f DefaultDependencies=no BindTo=%i.device After=systemd-readahead-collect.service systemd-readahead-replay.service %i.device -Before=basic.target shutdown.target +Before=shutdown.target [Service] Type=oneshot diff --git a/units/local-fs.target b/units/local-fs.target index 52d0e68101..1886f7499d 100644 --- a/units/local-fs.target +++ b/units/local-fs.target @@ -9,3 +9,5 @@ [Unit] Description=Local File Systems +OnFailure=emergency.target +OnFailureIsolate=yes diff --git a/units/quotacheck.service.in b/units/quotacheck.service.in index ed1ddc5589..27dcb1e4c6 100644 --- a/units/quotacheck.service.in +++ b/units/quotacheck.service.in @@ -8,7 +8,7 @@ [Unit] Description=File System Quota Check DefaultDependencies=no -After=systemd-readahead-collect.service systemd-readahead-replay.service +After=systemd-readahead-collect.service systemd-readahead-replay.service remount-rootfs.service Before=local-fs.target shutdown.target ConditionPathExists=/sbin/quotacheck diff --git a/units/remount-rootfs.service b/units/remount-rootfs.service index 31309015ca..e95023f03d 100644 --- a/units/remount-rootfs.service +++ b/units/remount-rootfs.service @@ -9,7 +9,7 @@ Description=Remount Root FS DefaultDependencies=no Conflicts=shutdown.target -After=systemd-readahead-collect.service systemd-readahead-replay.service +After=systemd-readahead-collect.service systemd-readahead-replay.service fsck-root.service Before=local-fs.target shutdown.target [Service] diff --git a/units/rescue.service.m4 b/units/rescue.service.m4 index 241c75071f..d2fd582e86 100644 --- a/units/rescue.service.m4 +++ b/units/rescue.service.m4 @@ -25,8 +25,11 @@ ExecStart=-/bin/bash -c "exec ${SINGLE}"', m4_ifdef(`TARGET_MANDRIVA', `EnvironmentFile=/etc/sysconfig/init ExecStart=-/bin/bash -c "exec ${SINGLE}"', -`ExecStart=-/sbin/sulogin')) -ExecStopPost=-/bin/systemctl --fail default +`ExecStart=-/sbin/sulogin' +m4_ifdef(`TARGET_MEEGO', +`EnvironmentFile=/etc/sysconfig/init +ExecStart=-/bin/bash -c "exec ${SINGLE}"',))) +ExecStopPost=-/bin/systemctl --fail --no-block default StandardInput=tty-force KillMode=process diff --git a/units/syslog.target b/units/syslog.target index 8b1626ed55..825b26e7bf 100644 --- a/units/syslog.target +++ b/units/syslog.target @@ -12,3 +12,8 @@ [Unit] Description=Syslog + +# Avoid that we conflict with shutdown.target, so that we can stay +# until the very end and do not cancel shutdown.target if we should +# hapen to be activated very late. +DefaultDependencies=no diff --git a/units/systemd-ask-password-console.path b/units/systemd-ask-password-console.path index 4005a27734..b5acf943b4 100644 --- a/units/systemd-ask-password-console.path +++ b/units/systemd-ask-password-console.path @@ -13,3 +13,4 @@ Before=basic.target shutdown.target [Path] DirectoryNotEmpty=/run/systemd/ask-password +MakeDirectory=yes diff --git a/units/systemd-ask-password-plymouth.path b/units/systemd-ask-password-plymouth.path index a2aec44122..6a96520921 100644 --- a/units/systemd-ask-password-plymouth.path +++ b/units/systemd-ask-password-plymouth.path @@ -13,3 +13,4 @@ Before=basic.target shutdown.target [Path] DirectoryNotEmpty=/run/systemd/ask-password +MakeDirectory=yes diff --git a/units/systemd-ask-password-wall.path b/units/systemd-ask-password-wall.path index 7a883d5af8..050b73b2e1 100644 --- a/units/systemd-ask-password-wall.path +++ b/units/systemd-ask-password-wall.path @@ -13,3 +13,4 @@ Before=basic.target shutdown.target [Path] DirectoryNotEmpty=/run/systemd/ask-password +MakeDirectory=yes diff --git a/units/systemd-hostnamed.service.in b/units/systemd-hostnamed.service.in new file mode 100644 index 0000000000..6efab1e25f --- /dev/null +++ b/units/systemd-hostnamed.service.in @@ -0,0 +1,17 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# See systemd.special(7) for details + +[Unit] +Description=Hostname Service + +[Service] +ExecStart=@rootlibexecdir@/systemd-hostnamed +Type=dbus +BusName=org.freedesktop.hostname1 +CapabilityBoundingSet=CAP_SYS_ADMIN diff --git a/units/systemd-kmsg-syslogd.service.in b/units/systemd-kmsg-syslogd.service.in index b81e4a3069..b20889e5e5 100644 --- a/units/systemd-kmsg-syslogd.service.in +++ b/units/systemd-kmsg-syslogd.service.in @@ -14,4 +14,6 @@ DefaultDependencies=no [Service] ExecStart=@rootlibexecdir@/systemd-kmsg-syslogd NotifyAccess=all +StandardOutput=null Sockets=syslog.socket +CapabilityBoundingSet=CAP_DAC_OVERRIDE diff --git a/units/systemd-logger.service.in b/units/systemd-logger.service.in index f82db15ac1..5f7fe40939 100644 --- a/units/systemd-logger.service.in +++ b/units/systemd-logger.service.in @@ -10,9 +10,11 @@ [Unit] Description=Stdio Syslog Bridge DefaultDependencies=no +Requires=syslog.socket After=syslog.socket [Service] ExecStart=@rootlibexecdir@/systemd-logger NotifyAccess=all StandardOutput=null +CapabilityBoundingSet=CAP_SYS_ADMIN CAP_SETUID CAP_SETGID diff --git a/units/systemd-logger.socket b/units/systemd-logger.socket index 389b507d24..7178cc8246 100644 --- a/units/systemd-logger.socket +++ b/units/systemd-logger.socket @@ -8,9 +8,14 @@ # See systemd.special(7) for details [Unit] -Description=Stream Logging Socket +Description=Stdio Syslog Bridge Socket DefaultDependencies=no Before=sockets.target +# Mount and swap units need this. If this socket unit is removed by an +# isolate request the mount and and swap units would be removed too, +# hence let's exclude this from isolate requests. +IgnoreOnIsolate=yes + [Socket] ListenStream=/run/systemd/logger diff --git a/units/systemd-shutdownd.service.in b/units/systemd-shutdownd.service.in index 2214cafab2..657365a451 100644 --- a/units/systemd-shutdownd.service.in +++ b/units/systemd-shutdownd.service.in @@ -8,7 +8,7 @@ # See systemd.special(7) for details [Unit] -Description=Delayed Shutdown Daemon +Description=Delayed Shutdown Service DefaultDependencies=no [Service] diff --git a/units/systemd-update-utmp-runlevel.service.in b/units/systemd-update-utmp-runlevel.service.in index 865a1535de..614c759a63 100644 --- a/units/systemd-update-utmp-runlevel.service.in +++ b/units/systemd-update-utmp-runlevel.service.in @@ -8,7 +8,6 @@ [Unit] Description=Notify Audit System and Update UTMP about System Runlevel Changes DefaultDependencies=no -Wants=local-fs.target sysinit.target After=local-fs.target sysinit.target auditd.service runlevel1.target runlevel2.target runlevel3.target runlevel4.target runlevel5.target systemd-tmpfiles-setup.service Before=poweroff.service reboot.service halt.service diff --git a/units/systemd-update-utmp-shutdown.service.in b/units/systemd-update-utmp-shutdown.service.in index c30d86d24c..e7c3c04a00 100644 --- a/units/systemd-update-utmp-shutdown.service.in +++ b/units/systemd-update-utmp-shutdown.service.in @@ -8,7 +8,6 @@ [Unit] Description=Notify Audit System and Update UTMP about System Shutdown DefaultDependencies=no -Wants=local-fs.target sysinit.target After=local-fs.target sysinit.target auditd.service systemd-update-utmp-runlevel.service Before=poweroff.service reboot.service halt.service |