From nobody Thu Apr 30 17:59:23 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4g624D2vhTz6bx8r for ; Thu, 30 Apr 2026 17:59:24 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4g624C5BR7z3qkQ for ; Thu, 30 Apr 2026 17:59:23 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1777571963; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=1GgjEjsIb9N0RPG7jzYVrkpg/yBMAymNSuQhEoJtmC4=; b=a9IKv/+1SyQPeODSU1r2HX9kX0lJ5E8EZhvE/42sN5Xy4FcysQd+tUc+eZ27P1N/jTkl4q QFYu2rqo5dloEDJENgiigadPvZ9IDlWry9ycqNDnLs6i21u21I5s6Eyi/mXndrHQx/TSw0 sgsgo9uYDOKS3eeN4IFcHx6zi77h4MX2bqzs2v8wJHDZbFCJpI1gsLXwzbYBh0e+NnTjaV 66p23fwJRGd1a4Mx/8J2z5qW2no9emnBolxrO+SU8sIUt7rQmimbxbCh+F/T3hLfvOfUdm 07xQgrJ8fRQGKzvDEQ2nDWSsLMEDh9S2yWoLlBqVY7Hn+MAht7R9JEKPOV09sQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1777571963; a=rsa-sha256; cv=none; b=C/D8LAR8KUJ4VFXv6/N6BKRdoa7VCT5creRxzMdE6R8bf2lfX3MBreNeCAUqsGeQSK2+oM 1slJCIEvOuJdMTb7ZAgr6u5OH+3Hi4rai/4C92oDaG+rBlauAa70P+HEiRWdwyVyZvWvVy 5Q53pNFgBsKjdp4sc1kzC43iJxnYDH8fG5s5a+qZvqVRfKkYGjLedsrYpesPTeHZkM47+6 j1gKpS0tAhxEOZMSb/TACQgvbQmrrTCHrHP9d9JY79yD166/ZP7k290nGFrgHFPNlnk/uM TZiQ1PAnJC8orC0O2+FKfYcVadclwUlSPCeTNdpyKGfngbP9B2h13HhomymxQA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1777571963; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=1GgjEjsIb9N0RPG7jzYVrkpg/yBMAymNSuQhEoJtmC4=; b=gD5hjy57G/GnwbV5aakTh7RY6S8EnFPHnR4s8xFbOfeNfusBfVjcOcjomLbspSkTeFfTfb /6PJoY5yViosU8/YaammovFlJ1DCHNlPLdL7YzXBLQzJoskiDz4hPmNpdBVgG2VgLUZyxx PVTTUebQpyk9mSBNtcYlmeZz6T7nYtTWSK96o+zl2GVF7JXBmsKjbCLVPfVYcfxlb/DHyi fayHSSbC6zZFMISKUfvJ/yCATOvP9ULG9YmnudBFkluNiNheGd+pTHbmWZNjmunu3L0Q7Y 48lmbUbOvsxrXO3ViE1nMrD9Z9Oozdj9YsONnc2UweH465MBVE5Zg7Ci7nVeqA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4g624C4jFcz6s6 for ; Thu, 30 Apr 2026 17:59:23 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 32b75 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 30 Apr 2026 17:59:23 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Olivier Certner Subject: git: c63d3e582ac0 - stable/15 - netstat(1): '-w': Banners to appear before a new statistics line, not after List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: olce X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: c63d3e582ac0712254a9308adcb6fedebe0b8567 Auto-Submitted: auto-generated Date: Thu, 30 Apr 2026 17:59:23 +0000 Message-Id: <69f3987b.32b75.20e33dad@gitrepo.freebsd.org> The branch stable/15 has been updated by olce: URL: https://cgit.FreeBSD.org/src/commit/?id=c63d3e582ac0712254a9308adcb6fedebe0b8567 commit c63d3e582ac0712254a9308adcb6fedebe0b8567 Author: Olivier Certner AuthorDate: 2026-04-02 19:13:02 +0000 Commit: Olivier Certner CommitDate: 2026-04-30 17:58:45 +0000 netstat(1): '-w': Banners to appear before a new statistics line, not after Recurring banners except the first are printed just after the latest interval's statistics line, giving the false impression that the latter are omitted. It is also better to print a new banner only if it is going to be followed by a new line of statistics, in case netstat(1) is interrupted or we have reached the number of iterations specified by '-q'. Fix this by pushing printing these banners inside the loop producing statistics lines, after having waited for the next interval. The first banner is printed before the loop, as we want it to be printed immediately at launch, even if at this point we do not have statistics to display (we have to wait for an interval to compute these, as they are based on a difference). While here, remove the 'goto' spaghetti by putting banner printing into its own private function and using a proper infinite loop in sidewaysintpr(). While here, document the why of the 21 statistics line span between two banners. While here, check for the number of output lines of statistics once such a line has effectively been printed. This allows to remove the internal incrementation performed when reading '-w''s argument, which was a hack to compensate the misplaced check. While here, in the manual page, simplify the description of the '-w' mode and mention that passing 0 to '-q' means "no count limit". Reviewed by: glebius Fixes: 84c1edcbad7d ("Rewrite netstat/if.c to use ...") Fixes: bf10ffe1d3a9 ("Add a new option, -q howmany, ...") MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D56227 (cherry picked from commit 31749859525b2b79634dc7c066c3563be5b1e3fd) --- usr.bin/netstat/if.c | 146 +++++++++++++++++++++++++++------------------- usr.bin/netstat/main.c | 2 - usr.bin/netstat/netstat.1 | 20 ++----- 3 files changed, 92 insertions(+), 76 deletions(-) diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c index 7ee03eb3689b..637aa4738d40 100644 --- a/usr.bin/netstat/if.c +++ b/usr.bin/netstat/if.c @@ -396,7 +396,7 @@ intpr(void (*pfunc)(char *), int af) u_int npkt_len = 8, nbyte_len = 10, nerr_len = 5; if (interval) - return sidewaysintpr(); + return (sidewaysintpr()); if (getifaddrs(&ifap) != 0) xo_err(EX_OSERR, "getifaddrs"); @@ -652,6 +652,21 @@ catchalarm(int signo __unused) signalled = true; } +static void +running_stats_banner(void) +{ + xo_emit("{T:/%17s} {T:/%14s} {T:/%16s}\n", "input", + interface != NULL ? interface : "(Total)", "output"); + xo_emit("{T:/%10s} {T:/%5s} {T:/%5s} {T:/%10s} {T:/%10s} {T:/%5s} " + "{T:/%10s} {T:/%5s}", + "packets", "errs", "idrops", "bytes", "packets", "errs", "bytes", + "colls"); + if (dflag) + xo_emit(" {T:/%5.5s}", "drops"); + xo_emit("\n"); + xo_flush(); +} + /* * Print a running summary of interface statistics. * Repeat display every interval seconds, showing statistics @@ -675,71 +690,82 @@ sidewaysintpr(void) interval_it.it_interval.tv_usec = 0; interval_it.it_value = interval_it.it_interval; setitimer(ITIMER_REAL, &interval_it, NULL); + xo_open_list("interface-statistics"); -banner: - xo_emit("{T:/%17s} {T:/%14s} {T:/%16s}\n", "input", - interface != NULL ? interface : "(Total)", "output"); - xo_emit("{T:/%10s} {T:/%5s} {T:/%5s} {T:/%10s} {T:/%10s} {T:/%5s} " - "{T:/%10s} {T:/%5s}", - "packets", "errs", "idrops", "bytes", "packets", "errs", "bytes", - "colls"); - if (dflag) - xo_emit(" {T:/%5.5s}", "drops"); - xo_emit("\n"); - xo_flush(); + /* + * We print the first banner right away, even if we'll have to wait for + * the specified interval to get the first statistics line. Next + * banners will be printed only when the next statistics line is + * available. + */ + running_stats_banner(); + /* Number of written statistics line since latest banner. */ line = 0; -loop: - if ((noutputs != 0) && (--noutputs == 0)) { - xo_close_list("interface-statistics"); - return; - } - oldmask = sigblock(sigmask(SIGALRM)); - while (!signalled) - sigpause(0); - signalled = false; - sigsetmask(oldmask); - line++; - - fill_iftot(new); - - xo_open_instance("stats"); - show_stat("lu", 10, "received-packets", - new->ift_ip - old->ift_ip, 1, 1); - show_stat("lu", 5, "received-errors", - new->ift_ie - old->ift_ie, 1, 1); - show_stat("lu", 5, "dropped-packets", - new->ift_id - old->ift_id, 1, 1); - show_stat("lu", 10, "received-bytes", - new->ift_ib - old->ift_ib, 1, 0); - show_stat("lu", 10, "sent-packets", - new->ift_op - old->ift_op, 1, 1); - show_stat("lu", 5, "send-errors", - new->ift_oe - old->ift_oe, 1, 1); - show_stat("lu", 10, "sent-bytes", - new->ift_ob - old->ift_ob, 1, 0); - show_stat("NRSlu", 5, "collisions", - new->ift_co - old->ift_co, 1, 1); - if (dflag) - show_stat("LSlu", 5, "dropped-packets", - new->ift_od - old->ift_od, 1, 1); - xo_close_instance("stats"); - xo_emit("\n"); - xo_flush(); + for (;;) { + /* Wait for next interval. */ + oldmask = sigblock(sigmask(SIGALRM)); + while (!signalled) + sigpause(0); + signalled = false; + sigsetmask(oldmask); - if (new == &ift[0]) { - new = &ift[1]; - old = &ift[0]; - } else { - new = &ift[0]; - old = &ift[1]; - } + fill_iftot(new); - if (line == 21) - goto banner; - else - goto loop; + /* + * We want that, on a 24-line display, when the previous banner + * reaches exactly the top of the screen, a new banner is + * printed before the next statistics line. This ensures that + * at least one banner is visible on screen at all time + * (provided the screen has at least 24 lines). Since the + * banner takes 2 lines, and the last screen line is occupied by + * the cursor, it's after having written 21 statistics lines + * that we must output the banner. + */ + if (line == 21) { + running_stats_banner(); + line = 0; + } + ++line; + + xo_open_instance("stats"); + show_stat("lu", 10, "received-packets", + new->ift_ip - old->ift_ip, 1, 1); + show_stat("lu", 5, "received-errors", + new->ift_ie - old->ift_ie, 1, 1); + show_stat("lu", 5, "dropped-packets", + new->ift_id - old->ift_id, 1, 1); + show_stat("lu", 10, "received-bytes", + new->ift_ib - old->ift_ib, 1, 0); + show_stat("lu", 10, "sent-packets", + new->ift_op - old->ift_op, 1, 1); + show_stat("lu", 5, "send-errors", + new->ift_oe - old->ift_oe, 1, 1); + show_stat("lu", 10, "sent-bytes", + new->ift_ob - old->ift_ob, 1, 0); + show_stat("NRSlu", 5, "collisions", + new->ift_co - old->ift_co, 1, 1); + if (dflag) + show_stat("LSlu", 5, "dropped-packets", + new->ift_od - old->ift_od, 1, 1); + xo_close_instance("stats"); + xo_emit("\n"); + xo_flush(); + + if ((noutputs != 0) && (--noutputs == 0)) { + xo_close_list("interface-statistics"); + return; + } + + if (new == &ift[0]) { + new = &ift[1]; + old = &ift[0]; + } else { + new = &ift[0]; + old = &ift[1]; + } + } /* NOTREACHED */ } diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index f901ddfb2888..0084426540f6 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -389,8 +389,6 @@ main(int argc, char *argv[]) break; case 'q': noutputs = atoi(optarg); - if (noutputs != 0) - noutputs++; break; case 'r': rflag = true; diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1 index 42604cec0b16..5c7f2336c06b 100644 --- a/usr.bin/netstat/netstat.1 +++ b/usr.bin/netstat/netstat.1 @@ -356,23 +356,14 @@ See At intervals of .Ar wait seconds, display the information regarding packet traffic on all -configured network interfaces or a single -.Ar interface . +configured network interfaces, or a single +.Ar interface +if +.Fl I +is specified. .Pp -When -.Nm -is invoked with the -.Fl w -option and a -.Ar wait -interval argument, it displays a running count of statistics related to -network interfaces. An obsolescent version of this option used a numeric parameter with no option, and is currently supported for backward compatibility. -By default, this display summarizes information for all interfaces. -Information for a specific interface may be displayed with the -.Fl I Ar interface -option. .Bl -tag -width indent .It Fl I Ar interface Only show information regarding @@ -399,6 +390,7 @@ See Exit after .Ar howmany outputs. +A value of zero indicates no limit, and is the default. .It Fl j Ar jail Run inside a jail. See