Util-Linux package development
 help / color / mirror / Atom feed
* Re: [PATCH 3/3] lsirq,irqtop: add support for reading data from given file
From: zhenwei pi @ 2025-02-28  1:41 UTC (permalink / raw)
  To: Joe Jin, Karel Zak, Sami Kerola; +Cc: util-linux
In-Reply-To: <20250227044916.89925-4-joe.jin@oracle.com>

Does the '--input IRQFILE' change?

irqtop reads 'IRQFILE' and uses the current one to calculate the 
increment from the previous one, I'm curious about this case ...

But I guess lsirq would work fine.

On 2/27/25 12:49, Joe Jin wrote:
> This is helpful for analyzng data saved from other system.
> 
> Signed-off-by: Joe Jin <joe.jin@oracle.com>
> Cc: Zhenwei Pi <pizhenwei@bytedance.com>
> Cc: Sami Kerola <kerolasa@iki.fi>
> ---
>   bash-completion/irqtop  |  4 ++++
>   bash-completion/lsirq   |  4 ++++
>   sys-utils/irq-common.c  | 19 +++++++++----------
>   sys-utils/irq-common.h  |  3 ++-
>   sys-utils/irqtop.1.adoc |  3 +++
>   sys-utils/irqtop.c      | 28 +++++++++++++++++++++++++---
>   sys-utils/lsirq.1.adoc  |  3 +++
>   sys-utils/lsirq.c       | 28 ++++++++++++++++++++++++----
>   8 files changed, 74 insertions(+), 18 deletions(-)
> 
> diff --git a/bash-completion/irqtop b/bash-completion/irqtop
> index 47b7b0af6..3bea5fc0e 100644
> --- a/bash-completion/irqtop
> +++ b/bash-completion/irqtop
> @@ -15,6 +15,9 @@ _irqtop_module()
>   		'-C'|'--cpu-list')
>   			return 0
>   			;;
> +		'-i'|'--input')
> +			COMPREPLY=( $(compgen -W "input file" -- $cur) )
> +			;;
>   		'-t'|'--threshold')
>   			return 0
>   			;;
> @@ -51,6 +54,7 @@ _irqtop_module()
>   		--cpu-stat
>   		--cpu-list
>   		--delay
> +		--input
>   		--number
>   		--sort
>   		--output
> diff --git a/bash-completion/lsirq b/bash-completion/lsirq
> index 4c3c9f04f..b913eecd0 100644
> --- a/bash-completion/lsirq
> +++ b/bash-completion/lsirq
> @@ -5,6 +5,9 @@ _lsirq_module()
>   	cur="${COMP_WORDS[COMP_CWORD]}"
>   	prev="${COMP_WORDS[COMP_CWORD-1]}"
>   	case $prev in
> +		'-i'|'--input')
> +			COMPREPLY=( $(compgen -W "input file" -- $cur) )
> +			;;
>   		'-o'|'--output')
>   			local prefix realcur OUTPUT
>   			realcur="${cur##*,}"
> @@ -35,6 +38,7 @@ _lsirq_module()
>   	OPTS="	--json
>   		--pairs
>   		--noheadings
> +		--input
>   		--output
>   		--softirq
>   		--sort
> diff --git a/sys-utils/irq-common.c b/sys-utils/irq-common.c
> index f069d8a63..560dd4b82 100644
> --- a/sys-utils/irq-common.c
> +++ b/sys-utils/irq-common.c
> @@ -233,7 +233,8 @@ static bool cpu_in_list(int cpu, size_t setsize, cpu_set_t *cpuset)
>   /*
>    * irqinfo - parse the system's interrupts
>    */
> -static struct irq_stat *get_irqinfo(int softirq, size_t setsize, cpu_set_t *cpuset)
> +static struct irq_stat *get_irqinfo(const char *input_file, int softirq,
> +				    size_t setsize, cpu_set_t *cpuset)
>   {
>   	FILE *irqfile;
>   	char *line = NULL, *tmp;
> @@ -247,18 +248,15 @@ static struct irq_stat *get_irqinfo(int softirq, size_t setsize, cpu_set_t *cpus
>   	stat->irq_info = xmalloc(sizeof(*stat->irq_info) * IRQ_INFO_LEN);
>   	stat->nr_irq_info = IRQ_INFO_LEN;
>   
> -	if (softirq)
> -		irqfile = fopen(_PATH_PROC_SOFTIRQS, "r");
> -	else
> -		irqfile = fopen(_PATH_PROC_INTERRUPTS, "r");
> +	irqfile = fopen(input_file, "r");
>   	if (!irqfile) {
> -		warn(_("cannot open %s"), _PATH_PROC_INTERRUPTS);
> +		warn(_("cannot open %s"), input_file);
>   		goto free_stat;
>   	}
>   
>   	/* read header firstly */
>   	if (getline(&line, &len, irqfile) < 0) {
> -		warn(_("cannot read %s"), _PATH_PROC_INTERRUPTS);
> +		warn(_("cannot read %s"), input_file);
>   		goto close_file;
>   	}
>   
> @@ -270,7 +268,7 @@ static struct irq_stat *get_irqinfo(int softirq, size_t setsize, cpu_set_t *cpus
>   
>   	stat->cpus =  xcalloc(stat->nr_active_cpu, sizeof(struct irq_cpu));
>   
> -	/* parse each line of _PATH_PROC_INTERRUPTS */
> +	/* parse each line of input file */
>   	while (getline(&line, &len, irqfile) >= 0) {
>   		unsigned long count;
>   		size_t index;
> @@ -527,7 +525,8 @@ struct libscols_table *get_scols_cpus_table(struct irq_output *out,
>   	return NULL;
>   }
>   
> -struct libscols_table *get_scols_table(struct irq_output *out,
> +struct libscols_table *get_scols_table(const char *input_file,
> +					      struct irq_output *out,
>   					      struct irq_stat *prev,
>   					      struct irq_stat **xstat,
>   					      int softirq,
> @@ -542,7 +541,7 @@ struct libscols_table *get_scols_table(struct irq_output *out,
>   	size_t i;
>   
>   	/* the stats */
> -	stat = get_irqinfo(softirq, setsize, cpuset);
> +	stat = get_irqinfo(input_file, softirq, setsize, cpuset);
>   	if (!stat)
>   		return NULL;
>   
> diff --git a/sys-utils/irq-common.h b/sys-utils/irq-common.h
> index 02b72d752..b9cf72d2a 100644
> --- a/sys-utils/irq-common.h
> +++ b/sys-utils/irq-common.h
> @@ -73,7 +73,8 @@ void irq_print_columns(FILE *f, int nodelta);
>   void set_sort_func_by_name(struct irq_output *out, const char *name);
>   void set_sort_func_by_key(struct irq_output *out, const char c);
>   
> -struct libscols_table *get_scols_table(struct irq_output *out,
> +struct libscols_table *get_scols_table(const char *input_file,
> +                                              struct irq_output *out,
>                                                 struct irq_stat *prev,
>                                                 struct irq_stat **xstat,
>                                                 int softirq,
> diff --git a/sys-utils/irqtop.1.adoc b/sys-utils/irqtop.1.adoc
> index 75cfe2e41..715008d07 100644
> --- a/sys-utils/irqtop.1.adoc
> +++ b/sys-utils/irqtop.1.adoc
> @@ -37,6 +37,9 @@ Specify cpus in list format to show.
>   *-d*, *--delay* _seconds_::
>   Update interrupt output every _seconds_ intervals.
>   
> +*-i*, *--input* _file_::
> +Read data from _file_ (Which was created by other tools, e.g. sosreport).
> +
>   *-n*, *--number* _number_::
>   Specifies the maximum _number_ of iterations before quitting.
>   
> diff --git a/sys-utils/irqtop.c b/sys-utils/irqtop.c
> index ba5680671..4cf1dc79a 100644
> --- a/sys-utils/irqtop.c
> +++ b/sys-utils/irqtop.c
> @@ -87,6 +87,8 @@ struct irqtop_ctl {
>   	bool	batch;
>   	bool	request_exit,
>   		softirq;
> +
> +	char	*input;
>   };
>   
>   #define irqtop_batch_mode(ctl) ((ctl)->batch == true)
> @@ -122,8 +124,9 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
>   	char timestr[64], *data, *data0, *p;
>   
>   	/* make irqs table */
> -	table = get_scols_table(out, ctl->prev_stat, &stat, ctl->softirq,
> -				ctl->threshold, ctl->setsize, ctl->cpuset);
> +	table = get_scols_table(ctl->input, out, ctl->prev_stat, &stat,
> +				ctl->softirq, ctl->threshold, ctl->setsize,
> +				ctl->cpuset);
>   	if (!table) {
>   		ctl->request_exit = 1;
>   		return 1;
> @@ -292,6 +295,7 @@ static void __attribute__((__noreturn__)) usage(void)
>   	fputs(_(" -c, --cpu-stat <mode> show per-cpu stat (auto, enable, disable)\n"), stdout);
>   	fputs(_(" -C, --cpu-list <list> specify cpus in list format\n"), stdout);
>   	fputs(_(" -d, --delay <secs>   delay updates\n"), stdout);
> +	fputs(_(" -i, --input <file>   read data from file\n"), stdout);
>   	fputs(_(" -n, --number <number> the maximum number of iterations\n"), stdout);
>   	fputs(_(" -o, --output <list>  define which output columns to use\n"), stdout);
>   	fputs(_(" -s, --sort <column>  specify sort column\n"), stdout);
> @@ -325,6 +329,7 @@ static void parse_args(	struct irqtop_ctl *ctl,
>   		{"cpu-stat", required_argument, NULL, 'c'},
>   		{"cpu-list", required_argument, NULL, 'C'},
>   		{"delay", required_argument, NULL, 'd'},
> +		{"input", required_argument, NULL, 'i'},
>   		{"number", required_argument, NULL, 'n'},
>   		{"sort", required_argument, NULL, 's'},
>   		{"output", required_argument, NULL, 'o'},
> @@ -336,7 +341,7 @@ static void parse_args(	struct irqtop_ctl *ctl,
>   	};
>   	int o;
>   
> -	while ((o = getopt_long(argc, argv, "bc:C:d:n:o:s:St:hV", longopts, NULL)) != -1) {
> +	while ((o = getopt_long(argc, argv, "bc:C:d:i:n:o:s:St:hV", longopts, NULL)) != -1) {
>   		switch (o) {
>   		case 'b':
>   			ctl->batch = true;
> @@ -376,6 +381,13 @@ static void parse_args(	struct irqtop_ctl *ctl,
>   				ctl->timer.it_value = ctl->timer.it_interval;
>   			}
>   			break;
> +		case 'i':
> +			ctl->input = strdup(optarg);
> +			if (!ctl->input)
> +				err_oom();
> +			ctl->number = 1;
> +			ctl->batch = true;
> +			break;
>   		case 'n':
>   			ctl->number = str2num_or_err(optarg, 10,
>   					_("failed to parse number argument"),
> @@ -402,6 +414,15 @@ static void parse_args(	struct irqtop_ctl *ctl,
>   		}
>   	}
>   
> +	if (ctl->input == NULL) {
> +		if (ctl->softirq == 1)
> +			ctl->input = strdup(_PATH_PROC_SOFTIRQS);
> +		else
> +			ctl->input = strdup(_PATH_PROC_INTERRUPTS);
> +		if (!ctl->input)
> +			err_oom();
> +	}
> +
>   	/* default */
>   	if (!out->ncolumns) {
>   		out->columns[out->ncolumns++] = COL_IRQ;
> @@ -453,6 +474,7 @@ int main(int argc, char **argv)
>   
>   	free_irqstat(ctl.prev_stat);
>   	free(ctl.hostname);
> +	free(ctl.input);
>   	cpuset_free(ctl.cpuset);
>   
>   	if (ctl.batch == false) {
> diff --git a/sys-utils/lsirq.1.adoc b/sys-utils/lsirq.1.adoc
> index 02aea16b3..dd265710c 100644
> --- a/sys-utils/lsirq.1.adoc
> +++ b/sys-utils/lsirq.1.adoc
> @@ -25,6 +25,9 @@ The default output is subject to change. So whenever possible, you should avoid
>   *-n*, *--noheadings*::
>   Don't print headings.
>   
> +*-i*, *--input* _file_::
> +Read data from _file_ (Which was created by other tools, e.g. sosreport).
> +
>   *-o*, *--output* _list_::
>   Specify which output columns to print. Use *--help* to get a list of all supported columns. The default list of columns may be extended if list is specified in the format _+list_.
>   
> diff --git a/sys-utils/lsirq.c b/sys-utils/lsirq.c
> index e31addaf5..45d542919 100644
> --- a/sys-utils/lsirq.c
> +++ b/sys-utils/lsirq.c
> @@ -29,16 +29,17 @@
>   #include "optutils.h"
>   #include "strutils.h"
>   #include "xalloc.h"
> +#include "pathnames.h"
>   
>   #include "irq-common.h"
>   
> -static int print_irq_data(struct irq_output *out,
> +static int print_irq_data(const char *input_file, struct irq_output *out,
>   			  int softirq, unsigned long threshold,
>   			  size_t setsize, cpu_set_t *cpuset)
>   {
>   	struct libscols_table *table;
>   
> -	table = get_scols_table(out, NULL, NULL, softirq, threshold, setsize, cpuset);
> +	table = get_scols_table(input_file, out, NULL, NULL, softirq, threshold, setsize, cpuset);
>   	if (!table)
>   		return -1;
>   
> @@ -58,6 +59,7 @@ static void __attribute__((__noreturn__)) usage(void)
>   	fputs(USAGE_OPTIONS, stdout);
>   	fputs(_(" -J, --json           use JSON output format\n"), stdout);
>   	fputs(_(" -P, --pairs          use key=\"value\" output format\n"), stdout);
> +	fputs(_(" -i, --input          read data from input file\n"), stdout);
>   	fputs(_(" -n, --noheadings     don't print headings\n"), stdout);
>   	fputs(_(" -o, --output <list>  define which output columns to use\n"), stdout);
>   	fputs(_(" -s, --sort <column>  specify sort column\n"), stdout);
> @@ -82,6 +84,7 @@ int main(int argc, char **argv)
>   	static const struct option longopts[] = {
>   		{"sort", required_argument, NULL, 's'},
>   		{"noheadings", no_argument, NULL, 'n'},
> +		{"input", required_argument, NULL, 'i'},
>   		{"output", required_argument, NULL, 'o'},
>   		{"threshold", required_argument, NULL, 't'},
>   		{"cpu-list", required_argument, NULL, 'C'},
> @@ -103,10 +106,11 @@ int main(int argc, char **argv)
>   	cpu_set_t *cpuset = NULL;
>   	size_t setsize = 0;
>   	int softirq = 0;
> +	char *input = NULL;
>   
>   	setlocale(LC_ALL, "");
>   
> -	while ((c = getopt_long(argc, argv, "no:s:t:C:ShJPV", longopts, NULL)) != -1) {
> +	while ((c = getopt_long(argc, argv, "i:no:s:t:C:ShJPV", longopts, NULL)) != -1) {
>   		err_exclusive_options(c, longopts, excl, excl_st);
>   
>   		switch (c) {
> @@ -116,6 +120,11 @@ int main(int argc, char **argv)
>   		case 'P':
>   			out.pairs = 1;
>   			break;
> +		case 'i':
> +			input = strdup(optarg);
> +			if (!input)
> +				err_oom();
> +			break;
>   		case 'n':
>   			out.no_headings = 1;
>   			break;
> @@ -157,6 +166,15 @@ int main(int argc, char **argv)
>   		}
>   	}
>   
> +	if (input == NULL) {
> +		if (softirq == 1)
> +			input = strdup(_PATH_PROC_SOFTIRQS);
> +		else
> +			input = strdup(_PATH_PROC_INTERRUPTS);
> +		if (!input)
> +			err_oom();
> +	}
> +
>   	/* default */
>   	if (!out.ncolumns) {
>   		out.columns[out.ncolumns++] = COL_IRQ;
> @@ -171,8 +189,10 @@ int main(int argc, char **argv)
>   				irq_column_name_to_id) < 0)
>   		exit(EXIT_FAILURE);
>   
> -	if (print_irq_data(&out, softirq, threshold, setsize, cpuset) < 0)
> +	if (print_irq_data(input, &out, softirq, threshold, setsize, cpuset) < 0)
>   		return EXIT_FAILURE;
>   
> +	free(input);
> +
>   	return EXIT_SUCCESS;
>   }


^ permalink raw reply

* Re: [PATCH 1/3] irqtop: add batch mode support
From: zhenwei pi @ 2025-02-28  1:34 UTC (permalink / raw)
  To: Joe Jin, Karel Zak, Sami Kerola; +Cc: util-linux
In-Reply-To: <20250227044916.89925-2-joe.jin@oracle.com>

Hi Joe,

I'm a little confused about 'batch'...

Rather than the original terminal formatted style, the new change brings 
'raw' style?

What about 'raw'? Hi Karel, what do you think of this?

On 2/27/25 12:49, Joe Jin wrote:
> Add batch mode support, which could be useful for sending output to
> other programs or to a file.
> 
> Signed-off-by: Joe Jin <joe.jin@oracle.com>
> Cc: Zhenwei Pi <pizhenwei@bytedance.com>
> Cc: Sami Kerola <kerolasa@iki.fi>
> ---
>   bash-completion/irqtop  |  6 +++-
>   sys-utils/irqtop.1.adoc |  3 ++
>   sys-utils/irqtop.c      | 79 ++++++++++++++++++++++++++++-------------
>   3 files changed, 63 insertions(+), 25 deletions(-)
> 
> diff --git a/bash-completion/irqtop b/bash-completion/irqtop
> index b9e454d4c..215281ee8 100644
> --- a/bash-completion/irqtop
> +++ b/bash-completion/irqtop
> @@ -5,6 +5,9 @@ _irqtop_module()
>   	cur="${COMP_WORDS[COMP_CWORD]}"
>   	prev="${COMP_WORDS[COMP_CWORD-1]}"
>   	case $prev in
> +		'-b'|'--batch')
> +			return 0
> +			;;
>   		'-c'|'--cpu-stat')
>   			COMPREPLY=( $(compgen -W "auto enable disable" -- $cur) )
>   			return 0
> @@ -40,7 +43,8 @@ _irqtop_module()
>   			return 0
>   			;;
>   	esac
> -	OPTS="	--cpu-stat
> +	OPTS="	--batch
> +		--cpu-stat
>   		--cpu-list
>   		--delay
>   		--sort
> diff --git a/sys-utils/irqtop.1.adoc b/sys-utils/irqtop.1.adoc
> index 443e23b84..e81f4fbb6 100644
> --- a/sys-utils/irqtop.1.adoc
> +++ b/sys-utils/irqtop.1.adoc
> @@ -25,6 +25,9 @@ The default output is subject to change. So whenever possible, you should avoid
>   *-o*, *--output* _list_::
>   Specify which output columns to print. Use *--help* to get a list of all supported columns. The default list of columns may be extended if list is specified in the format _+list_.
>   
> +*-b*, *--batch*::
> +Starts irqtop in batch mode, which could be useful for sending output to other programs or to a file.
> +
>   *-c*, *--cpu-stat* _mode_::
>   Show per-cpu statistics by specified mode. Available modes are: *auto*, *enable*, *disable*. The default option *auto* detects the width of window, then shows the per-cpu statistics if the width of window is large enough to show a full line of statistics.
>   
> diff --git a/sys-utils/irqtop.c b/sys-utils/irqtop.c
> index 8fbedb16a..00bf8fe50 100644
> --- a/sys-utils/irqtop.c
> +++ b/sys-utils/irqtop.c
> @@ -83,10 +83,22 @@ struct irqtop_ctl {
>   	cpu_set_t *cpuset;
>   
>   	enum irqtop_cpustat_mode cpustat_mode;
> +	bool	batch;
>   	bool	request_exit,
>   		softirq;
>   };
>   
> +#define irqtop_batch_mode(ctl) ((ctl)->batch == true)
> +#define irqtop_printf(ctl, fmt, args...)		\
> +	do { 						\
> +		if (irqtop_batch_mode(ctl))		\
> +			fprintf(stdout, fmt, ##args);	\
> +		else {					\
> +			wprintw(ctl->win, fmt, ##args);	\
> +		}					\
> +	}while(0)
> +
> +
>   /* user's input parser */
>   static void parse_input(struct irqtop_ctl *ctl, struct irq_output *out, char c)
>   {
> @@ -128,16 +140,19 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
>   			scols_table_enable_nowrap(cpus, 1);
>   	}
>   
> -	/* print header */
> -	move(0, 0);
>   	strtime_iso(&now, ISO_TIMESTAMP, timestr, sizeof(timestr));
> -	wprintw(ctl->win, _("irqtop | total: %ld delta: %ld | %s | %s\n\n"),
> +	if (!irqtop_batch_mode(ctl))
> +		move(0, 0);
> +
> +	/* print header */
> +	irqtop_printf(ctl, _("irqtop | total: %ld delta: %ld | %s | %s\n\n"),
>   			   stat->total_irq, stat->delta_irq, ctl->hostname, timestr);
>   
> +
>   	/* print cpus table or not by -c option */
>   	if (cpus) {
>   		scols_print_table_to_string(cpus, &data);
> -		wprintw(ctl->win, "%s\n\n", data);
> +		irqtop_printf(ctl, "%s\n\n", data);
>   		free(data);
>   	}
>   
> @@ -149,13 +164,15 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
>   	if (p) {
>   		/* print header in reverse mode */
>   		*p = '\0';
> -		attron(A_REVERSE);
> -		wprintw(ctl->win, "%s\n", data);
> -		attroff(A_REVERSE);
> +		if (!irqtop_batch_mode(ctl))
> +			attron(A_REVERSE);
> +		irqtop_printf(ctl, "%s\n", data);
> +		if (!irqtop_batch_mode(ctl))
> +			attroff(A_REVERSE);
>   		data = p + 1;
>   	}
>   
> -	wprintw(ctl->win, "%s", data);
> +	irqtop_printf(ctl, "%s\n", data);
>   	free(data0);
>   
>   	/* clean up */
> @@ -212,7 +229,8 @@ static int event_loop(struct irqtop_ctl *ctl, struct irq_output *out)
>   		err(EXIT_FAILURE, _("epoll_ctl failed"));
>   
>   	retval |= update_screen(ctl, out);
> -	refresh();
> +	if (!irqtop_batch_mode(ctl))
> +		refresh();
>   
>   	while (!ctl->request_exit) {
>   		const ssize_t nr_events = epoll_wait(efd, events, MAX_EVENTS, -1);
> @@ -227,10 +245,12 @@ static int event_loop(struct irqtop_ctl *ctl, struct irq_output *out)
>   					continue;
>   				}
>   				if (siginfo.ssi_signo == SIGWINCH) {
> -					get_terminal_dimension(&ctl->cols, &ctl->rows);
> +					if (!irqtop_batch_mode(ctl)) {
> +						get_terminal_dimension(&ctl->cols, &ctl->rows);
>   #if HAVE_RESIZETERM
> -					resizeterm(ctl->rows, ctl->cols);
> +						resizeterm(ctl->rows, ctl->cols);
>   #endif
> +					}
>   				}
>   				else {
>   					ctl->request_exit = 1;
> @@ -245,7 +265,8 @@ static int event_loop(struct irqtop_ctl *ctl, struct irq_output *out)
>   			} else
>   				abort();
>   			retval |= update_screen(ctl, out);
> -			refresh();
> +			if (!irqtop_batch_mode(ctl))
> +				refresh();
>   		}
>   	}
>   	return retval;
> @@ -260,6 +281,7 @@ static void __attribute__((__noreturn__)) usage(void)
>   	puts(_("Interactive utility to display kernel interrupt information."));
>   
>   	fputs(USAGE_OPTIONS, stdout);
> +	fputs(_(" -b, --batch batch mode\n"), stdout);
>   	fputs(_(" -c, --cpu-stat <mode> show per-cpu stat (auto, enable, disable)\n"), stdout);
>   	fputs(_(" -C, --cpu-list <list> specify cpus in list format\n"), stdout);
>   	fputs(_(" -d, --delay <secs>   delay updates\n"), stdout);
> @@ -291,6 +313,7 @@ static void parse_args(	struct irqtop_ctl *ctl,
>   {
>   	const char *outarg = NULL;
>   	static const struct option longopts[] = {
> +		{"batch", no_argument, NULL, 'b'},
>   		{"cpu-stat", required_argument, NULL, 'c'},
>   		{"cpu-list", required_argument, NULL, 'C'},
>   		{"delay", required_argument, NULL, 'd'},
> @@ -304,8 +327,11 @@ static void parse_args(	struct irqtop_ctl *ctl,
>   	};
>   	int o;
>   
> -	while ((o = getopt_long(argc, argv, "c:C:d:o:s:St:hV", longopts, NULL)) != -1) {
> +	while ((o = getopt_long(argc, argv, "bc:C:d:o:s:St:hV", longopts, NULL)) != -1) {
>   		switch (o) {
> +		case 'b':
> +			ctl->batch = true;
> +			break;
>   		case 'c':
>   			if (!strcmp(optarg, "auto"))
>   				ctl->cpustat_mode = IRQTOP_CPUSTAT_AUTO;
> @@ -394,16 +420,18 @@ int main(int argc, char **argv)
>   
>   	parse_args(&ctl, &out, argc, argv);
>   
> -	is_tty = isatty(STDIN_FILENO);
> -	if (is_tty && tcgetattr(STDIN_FILENO, &saved_tty) == -1)
> -		fputs(_("terminal setting retrieval"), stdout);
> +	if (ctl.batch == false) {
> +		is_tty = isatty(STDIN_FILENO);
> +		if (is_tty && tcgetattr(STDIN_FILENO, &saved_tty) == -1)
> +			fputs(_("terminal setting retrieval"), stdout);
>   
> -	ctl.win = initscr();
> -	get_terminal_dimension(&ctl.cols, &ctl.rows);
> +		ctl.win = initscr();
> +		get_terminal_dimension(&ctl.cols, &ctl.rows);
>   #if HAVE_RESIZETERM
> -	resizeterm(ctl.rows, ctl.cols);
> +		resizeterm(ctl.rows, ctl.cols);
>   #endif
> -	curs_set(0);
> +		curs_set(0);
> +	}
>   
>   	ctl.hostname = xgethostname();
>   	event_loop(&ctl, &out);
> @@ -412,10 +440,13 @@ int main(int argc, char **argv)
>   	free(ctl.hostname);
>   	cpuset_free(ctl.cpuset);
>   
> -	if (is_tty)
> -		tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tty);
> -	delwin(ctl.win);
> -	endwin();
> +	if (ctl.batch == false) {
> +		if (is_tty)
> +			tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tty);
> +
> +		delwin(ctl.win);
> +		endwin();
> +	}
>   
>   	return EXIT_SUCCESS;
>   }


^ permalink raw reply

* Re: [PATCH 0/3] irqtop,lsirq: Miscellaneous enhancements
From: Joe Jin @ 2025-02-27 19:49 UTC (permalink / raw)
  To: kerolasa; +Cc: Karel Zak, Zhenwei Pi, util-linux
In-Reply-To: <CAG27Bk0tKeqnPbpuZ27aqd=2q7sx8yt263Mdq-3jock0ePymVg@mail.gmail.com>

On 2/26/25 23:36, Sami Kerola wrote:
> On Thu, 27 Feb 2025 at 04:49, Joe Jin <joe.jin@oracle.com> wrote:
>> This patchset add below new options:
>>  '-b|--batch' : Batch mode
>>  '-n|--number': specifies the maximum number of iterations
>>  '-i|--input' : Read data from file
> Thanks for contribution,
>
> If batch mode is added the tool should also gain --json option for
> structured output.

Will add new option for json output format support.

Thanks,
Joe
>


^ permalink raw reply

* Re: [PATCH 3/3] lsirq,irqtop: add support for reading data from given file
From: Joe Jin @ 2025-02-27 18:33 UTC (permalink / raw)
  To: Karel Zak; +Cc: Zhenwei Pi, Sami Kerola, util-linux
In-Reply-To: <tzkpkjopbtqlpmeic2xoephezgfl63xa5e4eytycmg24cbnx4q@qamwltb7ol6y>

On 2/27/25 01:30, Karel Zak wrote:
> On Wed, Feb 26, 2025 at 08:49:16PM GMT, Joe Jin wrote:
>> +	if (ctl->input == NULL) {
>> +		if (ctl->softirq == 1)
>> +			ctl->input = strdup(_PATH_PROC_SOFTIRQS);
>> +		else
>> +			ctl->input = strdup(_PATH_PROC_INTERRUPTS);
>> +		if (!ctl->input)
>> +			err_oom();
>> +	}
>  Please, use xstrdup(), than you do not need to care about result and
>  use err_oom();
Will make change for this, thanks for your suggestions.

Thanks,
Joe

^ permalink raw reply

* Re: [PATCH 2/3] irqtop: add max iteration support
From: Joe Jin @ 2025-02-27 18:32 UTC (permalink / raw)
  To: Karel Zak; +Cc: Zhenwei Pi, Sami Kerola, util-linux
In-Reply-To: <pr4fky3knju6kxdk7tkdffc6qcxrintim4y42aoj4rcfrn2wk4@2no665wcutja>

On 2/27/25 01:28, Karel Zak wrote:
> On Wed, Feb 26, 2025 at 08:49:15PM GMT, Joe Jin wrote:
>>  	enum irqtop_cpustat_mode cpustat_mode;
>> +	int64_t	number;
> Can we find a better name for the variable and the option?
>
>   --nloops 
>   --repeat

How about of "--iter"?

Thanks,
Joe
>
> or so ;-)
>
>     Karel
>


^ permalink raw reply

* Re: [PATCH 1/3] irqtop: add batch mode support
From: Joe Jin @ 2025-02-27 18:30 UTC (permalink / raw)
  To: Karel Zak; +Cc: Zhenwei Pi, Sami Kerola, util-linux
In-Reply-To: <3cip52rtte72zolbb2ta6ztl63p4ez7oo2wmi5fpqvjxz45jwk@akiqt56yf4vs>

On 2/27/25 01:25, Karel Zak wrote:
> On Wed, Feb 26, 2025 at 08:49:14PM GMT, Joe Jin wrote:
>> +#define irqtop_batch_mode(ctl) ((ctl)->batch == true)
> Do we need this macro? I think use
>
>  if (ctl->batch)
>    ...
> or
>
>  if (!ctl->batch)
>    ...
>
> in the code is good enough.

I'll remove the macro.

>
>> +#define irqtop_printf(ctl, fmt, args...)		\
>> +	do { 						\
>> +		if (irqtop_batch_mode(ctl))		\
>> +			fprintf(stdout, fmt, ##args);	\
>> +		else {					\
>> +			wprintw(ctl->win, fmt, ##args);	\
>> +		}					\
>> +	}while(0)
> It would be more robust to use an inline function with vw_printw() and
> vfprintf() rather than a macro with a variadic number of arguments, or
> use __VA_ARGS__ in the macro.

Thanks for your suggestions, I'll create an inline function.

Thanks,
Joe

>
>     Karel
>


^ permalink raw reply

* Re: [PATCH 3/3] lsirq,irqtop: add support for reading data from given file
From: Karel Zak @ 2025-02-27  9:30 UTC (permalink / raw)
  To: Joe Jin; +Cc: Zhenwei Pi, Sami Kerola, util-linux
In-Reply-To: <20250227044916.89925-4-joe.jin@oracle.com>

On Wed, Feb 26, 2025 at 08:49:16PM GMT, Joe Jin wrote:
> +	if (ctl->input == NULL) {
> +		if (ctl->softirq == 1)
> +			ctl->input = strdup(_PATH_PROC_SOFTIRQS);
> +		else
> +			ctl->input = strdup(_PATH_PROC_INTERRUPTS);
> +		if (!ctl->input)
> +			err_oom();
> +	}

 Please, use xstrdup(), than you do not need to care about result and
 use err_oom();

    Karel
-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply

* Re: [PATCH 2/3] irqtop: add max iteration support
From: Karel Zak @ 2025-02-27  9:28 UTC (permalink / raw)
  To: Joe Jin; +Cc: Zhenwei Pi, Sami Kerola, util-linux
In-Reply-To: <20250227044916.89925-3-joe.jin@oracle.com>

On Wed, Feb 26, 2025 at 08:49:15PM GMT, Joe Jin wrote:
>  	enum irqtop_cpustat_mode cpustat_mode;
> +	int64_t	number;

Can we find a better name for the variable and the option?

  --nloops 
  --repeat

or so ;-)

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply

* Re: [PATCH 1/3] irqtop: add batch mode support
From: Karel Zak @ 2025-02-27  9:25 UTC (permalink / raw)
  To: Joe Jin; +Cc: Zhenwei Pi, Sami Kerola, util-linux
In-Reply-To: <20250227044916.89925-2-joe.jin@oracle.com>

On Wed, Feb 26, 2025 at 08:49:14PM GMT, Joe Jin wrote:
> +#define irqtop_batch_mode(ctl) ((ctl)->batch == true)

Do we need this macro? I think use

 if (ctl->batch)
   ...
or

 if (!ctl->batch)
   ...

in the code is good enough.

> +#define irqtop_printf(ctl, fmt, args...)		\
> +	do { 						\
> +		if (irqtop_batch_mode(ctl))		\
> +			fprintf(stdout, fmt, ##args);	\
> +		else {					\
> +			wprintw(ctl->win, fmt, ##args);	\
> +		}					\
> +	}while(0)

It would be more robust to use an inline function with vw_printw() and
vfprintf() rather than a macro with a variadic number of arguments, or
use __VA_ARGS__ in the macro.

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply

* Re: [PATCH 0/3] irqtop,lsirq: Miscellaneous enhancements
From: Sami Kerola @ 2025-02-27  7:36 UTC (permalink / raw)
  To: Joe Jin; +Cc: Karel Zak, Zhenwei Pi, util-linux
In-Reply-To: <20250227044916.89925-1-joe.jin@oracle.com>

On Thu, 27 Feb 2025 at 04:49, Joe Jin <joe.jin@oracle.com> wrote:
> This patchset add below new options:
>  '-b|--batch' : Batch mode
>  '-n|--number': specifies the maximum number of iterations
>  '-i|--input' : Read data from file

Thanks for contribution,

If batch mode is added the tool should also gain --json option for
structured output.

-- 
Sami Kerola
https://kerolasa.iki.fi/

^ permalink raw reply

* [PATCH 2/3] irqtop: add max iteration support
From: Joe Jin @ 2025-02-27  4:49 UTC (permalink / raw)
  To: Karel Zak, Zhenwei Pi, Sami Kerola; +Cc: util-linux, Joe Jin
In-Reply-To: <20250227044916.89925-1-joe.jin@oracle.com>

Add support for setting the number of iterations. This is useful in
non-interactive mode.

Signed-off-by: Joe Jin <joe.jin@oracle.com>
Cc: Zhenwei Pi <pizhenwei@bytedance.com>
Cc: Sami Kerola <kerolasa@iki.fi>
---
 bash-completion/irqtop  |  5 +++++
 sys-utils/irqtop.1.adoc |  3 +++
 sys-utils/irqtop.c      | 19 +++++++++++++++++--
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/bash-completion/irqtop b/bash-completion/irqtop
index 215281ee8..47b7b0af6 100644
--- a/bash-completion/irqtop
+++ b/bash-completion/irqtop
@@ -22,6 +22,10 @@ _irqtop_module()
 			COMPREPLY=( $(compgen -W "secs" -- $cur) )
 			return 0
 			;;
+		'-n'|'--number')
+			COMPREPLY=( $(compgen -W "the max iterations" -- $cur) )
+			return 0
+			;;
 		'-s'|'--sort')
 			COMPREPLY=( $(compgen -W "irq total delta name" -- $cur) )
 			return 0
@@ -47,6 +51,7 @@ _irqtop_module()
 		--cpu-stat
 		--cpu-list
 		--delay
+		--number
 		--sort
 		--output
 		--softirq
diff --git a/sys-utils/irqtop.1.adoc b/sys-utils/irqtop.1.adoc
index e81f4fbb6..75cfe2e41 100644
--- a/sys-utils/irqtop.1.adoc
+++ b/sys-utils/irqtop.1.adoc
@@ -37,6 +37,9 @@ Specify cpus in list format to show.
 *-d*, *--delay* _seconds_::
 Update interrupt output every _seconds_ intervals.
 
+*-n*, *--number* _number_::
+Specifies the maximum _number_ of iterations before quitting.
+
 *-s*, *--sort* _column_::
 Specify sort criteria by column name. See *--help* output to get column names. The sort criteria may be changes in interactive mode.
 
diff --git a/sys-utils/irqtop.c b/sys-utils/irqtop.c
index 00bf8fe50..ba5680671 100644
--- a/sys-utils/irqtop.c
+++ b/sys-utils/irqtop.c
@@ -83,6 +83,7 @@ struct irqtop_ctl {
 	cpu_set_t *cpuset;
 
 	enum irqtop_cpustat_mode cpustat_mode;
+	int64_t	number;
 	bool	batch;
 	bool	request_exit,
 		softirq;
@@ -180,6 +181,12 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
 	if (ctl->prev_stat)
 		free_irqstat(ctl->prev_stat);
 	ctl->prev_stat = stat;
+
+	if (ctl->number > 0) {
+		ctl->number--;
+		if (ctl->number == 0)
+			ctl->request_exit = 1;
+	}
 	return 0;
 }
 
@@ -285,6 +292,7 @@ static void __attribute__((__noreturn__)) usage(void)
 	fputs(_(" -c, --cpu-stat <mode> show per-cpu stat (auto, enable, disable)\n"), stdout);
 	fputs(_(" -C, --cpu-list <list> specify cpus in list format\n"), stdout);
 	fputs(_(" -d, --delay <secs>   delay updates\n"), stdout);
+	fputs(_(" -n, --number <number> the maximum number of iterations\n"), stdout);
 	fputs(_(" -o, --output <list>  define which output columns to use\n"), stdout);
 	fputs(_(" -s, --sort <column>  specify sort column\n"), stdout);
 	fputs(_(" -S, --softirq        show softirqs instead of interrupts\n"), stdout);
@@ -317,6 +325,7 @@ static void parse_args(	struct irqtop_ctl *ctl,
 		{"cpu-stat", required_argument, NULL, 'c'},
 		{"cpu-list", required_argument, NULL, 'C'},
 		{"delay", required_argument, NULL, 'd'},
+		{"number", required_argument, NULL, 'n'},
 		{"sort", required_argument, NULL, 's'},
 		{"output", required_argument, NULL, 'o'},
 		{"softirq", no_argument, NULL, 'S'},
@@ -327,7 +336,7 @@ static void parse_args(	struct irqtop_ctl *ctl,
 	};
 	int o;
 
-	while ((o = getopt_long(argc, argv, "bc:C:d:o:s:St:hV", longopts, NULL)) != -1) {
+	while ((o = getopt_long(argc, argv, "bc:C:d:n:o:s:St:hV", longopts, NULL)) != -1) {
 		switch (o) {
 		case 'b':
 			ctl->batch = true;
@@ -367,6 +376,11 @@ static void parse_args(	struct irqtop_ctl *ctl,
 				ctl->timer.it_value = ctl->timer.it_interval;
 			}
 			break;
+		case 'n':
+			ctl->number = str2num_or_err(optarg, 10,
+					_("failed to parse number argument"),
+					0, INT_MAX);
+			break;
 		case 's':
 			set_sort_func_by_name(out, optarg);
 			break;
@@ -413,7 +427,8 @@ int main(int argc, char **argv)
 	};
 	struct irqtop_ctl ctl = {
 		.timer.it_interval = {3, 0},
-		.timer.it_value = {3, 0}
+		.timer.it_value = {3, 0},
+		.number = -1
 	};
 
 	setlocale(LC_ALL, "");
-- 
2.43.5


^ permalink raw reply related

* [PATCH 3/3] lsirq,irqtop: add support for reading data from given file
From: Joe Jin @ 2025-02-27  4:49 UTC (permalink / raw)
  To: Karel Zak, Zhenwei Pi, Sami Kerola; +Cc: util-linux, Joe Jin
In-Reply-To: <20250227044916.89925-1-joe.jin@oracle.com>

This is helpful for analyzng data saved from other system.

Signed-off-by: Joe Jin <joe.jin@oracle.com>
Cc: Zhenwei Pi <pizhenwei@bytedance.com>
Cc: Sami Kerola <kerolasa@iki.fi>
---
 bash-completion/irqtop  |  4 ++++
 bash-completion/lsirq   |  4 ++++
 sys-utils/irq-common.c  | 19 +++++++++----------
 sys-utils/irq-common.h  |  3 ++-
 sys-utils/irqtop.1.adoc |  3 +++
 sys-utils/irqtop.c      | 28 +++++++++++++++++++++++++---
 sys-utils/lsirq.1.adoc  |  3 +++
 sys-utils/lsirq.c       | 28 ++++++++++++++++++++++++----
 8 files changed, 74 insertions(+), 18 deletions(-)

diff --git a/bash-completion/irqtop b/bash-completion/irqtop
index 47b7b0af6..3bea5fc0e 100644
--- a/bash-completion/irqtop
+++ b/bash-completion/irqtop
@@ -15,6 +15,9 @@ _irqtop_module()
 		'-C'|'--cpu-list')
 			return 0
 			;;
+		'-i'|'--input')
+			COMPREPLY=( $(compgen -W "input file" -- $cur) )
+			;;
 		'-t'|'--threshold')
 			return 0
 			;;
@@ -51,6 +54,7 @@ _irqtop_module()
 		--cpu-stat
 		--cpu-list
 		--delay
+		--input
 		--number
 		--sort
 		--output
diff --git a/bash-completion/lsirq b/bash-completion/lsirq
index 4c3c9f04f..b913eecd0 100644
--- a/bash-completion/lsirq
+++ b/bash-completion/lsirq
@@ -5,6 +5,9 @@ _lsirq_module()
 	cur="${COMP_WORDS[COMP_CWORD]}"
 	prev="${COMP_WORDS[COMP_CWORD-1]}"
 	case $prev in
+		'-i'|'--input')
+			COMPREPLY=( $(compgen -W "input file" -- $cur) )
+			;;
 		'-o'|'--output')
 			local prefix realcur OUTPUT
 			realcur="${cur##*,}"
@@ -35,6 +38,7 @@ _lsirq_module()
 	OPTS="	--json
 		--pairs
 		--noheadings
+		--input
 		--output
 		--softirq
 		--sort
diff --git a/sys-utils/irq-common.c b/sys-utils/irq-common.c
index f069d8a63..560dd4b82 100644
--- a/sys-utils/irq-common.c
+++ b/sys-utils/irq-common.c
@@ -233,7 +233,8 @@ static bool cpu_in_list(int cpu, size_t setsize, cpu_set_t *cpuset)
 /*
  * irqinfo - parse the system's interrupts
  */
-static struct irq_stat *get_irqinfo(int softirq, size_t setsize, cpu_set_t *cpuset)
+static struct irq_stat *get_irqinfo(const char *input_file, int softirq,
+				    size_t setsize, cpu_set_t *cpuset)
 {
 	FILE *irqfile;
 	char *line = NULL, *tmp;
@@ -247,18 +248,15 @@ static struct irq_stat *get_irqinfo(int softirq, size_t setsize, cpu_set_t *cpus
 	stat->irq_info = xmalloc(sizeof(*stat->irq_info) * IRQ_INFO_LEN);
 	stat->nr_irq_info = IRQ_INFO_LEN;
 
-	if (softirq)
-		irqfile = fopen(_PATH_PROC_SOFTIRQS, "r");
-	else
-		irqfile = fopen(_PATH_PROC_INTERRUPTS, "r");
+	irqfile = fopen(input_file, "r");
 	if (!irqfile) {
-		warn(_("cannot open %s"), _PATH_PROC_INTERRUPTS);
+		warn(_("cannot open %s"), input_file);
 		goto free_stat;
 	}
 
 	/* read header firstly */
 	if (getline(&line, &len, irqfile) < 0) {
-		warn(_("cannot read %s"), _PATH_PROC_INTERRUPTS);
+		warn(_("cannot read %s"), input_file);
 		goto close_file;
 	}
 
@@ -270,7 +268,7 @@ static struct irq_stat *get_irqinfo(int softirq, size_t setsize, cpu_set_t *cpus
 
 	stat->cpus =  xcalloc(stat->nr_active_cpu, sizeof(struct irq_cpu));
 
-	/* parse each line of _PATH_PROC_INTERRUPTS */
+	/* parse each line of input file */
 	while (getline(&line, &len, irqfile) >= 0) {
 		unsigned long count;
 		size_t index;
@@ -527,7 +525,8 @@ struct libscols_table *get_scols_cpus_table(struct irq_output *out,
 	return NULL;
 }
 
-struct libscols_table *get_scols_table(struct irq_output *out,
+struct libscols_table *get_scols_table(const char *input_file,
+					      struct irq_output *out,
 					      struct irq_stat *prev,
 					      struct irq_stat **xstat,
 					      int softirq,
@@ -542,7 +541,7 @@ struct libscols_table *get_scols_table(struct irq_output *out,
 	size_t i;
 
 	/* the stats */
-	stat = get_irqinfo(softirq, setsize, cpuset);
+	stat = get_irqinfo(input_file, softirq, setsize, cpuset);
 	if (!stat)
 		return NULL;
 
diff --git a/sys-utils/irq-common.h b/sys-utils/irq-common.h
index 02b72d752..b9cf72d2a 100644
--- a/sys-utils/irq-common.h
+++ b/sys-utils/irq-common.h
@@ -73,7 +73,8 @@ void irq_print_columns(FILE *f, int nodelta);
 void set_sort_func_by_name(struct irq_output *out, const char *name);
 void set_sort_func_by_key(struct irq_output *out, const char c);
 
-struct libscols_table *get_scols_table(struct irq_output *out,
+struct libscols_table *get_scols_table(const char *input_file,
+                                              struct irq_output *out,
                                               struct irq_stat *prev,
                                               struct irq_stat **xstat,
                                               int softirq,
diff --git a/sys-utils/irqtop.1.adoc b/sys-utils/irqtop.1.adoc
index 75cfe2e41..715008d07 100644
--- a/sys-utils/irqtop.1.adoc
+++ b/sys-utils/irqtop.1.adoc
@@ -37,6 +37,9 @@ Specify cpus in list format to show.
 *-d*, *--delay* _seconds_::
 Update interrupt output every _seconds_ intervals.
 
+*-i*, *--input* _file_::
+Read data from _file_ (Which was created by other tools, e.g. sosreport).
+
 *-n*, *--number* _number_::
 Specifies the maximum _number_ of iterations before quitting.
 
diff --git a/sys-utils/irqtop.c b/sys-utils/irqtop.c
index ba5680671..4cf1dc79a 100644
--- a/sys-utils/irqtop.c
+++ b/sys-utils/irqtop.c
@@ -87,6 +87,8 @@ struct irqtop_ctl {
 	bool	batch;
 	bool	request_exit,
 		softirq;
+
+	char	*input;
 };
 
 #define irqtop_batch_mode(ctl) ((ctl)->batch == true)
@@ -122,8 +124,9 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
 	char timestr[64], *data, *data0, *p;
 
 	/* make irqs table */
-	table = get_scols_table(out, ctl->prev_stat, &stat, ctl->softirq,
-				ctl->threshold, ctl->setsize, ctl->cpuset);
+	table = get_scols_table(ctl->input, out, ctl->prev_stat, &stat,
+				ctl->softirq, ctl->threshold, ctl->setsize,
+				ctl->cpuset);
 	if (!table) {
 		ctl->request_exit = 1;
 		return 1;
@@ -292,6 +295,7 @@ static void __attribute__((__noreturn__)) usage(void)
 	fputs(_(" -c, --cpu-stat <mode> show per-cpu stat (auto, enable, disable)\n"), stdout);
 	fputs(_(" -C, --cpu-list <list> specify cpus in list format\n"), stdout);
 	fputs(_(" -d, --delay <secs>   delay updates\n"), stdout);
+	fputs(_(" -i, --input <file>   read data from file\n"), stdout);
 	fputs(_(" -n, --number <number> the maximum number of iterations\n"), stdout);
 	fputs(_(" -o, --output <list>  define which output columns to use\n"), stdout);
 	fputs(_(" -s, --sort <column>  specify sort column\n"), stdout);
@@ -325,6 +329,7 @@ static void parse_args(	struct irqtop_ctl *ctl,
 		{"cpu-stat", required_argument, NULL, 'c'},
 		{"cpu-list", required_argument, NULL, 'C'},
 		{"delay", required_argument, NULL, 'd'},
+		{"input", required_argument, NULL, 'i'},
 		{"number", required_argument, NULL, 'n'},
 		{"sort", required_argument, NULL, 's'},
 		{"output", required_argument, NULL, 'o'},
@@ -336,7 +341,7 @@ static void parse_args(	struct irqtop_ctl *ctl,
 	};
 	int o;
 
-	while ((o = getopt_long(argc, argv, "bc:C:d:n:o:s:St:hV", longopts, NULL)) != -1) {
+	while ((o = getopt_long(argc, argv, "bc:C:d:i:n:o:s:St:hV", longopts, NULL)) != -1) {
 		switch (o) {
 		case 'b':
 			ctl->batch = true;
@@ -376,6 +381,13 @@ static void parse_args(	struct irqtop_ctl *ctl,
 				ctl->timer.it_value = ctl->timer.it_interval;
 			}
 			break;
+		case 'i':
+			ctl->input = strdup(optarg);
+			if (!ctl->input)
+				err_oom();
+			ctl->number = 1;
+			ctl->batch = true;
+			break;
 		case 'n':
 			ctl->number = str2num_or_err(optarg, 10,
 					_("failed to parse number argument"),
@@ -402,6 +414,15 @@ static void parse_args(	struct irqtop_ctl *ctl,
 		}
 	}
 
+	if (ctl->input == NULL) {
+		if (ctl->softirq == 1)
+			ctl->input = strdup(_PATH_PROC_SOFTIRQS);
+		else
+			ctl->input = strdup(_PATH_PROC_INTERRUPTS);
+		if (!ctl->input)
+			err_oom();
+	}
+
 	/* default */
 	if (!out->ncolumns) {
 		out->columns[out->ncolumns++] = COL_IRQ;
@@ -453,6 +474,7 @@ int main(int argc, char **argv)
 
 	free_irqstat(ctl.prev_stat);
 	free(ctl.hostname);
+	free(ctl.input);
 	cpuset_free(ctl.cpuset);
 
 	if (ctl.batch == false) {
diff --git a/sys-utils/lsirq.1.adoc b/sys-utils/lsirq.1.adoc
index 02aea16b3..dd265710c 100644
--- a/sys-utils/lsirq.1.adoc
+++ b/sys-utils/lsirq.1.adoc
@@ -25,6 +25,9 @@ The default output is subject to change. So whenever possible, you should avoid
 *-n*, *--noheadings*::
 Don't print headings.
 
+*-i*, *--input* _file_::
+Read data from _file_ (Which was created by other tools, e.g. sosreport).
+
 *-o*, *--output* _list_::
 Specify which output columns to print. Use *--help* to get a list of all supported columns. The default list of columns may be extended if list is specified in the format _+list_.
 
diff --git a/sys-utils/lsirq.c b/sys-utils/lsirq.c
index e31addaf5..45d542919 100644
--- a/sys-utils/lsirq.c
+++ b/sys-utils/lsirq.c
@@ -29,16 +29,17 @@
 #include "optutils.h"
 #include "strutils.h"
 #include "xalloc.h"
+#include "pathnames.h"
 
 #include "irq-common.h"
 
-static int print_irq_data(struct irq_output *out,
+static int print_irq_data(const char *input_file, struct irq_output *out,
 			  int softirq, unsigned long threshold,
 			  size_t setsize, cpu_set_t *cpuset)
 {
 	struct libscols_table *table;
 
-	table = get_scols_table(out, NULL, NULL, softirq, threshold, setsize, cpuset);
+	table = get_scols_table(input_file, out, NULL, NULL, softirq, threshold, setsize, cpuset);
 	if (!table)
 		return -1;
 
@@ -58,6 +59,7 @@ static void __attribute__((__noreturn__)) usage(void)
 	fputs(USAGE_OPTIONS, stdout);
 	fputs(_(" -J, --json           use JSON output format\n"), stdout);
 	fputs(_(" -P, --pairs          use key=\"value\" output format\n"), stdout);
+	fputs(_(" -i, --input          read data from input file\n"), stdout);
 	fputs(_(" -n, --noheadings     don't print headings\n"), stdout);
 	fputs(_(" -o, --output <list>  define which output columns to use\n"), stdout);
 	fputs(_(" -s, --sort <column>  specify sort column\n"), stdout);
@@ -82,6 +84,7 @@ int main(int argc, char **argv)
 	static const struct option longopts[] = {
 		{"sort", required_argument, NULL, 's'},
 		{"noheadings", no_argument, NULL, 'n'},
+		{"input", required_argument, NULL, 'i'},
 		{"output", required_argument, NULL, 'o'},
 		{"threshold", required_argument, NULL, 't'},
 		{"cpu-list", required_argument, NULL, 'C'},
@@ -103,10 +106,11 @@ int main(int argc, char **argv)
 	cpu_set_t *cpuset = NULL;
 	size_t setsize = 0;
 	int softirq = 0;
+	char *input = NULL;
 
 	setlocale(LC_ALL, "");
 
-	while ((c = getopt_long(argc, argv, "no:s:t:C:ShJPV", longopts, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "i:no:s:t:C:ShJPV", longopts, NULL)) != -1) {
 		err_exclusive_options(c, longopts, excl, excl_st);
 
 		switch (c) {
@@ -116,6 +120,11 @@ int main(int argc, char **argv)
 		case 'P':
 			out.pairs = 1;
 			break;
+		case 'i':
+			input = strdup(optarg);
+			if (!input)
+				err_oom();
+			break;
 		case 'n':
 			out.no_headings = 1;
 			break;
@@ -157,6 +166,15 @@ int main(int argc, char **argv)
 		}
 	}
 
+	if (input == NULL) {
+		if (softirq == 1)
+			input = strdup(_PATH_PROC_SOFTIRQS);
+		else
+			input = strdup(_PATH_PROC_INTERRUPTS);
+		if (!input)
+			err_oom();
+	}
+
 	/* default */
 	if (!out.ncolumns) {
 		out.columns[out.ncolumns++] = COL_IRQ;
@@ -171,8 +189,10 @@ int main(int argc, char **argv)
 				irq_column_name_to_id) < 0)
 		exit(EXIT_FAILURE);
 
-	if (print_irq_data(&out, softirq, threshold, setsize, cpuset) < 0)
+	if (print_irq_data(input, &out, softirq, threshold, setsize, cpuset) < 0)
 		return EXIT_FAILURE;
 
+	free(input);
+
 	return EXIT_SUCCESS;
 }
-- 
2.43.5


^ permalink raw reply related

* [PATCH 1/3] irqtop: add batch mode support
From: Joe Jin @ 2025-02-27  4:49 UTC (permalink / raw)
  To: Karel Zak, Zhenwei Pi, Sami Kerola; +Cc: util-linux, Joe Jin
In-Reply-To: <20250227044916.89925-1-joe.jin@oracle.com>

Add batch mode support, which could be useful for sending output to
other programs or to a file.

Signed-off-by: Joe Jin <joe.jin@oracle.com>
Cc: Zhenwei Pi <pizhenwei@bytedance.com>
Cc: Sami Kerola <kerolasa@iki.fi>
---
 bash-completion/irqtop  |  6 +++-
 sys-utils/irqtop.1.adoc |  3 ++
 sys-utils/irqtop.c      | 79 ++++++++++++++++++++++++++++-------------
 3 files changed, 63 insertions(+), 25 deletions(-)

diff --git a/bash-completion/irqtop b/bash-completion/irqtop
index b9e454d4c..215281ee8 100644
--- a/bash-completion/irqtop
+++ b/bash-completion/irqtop
@@ -5,6 +5,9 @@ _irqtop_module()
 	cur="${COMP_WORDS[COMP_CWORD]}"
 	prev="${COMP_WORDS[COMP_CWORD-1]}"
 	case $prev in
+		'-b'|'--batch')
+			return 0
+			;;
 		'-c'|'--cpu-stat')
 			COMPREPLY=( $(compgen -W "auto enable disable" -- $cur) )
 			return 0
@@ -40,7 +43,8 @@ _irqtop_module()
 			return 0
 			;;
 	esac
-	OPTS="	--cpu-stat
+	OPTS="	--batch
+		--cpu-stat
 		--cpu-list
 		--delay
 		--sort
diff --git a/sys-utils/irqtop.1.adoc b/sys-utils/irqtop.1.adoc
index 443e23b84..e81f4fbb6 100644
--- a/sys-utils/irqtop.1.adoc
+++ b/sys-utils/irqtop.1.adoc
@@ -25,6 +25,9 @@ The default output is subject to change. So whenever possible, you should avoid
 *-o*, *--output* _list_::
 Specify which output columns to print. Use *--help* to get a list of all supported columns. The default list of columns may be extended if list is specified in the format _+list_.
 
+*-b*, *--batch*::
+Starts irqtop in batch mode, which could be useful for sending output to other programs or to a file.
+
 *-c*, *--cpu-stat* _mode_::
 Show per-cpu statistics by specified mode. Available modes are: *auto*, *enable*, *disable*. The default option *auto* detects the width of window, then shows the per-cpu statistics if the width of window is large enough to show a full line of statistics.
 
diff --git a/sys-utils/irqtop.c b/sys-utils/irqtop.c
index 8fbedb16a..00bf8fe50 100644
--- a/sys-utils/irqtop.c
+++ b/sys-utils/irqtop.c
@@ -83,10 +83,22 @@ struct irqtop_ctl {
 	cpu_set_t *cpuset;
 
 	enum irqtop_cpustat_mode cpustat_mode;
+	bool	batch;
 	bool	request_exit,
 		softirq;
 };
 
+#define irqtop_batch_mode(ctl) ((ctl)->batch == true)
+#define irqtop_printf(ctl, fmt, args...)		\
+	do { 						\
+		if (irqtop_batch_mode(ctl))		\
+			fprintf(stdout, fmt, ##args);	\
+		else {					\
+			wprintw(ctl->win, fmt, ##args);	\
+		}					\
+	}while(0)
+
+
 /* user's input parser */
 static void parse_input(struct irqtop_ctl *ctl, struct irq_output *out, char c)
 {
@@ -128,16 +140,19 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
 			scols_table_enable_nowrap(cpus, 1);
 	}
 
-	/* print header */
-	move(0, 0);
 	strtime_iso(&now, ISO_TIMESTAMP, timestr, sizeof(timestr));
-	wprintw(ctl->win, _("irqtop | total: %ld delta: %ld | %s | %s\n\n"),
+	if (!irqtop_batch_mode(ctl))
+		move(0, 0);
+
+	/* print header */
+	irqtop_printf(ctl, _("irqtop | total: %ld delta: %ld | %s | %s\n\n"),
 			   stat->total_irq, stat->delta_irq, ctl->hostname, timestr);
 
+
 	/* print cpus table or not by -c option */
 	if (cpus) {
 		scols_print_table_to_string(cpus, &data);
-		wprintw(ctl->win, "%s\n\n", data);
+		irqtop_printf(ctl, "%s\n\n", data);
 		free(data);
 	}
 
@@ -149,13 +164,15 @@ static int update_screen(struct irqtop_ctl *ctl, struct irq_output *out)
 	if (p) {
 		/* print header in reverse mode */
 		*p = '\0';
-		attron(A_REVERSE);
-		wprintw(ctl->win, "%s\n", data);
-		attroff(A_REVERSE);
+		if (!irqtop_batch_mode(ctl))
+			attron(A_REVERSE);
+		irqtop_printf(ctl, "%s\n", data);
+		if (!irqtop_batch_mode(ctl))
+			attroff(A_REVERSE);
 		data = p + 1;
 	}
 
-	wprintw(ctl->win, "%s", data);
+	irqtop_printf(ctl, "%s\n", data);
 	free(data0);
 
 	/* clean up */
@@ -212,7 +229,8 @@ static int event_loop(struct irqtop_ctl *ctl, struct irq_output *out)
 		err(EXIT_FAILURE, _("epoll_ctl failed"));
 
 	retval |= update_screen(ctl, out);
-	refresh();
+	if (!irqtop_batch_mode(ctl))
+		refresh();
 
 	while (!ctl->request_exit) {
 		const ssize_t nr_events = epoll_wait(efd, events, MAX_EVENTS, -1);
@@ -227,10 +245,12 @@ static int event_loop(struct irqtop_ctl *ctl, struct irq_output *out)
 					continue;
 				}
 				if (siginfo.ssi_signo == SIGWINCH) {
-					get_terminal_dimension(&ctl->cols, &ctl->rows);
+					if (!irqtop_batch_mode(ctl)) {
+						get_terminal_dimension(&ctl->cols, &ctl->rows);
 #if HAVE_RESIZETERM
-					resizeterm(ctl->rows, ctl->cols);
+						resizeterm(ctl->rows, ctl->cols);
 #endif
+					}
 				}
 				else {
 					ctl->request_exit = 1;
@@ -245,7 +265,8 @@ static int event_loop(struct irqtop_ctl *ctl, struct irq_output *out)
 			} else
 				abort();
 			retval |= update_screen(ctl, out);
-			refresh();
+			if (!irqtop_batch_mode(ctl))
+				refresh();
 		}
 	}
 	return retval;
@@ -260,6 +281,7 @@ static void __attribute__((__noreturn__)) usage(void)
 	puts(_("Interactive utility to display kernel interrupt information."));
 
 	fputs(USAGE_OPTIONS, stdout);
+	fputs(_(" -b, --batch batch mode\n"), stdout);
 	fputs(_(" -c, --cpu-stat <mode> show per-cpu stat (auto, enable, disable)\n"), stdout);
 	fputs(_(" -C, --cpu-list <list> specify cpus in list format\n"), stdout);
 	fputs(_(" -d, --delay <secs>   delay updates\n"), stdout);
@@ -291,6 +313,7 @@ static void parse_args(	struct irqtop_ctl *ctl,
 {
 	const char *outarg = NULL;
 	static const struct option longopts[] = {
+		{"batch", no_argument, NULL, 'b'},
 		{"cpu-stat", required_argument, NULL, 'c'},
 		{"cpu-list", required_argument, NULL, 'C'},
 		{"delay", required_argument, NULL, 'd'},
@@ -304,8 +327,11 @@ static void parse_args(	struct irqtop_ctl *ctl,
 	};
 	int o;
 
-	while ((o = getopt_long(argc, argv, "c:C:d:o:s:St:hV", longopts, NULL)) != -1) {
+	while ((o = getopt_long(argc, argv, "bc:C:d:o:s:St:hV", longopts, NULL)) != -1) {
 		switch (o) {
+		case 'b':
+			ctl->batch = true;
+			break;
 		case 'c':
 			if (!strcmp(optarg, "auto"))
 				ctl->cpustat_mode = IRQTOP_CPUSTAT_AUTO;
@@ -394,16 +420,18 @@ int main(int argc, char **argv)
 
 	parse_args(&ctl, &out, argc, argv);
 
-	is_tty = isatty(STDIN_FILENO);
-	if (is_tty && tcgetattr(STDIN_FILENO, &saved_tty) == -1)
-		fputs(_("terminal setting retrieval"), stdout);
+	if (ctl.batch == false) {
+		is_tty = isatty(STDIN_FILENO);
+		if (is_tty && tcgetattr(STDIN_FILENO, &saved_tty) == -1)
+			fputs(_("terminal setting retrieval"), stdout);
 
-	ctl.win = initscr();
-	get_terminal_dimension(&ctl.cols, &ctl.rows);
+		ctl.win = initscr();
+		get_terminal_dimension(&ctl.cols, &ctl.rows);
 #if HAVE_RESIZETERM
-	resizeterm(ctl.rows, ctl.cols);
+		resizeterm(ctl.rows, ctl.cols);
 #endif
-	curs_set(0);
+		curs_set(0);
+	}
 
 	ctl.hostname = xgethostname();
 	event_loop(&ctl, &out);
@@ -412,10 +440,13 @@ int main(int argc, char **argv)
 	free(ctl.hostname);
 	cpuset_free(ctl.cpuset);
 
-	if (is_tty)
-		tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tty);
-	delwin(ctl.win);
-	endwin();
+	if (ctl.batch == false) {
+		if (is_tty)
+			tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tty);
+
+		delwin(ctl.win);
+		endwin();
+	}
 
 	return EXIT_SUCCESS;
 }
-- 
2.43.5


^ permalink raw reply related

* [PATCH 0/3] irqtop,lsirq: Miscellaneous enhancements
From: Joe Jin @ 2025-02-27  4:49 UTC (permalink / raw)
  To: Karel Zak, Zhenwei Pi, Sami Kerola; +Cc: util-linux, Joe Jin

This patchset add below new options:
 '-b|--batch' : Batch mode
 '-n|--number': specifies the maximum number of iterations
 '-i|--input' : Read data from file

Joe Jin (3):
  irqtop: add batch mode support
  irqtop: add max iteration support
  lsirq,irqtop: add support for reading data from given file

 bash-completion/irqtop  |  15 ++++-
 bash-completion/lsirq   |   4 ++
 sys-utils/irq-common.c  |  19 +++----
 sys-utils/irq-common.h  |   3 +-
 sys-utils/irqtop.1.adoc |   9 +++
 sys-utils/irqtop.c      | 122 +++++++++++++++++++++++++++++++---------
 sys-utils/lsirq.1.adoc  |   3 +
 sys-utils/lsirq.c       |  28 +++++++--
 8 files changed, 160 insertions(+), 43 deletions(-)

-- 
2.43.5


^ permalink raw reply

* Re: Bug#1098638: fdisk: creates partitions one sector too large
From: Thorsten Glaser @ 2025-02-26  9:22 UTC (permalink / raw)
  To: Karel Zak; +Cc: Chris Hofstaedtler, 1098638-quiet, util-linux
In-Reply-To: <7tyxu3bufdztsdkt4svgvz5ul4bzsnvbstndcopht36lklthbj@3kmnuyuwhtwp>

On Tue, 25 Feb 2025, Karel Zak wrote:

>The convention of +<sectors> is strictly evaluated as <first> + <size>,
>without subtracting 1.

I guess someone made the maths mistake here: the last sector
is always <first> + <size> - 1, compare C arrays.

>This is how fdisk has functioned since its inception. I noticed this
>in the v2.13 code and was able to replicate it with v2.14 (year 2008).

Ouch. Then I agree changing this is not prudent at this point,
but please *do* clarify this in the question text. Let me
propose new text… hmm, let me see the old…

>> > Command (m for help): n
>> > Partition number (1-128, default 1):
>> > First sector (2048-7814037134, default 2048):
>> > Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-7814037134, default 7814035455): +2097152

… let’s go multiline for this:

| Last sector (2048-7814037134, default 7814035455),
| +/-sectors from first sector, or +/-size{K,M,G,T,P}:

>This is different from +<size>{M,G,T,..} where the final
>size is reduced by 1 and aligned to the disk I/O limits.

I expected the -1 (fencepost) but not the alignment, but
that makes sense.

>Additionally, it should be noted that people use 'echo
>"something" | fdisk' in scripts ...

Indeed, I do so myself, though in scripts I have so far
always calculated the last sector manually, it was only
that day interactively when I wanted to enter a manual
size in sectors: specifically, a split-mode dm-integrity
<https://evolvis.org/plugins/scmgit/cgi-bin/gitweb.cgi?p=useful-scripts/useful-scripts.git;a=blob;f=integritysetup/README.txt;h=76a7a67cb35d34c08eeeb916ce26f1832febf922;hb=HEAD#l113>
partition (where I manually aligned the result from the
isize-p script in the aforementioned documentation to a
multiple of 2048).

────────────────────────────────────────────────────────────────────────

So, would you please consider changing the wording, at
least, upstream? (And, perhaps, throw in another sentence
or two into the manpage, stating that the +sectors syntax
isn’t meant to express size, unlike the others.)

Thanks,
//mirabilos
-- 
[16:04:33] bkix: "veni vidi violini"
[16:04:45] bkix: "ich kam, sah und vergeigte"...

^ permalink raw reply

* Re: Bug#1098638: fdisk: creates partitions one sector too large
From: Karel Zak @ 2025-02-25 12:07 UTC (permalink / raw)
  To: Chris Hofstaedtler; +Cc: Thorsten Glaser, 1098638-quiet, util-linux
In-Reply-To: <Z7shDWfLwHPMxT2C@per.namespace.at>

On Sun, Feb 23, 2025 at 02:22:21PM GMT, Chris Hofstaedtler wrote:
> Control: tags -1 + upstream
> 
> Looping in upstream.
> 
> On Sat, Feb 22, 2025 at 12:57:38AM +0100, Thorsten Glaser wrote:
> > Package: fdisk
> > Version: 2.38.1-5+deb12u1
> > 
> > When I create a new partition with +sectors, fdisk creates one
> > that is one sector too large:
> > 
> > 
> > Command (m for help): n
> > Partition number (1-128, default 1):
> > First sector (2048-7814037134, default 2048):
> > Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-7814037134, default 7814035455): +2097152
> > 
> > Created a new partition 1 of type 'Linux filesystem' and of size 1 GiB.
> > 
> > Command (m for help): p
> > Disk /dev/sdb: 3.64 TiB, 4000787030016 bytes, 7814037168 sectors
> > Disk model: ST4000NM0245-1Z2
> > Units: sectors of 1 * 512 = 512 bytes
> > Sector size (logical/physical): 512 bytes / 4096 bytes
> > I/O size (minimum/optimal): 4096 bytes / 4096 bytes
> > Disklabel type: gpt
> > Disk identifier: DDA88AFF-1E6A-7448-AB5A-85470938DBC7
> > 
> > Device       Start        End    Sectors  Size Type
> > /dev/sdb1     2048    2099200    2097153    1G Linux filesystem

This is how fdisk has functioned since its inception. I noticed this
in the v2.13 code and was able to replicate it with v2.14 (year 2008).

The convention of +<sectors> is strictly evaluated as <first> + <size>,
without subtracting 1. This is different from +<size>{M,G,T,..} where the final
size is reduced by 1 and aligned to the disk I/O limits.

I have doubts about changing this after 20 years due to backward
compatibility. Additionally, it should be noted that people use 'echo
"something" | fdisk' in scripts ...

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply

* Re: Bug#1098694: Crash in agetty due to invalid strncmp call in Trixie
From: Karel Zak @ 2025-02-25  7:55 UTC (permalink / raw)
  To: Chris Hofstaedtler; +Cc: 1098694-quiet, Florian Bach, util-linux
In-Reply-To: <2tlkt7g2blnq3gigedhwgnrt5w7n6k5zyr3dvpadyrl2bn5p2d@v6rhkcmaeryo>

On Mon, Feb 24, 2025 at 07:59:11PM GMT, Karel Zak wrote:
>  Oh, I have implemented something like this https://github.com/util-linux/util-linux/pull/3425

Merged.

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply

* Re: [PATCH 1/6] scriptreplay: indicate that <divisor> is conditional on <typescript>
From: Karel Zak @ 2025-02-25  7:54 UTC (permalink / raw)
  To: Benno Schulenberg; +Cc: util-linux
In-Reply-To: <20250224130840.25770-1-bensberg@telfort.nl>

On Mon, Feb 24, 2025 at 02:08:35PM GMT, Benno Schulenberg wrote:
>  term-utils/scriptreplay.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)

All 6 patches applied, thanks!

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply

* Re: [ANNOUNCE] util-linux v2.41-rc1
From: Karel Zak @ 2025-02-25  7:53 UTC (permalink / raw)
  To: Samuel Thibault, util-linux
In-Reply-To: <Z7cPetD5HqKnWkDT@begin>

On Thu, Feb 20, 2025 at 12:18:18PM GMT, Samuel Thibault wrote:
> Here is a patch to fix missing references to mq_open/close.

Applied, thanks!

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply

* Re: Bug#1098694: Crash in agetty due to invalid strncmp call in Trixie
From: Karel Zak @ 2025-02-24 18:59 UTC (permalink / raw)
  To: Chris Hofstaedtler; +Cc: 1098694-quiet, Florian Bach, util-linux
In-Reply-To: <b5ikwzm4qjyxazwnck736kqdihgjmyjbsfuikfwntaece7fmmu@oxxt7prt45jz>

On Sun, Feb 23, 2025 at 09:13:39PM GMT, Chris Hofstaedtler wrote:
> * Chris Hofstaedtler <zeha@debian.org> [250223 20:06]:
> > > [..] After I sent this bug report yesterday, I also found out that
> > > someone has reported what I believe is the same bug to
> > > upstream a while ago ( https://github.com/util-linux/util-linux/issues/3304
> > > ) but so far nobody has commented on that report.
> > 
> > Yeah, this seems like the same issue.
> 
> Below is a patch that works, but certainly feels dirty:
> 
> 
> From: Chris Hofstaedtler <zeha@debian.org>
> Date: Sun, 23 Feb 2025 20:10:05 +0100
> Subject: agetty: restore op->tty if getting the tty name fails
> 
> Signed-off-by: Chris Hofstaedtler <zeha@debian.org>
> ---
>  term-utils/agetty.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/term-utils/agetty.c b/term-utils/agetty.c
> index a382313..e65c985 100644
> --- a/term-utils/agetty.c
> +++ b/term-utils/agetty.c
> @@ -929,9 +929,11 @@ static void parse_args(int argc, char **argv, struct options *op)
>  	/* resolve the tty path in case it was provided as stdin */
>  	if (strcmp(op->tty, "-") == 0) {
>  		op->tty_is_stdin = 1;
> +		const char* tty_orig = op->tty;
>  		int fd = get_terminal_name(NULL, &op->tty, NULL);
>  		if (fd < 0) {
>  			log_warn(_("could not get terminal name: %d"), fd);
> +			op->tty = tty_orig;
>  		}

 Oh, I have implemented something like this https://github.com/util-linux/util-linux/pull/3425

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply

* [PATCH 2/6] scriptreplay: make Up/Down keys use a percentage instead of fixed amount
From: Benno Schulenberg @ 2025-02-24 13:08 UTC (permalink / raw)
  To: util-linux; +Cc: Jonathan Ketchker
In-Reply-To: <20250224130840.25770-1-bensberg@telfort.nl>

Using a fixed 0.1 amount made each subsequent Down-arrow key slow things
down _more_, and each subsequent Up-arrow key speed things up _less_.
It's nicer when each subsequent keystroke has the same relative effect.

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
---
 term-utils/scriptreplay.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/term-utils/scriptreplay.c b/term-utils/scriptreplay.c
index 0e1444ca1..5751e1b52 100644
--- a/term-utils/scriptreplay.c
+++ b/term-utils/scriptreplay.c
@@ -76,8 +76,8 @@ usage(void)
 	fputs(USAGE_SEPARATOR, out);
 	fputs(_("Key bindings:\n"), out);
 	fputs(_(" space        toggles between pause and play\n"), out);
-	fputs(_(" up-arrow     increases the time divisor with 0.1\n"), out);
-	fputs(_(" down-arrow   decreases the time divisor with 0.1\n"), out);
+	fputs(_(" up-arrow     increases playback speed with ten percent\n"), out);
+	fputs(_(" down-arrow   decreases playback speed with ten percent\n"), out);
 
 	fprintf(out, USAGE_MAN_TAIL("scriptreplay(1)"));
 	exit(EXIT_SUCCESS);
@@ -343,10 +343,10 @@ main(int argc, char *argv[])
 			if (ch == '[') {
 				ch = fgetc(stdin);
 				if (ch == 'A') { /* Up arrow */
-					divi += 0.1;
+					divi *= 1.1;
 					replay_set_delay_div(setup, divi);
 				} else if (ch == 'B') { /* Down arrow */
-					divi -= 0.1;
+					divi *= 0.9;
 					if (divi < 0.1)
 						divi = 0.1;
 					replay_set_delay_div(setup, divi);
-- 
2.48.1


^ permalink raw reply related

* [PATCH 1/6] scriptreplay: indicate that <divisor> is conditional on <typescript>
From: Benno Schulenberg @ 2025-02-24 13:08 UTC (permalink / raw)
  To: util-linux

Also, use angle brackets to show that those words are placeholders,
not literals, and improve the descriptions of the key bindings.

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
---
 term-utils/scriptreplay.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/term-utils/scriptreplay.c b/term-utils/scriptreplay.c
index c8a1ad0c4..0e1444ca1 100644
--- a/term-utils/scriptreplay.c
+++ b/term-utils/scriptreplay.c
@@ -50,7 +50,7 @@ usage(void)
 	      _(" %s [options]\n"),
 	      program_invocation_short_name);
 	fprintf(out,
-	      _(" %s [-t] timingfile [typescript] [divisor]\n"),
+	      _(" %s [-t] <timingfile> [<typescript> [<divisor>]]\n"),
 	      program_invocation_short_name);
 
 	fputs(USAGE_SEPARATOR, out);
@@ -75,9 +75,9 @@ usage(void)
 
 	fputs(USAGE_SEPARATOR, out);
 	fputs(_("Key bindings:\n"), out);
-	fputs(_(" space        toggles pause and unpause\n"), out);
-	fputs(_(" up-arrow     increases the playback speed by 0.1 times\n"), out);
-	fputs(_(" down-arrow   decreases the playback speed by 0.1 times\n"), out);
+	fputs(_(" space        toggles between pause and play\n"), out);
+	fputs(_(" up-arrow     increases the time divisor with 0.1\n"), out);
+	fputs(_(" down-arrow   decreases the time divisor with 0.1\n"), out);
 
 	fprintf(out, USAGE_MAN_TAIL("scriptreplay(1)"));
 	exit(EXIT_SUCCESS);
-- 
2.48.1


^ permalink raw reply related

* [PATCH 6/6] scriptlive: improve some descriptions, markup, and grammar in the manpage
From: Benno Schulenberg @ 2025-02-24 13:08 UTC (permalink / raw)
  To: util-linux
In-Reply-To: <20250224130840.25770-1-bensberg@telfort.nl>

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
---
 term-utils/scriptlive.1.adoc | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/term-utils/scriptlive.1.adoc b/term-utils/scriptlive.1.adoc
index 58aeb4ce1..10e299875 100644
--- a/term-utils/scriptlive.1.adoc
+++ b/term-utils/scriptlive.1.adoc
@@ -21,9 +21,14 @@ This program re-runs a typescript, using stdin typescript and timing information
 
 The *session is executed* in a newly created pseudoterminal with the user's $SHELL (or defaults to _/bin/bash_).
 
-*Be careful!* Do not forget that the typescript may contains arbitrary commands. It is recommended to use *"scriptreplay --stream in --log-in typescript"* (or with *--log-io* instead of *--log-in*) to verify the typescript before it is executed by *scriptlive*.
+*Be careful!* The typescript may contain arbitrary commands. It is
+recommended to use *"scriptreplay --stream in --log-in typescript"*
+(or with *--log-io* instead of *--log-in*) to verify the typescript
+before it is executed with *scriptlive*.
 
-The timing information is what *script*(1) outputs to file specified by *--log-timing*. The typescript has to contain stdin information and it is what script1 outputs to file specified by *--log-in* or *--log-io*.
+The timing information is what *script*(1) outputs to the file specified by
+*--log-timing*. The typescript has to contain stdin information, and is what
+*script*(1) outputs to the file specified by *--log-in* or *--log-io*.
 
 == OPTIONS
 
@@ -34,15 +39,19 @@ File containing *script*'s terminal input.
 File containing *script*'s terminal output and input.
 
 *-E*, *--echo* _when_::
-This option controls the *ECHO* flag for the slave end of the session's pseudoterminal. The supported modes are _always_, _never_, or _auto_.
+This option controls the *ECHO* flag for the slave end of the session's
+pseudoterminal. The supported modes are *always*, *never*, and *auto*.
 +
-The default is _auto_ -- in this case, *ECHO* enabled; this default behavior is subject to change.
+The default is *auto* -- in which case *ECHO* is enabled. This default
+behavior is subject to change.
 
 *-t*, *--timing* _file_::
-File containing *script*'s timing output. This option overrides old-style arguments.
+File containing *script*'s timing output.
+This option replaces the _timingfile_ positional argument.
 
 *-T*, *--log-timing* _file_::
-Aliased to *-t*, maintained for compatibility with *script*(1) command-line options.
+An alias for *-t*; maintained for compatibility with the *script*(1)
+command-line options.
 
 *-d*, *--divisor* _number_::
 Speed up the replay displaying this _number_ of times. The argument is a floating-point number. It's called divisor because it divides the timings by this factor. This option overrides old-style arguments.
-- 
2.48.1


^ permalink raw reply related

* [PATCH 5/6] scriptlive: reduce two usage synopses to one simple one
From: Benno Schulenberg @ 2025-02-24 13:08 UTC (permalink / raw)
  To: util-linux
In-Reply-To: <20250224130840.25770-1-bensberg@telfort.nl>

No synopsis can show all possible permutattions of arguments and
options, so do not even try and just give the most basic form,
without unneeded -t, -I, or -B.

Also, use angle brackets to show that <timingfile> and <typescript>
are placeholders.

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
---
 term-utils/scriptlive.1.adoc | 2 +-
 term-utils/scriptlive.c      | 7 +++----
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/term-utils/scriptlive.1.adoc b/term-utils/scriptlive.1.adoc
index 1efb429bb..58aeb4ce1 100644
--- a/term-utils/scriptlive.1.adoc
+++ b/term-utils/scriptlive.1.adoc
@@ -13,7 +13,7 @@ scriptlive - re-run session typescripts, using timing information
 
 == SYNOPSIS
 
-*scriptlive* [options] [*-t*] _timingfile_ [*-I*|*-B*] _typescript_
+*scriptlive* [options] _timingfile_ _typescript_
 
 == DESCRIPTION
 
diff --git a/term-utils/scriptlive.c b/term-utils/scriptlive.c
index 1b0bf96cb..e4a3434ed 100644
--- a/term-utils/scriptlive.c
+++ b/term-utils/scriptlive.c
@@ -54,10 +54,7 @@ usage(void)
 	FILE *out = stdout;
 	fputs(USAGE_HEADER, out);
 	fprintf(out,
-	      _(" %s [options]\n"),
-	      program_invocation_short_name);
-	fprintf(out,
-	      _(" %s [-t] timingfile [-I|-B] typescript\n"),
+	      _(" %s [options] <timingfile> <typescript>\n"),
 	      program_invocation_short_name);
 
 	fputs(USAGE_SEPARATOR, out);
@@ -74,6 +71,8 @@ usage(void)
 	fputs(_(" -d, --divisor <num>     speed up or slow down execution with time divisor\n"), out);
 	fputs(_(" -E, --echo <when>       echo input in session (auto, always or never)\n"), out);
 	fputs(_(" -m, --maxdelay <num>    wait at most this many seconds between updates\n"), out);
+
+	fputs(USAGE_SEPARATOR, out);
 	fprintf(out, USAGE_HELP_OPTIONS(25));
 
 	fprintf(out, USAGE_MAN_TAIL("scriptlive(1)"));
-- 
2.48.1


^ permalink raw reply related

* [PATCH 4/6] scriptreplay: mark literal values in the man page in bold, not italic
From: Benno Schulenberg @ 2025-02-24 13:08 UTC (permalink / raw)
  To: util-linux
In-Reply-To: <20250224130840.25770-1-bensberg@telfort.nl>

Also, mention which keys can be used to speed up, slow down, and pause
the replay.  Shorten the description of '-s' as it is deprecated.  And
improve the description of '-t': it does not override the _timingfile_
positional argument, but takes the place of it, makes it unneeded.

Signed-off-by: Benno Schulenberg <bensberg@telfort.nl>
---
 term-utils/scriptreplay.1.adoc | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/term-utils/scriptreplay.1.adoc b/term-utils/scriptreplay.1.adoc
index 7665d28f8..deabb7b16 100644
--- a/term-utils/scriptreplay.1.adoc
+++ b/term-utils/scriptreplay.1.adoc
@@ -23,11 +23,14 @@ The replay simply displays the information again; the programs that were run whe
 
 The timing information is what *script*(1) outputs to file specified by *--log-timing*.
 
-By default, the typescript to display is assumed to be named _typescript_, but other filenames may be specified, as the second parameter or with option *--log-out*.
+By default, the _typescript_ to display is assumed to be named *typescript*,
+but other filenames may be specified, as the second parameter or with option
+*--log-out*.
 
 If the third parameter or *--divisor* is specified, it is used as a speed-up multiplier. For example, a speed-up of 2 makes *scriptreplay* go twice as fast, and a speed-down of 0.1 makes it go ten times slower than the original session.
 
-During the replay, you can interactively speed up, slow down, or pause the playback using key bindings.
+During the replay, you can interactively speed up, slow down, or pause the
+playback using the Up, Down, and Space keys.
 
 == OPTIONS
 
@@ -41,16 +44,20 @@ File containing *script*'s terminal output.
 File containing *script*'s terminal output and input.
 
 *-t*, *--timing* _file_::
-File containing *script*'s timing output. This option overrides old-style arguments.
+File containing *script*'s timing output.
+This option replaces the _timingfile_ positional argument.
 
 *-T*, *--log-timing* _file_::
 This is an alias for *-t*, maintained for compatibility with *script*(1) command-line options.
 
 *-s*, *--typescript* _file_::
-File containing *script*'s terminal output. Deprecated alias to *--log-out*. This option overrides old-style arguments.
+Deprecated alias of *--log-out*.
 
 *-c*, *--cr-mode* _mode_::
-Specifies how to use the CR (0x0D, carriage return) character from log files. The default mode is _auto_, in this case CR is replaced with line break for stdin log, because otherwise *scriptreplay* would overwrite the same line. The other modes are _never_ and _always_.
+Specifies how to handle the CR (carriage return, 0x0D) character from log
+files. The default mode is *auto*, in which case CR is replaced with a
+line break for the stdin log, because otherwise *scriptreplay* would
+overwrite the same line. The other modes are *never* and *always*.
 
 *-d*, *--divisor* _number_::
 Speed up the replay displaying this _number_ of times. The argument is a floating-point number. It's called divisor because it divides the timings by this factor. This option overrides old-style arguments.
@@ -59,10 +66,15 @@ Speed up the replay displaying this _number_ of times. The argument is a floatin
 Set the maximum delay between updates to _number_ of seconds. The argument is a floating-point number. This can be used to avoid long pauses in the typescript replay.
 
 *--summary*::
-Display details about the session recorded in the specified timing file and exit. The session has to be recorded using _advanced_ format (see *script*(1) option *--logging-format* for more details).
+Display details about the session recorded in the specified timing file and
+exit. The session must have been recorded using the *advanced* format (see
+*script*(1) option *--logging-format* for more details).
 
 *-x*, *--stream* _type_::
-Forces *scriptreplay* to print only the specified stream. The supported stream types are _in_, _out_, _signal_, or _info_. This option is recommended for multi-stream logs (e.g., *--log-io*) in order to print only specified data.
+Forces *scriptreplay* to print only the specified stream. The supported stream
+types are *in*, *out*, *signal*, and *info*. This option is recommended for
+multi-stream logs (created with *--log-io*) in order to print only the desired
+data.
 
 include::man-common/help-version.adoc[]
 
-- 
2.48.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox