summaryrefslogtreecommitdiffstats
path: root/tools/lib/subcmd/pager.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-19 10:09:22 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-19 10:09:22 -0700
commitf4cdf7ca9a1fdcca413157df19753f388a5a224e (patch)
tree60a31895b2446cd7fa27514e8c2843534a0de0da /tools/lib/subcmd/pager.c
downloadlinux-stable-f4cdf7ca9a1fdcca413157df19753f388a5a224e.tar.gz
linux-stable-f4cdf7ca9a1fdcca413157df19753f388a5a224e.zip
Merge tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-mediagrafted
Pull media updates from Mauro Carvalho Chehab: - v4l2-core: added ISP statistics support and per-block validation - v4l2-core: Allow unknown HDR10 white point and luminance - New camera sensors: Sony IMX678 and IMX471m, Himax HM1092 IR sensor - New codec: Milos: VPU v2.0 codec support - isp driver: gained support for Dreamchip RPPX1 ISP framework - vsp1 driver: gained support for RZ/T2H and RZ/N2H - Novalake driver: gained CVS support for new NVL hardware - dvb-core: fix feed leak on failed DMX_ADD_PID - several driver fixes, cleanups and minor improvements * tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (308 commits) media: ipu-bridge: check all DMI entries when overriding sensor rotation media: v4l2-async: avoid deleting unlinked ASC entry on link error media: rzg2l-cru: Align bytesperline to hardware DMA stride requirement media: intel/ipu6: fix async notifier cleanup leak on parse error media: staging/ipu7: fix async notifier UAF on probe error path media: amd: isp4: fix self-deadlock in isp4sd_pwron_and_init() error path media: amd: isp4: release partial allocations in isp4if_alloc_fw_gpumem() media: rcar-isp: Fix VSPX reference leaks media: rcar-isp: Release ISPCORE resources media: i2c: imx415: Release runtime PM reference on VBLANK error media: i2c: imx415: Return test pattern write errors media: renesas: vsp1: Declare index variables in for loop statement media: renesas: vsp1: Make reset control optional to support platforms without a reset line media: dt-bindings: media: renesas,vsp1: Document RZ/T2H and RZ/N2H SoCs media: dt-bindings: media: renesas,fcp: Document RZ/T2H and RZ/N2H SoCs media: nxp: imx8-isi: Add additional 32-bit RGB format support media: nxp: imx8-isi: Add 16-bit raw Bayer format support media: nxp: imx8-isi: Implement per-stream reference counting for multiplexed streams media: nxp: imx8-isi: Use BIT_ULL() for 64-bit stream masks media: nxp: imx8-isi: Correct color map between V4L2 and ISI ...
Diffstat (limited to 'tools/lib/subcmd/pager.c')
-rw-r--r--tools/lib/subcmd/pager.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/tools/lib/subcmd/pager.c b/tools/lib/subcmd/pager.c
new file mode 100644
index 000000000..e3d47b59b
--- /dev/null
+++ b/tools/lib/subcmd/pager.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <sys/select.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include "pager.h"
+#include "run-command.h"
+#include "sigchain.h"
+#include "subcmd-config.h"
+
+/*
+ * This is split up from the rest of git so that we can do
+ * something different on Windows.
+ */
+
+static int spawned_pager;
+static int pager_columns;
+
+void pager_init(const char *pager_env)
+{
+ subcmd_config.pager_env = pager_env;
+}
+
+static const char *forced_pager;
+
+void force_pager(const char *pager)
+{
+ forced_pager = pager;
+}
+
+static void pager_preexec(void)
+{
+ /*
+ * Work around bug in "less" by not starting it until we
+ * have real input
+ */
+ fd_set in;
+ fd_set exception;
+
+ FD_ZERO(&in);
+ FD_ZERO(&exception);
+ FD_SET(0, &in);
+ FD_SET(0, &exception);
+ select(1, &in, NULL, &exception, NULL);
+
+ setenv("LESS", "FRSX", 0);
+}
+
+static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
+static struct child_process pager_process;
+
+static void wait_for_pager(void)
+{
+ fflush(stdout);
+ fflush(stderr);
+ /* signal EOF to pager */
+ close(1);
+ close(2);
+ finish_command(&pager_process);
+}
+
+static void wait_for_pager_signal(int signo)
+{
+ wait_for_pager();
+ sigchain_pop(signo);
+ raise(signo);
+}
+
+void setup_pager(void)
+{
+ const char *pager = getenv(subcmd_config.pager_env);
+ struct winsize sz;
+
+ if (forced_pager)
+ pager = forced_pager;
+ if (!isatty(1) && !forced_pager)
+ return;
+ if (ioctl(1, TIOCGWINSZ, &sz) == 0)
+ pager_columns = sz.ws_col;
+ if (!pager)
+ pager = getenv("PAGER");
+ if (!(pager || access("/usr/bin/pager", X_OK)))
+ pager = "/usr/bin/pager";
+ if (!(pager || access("/usr/bin/less", X_OK)))
+ pager = "/usr/bin/less";
+ if (!pager)
+ pager = "cat";
+ if (!*pager || !strcmp(pager, "cat"))
+ return;
+
+ spawned_pager = 1; /* means we are emitting to terminal */
+
+ /* spawn the pager */
+ pager_argv[2] = pager;
+ pager_process.argv = pager_argv;
+ pager_process.in = -1;
+ pager_process.preexec_cb = pager_preexec;
+
+ if (start_command(&pager_process))
+ return;
+
+ /* original process continues, but writes to the pipe */
+ dup2(pager_process.in, 1);
+ if (isatty(2))
+ dup2(pager_process.in, 2);
+ close(pager_process.in);
+
+ /* this makes sure that the parent terminates after the pager */
+ sigchain_push_common(wait_for_pager_signal);
+ atexit(wait_for_pager);
+}
+
+int pager_in_use(void)
+{
+ return spawned_pager;
+}
+
+int pager_get_columns(void)
+{
+ char *s;
+
+ s = getenv("COLUMNS");
+ if (s)
+ return atoi(s);
+
+ return (pager_columns ? pager_columns : 80) - 2;
+}