summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/shared/pager.c53
-rw-r--r--src/shared/pager.h2
-rw-r--r--src/systemctl/systemctl.c47
-rw-r--r--src/verify/verify.c47
4 files changed, 104 insertions, 45 deletions
diff --git a/src/shared/pager.c b/src/shared/pager.c
index 002e3aa373..54790947ba 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 03dca8bc03..67446170d0 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 96a0d0578e..fc325095ac 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 fc513b1b69..cad79ecf48 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;