chiark / gitweb /
systemd-verify: check man pages
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 20 Jul 2014 22:23:53 +0000 (18:23 -0400)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 20 Jul 2014 23:48:16 +0000 (19:48 -0400)
src/shared/pager.c
src/shared/pager.h
src/systemctl/systemctl.c
src/verify/verify.c

index 002e3aa37356c7b0f556dd635bcacade31c7d502..54790947ba7d82eb678e73b1d99fd888bbe6094b 100644 (file)
@@ -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;
+}
index 03dca8bc03e8331513c6365d3e9d1358e2745cf3..67446170d0337d7f853d26e6c0c4b30c475be1a3 100644 (file)
@@ -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);
index 96a0d0578ee2459f153dcd9c99a518d409b00e54..fc325095ac833f16a89e95e33faa903f1eb72451 100644 (file)
@@ -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) {
index fc513b1b69b1a531c8904160191654cd0b970075..cad79ecf48f7a89d267943903a8f7e30165da397 100644 (file)
 #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;