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