Michal Schmidt 99043c
From b0b19cfc571423eca0694c0da8ed1fe3b875105a Mon Sep 17 00:00:00 2001
Michal Schmidt 99043c
From: Lennart Poettering <lennart@poettering.net>
Michal Schmidt 99043c
Date: Thu, 31 May 2012 04:11:57 +0200
Michal Schmidt 99043c
Subject: [PATCH] systemctl: introduce "systemctl man" to show man page for
Michal Schmidt 99043c
 unit
Michal Schmidt 99043c
Michal Schmidt 99043c
For now this only reads man: URLs, but later on we might want to support
Michal Schmidt 99043c
info: too. http/https is probably out of focus.
Michal Schmidt 99043c
(cherry picked from commit 256425cc10d74c13602527eb86b4ba0938964565)
Michal Schmidt 99043c
Michal Schmidt 99043c
Conflicts:
Michal Schmidt 99043c
	TODO
Michal Schmidt 99043c
---
Michal Schmidt 99043c
 man/systemctl.xml         |    8 +++++
Michal Schmidt 99043c
 src/systemctl/systemctl.c |   79 +++++++++++++++++++++++++++++++++++++++++++--
Michal Schmidt 99043c
 2 files changed, 84 insertions(+), 3 deletions(-)
Michal Schmidt 99043c
Michal Schmidt 99043c
diff --git a/man/systemctl.xml b/man/systemctl.xml
Michal Schmidt 99043c
index 7ae5add..425bfd5 100644
Michal Schmidt 99043c
--- a/man/systemctl.xml
Michal Schmidt 99043c
+++ b/man/systemctl.xml
Michal Schmidt 99043c
@@ -633,7 +633,15 @@
Michal Schmidt 99043c
                                 looking for formatted human-readable
Michal Schmidt 99043c
                                 output.</para></listitem>
Michal Schmidt 99043c
                         </varlistentry>
Michal Schmidt 99043c
+                        <varlistentry>
Michal Schmidt 99043c
+                                <term><command>man [NAME...|PID...]</command></term>
Michal Schmidt 99043c
 
Michal Schmidt 99043c
+                                <listitem><para>Show manual pages for
Michal Schmidt 99043c
+                                one or more units, if available. If a
Michal Schmidt 99043c
+                                PID is passed the manual pages for the
Michal Schmidt 99043c
+                                unit the process of the PID belongs to
Michal Schmidt 99043c
+                                is shown.</para></listitem>
Michal Schmidt 99043c
+                        </varlistentry>
Michal Schmidt 99043c
                         <varlistentry>
Michal Schmidt 99043c
                                 <term><command>reset-failed [NAME...]</command></term>
Michal Schmidt 99043c
 
Michal Schmidt 99043c
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
Michal Schmidt 99043c
index 7f03a65..377a878 100644
Michal Schmidt 99043c
--- a/src/systemctl/systemctl.c
Michal Schmidt 99043c
+++ b/src/systemctl/systemctl.c
Michal Schmidt 99043c
@@ -2449,6 +2449,73 @@ static void print_status_info(UnitStatusInfo *i) {
Michal Schmidt 99043c
                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
Michal Schmidt 99043c
 }
Michal Schmidt 99043c
 
Michal Schmidt 99043c
+static void man_status_info(UnitStatusInfo *i) {
Michal Schmidt 99043c
+        char **p;
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+        assert(i);
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+        if (!i->documentation) {
Michal Schmidt 99043c
+                log_info("Documentation for %s not known.", i->id);
Michal Schmidt 99043c
+                return;
Michal Schmidt 99043c
+        }
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+        STRV_FOREACH(p, i->documentation) {
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+                if (startswith(*p, "man:")) {
Michal Schmidt 99043c
+                        size_t k;
Michal Schmidt 99043c
+                        char *e = NULL;
Michal Schmidt 99043c
+                        char *page = NULL, *section = NULL;
Michal Schmidt 99043c
+                        const char *args[4] = { "man", NULL, NULL, NULL };
Michal Schmidt 99043c
+                        pid_t pid;
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+                        k = strlen(*p);
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+                        if ((*p)[k-1] == ')')
Michal Schmidt 99043c
+                                e = strrchr(*p, '(');
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+                        if (e) {
Michal Schmidt 99043c
+                                page = strndup((*p) + 4, e - *p - 4);
Michal Schmidt 99043c
+                                if (!page) {
Michal Schmidt 99043c
+                                        log_error("Out of memory.");
Michal Schmidt 99043c
+                                        return;
Michal Schmidt 99043c
+                                }
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+                                section = strndup(e + 1, *p + k - e - 2);
Michal Schmidt 99043c
+                                if (!section) {
Michal Schmidt 99043c
+                                        free(page);
Michal Schmidt 99043c
+                                        log_error("Out of memory");
Michal Schmidt 99043c
+                                        return;
Michal Schmidt 99043c
+                                }
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+                                args[1] = section;
Michal Schmidt 99043c
+                                args[2] = page;
Michal Schmidt 99043c
+                        } else
Michal Schmidt 99043c
+                                args[1] = *p + 4;
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+                        pid = fork();
Michal Schmidt 99043c
+                        if (pid < 0) {
Michal Schmidt 99043c
+                                log_error("Failed to fork: %m");
Michal Schmidt 99043c
+                                free(page);
Michal Schmidt 99043c
+                                free(section);
Michal Schmidt 99043c
+                                continue;
Michal Schmidt 99043c
+                        }
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+                        if (pid == 0) {
Michal Schmidt 99043c
+                                /* Child */
Michal Schmidt 99043c
+                                execvp(args[0], (char**) args);
Michal Schmidt 99043c
+                                log_error("Failed to execute man: %m");
Michal Schmidt 99043c
+                                _exit(EXIT_FAILURE);
Michal Schmidt 99043c
+                        }
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+                        free(page);
Michal Schmidt 99043c
+                        free(section);
Michal Schmidt 99043c
+
Michal Schmidt 99043c
+                        wait_for_terminate(pid, NULL);
Michal Schmidt 99043c
+                } else
Michal Schmidt 99043c
+                        log_info("Can't show %s.", *p);
Michal Schmidt 99043c
+        }
Michal Schmidt 99043c
+}
Michal Schmidt 99043c
+
Michal Schmidt 99043c
 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
Michal Schmidt 99043c
 
Michal Schmidt 99043c
         assert(name);
Michal Schmidt 99043c
@@ -2947,8 +3014,12 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo
Michal Schmidt 99043c
 
Michal Schmidt 99043c
         r = 0;
Michal Schmidt 99043c
 
Michal Schmidt 99043c
-        if (!show_properties)
Michal Schmidt 99043c
-                print_status_info(&info;;
Michal Schmidt 99043c
+        if (!show_properties) {
Michal Schmidt 99043c
+                if (streq(verb, "man"))
Michal Schmidt 99043c
+                        man_status_info(&info;;
Michal Schmidt 99043c
+                else
Michal Schmidt 99043c
+                        print_status_info(&info;;
Michal Schmidt 99043c
+        }
Michal Schmidt 99043c
 
Michal Schmidt 99043c
         strv_free(info.documentation);
Michal Schmidt 99043c
 
Michal Schmidt 99043c
@@ -3039,7 +3110,7 @@ static int show(DBusConnection *bus, char **args) {
Michal Schmidt 99043c
         assert(bus);
Michal Schmidt 99043c
         assert(args);
Michal Schmidt 99043c
 
Michal Schmidt 99043c
-        show_properties = !streq(args[0], "status");
Michal Schmidt 99043c
+        show_properties = streq(args[0], "show");
Michal Schmidt 99043c
 
Michal Schmidt 99043c
         if (show_properties)
Michal Schmidt 99043c
                 pager_open_if_enabled();
Michal Schmidt 99043c
@@ -4209,6 +4280,7 @@ static int systemctl_help(void) {
Michal Schmidt 99043c
                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
Michal Schmidt 99043c
                "  show [NAME...|JOB...]           Show properties of one or more\n"
Michal Schmidt 99043c
                "                                  units/jobs or the manager\n"
Michal Schmidt 99043c
+               "  man [NAME...|PID...]            Show manual for one or more units\n"
Michal Schmidt 99043c
                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
Michal Schmidt 99043c
                "                                  units\n"
Michal Schmidt 99043c
                "  load [NAME...]                  Load one or more units\n\n"
Michal Schmidt 99043c
@@ -5172,6 +5244,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
Michal Schmidt 99043c
                 { "check",                 MORE,  2, check_unit        },
Michal Schmidt 99043c
                 { "show",                  MORE,  1, show              },
Michal Schmidt 99043c
                 { "status",                MORE,  2, show              },
Michal Schmidt 99043c
+                { "man",                   MORE,  2, show              },
Michal Schmidt 99043c
                 { "dump",                  EQUAL, 1, dump              },
Michal Schmidt 99043c
                 { "dot",                   EQUAL, 1, dot               },
Michal Schmidt 99043c
                 { "snapshot",              LESS,  2, snapshot          },