[systemd-commits] 4 commits - fixme man/systemctl.xml man/systemd-install.xml man/systemd.xml src/install.c src/mount-setup.c src/systemctl.c

Lennart Poettering lennart at kemper.freedesktop.org
Thu Jul 15 17:57:10 PDT 2010


 fixme                   |   32 +++++
 man/systemctl.xml       |   44 +++++++
 man/systemd-install.xml |   12 +-
 man/systemd.xml         |    2 
 src/install.c           |   21 ++-
 src/mount-setup.c       |   14 ++
 src/systemctl.c         |  273 ++++++++++++++++++++++++++++++++++++++++++++++--
 7 files changed, 385 insertions(+), 13 deletions(-)

New commits:
commit 949c6510326c8d62bfae9866ebfda9506d0eb755
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Jul 16 02:56:57 2010 +0200

    mount-setup: consider a few file systems API mounts and ignore them

diff --git a/src/mount-setup.c b/src/mount-setup.c
index 33e6f4f..6b0539b 100644
--- a/src/mount-setup.c
+++ b/src/mount-setup.c
@@ -51,6 +51,16 @@ static const MountPoint mount_table[] = {
         { "cgroup",   "/cgroup/systemd", "cgroup",   "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
 };
 
+/* These are API file systems that might be mounted by other software,
+ * we just list them here so that we know that we should igore them */
+
+static const char * const ignore_paths[] = {
+        "/selinux",
+        "/proc/bus/usb",
+        "/var/lib/nfs/rpc_pipefs",
+        "/proc/fs/nfsd"
+};
+
 bool mount_point_is_api(const char *path) {
         unsigned i;
 
@@ -61,6 +71,10 @@ bool mount_point_is_api(const char *path) {
                 if (path_startswith(path, mount_table[i].where))
                         return true;
 
+        for (i = 0; i < ELEMENTSOF(ignore_paths); i++)
+                if (path_startswith(path, ignore_paths[i]))
+                        return true;
+
         return path_startswith(path, "/cgroup/");
 }
 
commit 992f87e192673d74cbdc4a50c27b8169401c6720
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Jul 16 02:56:40 2010 +0200

    install: refuse installation of symlinked units

diff --git a/src/install.c b/src/install.c
index 6fc2a9f..bd23a93 100644
--- a/src/install.c
+++ b/src/install.c
@@ -24,6 +24,7 @@
 #include <getopt.h>
 #include <errno.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "log.h"
 #include "path-lookup.h"
@@ -722,22 +723,32 @@ static int install_info_apply(LookupPaths *paths, InstallInfo *i, const char *co
         assert(i);
 
         STRV_FOREACH(p, paths->unit_path) {
+                int fd;
 
                 if (!(filename = path_make_absolute(i->name, *p))) {
                         log_error("Out of memory");
                         return -ENOMEM;
                 }
 
-                if ((f = fopen(filename, "re")))
-                        break;
+                /* Ensure that we don't follow symlinks */
+                if ((fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NOCTTY)) >= 0)
+                        if ((f = fdopen(fd, "re")))
+                                break;
 
-                free(filename);
-                filename = NULL;
+                if (errno == ELOOP) {
+                        log_error("Refusing to operate on symlinks, please pass unit names or absolute paths to unit files.");
+                        free(filename);
+                        return -errno;
+                }
 
                 if (errno != ENOENT) {
                         log_error("Failed to open %s: %m", filename);
+                        free(filename);
                         return -errno;
                 }
+
+                free(filename);
+                filename = NULL;
         }
 
         if (!f) {
@@ -810,7 +821,7 @@ static int do_realize(bool enabled) {
         }
 
         if (arg_where == WHERE_SYSTEM && sd_booted() <= 0) {
-                log_info("systemd is not running, --realize has not effect.");
+                log_info("systemd is not running, --realize has no effect.");
                 return 0;
         }
 
commit 7461d1b76f53ed8dc2d6dc2d63d473d4b165e839
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Jul 16 02:56:19 2010 +0200

    man: various man page updates

diff --git a/man/systemd-install.xml b/man/systemd-install.xml
index 1e26310..03ed0c7 100644
--- a/man/systemd-install.xml
+++ b/man/systemd-install.xml
@@ -68,7 +68,8 @@
 
                 <para><command>systemd-install</command> enables or
                 disables systemd units, or checks whether they are
-                enabled.</para>
+                enabled, according to the installation suggestions
+                included in the unit files.</para>
 
                 <para>This command is useful to apply or undo the
                 installation instructions encoded in the <literal>[Install]</literal>
@@ -83,6 +84,15 @@
                 files in the configuration tree, but does not start
                 them. The latter equals starting them, but does not
                 necessarily require them to be enabled.</para>
+
+                <para>Note that while
+                <command>systemd-install</command> is the recommended
+                tool to create or remove symlinks in the systemd
+                configuration directory the administrator can also
+                create links there manually, which is particularly
+                useful to use configurations that deviate from the
+                installation suggestions included in the unit
+                files.</para>
         </refsect1>
 
         <refsect1>
diff --git a/man/systemd.xml b/man/systemd.xml
index d19094c..e74d71b 100644
--- a/man/systemd.xml
+++ b/man/systemd.xml
@@ -280,7 +280,7 @@
                         systemd units, which later may be restored by
                         activating the saved snapshot unit. For more
                         information see
-                        <citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
+                        <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
 
                         <listitem><para>Timer units are useful for
                         triggering activation of other units based on
commit 4445a8755774550cd5f1b41fb6067b07374a4163
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Jul 16 02:56:00 2010 +0200

    systemctl: add to command for virtualizing the dependency tree with graphviz

diff --git a/fixme b/fixme
index dabce25..1796e0a 100644
--- a/fixme
+++ b/fixme
@@ -35,6 +35,38 @@
 
 * systemctl status $PID, systemctl stop $PID!
 
+* systemctl list-units doesn't show units with actvie jobs?
+
+* timeout waiting for mount devices?
+
+* default logic for serial getty, ck logging, ssk readahead
+
+* place /etc/inittab with explaining blurb.
+
+* OnFailure=foo.unit
+
+* default.target must be %ghosted...
+
+* systemd.path muss irgendwie nen sinvolles Defaultdependencies=True kriegen, genaus timer usw.
+
+* In command lines, support both "$FOO" and $FOO
+
+* systemd-install disable should recursively kill all symlinks
+
+* __nss_disable_nscd() aufrufen um loops zu verhindern
+
+* in %post create all symlinks manually and use inittab data
+
+* check mtimes of dirs and unit files in systemctl
+
+* /etc must always take precedence even if we follow symlinks!
+
+* when adding default deps to targets, check if they are already there and skip
+
+* /lib/init/rw
+
+* vielleicht implizit immer auf syslog dependen?
+
 External:
 
 * patch /etc/init.d/functions with:
diff --git a/man/systemctl.xml b/man/systemctl.xml
index d73e974..42682b7 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -128,6 +128,32 @@
                         </varlistentry>
 
                         <varlistentry>
+                                <term><option>--order</option></term>
+                                <term><option>--require</option></term>
+
+                                <listitem><para>When used in
+                                conjunction with the
+                                <command>dot</command> command (see
+                                below), selects which dependencies are
+                                shown in the dependency graph. If
+                                <option>--order</option> is passed
+                                only dependencies of type
+                                <varname>After=</varname> or
+                                <varname>Before=</varname> are
+                                shown. If <option>--require</option>
+                                is passed only dependencies of type
+                                <varname>Requires=</varname>,
+                                <varname>RequiresOverridable=</varname>,
+                                <varname>Requisite=</varname>,
+                                <varname>RequisiteOverridable=</varname>,
+                                <varname>Wants=</varname> and
+                                <varname>Conflicts=</varname> are
+                                shown. If neither is passed, shows
+                                dependencies of all these
+                                types.</para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
                                 <term><option>--system</option></term>
 
                                 <listitem><para>Talk to the systemd
@@ -356,6 +382,24 @@
                                 applications.</para></listitem>
                         </varlistentry>
                         <varlistentry>
+                                <term><command>dot</command></term>
+
+                                <listitem><para>Generate textual
+                                dependency graph description in dot
+                                format for further processing with the
+                                GraphViz
+                                <citerefentry><refentrytitle>dot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+                                tool. Use a command line like
+                                <command>systemctl dot | dot -Tsvg >
+                                systemd.svg</command> to generate a
+                                graphical dependency tree. Unless
+                                <option>--order</option> or
+                                <option>--require</option> is passed
+                                the generated graph will show both
+                                ordering and requirement
+                                dependencies.</para></listitem>
+                        </varlistentry>
+                        <varlistentry>
                                 <term><command>snapshot [NAME]</command></term>
 
                                 <listitem><para>Create a snapshot. If
diff --git a/src/systemctl.c b/src/systemctl.c
index bdb294e..6388d23 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -59,7 +59,7 @@ static bool arg_no_wall = false;
 static bool arg_dry = false;
 static bool arg_quiet = false;
 static char **arg_wall = NULL;
-enum action {
+static enum action {
         ACTION_INVALID,
         ACTION_SYSTEMCTL,
         ACTION_HALT,
@@ -77,6 +77,11 @@ enum action {
         ACTION_RUNLEVEL,
         _ACTION_MAX
 } arg_action = ACTION_SYSTEMCTL;
+static enum dot {
+        DOT_ALL,
+        DOT_ORDER,
+        DOT_REQUIRE
+} arg_dot = DOT_ALL;
 
 static bool private_bus = false;
 
@@ -186,7 +191,7 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) {
         printf("%-45s %-6s %-12s %-12s %-15s %s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB", "DESCRIPTION");
 
         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                const char *id, *description, *load_state, *active_state, *sub_state, *unit_state, *job_type, *job_path, *dot;
+                const char *id, *description, *load_state, *active_state, *sub_state, *unit_path, *job_type, *job_path, *dot;
                 uint32_t job_id;
 
                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
@@ -202,7 +207,7 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) {
                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_state, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0 ||
                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &job_id, true) < 0 ||
                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &job_type, true) < 0 ||
                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, false) < 0) {
@@ -247,7 +252,247 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) {
         if (arg_all)
                 printf("\n%u units listed.\n", k);
         else
-                printf("\n%u live units listed. Pass --all to see dead units, too.\n", k);
+                printf("\n%u units listed. Pass --all to see inactive units, too.\n", k);
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
+static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
+        static const char * const colors[] = {
+                "Requires",              "[color=\"black\"]",
+                "RequiresOverridable",   "[color=\"black\"]",
+                "Requisite",             "[color=\"darkblue\"]",
+                "RequisiteOverridable",  "[color=\"darkblue\"]",
+                "Wants",                 "[color=\"darkgrey\"]",
+                "Conflicts",             "[color=\"red\"]",
+                "After",                 "[color=\"green\"]"
+        };
+
+        const char *c = NULL;
+        unsigned i;
+
+        assert(name);
+        assert(prop);
+        assert(iter);
+
+        for (i = 0; i < ELEMENTSOF(colors); i += 2)
+                if (streq(colors[i], prop)) {
+                        c = colors[i+1];
+                        break;
+                }
+
+        if (!c)
+                return 0;
+
+        if (arg_dot != DOT_ALL)
+                if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
+                        return 0;
+
+        switch (dbus_message_iter_get_arg_type(iter)) {
+
+        case DBUS_TYPE_ARRAY:
+
+                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
+                        DBusMessageIter sub;
+
+                        dbus_message_iter_recurse(iter, &sub);
+
+                        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                                const char *s;
+
+                                assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
+                                dbus_message_iter_get_basic(&sub, &s);
+                                printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
+
+                                dbus_message_iter_next(&sub);
+                        }
+
+                        return 0;
+                }
+        }
+
+        return 0;
+}
+
+static int dot_one(DBusConnection *bus, const char *name, const char *path) {
+        DBusMessage *m = NULL, *reply = NULL;
+        const char *interface = "org.freedesktop.systemd1.Unit";
+        int r;
+        DBusError error;
+        DBusMessageIter iter, sub, sub2, sub3;
+
+        assert(bus);
+        assert(path);
+
+        dbus_error_init(&error);
+
+        if (!(m = dbus_message_new_method_call(
+                              "org.freedesktop.systemd1",
+                              path,
+                              "org.freedesktop.DBus.Properties",
+                              "GetAll"))) {
+                log_error("Could not allocate message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_STRING, &interface,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not append arguments to message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+                log_error("Failed to issue method call: %s", error.message);
+                r = -EIO;
+                goto finish;
+        }
+
+        if (!dbus_message_iter_init(reply, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
+                log_error("Failed to parse reply.");
+                r = -EIO;
+                goto finish;
+        }
+
+        dbus_message_iter_recurse(&iter, &sub);
+
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                const char *prop;
+
+                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_recurse(&sub, &sub2);
+
+                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_recurse(&sub2, &sub3);
+
+                if (dot_one_property(name, prop, &sub3)) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_next(&sub);
+        }
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        return r;
+}
+
+static int dot(DBusConnection *bus, char **args, unsigned n) {
+        DBusMessage *m = NULL, *reply = NULL;
+        DBusError error;
+        int r;
+        DBusMessageIter iter, sub, sub2;
+
+        dbus_error_init(&error);
+
+        assert(bus);
+
+        if (!(m = dbus_message_new_method_call(
+                              "org.freedesktop.systemd1",
+                              "/org/freedesktop/systemd1",
+                              "org.freedesktop.systemd1.Manager",
+                              "ListUnits"))) {
+                log_error("Could not allocate message.");
+                return -ENOMEM;
+        }
+
+        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+                log_error("Failed to issue method call: %s", error.message);
+                r = -EIO;
+                goto finish;
+        }
+
+        if (!dbus_message_iter_init(reply, &iter) ||
+            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
+                log_error("Failed to parse reply.");
+                r = -EIO;
+                goto finish;
+        }
+
+        printf("digraph systemd {\n");
+
+        dbus_message_iter_recurse(&iter, &sub);
+        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+                const char *id, *description, *load_state, *active_state, *sub_state, *unit_path;
+
+                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                dbus_message_iter_recurse(&sub, &sub2);
+
+                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
+                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
+                        log_error("Failed to parse reply.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                if ((r = dot_one(bus, id, unit_path)) < 0)
+                        goto finish;
+
+                /* printf("\t\"%s\";\n", id); */
+                dbus_message_iter_next(&sub);
+        }
+
+        printf("}\n");
+
+        log_info("   Color legend: black     = Requires\n"
+                 "                 dark blue = Requisite\n"
+                 "                 dark grey = Wants\n"
+                 "                 red       = Conflicts\n"
+                 "                 green     = After\n");
+
+        if (isatty(fileno(stdout)))
+                log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
+                           "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
 
         r = 0;
 
@@ -2504,6 +2749,8 @@ static int systemctl_help(void) {
                "                     pending\n"
                "     --system        Connect to system bus\n"
                "     --session       Connect to session bus\n"
+               "     --order         When generating graph for dot, show only order\n"
+               "     --require        When generating graph for dot, show only requirement\n"
                "  -q --quiet         Suppress output\n"
                "     --no-block      Do not wait until operation finished\n"
                "     --no-wall       Don't send wall message before halt/power-off/reboot\n\n"
@@ -2529,6 +2776,7 @@ static int systemctl_help(void) {
                "  clear-jobs                      Cancel all jobs\n"
                "  monitor                         Monitor unit/job changes\n"
                "  dump                            Dump server status\n"
+               "  dot                             Dump dependency graph for dot(1)\n"
                "  snapshot [NAME]                 Create a snapshot\n"
                "  delete [NAME...]                Remove one or more snapshots\n"
                "  daemon-reload                   Reload systemd manager configuration\n"
@@ -2620,7 +2868,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_SESSION,
                 ARG_SYSTEM,
                 ARG_NO_BLOCK,
-                ARG_NO_WALL
+                ARG_NO_WALL,
+                ARG_ORDER,
+                ARG_REQUIRE
         };
 
         static const struct option options[] = {
@@ -2634,6 +2884,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK },
                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL  },
                 { "quiet",     no_argument,       NULL, 'q'          },
+                { "order",     no_argument,       NULL, ARG_ORDER    },
+                { "require",   no_argument,       NULL, ARG_REQUIRE  },
                 { NULL,        0,                 NULL, 0            }
         };
 
@@ -2687,6 +2939,14 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_no_wall = true;
                         break;
 
+                case ARG_ORDER:
+                        arg_dot = DOT_ORDER;
+                        break;
+
+                case ARG_REQUIRE:
+                        arg_dot = DOT_REQUIRE;
+                        break;
+
                 case 'q':
                         arg_quiet = true;
                         break;
@@ -3212,6 +3472,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
                 { "status",            MORE,  2, show            },
                 { "monitor",           EQUAL, 1, monitor         },
                 { "dump",              EQUAL, 1, dump            },
+                { "dot",               EQUAL, 1, dot             },
                 { "snapshot",          LESS,  2, snapshot        },
                 { "delete",            MORE,  2, delete_snapshot },
                 { "daemon-reload",     EQUAL, 1, clear_jobs      },
@@ -3225,7 +3486,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
                 { "reboot",            EQUAL, 1, start_special   },
                 { "default",           EQUAL, 1, start_special   },
                 { "rescue",            EQUAL, 1, start_special   },
-                { "emergency",         EQUAL, 1, start_special   }
+                { "emergency",         EQUAL, 1, start_special   },
         };
 
         int left;


More information about the systemd-commits mailing list