ifstat.c revision 1.4 1 1.4 christos /* $NetBSD: ifstat.c,v 1.4 2016/08/05 07:22:17 christos Exp $ */
2 1.2 scole
3 1.1 scole /*
4 1.1 scole * Copyright (c) 2003, Trent Nelson, <trent (at) arpa.com>.
5 1.1 scole * All rights reserved.
6 1.1 scole *
7 1.1 scole * Redistribution and use in source and binary forms, with or without
8 1.1 scole * modification, are permitted provided that the following conditions
9 1.1 scole * are met:
10 1.1 scole * 1. Redistributions of source code must retain the above copyright
11 1.1 scole * notice, this list of conditions and the following disclaimer.
12 1.1 scole * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 scole * notice, this list of conditions and the following disclaimer in the
14 1.1 scole * documentation and/or other materials provided with the distribution.
15 1.1 scole * 3. The name of the author may not be used to endorse or promote products
16 1.1 scole * derived from this software without specific prior written permission.
17 1.1 scole *
18 1.1 scole * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 1.1 scole * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 1.1 scole * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 1.1 scole * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 1.1 scole * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 1.1 scole * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 1.1 scole * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTIFSTAT_ERRUPTION)
25 1.1 scole * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 1.1 scole * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 1.1 scole * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 1.1 scole * SUCH DAMAGE.
29 1.1 scole *
30 1.1 scole * $FreeBSD: releng/10.1/usr.bin/systat/ifstat.c 247037 2013-02-20 14:19:09Z melifaro $
31 1.1 scole */
32 1.1 scole
33 1.1 scole #include <sys/cdefs.h>
34 1.1 scole #ifndef lint
35 1.4 christos __RCSID("$NetBSD: ifstat.c,v 1.4 2016/08/05 07:22:17 christos Exp $");
36 1.1 scole #endif /* not lint */
37 1.1 scole
38 1.1 scole #include <sys/types.h>
39 1.1 scole #include <sys/socket.h>
40 1.1 scole #include <sys/sysctl.h>
41 1.1 scole #include <sys/time.h>
42 1.1 scole #include <net/if.h>
43 1.1 scole
44 1.1 scole #include <ifaddrs.h>
45 1.1 scole #include <stdlib.h>
46 1.1 scole #include <string.h>
47 1.1 scole #include <err.h>
48 1.1 scole #include <errno.h>
49 1.1 scole #include <fnmatch.h>
50 1.1 scole
51 1.1 scole #include "systat.h"
52 1.1 scole #include "extern.h"
53 1.1 scole #include "convtbl.h"
54 1.1 scole
55 1.1 scole /* Column numbers */
56 1.1 scole
57 1.1 scole #define C1 0 /* 0-19 */
58 1.1 scole #define C2 20 /* 20-39 */
59 1.1 scole #define C3 40 /* 40-59 */
60 1.1 scole #define C4 60 /* 60-80 */
61 1.1 scole #define C5 80 /* Used for label positioning. */
62 1.1 scole
63 1.1 scole static const int col2 = C2;
64 1.1 scole static const int col3 = C3;
65 1.1 scole static const int col4 = C4;
66 1.1 scole
67 1.1 scole SLIST_HEAD(, if_stat) curlist;
68 1.1 scole
69 1.1 scole struct if_stat {
70 1.1 scole SLIST_ENTRY(if_stat) link;
71 1.1 scole char if_name[IF_NAMESIZE];
72 1.1 scole struct ifdatareq if_mib;
73 1.1 scole struct timeval tv;
74 1.1 scole struct timeval tv_lastchanged;
75 1.1 scole u_long if_in_curtraffic;
76 1.1 scole u_long if_out_curtraffic;
77 1.1 scole u_long if_in_traffic_peak;
78 1.1 scole u_long if_out_traffic_peak;
79 1.1 scole u_long if_in_curpps;
80 1.1 scole u_long if_out_curpps;
81 1.1 scole u_long if_in_pps_peak;
82 1.1 scole u_long if_out_pps_peak;
83 1.1 scole u_int if_row; /* Index into ifmib sysctl */
84 1.1 scole u_int if_ypos; /* 0 if not being displayed */
85 1.1 scole u_int display;
86 1.1 scole u_int match;
87 1.1 scole };
88 1.1 scole
89 1.1 scole extern int curscale;
90 1.1 scole extern char *matchline;
91 1.1 scole extern int showpps;
92 1.1 scole extern int needsort;
93 1.1 scole
94 1.1 scole static int needclear = 0;
95 1.1 scole
96 1.1 scole static void right_align_string(struct if_stat *);
97 1.1 scole static void getifmibdata(const int, struct ifdatareq *);
98 1.1 scole static void sort_interface_list(void);
99 1.1 scole static u_int getifnum(void);
100 1.1 scole
101 1.1 scole #define IFSTAT_ERR(n, s) do { \
102 1.1 scole putchar('\014'); \
103 1.1 scole closeifstat(wnd); \
104 1.1 scole err((n), (s)); \
105 1.1 scole } while (0)
106 1.1 scole
107 1.1 scole #define TOPLINE 5
108 1.1 scole #define TOPLABEL \
109 1.1 scole " Interface Traffic Peak Total"
110 1.1 scole
111 1.1 scole #define STARTING_ROW (TOPLINE + 1)
112 1.1 scole #define ROW_SPACING (3)
113 1.1 scole
114 1.1 scole #define IN_col2 (showpps ? ifp->if_in_curpps : ifp->if_in_curtraffic)
115 1.1 scole #define OUT_col2 (showpps ? ifp->if_out_curpps : ifp->if_out_curtraffic)
116 1.1 scole #define IN_col3 (showpps ? \
117 1.1 scole ifp->if_in_pps_peak : ifp->if_in_traffic_peak)
118 1.1 scole #define OUT_col3 (showpps ? \
119 1.1 scole ifp->if_out_pps_peak : ifp->if_out_traffic_peak)
120 1.1 scole #define IN_col4 (showpps ? \
121 1.1 scole ifp->if_mib.ifdr_data.ifi_ipackets : ifp->if_mib.ifdr_data.ifi_ibytes)
122 1.1 scole #define OUT_col4 (showpps ? \
123 1.1 scole ifp->if_mib.ifdr_data.ifi_opackets : ifp->if_mib.ifdr_data.ifi_obytes)
124 1.1 scole
125 1.1 scole #define EMPTY_COLUMN " "
126 1.1 scole #define CLEAR_COLUMN(y, x) mvprintw((y), (x), "%20s", EMPTY_COLUMN);
127 1.1 scole
128 1.1 scole #define DOPUTRATE(c, r, d) do { \
129 1.1 scole CLEAR_COLUMN(r, c); \
130 1.1 scole if (showpps) { \
131 1.1 scole mvprintw(r, (c), "%10.3f %cp%s ", \
132 1.1 scole convert(d##_##c, curscale), \
133 1.1 scole *get_string(d##_##c, curscale), \
134 1.1 scole "/s"); \
135 1.1 scole } \
136 1.1 scole else { \
137 1.1 scole mvprintw(r, (c), "%10.3f %s%s ", \
138 1.1 scole convert(d##_##c, curscale), \
139 1.1 scole get_string(d##_##c, curscale), \
140 1.1 scole "/s"); \
141 1.1 scole } \
142 1.1 scole } while (0)
143 1.1 scole
144 1.1 scole #define DOPUTTOTAL(c, r, d) do { \
145 1.1 scole CLEAR_COLUMN((r), (c)); \
146 1.1 scole if (showpps) { \
147 1.1 scole mvprintw((r), (c), "%12.3f %cp ", \
148 1.1 scole convert(d##_##c, SC_AUTO), \
149 1.1 scole *get_string(d##_##c, SC_AUTO)); \
150 1.1 scole } \
151 1.1 scole else { \
152 1.1 scole mvprintw((r), (c), "%12.3f %s ", \
153 1.1 scole convert(d##_##c, SC_AUTO), \
154 1.1 scole get_string(d##_##c, SC_AUTO)); \
155 1.1 scole } \
156 1.1 scole } while (0)
157 1.1 scole
158 1.1 scole #define PUTRATE(c, r) do { \
159 1.1 scole DOPUTRATE(c, (r), IN); \
160 1.1 scole DOPUTRATE(c, (r)+1, OUT); \
161 1.1 scole } while (0)
162 1.1 scole
163 1.1 scole #define PUTTOTAL(c, r) do { \
164 1.1 scole DOPUTTOTAL(c, (r), IN); \
165 1.1 scole DOPUTTOTAL(c, (r)+1, OUT); \
166 1.1 scole } while (0)
167 1.1 scole
168 1.1 scole #define PUTNAME(p) do { \
169 1.1 scole mvprintw(p->if_ypos, 0, "%s", p->if_name); \
170 1.1 scole mvprintw(p->if_ypos, col2-3, "%s", (const char *)"in"); \
171 1.1 scole mvprintw(p->if_ypos+1, col2-3, "%s", (const char *)"out"); \
172 1.1 scole } while (0)
173 1.1 scole
174 1.1 scole WINDOW *
175 1.1 scole openifstat(void)
176 1.1 scole {
177 1.1 scole return (subwin(stdscr, -1, 0, 5, 0));
178 1.1 scole }
179 1.1 scole
180 1.1 scole void
181 1.1 scole closeifstat(WINDOW *w)
182 1.1 scole {
183 1.1 scole struct if_stat *node = NULL;
184 1.1 scole
185 1.1 scole while (!SLIST_EMPTY(&curlist)) {
186 1.1 scole node = SLIST_FIRST(&curlist);
187 1.1 scole SLIST_REMOVE_HEAD(&curlist, link);
188 1.1 scole free(node);
189 1.1 scole }
190 1.1 scole
191 1.1 scole if (w != NULL) {
192 1.1 scole wclear(w);
193 1.1 scole wrefresh(w);
194 1.1 scole delwin(w);
195 1.1 scole }
196 1.1 scole
197 1.1 scole return;
198 1.1 scole }
199 1.1 scole
200 1.1 scole void
201 1.1 scole labelifstat(void)
202 1.1 scole {
203 1.1 scole
204 1.1 scole wmove(wnd, TOPLINE, 0);
205 1.1 scole wclrtoeol(wnd);
206 1.1 scole mvprintw(TOPLINE, 0, "%s", TOPLABEL);
207 1.1 scole
208 1.1 scole return;
209 1.1 scole }
210 1.1 scole
211 1.1 scole void
212 1.1 scole showifstat(void)
213 1.1 scole {
214 1.1 scole struct if_stat *ifp = NULL;
215 1.1 scole
216 1.1 scole SLIST_FOREACH(ifp, &curlist, link) {
217 1.1 scole if (ifp->display == 0 || (ifp->match == 0) ||
218 1.1 scole ifp->if_ypos > (u_int)(LINES - 3 - 1))
219 1.1 scole continue;
220 1.1 scole PUTNAME(ifp);
221 1.1 scole PUTRATE(col2, ifp->if_ypos);
222 1.1 scole PUTRATE(col3, ifp->if_ypos);
223 1.1 scole PUTTOTAL(col4, ifp->if_ypos);
224 1.1 scole }
225 1.1 scole
226 1.1 scole return;
227 1.1 scole }
228 1.1 scole
229 1.1 scole int
230 1.1 scole initifstat(void)
231 1.1 scole {
232 1.1 scole struct if_stat *p = NULL;
233 1.1 scole u_int n = 0, i = 0;
234 1.1 scole
235 1.1 scole n = getifnum();
236 1.1 scole if (n <= 0)
237 1.1 scole return (-1);
238 1.1 scole
239 1.1 scole SLIST_INIT(&curlist);
240 1.1 scole
241 1.1 scole for (i = 0; i < n; i++) {
242 1.1 scole p = (struct if_stat *)calloc(1, sizeof(struct if_stat));
243 1.1 scole if (p == NULL)
244 1.1 scole IFSTAT_ERR(1, "out of memory");
245 1.1 scole SLIST_INSERT_HEAD(&curlist, p, link);
246 1.1 scole p->if_row = i+1;
247 1.1 scole getifmibdata(p->if_row, &p->if_mib);
248 1.1 scole right_align_string(p);
249 1.1 scole p->match = 1;
250 1.1 scole
251 1.1 scole /*
252 1.1 scole * Initially, we only display interfaces that have
253 1.1 scole * received some traffic.
254 1.1 scole */
255 1.1 scole if (p->if_mib.ifdr_data.ifi_ibytes != 0)
256 1.1 scole p->display = 1;
257 1.1 scole }
258 1.1 scole
259 1.1 scole sort_interface_list();
260 1.1 scole
261 1.1 scole return (1);
262 1.1 scole }
263 1.1 scole
264 1.1 scole void
265 1.1 scole fetchifstat(void)
266 1.1 scole {
267 1.1 scole struct if_stat *ifp = NULL;
268 1.1 scole struct timeval tv, new_tv, old_tv;
269 1.1 scole double elapsed = 0.0;
270 1.1 scole u_int new_inb, new_outb, old_inb, old_outb = 0;
271 1.1 scole u_int new_inp, new_outp, old_inp, old_outp = 0;
272 1.1 scole
273 1.1 scole SLIST_FOREACH(ifp, &curlist, link) {
274 1.1 scole /*
275 1.1 scole * Grab a copy of the old input/output values before we
276 1.1 scole * call getifmibdata().
277 1.1 scole */
278 1.1 scole old_inb = ifp->if_mib.ifdr_data.ifi_ibytes;
279 1.1 scole old_outb = ifp->if_mib.ifdr_data.ifi_obytes;
280 1.1 scole old_inp = ifp->if_mib.ifdr_data.ifi_ipackets;
281 1.1 scole old_outp = ifp->if_mib.ifdr_data.ifi_opackets;
282 1.1 scole TIMESPEC_TO_TIMEVAL(&ifp->tv_lastchanged, &ifp->if_mib.ifdr_data.ifi_lastchange);
283 1.1 scole
284 1.1 scole (void)gettimeofday(&new_tv, NULL);
285 1.1 scole (void)getifmibdata(ifp->if_row, &ifp->if_mib);
286 1.1 scole
287 1.1 scole new_inb = ifp->if_mib.ifdr_data.ifi_ibytes;
288 1.1 scole new_outb = ifp->if_mib.ifdr_data.ifi_obytes;
289 1.1 scole new_inp = ifp->if_mib.ifdr_data.ifi_ipackets;
290 1.1 scole new_outp = ifp->if_mib.ifdr_data.ifi_opackets;
291 1.1 scole
292 1.1 scole /* Display interface if it's received some traffic. */
293 1.1 scole if (new_inb > 0 && old_inb == 0) {
294 1.1 scole ifp->display = 1;
295 1.1 scole needsort = 1;
296 1.1 scole }
297 1.1 scole
298 1.1 scole /*
299 1.1 scole * The rest is pretty trivial. Calculate the new values
300 1.1 scole * for our current traffic rates, and while we're there,
301 1.1 scole * see if we have new peak rates.
302 1.1 scole */
303 1.1 scole old_tv = ifp->tv;
304 1.1 scole timersub(&new_tv, &old_tv, &tv);
305 1.1 scole elapsed = tv.tv_sec + (tv.tv_usec * 1e-6);
306 1.1 scole
307 1.1 scole ifp->if_in_curtraffic = new_inb - old_inb;
308 1.1 scole ifp->if_out_curtraffic = new_outb - old_outb;
309 1.1 scole
310 1.1 scole ifp->if_in_curpps = new_inp - old_inp;
311 1.1 scole ifp->if_out_curpps = new_outp - old_outp;
312 1.1 scole
313 1.1 scole /*
314 1.1 scole * Rather than divide by the time specified on the comm-
315 1.1 scole * and line, we divide by ``elapsed'' as this is likely
316 1.1 scole * to be more accurate.
317 1.1 scole */
318 1.1 scole ifp->if_in_curtraffic /= elapsed;
319 1.1 scole ifp->if_out_curtraffic /= elapsed;
320 1.1 scole ifp->if_in_curpps /= elapsed;
321 1.1 scole ifp->if_out_curpps /= elapsed;
322 1.1 scole
323 1.1 scole if (ifp->if_in_curtraffic > ifp->if_in_traffic_peak)
324 1.1 scole ifp->if_in_traffic_peak = ifp->if_in_curtraffic;
325 1.1 scole
326 1.1 scole if (ifp->if_out_curtraffic > ifp->if_out_traffic_peak)
327 1.1 scole ifp->if_out_traffic_peak = ifp->if_out_curtraffic;
328 1.1 scole
329 1.1 scole if (ifp->if_in_curpps > ifp->if_in_pps_peak)
330 1.1 scole ifp->if_in_pps_peak = ifp->if_in_curpps;
331 1.1 scole
332 1.1 scole if (ifp->if_out_curpps > ifp->if_out_pps_peak)
333 1.1 scole ifp->if_out_pps_peak = ifp->if_out_curpps;
334 1.1 scole
335 1.1 scole ifp->tv.tv_sec = new_tv.tv_sec;
336 1.1 scole ifp->tv.tv_usec = new_tv.tv_usec;
337 1.1 scole
338 1.1 scole }
339 1.1 scole
340 1.1 scole if (needsort)
341 1.1 scole sort_interface_list();
342 1.1 scole
343 1.1 scole return;
344 1.1 scole }
345 1.1 scole
346 1.1 scole /*
347 1.1 scole * We want to right justify our interface names against the first column
348 1.1 scole * (first sixteen or so characters), so we need to do some alignment.
349 1.1 scole */
350 1.1 scole static void
351 1.1 scole right_align_string(struct if_stat *ifp)
352 1.1 scole {
353 1.3 jakllsch if (ifp == NULL || ifp->if_mib.ifdr_name[0] == '\0')
354 1.1 scole return;
355 1.1 scole
356 1.4 christos snprintf(ifp->if_name, IF_NAMESIZE, "%*s", IF_NAMESIZE - 1,
357 1.4 christos ifp->if_mib.ifdr_name);
358 1.1 scole }
359 1.1 scole
360 1.1 scole static int
361 1.1 scole check_match(const char *ifname)
362 1.1 scole {
363 1.1 scole char *p = matchline, *c, t;
364 1.1 scole int match = 0, mlen;
365 1.1 scole
366 1.1 scole if (matchline == NULL)
367 1.1 scole return (0);
368 1.1 scole
369 1.1 scole /* Strip leading whitespaces */
370 1.1 scole while (*p == ' ')
371 1.1 scole p ++;
372 1.1 scole
373 1.1 scole c = p;
374 1.1 scole while ((mlen = strcspn(c, " ;,")) != 0) {
375 1.1 scole p = c + mlen;
376 1.1 scole t = *p;
377 1.1 scole if (p - c > 0) {
378 1.1 scole *p = '\0';
379 1.1 scole if (fnmatch(c, ifname, FNM_CASEFOLD) == 0) {
380 1.1 scole *p = t;
381 1.1 scole return (1);
382 1.1 scole }
383 1.1 scole *p = t;
384 1.1 scole c = p + strspn(p, " ;,");
385 1.1 scole }
386 1.1 scole else {
387 1.1 scole c = p + strspn(p, " ;,");
388 1.1 scole }
389 1.1 scole }
390 1.1 scole
391 1.1 scole return (match);
392 1.1 scole }
393 1.1 scole
394 1.1 scole /*
395 1.1 scole * This function iterates through our list of interfaces, identifying
396 1.1 scole * those that are to be displayed (ifp->display = 1). For each interf-
397 1.1 scole * rface that we're displaying, we generate an appropriate position for
398 1.1 scole * it on the screen (ifp->if_ypos).
399 1.1 scole *
400 1.1 scole * This function is called any time a change is made to an interface's
401 1.1 scole * ``display'' state.
402 1.1 scole */
403 1.1 scole void
404 1.1 scole sort_interface_list(void)
405 1.1 scole {
406 1.1 scole struct if_stat *ifp = NULL;
407 1.1 scole u_int y = STARTING_ROW;
408 1.1 scole
409 1.1 scole SLIST_FOREACH(ifp, &curlist, link) {
410 1.1 scole if (matchline && !check_match(ifp->if_mib.ifdr_name))
411 1.1 scole ifp->match = 0;
412 1.1 scole else
413 1.1 scole ifp->match = 1;
414 1.1 scole if (ifp->display && ifp->match) {
415 1.1 scole ifp->if_ypos = y;
416 1.1 scole y += ROW_SPACING;
417 1.1 scole }
418 1.1 scole }
419 1.1 scole
420 1.1 scole needsort = 0;
421 1.1 scole needclear = 1;
422 1.1 scole }
423 1.1 scole
424 1.1 scole static
425 1.1 scole unsigned int
426 1.1 scole getifnum(void)
427 1.1 scole {
428 1.1 scole struct ifaddrs *ifaddrs = NULL;
429 1.1 scole struct ifaddrs *ifa = NULL;
430 1.1 scole int num = 0;
431 1.1 scole
432 1.1 scole if (getifaddrs(&ifaddrs) == 0) {
433 1.1 scole for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
434 1.1 scole if (ifa->ifa_addr &&
435 1.1 scole ifa->ifa_addr->sa_family == AF_LINK)
436 1.1 scole num++;
437 1.1 scole }
438 1.1 scole
439 1.1 scole freeifaddrs(ifaddrs);
440 1.1 scole }
441 1.1 scole
442 1.1 scole return num;
443 1.1 scole }
444 1.1 scole
445 1.1 scole static void
446 1.1 scole getifmibdata(int row, struct ifdatareq *data)
447 1.1 scole {
448 1.1 scole struct ifaddrs *ifaddrs = NULL;
449 1.1 scole struct ifaddrs *ifa = NULL;
450 1.1 scole int found = 0;
451 1.1 scole int num = 0;
452 1.1 scole
453 1.1 scole if (getifaddrs(&ifaddrs) != 0) {
454 1.1 scole IFSTAT_ERR(2, "getifmibdata() error getting interface data");
455 1.1 scole return;
456 1.1 scole }
457 1.1 scole
458 1.1 scole for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
459 1.1 scole if (ifa->ifa_addr &&
460 1.1 scole ifa->ifa_addr->sa_family == AF_LINK) {
461 1.1 scole num++;
462 1.1 scole
463 1.1 scole /*
464 1.1 scole * expecting rows to start with 1 not 0,
465 1.1 scole * see freebsd "man ifmib"
466 1.1 scole */
467 1.1 scole if (num == row) {
468 1.1 scole found = 1;
469 1.1 scole data->ifdr_data = *(struct if_data *)ifa->ifa_data;
470 1.1 scole strncpy(data->ifdr_name, ifa->ifa_name, IF_NAMESIZE);
471 1.1 scole break;
472 1.1 scole }
473 1.1 scole }
474 1.1 scole }
475 1.1 scole
476 1.1 scole freeifaddrs(ifaddrs);
477 1.1 scole
478 1.1 scole if (!found) {
479 1.1 scole IFSTAT_ERR(2, "getifmibdata() error finding row");
480 1.1 scole }
481 1.1 scole }
482 1.1 scole
483 1.1 scole int
484 1.1 scole cmdifstat(const char *cmd, const char *args)
485 1.1 scole {
486 1.1 scole int retval = 0;
487 1.1 scole
488 1.1 scole retval = ifcmd(cmd, args);
489 1.1 scole /* ifcmd() returns 1 on success */
490 1.1 scole if (retval == 1) {
491 1.1 scole showifstat();
492 1.1 scole refresh();
493 1.1 scole if (needclear) {
494 1.1 scole werase(wnd);
495 1.1 scole labelifstat();
496 1.1 scole needclear = 0;
497 1.1 scole }
498 1.1 scole }
499 1.1 scole
500 1.1 scole return (retval);
501 1.1 scole }
502 1.1 scole
503 1.1 scole void
504 1.1 scole ifstat_scale(char* args)
505 1.1 scole {
506 1.1 scole cmdifstat("scale", args ? args : "");
507 1.1 scole }
508 1.1 scole
509 1.1 scole void
510 1.1 scole ifstat_pps(char* args)
511 1.1 scole {
512 1.1 scole cmdifstat("pps", "");
513 1.1 scole }
514 1.1 scole
515 1.1 scole void
516 1.1 scole ifstat_match(char* args)
517 1.1 scole {
518 1.1 scole cmdifstat("match", args ? args : "");
519 1.1 scole
520 1.1 scole /*
521 1.1 scole * force erase after match command because it is possible for
522 1.1 scole * another command to be sent in the interval before the window
523 1.1 scole * finishes redrawing completely. That stale data remains in window
524 1.1 scole * and never gets overwritten because there are fewer interfaces
525 1.1 scole * being drawn on screen. Only an issue for match command because
526 1.1 scole * pps and scale don't change the number of interfaces being drawn.
527 1.1 scole */
528 1.1 scole werase(wnd);
529 1.1 scole labelifstat();
530 1.1 scole }
531