File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mtr / ui / curses.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:18:58 2023 UTC (18 months, 1 week ago) by misho
Branches: mtr, MAIN
CVS tags: v0_95, HEAD
Version 0.95

    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: 
   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.
   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':
  160:     case -1:
  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;
  239:         if (!running_as_root() && (f < 1.0))
  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");
  367:         printw("  t       switch between ICMP ECHO and TCP\n");
  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 milliseconds. 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;
  409:     int addrcmp_result;
  410:     int err;
  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);
  423:         err = net_err(at);
  424:         addr = net_addr(at);
  425:         mpls = net_mpls(at);
  426: 
  427:         addrcmp_result = addrcmp(addr, &ctl->unspec_addr, ctl->af);
  428: 
  429:         if (err == 0 && addrcmp_result != 0) {
  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("%s", fmt_ipinfo(ctl, addr));
  436: #endif
  437:             if (name != NULL) {
  438:                 if (ctl->show_ips)
  439:                     printw("%s (%s)", name, strlongip(ctl->af, addr));
  440:                 else
  441:                     printw("%s", name);
  442:             } else {
  443:                 printw("%s", strlongip(ctl->af, 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++) {
  468:                 printw("\n    [MPLS: Lbl %lu TC %u S %u TTL %u]",
  469:                        mpls->label[k], mpls->tc[k], mpls->s[k],
  470:                        mpls->ttl[k]);
  471:             }
  472: 
  473:             /* Multi path */
  474:             for (i = 0; i < MAX_PATH; i++) {
  475:                 addrs = net_addrs(at, i);
  476:                 mplss = net_mplss(at, i);
  477:                 if (addrcmp(addrs, addr, ctl->af) == 0)
  478:                     continue;
  479:                 if (addrcmp(addrs, &ctl->unspec_addr,ctl->af) == 0)
  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("%s", fmt_ipinfo(ctl, addrs));
  489: #endif
  490:                 if (name != NULL) {
  491:                     if (ctl->show_ips)
  492:                         printw("%s (%s)", name, strlongip(ctl->af, addrs));
  493:                     else
  494:                         printw("%s", name);
  495:                 } else {
  496:                     printw("%s", strlongip(ctl->af, addrs));
  497:                 }
  498:                 for (k = 0; k < mplss->labels && ctl->enablempls; k++) {
  499:                     printw("\n    [MPLS: Lbl %lu TC %u S %u TTL %u]",
  500:                            mplss->label[k], mplss->tc[k], mplss->s[k],
  501:                            mplss->ttl[k]);
  502:                 }
  503:                 attroff(A_BOLD);
  504:             }
  505:         } else {
  506:             attron(A_BOLD);
  507:             printw("(%s)", host_error_to_string(err));
  508:             attroff(A_BOLD);
  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: {
  626:     int max, at, y, err;
  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);
  637:         err = net_err(at);
  638: 
  639:         if (!addr) {
  640:             printw("(%s)", host_error_to_string(err));
  641:             continue;
  642:         }
  643: 
  644:         if (err == 0
  645:             && addrcmp(addr, &ctl->unspec_addr, ctl->af)) {
  646: 
  647:             if (!net_up(at)) {
  648:                 attron(A_BOLD);
  649:             }
  650: 
  651: #ifdef HAVE_IPINFO
  652:             if (is_printii(ctl))
  653:                 printw("%s", fmt_ipinfo(ctl, addr));
  654: #endif
  655:             name = dns_lookup(ctl, addr);
  656:             printw("%s", name ? name : strlongip(ctl->af, addr));
  657:         } else {
  658:             attron(A_BOLD);
  659:             printw("(%s)", host_error_to_string(err));
  660:         }
  661: 
  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: 
  701:     mvprintw(1, 0, "%s (%s) -> %s (%s)",
  702: 	ctl->LocalHostname, net_localaddr(),
  703: 	ctl->Hostname, net_remoteaddr());
  704:     t = time(NULL);
  705:     mvprintw(1, maxx - 25, "%s", iso_time(&t));
  706:     printw("\n");
  707: 
  708:     printw("Keys:  ");
  709:     attron(A_BOLD);
  710:     printw("H");
  711:     attroff(A_BOLD);
  712:     printw("elp   ");
  713:     attron(A_BOLD);
  714:     printw("D");
  715:     attroff(A_BOLD);
  716:     printw("isplay mode   ");
  717:     attron(A_BOLD);
  718:     printw("R");
  719:     attroff(A_BOLD);
  720:     printw("estart statistics   ");
  721:     attron(A_BOLD);
  722:     printw("O");
  723:     attroff(A_BOLD);
  724:     printw("rder of fields   ");
  725:     attron(A_BOLD);
  726:     printw("q");
  727:     attroff(A_BOLD);
  728:     printw("uit\n");
  729: 
  730:     if (ctl->display_mode == DisplayModeDefault) {
  731:         for (i = 0; i < MAXFLD; i++) {
  732:             j = ctl->fld_index[ctl->fld_active[i]];
  733:             if (j < 0)
  734:                 continue;
  735: 
  736:             snprintf(fmt, sizeof(fmt), "%%%ds", data_fields[j].length);
  737:             snprintf(buf + hd_len, sizeof(buf) - hd_len, fmt,
  738:                      data_fields[j].title);
  739:             hd_len += data_fields[j].length;
  740:         }
  741:         attron(A_BOLD);
  742:         mvprintw(rowstat - 1, 0, " Host");
  743:         mvprintw(rowstat - 1, maxx - hd_len - 1, "%s", buf);
  744:         mvprintw(rowstat - 2, maxx - hd_len - 1,
  745:                  "   Packets               Pings");
  746:         attroff(A_BOLD);
  747: 
  748:         move(rowstat, 0);
  749:         mtr_curses_hosts(ctl, maxx - hd_len - 1);
  750: 
  751:     } else {
  752:         char msg[80];
  753:         int padding = 30;
  754:         int max_cols;
  755: 
  756: #ifdef HAVE_IPINFO
  757:         if (is_printii(ctl))
  758:             padding += get_iiwidth(ctl->ipinfo_no);
  759: #endif
  760:         max_cols =
  761:             maxx <= SAVED_PINGS + padding ? maxx - padding : SAVED_PINGS;
  762:         startstat = padding - 2;
  763: 
  764:         snprintf(msg, sizeof(msg), " Last %3d pings", max_cols);
  765:         mvprintw(rowstat - 1, startstat, "%s", msg);
  766: 
  767:         attroff(A_BOLD);
  768:         move(rowstat, 0);
  769: 
  770:         mtr_gen_scale(ctl);
  771:         mtr_curses_graph(ctl, startstat, max_cols);
  772: 
  773:         printw("\n");
  774:         attron(A_BOLD);
  775:         printw("Scale:");
  776:         attroff(A_BOLD);
  777: 
  778:         for (i = 0; i < NUM_FACTORS - 1; i++) {
  779:             printw("  ");
  780:             attrset(block_col[i + 1]);
  781:             printw("%c", block_map[i]);
  782:             attrset(A_NORMAL);
  783:             printw(":%d ms", scale[i] / 1000);
  784:         }
  785:         printw("  ");
  786:         attrset(block_col[NUM_FACTORS]);
  787:         printw("%c", block_map[NUM_FACTORS - 1]);
  788:         attrset(A_NORMAL);
  789:     }
  790: 
  791:     refresh();
  792: }
  793: 
  794: 
  795: void mtr_curses_open(
  796:     struct mtr_ctl *ctl)
  797: {
  798:     int bg_col = 0;
  799:     int i;
  800: 
  801:     initscr();
  802:     raw();
  803:     noecho();
  804:     start_color();
  805:     if (use_default_colors() == OK)
  806:         bg_col = -1;
  807:     for (i = 0; i < NUM_FACTORS; i++)
  808:         init_pair(i + 1, i, bg_col);
  809: 
  810:     mtr_curses_init();
  811:     mtr_curses_redraw(ctl);
  812: }
  813: 
  814: 
  815: void mtr_curses_close(
  816:     void)
  817: {
  818:     printw("\n");
  819:     endwin();
  820: }
  821: 
  822: 
  823: void mtr_curses_clear(
  824:     struct mtr_ctl *ctl)
  825: {
  826:     mtr_curses_close();
  827:     mtr_curses_open(ctl);
  828: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>