aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/pager.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/pager.c')
-rw-r--r--tools/perf/util/pager.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
new file mode 100644
index 000000000000..a28bccae5458
--- /dev/null
+++ b/tools/perf/util/pager.c
@@ -0,0 +1,99 @@
1#include "cache.h"
2#include "run-command.h"
3#include "sigchain.h"
4
5/*
6 * This is split up from the rest of git so that we can do
7 * something different on Windows.
8 */
9
10static int spawned_pager;
11
12#ifndef __MINGW32__
13static void pager_preexec(void)
14{
15 /*
16 * Work around bug in "less" by not starting it until we
17 * have real input
18 */
19 fd_set in;
20
21 FD_ZERO(&in);
22 FD_SET(0, &in);
23 select(1, &in, NULL, &in, NULL);
24
25 setenv("LESS", "FRSX", 0);
26}
27#endif
28
29static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
30static struct child_process pager_process;
31
32static void wait_for_pager(void)
33{
34 fflush(stdout);
35 fflush(stderr);
36 /* signal EOF to pager */
37 close(1);
38 close(2);
39 finish_command(&pager_process);
40}
41
42static void wait_for_pager_signal(int signo)
43{
44 wait_for_pager();
45 sigchain_pop(signo);
46 raise(signo);
47}
48
49void setup_pager(void)
50{
51 const char *pager = getenv("PERF_PAGER");
52
53 if (!isatty(1))
54 return;
55 if (!pager) {
56 if (!pager_program)
57 perf_config(perf_default_config, NULL);
58 pager = pager_program;
59 }
60 if (!pager)
61 pager = getenv("PAGER");
62 if (!pager)
63 pager = "less";
64 else if (!*pager || !strcmp(pager, "cat"))
65 return;
66
67 spawned_pager = 1; /* means we are emitting to terminal */
68
69 /* spawn the pager */
70 pager_argv[2] = pager;
71 pager_process.argv = pager_argv;
72 pager_process.in = -1;
73#ifndef __MINGW32__
74 pager_process.preexec_cb = pager_preexec;
75#endif
76 if (start_command(&pager_process))
77 return;
78
79 /* original process continues, but writes to the pipe */
80 dup2(pager_process.in, 1);
81 if (isatty(2))
82 dup2(pager_process.in, 2);
83 close(pager_process.in);
84
85 /* this makes sure that the parent terminates after the pager */
86 sigchain_push_common(wait_for_pager_signal);
87 atexit(wait_for_pager);
88}
89
90int pager_in_use(void)
91{
92 const char *env;
93
94 if (spawned_pager)
95 return 1;
96
97 env = getenv("PERF_PAGER_IN_USE");
98 return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0;
99}