X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fsystemctl.c;h=2c8c2cf61d5165036beffe54ec8784a67dc0a2e1;hb=4bc5f808e4c4891451b83abbc85c4830b3788782;hp=8a6277e75c62a941822ba7a8bd7313788371e456;hpb=611efaac7a76904ffc3d03592a8fe57da5f42c02;p=elogind.git diff --git a/src/systemctl.c b/src/systemctl.c index 8a6277e75..2c8c2cf61 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -110,11 +110,20 @@ static enum dot { static bool private_bus = false; +static pid_t pager_pid = 0; + static int daemon_reload(DBusConnection *bus, char **args, unsigned n); +static void pager_open(void); static bool on_tty(void) { static int t = -1; + /* Note that this is invoked relatively early, before we start + * the pager. That means the value we return reflects whether + * we originally were started on a tty, not if we currently + * are. But this is intended, since we want color, and so on + * when run in our own pager. */ + if (_unlikely_(t < 0)) t = isatty(STDOUT_FILENO) > 0; @@ -419,6 +428,8 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) { assert(bus); + pager_open(); + if (!(m = dbus_message_new_method_call( "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -765,6 +776,8 @@ static int list_jobs(DBusConnection *bus, char **args, unsigned n) { assert(bus); + pager_open(); + if (!(m = dbus_message_new_method_call( "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -2475,6 +2488,9 @@ static int show(DBusConnection *bus, char **args, unsigned n) { show_properties = !streq(args[0], "status"); + if (show_properties) + pager_open(); + if (show_properties && n <= 1) { /* If not argument is specified inspect the manager * itself */ @@ -2858,6 +2874,8 @@ static int dump(DBusConnection *bus, char **args, unsigned n) { dbus_error_init(&error); + pager_open(); + if (!(m = dbus_message_new_method_call( "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -3220,6 +3238,8 @@ static int show_enviroment(DBusConnection *bus, char **args, unsigned n) { dbus_error_init(&error); + pager_open(); + if (!(m = dbus_message_new_method_call( "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -5283,10 +5303,12 @@ static int runlevel_main(void) { } static void pager_open(void) { - pid_t pid; int fd[2]; const char *pager; + if (pager_pid > 0) + return; + if (!on_tty() || arg_no_pager) return; @@ -5294,32 +5316,44 @@ static void pager_open(void) { if (!*pager || streq(pager, "cat")) return; + /* Determine and cache number of columns before we spawn the + * pager so that we get the value from the actual tty */ + columns(); + if (pipe(fd) < 0) { log_error("Failed to create pager pipe: %m"); return; } - pid = fork(); - if (pid < 0) { + pager_pid = fork(); + if (pager_pid < 0) { log_error("Failed to fork pager: %m"); close_pipe(fd); return; } - /* The original process turns into the PAGER */ - if (pid != 0) { + /* In the child start the pager */ + if (pager_pid == 0) { dup2(fd[0], STDIN_FILENO); close_pipe(fd); - if (!getenv("LESS")) - setenv("LESS", "FRSX", 0); + setenv("LESS", "FRSX", 0); + + prctl(PR_SET_PDEATHSIG, SIGTERM); if (pager) { execlp(pager, pager, NULL); execl("/bin/sh", "sh", "-c", pager, NULL); } else { - execlp("sensible-pager", "sensible-pager", NULL); + /* Debian's alternatives command for pagers is + * called 'pager'. Note that we do not call + * sensible-pagers here, since that is just a + * shell script that implements a logic that + * is similar to this one anyway, but is + * Debian-specific. */ + execlp("pager", "pager", NULL); + execlp("less", "less", NULL); execlp("more", "more", NULL); } @@ -5328,13 +5362,25 @@ static void pager_open(void) { _exit(EXIT_FAILURE); } - /* Return in the child */ + /* Return in the parent */ if (dup2(fd[1], STDOUT_FILENO) < 0) log_error("Failed to duplicate pager pipe: %m"); close_pipe(fd); } +static void pager_close(void) { + siginfo_t dummy; + + if (pager_pid <= 0) + return; + + /* Inform pager that we are done */ + fclose(stdout); + wait_for_terminate(pager_pid, &dummy); + pager_pid = 0; +} + int main(int argc, char*argv[]) { int r, retval = EXIT_FAILURE; DBusConnection *bus = NULL; @@ -5352,8 +5398,6 @@ 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) { @@ -5417,5 +5461,7 @@ finish: strv_free(arg_property); + pager_close(); + return retval; }