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