From 78002a678106a9a4e0e9d747f54458ba84322f1a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sun, 20 Jul 2014 18:23:53 -0400 Subject: [PATCH] systemd-verify: check man pages --- src/shared/pager.c | 53 +++++++++++++++++++++++++++++++++++++++ src/shared/pager.h | 2 ++ src/systemctl/systemctl.c | 47 +++------------------------------- src/verify/verify.c | 47 ++++++++++++++++++++++++++++++++-- 4 files changed, 104 insertions(+), 45 deletions(-) diff --git a/src/shared/pager.c b/src/shared/pager.c index 002e3aa37..54790947b 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -150,3 +150,56 @@ void pager_close(void) { bool pager_have(void) { return pager_pid > 0; } + +int show_man_page(const char *desc, bool null_stdio) { + const char *args[4] = { "man", NULL, NULL, NULL }; + char *e = NULL; + pid_t pid; + size_t k; + int r; + siginfo_t status; + + k = strlen(desc); + + if (desc[k-1] == ')') + e = strrchr(desc, '('); + + if (e) { + char *page = NULL, *section = NULL; + + page = strndupa(desc, e - desc); + section = strndupa(e + 1, desc + k - e - 2); + + args[1] = section; + args[2] = page; + } else + args[1] = desc; + + pid = fork(); + if (pid < 0) { + log_error("Failed to fork: %m"); + return -errno; + } + + if (pid == 0) { + /* Child */ + if (null_stdio) { + r = make_null_stdio(); + if (r < 0) { + log_error("Failed to kill stdio: %s", strerror(-r)); + _exit(EXIT_FAILURE); + } + } + + execvp(args[0], (char**) args); + log_error("Failed to execute man: %m"); + _exit(EXIT_FAILURE); + } + + r = wait_for_terminate(pid, &status); + if (r < 0) + return r; + + log_debug("Exit code %i status %i", status.si_code, status.si_status); + return status.si_status; +} diff --git a/src/shared/pager.h b/src/shared/pager.h index 03dca8bc0..67446170d 100644 --- a/src/shared/pager.h +++ b/src/shared/pager.h @@ -28,3 +28,5 @@ int pager_open(bool jump_to_end); void pager_close(void); bool pager_have(void) _pure_; + +int show_man_page(const char *page, bool null_stdio); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 96a0d0578..fc325095a 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3503,50 +3503,11 @@ static void show_unit_help(UnitStatusInfo *i) { return; } - STRV_FOREACH(p, i->documentation) { - - if (startswith(*p, "man:")) { - const char *args[4] = { "man", NULL, NULL, NULL }; - _cleanup_free_ char *page = NULL, *section = NULL; - char *e = NULL; - pid_t pid; - size_t k; - - k = strlen(*p); - - if ((*p)[k-1] == ')') - e = strrchr(*p, '('); - - if (e) { - page = strndup((*p) + 4, e - *p - 4); - section = strndup(e + 1, *p + k - e - 2); - if (!page || !section) { - log_oom(); - return; - } - - args[1] = section; - args[2] = page; - } else - args[1] = *p + 4; - - pid = fork(); - if (pid < 0) { - log_error("Failed to fork: %m"); - continue; - } - - if (pid == 0) { - /* Child */ - execvp(args[0], (char**) args); - log_error("Failed to execute man: %m"); - _exit(EXIT_FAILURE); - } - - wait_for_terminate(pid, NULL); - } else + STRV_FOREACH(p, i->documentation) + if (startswith(*p, "man:")) + show_man_page(*p + 4, false); + else log_info("Can't show: %s", *p); - } } static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *i, const char *contents) { diff --git a/src/verify/verify.c b/src/verify/verify.c index fc513b1b6..cad79ecf4 100644 --- a/src/verify/verify.c +++ b/src/verify/verify.c @@ -27,8 +27,10 @@ #include "log.h" #include "strv.h" #include "build.h" +#include "pager.h" SystemdRunningAs arg_running_as = SYSTEMD_SYSTEM; +bool arg_no_man = false; static int generate_path(char **var, char **filenames) { char **filename; @@ -140,6 +142,37 @@ static int verify_executables(Unit *u) { return r; } +static int verify_documentation(Unit *u) { + char **p; + int r = 0, k; + + if (arg_no_man) + return 0; + + STRV_FOREACH(p, u->documentation) { + log_debug_unit(u->id, "%s: found documentation item %s.", u->id, *p); + if (startswith(*p, "man:")) { + k = show_man_page(*p + 4, true); + if (k != 0) { + if (k < 0) + log_error_unit(u->id, "%s: can't show %s: %s", + u->id, *p, strerror(-r)); + else { + log_error_unit(u->id, "%s: man %s command failed with code %d", + u->id, *p + 4, k); + k = -ENOEXEC; + } + if (r == 0) + r = k; + } + } + } + + /* Check remote URLs? */ + + return r; +} + static int test_unit(Unit *u) { _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL; Job *j; @@ -167,6 +200,10 @@ static int test_unit(Unit *u) { if (k < 0 && r == 0) r = k; + k = verify_documentation(u); + if (k < 0 && r == 0) + r = k; + return r; } @@ -242,8 +279,9 @@ static void help(void) { " -h --help Show this help\n" " --version Show package version\n" " --system Connect to system manager\n" - " --user Connect to user service manager\n", - program_invocation_short_name); + " --user Connect to user service manager\n" + " --no-man Do not check for existence of man pages\n" + , program_invocation_short_name); } static int parse_argv(int argc, char *argv[]) { @@ -251,6 +289,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERSION = 0x100, ARG_USER, ARG_SYSTEM, + ARG_NO_MAN, }; static const struct option options[] = { @@ -288,6 +327,10 @@ static int parse_argv(int argc, char *argv[]) { arg_running_as = SYSTEMD_SYSTEM; break; + case ARG_NO_MAN: + arg_no_man = true; + break; + case '?': log_error("Unknown option %s.", argv[optind-1]); return -EINVAL; -- 2.30.2