[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