From 0736af98c6fae9c7d31e3dd17589421b7e883ef5 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Sun, 2 Jan 2011 00:25:57 +0100 Subject: [PATCH] systemctl: implement auto-pager a la git --- TODO | 2 -- man/systemctl.xml | 7 +++++++ src/systemctl.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index e864634ac..69cff589a 100644 --- a/TODO +++ b/TODO @@ -69,8 +69,6 @@ * suspend, resume -* systemctl auto-pager a la git - * readahead: btrfs/LVM SSD detection * when processes remain in a service even though the start command failed enter active diff --git a/man/systemctl.xml b/man/systemctl.xml index 6b05e95de..c21ed8556 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -170,6 +170,13 @@ argument it is only verified and enqueued. + + + + Do not pipe output into a + pager. + + diff --git a/src/systemctl.c b/src/systemctl.c index 4768fb20a..585f1dc5f 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -65,6 +65,7 @@ static bool arg_user = false; static bool arg_global = false; static bool arg_immediate = false; static bool arg_no_block = false; +static bool arg_no_pager = false; static bool arg_no_wtmp = false; static bool arg_no_sync = false; static bool arg_no_wall = false; @@ -4110,6 +4111,7 @@ static int systemctl_help(void) { " pending\n" " -q --quiet Suppress output\n" " --no-block Do not wait until operation finished\n" + " --no-pager Do not pipe output into a pager.\n" " --system Connect to system manager\n" " --user Connect to user service manager\n" " --order When generating graph for dot, show only order\n" @@ -4249,6 +4251,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_SYSTEM, ARG_GLOBAL, ARG_NO_BLOCK, + ARG_NO_PAGER, ARG_NO_WALL, ARG_ORDER, ARG_REQUIRE, @@ -4272,6 +4275,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "system", no_argument, NULL, ARG_SYSTEM }, { "global", no_argument, NULL, ARG_GLOBAL }, { "no-block", no_argument, NULL, ARG_NO_BLOCK }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "no-wall", no_argument, NULL, ARG_NO_WALL }, { "quiet", no_argument, NULL, 'q' }, { "order", no_argument, NULL, ARG_ORDER }, @@ -4348,6 +4352,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_no_block = true; break; + case ARG_NO_PAGER: + arg_no_pager = true; + break; + case ARG_NO_WALL: arg_no_wall = true; break; @@ -5274,6 +5282,48 @@ static int runlevel_main(void) { return 0; } +static void pager_open(void) { + pid_t pid; + int fd[2]; + const char *pager = getenv("PAGER"); + + if (!on_tty() || arg_no_pager) + return; + if (!pager) + pager = "less"; + else if (!*pager || !strcmp(pager, "cat")) + return; + + if (pipe(fd) < 0) + return; + pid = fork(); + if (pid < 0) { + close(fd[0]); + close(fd[1]); + return; + } + + /* Return in the child */ + if (!pid) { + dup2(fd[1], 1); + close(fd[0]); + close(fd[1]); + return; + } + + /* The original process turns into the PAGER */ + dup2(fd[0], 0); + close(fd[0]); + close(fd[1]); + + setenv("LESS", "FRSX", 0); + execlp(pager, pager, NULL); + execl("/bin/sh", "sh", "-c", pager, NULL); + + log_error("unable to execute pager '%s'", pager); + _exit(EXIT_FAILURE); +} + int main(int argc, char*argv[]) { int r, retval = EXIT_FAILURE; DBusConnection *bus = NULL; @@ -5291,6 +5341,8 @@ int main(int argc, char*argv[]) { goto finish; } + pager_open(); + /* /sbin/runlevel doesn't need to communicate via D-Bus, so * let's shortcut this */ if (arg_action == ACTION_RUNLEVEL) { -- 2.30.2