Annotation of embedaddon/mtr/ui/curses.c, revision 1.1.1.2
1.1 misho 1: /*
2: mtr -- a network diagnostic tool
3: Copyright (C) 1997,1998 Matt Kimball
4:
5: This program is free software; you can redistribute it and/or modify
6: it under the terms of the GNU General Public License version 2 as
7: published by the Free Software Foundation.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
1.1.1.2 ! misho 14: You should have received a copy of the GNU General Public License along
! 15: with this program; if not, write to the Free Software Foundation, Inc.,
! 16: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.1 misho 17: */
18:
19: #include "config.h"
20:
21: #include "mtr.h"
22:
23: #include <strings.h>
24: #include <unistd.h>
25:
26: #include <ctype.h>
27: #include <stdlib.h>
28: #include <string.h>
29: #include <time.h>
30:
31: /* MacOSX may need this before socket.h...*/
32: #if defined(HAVE_SYS_TYPES_H)
33: #include <sys/types.h>
34: #endif
35:
36: #include <sys/socket.h>
37: #include <netinet/in.h>
38: #include <arpa/inet.h>
39:
40: #if defined(HAVE_NCURSES_H)
41: #include <ncurses.h>
42: #elif defined(HAVE_NCURSES_CURSES_H)
43: #include <ncurses/curses.h>
44: #elif defined(HAVE_CURSES_H)
45: #include <curses.h>
46: #elif defined(HAVE_CURSESX_H)
47: #include <cursesX.h>
48: #else
49: #error No curses header file available
50: #endif
51:
52: /* This go-around is needed only when compiling with antique version of curses.
53: getmaxyx is part of Technical Standard X/Open Curses Issue 4, Version 2 (1996).
54: http://pubs.opengroup.org/onlinepubs/9693989999/toc.pdf see page 106 */
55: #ifndef getmaxyx
56: #define getmaxyx(win,y,x) ((y) = (win)->_maxy + 1, (x) = (win)->_maxx + 1)
57: #endif
58:
59: #include "mtr.h"
60: #include "mtr-curses.h"
61: #include "net.h"
62: #include "dns.h"
63: #include "asn.h"
64: #include "display.h"
65: #include "utils.h"
66:
67:
68: enum { NUM_FACTORS = 8 };
69: static double factors[NUM_FACTORS];
70: static int scale[NUM_FACTORS];
71: static char block_map[NUM_FACTORS];
72:
73: enum { black = 1, red, green, yellow, blue, magenta, cyan, white };
74: static const int block_col[NUM_FACTORS + 1] = {
75: COLOR_PAIR(red) | A_BOLD,
76: A_NORMAL,
77: COLOR_PAIR(green),
78: COLOR_PAIR(green) | A_BOLD,
79: COLOR_PAIR(yellow) | A_BOLD,
80: COLOR_PAIR(magenta) | A_BOLD,
81: COLOR_PAIR(magenta),
82: COLOR_PAIR(red),
83: COLOR_PAIR(red) | A_BOLD
84: };
85:
86: static void pwcenter(
87: char *str)
88: {
89: int maxx;
90: size_t cx;
91: int __unused_int ATTRIBUTE_UNUSED;
92:
93: getmaxyx(stdscr, __unused_int, maxx);
94: cx = (size_t) (maxx - strlen(str)) / 2;
95: printw("%*s%s", (int) cx, "", str);
96: }
97:
98:
99: static char *format_number(
100: int n,
101: int w,
102: char *buf)
103: {
104: if (w != 5)
105: /* XXX todo: implement w != 5.. */
106: snprintf(buf, w + 1, "%s", "unimpl");
107: else if (n < 100000)
108: /* buf is good as-is */ ;
109: else if (n < 1000000)
110: snprintf(buf, w + 1, "%3dk%1d", n / 1000, (n % 1000) / 100);
111: else if (n < 10000000)
112: snprintf(buf, w + 1, "%1dM%03d", n / 1000000,
113: (n % 1000000) / 1000);
114: else if (n < 100000000)
115: snprintf(buf, w + 1, "%2dM%02d", n / 1000000,
116: (n % 1000000) / 10000);
117: else if (n < 1000000000)
118: snprintf(buf, w + 1, "%3dM%01d", n / 1000000,
119: (n % 1000000) / 100000);
120: else /* if (n < 10000000000) */
121: snprintf(buf, w + 1, "%1dG%03d", n / 1000000000,
122: (n % 1000000000) / 1000000);
123:
124: return buf;
125: }
126:
127:
128: int mtr_curses_keyaction(
129: struct mtr_ctl *ctl)
130: {
131: int c = getch();
132: int i = 0;
133: float f = 0.0;
134: char buf[MAXFLD + 1];
135:
136: if (c == 'Q') { /* must be checked before c = tolower(c) */
137: mvprintw(2, 0, "Type of Service(tos): %d\n", ctl->tos);
138: mvprintw(3, 0,
139: "default 0x00, min cost 0x02, rel 0x04,, thr 0x08, low del 0x10...\n");
140: move(2, 22);
141: refresh();
142: while ((c = getch()) != '\n' && i < MAXFLD) {
143: attron(A_BOLD);
144: printw("%c", c);
145: attroff(A_BOLD);
146: refresh();
147: buf[i++] = c; /* need more checking on 'c' */
148: }
149: buf[i] = '\0';
150: ctl->tos = atoi(buf);
151: if (ctl->tos > 255 || ctl->tos < 0)
152: ctl->tos = 0;
153: return ActionNone;
154: }
155:
156: c = tolower(c);
157:
158: switch (c) {
159: case 'q':
1.1.1.2 ! misho 160: case -1:
1.1 misho 161: case 3:
162: return ActionQuit;
163: case 12:
164: return ActionClear;
165: case 19:
166: case 'p':
167: return ActionPause;
168: case 17:
169: case ' ':
170: return ActionResume;
171: case 'r':
172: return ActionReset;
173: case 'd':
174: return ActionDisplay;
175: case 'e':
176: return ActionMPLS;
177: case 'n':
178: return ActionDNS;
179: #ifdef HAVE_IPINFO
180: case 'y':
181: return ActionII;
182: case 'z':
183: return ActionAS;
184: #endif
185: case '+':
186: return ActionScrollDown;
187: case '-':
188: return ActionScrollUp;
189: case 's':
190: mvprintw(2, 0, "Change Packet Size: %d\n", ctl->cpacketsize);
191: mvprintw(3, 0, "Size Range: %d-%d, < 0:random.\n", MINPACKET,
192: MAXPACKET);
193: move(2, 20);
194: refresh();
195: while ((c = getch()) != '\n' && i < MAXFLD) {
196: attron(A_BOLD);
197: printw("%c", c);
198: attroff(A_BOLD);
199: refresh();
200: buf[i++] = c; /* need more checking on 'c' */
201: }
202: buf[i] = '\0';
203: ctl->cpacketsize = atoi(buf);
204: return ActionNone;
205: case 'b':
206: mvprintw(2, 0, "Ping Bit Pattern: %d\n", ctl->bitpattern);
207: mvprintw(3, 0, "Pattern Range: 0(0x00)-255(0xff), <0 random.\n");
208: move(2, 18);
209: refresh();
210: while ((c = getch()) != '\n' && i < MAXFLD) {
211: attron(A_BOLD);
212: printw("%c", c);
213: attroff(A_BOLD);
214: refresh();
215: buf[i++] = c; /* need more checking on 'c' */
216: }
217: buf[i] = '\0';
218: ctl->bitpattern = atoi(buf);
219: if (ctl->bitpattern > 255)
220: ctl->bitpattern = -1;
221: return ActionNone;
222: case 'i':
223: mvprintw(2, 0, "Interval : %0.0f\n\n", ctl->WaitTime);
224: move(2, 11);
225: refresh();
226: while ((c = getch()) != '\n' && i < MAXFLD) {
227: attron(A_BOLD);
228: printw("%c", c);
229: attroff(A_BOLD);
230: refresh();
231: buf[i++] = c; /* need more checking on 'c' */
232: }
233: buf[i] = '\0';
234:
235: f = atof(buf);
236:
237: if (f <= 0.0)
238: return ActionNone;
1.1.1.2 ! misho 239: if (!running_as_root() && (f < 1.0))
1.1 misho 240: return ActionNone;
241: ctl->WaitTime = f;
242:
243: return ActionNone;
244: case 'f':
245: mvprintw(2, 0, "First TTL: %d\n\n", ctl->fstTTL);
246: move(2, 11);
247: refresh();
248: while ((c = getch()) != '\n' && i < MAXFLD) {
249: attron(A_BOLD);
250: printw("%c", c);
251: attroff(A_BOLD);
252: refresh();
253: buf[i++] = c; /* need more checking on 'c' */
254: }
255: buf[i] = '\0';
256: i = atoi(buf);
257:
258: if (i < 1 || i > ctl->maxTTL)
259: return ActionNone;
260: ctl->fstTTL = i;
261:
262: return ActionNone;
263: case 'm':
264: mvprintw(2, 0, "Max TTL: %d\n\n", ctl->maxTTL);
265: move(2, 9);
266: refresh();
267: while ((c = getch()) != '\n' && i < MAXFLD) {
268: attron(A_BOLD);
269: printw("%c", c);
270: attroff(A_BOLD);
271: refresh();
272: buf[i++] = c; /* need more checking on 'c' */
273: }
274: buf[i] = '\0';
275: i = atoi(buf);
276:
277: if (i < ctl->fstTTL || i > (MaxHost - 1))
278: return ActionNone;
279: ctl->maxTTL = i;
280:
281: return ActionNone;
282: /* fields to display & their ordering */
283: case 'o':
284: mvprintw(2, 0, "Fields: %s\n\n", ctl->fld_active);
285:
286: for (i = 0; i < MAXFLD; i++) {
287: if (data_fields[i].descr != NULL)
288: printw(" %s\n", data_fields[i].descr);
289: }
290: printw("\n");
291: move(2, 8); /* length of "Fields: " */
292: refresh();
293:
294: i = 0;
295: while ((c = getch()) != '\n' && i < MAXFLD) {
296: if (strchr(ctl->available_options, c)) {
297: attron(A_BOLD);
298: printw("%c", c);
299: attroff(A_BOLD);
300: refresh();
301: buf[i++] = c; /* Only permit values in "available_options" be entered */
302: } else {
303: printf("\a"); /* Illegal character. Beep, ring the bell. */
304: }
305: }
306: buf[i] = '\0';
307: if (strlen(buf) > 0)
308: xstrncpy(ctl->fld_active, buf, 2 * MAXFLD);
309:
310: return ActionNone;
311: case 'j':
312: if (strchr(ctl->fld_active, 'N'))
313: /* GeoMean and jitter */
314: xstrncpy(ctl->fld_active, "DR AGJMXI", 2 * MAXFLD);
315: else
316: /* default */
317: xstrncpy(ctl->fld_active, "LS NABWV", 2 * MAXFLD);
318: return ActionNone;
319: case 'u':
320: switch (ctl->mtrtype) {
321: case IPPROTO_ICMP:
322: case IPPROTO_TCP:
323: ctl->mtrtype = IPPROTO_UDP;
324: break;
325: case IPPROTO_UDP:
326: ctl->mtrtype = IPPROTO_ICMP;
327: break;
328: }
329: return ActionNone;
330: case 't':
331: switch (ctl->mtrtype) {
332: case IPPROTO_ICMP:
333: case IPPROTO_UDP:
334: ctl->mtrtype = IPPROTO_TCP;
335: break;
336: case IPPROTO_TCP:
337: ctl->mtrtype = IPPROTO_ICMP;
338: break;
339: }
340: return ActionNone;
341: /* reserve to display help message -Min */
342: case '?':
343: case 'h':
344: mvprintw(2, 0, "Command:\n");
345: printw(" ?|h help\n");
346: printw(" p pause (SPACE to resume)\n");
347: printw(" d switching display mode\n");
348: printw(" e toggle MPLS information on/off\n");
349: printw(" n toggle DNS on/off\n");
350: printw(" r reset all counters\n");
351: printw
352: (" o str set the columns to display, default str='LRS N BAWV'\n");
353: printw
354: (" j toggle latency(LS NABWV)/jitter(DR AGJMXI) stats\n");
355: printw(" c <n> report cycle n, default n=infinite\n");
356: printw
357: (" i <n> set the ping interval to n seconds, default n=1\n");
358: printw
359: (" f <n> set the initial time-to-live(ttl), default n=1\n");
360: printw
361: (" m <n> set the max time-to-live, default n= # of hops\n");
362: printw(" s <n> set the packet size to n or random(n<0)\n");
363: printw
364: (" b <c> set ping bit pattern to c(0..255) or random(c<0)\n");
365: printw(" Q <t> set ping packet's TOS to t\n");
366: printw(" u switch between ICMP ECHO and UDP datagrams\n");
1.1.1.2 ! misho 367: printw(" t switch between ICMP ECHO and TCP\n");
1.1 misho 368: #ifdef HAVE_IPINFO
369: printw(" y switching IP info\n");
370: printw(" z toggle ASN info on/off\n");
371: #endif
372: printw("\n");
373: printw(" press any key to go back...");
374: getch(); /* read and ignore 'any key' */
375: return ActionNone;
376: default: /* ignore unknown input */
377: return ActionNone;
378: }
379: }
380:
381:
382: static void format_field(
383: char *dst,
384: int dst_length,
385: const char *format,
386: int n)
387: {
388: if (index(format, 'N')) {
389: *dst++ = ' ';
390: format_number(n, 5, dst);
391: } else if (strchr(format, 'f')) {
392: /* this is for fields where we measure integer microseconds but
393: display floating point miliseconds. Convert to float here. */
394: snprintf(dst, dst_length, format, n / 1000.0);
395: /* this was marked as a temporary hack over 10 years ago. -- REW */
396: } else {
397: snprintf(dst, dst_length, format, n);
398: }
399: }
400:
401: static void mtr_curses_hosts(
402: struct mtr_ctl *ctl,
403: int startstat)
404: {
405: int max;
406: int at;
407: struct mplslen *mpls, *mplss;
408: ip_t *addr, *addrs;
1.1.1.2 ! misho 409: int addrcmp_result;
! 410: int err;
1.1 misho 411: int y;
412: char *name;
413:
414: int i, j, k;
415: int hd_len;
416: char buf[1024];
417: int __unused_int ATTRIBUTE_UNUSED;
418:
419: max = net_max(ctl);
420:
421: for (at = net_min(ctl) + ctl->display_offset; at < max; at++) {
422: printw("%2d. ", at + 1);
1.1.1.2 ! misho 423: err = net_err(at);
1.1 misho 424: addr = net_addr(at);
425: mpls = net_mpls(at);
426:
1.1.1.2 ! misho 427: addrcmp_result = addrcmp(addr, &ctl->unspec_addr, ctl->af);
! 428:
! 429: if (err == 0 && addrcmp_result != 0) {
1.1 misho 430: name = dns_lookup(ctl, addr);
431: if (!net_up(at))
432: attron(A_BOLD);
433: #ifdef HAVE_IPINFO
434: if (is_printii(ctl))
435: printw(fmt_ipinfo(ctl, addr));
436: #endif
437: if (name != NULL) {
438: if (ctl->show_ips)
439: printw("%s (%s)", name, strlongip(ctl, addr));
440: else
441: printw("%s", name);
442: } else {
443: printw("%s", strlongip(ctl, addr));
444: }
445: attroff(A_BOLD);
446:
447: getyx(stdscr, y, __unused_int);
448: move(y, startstat);
449:
450: /* net_xxx returns times in usecs. Just display millisecs */
451: hd_len = 0;
452: for (i = 0; i < MAXFLD; i++) {
453: /* Ignore options that don't exist */
454: /* On the other hand, we now check the input side. Shouldn't happen,
455: can't be careful enough. */
456: j = ctl->fld_index[ctl->fld_active[i]];
457: if (j == -1)
458: continue;
459: format_field(buf + hd_len, sizeof(buf) - hd_len,
460: data_fields[j].format,
461: data_fields[j].net_xxx(at));
462: hd_len += data_fields[j].length;
463: }
464: buf[hd_len] = 0;
465: printw("%s", buf);
466:
467: for (k = 0; k < mpls->labels && ctl->enablempls; k++) {
1.1.1.2 ! misho 468: printw("\n [MPLS: Lbl %lu TC %u S %u TTL %u]",
! 469: mpls->label[k], mpls->tc[k], mpls->s[k],
1.1 misho 470: mpls->ttl[k]);
471: }
472:
473: /* Multi path */
1.1.1.2 ! misho 474: for (i = 0; i < MAX_PATH; i++) {
1.1 misho 475: addrs = net_addrs(at, i);
476: mplss = net_mplss(at, i);
1.1.1.2 ! misho 477: if (addrcmp(addrs, addr, ctl->af) == 0)
1.1 misho 478: continue;
1.1.1.2 ! misho 479: if (addrcmp(addrs, &ctl->unspec_addr,ctl->af) == 0)
1.1 misho 480: break;
481:
482: name = dns_lookup(ctl, addrs);
483: if (!net_up(at))
484: attron(A_BOLD);
485: printw("\n ");
486: #ifdef HAVE_IPINFO
487: if (is_printii(ctl))
488: printw(fmt_ipinfo(ctl, addrs));
489: #endif
490: if (name != NULL) {
491: if (ctl->show_ips)
492: printw("%s (%s)", name, strlongip(ctl, addrs));
493: else
494: printw("%s", name);
495: } else {
496: printw("%s", strlongip(ctl, addrs));
497: }
498: for (k = 0; k < mplss->labels && ctl->enablempls; k++) {
1.1.1.2 ! misho 499: printw("\n [MPLS: Lbl %lu TC %u S %u TTL %u]",
! 500: mplss->label[k], mplss->tc[k], mplss->s[k],
1.1 misho 501: mplss->ttl[k]);
502: }
503: attroff(A_BOLD);
504: }
505: } else {
1.1.1.2 ! misho 506: attron(A_BOLD);
! 507: printw("(%s)", host_error_to_string(err));
! 508: attroff(A_BOLD);
1.1 misho 509: }
510:
511: printw("\n");
512: }
513: move(2, 0);
514: }
515:
516: static void mtr_gen_scale(
517: struct mtr_ctl *ctl)
518: {
519: int *saved, i, max, at;
520: int range;
521: static int low_ms, high_ms;
522:
523: low_ms = 1000000;
524: high_ms = -1;
525:
526: for (i = 0; i < NUM_FACTORS; i++) {
527: scale[i] = 0;
528: }
529: max = net_max(ctl);
530: for (at = ctl->display_offset; at < max; at++) {
531: saved = net_saved_pings(at);
532: for (i = 0; i < SAVED_PINGS; i++) {
533: if (saved[i] < 0)
534: continue;
535: if (saved[i] < low_ms) {
536: low_ms = saved[i];
537: }
538: if (saved[i] > high_ms) {
539: high_ms = saved[i];
540: }
541: }
542: }
543: range = high_ms - low_ms;
544: for (i = 0; i < NUM_FACTORS; i++) {
545: scale[i] = low_ms + ((double) range * factors[i]);
546: }
547: }
548:
549: static void mtr_curses_init(
550: void)
551: {
552: int i;
553: int block_split;
554:
555: /* Initialize factors to a log scale. */
556: for (i = 0; i < NUM_FACTORS; i++) {
557: factors[i] = ((double) 1 / NUM_FACTORS) * (i + 1);
558: factors[i] *= factors[i]; /* Squared. */
559: }
560:
561: /* Initialize block_map. The block_split is always smaller than 9 */
562: block_split = (NUM_FACTORS - 2) / 2;
563: for (i = 1; i <= block_split; i++) {
564: block_map[i] = '0' + i;
565: }
566: for (i = block_split + 1; i < NUM_FACTORS - 1; i++) {
567: block_map[i] = 'a' + i - block_split - 1;
568: }
569: block_map[0] = '.';
570: block_map[NUM_FACTORS - 1] = '>';
571: }
572:
573: static void mtr_print_scaled(
574: int ms)
575: {
576: int i;
577:
578: for (i = 0; i < NUM_FACTORS; i++) {
579: if (ms <= scale[i]) {
580: attrset(block_col[i + 1]);
581: printw("%c", block_map[i]);
582: attrset(A_NORMAL);
583: return;
584: }
585: }
586: printw(">");
587: }
588:
589:
590: static void mtr_fill_graph(
591: struct mtr_ctl *ctl,
592: int at,
593: int cols)
594: {
595: int *saved;
596: int i;
597:
598: saved = net_saved_pings(at);
599: for (i = SAVED_PINGS - cols; i < SAVED_PINGS; i++) {
600: if (saved[i] == -2) {
601: printw(" ");
602: } else if (saved[i] == -1) {
603: attrset(block_col[0]);
604: printw("%c", '?');
605: attrset(A_NORMAL);
606: } else {
607: if (ctl->display_mode == DisplayModeBlockmap) {
608: if (saved[i] > scale[6]) {
609: printw("%c", block_map[NUM_FACTORS - 1]);
610: } else {
611: printw(".");
612: }
613: } else {
614: mtr_print_scaled(saved[i]);
615: }
616: }
617: }
618: }
619:
620:
621: static void mtr_curses_graph(
622: struct mtr_ctl *ctl,
623: int startstat,
624: int cols)
625: {
1.1.1.2 ! misho 626: int max, at, y, err;
1.1 misho 627: ip_t *addr;
628: char *name;
629: int __unused_int ATTRIBUTE_UNUSED;
630:
631: max = net_max(ctl);
632:
633: for (at = ctl->display_offset; at < max; at++) {
634: printw("%2d. ", at + 1);
635:
636: addr = net_addr(at);
1.1.1.2 ! misho 637: err = net_err(at);
! 638:
1.1 misho 639: if (!addr) {
1.1.1.2 ! misho 640: printw("(%s)", host_error_to_string(err));
1.1 misho 641: continue;
642: }
643:
1.1.1.2 ! misho 644: if (err == 0
! 645: && addrcmp(addr, &ctl->unspec_addr, ctl->af)) {
! 646:
! 647: if (!net_up(at)) {
! 648: attron(A_BOLD);
! 649: }
! 650:
1.1 misho 651: #ifdef HAVE_IPINFO
652: if (is_printii(ctl))
653: printw(fmt_ipinfo(ctl, addr));
654: #endif
655: name = dns_lookup(ctl, addr);
656: printw("%s", name ? name : strlongip(ctl, addr));
1.1.1.2 ! misho 657: } else {
! 658: attron(A_BOLD);
! 659: printw("(%s)", host_error_to_string(err));
! 660: }
! 661:
1.1 misho 662: attroff(A_BOLD);
663:
664: getyx(stdscr, y, __unused_int);
665: move(y, startstat);
666:
667: printw(" ");
668: mtr_fill_graph(ctl, at, cols);
669: printw("\n");
670: }
671: }
672:
673:
674: void mtr_curses_redraw(
675: struct mtr_ctl *ctl)
676: {
677: int maxx;
678: int startstat;
679: int rowstat;
680: time_t t;
681: int __unused_int ATTRIBUTE_UNUSED;
682:
683: int i, j;
684: int hd_len = 0;
685: char buf[1024];
686: char fmt[16];
687:
688:
689: erase();
690: getmaxyx(stdscr, __unused_int, maxx);
691:
692: rowstat = 5;
693:
694: move(0, 0);
695: attron(A_BOLD);
696: snprintf(buf, sizeof(buf), "%s%s%s", "My traceroute [v",
697: PACKAGE_VERSION, "]");
698: pwcenter(buf);
699: attroff(A_BOLD);
700:
1.1.1.2 ! misho 701: mvprintw(1, 0, "%s (%s) -> %s", ctl->LocalHostname, net_localaddr(), ctl->Hostname);
1.1 misho 702: t = time(NULL);
703: mvprintw(1, maxx - 25, iso_time(&t));
704: printw("\n");
705:
706: printw("Keys: ");
707: attron(A_BOLD);
708: printw("H");
709: attroff(A_BOLD);
710: printw("elp ");
711: attron(A_BOLD);
712: printw("D");
713: attroff(A_BOLD);
714: printw("isplay mode ");
715: attron(A_BOLD);
716: printw("R");
717: attroff(A_BOLD);
718: printw("estart statistics ");
719: attron(A_BOLD);
720: printw("O");
721: attroff(A_BOLD);
722: printw("rder of fields ");
723: attron(A_BOLD);
724: printw("q");
725: attroff(A_BOLD);
726: printw("uit\n");
727:
728: if (ctl->display_mode == DisplayModeDefault) {
729: for (i = 0; i < MAXFLD; i++) {
730: j = ctl->fld_index[ctl->fld_active[i]];
731: if (j < 0)
732: continue;
733:
734: snprintf(fmt, sizeof(fmt), "%%%ds", data_fields[j].length);
735: snprintf(buf + hd_len, sizeof(buf) - hd_len, fmt,
736: data_fields[j].title);
737: hd_len += data_fields[j].length;
738: }
739: attron(A_BOLD);
740: mvprintw(rowstat - 1, 0, " Host");
741: mvprintw(rowstat - 1, maxx - hd_len - 1, "%s", buf);
742: mvprintw(rowstat - 2, maxx - hd_len - 1,
743: " Packets Pings");
744: attroff(A_BOLD);
745:
746: move(rowstat, 0);
747: mtr_curses_hosts(ctl, maxx - hd_len - 1);
748:
749: } else {
750: char msg[80];
751: int padding = 30;
752: int max_cols;
753:
754: #ifdef HAVE_IPINFO
755: if (is_printii(ctl))
756: padding += get_iiwidth(ctl->ipinfo_no);
757: #endif
758: max_cols =
759: maxx <= SAVED_PINGS + padding ? maxx - padding : SAVED_PINGS;
760: startstat = padding - 2;
761:
762: snprintf(msg, sizeof(msg), " Last %3d pings", max_cols);
763: mvprintw(rowstat - 1, startstat, msg);
764:
765: attroff(A_BOLD);
766: move(rowstat, 0);
767:
768: mtr_gen_scale(ctl);
769: mtr_curses_graph(ctl, startstat, max_cols);
770:
771: printw("\n");
772: attron(A_BOLD);
773: printw("Scale:");
774: attroff(A_BOLD);
775:
776: for (i = 0; i < NUM_FACTORS - 1; i++) {
777: printw(" ");
778: attrset(block_col[i + 1]);
779: printw("%c", block_map[i]);
780: attrset(A_NORMAL);
781: printw(":%d ms", scale[i] / 1000);
782: }
783: printw(" ");
784: attrset(block_col[NUM_FACTORS]);
785: printw("%c", block_map[NUM_FACTORS - 1]);
786: attrset(A_NORMAL);
787: }
788:
789: refresh();
790: }
791:
792:
793: void mtr_curses_open(
794: struct mtr_ctl *ctl)
795: {
796: int bg_col = 0;
797: int i;
798:
799: initscr();
800: raw();
801: noecho();
802: start_color();
803: if (use_default_colors() == OK)
804: bg_col = -1;
805: for (i = 0; i < NUM_FACTORS; i++)
806: init_pair(i + 1, i, bg_col);
807:
808: mtr_curses_init();
809: mtr_curses_redraw(ctl);
810: }
811:
812:
813: void mtr_curses_close(
814: void)
815: {
816: printw("\n");
817: endwin();
818: }
819:
820:
821: void mtr_curses_clear(
822: struct mtr_ctl *ctl)
823: {
824: mtr_curses_close();
825: mtr_curses_open(ctl);
826: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>