From: yuriyryabikov <22548029+kurok@users.noreply.github.com> Date: Wed, 22 Apr 2026 11:46:13 +0000 (+0100) Subject: lslocks: add --pager and --nopager options X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=2779bd9f6ab4e234a90186a70bb6cc00f520d38b;p=thirdparty%2Futil-linux.git lslocks: add --pager and --nopager options Signed-off-by: yuriyryabikov <22548029+kurok@users.noreply.github.com> --- diff --git a/bash-completion/lslocks b/bash-completion/lslocks index b2a617e71..cd6d95cb3 100644 --- a/bash-completion/lslocks +++ b/bash-completion/lslocks @@ -42,6 +42,8 @@ _lslocks_module() --notruncate --list-columns --filter + --pager + --nopager --help --version " diff --git a/include/pager.h b/include/pager.h index 8a2edb3ae..508879934 100644 --- a/include/pager.h +++ b/include/pager.h @@ -7,8 +7,18 @@ #ifndef UTIL_LINUX_PAGER #define UTIL_LINUX_PAGER +#include + +/* --pager / --nopager */ +enum ul_pagermode { + UL_PAGER_AUTO = 0, /* unspecified by user; obey PAGER_ENABLE */ + UL_PAGER_NEVER, /* --nopager (or --json/--raw) */ + UL_PAGER_ALWAYS /* --pager */ +}; + void pager_open(void); void pager_open_header(int header_lines, int first_col_width); void pager_close(void); +bool pager_is_enabled(enum ul_pagermode mode); #endif diff --git a/lib/pager.c b/lib/pager.c index 64a0a3a6b..180447c1b 100644 --- a/lib/pager.c +++ b/lib/pager.c @@ -26,6 +26,7 @@ #include "strutils.h" #include "ttyutils.h" #include "pager.h" +#include "env.h" static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; @@ -356,6 +357,40 @@ void pager_close(void) pager_caught_sigpipe = 0; } +/* Decide whether the pager should run for the given @mode. + * + * UL_PAGER_ALWAYS and UL_PAGER_NEVER reflect an explicit user choice + * (--pager / --nopager) and are honored unconditionally. + * + * UL_PAGER_AUTO consults the PAGER_ENABLE environment variable (accepted + * values parsed by ul_strtobool()). PAGER_ENABLE is ignored when stdout + * is not a terminal, so pipelines like `lslocks | grep foo` do not spawn + * a pager. The variable is also suppressed in privileged (SUID/SGID) + * contexts via safe_getenv(). + */ +bool pager_is_enabled(enum ul_pagermode mode) +{ + switch (mode) { + case UL_PAGER_ALWAYS: + return true; + case UL_PAGER_NEVER: + return false; + case UL_PAGER_AUTO: { + const char *s; + bool val; + + if (!isatty(STDOUT_FILENO)) + return false; + s = safe_getenv("PAGER_ENABLE"); + if (!s || ul_strtobool(s, &val) != 0) + return false; + return val; + } + default: + return false; + } +} + #ifdef TEST_PROGRAM_PAGER #define MAX 255 diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am index 27abeb3ca..11b2f82ee 100644 --- a/misc-utils/Makemodule.am +++ b/misc-utils/Makemodule.am @@ -85,7 +85,7 @@ usrbin_exec_PROGRAMS += lslocks MANPAGES += misc-utils/lslocks.8 dist_noinst_DATA += misc-utils/lslocks.8.adoc lslocks_LDADD = $(LDADD) libcommon.la libmount.la libsmartcols.la -lslocks_SOURCES = misc-utils/lslocks.c +lslocks_SOURCES = misc-utils/lslocks.c include/pager.h lib/pager.c lslocks_CFLAGS = $(AM_CFLAGS) -I$(ul_libmount_incdir) -I$(ul_libsmartcols_incdir) endif diff --git a/misc-utils/lslocks.8.adoc b/misc-utils/lslocks.8.adoc index 964ec08a8..69894c728 100644 --- a/misc-utils/lslocks.8.adoc +++ b/misc-utils/lslocks.8.adoc @@ -72,6 +72,16 @@ ____ lslocks --filter 'TYPE != "POSIX" and MODE == "READ" and PATH =~ ".*\.qcow2"' ____ +*--pager*:: +Pipe output into a pager (by default *less*(1)). The pager freezes the +header line so column names stay visible while scrolling. +The *PAGER* environment variable overrides the default pager program. +Mutually exclusive with *--json* and *--raw*. + +*--nopager*:: +Do not pipe output into a pager. Overrides the *PAGER_ENABLE* environment +variable. + *-r*, *--raw*:: Use the raw output format. @@ -87,6 +97,12 @@ include::man-common/env-smartcols.adoc[] *LSLOCKS_COLUMNS*=:: Specify a comma-separated list of output columns to print. All columns listed by *--list-columns* can be used. +*PAGER_ENABLE*=:: +If set to a recognized boolean value (e.g. "yes", "true", "on", "1"), automatically pipe output through a pager. +The *--pager* and *--nopager* command-line options override this variable. +Ignored when standard output is not a terminal, and in privileged (setuid/setgid) contexts. +This is a project-independent variable; other tools may support it as well. + == OUTPUT COMMAND:: diff --git a/misc-utils/lslocks.c b/misc-utils/lslocks.c index 8d79af4d7..fbaf7a2f8 100644 --- a/misc-utils/lslocks.c +++ b/misc-utils/lslocks.c @@ -50,6 +50,7 @@ #include "procfs.h" #include "column-list-table.h" #include "fileutils.h" +#include "pager.h" /* column IDs */ enum { @@ -138,6 +139,7 @@ struct lslocks { int raw; int json; int bytes; + enum ul_pagermode pager_mode; pid_t target_pid; @@ -947,6 +949,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -Q, --filter apply display filter\n"), out); fputs(_(" -r, --raw use the raw output format\n"), out); fputs(_(" -u, --notruncate don't truncate text in columns\n"), out); + fputs(_(" --pager pipe output into a pager\n"), out); + fputs(_(" --nopager disable pager output\n"), out); fputs(USAGE_SEPARATOR, out); fprintf(out, USAGE_LIST_COLUMNS_OPTION(24)); @@ -1081,7 +1085,9 @@ int main(int argc, char *argv[]) struct libscols_filter *filter = NULL; char *outarg = NULL; enum { - OPT_OUTPUT_ALL = CHAR_MAX + 1 + OPT_OUTPUT_ALL = CHAR_MAX + 1, + OPT_PAGER, + OPT_NO_PAGER, }; static const struct option long_opts[] = { { "bytes", no_argument, NULL, 'b' }, @@ -1097,11 +1103,16 @@ int main(int argc, char *argv[]) { "noinaccessible", no_argument, NULL, 'i' }, { "filter", required_argument, NULL, 'Q' }, { "list-columns", no_argument, NULL, 'H' }, + { "pager", no_argument, NULL, OPT_PAGER }, + { "nopager", no_argument, NULL, OPT_NO_PAGER }, { NULL, 0, NULL, 0 } }; static const ul_excl_t excl[] = { /* rows and cols in ASCII order */ { 'J','r' }, + { 'J', OPT_PAGER }, + { 'r', OPT_PAGER }, + { OPT_PAGER, OPT_NO_PAGER }, { 0 } }; int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; @@ -1127,6 +1138,7 @@ int main(int argc, char *argv[]) break; case 'J': lslocks.json = 1; + lslocks.pager_mode = UL_PAGER_NEVER; break; case 'p': lslocks.target_pid = strtopid_or_err(optarg, _("invalid PID argument")); @@ -1143,6 +1155,7 @@ int main(int argc, char *argv[]) break; case 'r': lslocks.raw = 1; + lslocks.pager_mode = UL_PAGER_NEVER; break; case 'u': disable_columns_truncate(); @@ -1151,6 +1164,12 @@ int main(int argc, char *argv[]) case 'H': collist = 1; break; + case OPT_PAGER: + lslocks.pager_mode = UL_PAGER_ALWAYS; + break; + case OPT_NO_PAGER: + lslocks.pager_mode = UL_PAGER_NEVER; + break; case 'Q': filter = new_filter(optarg); break; @@ -1191,6 +1210,9 @@ int main(int argc, char *argv[]) if (filter) init_scols_filter(table, filter, lslocks.bytes); + if (pager_is_enabled(lslocks.pager_mode)) + pager_open_header(lslocks.no_headings ? 0 : 1, 0); + /* get_pids_locks() get locks related information from "lock:" fields * of /proc/$pid/fdinfo/$fd as fallback information. * get_proc_locks() used the fallback information if /proc/locks @@ -1208,5 +1230,7 @@ int main(int argc, char *argv[]) scols_unref_table(table); lslocks_free(&lslocks); + + pager_close(); return rc; } diff --git a/misc-utils/meson.build b/misc-utils/meson.build index 4d95beadc..8bb99822e 100644 --- a/misc-utils/meson.build +++ b/misc-utils/meson.build @@ -45,7 +45,8 @@ whereis_manadocs = files('whereis.1.adoc') lslocks_sources = files( 'lslocks.c', -) +) + \ + pager_c lslocks_manadocs = files('lslocks.8.adoc') lsblk_sources = files(