9fc0f6
From 97784aaf5e005bf57c572a6f8ccae5baee59bd0f Mon Sep 17 00:00:00 2001
9fc0f6
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
9fc0f6
Date: Fri, 20 Dec 2013 20:25:39 -0500
9fc0f6
Subject: [PATCH] tmpfiles: introduce the concept of unsafe operations
9fc0f6
9fc0f6
Various operations done by systemd-tmpfiles may only be safely done at
9fc0f6
boot (e.g. removal of X lockfiles in /tmp, creation of /run/nologin).
9fc0f6
Other operations may be done at any point in time (e.g. setting the
9fc0f6
ownership on /{run,var}/log/journal). This distinction is largely
9fc0f6
orthogonal to the type of operation.
9fc0f6
9fc0f6
A new switch --unsafe is added, and operations which should only be
9fc0f6
executed during bootup are marked with an exclamation mark in the
9fc0f6
configuration files. systemd-tmpfiles.service is modified to use this
9fc0f6
switch, and guards are added so it is hard to re-start it by mistake.
9fc0f6
9fc0f6
If we install a new version of systemd, we actually want to enforce
9fc0f6
some changes to tmpfiles configuration immediately. This should now be
9fc0f6
possible to do safely, so distribution packages can be modified to
9fc0f6
execute the "safe" subset at package installation time.
9fc0f6
9fc0f6
/run/nologin creation is split out into a separate service, to make it
9fc0f6
easy to override.
9fc0f6
9fc0f6
https://bugzilla.redhat.com/show_bug.cgi?id=1043212
9fc0f6
https://bugzilla.redhat.com/show_bug.cgi?id=1045849
9fc0f6
---
9fc0f6
 Makefile.am                             |  1 +
9fc0f6
 man/systemd-tmpfiles.xml                |  6 ++++++
9fc0f6
 man/tmpfiles.d.xml                      | 25 +++++++++++++++++++++++++
9fc0f6
 src/tmpfiles/tmpfiles.c                 | 22 +++++++++++++++++++---
9fc0f6
 tmpfiles.d/legacy.conf                  |  6 +++---
9fc0f6
 tmpfiles.d/systemd-nologin.conf         | 11 +++++++++++
9fc0f6
 tmpfiles.d/systemd.conf                 |  4 +---
9fc0f6
 tmpfiles.d/x11.conf                     |  2 +-
9fc0f6
 units/systemd-tmpfiles-setup.service.in |  6 ++++--
9fc0f6
 9 files changed, 71 insertions(+), 12 deletions(-)
9fc0f6
 create mode 100644 tmpfiles.d/systemd-nologin.conf
9fc0f6
9fc0f6
diff --git a/Makefile.am b/Makefile.am
9fc0f6
index 3103bac..f4867d9 100644
9fc0f6
--- a/Makefile.am
9fc0f6
+++ b/Makefile.am
9fc0f6
@@ -1589,6 +1589,7 @@ nodist_systemunit_DATA += \
9fc0f6
 
9fc0f6
 dist_tmpfiles_DATA = \
9fc0f6
 	tmpfiles.d/systemd.conf \
9fc0f6
+	tmpfiles.d/systemd-nologin.conf \
9fc0f6
 	tmpfiles.d/tmp.conf \
9fc0f6
 	tmpfiles.d/x11.conf
9fc0f6
 
9fc0f6
diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml
9fc0f6
index 91c0372..495247e 100644
9fc0f6
--- a/man/systemd-tmpfiles.xml
9fc0f6
+++ b/man/systemd-tmpfiles.xml
9fc0f6
@@ -133,6 +133,12 @@
9fc0f6
                                 removed.</para></listitem>
9fc0f6
                         </varlistentry>
9fc0f6
                         <varlistentry>
9fc0f6
+                                <term><option>--unsafe</option></term>
9fc0f6
+                                <listitem><para>Also execute lines
9fc0f6
+                                with an exclamation mark.
9fc0f6
+                                </para></listitem>
9fc0f6
+                        </varlistentry>
9fc0f6
+                        <varlistentry>
9fc0f6
                                 <term><option>--prefix=PATH</option></term>
9fc0f6
                                 <listitem><para>Only apply rules that
9fc0f6
                                 apply to paths with the specified
9fc0f6
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
9fc0f6
index a00637b..39aa68d 100644
9fc0f6
--- a/man/tmpfiles.d.xml
9fc0f6
+++ b/man/tmpfiles.d.xml
9fc0f6
@@ -113,6 +113,9 @@ L    /tmp/foobar -    -    -    -   /dev/null</programlisting>
9fc0f6
                 <refsect2>
9fc0f6
                         <title>Type</title>
9fc0f6
 
9fc0f6
+                        <para>The type consists of a single letter and
9fc0f6
+                        optionally an exclamation mark.</para>
9fc0f6
+
9fc0f6
                         <para>The following line types are understood:</para>
9fc0f6
 
9fc0f6
                         <variablelist>
9fc0f6
@@ -262,6 +265,28 @@ L    /tmp/foobar -    -    -    -   /dev/null</programlisting>
9fc0f6
                                         names.</para></listitem>
9fc0f6
                                 </varlistentry>
9fc0f6
                         </variablelist>
9fc0f6
+
9fc0f6
+                        <para>If the exclamation mark is used, this
9fc0f6
+                        line is only safe of execute during boot, and
9fc0f6
+                        can break a running system. Lines without the
9fc0f6
+                        exclamation mark are presumed to be safe to
9fc0f6
+                        execute at any time, e.g. on package upgrades.
9fc0f6
+                        <command>systemd-tmpfiles</command> will
9fc0f6
+                        execute line with an exclamation mark only if
9fc0f6
+                        option <option>--unsafe</option> is given.
9fc0f6
+                        </para>
9fc0f6
+
9fc0f6
+                        <para>For example:
9fc0f6
+                        <programlisting>
9fc0f6
+# Make sure these are created by default so that nobody else can
9fc0f6
+d /tmp/.X11-unix 1777 root root 10d
9fc0f6
+
9fc0f6
+# Unlink the X11 lock files
9fc0f6
+r! /tmp/.X[0-9]*-lock
9fc0f6
+                        </programlisting>
9fc0f6
+                        The second line in contrast to the first one
9fc0f6
+                        would break a running system, and will only be
9fc0f6
+                        executed with <option>--unsafe</option>.</para>
9fc0f6
                 </refsect2>
9fc0f6
 
9fc0f6
                 <refsect2>
9fc0f6
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
9fc0f6
index 9a397af..1983717 100644
9fc0f6
--- a/src/tmpfiles/tmpfiles.c
9fc0f6
+++ b/src/tmpfiles/tmpfiles.c
9fc0f6
@@ -106,6 +106,7 @@ static Set *unix_sockets = NULL;
9fc0f6
 static bool arg_create = false;
9fc0f6
 static bool arg_clean = false;
9fc0f6
 static bool arg_remove = false;
9fc0f6
+static bool arg_unsafe = false;
9fc0f6
 
9fc0f6
 static char **include_prefixes = NULL;
9fc0f6
 static char **exclude_prefixes = NULL;
9fc0f6
@@ -1073,7 +1074,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
9fc0f6
         _cleanup_item_free_ Item *i = NULL;
9fc0f6
         Item *existing;
9fc0f6
         _cleanup_free_ char
9fc0f6
-                *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
9fc0f6
+                *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
9fc0f6
         char type;
9fc0f6
         Hashmap *h;
9fc0f6
         int r, n = -1;
9fc0f6
@@ -1083,8 +1084,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
9fc0f6
         assert(buffer);
9fc0f6
 
9fc0f6
         r = sscanf(buffer,
9fc0f6
-                   "%c %ms %ms %ms %ms %ms %n",
9fc0f6
-                   &type,
9fc0f6
+                   "%ms %ms %ms %ms %ms %ms %n",
9fc0f6
+                   &action,
9fc0f6
                    &path,
9fc0f6
                    &mode,
9fc0f6
                    &user,
9fc0f6
@@ -1096,6 +1097,14 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
9fc0f6
                 return -EIO;
9fc0f6
         }
9fc0f6
 
9fc0f6
+        if (strlen(action) > 2 || (strlen(action) > 1 && action[1] != '!')) {
9fc0f6
+                log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
9fc0f6
+                return -EINVAL;
9fc0f6
+        } else if (strlen(action) > 1 && !arg_unsafe)
9fc0f6
+                return 0;
9fc0f6
+
9fc0f6
+        type = action[0];
9fc0f6
+
9fc0f6
         i = new0(Item, 1);
9fc0f6
         if (!i)
9fc0f6
                 return log_oom();
9fc0f6
@@ -1266,6 +1275,7 @@ static int help(void) {
9fc0f6
                "     --create               Create marked files/directories\n"
9fc0f6
                "     --clean                Clean up marked directories\n"
9fc0f6
                "     --remove               Remove marked files/directories\n"
9fc0f6
+               "     --unsafe               Execute actions only safe at boot\n"
9fc0f6
                "     --prefix=PATH          Only apply rules that apply to paths with the specified prefix\n"
9fc0f6
                "     --exclude-prefix=PATH  Ignore rules that apply to paths with the specified prefix\n",
9fc0f6
                program_invocation_short_name);
9fc0f6
@@ -1279,6 +1289,7 @@ static int parse_argv(int argc, char *argv[]) {
9fc0f6
                 ARG_CREATE,
9fc0f6
                 ARG_CLEAN,
9fc0f6
                 ARG_REMOVE,
9fc0f6
+                ARG_UNSAFE,
9fc0f6
                 ARG_PREFIX,
9fc0f6
                 ARG_EXCLUDE_PREFIX,
9fc0f6
         };
9fc0f6
@@ -1288,6 +1299,7 @@ static int parse_argv(int argc, char *argv[]) {
9fc0f6
                 { "create",         no_argument,         NULL, ARG_CREATE         },
9fc0f6
                 { "clean",          no_argument,         NULL, ARG_CLEAN          },
9fc0f6
                 { "remove",         no_argument,         NULL, ARG_REMOVE         },
9fc0f6
+                { "unsafe",         no_argument,         NULL, ARG_UNSAFE         },
9fc0f6
                 { "prefix",         required_argument,   NULL, ARG_PREFIX         },
9fc0f6
                 { "exclude-prefix", required_argument,   NULL, ARG_EXCLUDE_PREFIX },
9fc0f6
                 { NULL,             0,                   NULL, 0                  }
9fc0f6
@@ -1318,6 +1330,10 @@ static int parse_argv(int argc, char *argv[]) {
9fc0f6
                         arg_remove = true;
9fc0f6
                         break;
9fc0f6
 
9fc0f6
+                case ARG_UNSAFE:
9fc0f6
+                        arg_unsafe = true;
9fc0f6
+                        break;
9fc0f6
+
9fc0f6
                 case ARG_PREFIX:
9fc0f6
                         if (strv_extend(&include_prefixes, optarg) < 0)
9fc0f6
                                 return log_oom();
9fc0f6
diff --git a/tmpfiles.d/legacy.conf b/tmpfiles.d/legacy.conf
9fc0f6
index 3fff347..a165687 100644
9fc0f6
--- a/tmpfiles.d/legacy.conf
9fc0f6
+++ b/tmpfiles.d/legacy.conf
9fc0f6
@@ -29,6 +29,6 @@ d /run/lock/lockdev 0775 root lock -
9fc0f6
 # kernel command line options 'fsck.mode=force', 'fsck.mode=skip' and
9fc0f6
 # 'quotacheck.mode=force'
9fc0f6
 
9fc0f6
-r /forcefsck
9fc0f6
-r /fastboot
9fc0f6
-r /forcequotacheck
9fc0f6
+r! /forcefsck
9fc0f6
+r! /fastboot
9fc0f6
+r! /forcequotacheck
9fc0f6
diff --git a/tmpfiles.d/systemd-nologin.conf b/tmpfiles.d/systemd-nologin.conf
9fc0f6
new file mode 100644
9fc0f6
index 0000000..d61232b
9fc0f6
--- /dev/null
9fc0f6
+++ b/tmpfiles.d/systemd-nologin.conf
9fc0f6
@@ -0,0 +1,11 @@
9fc0f6
+#  This file is part of systemd.
9fc0f6
+#
9fc0f6
+#  systemd is free software; you can redistribute it and/or modify it
9fc0f6
+#  under the terms of the GNU Lesser General Public License as published by
9fc0f6
+#  the Free Software Foundation; either version 2.1 of the License, or
9fc0f6
+#  (at your option) any later version.
9fc0f6
+
9fc0f6
+# See tmpfiles.d(5) and systemd-forbid-user-logins.service(5).
9fc0f6
+# This file has special suffix so it is not run by mistake.
9fc0f6
+
9fc0f6
+F! /run/nologin 0644 - - - "System is booting up. See pam_nologin(8)"
9fc0f6
diff --git a/tmpfiles.d/systemd.conf b/tmpfiles.d/systemd.conf
9fc0f6
index a05c657..7c6d6b9 100644
9fc0f6
--- a/tmpfiles.d/systemd.conf
9fc0f6
+++ b/tmpfiles.d/systemd.conf
9fc0f6
@@ -8,7 +8,7 @@
9fc0f6
 # See tmpfiles.d(5) for details
9fc0f6
 
9fc0f6
 d /run/user 0755 root root ~10d
9fc0f6
-F /run/utmp 0664 root utmp -
9fc0f6
+F! /run/utmp 0664 root utmp -
9fc0f6
 
9fc0f6
 f /var/log/wtmp 0664 root utmp -
9fc0f6
 f /var/log/btmp 0600 root utmp -
9fc0f6
@@ -22,8 +22,6 @@ d /run/systemd/users 0755 root root -
9fc0f6
 d /run/systemd/machines 0755 root root -
9fc0f6
 d /run/systemd/shutdown 0755 root root -
9fc0f6
 
9fc0f6
-F /run/nologin 0644 - - - "System is booting up. See pam_nologin(8)"
9fc0f6
-
9fc0f6
 m /var/log/journal 2755 root systemd-journal - -
9fc0f6
 m /var/log/journal/%m 2755 root systemd-journal - -
9fc0f6
 m /run/log/journal 2755 root systemd-journal - -
9fc0f6
diff --git a/tmpfiles.d/x11.conf b/tmpfiles.d/x11.conf
9fc0f6
index ece6a5c..4c96a54 100644
9fc0f6
--- a/tmpfiles.d/x11.conf
9fc0f6
+++ b/tmpfiles.d/x11.conf
9fc0f6
@@ -15,4 +15,4 @@ d /tmp/.font-unix 1777 root root 10d
9fc0f6
 d /tmp/.Test-unix 1777 root root 10d
9fc0f6
 
9fc0f6
 # Unlink the X11 lock files
9fc0f6
-r /tmp/.X[0-9]*-lock
9fc0f6
+r! /tmp/.X[0-9]*-lock
9fc0f6
diff --git a/units/systemd-tmpfiles-setup.service.in b/units/systemd-tmpfiles-setup.service.in
9fc0f6
index 3405e28..c2dcae0 100644
9fc0f6
--- a/units/systemd-tmpfiles-setup.service.in
9fc0f6
+++ b/units/systemd-tmpfiles-setup.service.in
9fc0f6
@@ -6,7 +6,7 @@
9fc0f6
 #  (at your option) any later version.
9fc0f6
 
9fc0f6
 [Unit]
9fc0f6
-Description=Recreate Volatile Files and Directories
9fc0f6
+Description=Create Volatile Files and Directories
9fc0f6
 Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
9fc0f6
 DefaultDependencies=no
9fc0f6
 Wants=local-fs.target
9fc0f6
@@ -18,8 +18,10 @@ ConditionDirectoryNotEmpty=|/lib/tmpfiles.d
9fc0f6
 ConditionDirectoryNotEmpty=|/usr/local/lib/tmpfiles.d
9fc0f6
 ConditionDirectoryNotEmpty=|/etc/tmpfiles.d
9fc0f6
 ConditionDirectoryNotEmpty=|/run/tmpfiles.d
9fc0f6
+RefuseManualStart=yes
9fc0f6
+RefuseManualStop=yes
9fc0f6
 
9fc0f6
 [Service]
9fc0f6
 Type=oneshot
9fc0f6
 RemainAfterExit=yes
9fc0f6
-ExecStart=@rootbindir@/systemd-tmpfiles --create --remove --exclude-prefix=/dev
9fc0f6
+ExecStart=@rootbindir@/systemd-tmpfiles --create --remove --unsafe --exclude-prefix=/dev