chiark / gitweb /
systemctl: introduce "systemctl man" to show man page for unit
authorLennart Poettering <lennart@poettering.net>
Thu, 31 May 2012 02:11:57 +0000 (04:11 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 31 May 2012 02:11:57 +0000 (04:11 +0200)
For now this only reads man: URLs, but later on we might want to support
info: too. http/https is probably out of focus.

TODO
man/systemctl.xml
src/systemctl/systemctl.c

diff --git a/TODO b/TODO
index 56cf0b8..045cfc4 100644 (file)
--- a/TODO
+++ b/TODO
@@ -32,8 +32,6 @@ Features:
 
 * make use of /sys/power/wake_lock in inhibitors
 
-* introduce "systemctl help" which invokes man for the man pages listed in Documentation=
-
 * drop accountsservice's StandardOutput=syslog and Type=dbus fields
 
 * make sure show-logs checks for utf8 validity, not ascii validity
index 53d6a47..34a3ea8 100644 (file)
                                 looking for formatted human-readable
                                 output.</para></listitem>
                         </varlistentry>
+                        <varlistentry>
+                                <term><command>man [NAME...|PID...]</command></term>
 
+                                <listitem><para>Show manual pages for
+                                one or more units, if available. If a
+                                PID is passed the manual pages for the
+                                unit the process of the PID belongs to
+                                is shown.</para></listitem>
+                        </varlistentry>
                         <varlistentry>
                                 <term><command>reset-failed [NAME...]</command></term>
 
index 58b6035..f65bd2f 100644 (file)
@@ -2458,6 +2458,73 @@ static void print_status_info(UnitStatusInfo *i) {
                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
 }
 
+static void man_status_info(UnitStatusInfo *i) {
+        char **p;
+
+        assert(i);
+
+        if (!i->documentation) {
+                log_info("Documentation for %s not known.", i->id);
+                return;
+        }
+
+        STRV_FOREACH(p, i->documentation) {
+
+                if (startswith(*p, "man:")) {
+                        size_t k;
+                        char *e = NULL;
+                        char *page = NULL, *section = NULL;
+                        const char *args[4] = { "man", NULL, NULL, NULL };
+                        pid_t pid;
+
+                        k = strlen(*p);
+
+                        if ((*p)[k-1] == ')')
+                                e = strrchr(*p, '(');
+
+                        if (e) {
+                                page = strndup((*p) + 4, e - *p - 4);
+                                if (!page) {
+                                        log_error("Out of memory.");
+                                        return;
+                                }
+
+                                section = strndup(e + 1, *p + k - e - 2);
+                                if (!section) {
+                                        free(page);
+                                        log_error("Out of memory");
+                                        return;
+                                }
+
+                                args[1] = section;
+                                args[2] = page;
+                        } else
+                                args[1] = *p + 4;
+
+                        pid = fork();
+                        if (pid < 0) {
+                                log_error("Failed to fork: %m");
+                                free(page);
+                                free(section);
+                                continue;
+                        }
+
+                        if (pid == 0) {
+                                /* Child */
+                                execvp(args[0], (char**) args);
+                                log_error("Failed to execute man: %m");
+                                _exit(EXIT_FAILURE);
+                        }
+
+                        free(page);
+                        free(section);
+
+                        wait_for_terminate(pid, NULL);
+                } else
+                        log_info("Can't show %s.", *p);
+        }
+}
+
 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
 
         assert(name);
@@ -2952,8 +3019,12 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo
 
         r = 0;
 
-        if (!show_properties)
-                print_status_info(&info);
+        if (!show_properties) {
+                if (streq(verb, "man"))
+                        man_status_info(&info);
+                else
+                        print_status_info(&info);
+        }
 
         strv_free(info.documentation);
 
@@ -3044,7 +3115,7 @@ static int show(DBusConnection *bus, char **args) {
         assert(bus);
         assert(args);
 
-        show_properties = !streq(args[0], "status");
+        show_properties = streq(args[0], "show");
 
         if (show_properties)
                 pager_open_if_enabled();
@@ -4213,6 +4284,7 @@ static int systemctl_help(void) {
                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
                "  show [NAME...|JOB...]           Show properties of one or more\n"
                "                                  units/jobs or the manager\n"
+               "  man [NAME...|PID...]            Show manual for one or more units\n"
                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
                "                                  units\n"
                "  load [NAME...]                  Load one or more units\n\n"
@@ -5176,6 +5248,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "check",                 MORE,  2, check_unit        },
                 { "show",                  MORE,  1, show              },
                 { "status",                MORE,  2, show              },
+                { "man",                   MORE,  2, show              },
                 { "dump",                  EQUAL, 1, dump              },
                 { "dot",                   EQUAL, 1, dot               },
                 { "snapshot",              LESS,  2, snapshot          },