Witness: enum witness_notifyResponse_type
[wireshark-wip.git] / ui / cli / tap-iostat.c
blobac826c3543319695f9cbbad04da78c259acc499f
1 /* tap-iostat.c
2 * iostat 2002 Ronnie Sahlberg
4 * $Id$
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "config.h"
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
31 #include <epan/epan_dissect.h>
32 #include <epan/packet_info.h>
33 #include <epan/tap.h>
34 #include <epan/timestamp.h>
35 #include <epan/stat_cmd_args.h>
36 #include <epan/strutil.h>
37 #include "globals.h"
39 #define CALC_TYPE_FRAMES 0
40 #define CALC_TYPE_BYTES 1
41 #define CALC_TYPE_FRAMES_AND_BYTES 2
42 #define CALC_TYPE_COUNT 3
43 #define CALC_TYPE_SUM 4
44 #define CALC_TYPE_MIN 5
45 #define CALC_TYPE_MAX 6
46 #define CALC_TYPE_AVG 7
47 #define CALC_TYPE_LOAD 8
49 void register_tap_listener_iostat(void);
51 typedef struct {
52 const char *func_name;
53 int calc_type;
54 } calc_type_ent_t;
56 static calc_type_ent_t calc_type_table[] = {
57 { "FRAMES", CALC_TYPE_FRAMES },
58 { "BYTES", CALC_TYPE_BYTES },
59 { "FRAMES BYTES", CALC_TYPE_FRAMES_AND_BYTES },
60 { "COUNT", CALC_TYPE_COUNT },
61 { "SUM", CALC_TYPE_SUM },
62 { "MIN", CALC_TYPE_MIN },
63 { "MAX", CALC_TYPE_MAX },
64 { "AVG", CALC_TYPE_AVG },
65 { "LOAD", CALC_TYPE_LOAD },
66 { NULL, 0 }
69 typedef struct _io_stat_t {
70 guint64 interval; /* The user-specified time interval (us) */
71 guint invl_prec; /* Decimal precision of the time interval (1=10s, 2=100s etc) */
72 int num_cols; /* The number of columns of stats in the table */
73 struct _io_stat_item_t *items; /* Each item is a single cell in the table */
74 time_t start_time; /* Time of first frame matching the filter */
75 const char **filters; /* 'io,stat' cmd strings (e.g., "AVG(smb.time)smb.time") */
76 guint64 *max_vals; /* The max value sans the decimal or nsecs portion in each stat column */
77 guint32 *max_frame; /* The max frame number displayed in each stat column */
78 } io_stat_t;
80 typedef struct _io_stat_item_t {
81 io_stat_t *parent;
82 struct _io_stat_item_t *next;
83 struct _io_stat_item_t *prev;
84 guint64 time; /* Time since start of capture (us)*/
85 int calc_type; /* The statistic type */
86 int colnum; /* Column number of this stat (0 to n) */
87 int hf_index;
88 guint32 frames;
89 guint32 num; /* The sample size of a given statistic (only needed for AVG) */
90 guint64 counter; /* The accumulated data for the calculation of that statistic */
91 gfloat float_counter;
92 gdouble double_counter;
93 } io_stat_item_t;
95 #define NANOSECS_PER_SEC 1000000000ULL
97 static guint64 last_relative_time;
99 static int
100 iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
102 io_stat_t *parent;
103 io_stat_item_t *mit;
104 io_stat_item_t *it;
105 guint64 relative_time, rt;
106 nstime_t *new_time;
107 GPtrArray *gp;
108 guint i;
109 int ftype;
111 mit = (io_stat_item_t *) arg;
112 parent = mit->parent;
114 /* If this frame's relative time is negative, set its relative time to last_relative_time
115 rather than disincluding it from the calculations. */
116 if (pinfo->rel_ts.secs >= 0) {
117 relative_time = ((guint64)pinfo->rel_ts.secs * 1000000ULL) +
118 ((guint64)((pinfo->rel_ts.nsecs+500)/1000));
119 last_relative_time = relative_time;
120 } else {
121 relative_time = last_relative_time;
124 if (mit->parent->start_time == 0) {
125 mit->parent->start_time = pinfo->fd->abs_ts.secs - pinfo->rel_ts.secs;
128 /* The prev item is always the last interval in which we saw packets. */
129 it = mit->prev;
131 /* If we have moved into a new interval (row), create a new io_stat_item_t struct for every interval
132 * between the last struct and this one. If an item was not found in a previous interval, an empty
133 * struct will be created for it. */
134 rt = relative_time;
135 while (rt >= it->time + parent->interval) {
136 it->next = (io_stat_item_t *)g_malloc(sizeof(io_stat_item_t));
137 it->next->prev = it;
138 it->next->next = NULL;
139 it = it->next;
140 mit->prev = it;
142 it->time = it->prev->time + parent->interval;
143 it->frames = 0;
144 it->counter = 0;
145 it->float_counter = 0;
146 it->double_counter = 0;
147 it->num = 0;
148 it->calc_type = it->prev->calc_type;
149 it->hf_index = it->prev->hf_index;
150 it->colnum = it->prev->colnum;
153 /* Store info in the current structure */
154 it->frames++;
156 switch(it->calc_type) {
157 case CALC_TYPE_FRAMES:
158 case CALC_TYPE_BYTES:
159 case CALC_TYPE_FRAMES_AND_BYTES:
160 it->counter += pinfo->fd->pkt_len;
161 break;
162 case CALC_TYPE_COUNT:
163 gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
164 if(gp){
165 it->counter += gp->len;
167 break;
168 case CALC_TYPE_SUM:
169 gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
170 if(gp){
171 guint64 val;
173 for(i=0;i<gp->len;i++){
174 switch(proto_registrar_get_ftype(it->hf_index)){
175 case FT_UINT8:
176 case FT_UINT16:
177 case FT_UINT24:
178 case FT_UINT32:
179 it->counter += fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
180 break;
181 case FT_UINT64:
182 it->counter += fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
183 break;
184 case FT_INT8:
185 case FT_INT16:
186 case FT_INT24:
187 case FT_INT32:
188 it->counter += fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
189 break;
190 case FT_INT64:
191 it->counter += (gint64)fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
192 break;
193 case FT_FLOAT:
194 it->float_counter +=
195 (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
196 break;
197 case FT_DOUBLE:
198 it->double_counter += fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
199 break;
200 case FT_RELATIVE_TIME:
201 new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
202 val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
203 it->counter += val;
204 break;
205 default:
207 * "Can't happen"; see the checks
208 * in register_io_tap().
210 g_assert_not_reached();
211 break;
215 break;
216 case CALC_TYPE_MIN:
217 gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
218 if(gp){
219 guint64 val;
220 gfloat float_val;
221 gdouble double_val;
223 ftype=proto_registrar_get_ftype(it->hf_index);
224 for(i=0;i<gp->len;i++){
225 switch(ftype){
226 case FT_UINT8:
227 case FT_UINT16:
228 case FT_UINT24:
229 case FT_UINT32:
230 val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
231 if ((it->frames==1 && i==0) || (val < it->counter)) {
232 it->counter=val;
234 break;
235 case FT_UINT64:
236 val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
237 if((it->frames==1 && i==0) || (val < it->counter)){
238 it->counter=val;
240 break;
241 case FT_INT8:
242 case FT_INT16:
243 case FT_INT24:
244 case FT_INT32:
245 val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
246 if((it->frames==1 && i==0) || ((gint32)val < (gint32)it->counter)) {
247 it->counter=val;
249 break;
250 case FT_INT64:
251 val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
252 if((it->frames==1 && i==0) || ((gint64)val < (gint64)it->counter)) {
253 it->counter=val;
255 break;
256 case FT_FLOAT:
257 float_val=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
258 if((it->frames==1 && i==0) || (float_val < it->float_counter)) {
259 it->float_counter=float_val;
261 break;
262 case FT_DOUBLE:
263 double_val=fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
264 if((it->frames==1 && i==0) || (double_val < it->double_counter)) {
265 it->double_counter=double_val;
267 break;
268 case FT_RELATIVE_TIME:
269 new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
270 val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
271 if((it->frames==1 && i==0) || (val < it->counter)) {
272 it->counter=val;
274 break;
275 default:
277 * "Can't happen"; see the checks
278 * in register_io_tap().
280 g_assert_not_reached();
281 break;
285 break;
286 case CALC_TYPE_MAX:
287 gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
288 if(gp){
289 guint64 val;
290 gfloat float_val;
291 gdouble double_val;
293 ftype=proto_registrar_get_ftype(it->hf_index);
294 for(i=0;i<gp->len;i++){
295 switch(ftype){
296 case FT_UINT8:
297 case FT_UINT16:
298 case FT_UINT24:
299 case FT_UINT32:
300 val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
301 if(val > it->counter)
302 it->counter=val;
303 break;
304 case FT_UINT64:
305 val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
306 if(val > it->counter)
307 it->counter=val;
308 break;
309 case FT_INT8:
310 case FT_INT16:
311 case FT_INT24:
312 case FT_INT32:
313 val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
314 if((gint32)val > (gint32)it->counter)
315 it->counter=val;
316 break;
317 case FT_INT64:
318 val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
319 if ((gint64)val > (gint64)it->counter)
320 it->counter=val;
321 break;
322 case FT_FLOAT:
323 float_val = (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
324 if(float_val > it->float_counter)
325 it->float_counter=float_val;
326 break;
327 case FT_DOUBLE:
328 double_val = fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
329 if(double_val > it->double_counter)
330 it->double_counter=double_val;
331 break;
332 case FT_RELATIVE_TIME:
333 new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
334 val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
335 if (val>it->counter)
336 it->counter=val;
337 break;
338 default:
340 * "Can't happen"; see the checks
341 * in register_io_tap().
343 g_assert_not_reached();
344 break;
348 break;
349 case CALC_TYPE_AVG:
350 gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
351 if(gp){
352 guint64 val;
354 ftype=proto_registrar_get_ftype(it->hf_index);
355 for(i=0;i<gp->len;i++){
356 it->num++;
357 switch(ftype) {
358 case FT_UINT8:
359 case FT_UINT16:
360 case FT_UINT24:
361 case FT_UINT32:
362 val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
363 it->counter += val;
364 break;
365 case FT_UINT64:
366 case FT_INT64:
367 val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
368 it->counter += val;
369 break;
370 case FT_INT8:
371 case FT_INT16:
372 case FT_INT24:
373 case FT_INT32:
374 val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
375 it->counter += val;
376 break;
377 case FT_FLOAT:
378 it->float_counter += (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
379 break;
380 case FT_DOUBLE:
381 it->double_counter += fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
382 break;
383 case FT_RELATIVE_TIME:
384 new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
385 val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
386 it->counter += val;
387 break;
388 default:
390 * "Can't happen"; see the checks
391 * in register_io_tap().
393 g_assert_not_reached();
394 break;
398 break;
399 case CALC_TYPE_LOAD:
400 gp = proto_get_finfo_ptr_array(edt->tree, it->hf_index);
401 if (gp) {
402 ftype = proto_registrar_get_ftype(it->hf_index);
403 if (ftype != FT_RELATIVE_TIME) {
404 fprintf(stderr,
405 "\ntshark: LOAD() is only supported for relative-time fields such as smb.time\n");
406 exit(10);
408 for(i=0;i<gp->len;i++){
409 guint64 val;
410 int tival;
411 io_stat_item_t *pit;
413 new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
414 val = ((guint64)new_time->secs*1000000ULL) + (guint64)(new_time->nsecs/1000);
415 tival = (int)(val % parent->interval);
416 it->counter += tival;
417 val -= tival;
418 pit = it->prev;
419 while (val > 0) {
420 if (val < (guint64)parent->interval) {
421 pit->counter += val;
422 break;
424 pit->counter += parent->interval;
425 val -= parent->interval;
426 pit = pit->prev;
430 break;
432 /* Store the highest value for this item in order to determine the width of each stat column.
433 * For real numbers we only need to know its magnitude (the value to the left of the decimal point
434 * so round it up before storing it as an integer in max_vals. For AVG of RELATIVE_TIME fields,
435 * calc the average, round it to the next second and store the seconds. For all other calc types
436 * of RELATIVE_TIME fields, store the counters without modification.
437 * fields. */
438 switch(it->calc_type) {
439 case CALC_TYPE_FRAMES:
440 case CALC_TYPE_FRAMES_AND_BYTES:
441 parent->max_frame[it->colnum] =
442 MAX(parent->max_frame[it->colnum], it->frames);
443 if (it->calc_type==CALC_TYPE_FRAMES_AND_BYTES)
444 parent->max_vals[it->colnum] =
445 MAX(parent->max_vals[it->colnum], it->counter);
447 case CALC_TYPE_BYTES:
448 case CALC_TYPE_COUNT:
449 case CALC_TYPE_LOAD:
450 parent->max_vals[it->colnum] = MAX(parent->max_vals[it->colnum], it->counter);
451 break;
452 case CALC_TYPE_SUM:
453 case CALC_TYPE_MIN:
454 case CALC_TYPE_MAX:
455 ftype=proto_registrar_get_ftype(it->hf_index);
456 switch(ftype) {
457 case FT_FLOAT:
458 parent->max_vals[it->colnum] =
459 MAX(parent->max_vals[it->colnum], (guint64)(it->float_counter+0.5));
460 break;
461 case FT_DOUBLE:
462 parent->max_vals[it->colnum] =
463 MAX(parent->max_vals[it->colnum],(guint64)(it->double_counter+0.5));
464 break;
465 case FT_RELATIVE_TIME:
466 parent->max_vals[it->colnum] =
467 MAX(parent->max_vals[it->colnum], it->counter);
468 break;
469 default:
470 /* UINT16-64 and INT8-64 */
471 parent->max_vals[it->colnum] =
472 MAX(parent->max_vals[it->colnum], it->counter);
473 break;
475 break;
476 case CALC_TYPE_AVG:
477 if (it->num==0) /* avoid division by zero */
478 break;
479 ftype=proto_registrar_get_ftype(it->hf_index);
480 switch(ftype) {
481 case FT_FLOAT:
482 parent->max_vals[it->colnum] =
483 MAX(parent->max_vals[it->colnum], (guint64)it->float_counter/it->num);
484 break;
485 case FT_DOUBLE:
486 parent->max_vals[it->colnum] =
487 MAX(parent->max_vals[it->colnum],(guint64)it->double_counter/it->num);
488 break;
489 case FT_RELATIVE_TIME:
490 parent->max_vals[it->colnum] =
491 MAX(parent->max_vals[it->colnum], ((it->counter/(guint64)it->num) + 500000000ULL) / NANOSECS_PER_SEC);
492 break;
493 default:
494 /* UINT16-64 and INT8-64 */
495 parent->max_vals[it->colnum] =
496 MAX(parent->max_vals[it->colnum], it->counter/it->num);
497 break;
500 return TRUE;
503 static int
504 magnitude (guint64 val, int max_w)
506 int i, mag=0;
508 for (i=0; i<max_w; i++) {
509 mag++;
510 if ((val /= 10)==0)
511 break;
513 return(mag);
517 * Print the calc_type_table[] function label centered in the column header.
519 static void
520 printcenter (const char *label, int lenval, int numpad)
522 int lenlab = (int) strlen(label), len;
523 const char spaces[]=" ", *spaces_ptr;
525 len = (int) (strlen(spaces)) - (((lenval-lenlab) / 2) + numpad);
526 if (len > 0 && len < 6) {
527 spaces_ptr = &spaces[len];
528 if ((lenval-lenlab)%2==0) {
529 printf("%s%s%s|", spaces_ptr, label, spaces_ptr);
530 } else {
531 printf("%s%s%s|", spaces_ptr-1, label, spaces_ptr);
533 } else if (len > 0 && len <= 15) {
534 printf("%s|", label);
538 typedef struct {
539 int fr; /* Width of this FRAMES column sans padding and border chars */
540 int val; /* Width of this non-FRAMES column sans padding and border chars */
541 } column_width;
543 static void
544 iostat_draw(void *arg)
546 guint32 num;
547 guint64 interval, duration, t, invl_end, dv;
548 int i, j, k, num_cols, num_rows, dur_secs_orig, dur_nsecs_orig, dur_secs, dur_nsecs, dur_mag,
549 invl_mag, invl_prec, tabrow_w, borderlen, invl_col_w, numpad=1, namelen, len_filt, type,
550 maxfltr_w, ftype;
551 int fr_mag; /* The magnitude of the max frame number in this column */
552 int val_mag; /* The magnitude of the max value in this column */
553 char *spaces, *spaces_s, *filler_s=NULL, **fmts, *fmt=NULL;
554 const char *filter;
555 static gchar dur_mag_s[3], invl_prec_s[3], fr_mag_s[3], val_mag_s[3], *invl_fmt, *full_fmt;
556 io_stat_item_t *mit, **stat_cols, *item, **item_in_column;
557 gboolean last_row=FALSE;
558 io_stat_t *iot;
559 column_width *col_w;
560 struct tm * tm_time;
561 time_t the_time;
563 mit = (io_stat_item_t *)arg;
564 iot = mit->parent;
565 num_cols = iot->num_cols;
566 col_w = (column_width *)g_malloc(sizeof(column_width) * num_cols);
567 fmts = (char **)g_malloc(sizeof(char *) * num_cols);
568 duration = ((guint64)cfile.elapsed_time.secs * 1000000ULL) +
569 (guint64)((cfile.elapsed_time.nsecs + 500) / 1000);
571 /* Store the pointer to each stat column */
572 stat_cols = (io_stat_item_t **) g_malloc(sizeof(io_stat_item_t *) * num_cols);
573 for (j=0; j<num_cols; j++)
574 stat_cols[j] = &iot->items[j];
576 /* The following prevents gross inaccuracies when the user specifies an interval that is greater
577 * than the capture duration. */
578 if (iot->interval > duration || iot->interval==G_MAXINT32) {
579 interval = duration;
580 iot->interval = G_MAXINT32;
581 } else {
582 interval = iot->interval;
585 /* Calc the capture duration's magnitude (dur_mag) */
586 dur_secs = (int)(duration/1000000ULL);
587 dur_secs_orig = dur_secs;
588 dur_nsecs = (int)(duration%1000000ULL);
589 dur_nsecs_orig = dur_nsecs;
590 dur_mag = magnitude((guint64)dur_secs, 5);
591 g_snprintf(dur_mag_s, 3, "%u", dur_mag);
593 /* Calc the interval's magnitude */
594 invl_mag = magnitude(interval/1000000ULL, 5);
596 /* Set or get the interval precision */
597 if (interval==duration) {
599 * An interval arg of 0 or an interval size exceeding the capture duration was specified.
600 * Set the decimal precision of duration based on its magnitude. */
601 if (dur_mag >= 2)
602 invl_prec = 1;
603 else if (dur_mag==1)
604 invl_prec = 3;
605 else
606 invl_prec = 6;
608 borderlen = 30 + dur_mag + (invl_prec==0 ? 0 : invl_prec+1);
609 } else {
610 invl_prec = iot->invl_prec;
611 borderlen = 24 + invl_mag + (invl_prec==0 ? 0 : invl_prec+1);
614 /* Round the duration according to invl_prec */
615 dv=1000000;
616 for (i=0; i<invl_prec; i++)
617 dv /= 10;
618 if ((duration%dv) > 5*(dv/10)) {
619 duration += 5*(dv/10);
620 duration = (duration/dv) * dv;
621 dur_secs = (int)(duration/1000000ULL);
622 dur_nsecs = (int)(duration%1000000ULL);
624 * Recalc dur_mag in case rounding has increased its magnitude */
625 dur_mag = magnitude((guint64)dur_secs, 5);
627 if (iot->interval==G_MAXINT32)
628 interval = duration;
630 /* Calc the width of the time interval column (incl borders and padding). */
631 if (invl_prec==0)
632 invl_col_w = (2*dur_mag) + 8;
633 else
634 invl_col_w = (2*dur_mag) + (2*invl_prec) + 10;
636 /* Update the width of the time interval column if date is shown */
637 switch (timestamp_get_type()) {
638 case TS_ABSOLUTE_WITH_YMD:
639 case TS_ABSOLUTE_WITH_YDOY:
640 case TS_UTC_WITH_YMD:
641 case TS_UTC_WITH_YDOY:
642 invl_col_w = MAX(invl_col_w, 23);
643 break;
645 default:
646 invl_col_w = MAX(invl_col_w, 12);
647 break;
650 borderlen = MAX(borderlen, invl_col_w);
652 /* Calc the total width of each row in the stats table and build the printf format string for each
653 * column based on its field type, width, and name length.
654 * NOTE: The magnitude of all types including float and double are stored in iot->max_vals which
655 * is an *integer*. */
656 tabrow_w = invl_col_w;
657 for (j=0; j<num_cols; j++) {
658 type = iot->items[j].calc_type;
659 if (type==CALC_TYPE_FRAMES_AND_BYTES) {
660 namelen = 5;
661 } else {
662 namelen = (int) strlen(calc_type_table[type].func_name);
664 if(type==CALC_TYPE_FRAMES
665 || type==CALC_TYPE_FRAMES_AND_BYTES) {
667 fr_mag = magnitude(iot->max_frame[j], 15);
668 fr_mag = MAX(6, fr_mag);
669 col_w[j].fr = fr_mag;
670 tabrow_w += col_w[j].fr + 3;
671 g_snprintf(fr_mag_s, 3, "%u", fr_mag);
673 if (type==CALC_TYPE_FRAMES) {
674 fmt = g_strconcat(" %", fr_mag_s, "u |", NULL);
675 } else {
676 /* CALC_TYPE_FRAMES_AND_BYTES
678 val_mag = magnitude(iot->max_vals[j], 15);
679 val_mag = MAX(5, val_mag);
680 col_w[j].val = val_mag;
681 tabrow_w += (col_w[j].val + 3);
682 g_snprintf(val_mag_s, 3, "%u", val_mag);
683 fmt = g_strconcat(" %", fr_mag_s, "u |", " %", val_mag_s, G_GINT64_MODIFIER, "u |", NULL);
685 if (fmt)
686 fmts[j] = fmt;
687 continue;
689 switch(type) {
690 case CALC_TYPE_BYTES:
691 case CALC_TYPE_COUNT:
693 val_mag = magnitude(iot->max_vals[j], 15);
694 val_mag = MAX(5, val_mag);
695 col_w[j].val = val_mag;
696 g_snprintf(val_mag_s, 3, "%u", val_mag);
697 fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "u |", NULL);
698 break;
700 default:
701 ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
702 switch (ftype) {
703 case FT_FLOAT:
704 case FT_DOUBLE:
705 val_mag = magnitude(iot->max_vals[j], 15);
706 g_snprintf(val_mag_s, 3, "%u", val_mag);
707 fmt = g_strconcat(" %", val_mag_s, ".6f |", NULL);
708 col_w[j].val = val_mag + 7;
709 break;
710 case FT_RELATIVE_TIME:
711 /* Convert FT_RELATIVE_TIME field to seconds
712 * CALC_TYPE_LOAD was already converted in iostat_packet() ) */
713 if (type==CALC_TYPE_LOAD) {
714 iot->max_vals[j] /= interval;
715 } else if (type != CALC_TYPE_AVG) {
716 iot->max_vals[j] = (iot->max_vals[j] + 500000000ULL) / NANOSECS_PER_SEC;
718 val_mag = magnitude(iot->max_vals[j], 15);
719 g_snprintf(val_mag_s, 3, "%u", val_mag);
720 fmt = g_strconcat(" %", val_mag_s, "u.%06u |", NULL);
721 col_w[j].val = val_mag + 7;
722 break;
724 default:
725 val_mag = magnitude(iot->max_vals[j], 15);
726 val_mag = MAX(namelen, val_mag);
727 col_w[j].val = val_mag;
728 g_snprintf(val_mag_s, 3, "%u", val_mag);
730 switch (ftype) {
731 case FT_UINT8:
732 case FT_UINT16:
733 case FT_UINT24:
734 case FT_UINT32:
735 case FT_UINT64:
736 fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "u |", NULL);
737 break;
738 case FT_INT8:
739 case FT_INT16:
740 case FT_INT24:
741 case FT_INT32:
742 case FT_INT64:
743 fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "d |", NULL);
744 break;
746 } /* End of ftype switch */
747 } /* End of calc_type switch */
748 tabrow_w += col_w[j].val + 3;
749 if (fmt)
750 fmts[j] = fmt;
751 } /* End of for loop (columns) */
753 borderlen = MAX(borderlen, tabrow_w);
755 /* Calc the max width of the list of filters. */
756 maxfltr_w = 0;
757 for(j=0; j<num_cols; j++) {
758 if (iot->filters[j]) {
759 k = (int) (strlen(iot->filters[j]) + 11);
760 maxfltr_w = MAX(maxfltr_w, k);
761 } else {
762 maxfltr_w = MAX(maxfltr_w, 26);
765 /* The stat table is not wrapped (by tshark) but filter is wrapped at the width of the stats table
766 * (which currently = borderlen); however, if the filter width exceeds the table width and the
767 * table width is less than 102 bytes, set borderlen to the lesser of the max filter width and 102.
768 * The filters will wrap at the lesser of borderlen-2 and the last space in the filter.
769 * NOTE: 102 is the typical size of a user window when the font is fixed width (e.g., COURIER 10).
770 * XXX: A pref could be added to change the max width from the default size of 102. */
771 if (maxfltr_w > borderlen && borderlen < 102)
772 borderlen = MIN(maxfltr_w, 102);
774 /* Prevent double right border by adding a space */
775 if (borderlen-tabrow_w==1)
776 borderlen++;
778 /* Display the top border */
779 printf("\n");
780 for (i=0; i<borderlen; i++)
781 printf("=");
783 spaces = (char*) g_malloc(borderlen+1);
784 for (i=0; i<borderlen; i++)
785 spaces[i] = ' ';
786 spaces[borderlen] = '\0';
788 spaces_s = &spaces[16];
789 printf("\n| IO Statistics%s|\n", spaces_s);
790 spaces_s = &spaces[2];
791 printf("|%s|\n", spaces_s);
793 if (invl_prec==0) {
794 invl_fmt = g_strconcat("%", dur_mag_s, "u", NULL);
795 full_fmt = g_strconcat("| Duration: ", invl_fmt, ".%6u secs%s|\n", NULL);
796 spaces_s = &spaces[25 + dur_mag];
797 printf(full_fmt, dur_secs_orig, dur_nsecs_orig, spaces_s);
798 g_free(full_fmt);
799 full_fmt = g_strconcat("| Interval: ", invl_fmt, " secs%s|\n", NULL);
800 spaces_s = &spaces[18 + dur_mag];
801 printf(full_fmt, (guint32)(interval/1000000ULL), spaces_s);
802 } else {
803 g_snprintf(invl_prec_s, 3, "%u", invl_prec);
804 invl_fmt = g_strconcat("%", dur_mag_s, "u.%0", invl_prec_s, "u", NULL);
805 full_fmt = g_strconcat("| Duration: ", invl_fmt, " secs%s|\n", NULL);
806 spaces_s = &spaces[19 + dur_mag + invl_prec];
807 printf(full_fmt, dur_secs, dur_nsecs/(int)dv, spaces_s);
808 g_free(full_fmt);
810 full_fmt = g_strconcat("| Interval: ", invl_fmt, " secs%s|\n", NULL);
811 spaces_s = &spaces[19 + dur_mag + invl_prec];
812 printf(full_fmt, (guint32)(interval/1000000ULL),
813 (guint32)((interval%1000000ULL)/dv), spaces_s);
815 g_free(full_fmt);
817 spaces_s = &spaces[2];
818 printf("|%s|\n", spaces_s);
820 /* Display the list of filters and their column numbers vertically */
821 printf("| Col");
822 for(j=0; j<num_cols; j++){
823 printf((j==0 ? "%2u: " : "| %2u: "), j+1);
824 if (!iot->filters[j] || (iot->filters[j]==0)) {
826 * An empty (no filter) comma field was specified */
827 spaces_s = &spaces[16 + 10];
828 printf("Frames and bytes%s|\n", spaces_s);
829 } else {
830 filter = iot->filters[j];
831 len_filt = (int) strlen(filter);
833 /* If the width of the widest filter exceeds the width of the stat table, borderlen has
834 * been set to 102 bytes above and filters wider than 102 will wrap at 91 bytes. */
835 if (len_filt+11 <= borderlen) {
836 printf("%s", filter);
837 if (len_filt+11 <= borderlen) {
838 spaces_s = &spaces[len_filt + 10];
839 printf("%s", spaces_s);
841 printf("|\n");
842 } else {
843 gchar *sfilter1, *sfilter2;
844 const gchar *pos;
845 gsize len;
846 int next_start, max_w=borderlen-11;
848 do {
849 if (len_filt > max_w) {
850 sfilter1 = g_strndup( (gchar *) filter, (gsize) max_w);
852 * Find the pos of the last space in sfilter1. If a space is found, set
853 * sfilter2 to the string prior to that space and print it; otherwise, wrap
854 * the filter at max_w. */
855 pos = g_strrstr(sfilter1, " ");
856 if (pos) {
857 len = (gsize)(pos-sfilter1);
858 next_start = (int) len+1;
859 } else {
860 len = (gsize) strlen(sfilter1);
861 next_start = (int)len;
863 sfilter2 = g_strndup(sfilter1, len);
864 printf("%s%s|\n", sfilter2, &spaces[len+10]);
865 g_free(sfilter1);
866 g_free(sfilter2);
868 printf("| ");
869 filter = &filter[next_start];
870 len_filt = (int) strlen(filter);
871 } else {
872 printf("%s%s|\n", filter, &spaces[((int)strlen(filter))+10]);
873 break;
875 } while (1);
880 printf("|-");
881 for(i=0;i<borderlen-3;i++){
882 printf("-");
884 printf("|\n");
886 /* Display spaces above "Interval (s)" label */
887 spaces_s = &spaces[borderlen-(invl_col_w-2)];
888 printf("|%s|", spaces_s);
890 /* Display column number headers */
891 for(j=0; j<num_cols; j++) {
892 item = stat_cols[j];
893 if(item->calc_type==CALC_TYPE_FRAMES_AND_BYTES)
894 spaces_s = &spaces[borderlen - (col_w[j].fr + col_w[j].val)] - 3;
895 else if (item->calc_type==CALC_TYPE_FRAMES)
896 spaces_s = &spaces[borderlen - col_w[j].fr];
897 else
898 spaces_s = &spaces[borderlen - col_w[j].val];
900 printf("%-2u%s|", j+1, spaces_s);
902 if (tabrow_w < borderlen) {
903 filler_s = &spaces[tabrow_w+1];
904 printf("%s|", filler_s);
907 k = 11;
908 switch (timestamp_get_type()) {
909 case TS_ABSOLUTE:
910 printf("\n| Time ");
911 break;
912 case TS_ABSOLUTE_WITH_YMD:
913 case TS_ABSOLUTE_WITH_YDOY:
914 case TS_UTC_WITH_YMD:
915 case TS_UTC_WITH_YDOY:
916 printf("\n| Date and time");
917 k = 16;
918 break;
919 case TS_RELATIVE:
920 case TS_NOT_SET:
921 printf("\n| Interval");
922 break;
923 default:
924 break;
927 spaces_s = &spaces[borderlen-(invl_col_w-k)];
928 printf("%s|", spaces_s);
930 /* Display the stat label in each column */
931 for(j=0; j<num_cols; j++) {
932 type = stat_cols[j]->calc_type;
933 if(type==CALC_TYPE_FRAMES) {
934 printcenter (calc_type_table[type].func_name, col_w[j].fr, numpad);
935 } else if (type==CALC_TYPE_FRAMES_AND_BYTES) {
936 printcenter ("Frames", col_w[j].fr, numpad);
937 printcenter ("Bytes", col_w[j].val, numpad);
938 } else {
939 printcenter (calc_type_table[type].func_name, col_w[j].val, numpad);
942 if (filler_s)
943 printf("%s|", filler_s);
944 printf("\n|-");
946 for(i=0; i<tabrow_w-3; i++)
947 printf("-");
948 printf("|");
950 if (tabrow_w < borderlen)
951 printf("%s|", &spaces[tabrow_w+1]);
953 printf("\n");
954 t=0;
955 if (invl_prec==0 && dur_mag==1)
956 full_fmt = g_strconcat("| ", invl_fmt, " <> ", invl_fmt, " |", NULL);
957 else
958 full_fmt = g_strconcat("| ", invl_fmt, " <> ", invl_fmt, " |", NULL);
960 if (interval == 0 || duration == 0) {
961 num_rows = 0;
962 } else {
963 num_rows = (int)(duration/interval) + ((int)(duration%interval) > 0 ? 1 : 0);
966 /* Load item_in_column with the first item in each column */
967 item_in_column = (io_stat_item_t **) g_malloc(sizeof(io_stat_item_t *) * num_cols);
968 for (j=0; j<num_cols; j++) {
969 item_in_column[j] = stat_cols[j];
972 /* Display the table values
974 * The outer loop is for time interval rows and the inner loop is for stat column items.*/
975 for (i=0; i<num_rows; i++) {
977 if (i==num_rows-1)
978 last_row = TRUE;
980 /* Compute the interval for this row */
981 if (!last_row) {
982 invl_end = t + interval;
983 } else {
984 invl_end = duration;
987 /* Patch for Absolute Time */
988 /* XXX - has a Y2.038K problem with 32-bit time_t */
989 the_time = (time_t)(iot->start_time + (t/1000000ULL));
991 /* Display the interval for this row */
992 switch (timestamp_get_type()) {
993 case TS_ABSOLUTE:
994 tm_time = localtime(&the_time);
995 printf("| %02d:%02d:%02d |",
996 tm_time->tm_hour,
997 tm_time->tm_min,
998 tm_time->tm_sec);
999 break;
1001 case TS_ABSOLUTE_WITH_YMD:
1002 tm_time = localtime(&the_time);
1003 printf("| %04d-%02d-%02d %02d:%02d:%02d |",
1004 tm_time->tm_year + 1900,
1005 tm_time->tm_mon + 1,
1006 tm_time->tm_mday,
1007 tm_time->tm_hour,
1008 tm_time->tm_min,
1009 tm_time->tm_sec);
1010 break;
1012 case TS_ABSOLUTE_WITH_YDOY:
1013 tm_time = localtime(&the_time);
1014 printf("| %04d/%03d %02d:%02d:%02d |",
1015 tm_time->tm_year + 1900,
1016 tm_time->tm_yday + 1,
1017 tm_time->tm_hour,
1018 tm_time->tm_min,
1019 tm_time->tm_sec);
1020 break;
1022 case TS_UTC:
1023 tm_time = gmtime(&the_time);
1024 printf("| %02d:%02d:%02d |",
1025 tm_time->tm_hour,
1026 tm_time->tm_min,
1027 tm_time->tm_sec);
1028 break;
1030 case TS_UTC_WITH_YMD:
1031 tm_time = gmtime(&the_time);
1032 printf("| %04d-%02d-%02d %02d:%02d:%02d |",
1033 tm_time->tm_year + 1900,
1034 tm_time->tm_mon + 1,
1035 tm_time->tm_mday,
1036 tm_time->tm_hour,
1037 tm_time->tm_min,
1038 tm_time->tm_sec);
1039 break;
1041 case TS_UTC_WITH_YDOY:
1042 tm_time = gmtime(&the_time);
1043 printf("| %04d/%03d %02d:%02d:%02d |",
1044 tm_time->tm_year + 1900,
1045 tm_time->tm_yday + 1,
1046 tm_time->tm_hour,
1047 tm_time->tm_min,
1048 tm_time->tm_sec);
1049 break;
1051 case TS_RELATIVE:
1052 case TS_NOT_SET:
1053 if (invl_prec==0) {
1054 if(last_row) {
1055 int maxw;
1056 maxw = dur_mag >= 3 ? dur_mag+1 : 3;
1057 g_free(full_fmt);
1058 g_snprintf(dur_mag_s, 3, "%u", maxw);
1059 full_fmt = g_strconcat( dur_mag==1 ? "| " : "| ",
1060 invl_fmt, " <> ", "%-",
1061 dur_mag_s, "s|", NULL);
1062 printf(full_fmt, (guint32)(t/1000000ULL), "Dur");
1063 } else {
1064 printf(full_fmt, (guint32)(t/1000000ULL),
1065 (guint32)(invl_end/1000000ULL));
1067 } else {
1068 printf(full_fmt, (guint32)(t/1000000ULL),
1069 (guint32)(t%1000000ULL / dv),
1070 (guint32)(invl_end/1000000ULL),
1071 (guint32)(invl_end%1000000ULL / dv));
1073 break;
1074 /* case TS_DELTA:
1075 case TS_DELTA_DIS:
1076 case TS_EPOCH:
1077 are not implemented */
1078 default:
1079 break;
1082 /* Display stat values in each column for this row */
1083 for (j=0; j<num_cols; j++) {
1084 fmt = fmts[j];
1085 item = item_in_column[j];
1087 if (item) {
1088 switch(item->calc_type) {
1089 case CALC_TYPE_FRAMES:
1090 printf(fmt, item->frames);
1091 break;
1092 case CALC_TYPE_BYTES:
1093 case CALC_TYPE_COUNT:
1094 printf(fmt, item->counter);
1095 break;
1096 case CALC_TYPE_FRAMES_AND_BYTES:
1097 printf(fmt, item->frames, item->counter);
1098 break;
1100 case CALC_TYPE_SUM:
1101 case CALC_TYPE_MIN:
1102 case CALC_TYPE_MAX:
1103 ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
1104 switch(ftype){
1105 case FT_FLOAT:
1106 printf(fmt, item->float_counter);
1107 break;
1108 case FT_DOUBLE:
1109 printf(fmt, item->double_counter);
1110 break;
1111 case FT_RELATIVE_TIME:
1112 item->counter = (item->counter + 500ULL) / 1000ULL;
1113 printf(fmt, (int)(item->counter/1000000ULL), (int)(item->counter%1000000ULL));
1114 break;
1115 default:
1116 printf(fmt, item->counter);
1117 break;
1119 break;
1121 case CALC_TYPE_AVG:
1122 num = item->num;
1123 if(num==0)
1124 num=1;
1125 ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
1126 switch(ftype){
1127 case FT_FLOAT:
1128 printf(fmt, item->float_counter/num);
1129 break;
1130 case FT_DOUBLE:
1131 printf(fmt, item->double_counter/num);
1132 break;
1133 case FT_RELATIVE_TIME:
1134 item->counter = ((item->counter / (guint64)num) + 500ULL) / 1000ULL;
1135 printf(fmt,
1136 (int)(item->counter/1000000ULL), (int)(item->counter%1000000ULL));
1137 break;
1138 default:
1139 printf(fmt, item->counter / (guint64)num);
1140 break;
1142 break;
1144 case CALC_TYPE_LOAD:
1145 ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
1146 switch(ftype){
1147 case FT_RELATIVE_TIME:
1148 if (!last_row) {
1149 printf(fmt,
1150 (int) (item->counter/interval),
1151 (int)((item->counter%interval)*1000000ULL / interval));
1152 } else {
1153 printf(fmt,
1154 (int) (item->counter/(invl_end-t)),
1155 (int)((item->counter%(invl_end-t))*1000000ULL / (invl_end-t)));
1157 break;
1159 break;
1162 if (last_row) {
1163 if (fmt)
1164 g_free(fmt);
1165 } else {
1166 item_in_column[j] = item_in_column[j]->next;
1168 } else {
1169 printf(fmt, (guint64)0, (guint64)0);
1172 if (filler_s)
1173 printf("%s|", filler_s);
1174 printf("\n");
1175 t += interval;
1178 for(i=0;i<borderlen;i++){
1179 printf("=");
1181 printf("\n");
1182 g_free(iot->items);
1183 g_free(iot->max_vals);
1184 g_free(iot->max_frame);
1185 g_free(iot);
1186 g_free(col_w);
1187 g_free(invl_fmt);
1188 g_free(full_fmt);
1189 g_free(fmts);
1190 g_free(spaces);
1191 g_free(stat_cols);
1192 g_free(item_in_column);
1196 static void
1197 register_io_tap(io_stat_t *io, int i, const char *filter)
1199 GString *error_string;
1200 const char *flt;
1201 int j;
1202 size_t namelen;
1203 const char *p, *parenp;
1204 char *field;
1205 header_field_info *hfi;
1207 io->items[i].prev=&io->items[i];
1208 io->items[i].next=NULL;
1209 io->items[i].parent=io;
1210 io->items[i].time=0;
1211 io->items[i].calc_type=CALC_TYPE_FRAMES_AND_BYTES;
1212 io->items[i].frames=0;
1213 io->items[i].counter=0;
1214 io->items[i].num=0;
1216 io->filters[i]=filter;
1217 flt=filter;
1219 field=NULL;
1220 hfi=NULL;
1221 for(j=0; calc_type_table[j].func_name; j++){
1222 namelen=strlen(calc_type_table[j].func_name);
1223 if(filter && strncmp(filter, calc_type_table[j].func_name, namelen) == 0) {
1224 io->items[i].calc_type=calc_type_table[j].calc_type;
1225 io->items[i].colnum = i;
1226 if(*(filter+namelen)=='(') {
1227 p=filter+namelen+1;
1228 parenp=strchr(p, ')');
1229 if(!parenp){
1230 fprintf(stderr,
1231 "\ntshark: Closing parenthesis missing from calculated expression.\n");
1232 exit(10);
1235 if(io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES){
1236 if(parenp!=p) {
1237 fprintf(stderr,
1238 "\ntshark: %s does not require or allow a field name within the parens.\n",
1239 calc_type_table[j].func_name);
1240 exit(10);
1242 } else {
1243 if(parenp==p) {
1244 /* bail out if a field name was not specified */
1245 fprintf(stderr, "\ntshark: You didn't specify a field name for %s(*).\n",
1246 calc_type_table[j].func_name);
1247 exit(10);
1251 field = (char *) g_malloc(parenp-p+1);
1252 memcpy(field, p, parenp-p);
1253 field[parenp-p] = '\0';
1254 flt=parenp + 1;
1255 if (io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES)
1256 break;
1257 hfi=proto_registrar_get_byname(field);
1258 if(!hfi){
1259 fprintf(stderr, "\ntshark: There is no field named '%s'.\n",
1260 field);
1261 g_free(field);
1262 exit(10);
1265 io->items[i].hf_index=hfi->id;
1266 break;
1268 } else {
1269 if (io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES)
1270 flt="";
1271 io->items[i].colnum = i;
1274 if(hfi && !(io->items[i].calc_type==CALC_TYPE_BYTES ||
1275 io->items[i].calc_type==CALC_TYPE_FRAMES ||
1276 io->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES)){
1277 /* check that the type is compatible */
1278 switch(hfi->type){
1279 case FT_UINT8:
1280 case FT_UINT16:
1281 case FT_UINT24:
1282 case FT_UINT32:
1283 case FT_UINT64:
1284 case FT_INT8:
1285 case FT_INT16:
1286 case FT_INT24:
1287 case FT_INT32:
1288 case FT_INT64:
1289 /* these types support all calculations */
1290 break;
1291 case FT_FLOAT:
1292 case FT_DOUBLE:
1293 /* these types only support SUM, COUNT, MAX, MIN, AVG */
1294 switch(io->items[i].calc_type){
1295 case CALC_TYPE_SUM:
1296 case CALC_TYPE_COUNT:
1297 case CALC_TYPE_MAX:
1298 case CALC_TYPE_MIN:
1299 case CALC_TYPE_AVG:
1300 break;
1301 default:
1302 fprintf(stderr,
1303 "\ntshark: %s is a float field, so %s(*) calculations are not supported on it.",
1304 field,
1305 calc_type_table[j].func_name);
1306 exit(10);
1308 break;
1309 case FT_RELATIVE_TIME:
1310 /* this type only supports SUM, COUNT, MAX, MIN, AVG, LOAD */
1311 switch(io->items[i].calc_type){
1312 case CALC_TYPE_SUM:
1313 case CALC_TYPE_COUNT:
1314 case CALC_TYPE_MAX:
1315 case CALC_TYPE_MIN:
1316 case CALC_TYPE_AVG:
1317 case CALC_TYPE_LOAD:
1318 break;
1319 default:
1320 fprintf(stderr,
1321 "\ntshark: %s is a relative-time field, so %s(*) calculations are not supported on it.",
1322 field,
1323 calc_type_table[j].func_name);
1324 exit(10);
1326 break;
1327 default:
1329 * XXX - support all operations on floating-point
1330 * numbers?
1332 if(io->items[i].calc_type!=CALC_TYPE_COUNT){
1333 fprintf(stderr,
1334 "\ntshark: %s doesn't have integral values, so %s(*) "
1335 "calculations are not supported on it.\n",
1336 field,
1337 calc_type_table[j].func_name);
1338 exit(10);
1340 break;
1342 g_free(field);
1345 error_string=register_tap_listener("frame", &io->items[i], flt, TL_REQUIRES_PROTO_TREE, NULL,
1346 iostat_packet, i?NULL:iostat_draw);
1347 if(error_string){
1348 g_free(io->items);
1349 g_free(io);
1350 fprintf(stderr, "\ntshark: Couldn't register io,stat tap: %s\n",
1351 error_string->str);
1352 g_string_free(error_string, TRUE);
1353 exit(1);
1357 static void
1358 iostat_init(const char *opt_arg, void* userdata _U_)
1360 gdouble interval_float;
1361 guint32 idx=0;
1362 int i;
1363 io_stat_t *io;
1364 const gchar *filters, *str, *pos;
1366 if ((*(opt_arg+(strlen(opt_arg)-1)) == ',') ||
1367 (sscanf(opt_arg, "io,stat,%lf%n", &interval_float, (int *)&idx) != 1) ||
1368 (idx < 8)) {
1369 fprintf(stderr, "\ntshark: invalid \"-z io,stat,<interval>[,<filter>][,<filter>]...\" argument\n");
1370 exit(1);
1373 filters=opt_arg+idx;
1374 if (*filters) {
1375 if (*filters != ',') {
1376 /* For locale's that use ',' instead of '.', the comma might
1377 * have been consumed during the floating point conversion. */
1378 --filters;
1379 if (*filters != ',') {
1380 fprintf(stderr, "\ntshark: invalid \"-z io,stat,<interval>[,<filter>][,<filter>]...\" argument\n");
1381 exit(1);
1384 } else
1385 filters=NULL;
1387 switch (timestamp_get_type()) {
1388 case TS_DELTA:
1389 case TS_DELTA_DIS:
1390 case TS_EPOCH:
1391 fprintf(stderr, "\ntshark: invalid -t operand. io,stat only supports -t <r|a|ad|adoy|u|ud|udoy>\n");
1392 exit(1);
1393 default:
1394 break;
1397 io = (io_stat_t *) g_malloc(sizeof(io_stat_t));
1399 /* If interval is 0, calculate statistics over the whole file by setting the interval to
1400 * G_MAXINT32 */
1401 if (interval_float==0) {
1402 io->interval = G_MAXINT32;
1403 io->invl_prec = 0;
1404 } else {
1405 /* Set interval to the number of us rounded to the nearest integer */
1406 io->interval = (guint64)(interval_float * 1000000.0 + 0.5);
1408 * Determine what interval precision the user has specified */
1409 io->invl_prec = 6;
1410 for (i=10; i<10000000; i*=10) {
1411 if (io->interval%i > 0)
1412 break;
1413 io->invl_prec--;
1415 if (io->invl_prec==0) {
1416 /* The precision is zero but if the user specified one of more zeros after the decimal point,
1417 they want that many decimal places shown in the table for all time intervals except
1418 response time values such as smb.time which always have 6 decimal places of precision.
1419 This feature is useful in cases where for example the duration is 9.1, you specify an
1420 interval of 1 and the last interval becomes "9 <> 9". If the interval is instead set to
1421 1.1, the last interval becomes
1422 last interval is rounded up to value that is greater than the duration. */
1423 const gchar *invl_start = opt_arg+8;
1424 gchar *intv_end;
1425 int invl_len;
1427 intv_end = g_strstr_len(invl_start, -1, ",");
1428 invl_len = (int)(intv_end - invl_start);
1429 invl_start = g_strstr_len(invl_start, invl_len, ".");
1431 if (invl_start != NULL) {
1432 invl_len = (int)(intv_end - invl_start - 1);
1433 if (invl_len)
1434 io->invl_prec = MIN(invl_len, 6);
1438 if (io->interval < 1){
1439 fprintf(stderr,
1440 "\ntshark: \"-z\" interval must be >=0.000001 seconds or \"0\" for the entire capture duration.\n");
1441 exit(10);
1444 /* Find how many ',' separated filters we have */
1445 io->num_cols = 1;
1446 io->start_time=0;
1448 if (filters && (*filters != '\0')) {
1449 /* Eliminate the first comma. */
1450 filters++;
1451 str = filters;
1452 while((str = strchr(str, ','))) {
1453 io->num_cols++;
1454 str++;
1458 io->items = (io_stat_item_t *) g_malloc(sizeof(io_stat_item_t) * io->num_cols);
1459 io->filters = (const char **)g_malloc(sizeof(char *) * io->num_cols);
1460 io->max_vals = (guint64 *) g_malloc(sizeof(guint64) * io->num_cols);
1461 io->max_frame = (guint32 *) g_malloc(sizeof(guint32) * io->num_cols);
1463 for (i=0; i<io->num_cols; i++) {
1464 io->max_vals[i] = 0;
1465 io->max_frame[i] = 0;
1468 /* Register a tap listener for each filter */
1469 if((!filters) || (filters[0]==0)) {
1470 register_io_tap(io, 0, NULL);
1471 } else {
1472 gchar *filter;
1473 i = 0;
1474 str = filters;
1475 do {
1476 pos = (gchar*) strchr(str, ',');
1477 if(pos==str){
1478 register_io_tap(io, i, NULL);
1479 } else if (pos==NULL) {
1480 str = (const char*) g_strstrip((gchar*)str);
1481 filter = g_strdup((gchar*) str);
1482 if (*filter)
1483 register_io_tap(io, i, filter);
1484 else
1485 register_io_tap(io, i, NULL);
1486 } else {
1487 filter = (gchar *)g_malloc((pos-str)+1);
1488 g_strlcpy( filter, str, (gsize) ((pos-str)+1));
1489 filter = g_strstrip(filter);
1490 register_io_tap(io, i, (char *) filter);
1492 str = pos+1;
1493 i++;
1494 } while(pos);
1498 void
1499 register_tap_listener_iostat(void)
1501 register_stat_cmd_arg("io,stat,", iostat_init, NULL);
1505 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1507 * Local variables:
1508 * c-basic-offset: 4
1509 * tab-width: 4
1510 * indent-tabs-mode: nil
1511 * End:
1513 * vi: set shiftwidth=4 tabstop=4 expandtab:
1514 * :indentSize=4:tabSize=4:noTabs=true: