bin/119705: [PATCH] make iostat a bit smarter about the number
of tty rows
Giorgos Keramidas
keramida at FreeBSD.org
Wed Jan 16 07:40:05 UTC 2008
The following reply was made to PR bin/119705; it has been noted by GNATS.
From: Giorgos Keramidas <keramida at freebsd.org>
To: Maxim Konovalov <maxim at macomnet.ru>
Cc: Bruce Evans <bde at freebsd.org>, bug-followup at freebsd.org
Subject: Re: bin/119705: [PATCH] make iostat a bit smarter about the number
of tty rows
Date: Wed, 16 Jan 2008 09:39:37 +0200
On 2008-01-16 09:13, Giorgos Keramidas <keramida at freebsd.org> wrote:
> On 2008-01-16 09:29, Maxim Konovalov <maxim at macomnet.ru> wrote:
> > Hi Giorgos,
> > It seems for me you forget to clear wresized flag -- I added
> > printf("%s\n", __func__); at the beginning of doresize() to notice
> > this.
>
> Indeed. Thanks for catching this.
>
> > IMHO the isatty() check doesn't belong to a pseudo signal handler
> > doresize(). Install SIGWINCH handler if and only if stdout is a tty.
>
> That's a good suggestion too, and it will save one isatty() call for
> each SIGWINCH delivery. I'll update the patch and follow-up with a
> second version in the PR. Nice...
Both fixed, I think. The new version of the patch is attached below,
after the following changes:
iostat-rows: fix a couple of nits reported by maxim
* Reset wresized when doresize() completes its work
* Only call isatty(fileno(stdout)) once, instead of every time
doresize() is called
* Only install a SIGWINCH handler if isatty() is true
While here, also fix another potential problem, when a terminal
has 3 rows or less. Instead of blindly subtracting 3 from w.ws_row
and ending up with a negative wrows value, default to 20 in that
case.
Since the traditional value of 20 rows is now used in two places with
this change, #define it as IOSTAT_DEFAULT_ROWS, to avoid repeating a
magic number multiple times.
%%%
diff --git a/usr.sbin/iostat/iostat.c b/usr.sbin/iostat/iostat.c
--- a/usr.sbin/iostat/iostat.c
+++ b/usr.sbin/iostat/iostat.c
@@ -113,6 +113,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
#include <limits.h>
#include <devstat.h>
@@ -131,17 +132,23 @@ struct nlist namelist[] = {
{ NULL },
};
+#define IOSTAT_DEFAULT_ROWS 20 /* Traditional default `wrows' */
+
struct statinfo cur, last;
int num_devices;
struct device_selection *dev_select;
int maxshowdevs;
volatile sig_atomic_t headercount;
+volatile sig_atomic_t wresized; /* Tty resized, when non-zero. */
+unsigned short wrows; /* Current number of tty rows. */
int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0;
int xflag = 0, zflag = 0;
/* local function declarations */
static void usage(void);
static void needhdr(int signo);
+static void needresize(int signo);
+static void doresize(void);
static void phdr(void);
static void devstats(int perf_select, long double etime, int havelast);
static void cpustats(void);
@@ -426,6 +433,20 @@ main(int argc, char **argv)
*/
(void)signal(SIGCONT, needhdr);
+ /*
+ * If our standard output is a tty, then install a SIGWINCH handler
+ * and set wresized so that our first iteration through the main
+ * iostat loop will peek at the terminal's current rows to find out
+ * how many lines can fit in a screenful of output.
+ */
+ if (isatty(fileno(stdout)) != 0) {
+ wresized = 1;
+ (void)signal(SIGWINCH, needresize);
+ } else {
+ wrows = IOSTAT_DEFAULT_ROWS;
+ return;
+ }
+
for (headercount = 1;;) {
struct devinfo *tmp_dinfo;
long tmp;
@@ -451,7 +472,9 @@ main(int argc, char **argv)
if (!--headercount) {
phdr();
- headercount = 20;
+ if (wresized != 0)
+ doresize();
+ headercount = wrows;
}
tmp_dinfo = last.dinfo;
@@ -493,7 +516,9 @@ main(int argc, char **argv)
break;
case 1:
phdr();
- headercount = 20;
+ if (wresized != 0)
+ doresize();
+ headercount = wrows;
break;
default:
break;
@@ -528,7 +553,9 @@ main(int argc, char **argv)
break;
case 1:
phdr();
- headercount = 20;
+ if (wresized != 0)
+ doresize();
+ headercount = wrows;
break;
default:
break;
@@ -587,6 +614,48 @@ needhdr(int signo)
{
headercount = 1;
+}
+
+/*
+ * When the terminal is resized, force an update of the maximum number of rows
+ * printed between each header repetition. Then force a new header to be
+ * prepended to the next output.
+ */
+void
+needresize(int signo)
+{
+
+ wresized = 1;
+ headercount = 1;
+}
+
+/*
+ * Update the global `wrows' count of terminal rows.
+ */
+void
+doresize(void)
+{
+ int status;
+ struct winsize w;
+
+ printf("wresized = %d\n", wresized);
+ for (;;) {
+ status = ioctl(fileno(stdout), TIOCGWINSZ, &w);
+ if (status == -1 && errno == EINTR)
+ continue;
+ else if (status == -1)
+ err(1, "ioctl");
+ if (w.ws_row > 3)
+ wrows = w.ws_row - 3;
+ else
+ wrows = IOSTAT_DEFAULT_ROWS;
+ break;
+ }
+
+ /*
+ * Inhibit doresize() calls until we are rescheduled by SIGWINCH.
+ */
+ wresized = 0;
}
static void
%%%
More information about the freebsd-bugs
mailing list