21 #include "addr_hash.h"
22 #include "serv_hash.h"
25 #include "sorted_list.h"
27 #include "screenfilter.h"
29 #define HOSTNAME_LENGTH 256
31 #define HISTORY_DIVISIONS 3
35 #define HELP_MESSAGE \
36 "Host display: General:\n"\
37 " n - toggle DNS host resolution P - pause display\n"\
38 " s - toggle show source host h - toggle this help display\n"\
39 " d - toggle show destination host b - toggle bar graph display\n"\
40 " t - cycle line display mode B - cycle bar graph average\n"\
41 " T - toggle cumulative line totals\n"\
42 "Port display: j/k - scroll display\n"\
43 " N - toggle service resolution f - edit filter code\n"\
44 " S - toggle show source port l - set screen filter\n"\
45 " D - toggle show destination port L - lin/log scales\n"\
46 " p - toggle port display ! - shell command\n"\
49 " 1/2/3 - sort by 1st/2nd/3rd column\n"\
50 " < - sort by source name\n"\
51 " > - sort by dest name\n"\
52 " o - freeze current order\n"\
54 "iftop, version " IFTOP_VERSION
57 /* 2, 10 and 40 seconds */
58 int history_divs[HISTORY_DIVISIONS] = {1, 5, 20};
60 #define UNIT_DIVISIONS 4
61 char* unit_bits[UNIT_DIVISIONS] = { "b", "kb", "Mb", "Gb"};
62 char* unit_bytes[UNIT_DIVISIONS] = { "B", "kB", "MB", "GB"};
64 typedef struct host_pair_line_tag {
66 double long total_recv;
67 double long total_sent;
68 double long recv[HISTORY_DIVISIONS];
69 double long sent[HISTORY_DIVISIONS];
73 extern hash_type* history;
74 extern int history_pos;
75 extern int history_len;
77 extern options_t options ;
81 hash_type* screen_hash;
82 hash_type* service_hash;
83 sorted_list_type screen_list;
84 host_pair_line totals;
85 int peaksent, peakrecv, peaktotal;
87 #define HELP_MSG_SIZE 80
89 int persistenthelp = 0;
91 char helpmsg[HELP_MSG_SIZE];
92 int dontshowdisplay = 0;
95 * Compare two screen lines based on bandwidth. Start comparing from the
98 int screen_line_bandwidth_compare(host_pair_line* aa, host_pair_line* bb, int start_div) {
100 switch(options.linedisplay) {
101 case OPTION_LINEDISPLAY_ONE_LINE_SENT:
102 for(i = start_div; i < HISTORY_DIVISIONS; i++) {
103 if(aa->sent[i] != bb->sent[i]) {
104 return(aa->sent[i] < bb->sent[i]);
108 case OPTION_LINEDISPLAY_ONE_LINE_RECV:
109 for(i = start_div; i < HISTORY_DIVISIONS; i++) {
110 if(aa->recv[i] != bb->recv[i]) {
111 return(aa->recv[i] < bb->recv[i]);
115 case OPTION_LINEDISPLAY_TWO_LINE:
116 case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
117 /* fallback to the combined sent+recv that also act as fallback for sent/recv */
120 for(i = start_div; i < HISTORY_DIVISIONS; i++) {
121 if(aa->recv[i] + aa->sent[i] != bb->recv[i] + bb->sent[i]) {
122 return(aa->recv[i] + aa->sent[i] < bb->recv[i] + bb->sent[i]);
129 * Compare two screen lines based on hostname / IP. Fall over to compare by
132 int screen_line_host_compare(void* a, void* b, host_pair_line* aa, host_pair_line* bb) {
133 char hosta[HOSTNAME_LENGTH], hostb[HOSTNAME_LENGTH];
136 /* This isn't overly efficient because we resolve again before
138 if (options.dnsresolution) {
139 resolve(aa->ap.af, a, hosta, HOSTNAME_LENGTH);
140 resolve(bb->ap.af, b, hostb, HOSTNAME_LENGTH);
143 inet_ntop(aa->ap.af, a, hosta, sizeof(hosta));
144 inet_ntop(bb->ap.af, b, hostb, sizeof(hostb));
147 r = strcmp(hosta, hostb);
150 return screen_line_bandwidth_compare(aa, bb, 2);
159 int screen_line_compare(void* a, void* b) {
160 host_pair_line* aa = (host_pair_line*)a;
161 host_pair_line* bb = (host_pair_line*)b;
162 if(options.sort == OPTION_SORT_DIV1) {
163 return screen_line_bandwidth_compare(aa, bb, 0);
165 else if(options.sort == OPTION_SORT_DIV2) {
166 return screen_line_bandwidth_compare(aa, bb, 1);
168 else if(options.sort == OPTION_SORT_DIV3) {
169 return screen_line_bandwidth_compare(aa, bb, 2);
171 else if(options.sort == OPTION_SORT_SRC) {
172 return screen_line_host_compare(&(aa->ap.src6), &(bb->ap.src6), aa, bb);
174 else if(options.sort == OPTION_SORT_DEST) {
175 return screen_line_host_compare(&(aa->ap.dst6), &(bb->ap.dst6), aa, bb);
181 void readable_size(float n, char* buf, int bsize, int ksize, int bytes) {
186 /* Convert to bits? */
192 if(n < size * 1000 || i >= UNIT_DIVISIONS - 1) {
193 snprintf(buf, bsize, " %4.0f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]);
199 snprintf(buf, bsize, " %4.2f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]);
202 else if(n < size * 100) {
203 snprintf(buf, bsize, " %4.1f%s", n / size, bytes ? unit_bytes[i] : unit_bits[i]);
210 /* Barchart scales. */
214 { 64000, 10 }, /* 64 kbit/s */
217 { 1000000, 10 }, /* 1 Mbit/s */
220 { 1000000000, 100 } /* 1 Gbit/s */
222 static int rateidx = 0, wantbiggerrate;
224 static int rateidx_init = 0;
226 static int get_bar_interval(float bandwidth) {
228 if(bandwidth > 100000000) {
234 static float get_max_bandwidth() {
236 if(options.max_bandwidth > 0) {
237 max = options.max_bandwidth;
240 max = scale[rateidx].max;
246 static int get_bar_length(const int rate) {
250 if (rate > scale[rateidx].max) {
253 while(rate > scale[rateidx_init++].max) {
255 rateidx = rateidx_init;
258 if(options.log_scale) {
259 l = log(rate) / log(get_max_bandwidth());
262 l = rate / get_max_bandwidth();
267 static void draw_bar_scale(int* y) {
270 max = get_max_bandwidth();
271 interval = get_bar_interval(max);
272 if(options.showbars) {
274 /* Draw bar graph scale on top of the window. */
277 mvhline(*y + 1, 0, 0, COLS);
280 if(options.log_scale) {
289 /* for (i = 1.25; i * 8 <= max; i *= interval) { */
293 /* This 1024 vs 1000 stuff is just plain evil */
294 readable_size(i, s, sizeof s, options.log_scale ? 1000 : 1024, options.bandwidth_in_bytes);
295 p = s + strspn(s, " ");
296 x = get_bar_length(i * 8);
297 mvaddch(*y + 1, x, ACS_BTEE);
298 if (x + strlen(p) >= COLS)
299 x = COLS - strlen(p);
302 if(options.log_scale) {
309 mvaddch(*y + 1, 0, ACS_LLCORNER);
313 mvhline(*y, 0, 0, COLS);
318 int history_length(const int d) {
319 if (history_len < history_divs[d])
320 return history_len * RESOLUTION;
322 return history_divs[d] * RESOLUTION;
325 void draw_line_total(float sent, float recv, int y, int x, option_linedisplay_t linedisplay, int bytes) {
328 switch(linedisplay) {
329 case OPTION_LINEDISPLAY_TWO_LINE:
330 draw_line_total(sent, recv, y, x, OPTION_LINEDISPLAY_ONE_LINE_SENT, bytes);
331 draw_line_total(sent, recv, y+1, x, OPTION_LINEDISPLAY_ONE_LINE_RECV, bytes);
333 case OPTION_LINEDISPLAY_ONE_LINE_SENT:
336 case OPTION_LINEDISPLAY_ONE_LINE_RECV:
339 case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
343 if(linedisplay != OPTION_LINEDISPLAY_TWO_LINE) {
344 readable_size(n, buf, 10, 1024, bytes);
349 void draw_bar(float n, int y) {
351 mvchgat(y, 0, -1, A_NORMAL, 0, NULL);
352 L = get_bar_length(8 * n);
354 mvchgat(y, 0, L + 1, A_REVERSE, 0, NULL);
357 void draw_line_totals(int y, host_pair_line* line, option_linedisplay_t linedisplay) {
359 int x = (COLS - 8 * HISTORY_DIVISIONS);
361 for(j = 0; j < HISTORY_DIVISIONS; j++) {
362 draw_line_total(line->sent[j], line->recv[j], y, x, linedisplay, options.bandwidth_in_bytes);
366 if(options.showbars) {
367 switch(linedisplay) {
368 case OPTION_LINEDISPLAY_TWO_LINE:
369 draw_bar(line->sent[options.bar_interval],y);
370 draw_bar(line->recv[options.bar_interval],y+1);
372 case OPTION_LINEDISPLAY_ONE_LINE_SENT:
373 draw_bar(line->sent[options.bar_interval],y);
375 case OPTION_LINEDISPLAY_ONE_LINE_RECV:
376 draw_bar(line->recv[options.bar_interval],y);
378 case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
379 draw_bar(line->recv[options.bar_interval] + line->sent[options.bar_interval],y);
385 void draw_totals(host_pair_line* totals) {
390 int x = (COLS - 8 * HISTORY_DIVISIONS);
392 draw_line_totals(y, totals, OPTION_LINEDISPLAY_TWO_LINE);
394 for(j = 0; j < HISTORY_DIVISIONS; j++) {
395 readable_size((totals->sent[j] + totals->recv[j]) , buf, 10, 1024, options.bandwidth_in_bytes);
401 extern history_type history_totals;
403 void screen_list_init() {
404 screen_list.compare = &screen_line_compare;
405 sorted_list_initialise(&screen_list);
408 void screen_list_clear() {
409 sorted_list_node* nn = NULL;
410 peaksent = peakrecv = peaktotal = 0;
411 while((nn = sorted_list_next_item(&screen_list, nn)) != NULL) {
414 sorted_list_destroy(&screen_list);
417 void calculate_totals() {
421 * Calculate peaks and totals
423 for(i = 0; i < HISTORY_LENGTH; i++) {
425 int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
427 for(j = 0; j < HISTORY_DIVISIONS; j++) {
428 if(i < history_divs[j]) {
429 totals.recv[j] += history_totals.recv[ii];
430 totals.sent[j] += history_totals.sent[ii];
434 if(history_totals.recv[i] > peakrecv) {
435 peakrecv = history_totals.recv[i];
437 if(history_totals.sent[i] > peaksent) {
438 peaksent = history_totals.sent[i];
440 if(history_totals.recv[i] + history_totals.sent[i] > peaktotal) {
441 peaktotal = history_totals.recv[i] + history_totals.sent[i];
444 for(i = 0; i < HISTORY_DIVISIONS; i++) {
445 int t = history_length(i);
451 void make_screen_list() {
452 hash_node_type* n = NULL;
453 while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) {
454 host_pair_line* line = (host_pair_line*)n->rec;
456 for(i = 0; i < HISTORY_DIVISIONS; i++) {
457 line->recv[i] /= history_length(i);
458 line->sent[i] /= history_length(i);
461 /* Don't make a new, sorted screen list if order is frozen
463 if(!options.freezeorder) {
464 sorted_list_insert(&screen_list, line);
471 * Zeros all data in the screen hash, but does not remove items.
473 void screen_hash_clear() {
474 hash_node_type* n = NULL;
475 while(hash_next_item(screen_hash, &n) == HASH_STATUS_OK) {
476 host_pair_line* hpl = (host_pair_line*)n->rec;
477 hpl->total_recv = hpl->total_sent = 0;
478 memset(hpl->recv, 0, sizeof(hpl->recv));
479 memset(hpl->sent, 0, sizeof(hpl->sent));
483 void analyse_data() {
484 hash_node_type* n = NULL;
486 if(options.paused == 1) {
491 memset(&totals, 0, sizeof totals);
493 if(options.freezeorder) {
498 hash_delete_all(screen_hash);
501 while(hash_next_item(history, &n) == HASH_STATUS_OK) {
502 history_type* d = (history_type*)n->rec;
503 host_pair_line* screen_line;
505 host_pair_line **h_p_l_pp;
507 } u_screen_line = { &screen_line };
514 ap = *(addr_pair*)n->key;
516 /* Aggregate hosts, if required */
517 if(options.aggregate_src) {
518 memset(&ap.src6, '\0', sizeof(ap.src6));
520 if(options.aggregate_dest) {
521 memset(&ap.dst6, '\0', sizeof(ap.dst6));
524 /* Aggregate ports, if required */
525 if(options.showports == OPTION_PORTS_DEST || options.showports == OPTION_PORTS_OFF) {
528 if(options.showports == OPTION_PORTS_SRC || options.showports == OPTION_PORTS_OFF) {
531 if(options.showports == OPTION_PORTS_OFF) {
536 if(hash_find(screen_hash, &ap, u_screen_line.void_pp) == HASH_STATUS_KEY_NOT_FOUND) {
537 screen_line = xcalloc(1, sizeof *screen_line);
538 hash_insert(screen_hash, &ap, screen_line);
539 screen_line->ap = ap;
542 screen_line->total_sent += d->total_sent;
543 screen_line->total_recv += d->total_recv;
545 for(i = 0; i < HISTORY_LENGTH; i++) {
547 int ii = (HISTORY_LENGTH + history_pos - i) % HISTORY_LENGTH;
549 for(j = 0; j < HISTORY_DIVISIONS; j++) {
550 if(i < history_divs[j]) {
551 screen_line->recv[j] += d->recv[ii];
552 screen_line->sent[j] += d->sent[ii];
566 void sprint_host(char * line, int af, struct in6_addr* addr, unsigned int port, unsigned int protocol, int L) {
567 char hostname[HOSTNAME_LENGTH];
568 char service[HOSTNAME_LENGTH];
573 } u_s_name = { &s_name };
578 if(IN6_IS_ADDR_UNSPECIFIED(addr)) {
579 sprintf(hostname, " * ");
582 if (options.dnsresolution)
583 resolve(af, addr, hostname, L);
585 inet_ntop(af, addr, hostname, sizeof(hostname));
587 left = strlen(hostname);
591 skey.protocol = protocol;
592 if(options.portresolution && hash_find(service_hash, &skey, u_s_name.void_pp) == HASH_STATUS_OK) {
593 snprintf(service, HOSTNAME_LENGTH, ":%s", s_name);
596 snprintf(service, HOSTNAME_LENGTH, ":%d", port);
604 sprintf(line, "%-*s", L, hostname);
605 if(left > (L - strlen(service))) {
606 left = L - strlen(service);
611 sprintf(line + left, "%-*s", L-left, service);
617 sorted_list_node* nn = NULL;
618 char host1[HOSTNAME_LENGTH], host2[HOSTNAME_LENGTH];
626 if (!line || lcols != COLS) {
628 line = calloc(COLS + 1, 1);
632 * erase() is faster than clear(). Dunno why we switched to
633 * clear() -pdw 24/10/02
639 if(options.showhelp) {
640 mvaddstr(y,0,HELP_MESSAGE);
645 while(i < options.screen_offset && ((nn = sorted_list_next_item(&screen_list, nn)) != NULL)) {
649 /* Screen layout: we have 2 * HISTORY_DIVISIONS 6-character wide history
650 * items, and so can use COLS - 12 * HISTORY_DIVISIONS to print the two
653 if(i == 0 || nn != NULL) {
654 while((y < LINES - 5) && ((nn = sorted_list_next_item(&screen_list, nn)) != NULL)) {
658 host_pair_line* screen_line = (host_pair_line*)nn->data;
661 L = (COLS - 8 * HISTORY_DIVISIONS - 4) / 2;
662 if(options.show_totals) {
665 if(L > HOSTNAME_LENGTH) {
669 sprint_host(host1, screen_line->ap.af,
670 &(screen_line->ap.src6),
671 screen_line->ap.src_port,
672 screen_line->ap.protocol, L);
673 sprint_host(host2, screen_line->ap.af,
674 &(screen_line->ap.dst6),
675 screen_line->ap.dst_port,
676 screen_line->ap.protocol, L);
678 if(!screen_filter_match(host1) && !screen_filter_match(host2)) {
682 mvaddstr(y, x, host1);
685 switch(options.linedisplay) {
686 case OPTION_LINEDISPLAY_TWO_LINE:
687 mvaddstr(y, x, " => ");
688 mvaddstr(y+1, x, " <= ");
690 case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
691 mvaddstr(y, x, "<=> ");
693 case OPTION_LINEDISPLAY_ONE_LINE_SENT:
694 mvaddstr(y, x, " => ");
696 case OPTION_LINEDISPLAY_ONE_LINE_RECV:
697 mvaddstr(y, x, " <= ");
704 mvaddstr(y, x, host2);
706 if(options.show_totals) {
707 draw_line_total(screen_line->total_sent, screen_line->total_recv, y, COLS - 8 * (HISTORY_DIVISIONS + 1), options.linedisplay, 1);
710 draw_line_totals(y, screen_line, options.linedisplay);
713 if(options.linedisplay == OPTION_LINEDISPLAY_TWO_LINE) {
726 mvhline(y-1, 0, 0, COLS);
728 mvaddstr(y, 0, "TX: ");
729 mvaddstr(y+1, 0, "RX: ");
730 mvaddstr(y+2, 0, "TOTAL: ");
732 /* Cummulative totals */
733 mvaddstr(y, 16, "cum: ");
735 readable_size(history_totals.total_sent, line, 10, 1024, 1);
736 mvaddstr(y, 22, line);
738 readable_size(history_totals.total_recv, line, 10, 1024, 1);
739 mvaddstr(y+1, 22, line);
741 readable_size(history_totals.total_recv + history_totals.total_sent, line, 10, 1024, 1);
742 mvaddstr(y+2, 22, line);
745 mvaddstr(y, 32, "peak: ");
747 readable_size(peaksent / RESOLUTION, line, 10, 1024, options.bandwidth_in_bytes);
748 mvaddstr(y, 39, line);
750 readable_size(peakrecv / RESOLUTION, line, 10, 1024, options.bandwidth_in_bytes);
751 mvaddstr(y+1, 39, line);
753 readable_size(peaktotal / RESOLUTION, line, 10, 1024, options.bandwidth_in_bytes);
754 mvaddstr(y+2, 39, line);
756 mvaddstr(y, COLS - 8 * HISTORY_DIVISIONS - 8, "rates:");
758 draw_totals(&totals);
763 mvaddstr(0, 1, helpmsg);
764 mvaddstr(0, 1 + strlen(helpmsg), " ");
765 mvchgat(0, 0, strlen(helpmsg) + 2, A_REVERSE, 0, NULL);
767 move(LINES - 1, COLS - 1);
771 /* Bar chart auto scale */
772 if (wantbiggerrate && options.max_bandwidth == 0) {
778 void ui_tick(int print) {
782 else if(showhelphint && (time(NULL) - helptimer > HELP_TIME) && !persistenthelp) {
788 void ui_curses_init() {
789 (void) initscr(); /* initialize the curses library */
790 keypad(stdscr, TRUE); /* enable keyboard mapping */
791 (void) nonl(); /* tell curses not to do NL->CR/NL on output */
792 (void) cbreak(); /* take input chars one at a time, no wait for \n */
793 (void) noecho(); /* don't echo input */
797 void showhelp(const char * s) {
798 strncpy(helpmsg, s, HELP_MSG_SIZE);
800 helptimer = time(NULL);
812 screen_hash = addr_hash_create();
814 service_hash = serv_hash_create();
815 serv_hash_initialise(service_hash);
817 snprintf(msg,20,"Listening on %s",options.interface);
824 void showportstatus() {
825 if(options.showports == OPTION_PORTS_ON) {
826 showhelp("Port display ON");
828 else if(options.showports == OPTION_PORTS_OFF) {
829 showhelp("Port display OFF");
831 else if(options.showports == OPTION_PORTS_DEST) {
832 showhelp("Port display DEST");
834 else if(options.showports == OPTION_PORTS_SRC) {
835 showhelp("Port display SOURCE");
842 char *edline(int linenum, const char *prompt, const char *initial);
844 char *set_filter_code(const char *filter);
846 extern sig_atomic_t foad;
857 if(options.dnsresolution) {
858 options.dnsresolution = 0;
859 showhelp("DNS resolution off");
862 options.dnsresolution = 1;
863 showhelp("DNS resolution on");
869 if(options.portresolution) {
870 options.portresolution = 0;
871 showhelp("Port resolution off");
874 options.portresolution = 1;
875 showhelp("Port resolution on");
882 options.showhelp = !options.showhelp;
887 if(options.showbars) {
888 options.showbars = 0;
889 showhelp("Bars off");
892 options.showbars = 1;
899 options.bar_interval = (options.bar_interval + 1) % 3;
900 if(options.bar_interval == 0) {
901 showhelp("Bars show 2s average");
903 else if(options.bar_interval == 1) {
904 showhelp("Bars show 10s average");
907 showhelp("Bars show 40s average");
912 if(options.aggregate_src) {
913 options.aggregate_src = 0;
914 showhelp("Show source host");
917 options.aggregate_src = 1;
918 showhelp("Hide source host");
922 if(options.aggregate_dest) {
923 options.aggregate_dest = 0;
924 showhelp("Show dest host");
927 options.aggregate_dest = 1;
928 showhelp("Hide dest host");
932 /* Show source ports */
933 if(options.showports == OPTION_PORTS_OFF) {
934 options.showports = OPTION_PORTS_SRC;
936 else if(options.showports == OPTION_PORTS_DEST) {
937 options.showports = OPTION_PORTS_ON;
939 else if(options.showports == OPTION_PORTS_ON) {
940 options.showports = OPTION_PORTS_DEST;
943 options.showports = OPTION_PORTS_OFF;
948 /* Show dest ports */
949 if(options.showports == OPTION_PORTS_OFF) {
950 options.showports = OPTION_PORTS_DEST;
952 else if(options.showports == OPTION_PORTS_SRC) {
953 options.showports = OPTION_PORTS_ON;
955 else if(options.showports == OPTION_PORTS_ON) {
956 options.showports = OPTION_PORTS_SRC;
959 options.showports = OPTION_PORTS_OFF;
965 (options.showports == OPTION_PORTS_OFF)
969 // Don't tick here, otherwise we get a bogus display
974 showhelp("Display unpaused");
978 showhelp("Display paused");
983 if(options.freezeorder) {
984 options.freezeorder = 0;
985 showhelp("Order unfrozen");
988 options.freezeorder = 1;
989 showhelp("Order frozen");
994 options.sort = OPTION_SORT_DIV1;
995 showhelp("Sort by col 1");
998 options.sort = OPTION_SORT_DIV2;
999 showhelp("Sort by col 2");
1002 options.sort = OPTION_SORT_DIV3;
1003 showhelp("Sort by col 3");
1006 options.sort = OPTION_SORT_SRC;
1007 showhelp("Sort by source");
1010 options.sort = OPTION_SORT_DEST;
1011 showhelp("Sort by dest");
1014 options.screen_offset++;
1018 if(options.screen_offset > 0) {
1019 options.screen_offset--;
1024 options.linedisplay = (options.linedisplay + 1) % 4;
1025 switch(options.linedisplay) {
1026 case OPTION_LINEDISPLAY_TWO_LINE:
1027 showhelp("Two lines per host");
1029 case OPTION_LINEDISPLAY_ONE_LINE_SENT:
1030 showhelp("Sent traffic only");
1032 case OPTION_LINEDISPLAY_ONE_LINE_RECV:
1033 showhelp("Received traffic only");
1035 case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
1036 showhelp("One line per host");
1043 dontshowdisplay = 1;
1044 if ((s = edline(0, "Net filter", options.filtercode))) {
1046 if (s[strspn(s, " \t")] == 0) {
1047 /* Empty filter; set to NULL. */
1051 if (!(m = set_filter_code(s))) {
1052 xfree(options.filtercode);
1053 options.filtercode = s;
1054 /* -lpcap will write junk to stderr; we do our best to
1056 move(COLS - 1, LINES - 1);
1058 showhelp("Installed new filter");
1064 dontshowdisplay = 0;
1071 dontshowdisplay = 1;
1072 if ((s = edline(0, "Screen filter", options.screenfilter))) {
1073 if(!screen_filter_set(s)) {
1074 showhelp("Invalid regexp");
1077 dontshowdisplay = 0;
1080 showhelp("Sorry, screen filters not supported on this platform")
1085 #ifdef ALLOW_SUBSHELL
1087 dontshowdisplay = 1;
1088 if ((s = edline(0, "Command", "")) && s[strspn(s, " \t")]) {
1095 if (i == -1 || (i == 127 && errno != 0)) {
1096 fprintf(stderr, "system: %s: %s\n", s, strerror(errno));
1098 } else if (i != 0) {
1100 fprintf(stderr, "%s: exited with code %d\n", s, WEXITSTATUS(i));
1101 else if (WIFSIGNALED(i))
1102 fprintf(stderr, "%s: killed by signal %d\n", s, WTERMSIG(i));
1107 fprintf(stderr, "Press any key....");
1108 while (getch() == ERR);
1113 dontshowdisplay = 0;
1115 showhelp("Sorry, subshells have been disabled.");
1120 options.show_totals = !options.show_totals;
1121 if(options.show_totals) {
1122 showhelp("Show cumulative totals");
1125 showhelp("Hide cumulative totals");
1130 options.log_scale = !options.log_scale;
1131 showhelp(options.log_scale ? "Logarithmic scale" : "Linear scale");
1141 showhelp("Press H or ? for help");