]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/pager.c
NEWS: finalize for v256~rc3
[thirdparty/systemd.git] / src / shared / pager.c
index cd8a840e578d1ebbcdd96dcbf149e7c6926abda6..9b8ae76700537859bc9a97620d2325753aae2a92 100644 (file)
@@ -25,7 +25,6 @@
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
-#include "util.h"
 
 static pid_t pager_pid = 0;
 
@@ -37,7 +36,7 @@ static bool stderr_redirected = false;
 _noreturn_ static void pager_fallback(void) {
         int r;
 
-        r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (uint64_t) -1, 0);
+        r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, UINT64_MAX, 0);
         if (r < 0) {
                 log_error_errno(r, "Internal pager failed: %m");
                 _exit(EXIT_FAILURE);
@@ -83,23 +82,24 @@ static int no_quit_on_interrupt(int exe_name_fd, const char *less_opts) {
         return r;
 }
 
-int pager_open(PagerFlags flags) {
-        _cleanup_close_pair_ int fd[2] = { -1, -1 }, exe_name_pipe[2] = { -1, -1 };
+void pager_open(PagerFlags flags) {
+        _cleanup_close_pair_ int fd[2] = EBADF_PAIR, exe_name_pipe[2] = EBADF_PAIR;
         _cleanup_strv_free_ char **pager_args = NULL;
+        _cleanup_free_ char *l = NULL;
         const char *pager, *less_opts;
         int r;
 
         if (flags & PAGER_DISABLE)
-                return 0;
+                return;
 
         if (pager_pid > 0)
-                return 1;
+                return;
 
         if (terminal_is_dumb())
-                return 0;
+                return;
 
         if (!is_main_thread())
-                return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Pager invoked from wrong thread.");
+                return (void) log_error_errno(SYNTHETIC_ERRNO(EPERM), "Pager invoked from wrong thread.");
 
         pager = getenv("SYSTEMD_PAGER");
         if (!pager)
@@ -108,11 +108,11 @@ int pager_open(PagerFlags flags) {
         if (pager) {
                 pager_args = strv_split(pager, WHITESPACE);
                 if (!pager_args)
-                        return log_oom();
+                        return (void) log_oom();
 
                 /* If the pager is explicitly turned off, honour it */
                 if (strv_isempty(pager_args) || strv_equal(pager_args, STRV_MAKE("cat")))
-                        return 0;
+                        return;
         }
 
         /* Determine and cache number of columns/lines before we spawn the pager so that we get the value from the
@@ -121,25 +121,29 @@ int pager_open(PagerFlags flags) {
         (void) lines();
 
         if (pipe2(fd, O_CLOEXEC) < 0)
-                return log_error_errno(errno, "Failed to create pager pipe: %m");
+                return (void) log_error_errno(errno, "Failed to create pager pipe: %m");
 
         /* This is a pipe to feed the name of the executed pager binary into the parent */
         if (pipe2(exe_name_pipe, O_CLOEXEC) < 0)
-                return log_error_errno(errno, "Failed to create exe_name pipe: %m");
+                return (void) log_error_errno(errno, "Failed to create exe_name pipe: %m");
 
         /* Initialize a good set of less options */
         less_opts = getenv("SYSTEMD_LESS");
         if (!less_opts)
                 less_opts = "FRSXMK";
-        if (flags & PAGER_JUMP_TO_END)
-                less_opts = strjoina(less_opts, " +G");
+        if (flags & PAGER_JUMP_TO_END) {
+                l = strjoin(less_opts, " +G");
+                if (!l)
+                        return (void) log_oom();
+                less_opts = l;
+        }
 
         /* We set SIGINT as PR_DEATHSIG signal here, to match the "K" parameter we set in $LESS, which enables SIGINT behaviour. */
         r = safe_fork("(pager)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGINT|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pager_pid);
         if (r < 0)
-                return r;
+                return;
         if (r == 0) {
-                const char *less_charset, *exe;
+                const char *less_charset;
 
                 /* In the child start the pager */
 
@@ -171,7 +175,7 @@ int pager_open(PagerFlags flags) {
                  * pager. If they didn't, use secure mode when under euid is changed. If $SYSTEMD_PAGERSECURE
                  * wasn't explicitly set, and we autodetect the need for secure mode, only use the pager we
                  * know to be good. */
-                int use_secure_mode = getenv_bool_secure("SYSTEMD_PAGERSECURE");
+                int use_secure_mode = secure_getenv_bool("SYSTEMD_PAGERSECURE");
                 bool trust_pager = use_secure_mode >= 0;
                 if (use_secure_mode == -ENXIO) {
                         uid_t uid;
@@ -189,12 +193,9 @@ int pager_open(PagerFlags flags) {
 
                 /* We generally always set variables used by less, even if we end up using a different pager.
                  * They shouldn't hurt in any case, and ideally other pagers would look at them too. */
-                if (use_secure_mode)
-                        r = setenv("LESSSECURE", "1", 1);
-                else
-                        r = unsetenv("LESSSECURE");
+                r = set_unset_env("LESSSECURE", use_secure_mode ? "1" : NULL, true);
                 if (r < 0) {
-                        log_error_errno(errno, "Failed to adjust environment variable LESSSECURE: %m");
+                        log_error_errno(r, "Failed to adjust environment variable LESSSECURE: %m");
                         _exit(EXIT_FAILURE);
                 }
 
@@ -203,7 +204,7 @@ int pager_open(PagerFlags flags) {
                                                   * secure mode. Thus, start the pager specified through
                                                   * envvars only when $SYSTEMD_PAGERSECURE was explicitly set
                                                   * as well. */
-                        r = loop_write(exe_name_pipe[1], pager_args[0], strlen(pager_args[0]) + 1, false);
+                        r = loop_write(exe_name_pipe[1], pager_args[0], strlen(pager_args[0]) + 1);
                         if (r < 0) {
                                 log_error_errno(r, "Failed to write pager name to socket: %m");
                                 _exit(EXIT_FAILURE);
@@ -217,57 +218,52 @@ int pager_open(PagerFlags flags) {
                 /* 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. */
-                FOREACH_STRING(exe, "pager", "less", "more") {
-                        /* Only less implements secure mode right now. */
-                        if (use_secure_mode && !streq(exe, "less"))
+                static const char* pagers[] = { "pager", "less", "more", "(built-in)" };
+
+                for (unsigned i = 0; i < ELEMENTSOF(pagers); i++) {
+                        /* Only less (and our trivial fallback) implement secure mode right now. */
+                        if (use_secure_mode && !STR_IN_SET(pagers[i], "less", "(built-in)"))
                                 continue;
 
-                        r = loop_write(exe_name_pipe[1], exe, strlen(exe) + 1, false);
-                        if (r  < 0) {
+                        r = loop_write(exe_name_pipe[1], pagers[i], strlen(pagers[i]) + 1);
+                        if (r < 0) {
                                 log_error_errno(r, "Failed to write pager name to socket: %m");
                                 _exit(EXIT_FAILURE);
                         }
-                        execlp(exe, exe, NULL);
-                        log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
-                                       "Failed to execute '%s', using next fallback pager: %m", exe);
-                }
 
-                /* Our builtin is also very secure. */
-                r = loop_write(exe_name_pipe[1], "(built-in)", strlen("(built-in)") + 1, false);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to write pager name to socket: %m");
-                        _exit(EXIT_FAILURE);
+                        if (i < ELEMENTSOF(pagers) - 1) {
+                                execlp(pagers[i], pagers[i], NULL);
+                                log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
+                                               "Failed to execute '%s', will try '%s' next: %m", pagers[i], pagers[i+1]);
+                        } else {
+                                /* Close pipe to signal the parent to start sending data */
+                                safe_close_pair(exe_name_pipe);
+                                pager_fallback();
+                                assert_not_reached();
+                        }
                 }
-                /* Close pipe to signal the parent to start sending data */
-                safe_close_pair(exe_name_pipe);
-                pager_fallback();
-                /* not reached */
         }
 
         /* Return in the parent */
         stored_stdout = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 3);
         if (dup2(fd[1], STDOUT_FILENO) < 0) {
                 stored_stdout = safe_close(stored_stdout);
-                return log_error_errno(errno, "Failed to duplicate pager pipe: %m");
+                return (void) log_error_errno(errno, "Failed to duplicate pager pipe: %m");
         }
         stdout_redirected = true;
 
         stored_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3);
         if (dup2(fd[1], STDERR_FILENO) < 0) {
                 stored_stderr = safe_close(stored_stderr);
-                return log_error_errno(errno, "Failed to duplicate pager pipe: %m");
+                return (void) log_error_errno(errno, "Failed to duplicate pager pipe: %m");
         }
         stderr_redirected = true;
 
         exe_name_pipe[1] = safe_close(exe_name_pipe[1]);
 
         r = no_quit_on_interrupt(TAKE_FD(exe_name_pipe[0]), less_opts);
-        if (r < 0)
-                return r;
         if (r > 0)
-                (void) ignore_signals(SIGINT, -1);
-
-        return 1;
+                (void) ignore_signals(SIGINT);
 }
 
 void pager_close(void) {
@@ -289,7 +285,7 @@ void pager_close(void) {
         stdout_redirected = stderr_redirected = false;
 
         (void) kill(pager_pid, SIGCONT);
-        (void) wait_for_terminate(pager_pid, NULL);
+        (void) wait_for_terminate(TAKE_PID(pager_pid), NULL);
         pager_pid = 0;
 }
 
@@ -312,15 +308,15 @@ int show_man_page(const char *desc, bool null_stdio) {
         if (e) {
                 char *page = NULL, *section = NULL;
 
-                page = strndupa(desc, e - desc);
-                section = strndupa(e + 1, desc + k - e - 2);
+                page = strndupa_safe(desc, e - desc);
+                section = strndupa_safe(e + 1, desc + k - e - 2);
 
                 args[1] = section;
                 args[2] = page;
         } else
                 args[1] = desc;
 
-        r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG|(null_stdio ? FORK_NULL_STDIO : 0)|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
+        r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|(null_stdio ? FORK_REARRANGE_STDIO : 0)|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
         if (r < 0)
                 return r;
         if (r == 0) {