PageRenderTime 32ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/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
  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 interval precision the user has specified */
  1256. io->invl_prec = 6;
  1257. for (i=10; i<10000000; i*=10) {
  1258. if (io->interval%i > 0)
  1259. break;
  1260. io->invl_prec--;
  1261. }
  1262. if (io->invl_prec==0) {
  1263. /* The precision is zero but if the user specified one of more zeros after the decimal point,
  1264. they want that many decimal places shown in the table for all time intervals except
  1265. response time values such as smb.time which always have 6 decimal places of precision.
  1266. This feature is useful in cases where for example the duration is 9.1, you specify an
  1267. interval of 1 and the last interval becomes "9 <> 9". If the interval is instead set to
  1268. 1.1, the last interval becomes
  1269. last interval is rounded up to value that is greater than the duration. */
  1270. const gchar *invl_start = opt_arg+8;
  1271. gchar *intv_end;
  1272. int invl_len;
  1273. intv_end = g_strstr_len(invl_start, -1, ",");
  1274. invl_len = (int)(intv_end - invl_start);
  1275. invl_start = g_strstr_len(invl_start, invl_len, ".");
  1276. if (invl_start != NULL) {
  1277. invl_len = (int)(intv_end - invl_start - 1);
  1278. if (invl_len)
  1279. io->invl_prec = MIN(invl_len, 6);
  1280. }
  1281. }
  1282. }
  1283. if (io->interval < 1){
  1284. fprintf(stderr,
  1285. "\ntshark: \"-z\" interval must be >=0.000001 seconds or \"0\" for the entire capture duration.\n");
  1286. exit(10);
  1287. }
  1288. /* Find how many ',' separated filters we have */
  1289. io->num_cols = 1;
  1290. io->start_time=0;
  1291. if (filters && (*filters != '\0')) {
  1292. /* Eliminate the first comma. */
  1293. filters++;
  1294. str = filters;
  1295. while((str = strchr(str, ','))) {
  1296. io->num_cols++;
  1297. str++;
  1298. }
  1299. }
  1300. io->items = (io_stat_item_t *) g_malloc(sizeof(io_stat_item_t) * io->num_cols);
  1301. io->filters = (const char **)g_malloc(sizeof(char *) * io->num_cols);
  1302. io->max_vals = (guint64 *) g_malloc(sizeof(guint64) * io->num_cols);
  1303. io->max_frame = (guint32 *) g_malloc(sizeof(guint32) * io->num_cols);
  1304. for (i=0; i<io->num_cols; i++) {
  1305. io->max_vals[i] = 0;
  1306. io->max_frame[i] = 0;
  1307. }
  1308. /* Register a tap listener for each filter */
  1309. if((!filters) || (filters[0]==0)) {
  1310. register_io_tap(io, 0, NULL);
  1311. } else {
  1312. gchar *filter;
  1313. i = 0;
  1314. str = filters;
  1315. do {
  1316. pos = (gchar*) strchr(str, ',');
  1317. if(pos==str){
  1318. register_io_tap(io, i, NULL);
  1319. } else if (pos==NULL) {
  1320. str = (const char*) g_strstrip((gchar*)str);
  1321. filter = g_strdup((gchar*) str);
  1322. if (*filter)
  1323. register_io_tap(io, i, filter);
  1324. else
  1325. register_io_tap(io, i, NULL);
  1326. } else {
  1327. filter = (gchar *)g_malloc((pos-str)+1);
  1328. g_strlcpy( filter, str, (gsize) ((pos-str)+1));
  1329. filter = g_strstrip(filter);
  1330. register_io_tap(io, i, (char *) filter);
  1331. }
  1332. str = pos+1;
  1333. i++;
  1334. } while(pos);
  1335. }
  1336. }
  1337. void
  1338. register_tap_listener_iostat(void)
  1339. {
  1340. register_stat_cmd_arg("io,stat,", iostat_init, NULL);
  1341. }
  1342. /*
  1343. * Editor modelines - http://www.wireshark.org/tools/modelines.html
  1344. *
  1345. * Local variables:
  1346. * c-basic-offset: 4
  1347. * tab-width: 4
  1348. * indent-tabs-mode: nil
  1349. * End:
  1350. *
  1351. * vi: set shiftwidth=4 tabstop=4 expandtab:
  1352. * :indentSize=4:tabSize=4:noTabs=true:
  1353. */