1 /*
2 * Copyright © 2018 Rob Clark <[email protected]>
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include <errno.h>
7 #include <signal.h>
8 #include <stdbool.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15
16 #include "pager.h"
17
18 static pid_t pager_pid;
19
20 static void
pager_death(int n)21 pager_death(int n)
22 {
23 exit(0);
24 }
25
26 void
pager_open(void)27 pager_open(void)
28 {
29 int fd[2];
30
31 if (pipe(fd) < 0) {
32 fprintf(stderr, "Failed to create pager pipe: %m\n");
33 exit(-1);
34 }
35
36 pager_pid = fork();
37 if (pager_pid < 0) {
38 fprintf(stderr, "Failed to fork pager: %m\n");
39 exit(-1);
40 }
41
42 if (pager_pid == 0) {
43 const char *less_opts;
44
45 dup2(fd[0], STDIN_FILENO);
46 close(fd[0]);
47 close(fd[1]);
48
49 less_opts = "FRSMKX";
50 setenv("LESS", less_opts, 1);
51
52 execlp("less", "less", NULL);
53
54 } else {
55 /* we want to kill the parent process when pager exits: */
56 signal(SIGCHLD, pager_death);
57 dup2(fd[1], STDOUT_FILENO);
58 close(fd[0]);
59 close(fd[1]);
60 }
61 }
62
63 int
pager_close(void)64 pager_close(void)
65 {
66 siginfo_t status;
67
68 close(STDOUT_FILENO);
69
70 while (true) {
71 memset(&status, 0, sizeof(status));
72 if (waitid(P_PID, pager_pid, &status, WEXITED) < 0) {
73 if (errno == EINTR)
74 continue;
75 return -errno;
76 }
77
78 return 0;
79 }
80 }
81