From: Lennart Poettering Date: Thu, 31 May 2012 02:11:57 +0000 (+0200) Subject: systemctl: introduce "systemctl man" to show man page for unit X-Git-Tag: v185~38 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=256425cc10d74c13602527eb86b4ba0938964565 systemctl: introduce "systemctl man" to show man page for unit For now this only reads man: URLs, but later on we might want to support info: too. http/https is probably out of focus. --- diff --git a/TODO b/TODO index 56cf0b820..045cfc414 100644 --- 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 diff --git a/man/systemctl.xml b/man/systemctl.xml index 53d6a47c9..34a3ea843 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -632,7 +632,15 @@ looking for formatted human-readable output. + + man [NAME...|PID...] + 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. + reset-failed [NAME...] diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 58b6035c6..f65bd2faa 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -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 },