[systemd-commits] 8 commits - TODO man/sd_get_seats.xml man/sd_login_monitor_new.xml src/core src/libsystemd-bus src/login src/nss-myhostname src/shared src/systemd src/test

Lennart Poettering lennart at kemper.freedesktop.org
Wed Apr 24 15:06:30 PDT 2013


 TODO                                |   14 -
 man/sd_get_seats.xml                |   27 ++-
 man/sd_login_monitor_new.xml        |   31 ++--
 src/core/dbus-job.c                 |   17 --
 src/core/unit.c                     |   26 +--
 src/core/unit.h                     |    1 
 src/libsystemd-bus/busctl.c         |  266 +++++++++++++++++++++++++++++++++---
 src/login/inhibit.c                 |    8 -
 src/login/libsystemd-login.sym      |    5 
 src/login/loginctl.c                |    2 
 src/login/logind-dbus.c             |    3 
 src/login/logind.c                  |    2 
 src/login/sd-login.c                |   58 +++++++
 src/login/test-login.c              |   12 +
 src/nss-myhostname/nss-myhostname.c |  180 +++++++++++++++++-------
 src/shared/cgroup-util.c            |   77 +++++++---
 src/shared/cgroup-util.h            |    2 
 src/shared/fileio.c                 |   46 ++++--
 src/systemd/sd-login.h              |    6 
 src/test/test-cgroup-util.c         |   14 +
 20 files changed, 634 insertions(+), 163 deletions(-)

New commits:
commit 78edb35ab4f4227485cb9ec816b43c37e0d5e62a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Apr 24 19:01:29 2013 -0300

    cgroup: always validate cgroup controller names
    
    Let's better be safe than sorry.

diff --git a/TODO b/TODO
index 88a3b2c..cfd42ce 100644
--- a/TODO
+++ b/TODO
@@ -57,10 +57,6 @@ Features:
 
 * add s.th. like "systemctl set-log-level debug"
 
-* sd-login: allow enumerating machines and add inotify iface
-
-* cgroup-util: verify syntax of cgroup controllers
-
 * cgtop: make cgtop useful in a container
 
 * make sure cg_pid_get_path() works properly for co-mounted controllers
diff --git a/src/core/unit.c b/src/core/unit.c
index 4b9abf3..c0c3ce9 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1938,7 +1938,7 @@ char *unit_dbus_path(Unit *u) {
         return unit_dbus_path_from_name(u->id);
 }
 
-int unit_add_cgroup(Unit *u, CGroupBonding *b) {
+static int unit_add_cgroup(Unit *u, CGroupBonding *b) {
         int r;
 
         assert(u);
@@ -2100,6 +2100,9 @@ static int unit_add_one_default_cgroup(Unit *u, const char *controller) {
 
         assert(u);
 
+        if (controller && !cg_controller_is_valid(controller, true))
+                return -EINVAL;
+
         if (!controller)
                 controller = SYSTEMD_CGROUP_CONTROLLER;
 
@@ -2202,13 +2205,15 @@ int unit_add_cgroup_attribute(
                 controller = c;
         }
 
-        if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER))
+        if (!controller ||
+            streq(controller, SYSTEMD_CGROUP_CONTROLLER) ||
+            streq(controller, "systemd"))
                 return -EINVAL;
 
         if (!filename_is_safe(name))
                 return -EINVAL;
 
-        if (!filename_is_safe(controller))
+        if (!cg_controller_is_valid(controller, false))
                 return -EINVAL;
 
         /* Check if this attribute already exists. Note that we will
@@ -2276,42 +2281,39 @@ int unit_add_cgroup_attribute(
 }
 
 int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
-        char *t;
+        _cleanup_free_ char *t = NULL;
         int r;
 
         assert(u);
         assert(type);
         assert(_found);
 
-        if (!(t = unit_name_change_suffix(u->id, type)))
+        t = unit_name_change_suffix(u->id, type);
+        if (!t)
                 return -ENOMEM;
 
         assert(!unit_has_name(u, t));
 
         r = manager_load_unit(u->manager, t, NULL, NULL, _found);
-        free(t);
-
         assert(r < 0 || *_found != u);
-
         return r;
 }
 
 int unit_get_related_unit(Unit *u, const char *type, Unit **_found) {
+        _cleanup_free_ char *t = NULL;
         Unit *found;
-        char *t;
 
         assert(u);
         assert(type);
         assert(_found);
 
-        if (!(t = unit_name_change_suffix(u->id, type)))
+        t = unit_name_change_suffix(u->id, type);
+        if (!t)
                 return -ENOMEM;
 
         assert(!unit_has_name(u, t));
 
         found = manager_get_unit(u->manager, t);
-        free(t);
-
         if (!found)
                 return -ENOENT;
 
diff --git a/src/core/unit.h b/src/core/unit.h
index 51a8364..6bfe58c 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -450,7 +450,6 @@ int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDep
 
 int unit_add_exec_dependencies(Unit *u, ExecContext *c);
 
-int unit_add_cgroup(Unit *u, CGroupBonding *b);
 int unit_add_cgroup_from_text(Unit *u, const char *name, bool overwrite, CGroupBonding **ret);
 int unit_add_default_cgroups(Unit *u);
 CGroupBonding* unit_get_default_cgroup(Unit *u);
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index 9ec4f40..b79a24a 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -510,6 +510,9 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
 
         assert(fs);
 
+        if (controller && !cg_controller_is_valid(controller, true))
+                return -EINVAL;
+
         if (_unlikely_(!good)) {
                 int r;
 
@@ -546,7 +549,7 @@ int cg_get_path_and_check(const char *controller, const char *path, const char *
 
         assert(fs);
 
-        if (isempty(controller))
+        if (!cg_controller_is_valid(controller, true))
                 return -EINVAL;
 
         /* Normalize the controller syntax */
@@ -741,6 +744,9 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
         assert(path);
         assert(pid >= 0);
 
+        if (controller && !cg_controller_is_valid(controller, true))
+                return -EINVAL;
+
         if (!controller)
                 controller = SYSTEMD_CGROUP_CONTROLLER;
 
@@ -933,7 +939,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
 
         e = strchr(spec, ':');
         if (!e) {
-                if (!filename_is_safe(spec))
+                if (!cg_controller_is_valid(spec, true))
                         return -EINVAL;
 
                 if (controller) {
@@ -953,7 +959,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) {
         t = strndup(spec, e-spec);
         if (!t)
                 return -ENOMEM;
-        if (!filename_is_safe(t)) {
+        if (!cg_controller_is_valid(t, true)) {
                 free(t);
                 return -EINVAL;
         }
@@ -987,18 +993,19 @@ int cg_join_spec(const char *controller, const char *path, char **spec) {
 
         assert(path);
 
+
         if (!controller)
                 controller = "systemd";
-        else if (controller[0] == 0 ||
-                 strchr(controller, ':') ||
-                 strchr(controller, '/'))
-                return -EINVAL;
+        else {
+                if (!cg_controller_is_valid(controller, true))
+                        return -EINVAL;
+
+                controller = normalize_controller(controller);
+        }
 
         if (!path_is_absolute(path))
                 return -EINVAL;
 
-        controller = normalize_controller(controller);
-
         s = strjoin(controller, ":", path, NULL);
         if (!s)
                 return -ENOMEM;
@@ -1008,7 +1015,8 @@ int cg_join_spec(const char *controller, const char *path, char **spec) {
 }
 
 int cg_mangle_path(const char *path, char **result) {
-        char *t, *c, *p;
+        _cleanup_free_ char *c = NULL, *p = NULL;
+        char *t;
         int r;
 
         assert(path);
@@ -1030,11 +1038,7 @@ int cg_mangle_path(const char *path, char **result) {
         if (r < 0)
                 return r;
 
-        r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
-        free(c);
-        free(p);
-
-        return r;
+        return cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
 }
 
 int cg_get_system_path(char **path) {
@@ -1138,14 +1142,20 @@ char **cg_shorten_controllers(char **controllers) {
 
                 p = normalize_controller(*f);
 
-                if (streq(*f, "systemd")) {
+                if (streq(p, "systemd")) {
+                        free(*f);
+                        continue;
+                }
+
+                if (!cg_controller_is_valid(p, true)) {
+                        log_warning("Controller %s is not valid, removing from controllers list.", p);
                         free(*f);
                         continue;
                 }
 
                 r = check_hierarchy(p);
                 if (r < 0) {
-                        log_debug("Controller %s is not available, removing from controllers list.", *f);
+                        log_debug("Controller %s is not available, removing from controllers list.", p);
                         free(*f);
                         continue;
                 }
@@ -1457,7 +1467,7 @@ int cg_controller_from_attr(const char *attr, char **controller) {
         if (!c)
                 return -ENOMEM;
 
-        if (!filename_is_safe(c)) {
+        if (!cg_controller_is_valid(c, false)) {
                 free(c);
                 return -EINVAL;
         }
@@ -1517,3 +1527,34 @@ char *cg_unescape(const char *p) {
 
         return (char*) p;
 }
+
+#define CONTROLLER_VALID                        \
+        "0123456789"                            \
+        "abcdefghijklmnopqrstuvwxyz"            \
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"            \
+        "_"
+
+bool cg_controller_is_valid(const char *p, bool allow_named) {
+        const char *t, *s;
+
+        if (!p)
+                return false;
+
+        if (allow_named) {
+                s = startswith(p, "name=");
+                if (s)
+                        p = s;
+        }
+
+        if (*p == 0 || *p == '_')
+                return false;
+
+        for (t = p; *t; t++)
+                if (!strchr(CONTROLLER_VALID, *t))
+                        return false;
+
+        if (t - p > FILENAME_MAX)
+                return false;
+
+        return true;
+}
diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h
index 2099f93..a2ee72d 100644
--- a/src/shared/cgroup-util.h
+++ b/src/shared/cgroup-util.h
@@ -96,3 +96,5 @@ int cg_controller_from_attr(const char *attr, char **controller);
 
 char *cg_escape(const char *p);
 char *cg_unescape(const char *p);
+
+bool cg_controller_is_valid(const char *p, bool allow_named);
diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c
index 95cede7..6726f8f 100644
--- a/src/test/test-cgroup-util.c
+++ b/src/test/test-cgroup-util.c
@@ -153,6 +153,19 @@ static void test_escape(void) {
         test_escape_one("_foobar", "__foobar");
 }
 
+static void test_controller_is_valid(void) {
+        assert_se(cg_controller_is_valid("foobar", false));
+        assert_se(cg_controller_is_valid("foo_bar", false));
+        assert_se(cg_controller_is_valid("name=foo", true));
+        assert_se(!cg_controller_is_valid("", false));
+        assert_se(!cg_controller_is_valid("name=", true));
+        assert_se(!cg_controller_is_valid("=", false));
+        assert_se(!cg_controller_is_valid("cpu,cpuacct", false));
+        assert_se(!cg_controller_is_valid("_", false));
+        assert_se(!cg_controller_is_valid("_foobar", false));
+        assert_se(!cg_controller_is_valid("tatü", false));
+}
+
 int main(void) {
         test_path_decode_unit();
         test_path_get_unit();
@@ -160,6 +173,7 @@ int main(void) {
         test_get_paths();
         test_proc();
         test_escape();
+        test_controller_is_valid();
 
         return 0;
 }

commit e10375f2c0f5dd0dc8508f3ca165eb8aa63c64fb
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Apr 24 17:54:55 2013 -0300

    login: allow watching virtual machines with sd_get_machine_names()

diff --git a/man/sd_login_monitor_new.xml b/man/sd_login_monitor_new.xml
index b187ad0..26af0ea 100644
--- a/man/sd_login_monitor_new.xml
+++ b/man/sd_login_monitor_new.xml
@@ -50,7 +50,7 @@
                 <refname>sd_login_monitor_get_events</refname>
                 <refname>sd_login_monitor_get_timeout</refname>
                 <refname>sd_login_monitor</refname>
-                <refpurpose>Monitor login sessions, seats and users</refpurpose>
+                <refpurpose>Monitor login sessions, seats, users and virtual machines/containers</refpurpose>
         </refnamediv>
 
         <refsynopsisdiv>
@@ -96,23 +96,26 @@
                 <title>Description</title>
 
                 <para><function>sd_login_monitor_new()</function> may
-                be used to monitor login sessions, users and seats. Via
-                a monitor object a file descriptor can be integrated
-                into an application defined event loop which is woken
-                up each time a user logs in, logs out or a seat is
-                added or removed, or a session, user, or seat changes
-                state otherwise. The first parameter takes a string
-                which can be <literal>seat</literal> (to get
+                be used to monitor login sessions, users, seats and
+                virtual machines/containers. Via a monitor object a
+                file descriptor can be integrated into an application
+                defined event loop which is woken up each time a user
+                logs in, logs out or a seat is added or removed, or a
+                session, user, seat or virtual machine/container
+                changes state otherwise. The first parameter takes a
+                string which can be <literal>seat</literal> (to get
                 only notifications about seats being added, removed or
                 changed), <literal>session</literal> (to get only
                 notifications about sessions being created or removed
-                or changed) or <literal>uid</literal> (to get only
+                or changed), <literal>uid</literal> (to get only
                 notifications when a user changes state in respect to
-                logins). If notifications shall be generated in all
-                these conditions, NULL may be passed. Note that in the
-                future additional categories may be defined. The
-                second parameter returns a monitor object and needs to
-                be freed with the
+                logins) or <literal>machine</literal> (to get only
+                notifications when a virtual machine or container is
+                started or stopped). If notifications shall be
+                generated in all these conditions, NULL may be
+                passed. Note that in the future additional categories
+                may be defined. The second parameter returns a monitor
+                object and needs to be freed with the
                 <function>sd_login_monitor_unref()</function> call
                 after use.</para>
 
diff --git a/src/login/sd-login.c b/src/login/sd-login.c
index 35deb85..bc8cd8a 100644
--- a/src/login/sd-login.c
+++ b/src/login/sd-login.c
@@ -677,6 +677,27 @@ _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
                 good = true;
         }
 
+        if (!category || streq(category, "machine")) {
+                _cleanup_free_ char *md = NULL, *p = NULL;
+                int r;
+
+                r = cg_get_machine_path(&md);
+                if (r < 0)
+                        return r;
+
+                r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, md, NULL, &p);
+                if (r < 0)
+                        return r;
+
+                k = inotify_add_watch(fd, p, IN_MOVED_TO|IN_CREATE|IN_DELETE);
+                if (k < 0) {
+                        close_nointr_nofail(fd);
+                        return -errno;
+                }
+
+                good = true;
+        }
+
         if (!good) {
                 close_nointr(fd);
                 return -EINVAL;
diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h
index 2415039..4855e32 100644
--- a/src/systemd/sd-login.h
+++ b/src/systemd/sd-login.h
@@ -157,7 +157,8 @@ int sd_get_machine_names(char ***machines);
 typedef struct sd_login_monitor sd_login_monitor;
 
 /* Create a new monitor. Category must be NULL, "seat", "session",
- * "uid" to get monitor events for the specific category (or all). */
+ * "uid", "machine" to get monitor events for the specific category
+ * (or all). */
 int sd_login_monitor_new(const char *category, sd_login_monitor** ret);
 
 /* Destroys the passed monitor. Returns NULL. */

commit a20affe2f0fb4c8d488155a0b860549e9389f32a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Apr 24 17:54:17 2013 -0300

    login: add new call sd_get_machine_names() to get a list of current virtual machines and containers

diff --git a/man/sd_get_seats.xml b/man/sd_get_seats.xml
index 4bdb5c3..9bc866d 100644
--- a/man/sd_get_seats.xml
+++ b/man/sd_get_seats.xml
@@ -46,7 +46,8 @@
                 <refname>sd_get_seats</refname>
                 <refname>sd_get_sessions</refname>
                 <refname>sd_get_uids</refname>
-                <refpurpose>Determine available seats, sessions and logged in users</refpurpose>
+                <refname>sd_get_machine_names</refname>
+                <refpurpose>Determine available seats, sessions, logged in users and virtual machines/containers</refpurpose>
         </refnamediv>
 
         <refsynopsisdiv>
@@ -68,6 +69,11 @@
                                 <paramdef>uid_t** <parameter>users</parameter></paramdef>
                         </funcprototype>
 
+                        <funcprototype>
+                                <funcdef>int <function>sd_get_machine_names</function></funcdef>
+                                <paramdef>char*** <parameter>machines</parameter></paramdef>
+                        </funcprototype>
+
                 </funcsynopsis>
         </refsynopsisdiv>
 
@@ -90,6 +96,11 @@
                 <para>Similar, <function>sd_get_uids()</function> may
                 be used to determine all Unix users who currently have login sessions.</para>
 
+                <para>Similar,
+                <function>sd_get_machine_names()</function> may be
+                used to determine all current virtual machines and
+                containers on the system.</para>
+
                 <para>Note that the returned lists are not sorted and in an undefined order.</para>
         </refsect1>
 
@@ -97,18 +108,20 @@
                 <title>Return Value</title>
 
                 <para>On success <function>sd_get_seats()</function>,
-                <function>sd_get_sessions()</function> and
-                <function>sd_get_uids()</function> return the number
-                of entries in the arrays. On failure, these calls
-                return a negative errno-style error code.</para>
+                <function>sd_get_sessions()</function>,
+                <function>sd_get_uids()</function> and
+                <function>sd_get_machine_names()</function> return the
+                number of entries in the arrays. On failure, these
+                calls return a negative errno-style error code.</para>
         </refsect1>
 
         <refsect1>
                 <title>Notes</title>
 
                 <para>The <function>sd_get_seats()</function>,
-                <function>sd_get_sessions()</function> and
-                <function>sd_get_uids()</function> interfaces
+                <function>sd_get_sessions()</function>,
+                <function>sd_get_uids()</function> and
+                <function>sd_get_machine_names()</function> interfaces
                 are available as shared library, which can be compiled
                 and linked to with the
                 <literal>libsystemd-login</literal>
diff --git a/src/login/libsystemd-login.sym b/src/login/libsystemd-login.sym
index f4cd209..925fb91 100644
--- a/src/login/libsystemd-login.sym
+++ b/src/login/libsystemd-login.sym
@@ -70,3 +70,8 @@ global:
         sd_pid_get_user_unit;
         sd_pid_get_machine_name;
 } LIBSYSTEMD_LOGIN_201;
+
+LIBSYSTEMD_LOGIN_203 {
+global:
+        sd_get_machine_names;
+} LIBSYSTEMD_LOGIN_202;
diff --git a/src/login/sd-login.c b/src/login/sd-login.c
index 157b7e0..35deb85 100644
--- a/src/login/sd-login.c
+++ b/src/login/sd-login.c
@@ -591,6 +591,43 @@ _public_ int sd_get_uids(uid_t **users) {
         return r;
 }
 
+int sd_get_machine_names(char ***machines) {
+        _cleanup_closedir_ DIR *d = NULL;
+        _cleanup_strv_free_ char **l = NULL;
+        _cleanup_free_ char *md = NULL;
+        char *n;
+        int c = 0, r;
+
+        r = cg_get_machine_path(&md);
+        if (r < 0)
+                return r;
+
+        r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, md, &d);
+        if (r < 0)
+                return r;
+
+        while ((r = cg_read_subgroup(d, &n)) > 0) {
+
+                r = strv_push(&l, n);
+                if (r < 0) {
+                        free(n);
+                        return -ENOMEM;
+                }
+
+                c++;
+        }
+
+        if (r < 0)
+                return r;
+
+        if (machines) {
+                *machines = l;
+                l = NULL;
+        }
+
+        return c;
+}
+
 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
         return (int) (unsigned long) m - 1;
 }
diff --git a/src/login/test-login.c b/src/login/test-login.c
index e4d0c93..945cb38 100644
--- a/src/login/test-login.c
+++ b/src/login/test-login.c
@@ -35,7 +35,7 @@ int main(int argc, char* argv[]) {
         char *state;
         char *session2;
         char *t;
-        char **seats, **sessions;
+        char **seats, **sessions, **machines;
         uid_t *uids;
         unsigned n;
         struct pollfd pollfd;
@@ -180,9 +180,17 @@ int main(int argc, char* argv[]) {
         printf("n_uids = %i\n", r);
         assert_se(sd_get_uids(NULL) == r);
 
-        r = sd_login_monitor_new("session", &m);
+        r = sd_get_machine_names(&machines);
         assert_se(r >= 0);
+        assert_se(r == (int) strv_length(machines));
+        assert_se(t = strv_join(machines, ", "));
+        strv_free(machines);
+        printf("n_machines = %i\n", r);
+        printf("machines = %s\n", t);
+        free(t);
 
+        r = sd_login_monitor_new("session", &m);
+        assert_se(r >= 0);
 
         for (n = 0; n < 5; n++) {
                 usec_t timeout, nw;
diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h
index 1083742..2415039 100644
--- a/src/systemd/sd-login.h
+++ b/src/systemd/sd-login.h
@@ -150,6 +150,9 @@ int sd_get_sessions(char ***sessions);
  * users. If users is NULL only returns the number of users. */
 int sd_get_uids(uid_t **users);
 
+/* Get all running virtual machines/containers */
+int sd_get_machine_names(char ***machines);
+
 /* Monitor object */
 typedef struct sd_login_monitor sd_login_monitor;
 

commit e8a7a315391a6a07897122725cd707f4e9ce63d7
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Apr 24 17:18:01 2013 -0300

    nss-myhostname: resolve 'localhost' so that /etc/hosts becomes optional
    
    This makes sure nss-myhostname not only resolves the local host name to
    127.0.0.2/::1 but also the host name 'localhost: to 127.0.0.1/::1. This
    makes installation of /etc/passwd optional, as it usually only includes
    a mapping for 'localhost'.
    
    This change also resolves ::1 to the local hostname (as before), but
    also lists 'localhost' as an alias. This means look-ups are now fully
    reversible, even though they are 1:n mappings.
    
    Finally, the module will no longer erroneously claim that local IP
    addresses which aren't on the loopback device were.

diff --git a/TODO b/TODO
index 9a23ab5..88a3b2c 100644
--- a/TODO
+++ b/TODO
@@ -26,6 +26,10 @@ Fedora 19:
 
 Features:
 
+* nss-myhostname: investigate whether there's any point in also
+  resolving localhost6, localhost.localdomain, ip6-localhost or any of
+  the other names often seen in /etc/hosts
+
 * see if we can fix https://bugs.freedesktop.org/show_bug.cgi?id=63672
   without dropping the location cache entirely.
 
@@ -47,14 +51,10 @@ Features:
 
 * timedatctl, localectl: possibly make some commands work without the daemon, for chroot situations...
 
-* logind: consider making suspend inhibitor locks non-session specific, but keep suspend-key inhibitor locks session specific
-
 * logind: add Suspend() bus calls which take timestamps to fix double suspend issues when somebody hits suspend and closes laptop quickly.
 
 * we need dynamic units
 
-* nss-myhostname should also resolve 'localhost' so that /etc/hosts becomes optional.
-
 * add s.th. like "systemctl set-log-level debug"
 
 * sd-login: allow enumerating machines and add inotify iface
diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c
index 8699098..60e256d 100644
--- a/src/nss-myhostname/nss-myhostname.c
+++ b/src/nss-myhostname/nss-myhostname.c
@@ -32,7 +32,6 @@
 
 #include "ifconf.h"
 #include "macro.h"
-#include "util.h"
 
 /* Ensure that glibc's assert is used. We cannot use assert from macro.h, as
  * libnss_myhostname will be linked into arbitrary programs which will, in turn
@@ -101,31 +100,46 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
 
         unsigned lo_ifi;
         char hn[HOST_NAME_MAX+1] = {};
+        const char *canonical = NULL;
         size_t l, idx, ms;
         char *r_name;
         struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL;
         struct address *addresses = NULL, *a;
         unsigned n_addresses = 0, n;
+        uint32_t local_address_ipv4;
 
-        if (gethostname(hn, sizeof(hn)-1) < 0) {
-                *errnop = errno;
-                *h_errnop = NO_RECOVERY;
-                return NSS_STATUS_UNAVAIL;
-        }
+        if (strcasecmp(name, "localhost") == 0) {
+                /* We respond to 'localhost', so that /etc/hosts
+                 * is optional */
 
-        if (strcasecmp(name, hn) != 0) {
-                *errnop = ENOENT;
-                *h_errnop = HOST_NOT_FOUND;
-                return NSS_STATUS_NOTFOUND;
-        }
+                canonical = "localhost";
+                local_address_ipv4 = htonl(INADDR_LOOPBACK);
+        } else {
+                /* We respond to our local host name */
 
-        /* If this fails, n_addresses is 0. Which is fine */
-        ifconf_acquire_addresses(&addresses, &n_addresses);
+                if (gethostname(hn, sizeof(hn)-1) < 0) {
+                        *errnop = errno;
+                        *h_errnop = NO_RECOVERY;
+                        return NSS_STATUS_UNAVAIL;
+                }
+
+                if (strcasecmp(name, hn) != 0) {
+                        *errnop = ENOENT;
+                        *h_errnop = HOST_NOT_FOUND;
+                        return NSS_STATUS_NOTFOUND;
+                }
+
+                /* If this fails, n_addresses is 0. Which is fine */
+                ifconf_acquire_addresses(&addresses, &n_addresses);
+
+                canonical = hn;
+                local_address_ipv4 = LOCALADDRESS_IPV4;
+        }
 
         /* If this call fails we fill in 0 as scope. Which is fine */
-        lo_ifi = if_nametoindex(LOOPBACK_INTERFACE);
+        lo_ifi = n_addresses <= 0 ? if_nametoindex(LOOPBACK_INTERFACE) : 0;
 
-        l = strlen(hn);
+        l = strlen(canonical);
         ms = ALIGN(l+1)+ALIGN(sizeof(struct gaih_addrtuple))*(n_addresses > 0 ? n_addresses : 2);
         if (buflen < ms) {
                 *errnop = ENOMEM;
@@ -136,7 +150,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
 
         /* First, fill in hostname */
         r_name = buffer;
-        memcpy(r_name, hn, l+1);
+        memcpy(r_name, canonical, l+1);
         idx = ALIGN(l+1);
 
         if (n_addresses <= 0) {
@@ -156,7 +170,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
                 r_tuple->next = r_tuple_prev;
                 r_tuple->name = r_name;
                 r_tuple->family = AF_INET;
-                *(uint32_t*) r_tuple->addr = LOCALADDRESS_IPV4;
+                *(uint32_t*) r_tuple->addr = local_address_ipv4;
                 r_tuple->scopeid = (uint32_t) lo_ifi;
 
                 idx += ALIGN(sizeof(struct gaih_addrtuple));
@@ -194,31 +208,34 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
 }
 
 static enum nss_status fill_in_hostent(
-                const char *hn,
+                const char *canonical, const char *additional,
                 int af,
+                struct address *addresses, unsigned n_addresses,
+                uint32_t local_address_ipv4,
                 struct hostent *result,
                 char *buffer, size_t buflen,
                 int *errnop, int *h_errnop,
                 int32_t *ttlp,
                 char **canonp) {
 
-        size_t l, idx, ms;
-        char *r_addr, *r_name, *r_aliases, *r_addr_list;
+        size_t l_canonical, l_additional, idx, ms;
+        char *r_addr, *r_name, *r_aliases, *r_alias = NULL, *r_addr_list;
         size_t alen;
-        struct address *addresses = NULL, *a;
-        unsigned n_addresses = 0, n, c;
+        struct address *a;
+        unsigned n, c;
 
         alen = PROTO_ADDRESS_SIZE(af);
 
-        ifconf_acquire_addresses(&addresses, &n_addresses);
-
         for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++)
                 if (af == a->family)
                         c++;
 
-        l = strlen(hn);
-        ms = ALIGN(l+1)+
+        l_canonical = strlen(canonical);
+        l_additional = additional ? strlen(additional) : 0;
+        ms = ALIGN(l_canonical+1)+
+                (additional ? ALIGN(l_additional+1) : 0) +
                 sizeof(char*)+
+                (additional ? sizeof(char*) : 0) +
                 (c > 0 ? c : 1)*ALIGN(alen)+
                 (c > 0 ? c+1 : 2)*sizeof(char*);
 
@@ -229,15 +246,27 @@ static enum nss_status fill_in_hostent(
                 return NSS_STATUS_TRYAGAIN;
         }
 
-        /* First, fill in hostname */
+        /* First, fill in hostnames */
         r_name = buffer;
-        memcpy(r_name, hn, l+1);
-        idx = ALIGN(l+1);
+        memcpy(r_name, canonical, l_canonical+1);
+        idx = ALIGN(l_canonical+1);
 
-        /* Second, create (empty) aliases array */
+        if (additional) {
+                r_alias = buffer + idx;
+                memcpy(r_alias, additional, l_additional+1);
+                idx += ALIGN(l_additional+1);
+        }
+
+        /* Second, create aliases array */
         r_aliases = buffer + idx;
-        *(char**) r_aliases = NULL;
-        idx += sizeof(char*);
+        if (additional) {
+                ((char**) r_aliases)[0] = r_alias;
+                ((char**) r_aliases)[1] = NULL;
+                idx += 2*sizeof(char*);
+        } else {
+                ((char**) r_aliases)[0] = NULL;
+                idx += sizeof(char*);
+        }
 
         /* Third, add addresses */
         r_addr = buffer + idx;
@@ -256,7 +285,7 @@ static enum nss_status fill_in_hostent(
                 idx += c*ALIGN(alen);
         } else {
                 if (af == AF_INET)
-                        *(uint32_t*) r_addr = LOCALADDRESS_IPV4;
+                        *(uint32_t*) r_addr = local_address_ipv4;
                 else
                         memcpy(r_addr, LOCALADDRESS_IPV6, 16);
 
@@ -316,6 +345,10 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
                 char **canonp) {
 
         char hn[HOST_NAME_MAX+1] = {};
+        struct address *addresses = NULL;
+        unsigned n_addresses = 0;
+        const char *canonical, *additional = NULL;
+        uint32_t local_address_ipv4;
 
         if (af == AF_UNSPEC)
                 af = AF_INET;
@@ -326,19 +359,39 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
                 return NSS_STATUS_UNAVAIL;
         }
 
-        if (gethostname(hn, sizeof(hn)-1) < 0) {
-                *errnop = errno;
-                *h_errnop = NO_RECOVERY;
-                return NSS_STATUS_UNAVAIL;
-        }
+        if (strcasecmp(name, "localhost") == 0) {
+                canonical = "localhost";
+                local_address_ipv4 = htonl(INADDR_LOOPBACK);
+        } else {
+                if (gethostname(hn, sizeof(hn)-1) < 0) {
+                        *errnop = errno;
+                        *h_errnop = NO_RECOVERY;
+                        return NSS_STATUS_UNAVAIL;
+                }
 
-        if (strcasecmp(name, hn) != 0) {
-                *errnop = ENOENT;
-                *h_errnop = HOST_NOT_FOUND;
-                return NSS_STATUS_NOTFOUND;
+                if (strcasecmp(name, hn) != 0) {
+                        *errnop = ENOENT;
+                        *h_errnop = HOST_NOT_FOUND;
+                        return NSS_STATUS_NOTFOUND;
+                }
+
+                ifconf_acquire_addresses(&addresses, &n_addresses);
+
+                canonical = hn;
+                additional = n_addresses <= 0 && af == AF_INET6 ? "localhost" : NULL;
+                local_address_ipv4 = LOCALADDRESS_IPV4;
         }
 
-        return fill_in_hostent(hn, af, host, buffer, buflen, errnop, h_errnop, ttlp, canonp);
+        return fill_in_hostent(
+                        canonical, additional,
+                        af,
+                        addresses, n_addresses,
+                        local_address_ipv4,
+                        host,
+                        buffer, buflen,
+                        errnop, h_errnop,
+                        ttlp,
+                        canonp);
 }
 
 enum nss_status _nss_myhostname_gethostbyname2_r(
@@ -383,9 +436,11 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
                 int32_t *ttlp) {
 
         char hn[HOST_NAME_MAX+1] = {};
-        _cleanup_free_ struct address *addresses = NULL;
+        struct address *addresses = NULL;
         struct address *a;
         unsigned n_addresses = 0, n;
+        uint32_t local_address_ipv4 = LOCALADDRESS_IPV4;
+        const char *canonical = NULL, *additional = NULL;
 
         if (len != PROTO_ADDRESS_SIZE(af)) {
                 *errnop = EINVAL;
@@ -398,10 +453,18 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
                 if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4)
                         goto found;
 
+                if ((*(uint32_t*) addr) == htonl(INADDR_LOOPBACK)) {
+                        canonical = "localhost";
+                        local_address_ipv4 = htonl(INADDR_LOOPBACK);
+                        goto found;
+                }
+
         } else if (af == AF_INET6) {
 
-                if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0)
+                if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0) {
+                        additional = "localhost";
                         goto found;
+                }
 
         } else {
                 *errnop = EAFNOSUPPORT;
@@ -422,17 +485,34 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
         *errnop = ENOENT;
         *h_errnop = HOST_NOT_FOUND;
 
+        free(addresses);
+
         return NSS_STATUS_NOTFOUND;
 
 found:
-        if (gethostname(hn, sizeof(hn)-1) < 0) {
-                *errnop = errno;
-                *h_errnop = NO_RECOVERY;
+        if (!canonical) {
+                if (gethostname(hn, sizeof(hn)-1) < 0) {
+                        *errnop = errno;
+                        *h_errnop = NO_RECOVERY;
 
-                return NSS_STATUS_UNAVAIL;
+                        free(addresses);
+
+                        return NSS_STATUS_UNAVAIL;
+                }
+
+                canonical = hn;
         }
 
-        return fill_in_hostent(hn, af, host, buffer, buflen, errnop, h_errnop, ttlp, NULL);
+        return fill_in_hostent(
+                        canonical, additional,
+                        af,
+                        addresses, n_addresses,
+                        local_address_ipv4,
+                        host,
+                        buffer, buflen,
+                        errnop, h_errnop,
+                        ttlp,
+                        NULL);
 
 }
 

commit 2b77f67e78827cc7e85fb43b05d3e1623b31a1bf
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Apr 24 15:44:28 2013 -0300

    fileio: unify how we chop off whitespace from key and value in parse_env_file_internal()

diff --git a/TODO b/TODO
index aa2c1ce..9a23ab5 100644
--- a/TODO
+++ b/TODO
@@ -29,8 +29,6 @@ Features:
 * see if we can fix https://bugs.freedesktop.org/show_bug.cgi?id=63672
   without dropping the location cache entirely.
 
-* truncate whitespace of var names the same way as values in parse_env_file_internal()
-
 * dbus: when a unit failed to load (i.e. is in UNIT_ERROR state), we
   should be able to safely try another attempt when the bus call LoadUnit() is invoked.
 
diff --git a/src/shared/fileio.c b/src/shared/fileio.c
index 337b9e4..48dd442 100644
--- a/src/shared/fileio.c
+++ b/src/shared/fileio.c
@@ -177,7 +177,7 @@ static int parse_env_file_internal(
                 void *userdata) {
 
         _cleanup_free_ char *contents = NULL, *key = NULL;
-        size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_whitespace = (size_t) -1;
+        size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
         char *p, *value = NULL;
         int r;
 
@@ -212,6 +212,8 @@ static int parse_env_file_internal(
                                 state = COMMENT;
                         else if (!strchr(WHITESPACE, c)) {
                                 state = KEY;
+                                last_key_whitespace = (size_t) -1;
+
                                 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
                                         r = -ENOMEM;
                                         goto fail;
@@ -225,9 +227,15 @@ static int parse_env_file_internal(
                         if (strchr(newline, c)) {
                                 state = PRE_KEY;
                                 n_key = 0;
-                        } else if (c == '=')
+                        } else if (c == '=') {
                                 state = PRE_VALUE;
-                        else {
+                                last_value_whitespace = (size_t) -1;
+                        } else {
+                                if (!strchr(WHITESPACE, c))
+                                        last_key_whitespace = (size_t) -1;
+                                else if (last_key_whitespace == (size_t) -1)
+                                         last_key_whitespace = n_key;
+
                                 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
                                         r = -ENOMEM;
                                         goto fail;
@@ -247,8 +255,8 @@ static int parse_env_file_internal(
                                         value[n_value] = 0;
 
                                 /* strip trailing whitespace from key */
-                                while(n_key && strchr(WHITESPACE, key[--n_key]))
-                                        key[n_key]=0;
+                                if (last_key_whitespace != (size_t) -1)
+                                        key[last_key_whitespace] = 0;
 
                                 r = push(key, value, userdata);
                                 if (r < 0)
@@ -257,6 +265,7 @@ static int parse_env_file_internal(
                                 n_key = 0;
                                 value = NULL;
                                 value_alloc = n_value = 0;
+
                         } else if (c == '\'')
                                 state = SINGLE_QUOTE_VALUE;
                         else if (c == '\"')
@@ -285,13 +294,13 @@ static int parse_env_file_internal(
                                 if (value)
                                         value[n_value] = 0;
 
-                                /* Chomp off trailing whitespace */
-                                if (last_whitespace != (size_t) -1)
-                                        value[last_whitespace] = 0;
+                                /* Chomp off trailing whitespace from value */
+                                if (last_value_whitespace != (size_t) -1)
+                                        value[last_value_whitespace] = 0;
 
                                 /* strip trailing whitespace from key */
-                                while(n_key && strchr(WHITESPACE, key[--n_key]))
-                                        key[n_key]=0;
+                                if (last_key_whitespace != (size_t) -1)
+                                        key[last_key_whitespace] = 0;
 
                                 r = push(key, value, userdata);
                                 if (r < 0)
@@ -300,14 +309,15 @@ static int parse_env_file_internal(
                                 n_key = 0;
                                 value = NULL;
                                 value_alloc = n_value = 0;
+
                         } else if (c == '\\') {
                                 state = VALUE_ESCAPE;
-                                last_whitespace = (size_t) -1;
+                                last_value_whitespace = (size_t) -1;
                         } else {
                                 if (!strchr(WHITESPACE, c))
-                                        last_whitespace = (size_t) -1;
-                                else if (last_whitespace == (size_t) -1)
-                                        last_whitespace = n_value;
+                                        last_value_whitespace = (size_t) -1;
+                                else if (last_value_whitespace == (size_t) -1)
+                                        last_value_whitespace = n_value;
 
                                 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
                                         r = -ENOMEM;
@@ -417,9 +427,13 @@ static int parse_env_file_internal(
                 if (value)
                         value[n_value] = 0;
 
+                if (state == VALUE)
+                        if (last_value_whitespace != (size_t) -1)
+                                value[last_value_whitespace] = 0;
+
                 /* strip trailing whitespace from key */
-                while(n_key && strchr(WHITESPACE, key[--n_key]))
-                        key[n_key]=0;
+                if (last_key_whitespace != (size_t) -1)
+                        key[last_key_whitespace] = 0;
 
                 r = push(key, value, userdata);
                 if (r < 0)

commit 842865365e598a090045894f8990fd384e801ccb
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Apr 24 15:23:01 2013 -0300

    logind: don't busy loop if a job is still running but the delay timeout expires

diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
index 096542b..98ccfa6 100644
--- a/src/core/dbus-job.c
+++ b/src/core/dbus-job.c
@@ -218,7 +218,7 @@ const DBusObjectPathVTable bus_job_vtable = {
 };
 
 static int job_send_message(Job *j, DBusMessage* (*new_message)(Job *j)) {
-        DBusMessage *m = NULL;
+        _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
         int r;
 
         assert(j);
@@ -227,9 +227,9 @@ static int job_send_message(Job *j, DBusMessage* (*new_message)(Job *j)) {
         if (bus_has_subscriber(j->manager) || j->forgot_bus_clients) {
                 m = new_message(j);
                 if (!m)
-                        goto oom;
+                        return -ENOMEM;
+
                 r = bus_broadcast(j->manager, m);
-                dbus_message_unref(m);
                 if (r < 0)
                         return r;
 
@@ -238,18 +238,19 @@ static int job_send_message(Job *j, DBusMessage* (*new_message)(Job *j)) {
                  * to the client(s) which created the job */
                 JobBusClient *cl;
                 assert(j->bus_client_list);
+
                 LIST_FOREACH(client, cl, j->bus_client_list) {
                         assert(cl->bus);
 
                         m = new_message(j);
                         if (!m)
-                                goto oom;
+                                return -ENOMEM;
 
                         if (!dbus_message_set_destination(m, cl->name))
-                                goto oom;
+                                return -ENOMEM;
 
                         if (!dbus_connection_send(cl->bus, m, NULL))
-                                goto oom;
+                                return -ENOMEM;
 
                         dbus_message_unref(m);
                         m = NULL;
@@ -257,10 +258,6 @@ static int job_send_message(Job *j, DBusMessage* (*new_message)(Job *j)) {
         }
 
         return 0;
-oom:
-        if (m)
-                dbus_message_unref(m);
-        return -ENOMEM;
 }
 
 static DBusMessage* new_change_signal_message(Job *j) {
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 05cc1fd..68e499f 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -2400,7 +2400,6 @@ DBusHandlerResult bus_message_filter(
                         log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
 
                 else if (m->action_job && streq(m->action_job, path)) {
-
                         log_info("Operation finished.");
 
                         /* Tell people that they now may take a lock again */
@@ -2441,7 +2440,7 @@ int manager_dispatch_delayed(Manager *manager) {
 
         assert(manager);
 
-        if (!manager->action_unit || manager->action_job)
+        if (manager->action_what == 0 || manager->action_job)
                 return 0;
 
         /* Continue delay? */
diff --git a/src/login/logind.c b/src/login/logind.c
index 3b9da19..536612c 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -1626,7 +1626,7 @@ int manager_run(Manager *m) {
 
                 manager_gc(m, true);
 
-                if (m->action_what != 0) {
+                if (m->action_what != 0 && !m->action_job) {
                         usec_t x, y;
 
                         x = now(CLOCK_MONOTONIC);

commit 391a4f72422ab18c0a6b5f291fa47f8d606b9e14
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Apr 24 12:56:47 2013 -0300

    inhbit: show comm field of inhibiting processes

diff --git a/src/login/inhibit.c b/src/login/inhibit.c
index fe108c6..29e50c1 100644
--- a/src/login/inhibit.c
+++ b/src/login/inhibit.c
@@ -96,6 +96,7 @@ static int print_inhibitors(DBusConnection *bus, DBusError *error) {
         dbus_message_iter_recurse(&iter, &sub);
         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
                 const char *what, *who, *why, *mode;
+                _cleanup_free_ char *comm = NULL, *u = NULL;
                 dbus_uint32_t uid, pid;
 
                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT)
@@ -111,11 +112,14 @@ static int print_inhibitors(DBusConnection *bus, DBusError *error) {
                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0)
                         return -EIO;
 
-                printf("     Who: %s (UID %lu, PID %lu)\n"
+                get_process_comm(pid, &comm);
+                u = uid_to_name(uid);
+
+                printf("     Who: %s (UID %lu/%s, PID %lu/%s)\n"
                        "    What: %s\n"
                        "     Why: %s\n"
                        "    Mode: %s\n\n",
-                       who, (unsigned long) uid, (unsigned long) pid,
+                       who, (unsigned long) uid, strna(u), (unsigned long) pid, strna(comm),
                        what,
                        why,
                        mode);
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 36c65bc..caaea8d 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -1296,7 +1296,7 @@ static int help(void) {
                "  -p --property=NAME     Show only properties by this name\n"
                "  -a --all               Show all properties, including empty ones\n"
                "     --kill-who=WHO      Who to send signal to\n"
-               "  --full                 Do not ellipsize output\n"
+               "     --full              Do not ellipsize output\n"
                "  -s --signal=SIGNAL     Which signal to send\n"
                "     --no-ask-password   Don't prompt for password\n"
                "  -H --host=[USER@]HOST  Show information for remote host\n"

commit 1f8497905d7a60c5bf098039a971deb1b52cef09
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Apr 24 12:56:28 2013 -0300

    bus: add monitoring facility to busctl

diff --git a/src/libsystemd-bus/busctl.c b/src/libsystemd-bus/busctl.c
index 7348894..220c1eb 100644
--- a/src/libsystemd-bus/busctl.c
+++ b/src/libsystemd-bus/busctl.c
@@ -19,33 +19,49 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <getopt.h>
+
 #include "strv.h"
 #include "util.h"
 #include "log.h"
+#include "build.h"
+#include "pager.h"
 
 #include "sd-bus.h"
 #include "bus-message.h"
 #include "bus-internal.h"
 
-int main(int argc, char *argv[]) {
-        _cleanup_bus_unref_ sd_bus *bus = NULL;
+static bool arg_no_pager = false;
+static char *arg_address = NULL;
+static bool arg_user = false;
+static bool arg_no_unique = false;
+static char **arg_matches = NULL;
+
+static void pager_open_if_enabled(void) {
+
+        /* Cache result before we open the pager */
+        if (arg_no_pager)
+                return;
+
+        pager_open(false);
+}
+
+static int list_bus_names(sd_bus *bus, char **argv) {
         _cleanup_strv_free_ char **l = NULL;
         char **i;
         int r;
         size_t max_i = 0;
 
-        r = sd_bus_open_user(&bus);
-        if (r < 0) {
-                log_error("Failed to connect to bus: %s", strerror(-r));
-                goto fail;
-        }
+        assert(bus);
 
         r = sd_bus_list_names(bus, &l);
         if (r < 0) {
                 log_error("Failed to list names: %s", strerror(-r));
-                goto fail;
+                return r;
         }
 
+        pager_open_if_enabled();
+
         strv_sort(l);
 
         STRV_FOREACH(i, l)
@@ -59,8 +75,8 @@ int main(int argc, char *argv[]) {
                 pid_t pid;
                 uid_t uid;
 
-                /* if ((*i)[0] == ':') */
-                /*         continue; */
+                if (arg_no_unique && (*i)[0] == ':')
+                        continue;
 
                 printf("%-*s", (int) max_i, *i);
 
@@ -80,10 +96,8 @@ int main(int argc, char *argv[]) {
                         _cleanup_free_ char *u = NULL;
 
                         u = uid_to_name(uid);
-                        if (!u) {
-                                log_oom();
-                                goto fail;
-                        }
+                        if (!u)
+                                return log_oom();
 
                         if (strlen(u) > 16)
                                 u[16] = 0;
@@ -99,8 +113,228 @@ int main(int argc, char *argv[]) {
                         printf(" -\n");
         }
 
-        r = 0;
+        return 0;
+}
+
+static int monitor(sd_bus *bus, char *argv[]) {
+        char **i;
+        int r;
+
+        STRV_FOREACH(i, argv+1) {
+                _cleanup_free_ char *m = NULL;
+
+                if (!service_name_is_valid(*i)) {
+                        log_error("Invalid service name '%s'", *i);
+                        return -EINVAL;
+                }
+
+                m = strjoin("sender='", *i, "'", NULL);
+                if (!m)
+                        return log_oom();
+
+                r = sd_bus_add_match(bus, m, NULL, NULL);
+                if (r < 0) {
+                        log_error("Failed to add match: %s", strerror(-r));
+                        return r;
+                }
+        }
+
+        STRV_FOREACH(i, arg_matches) {
+                r = sd_bus_add_match(bus, *i, NULL, NULL);
+                if (r < 0) {
+                        log_error("Failed to add match: %s", strerror(-r));
+                        return r;
+                }
+        }
+
+        for (;;) {
+                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+
+                r = sd_bus_process(bus, &m);
+                if (r < 0) {
+                        log_error("Failed to process bus: %s", strerror(-r));
+                        return r;
+                }
+
+                if (m) {
+                        bus_message_dump(m);
+                        continue;
+                }
+
+                if (r > 0)
+                        continue;
+
+                r = sd_bus_wait(bus, (uint64_t) -1);
+                if (r < 0) {
+                        log_error("Failed to wait for bus: %s", strerror(-r));
+                        return r;
+                }
+        }
+
+        return -EINVAL;
+}
+
+static int help(void) {
+
+        printf("%s [OPTIONS...] {COMMAND} ...\n\n"
+               "Introspect the bus.\n\n"
+               "  -h --help              Show this help\n"
+               "     --version           Show package version\n"
+               "     --system            Connect to system bus\n"
+               "     --user              Connect to user bus\n"
+               "     --address=ADDRESS   Connect to bus specified by address\n"
+               "     --no-unique         Only show well-known names\n"
+               "     --match=MATCH       Only show matching messages\n"
+               "     --no-pager          Do not pipe output into a pager\n\n"
+               "Commands:\n"
+               "  list                   List bus names\n"
+               "  monitor [SERVICE...]   Show bus traffic\n",
+               program_invocation_short_name);
+
+        return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+        enum {
+                ARG_VERSION = 0x100,
+                ARG_NO_PAGER,
+                ARG_SYSTEM,
+                ARG_USER,
+                ARG_ADDRESS,
+                ARG_MATCH,
+                ARG_NO_UNIQUE
+        };
+
+        static const struct option options[] = {
+                { "help",      no_argument,       NULL, 'h'           },
+                { "version",   no_argument,       NULL, ARG_VERSION   },
+                { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
+                { "system",    no_argument,       NULL, ARG_SYSTEM    },
+                { "user",      no_argument,       NULL, ARG_USER      },
+                { "address",   required_argument, NULL, ARG_ADDRESS   },
+                { "no-unique", no_argument,       NULL, ARG_NO_UNIQUE },
+                { "match",     required_argument, NULL, ARG_MATCH     },
+                { NULL,        0,                 NULL, 0             },
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+
+                switch (c) {
+
+                case 'h':
+                        return help();
+
+                case ARG_VERSION:
+                        puts(PACKAGE_STRING);
+                        puts(SYSTEMD_FEATURES);
+                        return 0;
+
+                case ARG_NO_PAGER:
+                        arg_no_pager = true;
+                        break;
+
+                case ARG_USER:
+                        arg_user = true;
+                        break;
+
+                case ARG_SYSTEM:
+                        arg_user = false;
+                        break;
+
+                case ARG_ADDRESS:
+                        arg_address = optarg;
+                        break;
+
+                case ARG_NO_UNIQUE:
+                        arg_no_unique = true;
+                        break;
+
+                case ARG_MATCH:
+                        if (strv_extend(&arg_matches, optarg) < 0)
+                                return log_oom();
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        log_error("Unknown option code %c", c);
+                        return -EINVAL;
+                }
+        }
+
+        return 1;
+}
+
+static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
+        assert(bus);
+
+        if (optind >= argc ||
+            streq(argv[optind], "list"))
+                return list_bus_names(bus, argv + optind);
+
+        if (streq(argv[optind], "monitor"))
+                return monitor(bus, argv + optind);
+
+        if (streq(argv[optind], "help"))
+                return help();
+
+        log_error("Unknown command '%s'", argv[optind]);
+        return -EINVAL;
+}
+
+int main(int argc, char *argv[]) {
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
+        int r;
+
+        log_parse_environment();
+        log_open();
+
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                goto finish;
+
+        if (arg_address) {
+                r = sd_bus_new(&bus);
+                if (r < 0) {
+                        log_error("Failed to allocate bus: %s", strerror(-r));
+                        goto finish;
+                }
+
+                r = sd_bus_set_address(bus, arg_address);
+                if (r < 0) {
+                        log_error("Failed to set address: %s", strerror(-r));
+                        goto finish;
+                }
+
+                r = sd_bus_set_bus_client(bus, true);
+                if (r < 0) {
+                        log_error("Failed to set bus client: %s", strerror(-r));
+                        goto finish;
+                }
+
+                r = sd_bus_start(bus);
+        } else if (arg_user)
+                r = sd_bus_open_user(&bus);
+        else
+                r = sd_bus_open_system(&bus);
+
+        if (r < 0) {
+                log_error("Failed to connect to bus: %s", strerror(-r));
+                goto finish;
+        }
+
+        r = busctl_main(bus, argc, argv);
+
+finish:
+        pager_close();
+        strv_free(arg_matches);
 
-fail:
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }



More information about the systemd-commits mailing list