Branch data Line data Source code
1 : : /* 2 : : * libdpkg - Debian packaging suite library routines 3 : : * pager.c - pager execution support 4 : : * 5 : : * Copyright © 2018 Guillem Jover <guillem@debian.org> 6 : : * 7 : : * This is free software; you can redistribute it and/or modify 8 : : * it under the terms of the GNU General Public License as published by 9 : : * the Free Software Foundation; either version 2 of the License, or 10 : : * (at your option) any later version. 11 : : * 12 : : * This is distributed in the hope that it will be useful, 13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 : : * GNU General Public License for more details. 16 : : * 17 : : * You should have received a copy of the GNU General Public License 18 : : * along with this program. If not, see <https://www.gnu.org/licenses/>. 19 : : */ 20 : : 21 : : #include <config.h> 22 : : #include <compat.h> 23 : : 24 : : #include <sys/types.h> 25 : : 26 : : #include <stdbool.h> 27 : : #include <stdlib.h> 28 : : #include <string.h> 29 : : #include <signal.h> 30 : : #include <unistd.h> 31 : : 32 : : #include <dpkg/dpkg.h> 33 : : #include <dpkg/i18n.h> 34 : : #include <dpkg/string.h> 35 : : #include <dpkg/subproc.h> 36 : : #include <dpkg/command.h> 37 : : #include <dpkg/pager.h> 38 : : 39 : : static bool pager_enabled = true; 40 : : 41 : : void 42 : 0 : pager_enable(bool enable) 43 : : { 44 : 0 : pager_enabled = enable; 45 : 0 : } 46 : : 47 : : /** 48 : : * Get a suitable pager. 49 : : * 50 : : * @return A string representing a pager. 51 : : */ 52 : : const char * 53 : 3 : pager_get_exec(void) 54 : : { 55 : : const char *pager; 56 : : 57 [ + - + + ]: 3 : if (!isatty(0) || !isatty(1)) 58 : 1 : return CAT; 59 : : 60 : 2 : pager = getenv("DPKG_PAGER"); 61 [ + - ]: 2 : if (str_is_unset(pager)) 62 : 2 : pager = getenv("PAGER"); 63 [ + + ]: 2 : if (str_is_unset(pager)) 64 : 1 : pager = DEFAULTPAGER; 65 : : 66 : 2 : return pager; 67 : : } 68 : : 69 : : struct pager { 70 : : bool used; 71 : : const char *desc; 72 : : pid_t pid; 73 : : struct sigaction sigpipe; 74 : : int stdout_old; 75 : : int pipe[2]; 76 : : }; 77 : : 78 : : struct pager * 79 : 0 : pager_spawn(const char *desc) 80 : : { 81 : : struct sigaction sa; 82 : : struct pager *pager; 83 : : const char *exec; 84 : : 85 : 0 : pager = m_calloc(1, sizeof(*pager)); 86 [ # # # # ]: 0 : pager->used = isatty(0) && isatty(1); 87 : 0 : pager->desc = desc; 88 : : 89 : 0 : exec = pager_get_exec(); 90 [ # # ]: 0 : if (strcmp(exec, CAT) == 0) 91 : 0 : pager->used = false; 92 : : 93 [ # # ]: 0 : if (!pager_enabled) 94 : 0 : pager->used = false; 95 : : 96 [ # # ]: 0 : if (!pager->used) 97 : 0 : return pager; 98 : : 99 : 0 : m_pipe(pager->pipe); 100 : : 101 : 0 : memset(&sa, 0, sizeof(sa)); 102 : 0 : sigemptyset(&sa.sa_mask); 103 : 0 : sa.sa_handler = SIG_IGN; 104 : 0 : sa.sa_flags = 0; 105 : : 106 : 0 : sigaction(SIGPIPE, &sa, &pager->sigpipe); 107 : : 108 : 0 : pager->pid = subproc_fork(); 109 [ # # ]: 0 : if (pager->pid == 0) { 110 : : /* Set better defaults for less if not already set. */ 111 : 0 : setenv("LESS", "-FRSXMQ", 0); 112 : : 113 : 0 : m_dup2(pager->pipe[0], 0); 114 : 0 : close(pager->pipe[0]); 115 : 0 : close(pager->pipe[1]); 116 : : 117 : 0 : command_shell(exec, desc); 118 : : } 119 : : 120 : 0 : pager->stdout_old = m_dup(1); 121 : 0 : m_dup2(pager->pipe[1], 1); 122 : 0 : close(pager->pipe[0]); 123 : 0 : close(pager->pipe[1]); 124 : : 125 : : /* Force the output to fully buffered, because originally stdout was 126 : : * a tty, so it was set as line buffered. This way we send as much as 127 : : * possible to the pager, which will handle the output by itself. */ 128 : 0 : setvbuf(stdout, NULL, _IOFBF, 0); 129 : : 130 : 0 : return pager; 131 : : } 132 : : 133 : : void 134 : 0 : pager_reap(struct pager *pager) 135 : : { 136 [ # # ]: 0 : if (!pager->used) 137 : 0 : return; 138 : : 139 : 0 : m_dup2(pager->stdout_old, 1); 140 : 0 : subproc_reap(pager->pid, pager->desc, SUBPROC_NOPIPE); 141 : : 142 : 0 : sigaction(SIGPIPE, &pager->sigpipe, NULL); 143 : : 144 : 0 : free(pager); 145 : : }