]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/pager.c
nspawn: newer kernels (>= 3.14) allow resetting the audit loginuid, make use of this
[thirdparty/systemd.git] / src / shared / pager.c
CommitLineData
1968a360
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
1968a360
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
1968a360 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
1968a360
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <sys/types.h>
4a8e40eb 23#include <fcntl.h>
1968a360
LP
24#include <stdlib.h>
25#include <unistd.h>
26#include <string.h>
27#include <sys/prctl.h>
28
29#include "pager.h"
30#include "util.h"
31#include "macro.h"
32
33static pid_t pager_pid = 0;
34
919ce0b7 35noreturn static void pager_fallback(void) {
4a8e40eb 36 ssize_t n;
46e65dcc 37
4a8e40eb
MS
38 do {
39 n = splice(STDIN_FILENO, NULL, STDOUT_FILENO, NULL, 64*1024, 0);
40 } while (n > 0);
46e65dcc 41
4a8e40eb
MS
42 if (n < 0) {
43 log_error("Internal pager failed: %m");
44 _exit(EXIT_FAILURE);
45 }
46e65dcc 46
4a8e40eb
MS
47 _exit(EXIT_SUCCESS);
48}
49
1b12a7b5 50int pager_open(bool jump_to_end) {
1968a360
LP
51 int fd[2];
52 const char *pager;
53 pid_t parent_pid;
f89a3b6f 54 int r;
1968a360
LP
55
56 if (pager_pid > 0)
f89a3b6f 57 return 1;
1968a360 58
1968a360
LP
59 if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER")))
60 if (!*pager || streq(pager, "cat"))
f89a3b6f 61 return 0;
1968a360 62
8481248b 63 if (!on_tty())
f89a3b6f 64 return 0;
729e3769 65
1968a360
LP
66 /* Determine and cache number of columns before we spawn the
67 * pager so that we get the value from the actual tty */
68 columns();
69
70 if (pipe(fd) < 0) {
71 log_error("Failed to create pager pipe: %m");
f89a3b6f 72 return -errno;
1968a360
LP
73 }
74
75 parent_pid = getpid();
76
77 pager_pid = fork();
78 if (pager_pid < 0) {
f89a3b6f 79 r = -errno;
1968a360
LP
80 log_error("Failed to fork pager: %m");
81 close_pipe(fd);
f89a3b6f 82 return r;
1968a360
LP
83 }
84
85 /* In the child start the pager */
86 if (pager_pid == 0) {
87
88 dup2(fd[0], STDIN_FILENO);
89 close_pipe(fd);
90
1b12a7b5 91 if (jump_to_end)
b47ef6a0 92 setenv("LESS", "FRSXMK+G", 1);
1b12a7b5 93 else
b47ef6a0 94 setenv("LESS", "FRSXMK", 1);
1968a360
LP
95
96 /* Make sure the pager goes away when the parent dies */
97 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
98 _exit(EXIT_FAILURE);
99
100 /* Check whether our parent died before we were able
101 * to set the death signal */
102 if (getppid() != parent_pid)
103 _exit(EXIT_SUCCESS);
104
105 if (pager) {
106 execlp(pager, pager, NULL);
107 execl("/bin/sh", "sh", "-c", pager, NULL);
108 }
109
110 /* Debian's alternatives command for pagers is
111 * called 'pager'. Note that we do not call
112 * sensible-pagers here, since that is just a
113 * shell script that implements a logic that
114 * is similar to this one anyway, but is
115 * Debian-specific. */
116 execlp("pager", "pager", NULL);
117
118 execlp("less", "less", NULL);
119 execlp("more", "more", NULL);
1968a360 120
4a8e40eb
MS
121 pager_fallback();
122 /* not reached */
1968a360
LP
123 }
124
125 /* Return in the parent */
fafb6ecc 126 if (dup2(fd[1], STDOUT_FILENO) < 0) {
1968a360 127 log_error("Failed to duplicate pager pipe: %m");
f89a3b6f 128 return -errno;
fafb6ecc 129 }
1968a360
LP
130
131 close_pipe(fd);
f89a3b6f 132 return 1;
1968a360
LP
133}
134
135void pager_close(void) {
136
137 if (pager_pid <= 0)
138 return;
139
140 /* Inform pager that we are done */
141 fclose(stdout);
142 kill(pager_pid, SIGCONT);
143 wait_for_terminate(pager_pid, NULL);
144 pager_pid = 0;
145}
f89a3b6f
LP
146
147bool pager_have(void) {
148 return pager_pid > 0;
149}