PageRenderTime 47ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/ui/cli/tap-iostat.c

https://github.com/labx-technologies-llc/wireshark
C | 1466 lines | 1200 code | 113 blank | 153 comment | 204 complexity | 954d6ef35f234b09693b901751f3c69d MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /* tap-iostat.c
  2. * iostat 2002 Ronnie Sahlberg
  3. *
  4. * $Id$
  5. *
  6. * Wireshark - Network traffic analyzer
  7. * By Gerald Combs <gerald@wireshark.org>
  8. * Copyright 1998 Gerald Combs
  9. *
  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.
  14. *
  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.
  19. *
  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.
  23. */
  24. #include "config.h"
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <epan/epan_dissect.h>
  28. #include <epan/packet_info.h>
  29. #include <epan/tap.h>
  30. #include <epan/timestamp.h>
  31. #include <epan/stat_cmd_args.h>
  32. #include <epan/strutil.h>
  33. #include "globals.h"
  34. #define CALC_TYPE_FRAMES 0
  35. #define CALC_TYPE_BYTES 1
  36. #define CALC_TYPE_FRAMES_AND_BYTES 2
  37. #define CALC_TYPE_COUNT 3
  38. #define CALC_TYPE_SUM 4
  39. #define CALC_TYPE_MIN 5
  40. #define CALC_TYPE_MAX 6
  41. #define CALC_TYPE_AVG 7
  42. #define CALC_TYPE_LOAD 8
  43. typedef struct {
  44. const char *func_name;
  45. int calc_type;
  46. } calc_type_ent_t;
  47. static calc_type_ent_t calc_type_table[] = {
  48. { "FRAMES", CALC_TYPE_FRAMES },
  49. { "BYTES", CALC_TYPE_BYTES },
  50. { "FRAMES BYTES", CALC_TYPE_FRAMES_AND_BYTES },
  51. { "COUNT", CALC_TYPE_COUNT },
  52. { "SUM", CALC_TYPE_SUM },
  53. { "MIN", CALC_TYPE_MIN },
  54. { "MAX", CALC_TYPE_MAX },
  55. { "AVG", CALC_TYPE_AVG },
  56. { "LOAD", CALC_TYPE_LOAD },
  57. { NULL, 0 }
  58. };
  59. typedef struct _io_stat_t {
  60. guint64 interval; /* The user-specified time interval (us) */
  61. guint invl_prec; /* Decimal precision of the time interval (1=10s, 2=100s etc) */
  62. int num_cols; /* The number of columns of stats in the table */
  63. struct _io_stat_item_t *items; /* Each item is a single cell in the table */
  64. time_t start_time; /* Time of first frame matching the filter */
  65. const char **filters; /* 'io,stat' cmd strings (e.g., "AVG(smb.time)smb.time") */
  66. guint64 *max_vals; /* The max value sans the decimal or nsecs portion in each stat column */
  67. guint32 *max_frame; /* The max frame number displayed in each stat column */
  68. } io_stat_t;
  69. typedef struct _io_stat_item_t {
  70. io_stat_t *parent;
  71. struct _io_stat_item_t *next;
  72. struct _io_stat_item_t *prev;
  73. guint64 time; /* Time since start of capture (us)*/
  74. int calc_type; /* The statistic type */
  75. int colnum; /* Column number of this stat (0 to n) */
  76. int hf_index;
  77. guint32 frames;
  78. guint32 num; /* The sample size of a given statistic (only needed for AVG) */
  79. guint64 counter; /* The accumulated data for the calculation of that statistic */
  80. gfloat float_counter;
  81. gdouble double_counter;
  82. } io_stat_item_t;
  83. #define NANOSECS_PER_SEC 1000000000ULL
  84. static guint64 last_relative_time;
  85. static int
  86. iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
  87. {
  88. io_stat_t *parent;
  89. io_stat_item_t *mit;
  90. io_stat_item_t *it;
  91. guint64 relative_time, rt;
  92. nstime_t *new_time;
  93. GPtrArray *gp;
  94. guint i;
  95. int ftype;
  96. mit = (io_stat_item_t *) arg;
  97. parent = mit->parent;
  98. /* If this frame's relative time is negative, set its relative time to last_relative_time
  99. rather than disincluding it from the calculations. */
  100. if (pinfo->rel_ts.secs >= 0) {
  101. relative_time = ((guint64)pinfo->rel_ts.secs * 1000000ULL) +
  102. ((guint64)((pinfo->rel_ts.nsecs+500)/1000));
  103. last_relative_time = relative_time;
  104. } else {
  105. relative_time = last_relative_time;
  106. }
  107. if (mit->parent->start_time == 0) {
  108. mit->parent->start_time = pinfo->fd->abs_ts.secs - pinfo->rel_ts.secs;
  109. }
  110. /* The prev item is always the last interval in which we saw packets. */
  111. it = mit->prev;
  112. /* If we have moved into a new interval (row), create a new io_stat_item_t struct for every interval
  113. * between the last struct and this one. If an item was not found in a previous interval, an empty
  114. * struct will be created for it. */
  115. rt = relative_time;
  116. while (rt >= it->time + parent->interval) {
  117. it->next = (io_stat_item_t *)g_malloc(sizeof(io_stat_item_t));
  118. it->next->prev = it;
  119. it->next->next = NULL;
  120. it = it->next;
  121. mit->prev = it;
  122. it->time = it->prev->time + parent->interval;
  123. it->frames = 0;
  124. it->counter = 0;
  125. it->float_counter = 0;
  126. it->double_counter = 0;
  127. it->num = 0;
  128. it->calc_type = it->prev->calc_type;
  129. it->hf_index = it->prev->hf_index;
  130. it->colnum = it->prev->colnum;
  131. }
  132. /* Store info in the current structure */
  133. it->frames++;
  134. switch(it->calc_type) {
  135. case CALC_TYPE_FRAMES:
  136. case CALC_TYPE_BYTES:
  137. case CALC_TYPE_FRAMES_AND_BYTES:
  138. it->counter += pinfo->fd->pkt_len;
  139. break;
  140. case CALC_TYPE_COUNT:
  141. gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
  142. if(gp){
  143. it->counter += gp->len;
  144. }
  145. break;
  146. case CALC_TYPE_SUM:
  147. gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
  148. if(gp){
  149. guint64 val;
  150. for(i=0;i<gp->len;i++){
  151. switch(proto_registrar_get_ftype(it->hf_index)){
  152. case FT_UINT8:
  153. case FT_UINT16:
  154. case FT_UINT24:
  155. case FT_UINT32:
  156. it->counter += fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
  157. break;
  158. case FT_UINT64:
  159. it->counter += fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
  160. break;
  161. case FT_INT8:
  162. case FT_INT16:
  163. case FT_INT24:
  164. case FT_INT32:
  165. it->counter += fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
  166. break;
  167. case FT_INT64:
  168. it->counter += (gint64)fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
  169. break;
  170. case FT_FLOAT:
  171. it->float_counter +=
  172. (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
  173. break;
  174. case FT_DOUBLE:
  175. it->double_counter += fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
  176. break;
  177. case FT_RELATIVE_TIME:
  178. new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
  179. val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
  180. it->counter += val;
  181. break;
  182. default:
  183. /*
  184. * "Can't happen"; see the checks
  185. * in register_io_tap().
  186. */
  187. g_assert_not_reached();
  188. break;
  189. }
  190. }
  191. }
  192. break;
  193. case CALC_TYPE_MIN:
  194. gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
  195. if(gp){
  196. guint64 val;
  197. gfloat float_val;
  198. gdouble double_val;
  199. ftype=proto_registrar_get_ftype(it->hf_index);
  200. for(i=0;i<gp->len;i++){
  201. switch(ftype){
  202. case FT_UINT8:
  203. case FT_UINT16:
  204. case FT_UINT24:
  205. case FT_UINT32:
  206. val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
  207. if ((it->frames==1 && i==0) || (val < it->counter)) {
  208. it->counter=val;
  209. }
  210. break;
  211. case FT_UINT64:
  212. val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
  213. if((it->frames==1 && i==0) || (val < it->counter)){
  214. it->counter=val;
  215. }
  216. break;
  217. case FT_INT8:
  218. case FT_INT16:
  219. case FT_INT24:
  220. case FT_INT32:
  221. val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
  222. if((it->frames==1 && i==0) || ((gint32)val < (gint32)it->counter)) {
  223. it->counter=val;
  224. }
  225. break;
  226. case FT_INT64:
  227. val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
  228. if((it->frames==1 && i==0) || ((gint64)val < (gint64)it->counter)) {
  229. it->counter=val;
  230. }
  231. break;
  232. case FT_FLOAT:
  233. float_val=(gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
  234. if((it->frames==1 && i==0) || (float_val < it->float_counter)) {
  235. it->float_counter=float_val;
  236. }
  237. break;
  238. case FT_DOUBLE:
  239. double_val=fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
  240. if((it->frames==1 && i==0) || (double_val < it->double_counter)) {
  241. it->double_counter=double_val;
  242. }
  243. break;
  244. case FT_RELATIVE_TIME:
  245. new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
  246. val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
  247. if((it->frames==1 && i==0) || (val < it->counter)) {
  248. it->counter=val;
  249. }
  250. break;
  251. default:
  252. /*
  253. * "Can't happen"; see the checks
  254. * in register_io_tap().
  255. */
  256. g_assert_not_reached();
  257. break;
  258. }
  259. }
  260. }
  261. break;
  262. case CALC_TYPE_MAX:
  263. gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
  264. if(gp){
  265. guint64 val;
  266. gfloat float_val;
  267. gdouble double_val;
  268. ftype=proto_registrar_get_ftype(it->hf_index);
  269. for(i=0;i<gp->len;i++){
  270. switch(ftype){
  271. case FT_UINT8:
  272. case FT_UINT16:
  273. case FT_UINT24:
  274. case FT_UINT32:
  275. val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
  276. if(val > it->counter)
  277. it->counter=val;
  278. break;
  279. case FT_UINT64:
  280. val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
  281. if(val > it->counter)
  282. it->counter=val;
  283. break;
  284. case FT_INT8:
  285. case FT_INT16:
  286. case FT_INT24:
  287. case FT_INT32:
  288. val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
  289. if((gint32)val > (gint32)it->counter)
  290. it->counter=val;
  291. break;
  292. case FT_INT64:
  293. val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
  294. if ((gint64)val > (gint64)it->counter)
  295. it->counter=val;
  296. break;
  297. case FT_FLOAT:
  298. float_val = (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
  299. if(float_val > it->float_counter)
  300. it->float_counter=float_val;
  301. break;
  302. case FT_DOUBLE:
  303. double_val = fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
  304. if(double_val > it->double_counter)
  305. it->double_counter=double_val;
  306. break;
  307. case FT_RELATIVE_TIME:
  308. new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
  309. val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
  310. if (val>it->counter)
  311. it->counter=val;
  312. break;
  313. default:
  314. /*
  315. * "Can't happen"; see the checks
  316. * in register_io_tap().
  317. */
  318. g_assert_not_reached();
  319. break;
  320. }
  321. }
  322. }
  323. break;
  324. case CALC_TYPE_AVG:
  325. gp=proto_get_finfo_ptr_array(edt->tree, it->hf_index);
  326. if(gp){
  327. guint64 val;
  328. ftype=proto_registrar_get_ftype(it->hf_index);
  329. for(i=0;i<gp->len;i++){
  330. it->num++;
  331. switch(ftype) {
  332. case FT_UINT8:
  333. case FT_UINT16:
  334. case FT_UINT24:
  335. case FT_UINT32:
  336. val = fvalue_get_uinteger(&((field_info *)gp->pdata[i])->value);
  337. it->counter += val;
  338. break;
  339. case FT_UINT64:
  340. case FT_INT64:
  341. val = fvalue_get_integer64(&((field_info *)gp->pdata[i])->value);
  342. it->counter += val;
  343. break;
  344. case FT_INT8:
  345. case FT_INT16:
  346. case FT_INT24:
  347. case FT_INT32:
  348. val = fvalue_get_sinteger(&((field_info *)gp->pdata[i])->value);
  349. it->counter += val;
  350. break;
  351. case FT_FLOAT:
  352. it->float_counter += (gfloat)fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
  353. break;
  354. case FT_DOUBLE:
  355. it->double_counter += fvalue_get_floating(&((field_info *)gp->pdata[i])->value);
  356. break;
  357. case FT_RELATIVE_TIME:
  358. new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
  359. val = ((guint64)new_time->secs * NANOSECS_PER_SEC) + (guint64)new_time->nsecs;
  360. it->counter += val;
  361. break;
  362. default:
  363. /*
  364. * "Can't happen"; see the checks
  365. * in register_io_tap().
  366. */
  367. g_assert_not_reached();
  368. break;
  369. }
  370. }
  371. }
  372. break;
  373. case CALC_TYPE_LOAD:
  374. gp = proto_get_finfo_ptr_array(edt->tree, it->hf_index);
  375. if (gp) {
  376. ftype = proto_registrar_get_ftype(it->hf_index);
  377. if (ftype != FT_RELATIVE_TIME) {
  378. fprintf(stderr,
  379. "\ntshark: LOAD() is only supported for relative-time fields such as smb.time\n");
  380. exit(10);
  381. }
  382. for(i=0;i<gp->len;i++){
  383. guint64 val;
  384. int tival;
  385. io_stat_item_t *pit;
  386. new_time = (nstime_t *)fvalue_get(&((field_info *)gp->pdata[i])->value);
  387. val = ((guint64)new_time->secs*1000000ULL) + (guint64)(new_time->nsecs/1000);
  388. tival = (int)(val % parent->interval);
  389. it->counter += tival;
  390. val -= tival;
  391. pit = it->prev;
  392. while (val > 0) {
  393. if (val < (guint64)parent->interval) {
  394. pit->counter += val;
  395. break;
  396. }
  397. pit->counter += parent->interval;
  398. val -= parent->interval;
  399. pit = pit->prev;
  400. }
  401. }
  402. }
  403. break;
  404. }
  405. /* Store the highest value for this item in order to determine the width of each stat column.
  406. * For real numbers we only need to know its magnitude (the value to the left of the decimal point
  407. * so round it up before storing it as an integer in max_vals. For AVG of RELATIVE_TIME fields,
  408. * calc the average, round it to the next second and store the seconds. For all other calc types
  409. * of RELATIVE_TIME fields, store the counters without modification.
  410. * fields. */
  411. switch(it->calc_type) {
  412. case CALC_TYPE_FRAMES:
  413. case CALC_TYPE_FRAMES_AND_BYTES:
  414. parent->max_frame[it->colnum] =
  415. MAX(parent->max_frame[it->colnum], it->frames);
  416. if (it->calc_type==CALC_TYPE_FRAMES_AND_BYTES)
  417. parent->max_vals[it->colnum] =
  418. MAX(parent->max_vals[it->colnum], it->counter);
  419. case CALC_TYPE_BYTES:
  420. case CALC_TYPE_COUNT:
  421. case CALC_TYPE_LOAD:
  422. parent->max_vals[it->colnum] = MAX(parent->max_vals[it->colnum], it->counter);
  423. break;
  424. case CALC_TYPE_SUM:
  425. case CALC_TYPE_MIN:
  426. case CALC_TYPE_MAX:
  427. ftype=proto_registrar_get_ftype(it->hf_index);
  428. switch(ftype) {
  429. case FT_FLOAT:
  430. parent->max_vals[it->colnum] =
  431. MAX(parent->max_vals[it->colnum], (guint64)(it->float_counter+0.5));
  432. break;
  433. case FT_DOUBLE:
  434. parent->max_vals[it->colnum] =
  435. MAX(parent->max_vals[it->colnum],(guint64)(it->double_counter+0.5));
  436. break;
  437. case FT_RELATIVE_TIME:
  438. parent->max_vals[it->colnum] =
  439. MAX(parent->max_vals[it->colnum], it->counter);
  440. break;
  441. default:
  442. /* UINT16-64 and INT8-64 */
  443. parent->max_vals[it->colnum] =
  444. MAX(parent->max_vals[it->colnum], it->counter);
  445. break;
  446. }
  447. break;
  448. case CALC_TYPE_AVG:
  449. if (it->num==0) /* avoid division by zero */
  450. break;
  451. ftype=proto_registrar_get_ftype(it->hf_index);
  452. switch(ftype) {
  453. case FT_FLOAT:
  454. parent->max_vals[it->colnum] =
  455. MAX(parent->max_vals[it->colnum], (guint64)it->float_counter/it->num);
  456. break;
  457. case FT_DOUBLE:
  458. parent->max_vals[it->colnum] =
  459. MAX(parent->max_vals[it->colnum],(guint64)it->double_counter/it->num);
  460. break;
  461. case FT_RELATIVE_TIME:
  462. parent->max_vals[it->colnum] =
  463. MAX(parent->max_vals[it->colnum], ((it->counter/(guint64)it->num) + 500000000ULL) / NANOSECS_PER_SEC);
  464. break;
  465. default:
  466. /* UINT16-64 and INT8-64 */
  467. parent->max_vals[it->colnum] =
  468. MAX(parent->max_vals[it->colnum], it->counter/it->num);
  469. break;
  470. }
  471. }
  472. return TRUE;
  473. }
  474. static int
  475. magnitude (guint64 val, int max_w)
  476. {
  477. int i, mag=0;
  478. for (i=0; i<max_w; i++) {
  479. mag++;
  480. if ((val /= 10)==0)
  481. break;
  482. }
  483. return(mag);
  484. }
  485. /*
  486. * Print the calc_type_table[] function label centered in the column header.
  487. */
  488. static void
  489. printcenter (const char *label, int lenval, int numpad)
  490. {
  491. int lenlab = (int) strlen(label), len;
  492. const char spaces[]=" ", *spaces_ptr;
  493. len = (int) (strlen(spaces)) - (((lenval-lenlab) / 2) + numpad);
  494. if (len > 0 && len < 6) {
  495. spaces_ptr = &spaces[len];
  496. if ((lenval-lenlab)%2==0) {
  497. printf("%s%s%s|", spaces_ptr, label, spaces_ptr);
  498. } else {
  499. printf("%s%s%s|", spaces_ptr-1, label, spaces_ptr);
  500. }
  501. } else if (len > 0 && len <= 15) {
  502. printf("%s|", label);
  503. }
  504. }
  505. typedef struct {
  506. int fr; /* Width of this FRAMES column sans padding and border chars */
  507. int val; /* Width of this non-FRAMES column sans padding and border chars */
  508. } column_width;
  509. static void
  510. iostat_draw(void *arg)
  511. {
  512. guint32 num;
  513. guint64 interval, duration, t, invl_end, dv;
  514. int i, j, k, num_cols, num_rows, dur_secs_orig, dur_nsecs_orig, dur_secs, dur_nsecs, dur_mag,
  515. invl_mag, invl_prec, tabrow_w, borderlen, invl_col_w, numpad=1, namelen, len_filt, type,
  516. maxfltr_w, ftype;
  517. int fr_mag; /* The magnitude of the max frame number in this column */
  518. int val_mag; /* The magnitude of the max value in this column */
  519. char *spaces, *spaces_s, *filler_s=NULL, **fmts, *fmt=NULL;
  520. const char *filter;
  521. static gchar dur_mag_s[3], invl_prec_s[3], fr_mag_s[3], val_mag_s[3], *invl_fmt, *full_fmt;
  522. io_stat_item_t *mit, **stat_cols, *item, **item_in_column;
  523. gboolean last_row=FALSE;
  524. io_stat_t *iot;
  525. column_width *col_w;
  526. struct tm * tm_time;
  527. time_t the_time;
  528. mit = (io_stat_item_t *)arg;
  529. iot = mit->parent;
  530. num_cols = iot->num_cols;
  531. col_w = (column_width *)g_malloc(sizeof(column_width) * num_cols);
  532. fmts = (char **)g_malloc(sizeof(char *) * num_cols);
  533. duration = ((guint64)cfile.elapsed_time.secs * 1000000ULL) +
  534. (guint64)((cfile.elapsed_time.nsecs + 500) / 1000);
  535. /* Store the pointer to each stat column */
  536. stat_cols = (io_stat_item_t **) g_malloc(sizeof(io_stat_item_t *) * num_cols);
  537. for (j=0; j<num_cols; j++)
  538. stat_cols[j] = &iot->items[j];
  539. /* The following prevents gross inaccuracies when the user specifies an interval that is greater
  540. * than the capture duration. */
  541. if (iot->interval > duration || iot->interval==G_MAXINT32) {
  542. interval = duration;
  543. iot->interval = G_MAXINT32;
  544. } else {
  545. interval = iot->interval;
  546. }
  547. /* Calc the capture duration's magnitude (dur_mag) */
  548. dur_secs = (int)(duration/1000000ULL);
  549. dur_secs_orig = dur_secs;
  550. dur_nsecs = (int)(duration%1000000ULL);
  551. dur_nsecs_orig = dur_nsecs;
  552. dur_mag = magnitude((guint64)dur_secs, 5);
  553. g_snprintf(dur_mag_s, 3, "%u", dur_mag);
  554. /* Calc the interval's magnitude */
  555. invl_mag = magnitude(interval/1000000ULL, 5);
  556. /* Set or get the interval precision */
  557. if (interval==duration) {
  558. /*
  559. * An interval arg of 0 or an interval size exceeding the capture duration was specified.
  560. * Set the decimal precision of duration based on its magnitude. */
  561. if (dur_mag >= 2)
  562. invl_prec = 1;
  563. else if (dur_mag==1)
  564. invl_prec = 3;
  565. else
  566. invl_prec = 6;
  567. borderlen = 30 + dur_mag + (invl_prec==0 ? 0 : invl_prec+1);
  568. } else {
  569. invl_prec = iot->invl_prec;
  570. borderlen = 24 + invl_mag + (invl_prec==0 ? 0 : invl_prec+1);
  571. }
  572. /* Round the duration according to invl_prec */
  573. dv=1000000;
  574. for (i=0; i<invl_prec; i++)
  575. dv /= 10;
  576. if ((duration%dv) > 5*(dv/10)) {
  577. duration += 5*(dv/10);
  578. duration = (duration/dv) * dv;
  579. dur_secs = (int)(duration/1000000ULL);
  580. dur_nsecs = (int)(duration%1000000ULL);
  581. /*
  582. * Recalc dur_mag in case rounding has increased its magnitude */
  583. dur_mag = magnitude((guint64)dur_secs, 5);
  584. }
  585. if (iot->interval==G_MAXINT32)
  586. interval = duration;
  587. /* Calc the width of the time interval column (incl borders and padding). */
  588. if (invl_prec==0)
  589. invl_col_w = (2*dur_mag) + 8;
  590. else
  591. invl_col_w = (2*dur_mag) + (2*invl_prec) + 10;
  592. /* Update the width of the time interval column for "-t ad" */
  593. if (timestamp_get_type()==TS_ABSOLUTE_WITH_DATE)
  594. invl_col_w = MAX(invl_col_w, 23);
  595. else
  596. invl_col_w = MAX(invl_col_w, 12);
  597. borderlen = MAX(borderlen, invl_col_w);
  598. /* Calc the total width of each row in the stats table and build the printf format string for each
  599. * column based on its field type, width, and name length.
  600. * NOTE: The magnitude of all types including float and double are stored in iot->max_vals which
  601. * is an *integer*. */
  602. tabrow_w = invl_col_w;
  603. for (j=0; j<num_cols; j++) {
  604. type = iot->items[j].calc_type;
  605. if (type==CALC_TYPE_FRAMES_AND_BYTES) {
  606. namelen = 5;
  607. } else {
  608. namelen = (int) strlen(calc_type_table[type].func_name);
  609. }
  610. if(type==CALC_TYPE_FRAMES
  611. || type==CALC_TYPE_FRAMES_AND_BYTES) {
  612. fr_mag = magnitude(iot->max_frame[j], 15);
  613. fr_mag = MAX(6, fr_mag);
  614. col_w[j].fr = fr_mag;
  615. tabrow_w += col_w[j].fr + 3;
  616. g_snprintf(fr_mag_s, 3, "%u", fr_mag);
  617. if (type==CALC_TYPE_FRAMES) {
  618. fmt = g_strconcat(" %", fr_mag_s, "u |", NULL);
  619. } else {
  620. /* CALC_TYPE_FRAMES_AND_BYTES
  621. */
  622. val_mag = magnitude(iot->max_vals[j], 15);
  623. val_mag = MAX(5, val_mag);
  624. col_w[j].val = val_mag;
  625. tabrow_w += (col_w[j].val + 3);
  626. g_snprintf(val_mag_s, 3, "%u", val_mag);
  627. fmt = g_strconcat(" %", fr_mag_s, "u |", " %", val_mag_s, G_GINT64_MODIFIER, "u |", NULL);
  628. }
  629. if (fmt)
  630. fmts[j] = fmt;
  631. continue;
  632. }
  633. switch(type) {
  634. case CALC_TYPE_BYTES:
  635. case CALC_TYPE_COUNT:
  636. val_mag = magnitude(iot->max_vals[j], 15);
  637. val_mag = MAX(5, val_mag);
  638. col_w[j].val = val_mag;
  639. g_snprintf(val_mag_s, 3, "%u", val_mag);
  640. fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "u |", NULL);
  641. break;
  642. default:
  643. ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
  644. switch (ftype) {
  645. case FT_FLOAT:
  646. case FT_DOUBLE:
  647. val_mag = magnitude(iot->max_vals[j], 15);
  648. g_snprintf(val_mag_s, 3, "%u", val_mag);
  649. fmt = g_strconcat(" %", val_mag_s, ".6f |", NULL);
  650. col_w[j].val = val_mag + 7;
  651. break;
  652. case FT_RELATIVE_TIME:
  653. /* Convert FT_RELATIVE_TIME field to seconds
  654. * CALC_TYPE_LOAD was already converted in iostat_packet() ) */
  655. if (type==CALC_TYPE_LOAD) {
  656. iot->max_vals[j] /= interval;
  657. } else if (type != CALC_TYPE_AVG) {
  658. iot->max_vals[j] = (iot->max_vals[j] + 500000000ULL) / NANOSECS_PER_SEC;
  659. }
  660. val_mag = magnitude(iot->max_vals[j], 15);
  661. g_snprintf(val_mag_s, 3, "%u", val_mag);
  662. fmt = g_strconcat(" %", val_mag_s, "u.%06u |", NULL);
  663. col_w[j].val = val_mag + 7;
  664. break;
  665. default:
  666. val_mag = magnitude(iot->max_vals[j], 15);
  667. val_mag = MAX(namelen, val_mag);
  668. col_w[j].val = val_mag;
  669. g_snprintf(val_mag_s, 3, "%u", val_mag);
  670. switch (ftype) {
  671. case FT_UINT8:
  672. case FT_UINT16:
  673. case FT_UINT24:
  674. case FT_UINT32:
  675. case FT_UINT64:
  676. fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "u |", NULL);
  677. break;
  678. case FT_INT8:
  679. case FT_INT16:
  680. case FT_INT24:
  681. case FT_INT32:
  682. case FT_INT64:
  683. fmt = g_strconcat(" %", val_mag_s, G_GINT64_MODIFIER, "d |", NULL);
  684. break;
  685. }
  686. } /* End of ftype switch */
  687. } /* End of calc_type switch */
  688. tabrow_w += col_w[j].val + 3;
  689. if (fmt)
  690. fmts[j] = fmt;
  691. } /* End of for loop (columns) */
  692. borderlen = MAX(borderlen, tabrow_w);
  693. /* Calc the max width of the list of filters. */
  694. maxfltr_w = 0;
  695. for(j=0; j<num_cols; j++) {
  696. if (iot->filters[j]) {
  697. k = (int) (strlen(iot->filters[j]) + 11);
  698. maxfltr_w = MAX(maxfltr_w, k);
  699. } else {
  700. maxfltr_w = MAX(maxfltr_w, 26);
  701. }
  702. }
  703. /* The stat table is not wrapped (by tshark) but filter is wrapped at the width of the stats table
  704. * (which currently = borderlen); however, if the filter width exceeds the table width and the
  705. * table width is less than 102 bytes, set borderlen to the lesser of the max filter width and 102.
  706. * The filters will wrap at the lesser of borderlen-2 and the last space in the filter.
  707. * NOTE: 102 is the typical size of a user window when the font is fixed width (e.g., COURIER 10).
  708. * XXX: A pref could be added to change the max width from the default size of 102. */
  709. if (maxfltr_w > borderlen && borderlen < 102)
  710. borderlen = MIN(maxfltr_w, 102);
  711. /* Prevent double right border by adding a space */
  712. if (borderlen-tabrow_w==1)
  713. borderlen++;
  714. /* Display the top border */
  715. printf("\n");
  716. for (i=0; i<borderlen; i++)
  717. printf("=");
  718. spaces = (char*) g_malloc(borderlen+1);
  719. for (i=0; i<borderlen; i++)
  720. spaces[i] = ' ';
  721. spaces[borderlen] = '\0';
  722. spaces_s = &spaces[16];
  723. printf("\n| IO Statistics%s|\n", spaces_s);
  724. spaces_s = &spaces[2];
  725. printf("|%s|\n", spaces_s);
  726. if (invl_prec==0) {
  727. invl_fmt = g_strconcat("%", dur_mag_s, "u", NULL);
  728. full_fmt = g_strconcat("| Duration: ", invl_fmt, ".%6u secs%s|\n", NULL);
  729. spaces_s = &spaces[25 + dur_mag];
  730. printf(full_fmt, dur_secs_orig, dur_nsecs_orig, spaces_s);
  731. g_free(full_fmt);
  732. full_fmt = g_strconcat("| Interval: ", invl_fmt, " secs%s|\n", NULL);
  733. spaces_s = &spaces[18 + dur_mag];
  734. printf(full_fmt, (guint32)(interval/1000000ULL), spaces_s);
  735. } else {
  736. g_snprintf(invl_prec_s, 3, "%u", invl_prec);
  737. invl_fmt = g_strconcat("%", dur_mag_s, "u.%0", invl_prec_s, "u", NULL);
  738. full_fmt = g_strconcat("| Duration: ", invl_fmt, " secs%s|\n", NULL);
  739. spaces_s = &spaces[19 + dur_mag + invl_prec];
  740. printf(full_fmt, dur_secs, dur_nsecs/(int)dv, spaces_s);
  741. g_free(full_fmt);
  742. full_fmt = g_strconcat("| Interval: ", invl_fmt, " secs%s|\n", NULL);
  743. spaces_s = &spaces[19 + dur_mag + invl_prec];
  744. printf(full_fmt, (guint32)(interval/1000000ULL),
  745. (guint32)((interval%1000000ULL)/dv), spaces_s);
  746. }
  747. g_free(full_fmt);
  748. spaces_s = &spaces[2];
  749. printf("|%s|\n", spaces_s);
  750. /* Display the list of filters and their column numbers vertically */
  751. printf("| Col");
  752. for(j=0; j<num_cols; j++){
  753. printf((j==0 ? "%2u: " : "| %2u: "), j+1);
  754. if (!iot->filters[j] || (iot->filters[j]==0)) {
  755. /*
  756. * An empty (no filter) comma field was specified */
  757. spaces_s = &spaces[16 + 10];
  758. printf("Frames and bytes%s|\n", spaces_s);
  759. } else {
  760. filter = iot->filters[j];
  761. len_filt = (int) strlen(filter);
  762. /* If the width of the widest filter exceeds the width of the stat table, borderlen has
  763. * been set to 102 bytes above and filters wider than 102 will wrap at 91 bytes. */
  764. if (len_filt+11 <= borderlen) {
  765. printf("%s", filter);
  766. if (len_filt+11 <= borderlen) {
  767. spaces_s = &spaces[len_filt + 10];
  768. printf("%s", spaces_s);
  769. }
  770. printf("|\n");
  771. } else {
  772. gchar *sfilter1, *sfilter2;
  773. const gchar *pos;
  774. gsize len;
  775. int next_start, max_w=borderlen-11;
  776. do {
  777. if (len_filt > max_w) {
  778. sfilter1 = g_strndup( (gchar *) filter, (gsize) max_w);
  779. /*
  780. * Find the pos of the last space in sfilter1. If a space is found, set
  781. * sfilter2 to the string prior to that space and print it; otherwise, wrap
  782. * the filter at max_w. */
  783. pos = g_strrstr(sfilter1, " ");
  784. if (pos) {
  785. len = (gsize)(pos-sfilter1);
  786. next_start = (int) len+1;
  787. } else {
  788. len = (gsize) strlen(sfilter1);
  789. next_start = (int)len;
  790. }
  791. sfilter2 = g_strndup(sfilter1, len);
  792. printf("%s%s|\n", sfilter2, &spaces[len+10]);
  793. g_free(sfilter1);
  794. g_free(sfilter2);
  795. printf("| ");
  796. filter = &filter[next_start];
  797. len_filt = (int) strlen(filter);
  798. } else {
  799. printf("%s%s|\n", filter, &spaces[((int)strlen(filter))+10]);
  800. break;
  801. }
  802. } while (1);
  803. }
  804. }
  805. }
  806. printf("|-");
  807. for(i=0;i<borderlen-3;i++){
  808. printf("-");
  809. }
  810. printf("|\n");
  811. /* Display spaces above "Interval (s)" label */
  812. spaces_s = &spaces[borderlen-(invl_col_w-2)];
  813. printf("|%s|", spaces_s);
  814. /* Display column number headers */
  815. for(j=0; j<num_cols; j++) {
  816. item = stat_cols[j];
  817. if(item->calc_type==CALC_TYPE_FRAMES_AND_BYTES)
  818. spaces_s = &spaces[borderlen - (col_w[j].fr + col_w[j].val)] - 3;
  819. else if (item->calc_type==CALC_TYPE_FRAMES)
  820. spaces_s = &spaces[borderlen - col_w[j].fr];
  821. else
  822. spaces_s = &spaces[borderlen - col_w[j].val];
  823. printf("%-2u%s|", j+1, spaces_s);
  824. }
  825. if (tabrow_w < borderlen) {
  826. filler_s = &spaces[tabrow_w+1];
  827. printf("%s|", filler_s);
  828. }
  829. k = 11;
  830. switch (timestamp_get_type()) {
  831. case TS_ABSOLUTE:
  832. printf("\n| Time ");
  833. break;
  834. case TS_ABSOLUTE_WITH_DATE:
  835. printf("\n| Date and time");
  836. k = 16;
  837. break;
  838. case TS_RELATIVE:
  839. case TS_NOT_SET:
  840. printf("\n| Interval");
  841. break;
  842. default:
  843. break;
  844. }
  845. spaces_s = &spaces[borderlen-(invl_col_w-k)];
  846. printf("%s|", spaces_s);
  847. /* Display the stat label in each column */
  848. for(j=0; j<num_cols; j++) {
  849. type = stat_cols[j]->calc_type;
  850. if(type==CALC_TYPE_FRAMES) {
  851. printcenter (calc_type_table[type].func_name, col_w[j].fr, numpad);
  852. } else if (type==CALC_TYPE_FRAMES_AND_BYTES) {
  853. printcenter ("Frames", col_w[j].fr, numpad);
  854. printcenter ("Bytes", col_w[j].val, numpad);
  855. } else {
  856. printcenter (calc_type_table[type].func_name, col_w[j].val, numpad);
  857. }
  858. }
  859. if (filler_s)
  860. printf("%s|", filler_s);
  861. printf("\n|-");
  862. for(i=0; i<tabrow_w-3; i++)
  863. printf("-");
  864. printf("|");
  865. if (tabrow_w < borderlen)
  866. printf("%s|", &spaces[tabrow_w+1]);
  867. printf("\n");
  868. t=0;
  869. if (invl_prec==0 && dur_mag==1)
  870. full_fmt = g_strconcat("| ", invl_fmt, " <> ", invl_fmt, " |", NULL);
  871. else
  872. full_fmt = g_strconcat("| ", invl_fmt, " <> ", invl_fmt, " |", NULL);
  873. if (interval == 0 || duration == 0) {
  874. num_rows = 0;
  875. } else {
  876. num_rows = (int)(duration/interval) + ((int)(duration%interval) > 0 ? 1 : 0);
  877. }
  878. /* Load item_in_column with the first item in each column */
  879. item_in_column = (io_stat_item_t **) g_malloc(sizeof(io_stat_item_t *) * num_cols);
  880. for (j=0; j<num_cols; j++) {
  881. item_in_column[j] = stat_cols[j];
  882. }
  883. /* Display the table values
  884. *
  885. * The outer loop is for time interval rows and the inner loop is for stat column items.*/
  886. for (i=0; i<num_rows; i++) {
  887. if (i==num_rows-1)
  888. last_row = TRUE;
  889. /* Compute the interval for this row */
  890. if (!last_row) {
  891. invl_end = t + interval;
  892. } else {
  893. invl_end = duration;
  894. }
  895. /* Patch for Absolute Time */
  896. /* XXX - has a Y2.038K problem with 32-bit time_t */
  897. the_time = (time_t)(iot->start_time + (t/1000000ULL));
  898. tm_time = localtime(&the_time);
  899. /* Display the interval for this row */
  900. switch (timestamp_get_type()) {
  901. case TS_ABSOLUTE:
  902. printf("| %02d:%02d:%02d |",
  903. tm_time->tm_hour,
  904. tm_time->tm_min,
  905. tm_time->tm_sec);
  906. break;
  907. case TS_ABSOLUTE_WITH_DATE:
  908. printf("| %04d-%02d-%02d %02d:%02d:%02d |",
  909. tm_time->tm_year + 1900,
  910. tm_time->tm_mon + 1,
  911. tm_time->tm_mday,
  912. tm_time->tm_hour,
  913. tm_time->tm_min,
  914. tm_time->tm_sec);
  915. break;
  916. case TS_RELATIVE:
  917. case TS_NOT_SET:
  918. if (invl_prec==0) {
  919. if(last_row) {
  920. int maxw;
  921. maxw = dur_mag >= 3 ? dur_mag+1 : 3;
  922. g_free(full_fmt);
  923. g_snprintf(dur_mag_s, 3, "%u", maxw);
  924. full_fmt = g_strconcat( dur_mag==1 ? "| " : "| ",
  925. invl_fmt, " <> ", "%-",
  926. dur_mag_s, "s|", NULL);
  927. printf(full_fmt, (guint32)(t/1000000ULL), "Dur");
  928. } else {
  929. printf(full_fmt, (guint32)(t/1000000ULL),
  930. (guint32)(invl_end/1000000ULL));
  931. }
  932. } else {
  933. printf(full_fmt, (guint32)(t/1000000ULL),
  934. (guint32)(t%1000000ULL / dv),
  935. (guint32)(invl_end/1000000ULL),
  936. (guint32)(invl_end%1000000ULL / dv));
  937. }
  938. break;
  939. /* case TS_DELTA:
  940. case TS_DELTA_DIS:
  941. case TS_EPOCH:
  942. case TS_UTC:
  943. case TS_UTC_WITH_DATE:
  944. are not implemented */
  945. default:
  946. break;
  947. }
  948. /* Display stat values in each column for this row */
  949. for (j=0; j<num_cols; j++) {
  950. fmt = fmts[j];
  951. item = item_in_column[j];
  952. if (item) {
  953. switch(item->calc_type) {
  954. case CALC_TYPE_FRAMES:
  955. printf(fmt, item->frames);
  956. break;
  957. case CALC_TYPE_BYTES:
  958. case CALC_TYPE_COUNT:
  959. printf(fmt, item->counter);
  960. break;
  961. case CALC_TYPE_FRAMES_AND_BYTES:
  962. printf(fmt, item->frames, item->counter);
  963. break;
  964. case CALC_TYPE_SUM:
  965. case CALC_TYPE_MIN:
  966. case CALC_TYPE_MAX:
  967. ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
  968. switch(ftype){
  969. case FT_FLOAT:
  970. printf(fmt, item->float_counter);
  971. break;
  972. case FT_DOUBLE:
  973. printf(fmt, item->double_counter);
  974. break;
  975. case FT_RELATIVE_TIME:
  976. item->counter = (item->counter + 500ULL) / 1000ULL;
  977. printf(fmt, (int)(item->counter/1000000ULL), (int)(item->counter%1000000ULL));
  978. break;
  979. default:
  980. printf(fmt, item->counter);
  981. break;
  982. }
  983. break;
  984. case CALC_TYPE_AVG:
  985. num = item->num;
  986. if(num==0)
  987. num=1;
  988. ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
  989. switch(ftype){
  990. case FT_FLOAT:
  991. printf(fmt, item->float_counter/num);
  992. break;
  993. case FT_DOUBLE:
  994. printf(fmt, item->double_counter/num);
  995. break;
  996. case FT_RELATIVE_TIME:
  997. item->counter = ((item->counter / (guint64)num) + 500ULL) / 1000ULL;
  998. printf(fmt,
  999. (int)(item->counter/1000000ULL), (int)(item->counter%1000000ULL));
  1000. break;
  1001. default:
  1002. printf(fmt, item->counter / (guint64)num);
  1003. break;
  1004. }
  1005. break;
  1006. case CALC_TYPE_LOAD:
  1007. ftype = proto_registrar_get_ftype(stat_cols[j]->hf_index);
  1008. switch(ftype){
  1009. case FT_RELATIVE_TIME:
  1010. if (!last_row) {
  1011. printf(fmt,
  1012. (int) (item->counter/interval),
  1013. (int)((item->counter%interval)*1000000ULL / interval));
  1014. } else {
  1015. printf(fmt,
  1016. (int) (item->counter/(invl_end-t)),
  1017. (int)((item->counter%(invl_end-t))*1000000ULL / (invl_end-t)));
  1018. }
  1019. break;
  1020. }
  1021. break;
  1022. }
  1023. if (last_row) {
  1024. if (fmt)
  1025. g_free(fmt);
  1026. } else {
  1027. item_in_column[j] = item_in_column[j]->next;
  1028. }
  1029. } else {
  1030. printf(fmt, (guint64)0, (guint64)0);
  1031. }
  1032. }
  1033. if (filler_s)
  1034. printf("%s|", filler_s);
  1035. printf("\n");
  1036. t += interval;
  1037. }
  1038. for(i=0;i<borderlen;i++){
  1039. printf("=");
  1040. }
  1041. printf("\n");
  1042. g_free(iot->items);
  1043. g_free(iot->max_vals);
  1044. g_free(iot->max_frame);
  1045. g_free(iot);
  1046. g_free(col_w);
  1047. g_free(invl_fmt);
  1048. g_free(full_fmt);
  1049. g_free(fmts);
  1050. g_free(spaces);
  1051. g_free(stat_cols);
  1052. g_free(item_in_column);
  1053. }
  1054. static void
  1055. register_io_tap(io_stat_t *io, int i, const char *filter)
  1056. {
  1057. GString *error_string;
  1058. const char *flt;
  1059. int j;
  1060. size_t namelen;
  1061. const char *p, *parenp;
  1062. char *field;
  1063. header_field_info *hfi;
  1064. io->items[i].prev=&io->items[i];
  1065. io->items[i].next=NULL;
  1066. io->items[i].parent=io;
  1067. io->items[i].time=0;
  1068. io->items[i].calc_type=CALC_TYPE_FRAMES_AND_BYTES;
  1069. io->items[i].frames=0;
  1070. io->items[i].counter=0;
  1071. io->items[i].num=0;
  1072. io->filters[i]=filter;
  1073. flt=filter;
  1074. field=NULL;
  1075. hfi=NULL;
  1076. for(j=0; calc_type_table[j].func_name; j++){
  1077. namelen=strlen(calc_type_table[j].func_name);
  1078. if(filter && strncmp(filter, calc_type_table[j].func_name, namelen) == 0) {
  1079. io->items[i].calc_type=calc_type_table[j].calc_type;
  1080. io->items[i].colnum = i;
  1081. if(*(filter+namelen)=='(') {
  1082. p=filter+namelen+1;
  1083. parenp=strchr(p, ')');
  1084. if(!parenp){
  1085. fprintf(stderr,
  1086. "\ntshark: Closing parenthesis missing from calculated expression.\n");
  1087. exit(10);
  1088. }
  1089. if(io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES){
  1090. if(parenp!=p) {
  1091. fprintf(stderr,
  1092. "\ntshark: %s does not require or allow a field name within the parens.\n",
  1093. calc_type_table[j].func_name);
  1094. exit(10);
  1095. }
  1096. } else {
  1097. if(parenp==p) {
  1098. /* bail out if a field name was not specified */
  1099. fprintf(stderr, "\ntshark: You didn't specify a field name for %s(*).\n",
  1100. calc_type_table[j].func_name);
  1101. exit(10);
  1102. }
  1103. }
  1104. field = (char *) g_malloc(parenp-p+1);
  1105. memcpy(field, p, parenp-p);
  1106. field[parenp-p] = '\0';
  1107. flt=parenp + 1;
  1108. if (io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES)
  1109. break;
  1110. hfi=proto_registrar_get_byname(field);
  1111. if(!hfi){
  1112. fprintf(stderr, "\ntshark: There is no field named '%s'.\n",
  1113. field);
  1114. g_free(field);
  1115. exit(10);
  1116. }
  1117. io->items[i].hf_index=hfi->id;
  1118. break;
  1119. }
  1120. } else {
  1121. if (io->items[i].calc_type==CALC_TYPE_FRAMES || io->items[i].calc_type==CALC_TYPE_BYTES)
  1122. flt="";
  1123. io->items[i].colnum = i;
  1124. }
  1125. }
  1126. if(hfi && !(io->items[i].calc_type==CALC_TYPE_BYTES ||
  1127. io->items[i].calc_type==CALC_TYPE_FRAMES ||
  1128. io->items[i].calc_type==CALC_TYPE_FRAMES_AND_BYTES)){
  1129. /* check that the type is compatible */
  1130. switch(hfi->type){
  1131. case FT_UINT8:
  1132. case FT_UINT16:
  1133. case FT_UINT24:
  1134. case FT_UINT32:
  1135. case FT_UINT64:
  1136. case FT_INT8:
  1137. case FT_INT16:
  1138. case FT_INT24:
  1139. case FT_INT32:
  1140. case FT_INT64:
  1141. /* these types support all calculations */
  1142. break;
  1143. case FT_FLOAT:
  1144. case FT_DOUBLE:
  1145. /* these types only support SUM, COUNT, MAX, MIN, AVG */
  1146. switch(io->items[i].calc_type){
  1147. case CALC_TYPE_SUM:
  1148. case CALC_TYPE_COUNT:
  1149. case CALC_TYPE_MAX:
  1150. case CALC_TYPE_MIN:
  1151. case CALC_TYPE_AVG:
  1152. break;
  1153. default:
  1154. fprintf(stderr,
  1155. "\ntshark: %s is a float field, so %s(*) calculations are not supported on it.",
  1156. field,
  1157. calc_type_table[j].func_name);
  1158. exit(10);
  1159. }
  1160. break;
  1161. case FT_RELATIVE_TIME:
  1162. /* this type only supports SUM, COUNT, MAX, MIN, AVG, LOAD */
  1163. switch(io->items[i].calc_type){
  1164. case CALC_TYPE_SUM:
  1165. case CALC_TYPE_COUNT:
  1166. case CALC_TYPE_MAX:
  1167. case CALC_TYPE_MIN:
  1168. case CALC_TYPE_AVG:
  1169. case CALC_TYPE_LOAD:
  1170. break;
  1171. default:
  1172. fprintf(stderr,
  1173. "\ntshark: %s is a relative-time field, so %s(*) calculations are not supported on it.",
  1174. field,
  1175. calc_type_table[j].func_name);
  1176. exit(10);
  1177. }
  1178. break;
  1179. default:
  1180. /*
  1181. * XXX - support all operations on floating-point
  1182. * numbers?
  1183. */
  1184. if(io->items[i].calc_type!=CALC_TYPE_COUNT){
  1185. fprintf(stderr,
  1186. "\ntshark: %s doesn't have integral values, so %s(*) "
  1187. "calculations are not supported on it.\n",
  1188. field,
  1189. calc_type_table[j].func_name);
  1190. exit(10);
  1191. }
  1192. break;
  1193. }
  1194. g_free(field);
  1195. }
  1196. error_string=register_tap_listener("frame", &io->items[i], flt, TL_REQUIRES_PROTO_TREE, NULL,
  1197. iostat_packet, i?NULL:iostat_draw);
  1198. if(error_string){
  1199. g_free(io->items);
  1200. g_free(io);
  1201. fprintf(stderr, "\ntshark: Couldn't register io,stat tap: %s\n",
  1202. error_string->str);
  1203. g_string_free(error_string, TRUE);
  1204. exit(1);
  1205. }
  1206. }
  1207. static void
  1208. iostat_init(const char *opt_arg, void* userdata _U_)
  1209. {
  1210. gdouble interval_float;
  1211. guint32 idx=0;
  1212. int i;
  1213. io_stat_t *io;
  1214. const gchar *filters, *str, *pos;
  1215. if ((*(opt_arg+(strlen(opt_arg)-1)) == ',') ||
  1216. (sscanf(opt_arg, "io,stat,%lf%n", &interval_float, (int *)&idx) != 1) ||
  1217. (idx < 8)) {
  1218. fprintf(stderr, "\ntshark: invalid \"-z io,stat,<interval>[,<filter>][,<filter>]...\" argument\n");
  1219. exit(1);
  1220. }
  1221. filters=opt_arg+idx;
  1222. if (*filters) {
  1223. if (*filters != ',') {
  1224. /* For locale's that use ',' instead of '.', the comma might
  1225. * have been consumed during the floating point conversion. */
  1226. --filters;
  1227. if (*filters != ',') {
  1228. fprintf(stderr, "\ntshark: invalid \"-z io,stat,<interval>[,<filter>][,<filter>]...\" argument\n");
  1229. exit(1);
  1230. }
  1231. }
  1232. } else
  1233. filters=NULL;
  1234. switch (timestamp_get_type()) {
  1235. case TS_DELTA:
  1236. case TS_DELTA_DIS:
  1237. case TS_EPOCH:
  1238. case TS_UTC:
  1239. case TS_UTC_WITH_DATE:
  1240. fprintf(stderr, "\ntshark: invalid -t operand. io,stat only supports -t <r|a|ad>\n");
  1241. exit(1);
  1242. default:
  1243. break;
  1244. }
  1245. io = (io_stat_t *) g_malloc(sizeof(io_stat_t));
  1246. /* If interval is 0, calculate statistics over the whole file by setting the interval to
  1247. * G_MAXINT32 */
  1248. if (interval_float==0) {
  1249. io->interval = G_MAXINT32;
  1250. io->invl_prec = 0;
  1251. } else {
  1252. /* Set interval to the number of us rounded to the nearest integer */
  1253. io->interval = (guint64)(interval_float * 1000000.0 + 0.5);
  1254. /*
  1255. * Determine what i…

Large files files are truncated, but you can click here to view the full file