1/* 2 * Copyright (c) 2018 Rob Clark <robdclark@gmail.com> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include <errno.h> 25#include <signal.h> 26#include <stdbool.h> 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30#include <unistd.h> 31#include <sys/types.h> 32#include <sys/wait.h> 33 34#include "pager.h" 35 36static pid_t pager_pid; 37 38static void 39pager_death(int n) 40{ 41 exit(0); 42} 43 44void 45pager_open(void) 46{ 47 int fd[2]; 48 49 if (pipe(fd) < 0) { 50 fprintf(stderr, "Failed to create pager pipe: %m\n"); 51 exit(-1); 52 } 53 54 pager_pid = fork(); 55 if (pager_pid < 0) { 56 fprintf(stderr, "Failed to fork pager: %m\n"); 57 exit(-1); 58 } 59 60 if (pager_pid == 0) { 61 const char *less_opts; 62 63 dup2(fd[0], STDIN_FILENO); 64 close(fd[0]); 65 close(fd[1]); 66 67 less_opts = "FRSMKX"; 68 setenv("LESS", less_opts, 1); 69 70 execlp("less", "less", NULL); 71 72 } else { 73 /* we want to kill the parent process when pager exits: */ 74 signal(SIGCHLD, pager_death); 75 dup2(fd[1], STDOUT_FILENO); 76 close(fd[0]); 77 close(fd[1]); 78 } 79} 80 81int 82pager_close(void) 83{ 84 siginfo_t status; 85 86 close(STDOUT_FILENO); 87 88 while (true) { 89 memset(&status, 0, sizeof(status)); 90 if (waitid(P_PID, pager_pid, &status, WEXITED) < 0) { 91 if (errno == EINTR) 92 continue; 93 return -errno; 94 } 95 96 return 0; 97 } 98} 99