[systemd-commits] 12 commits - Makefile.am man/pam_systemd.xml man/systemd.service.xml man/systemd-tmpfiles.xml man/tmpfiles.d.xml src/cgroup.c src/dbus-service.c src/load-fragment.c src/pam-module.c src/readahead-collect.c src/readahead-replay.c src/service.c src/service.h src/systemctl.c src/tmpfiles.c src/util.c src/util.h tmpfiles.d/x11.conf TODO units/systemd-tmpfiles-clean.service.in units/systemd-tmpfiles-setup.service.in

Lennart Poettering lennart at kemper.freedesktop.org
Sun Feb 13 12:46:39 PST 2011


 Makefile.am                             |    5 -
 TODO                                    |   16 ---
 man/pam_systemd.xml                     |   50 ++++++++--
 man/systemd-tmpfiles.xml                |  150 ++++++++++++++++++++++++++++++++
 man/systemd.service.xml                 |   24 +++++
 man/tmpfiles.d.xml                      |   19 ++--
 src/cgroup.c                            |   15 ++-
 src/dbus-service.c                      |    5 -
 src/load-fragment.c                     |    1 
 src/pam-module.c                        |  125 +++++++++++++++++++++++---
 src/readahead-collect.c                 |    5 +
 src/readahead-replay.c                  |    5 +
 src/service.c                           |   22 +++-
 src/service.h                           |    1 
 src/systemctl.c                         |   43 +++++----
 src/tmpfiles.c                          |  147 ++++++++++++++++++-------------
 src/util.c                              |   96 +++++++++++++++++++-
 src/util.h                              |    2 
 tmpfiles.d/x11.conf                     |   11 --
 units/systemd-tmpfiles-clean.service.in |    2 
 units/systemd-tmpfiles-setup.service.in |    2 
 21 files changed, 584 insertions(+), 162 deletions(-)

New commits:
commit cfdc0c8941f25ab08140d56f773105228e459ac5
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 19:02:18 2011 +0100

    update TODO

diff --git a/TODO b/TODO
index 9827b07..f7269f1 100644
--- a/TODO
+++ b/TODO
@@ -124,10 +124,6 @@ Features:
 
 * allow runtime changing of log level and target
 
-* automatically determine TERM= based on tty name even for /dev/console
-    http://git.kernel.org/?p=linux/kernel/git/gregkh/tty-2.6.git;a=commitdiff;h=fbc92a3455577ab17615cbcb91826399061bd789
-    http://git.kernel.org/?p=linux/kernel/git/gregkh/tty-2.6.git;a=commitdiff;h=b7b8de087384cc1954a8cd075af3f9e5977caa2e
-
 * global defaults for StandardOuput=xxx
 
 Fedora:

commit 3030ccd79f71854551d06cda904fd56b85b1aeb7
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 19:01:47 2011 +0100

    util: when determining the right TERM for /dev/console consult /sys/class/tty/console/active

diff --git a/src/util.c b/src/util.c
index 09c1314..e78063c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -3550,18 +3550,28 @@ void filter_environ(const char *prefix) {
 }
 
 const char *default_term_for_tty(const char *tty) {
+        char *active = NULL;
+        const char *term;
+
         assert(tty);
 
         if (startswith(tty, "/dev/"))
                 tty += 5;
 
-        if (startswith(tty, "tty") &&
-            tty[3] >= '0' && tty[3] <= '9')
-                return "TERM=linux";
+        /* Resolve where /dev/console is pointing when determining
+         * TERM */
+        if (streq(tty, "console"))
+                if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
+                        truncate_nl(active);
+                        tty = active;
+                }
+
+        term = (startswith(tty, "tty") &&
+                tty[3] >= '0' && tty[3] <= '9') ? "TERM=linux" : "TERM=vt100";
 
-        /* FIXME: Proper handling of /dev/console would be cool */
+        free(active);
 
-        return "TERM=vt100";
+        return term;
 }
 
 bool running_in_vm(void) {

commit 2633eb8317623138f585957fcf8337a99fb1528f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 18:52:02 2011 +0100

    service: when guessing the main PID don't consider processes that aren't our children

diff --git a/src/cgroup.c b/src/cgroup.c
index 392736f..729cc75 100644
--- a/src/cgroup.c
+++ b/src/cgroup.c
@@ -403,7 +403,7 @@ char *cgroup_bonding_to_string(CGroupBonding *b) {
 
 pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
         FILE *f;
-        pid_t pid = 0, npid;
+        pid_t pid = 0, npid, mypid;
 
         assert(b);
 
@@ -413,15 +413,22 @@ pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
         if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
                 return 0;
 
+        mypid = getpid();
+
         while (cg_read_pid(f, &npid) > 0)  {
+                pid_t ppid;
 
                 if (npid == pid)
                         continue;
 
+                /* Ignore processes that aren't our kids */
+                if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
+                        continue;
+
                 if (pid != 0) {
-                        /* Dang, there's more than one PID in this
-                         * group, so we don't know what process is the
-                         * main process. */
+                        /* Dang, there's more than one daemonized PID
+                        in this group, so we don't know what process
+                        is the main process. */
                         pid = 0;
                         break;
                 }

commit 3185a36b05d53757a412f847d8c510978b9b00f0
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 18:51:30 2011 +0100

    service: make main pid guessing optional, and reread pid file after reloads

diff --git a/TODO b/TODO
index 4d5a144..9827b07 100644
--- a/TODO
+++ b/TODO
@@ -9,6 +9,8 @@ Bugs:
 
 Features:
 
+* Maybe store in unit files whether a service should be enabled by default on package installation
+
 * 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 instead of fstab
@@ -23,12 +25,8 @@ Features:
 
 * gnome-shell python script/glxinfo/is-accelerated wech
 
-* PID heuristik bei Type=forking ausmachbar machen
-
 * maybe introduce ExecRestartPre=
 
-* reload PID file after reload, allow dynamically changing main PIDs
-
 * figure out what happened to bluez patch
 
 * introduce StandardOutput=syslog+console and StandardOutput=kmsg+console to support fsck output at boot
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 3bd058f..7200525 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -216,6 +216,30 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><varname>GuessMainPID=</varname></term>
+
+                                <listitem><para>Takes a boolean value
+                                that specifies whether systemd should
+                                try to guess the main PID of a service
+                                should if it cannot be determined
+                                reliably. This option is ignored
+                                unless <option>Type=forking</option>
+                                is set and <option>PIDFile=</option>
+                                is unset because for the other types
+                                or with an explicitly configured PID
+                                file the main PID is always known. The
+                                guessing algorithm might come to
+                                incorrect conclusions if a daemon
+                                consists of more than one process. If
+                                the main PID cannot be determined
+                                failure detection and automatic
+                                restarting of a service will not work
+                                reliably. Defaults to
+                                <option>yes</option>.</para>
+                                </listitem>
+                        </varlistentry>
+
+                        <varlistentry>
                                 <term><varname>PIDFile=</varname></term>
 
                                 <listitem><para>Takes an absolute file
diff --git a/src/dbus-service.c b/src/dbus-service.c
index f929627..93fc2a3 100644
--- a/src/dbus-service.c
+++ b/src/dbus-service.c
@@ -127,8 +127,9 @@ DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connectio
                 BUS_EXEC_CONTEXT_PROPERTIES("org.freedesktop.systemd1.Service", u->service.exec_context),
                 { "org.freedesktop.systemd1.Service", "PermissionsStartOnly",   bus_property_append_bool,   "b", &u->service.permissions_start_only    },
                 { "org.freedesktop.systemd1.Service", "RootDirectoryStartOnly", bus_property_append_bool,   "b", &u->service.root_directory_start_only },
-                { "org.freedesktop.systemd1.Service", "RemainAfterExit",        bus_property_append_bool,   "b", &u->service.remain_after_exit          },
-                BUS_EXEC_STATUS_PROPERTIES("org.freedesktop.systemd1.Service", u->service.main_exec_status, "ExecMain"),
+                { "org.freedesktop.systemd1.Service", "RemainAfterExit",        bus_property_append_bool,   "b", &u->service.remain_after_exit         },
+                { "org.freedesktop.systemd1.Service", "GuessMainPID",           bus_property_append_bool,   "b", &u->service.guess_main_pid            },
+               BUS_EXEC_STATUS_PROPERTIES("org.freedesktop.systemd1.Service", u->service.main_exec_status, "ExecMain"),
                 { "org.freedesktop.systemd1.Service", "MainPID",                bus_property_append_pid,    "u", &u->service.main_pid                  },
                 { "org.freedesktop.systemd1.Service", "ControlPID",             bus_property_append_pid,    "u", &u->service.control_pid               },
 #ifdef HAVE_SYSV_COMPAT
diff --git a/src/load-fragment.c b/src/load-fragment.c
index ab2bcd2..eaeaada 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1854,6 +1854,7 @@ static int load_from_path(Unit *u, const char *path) {
                 { "PermissionsStartOnly",   config_parse_bool,            &u->service.permissions_start_only,              "Service" },
                 { "RootDirectoryStartOnly", config_parse_bool,            &u->service.root_directory_start_only,           "Service" },
                 { "RemainAfterExit",        config_parse_bool,            &u->service.remain_after_exit,                   "Service" },
+                { "GuessMainPID",           config_parse_bool,            &u->service.guess_main_pid,                      "Service" },
 #ifdef HAVE_SYSV_COMPAT
                 { "SysVStartPriority",      config_parse_sysv_priority,   &u->service.sysv_start_priority,                 "Service" },
 #else
diff --git a/src/service.c b/src/service.c
index 60576df..243e553 100644
--- a/src/service.c
+++ b/src/service.c
@@ -118,6 +118,7 @@ static void service_init(Unit *u) {
         s->sysv_start_priority = -1;
 #endif
         s->socket_fd = -1;
+        s->guess_main_pid = true;
 
         exec_context_init(&s->exec_context);
 
@@ -1151,6 +1152,7 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
                 "%sPermissionsStartOnly: %s\n"
                 "%sRootDirectoryStartOnly: %s\n"
                 "%sRemainAfterExit: %s\n"
+                "%sGuessMainPID: %s\n"
                 "%sType: %s\n"
                 "%sRestart: %s\n"
                 "%sNotifyAccess: %s\n",
@@ -1158,6 +1160,7 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
                 prefix, yes_no(s->permissions_start_only),
                 prefix, yes_no(s->root_directory_start_only),
                 prefix, yes_no(s->remain_after_exit),
+                prefix, yes_no(s->guess_main_pid),
                 prefix, service_type_to_string(s->type),
                 prefix, service_restart_to_string(s->restart),
                 prefix, notify_access_to_string(s->notify_access));
@@ -1236,11 +1239,6 @@ static int service_load_pid_file(Service *s) {
 
         assert(s);
 
-        if (s->main_pid_known)
-                return 0;
-
-        assert(s->main_pid <= 0);
-
         if (!s->pid_file)
                 return -ENOENT;
 
@@ -1275,9 +1273,14 @@ static int service_search_main_pid(Service *s) {
 
         assert(s);
 
+        /* If we know it anyway, don't ever fallback to unreliable
+         * heuristics */
         if (s->main_pid_known)
                 return 0;
 
+        if (!s->guess_main_pid)
+                return 0;
+
         assert(s->main_pid <= 0);
 
         if ((pid = cgroup_bonding_search_main_pid_list(s->meta.cgroup_bondings)) <= 0)
@@ -2674,9 +2677,16 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                                 log_warning("%s: failed to load PID file %s: %s", s->meta.id, s->pid_file, strerror(-r));
                                 }
 
-                                /* Fall through */
+                                s->reload_failure = !success;
+                                service_enter_running(s, true);
+                                break;
 
                         case SERVICE_RELOAD:
+                                if (success) {
+                                        service_load_pid_file(s);
+                                        service_search_main_pid(s);
+                                }
+
                                 s->reload_failure = !success;
                                 service_enter_running(s, true);
                                 break;
diff --git a/src/service.h b/src/service.h
index e06ff3d..627b356 100644
--- a/src/service.h
+++ b/src/service.h
@@ -125,6 +125,7 @@ struct Service {
         bool permissions_start_only;
         bool root_directory_start_only;
         bool remain_after_exit;
+        bool guess_main_pid;
 
         /* If we shut down, remember why */
         bool failure:1;

commit e9fbc77c8f6a396ce9432e3791710e30de6e570b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 18:21:11 2011 +0100

    pam: introduce whitelist and blacklist user list feature
    
    This is useful to exclude root from the session logout killings or to
    limit killing to the selinux guest users.

diff --git a/TODO b/TODO
index 8660f16..4d5a144 100644
--- a/TODO
+++ b/TODO
@@ -147,8 +147,6 @@ External:
 * patch kernel for cpu feature modalias for autoloading aes/kvm/...
     http://git.kernel.org/?p=linux/kernel/git/ak/linux-misc-2.6.git;a=shortlog;h=refs/heads/cpuid-match
 
-* place /etc/inittab with explaining blurb.
-
 * procps, psmisc, sysvinit-tools, hostname → util-linux-ng
 
 https://bugzilla.redhat.com/show_bug.cgi?id=614245 -- plymouth
diff --git a/man/pam_systemd.xml b/man/pam_systemd.xml
index 6fe6981..915e0b6 100644
--- a/man/pam_systemd.xml
+++ b/man/pam_systemd.xml
@@ -202,17 +202,43 @@
                         </varlistentry>
 
                         <varlistentry>
-                                <term><option>keep-root=</option></term>
+                                <term><option>kill-only-users=</option></term>
 
-                                <listitem><para>Takes a boolean
-                                argument. If true, all processes
-                                created by the root user (UID 0) during his
-                                session and from his session will be
-                                kept around after he logged out. This
-                                option allows cancelling the effect of
-                                <option>kill-session=1</option> and
-                                <option>kill-user=1</option> for the
-                                root user.</para></listitem>
+                                <listitem><para>Takes a comma
+                                separated list of user names or
+                                numeric user ids as argument. If this
+                                option is used the effect of the
+                                <option>kill-session=</option> and
+                                <option>kill-user=</option> options
+                                will apply only to the listed
+                                users. If this option is not used the
+                                option applies to all local
+                                users. Note that
+                                <option>kill-exclude-users=</option>
+                                takes precedence over this list and is
+                                hence subtracted from the list
+                                specified here.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><option>kill-exclude-users=</option></term>
+
+                                <listitem><para>Takes a comma
+                                separated list of user names or
+                                numeric user ids as argument. Users
+                                listed in this argument will not be
+                                subject to the effect of
+                                <option>kill-session=</option> or
+                                <option>kill-user=</option>.  Note
+                                that that this option takes precedence
+                                over
+                                <option>kill-only-users=</option>, and
+                                hence whatever is listed for
+                                <option>kill-exclude-users=</option>
+                                is guaranteed to never be killed by
+                                this PAM module, independent of any
+                                other configuration
+                                setting.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
@@ -259,7 +285,9 @@
                 <option>kill-session=0</option>,
                 <option>kill-user=0</option>,
                 <option>keep-root=1</option>,
-                <option>reset-controllers=cpu</option>.</para>
+                <option>reset-controllers=cpu</option>,
+                <option>kill-only-users=</option>,
+                <option>kill-exclude-users=root</option>.</para>
         </refsect1>
 
         <refsect1>
diff --git a/src/pam-module.c b/src/pam-module.c
index 117df05..7f91584 100644
--- a/src/pam-module.c
+++ b/src/pam-module.c
@@ -42,12 +42,14 @@ static int parse_argv(pam_handle_t *handle,
                       bool *create_session,
                       bool *kill_session,
                       bool *kill_user,
-                      bool *keep_root,
                       char ***controllers,
-                      char ***reset_controllers) {
+                      char ***reset_controllers,
+                      char ***kill_only_users,
+                      char ***kill_exclude_users) {
 
         unsigned i;
         bool reset_controller_set = false;
+        bool kill_exclude_users_set = false;
 
         assert(argc >= 0);
         assert(argc == 0 || argv);
@@ -82,15 +84,6 @@ static int parse_argv(pam_handle_t *handle,
                         if (kill_user)
                                 *kill_user = k;
 
-                } else if (startswith(argv[i], "keep-root=")) {
-                        if ((k = parse_boolean(argv[i] + 10)) < 0) {
-                                pam_syslog(handle, LOG_ERR, "Failed to parse keep-root= argument.");
-                                return k;
-                        }
-
-                        if (keep_root)
-                                *keep_root = k;
-
                 } else if (startswith(argv[i], "controllers=")) {
 
                         if (controllers) {
@@ -121,6 +114,36 @@ static int parse_argv(pam_handle_t *handle,
 
                         reset_controller_set = true;
 
+                } else if (startswith(argv[i], "kill-only-users=")) {
+
+                        if (kill_only_users) {
+                                char **l;
+
+                                if (!(l = strv_split(argv[i] + 16, ","))) {
+                                        pam_syslog(handle, LOG_ERR, "Out of memory.");
+                                        return -ENOMEM;
+                                }
+
+                                strv_free(*kill_only_users);
+                                *kill_only_users = l;
+                        }
+
+                } else if (startswith(argv[i], "kill-exclude-users=")) {
+
+                        if (kill_exclude_users) {
+                                char **l;
+
+                                if (!(l = strv_split(argv[i] + 19, ","))) {
+                                        pam_syslog(handle, LOG_ERR, "Out of memory.");
+                                        return -ENOMEM;
+                                }
+
+                                strv_free(*kill_exclude_users);
+                                *kill_exclude_users = l;
+                        }
+
+                        kill_exclude_users_set = true;
+
                 } else {
                         pam_syslog(handle, LOG_ERR, "Unknown parameter '%s'.", argv[i]);
                         return -EINVAL;
@@ -147,6 +170,17 @@ static int parse_argv(pam_handle_t *handle,
         if (kill_session && *kill_session && kill_user)
                 *kill_user = true;
 
+        if (!kill_exclude_users_set && kill_exclude_users) {
+                char **l;
+
+                if (!(l = strv_new("root", NULL))) {
+                        pam_syslog(handle, LOG_ERR, "Out of memory");
+                        return -ENOMEM;
+                }
+
+                *kill_exclude_users = l;
+        }
+
         return 0;
 }
 
@@ -369,7 +403,11 @@ _public_ PAM_EXTERN int pam_sm_open_session(
         if (sd_booted() <= 0)
                 return PAM_SUCCESS;
 
-        if (parse_argv(handle, argc, argv, &create_session, NULL, NULL, NULL, &controllers, &reset_controllers) < 0)
+        if (parse_argv(handle,
+                       argc, argv,
+                       &create_session, NULL, NULL,
+                       &controllers, &reset_controllers,
+                       NULL, NULL) < 0)
                 return PAM_SESSION_ERR;
 
         if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS)
@@ -500,6 +538,54 @@ static int session_remains(pam_handle_t *handle, const char *user_path) {
         return !!remains;
 }
 
+static bool check_user_lists(
+                pam_handle_t *handle,
+                uid_t uid,
+                char **kill_only_users,
+                char **kill_exclude_users) {
+
+        const char *name = NULL;
+        char **l;
+
+        assert(handle);
+
+        if (uid == 0)
+                name = "root"; /* Avoid obvious NSS requests, to suppress network traffic */
+        else {
+                struct passwd *pw;
+
+                if ((pw = pam_modutil_getpwuid(handle, uid)))
+                        name = pw->pw_name;
+        }
+
+        STRV_FOREACH(l, kill_exclude_users) {
+                uint32_t id;
+
+                if (safe_atou32(*l, &id) >= 0)
+                        if ((uid_t) id == uid)
+                                return false;
+
+                if (name && streq(name, *l))
+                        return false;
+        }
+
+        if (strv_isempty(kill_only_users))
+                return true;
+
+        STRV_FOREACH(l, kill_only_users) {
+                uint32_t id;
+
+                if (safe_atou32(*l, &id) >= 0)
+                        if ((uid_t) id == uid)
+                                return true;
+
+                if (name && streq(name, *l))
+                        return true;
+        }
+
+        return false;
+}
+
 _public_ PAM_EXTERN int pam_sm_close_session(
                 pam_handle_t *handle,
                 int flags,
@@ -508,13 +594,12 @@ _public_ PAM_EXTERN int pam_sm_close_session(
         const char *username = NULL;
         bool kill_session = false;
         bool kill_user = false;
-        bool keep_root = true;
         int lock_fd = -1, r;
         char *session_path = NULL, *nosession_path = NULL, *user_path = NULL;
         const char *id;
         struct passwd *pw;
         const void *created = NULL;
-        char **controllers = NULL, **c;
+        char **controllers = NULL, **c, **kill_only_users = NULL, **kill_exclude_users = NULL;
 
         assert(handle);
 
@@ -522,7 +607,11 @@ _public_ PAM_EXTERN int pam_sm_close_session(
         if (sd_booted() <= 0)
                 return PAM_SUCCESS;
 
-        if (parse_argv(handle, argc, argv, NULL, &kill_session, &kill_user, &keep_root, &controllers, NULL) < 0)
+        if (parse_argv(handle,
+                       argc, argv,
+                       NULL, &kill_session, &kill_user,
+                       &controllers, NULL,
+                       &kill_only_users, &kill_exclude_users) < 0)
                 return PAM_SESSION_ERR;
 
         if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS)
@@ -557,7 +646,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
                         goto finish;
                 }
 
-                if (kill_session && (pw->pw_uid != 0 || !keep_root))  {
+                if (kill_session && check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users))  {
                         pam_syslog(handle, LOG_INFO, "Killing remaining processes of user session %s of %s.", id, username);
 
                         /* Kill processes in session cgroup, and delete it */
@@ -591,7 +680,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
                 pam_syslog(handle, LOG_ERR, "Failed to determine whether a session remains: %s", strerror(-r));
 
         /* Kill user processes not attached to any session */
-        if (kill_user && r == 0 && (pw->pw_uid != 0 || !keep_root)) {
+        if (kill_user && r == 0 && check_user_lists(handle, pw->pw_uid, kill_only_users, kill_exclude_users)) {
 
                 /* Kill user cgroup */
                 if ((r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, user_path, true)) < 0)
@@ -635,6 +724,8 @@ finish:
         free(user_path);
 
         strv_free(controllers);
+        strv_free(kill_exclude_users);
+        strv_free(kill_only_users);
 
         return r;
 }

commit 7fc01d33196f329c24766795b7af66e598c3e65b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 17:18:45 2011 +0100

    systemctl: minor optimizations

diff --git a/src/systemctl.c b/src/systemctl.c
index 94a12dd..dfa952e 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -161,6 +161,7 @@ static void spawn_ask_password_agent(void) {
                 };
 
                 int fd;
+                bool stdout_is_tty, stderr_is_tty;
 
                 /* Make sure the agent goes away when the parent dies */
                 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
@@ -174,7 +175,10 @@ static void spawn_ask_password_agent(void) {
                 /* Don't leak fds to the agent */
                 close_all_fds(NULL, 0);
 
-                if (!isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO)) {
+                stdout_is_tty = isatty(STDOUT_FILENO);
+                stderr_is_tty = isatty(STDERR_FILENO);
+
+                if (!stdout_is_tty || !stderr_is_tty) {
                         /* Detach from stdout/stderr. and reopen
                          * /dev/tty for them. This is important to
                          * ensure that when systemctl is started via
@@ -187,15 +191,11 @@ static void spawn_ask_password_agent(void) {
                                 _exit(EXIT_FAILURE);
                         }
 
-                        if (!isatty(STDOUT_FILENO)) {
-                                close(STDOUT_FILENO);
+                        if (!stdout_is_tty)
                                 dup2(fd, STDOUT_FILENO);
-                        }
 
-                        if (!isatty(STDERR_FILENO)) {
-                                close(STDERR_FILENO);
+                        if (!stderr_is_tty)
                                 dup2(fd, STDERR_FILENO);
-                        }
 
                         if (fd > 2)
                                 close(fd);

commit 060ed82ec24d942c5f519e3dae45e9e2bfb227d8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 17:09:29 2011 +0100

    systemctl: don't unnecessarily close stdin/stdout/stderr for tty agent so that locking by tty works

diff --git a/TODO b/TODO
index 747a669..8660f16 100644
--- a/TODO
+++ b/TODO
@@ -11,8 +11,6 @@ Features:
 
 * perhaps add "systemctl reenable" as combination of "systemctl disable" and "systemctl enable"
 
-* tty name lock for password agent is broken, since it will always lock "/dev/tty" since we now reattach the agent process when forking it off systemctl
-
 * need a way to apply mount options of api vfs from systemd unit files instead of fstab
 
 * udisks should not use udisks-part-id, instead use blkid. also not probe /dev/loopxxx
diff --git a/src/systemctl.c b/src/systemctl.c
index c09b31d..94a12dd 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -121,7 +121,7 @@ static bool on_tty(void) {
         /* Note that this is invoked relatively early, before we start
          * the pager. That means the value we return reflects whether
          * we originally were started on a tty, not if we currently
-         * are. But this is intended, since we want color, and so on
+         * are. But this is intended, since we want colour and so on
          * when run in our own pager. */
 
         if (_unlikely_(t < 0))
@@ -174,27 +174,32 @@ static void spawn_ask_password_agent(void) {
                 /* Don't leak fds to the agent */
                 close_all_fds(NULL, 0);
 
-                /* Detach from stdin/stdout/stderr. and reopen
-                 * /dev/tty for them. This is important to ensure that
-                 * when systemctl is started via popen() or a similar
-                 * call that expects to read EOF we actually do
-                 * generate EOF and not delay this indefinitely by
-                 * because we keep an unused copy of stdin around. */
-                if ((fd = open("/dev/tty", O_RDWR)) < 0) {
-                        log_error("Failed to open /dev/tty: %m");
-                        _exit(EXIT_FAILURE);
-                }
+                if (!isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO)) {
+                        /* Detach from stdout/stderr. and reopen
+                         * /dev/tty for them. This is important to
+                         * ensure that when systemctl is started via
+                         * popen() or a similar call that expects to
+                         * read EOF we actually do generate EOF and
+                         * not delay this indefinitely by because we
+                         * keep an unused copy of stdin around. */
+                        if ((fd = open("/dev/tty", O_WRONLY)) < 0) {
+                                log_error("Failed to open /dev/tty: %m");
+                                _exit(EXIT_FAILURE);
+                        }
 
-                close(STDIN_FILENO);
-                close(STDOUT_FILENO);
-                close(STDERR_FILENO);
+                        if (!isatty(STDOUT_FILENO)) {
+                                close(STDOUT_FILENO);
+                                dup2(fd, STDOUT_FILENO);
+                        }
 
-                dup2(fd, STDIN_FILENO);
-                dup2(fd, STDOUT_FILENO);
-                dup2(fd, STDERR_FILENO);
+                        if (!isatty(STDERR_FILENO)) {
+                                close(STDERR_FILENO);
+                                dup2(fd, STDERR_FILENO);
+                        }
 
-                if (fd > 2)
-                        close(fd);
+                        if (fd > 2)
+                                close(fd);
+                }
 
                 execv(args[0], (char **) args);
                 _exit(EXIT_FAILURE);

commit 46a08e381589c50394d71e428c09857dfeaa3761
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 15:46:05 2011 +0100

    readahead: disable readahead in virtual machines

diff --git a/src/readahead-collect.c b/src/readahead-collect.c
index ac46c7b..4ca6d74 100644
--- a/src/readahead-collect.c
+++ b/src/readahead-collect.c
@@ -649,6 +649,11 @@ int main(int argc, char *argv[]) {
                 return 0;
         }
 
+        if (running_in_vm()) {
+                log_info("Disabling readahead collector due to execution in virtual machine.");
+                return 0;
+        }
+
         if (!(shared = shared_get()))
                 return 1;
 
diff --git a/src/readahead-replay.c b/src/readahead-replay.c
index 87f2e59..e9c573a 100644
--- a/src/readahead-replay.c
+++ b/src/readahead-replay.c
@@ -346,6 +346,11 @@ int main(int argc, char*argv[]) {
                 return 0;
         }
 
+        if (running_in_vm()) {
+                log_info("Disabling readahead replay due to execution in virtual machine.");
+                return 0;
+        }
+
         if (!(shared = shared_get()))
                 return 1;
 
diff --git a/src/util.c b/src/util.c
index 7692a2d..09c1314 100644
--- a/src/util.c
+++ b/src/util.c
@@ -3564,6 +3564,82 @@ const char *default_term_for_tty(const char *tty) {
         return "TERM=vt100";
 }
 
+bool running_in_vm(void) {
+
+#if defined(__i386__) || defined(__x86_64__)
+
+        /* Both CPUID and DMI are x86 specific interfaces... */
+
+        const char *const dmi_vendors[] = {
+                "/sys/class/dmi/id/sys_vendor",
+                "/sys/class/dmi/id/board_vendor",
+                "/sys/class/dmi/id/bios_vendor"
+        };
+
+        uint32_t eax = 0x40000000;
+        union {
+                uint32_t sig32[3];
+                char text[13];
+        } sig;
+
+        unsigned i;
+
+        for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
+                char *s;
+                bool b;
+
+                if (read_one_line_file(dmi_vendors[i], &s) < 0)
+                        continue;
+
+                b = startswith(s, "QEMU") ||
+                        /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+                        startswith(s, "VMware") ||
+                        startswith(s, "VMW") ||
+                        startswith(s, "Microsoft Corporation") ||
+                        startswith(s, "innotek GmbH") ||
+                        startswith(s, "Xen");
+
+                free(s);
+
+                if (b)
+                        return true;
+        }
+
+        /* http://lwn.net/Articles/301888/ */
+        zero(sig);
+
+
+#if defined (__i386__)
+#define REG_a "eax"
+#define REG_b "ebx"
+#elif defined (__amd64__)
+#define REG_a "rax"
+#define REG_b "rbx"
+#endif
+
+        __asm__ __volatile__ (
+                /* ebx/rbx is being used for PIC! */
+                "  push %%"REG_b"         \n\t"
+                "  cpuid                  \n\t"
+                "  mov %%ebx, %1          \n\t"
+                "  pop %%"REG_b"          \n\t"
+
+                : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
+                : "0" (eax)
+        );
+
+        if (streq(sig.text, "XenVMMXenVMM") ||
+            streq(sig.text, "KVMKVMKVM") ||
+            /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+            streq(sig.text, "VMwareVMware") ||
+            /* http://msdn.microsoft.com/en-us/library/bb969719.aspx */
+            streq(sig.text, "Microsoft Hv"))
+                return true;
+#endif
+
+        return false;
+}
+
 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 c8cae70..3f0f48f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -372,6 +372,8 @@ void filter_environ(const char *prefix);
 
 const char *default_term_for_tty(const char *tty);
 
+bool running_in_vm(void);
+
 #define NULSTR_FOREACH(i, l)                                    \
         for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
 

commit a49728dc8c64fe5a2a0e3327274a01adcf18c330
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 15:11:28 2011 +0100

    tmpfiles: simplify default tmpfiles configuration by using globs

diff --git a/tmpfiles.d/x11.conf b/tmpfiles.d/x11.conf
index 09f7dfe..5072b58 100644
--- a/tmpfiles.d/x11.conf
+++ b/tmpfiles.d/x11.conf
@@ -15,13 +15,4 @@ d /tmp/.font-unix 1777 root root 10d
 d /tmp/.Test-unix 1777 root root 10d
 
 # Unlink the X11 lock files
-r /tmp/.X0-lock
-r /tmp/.X1-lock
-r /tmp/.X2-lock
-r /tmp/.X3-lock
-r /tmp/.X4-lock
-r /tmp/.X5-lock
-r /tmp/.X6-lock
-r /tmp/.X7-lock
-r /tmp/.X8-lock
-r /tmp/.X9-lock
+r /tmp/.X[0-9]-lock

commit 522d4a495af3a615526fccdf038d2d68f41a73c8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 15:08:15 2011 +0100

    systemd: document systemd-tmpfiles

diff --git a/Makefile.am b/Makefile.am
index 56fdfce..dd872f8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -485,6 +485,7 @@ MANPAGES = \
 	man/systemctl.1 \
 	man/systemadm.1 \
 	man/systemd-cgls.1 \
+	man/systemd-tmpfiles.8 \
 	man/systemd-notify.1 \
 	man/sd_notify.3 \
 	man/sd_readahead.3 \
diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml
new file mode 100644
index 0000000..986a442
--- /dev/null
+++ b/man/systemd-tmpfiles.xml
@@ -0,0 +1,150 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU 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-tmpfiles">
+
+        <refentryinfo>
+                <title>systemd-tmpfiles</title>
+                <productname>systemd</productname>
+
+                <authorgroup>
+                        <author>
+                                <contrib>Developer</contrib>
+                                <firstname>Lennart</firstname>
+                                <surname>Poettering</surname>
+                                <email>lennart at poettering.net</email>
+                        </author>
+                </authorgroup>
+        </refentryinfo>
+
+        <refmeta>
+                <refentrytitle>systemd-tmpfiles</refentrytitle>
+                <manvolnum>8</manvolnum>
+        </refmeta>
+
+        <refnamediv>
+                <refname>systemd-tmpfiles</refname>
+                <refpurpose>Creates, deletes and cleans up volatile
+                and temporary files and directories.</refpurpose>
+        </refnamediv>
+
+        <refsynopsisdiv>
+                <cmdsynopsis>
+                        <command>systemd-tmpfiles <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="opt" rep="repeat">CONFIGURATION FILE</arg></command>
+                </cmdsynopsis>
+        </refsynopsisdiv>
+
+        <refsect1>
+                <title>Description</title>
+
+                <para><command>systemd-tmpfiles</command> creates,
+                deletes and cleans up volatile ad temporary files and
+                directories, based on the configuration from
+                <filename>/etc/tmpfiles.d/</filename>. See
+                <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+                for more details on these files.</para>
+
+                <para>If invoked with no arguments applies all
+                directives from all configuration files in
+                <filename>/etc/tmpfiles.d/*.conf</filename>. If one or
+                more absolute file names are passed on the command
+                line only the directives in these files are
+                applied.</para>
+        </refsect1>
+
+        <refsect1>
+                <title>Options</title>
+
+                <para>The following options are understood:</para>
+
+                <variablelist>
+
+                        <varlistentry>
+                                <term><option>--create</option></term>
+                                <listitem><para>If this option is passed all
+                                files and directories marked with f,
+                                F, d, D in the configuration files are
+                                created.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><option>--clean</option></term>
+                                <listitem><para>If this option is
+                                passed all files and directories with
+                                an age parameter configured will be
+                                cleaned up.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><option>--remove</option></term>
+                                <listitem><para>If this option is
+                                passed all files and directories marked
+                                with r, R in the configuration files
+                                are removed.</para></listitem>
+                        </varlistentry>
+                        <varlistentry>
+                                <term><option>--prefix=PATH</option></term>
+                                <listitem><para>Only apply rules that
+                                apply to paths with the specified
+                                prefix.</para></listitem>
+                        </varlistentry>
+
+
+                        <varlistentry>
+                                <term><option>--help</option></term>
+
+                                <listitem><para>Prints a short help
+                                text and exits.</para></listitem>
+                        </varlistentry>
+
+                </variablelist>
+
+                <para>It is possible to combine
+                <option>--create</option>, <option>--clean</option>,
+                and <option>--remove</option> in one invocation. For
+                example, during boot the following command line is
+                executed to ensure that all temporary and volatile
+                directores are removed and created according to the
+                configuration file:</para>
+
+                <programlisting>systemctl-tmpfiles --remove --create</programlisting>
+
+        </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>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>tmpwatch</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+                </para>
+        </refsect1>
+
+</refentry>
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index e211d6d..868b57e 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -42,7 +42,8 @@
 
         <refnamediv>
                 <refname>tmpfiles.d</refname>
-                <refpurpose>Configuration for creation, deletion and cleaning of temporary and volatile files</refpurpose>
+                <refpurpose>Configuration for creation, deletion and
+                cleaning of volatile and temporary files</refpurpose>
         </refnamediv>
 
         <refsynopsisdiv>
@@ -52,13 +53,14 @@
         <refsect1>
                 <title>Description</title>
 
-		<para><command>systemd</command> uses
+		<para><command>systemd-tmpfiles</command> uses the
+		configuration files in
 		<filename>/etc/tmpfiles.d/</filename> to describe the
-		creation, cleaning and removal of volatile files and
-		directories which usually reside in directories such
-		as <filename>/var/run</filename> or
-		<filename>/tmp</filename>.  Each configuration file is
-		named in the style of
+		creation, cleaning and removal of volatile and
+		temporary files and directories which usually reside
+		in directories such as <filename>/var/run</filename>
+		or <filename>/tmp</filename>. Each configuration file
+		is named in the style of
 		<filename>/etc/tmpfiles.d/&lt;program&gt;.conf</filename>.</para>
         </refsect1>
 
@@ -201,7 +203,8 @@ d /var/run/uscreens 0755 root root 10d12h</programlisting>
         <refsect1>
                 <title>See Also</title>
                 <para>
-                        <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+                        <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>
                 </para>
         </refsect1>
 
diff --git a/src/tmpfiles.c b/src/tmpfiles.c
index 36fc916..9b697e4 100644
--- a/src/tmpfiles.c
+++ b/src/tmpfiles.c
@@ -700,13 +700,13 @@ static int scandir_filter(const struct dirent *d) {
 
 static int help(void) {
 
-        printf("%s [OPTIONS...] [CONFIGURATION FILE]\n\n"
-               "Create and clean up temporary files and directories.\n\n"
+        printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
+               "Creates, deletes and cleans up volatile and temporary files and directories.\n\n"
                "  -h --help             Show this help\n"
                "     --create           Create marked files/directories\n"
                "     --clean            Clean up marked directories\n"
                "     --remove           Remove marked files/directories\n"
-               "     --prefix=PATH      Only apply rules that apply to paths\n",
+               "     --prefix=PATH      Only apply rules that apply to paths with the specified prefix\n",
                program_invocation_short_name);
 
         return 0;

commit 74ce487dafff196f657835672aae5ad1eb3a6daf
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 14:04:57 2011 +0100

    tmpfiles: move binary to /bin to make it publicly available

diff --git a/Makefile.am b/Makefile.am
index 5370504..56fdfce 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -95,7 +95,8 @@ rootbin_PROGRAMS = \
 	systemctl \
 	systemd-notify \
 	systemd-ask-password \
-	systemd-tty-ask-password-agent
+	systemd-tty-ask-password-agent \
+	systemd-tmpfiles
 
 bin_PROGRAMS = \
 	systemd-cgls
@@ -121,7 +122,6 @@ rootlibexec_PROGRAMS = \
 	systemd-reply-password \
 	systemd-readahead-collect \
 	systemd-readahead-replay \
-	systemd-tmpfiles \
 	systemd-user-sessions \
 	systemd-fsck \
 	systemd-quotacheck \
diff --git a/units/systemd-tmpfiles-clean.service.in b/units/systemd-tmpfiles-clean.service.in
index 9d05135..002daf6 100644
--- a/units/systemd-tmpfiles-clean.service.in
+++ b/units/systemd-tmpfiles-clean.service.in
@@ -15,5 +15,5 @@ ConditionPathExists=/etc/tmpfiles.d
 
 [Service]
 Type=oneshot
-ExecStart=@rootlibexecdir@/systemd-tmpfiles --clean
+ExecStart=@rootbindir@/systemd-tmpfiles --clean
 IOSchedulingClass=idle
diff --git a/units/systemd-tmpfiles-setup.service.in b/units/systemd-tmpfiles-setup.service.in
index d9274ed..b43f6f5 100644
--- a/units/systemd-tmpfiles-setup.service.in
+++ b/units/systemd-tmpfiles-setup.service.in
@@ -16,4 +16,4 @@ ConditionPathExists=/etc/tmpfiles.d
 [Service]
 Type=oneshot
 RemainAfterExit=yes
-ExecStart=@rootlibexecdir@/systemd-tmpfiles --create --remove
+ExecStart=@rootbindir@/systemd-tmpfiles --create --remove

commit fba6e687234660739e5ea1f2fc9c010db893c253
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Feb 13 14:00:54 2011 +0100

    tmpfiles: take names of tmpfiles configuration files on the command line

diff --git a/TODO b/TODO
index 8aac19b..747a669 100644
--- a/TODO
+++ b/TODO
@@ -126,8 +126,6 @@ Features:
 
 * systemctl condrestart should return 0 if service isn't running
 
-* tmpfiles: allow specification of .conf files on cmdline
-
 * allow runtime changing of log level and target
 
 * automatically determine TERM= based on tty name even for /dev/console
diff --git a/src/tmpfiles.c b/src/tmpfiles.c
index d7ca062..36fc916 100644
--- a/src/tmpfiles.c
+++ b/src/tmpfiles.c
@@ -85,6 +85,8 @@ static bool arg_create = false;
 static bool arg_clean = false;
 static bool arg_remove = false;
 
+static const char *arg_prefix = NULL;
+
 #define MAX_DEPTH 256
 
 static bool needs_glob(int t) {
@@ -538,7 +540,7 @@ static void item_free(Item *i) {
         free(i);
 }
 
-static int parse_line(const char *fname, unsigned line, const char *buffer, const char *prefix) {
+static int parse_line(const char *fname, unsigned line, const char *buffer) {
         Item *i;
         char *mode = NULL, *user = NULL, *group = NULL, *age = NULL;
         int r;
@@ -590,7 +592,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, cons
 
         path_kill_slashes(i->path);
 
-        if (prefix && !path_startswith(i->path, prefix)) {
+        if (arg_prefix && !path_startswith(i->path, arg_prefix)) {
                 r = 0;
                 goto finish;
         }
@@ -698,12 +700,13 @@ static int scandir_filter(const struct dirent *d) {
 
 static int help(void) {
 
-        printf("%s [OPTIONS...]\n\n"
-               "Create and clean up temporary directories.\n\n"
+        printf("%s [OPTIONS...] [CONFIGURATION FILE]\n\n"
+               "Create and clean up temporary files and directories.\n\n"
                "  -h --help             Show this help\n"
                "     --create           Create marked files/directories\n"
                "     --clean            Clean up marked directories\n"
-               "     --remove           Remove marked files/directories\n",
+               "     --remove           Remove marked files/directories\n"
+               "     --prefix=PATH      Only apply rules that apply to paths\n",
                program_invocation_short_name);
 
         return 0;
@@ -714,7 +717,8 @@ static int parse_argv(int argc, char *argv[]) {
         enum {
                 ARG_CREATE,
                 ARG_CLEAN,
-                ARG_REMOVE
+                ARG_REMOVE,
+                ARG_PREFIX
         };
 
         static const struct option options[] = {
@@ -722,6 +726,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "create",    no_argument,       NULL, ARG_CREATE    },
                 { "clean",     no_argument,       NULL, ARG_CLEAN     },
                 { "remove",    no_argument,       NULL, ARG_REMOVE    },
+                { "prefix",    required_argument, NULL, ARG_PREFIX    },
                 { NULL,        0,                 NULL, 0             }
         };
 
@@ -750,6 +755,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_remove = true;
                         break;
 
+                case ARG_PREFIX:
+                        arg_prefix = optarg;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -760,28 +769,66 @@ static int parse_argv(int argc, char *argv[]) {
         }
 
         if (!arg_clean && !arg_create && !arg_remove) {
-                help();
+                log_error("You need to specify at leat one of --clean, --create or --remove.");
                 return -EINVAL;
         }
 
         return 1;
 }
 
+static int read_config_file(const char *fn, bool ignore_enoent) {
+        FILE *f;
+        unsigned v = 0;
+        int r = 0;
+
+        assert(fn);
+
+        if (!(f = fopen(fn, "re"))) {
+
+                if (ignore_enoent && errno == ENOENT)
+                        return 0;
+
+                log_error("Failed to open %s: %m", fn);
+                return -errno;
+        }
+
+        for (;;) {
+                char line[LINE_MAX], *l;
+                int k;
+
+                if (!(fgets(line, sizeof(line), f)))
+                        break;
+
+                v++;
+
+                l = strstrip(line);
+                if (*l == '#' || *l == 0)
+                        continue;
+
+                if ((k = parse_line(fn, v, l)) < 0)
+                        if (r == 0)
+                                r = k;
+        }
+
+        if (ferror(f)) {
+                log_error("Failed to read from file %s: %m", fn);
+                if (r == 0)
+                        r = -EIO;
+        }
+
+        fclose(f);
+
+        return r;
+}
+
 int main(int argc, char *argv[]) {
-        struct dirent **de = NULL;
-        int r, n, j;
-        const char *prefix = NULL;
+        int r;
         Item *i;
         Iterator iterator;
 
         if ((r = parse_argv(argc, argv)) <= 0)
                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 
-        if (optind < argc)
-                prefix = argv[optind];
-        else
-                prefix = "/";
-
         log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
         log_open();
@@ -797,75 +844,51 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        if ((n = scandir("/etc/tmpfiles.d/", &de, scandir_filter, alphasort)) < 0) {
-
-                if (errno == ENOENT)
-                        r = EXIT_SUCCESS;
-                else {
-                        log_error("Failed to enumerate /etc/tmpfiles.d/ files: %m");
-                        r = EXIT_FAILURE;
-                }
-
-                goto finish;
-        }
-
         r = EXIT_SUCCESS;
 
-        for (j = 0; j < n; j++) {
-                int k;
-                char *fn;
-                FILE *f;
-                unsigned v;
+        if (optind < argc) {
+                int j;
 
-                k = asprintf(&fn, "/etc/tmpfiles.d/%s", de[j]->d_name);
-                free(de[j]);
+                for (j = optind; j < argc; j++)
+                        if (read_config_file(argv[j], false) < 0)
+                                r = EXIT_FAILURE;
 
-                if (k < 0) {
-                        log_error("Failed to allocate file name.");
-                        r = EXIT_FAILURE;
-                        continue;
-                }
+        } else {
+                int n, j;
+                struct dirent **de = NULL;
 
-                if (!(f = fopen(fn, "re"))) {
+                if ((n = scandir("/etc/tmpfiles.d/", &de, scandir_filter, alphasort)) < 0) {
 
                         if (errno != ENOENT) {
-                                log_error("Failed to open %s: %m", fn);
+                                log_error("Failed to enumerate /etc/tmpfiles.d/ files: %m");
                                 r = EXIT_FAILURE;
                         }
 
-                        free(fn);
-                        continue;
+                        goto finish;
                 }
 
-                v = 0;
-                for (;;) {
-                        char line[LINE_MAX], *l;
-
-                        if (!(fgets(line, sizeof(line), f)))
-                                break;
+                for (j = 0; j < n; j++) {
+                        int k;
+                        char *fn;
 
-                        v++;
+                        k = asprintf(&fn, "/etc/tmpfiles.d/%s", de[j]->d_name);
+                        free(de[j]);
 
-                        l = strstrip(line);
-                        if (*l == '#' || *l == 0)
+                        if (k < 0) {
+                                log_error("Failed to allocate file name.");
+                                r = EXIT_FAILURE;
                                 continue;
+                        }
 
-                        if (parse_line(fn, v, l, prefix) < 0)
+                        if (read_config_file(fn, true) < 0)
                                 r = EXIT_FAILURE;
-                }
 
-                if (ferror(f)) {
-                        r = EXIT_FAILURE;
-                        log_error("Failed to read from file %s: %m", fn);
+                        free(fn);
                 }
 
-                free(fn);
-
-                fclose(f);
+                free(de);
         }
 
-        free(de);
-
         HASHMAP_FOREACH(i, globs, iterator)
                 if (process_item(i) < 0)
                         r = EXIT_FAILURE;



More information about the systemd-commits mailing list