Bug Summary

File:ui/cli/tap-iostat.c
Warning:line 1724, column 23
Potential leak of memory pointed to by 'filter'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name tap-iostat.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-truncation -Wno-format-nonliteral -Wno-pointer-sign -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2025-10-21-100328-3623-1 -x c /builds/wireshark/wireshark/ui/cli/tap-iostat.c
1/* tap-iostat.c
2 * iostat 2002 Ronnie Sahlberg
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <[email protected]>
6 * Copyright 1998 Gerald Combs
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11#include "config.h"
12
13#include <stdlib.h>
14#include <string.h>
15#include <locale.h>
16
17#include <epan/epan_dissect.h>
18#include <epan/tap.h>
19#include <epan/stat_tap_ui.h>
20#include "globals.h"
21#include <wsutil/ws_assert.h>
22#include <wsutil/time_util.h>
23#include <wsutil/to_str.h>
24#include <wsutil/cmdarg_err.h>
25
26#define CALC_TYPE_FRAMES0 0
27#define CALC_TYPE_BYTES1 1
28#define CALC_TYPE_FRAMES_AND_BYTES2 2
29#define CALC_TYPE_COUNT3 3
30#define CALC_TYPE_SUM4 4
31#define CALC_TYPE_MIN5 5
32#define CALC_TYPE_MAX6 6
33#define CALC_TYPE_AVG7 7
34#define CALC_TYPE_LOAD8 8
35
36void register_tap_listener_iostat(void);
37
38typedef struct {
39 const char *func_name;
40 int calc_type;
41} calc_type_ent_t;
42
43static calc_type_ent_t calc_type_table[] = {
44 { "FRAMES", CALC_TYPE_FRAMES0 },
45 { "BYTES", CALC_TYPE_BYTES1 },
46 { "FRAMES BYTES", CALC_TYPE_FRAMES_AND_BYTES2 },
47 { "COUNT", CALC_TYPE_COUNT3 },
48 { "SUM", CALC_TYPE_SUM4 },
49 { "MIN", CALC_TYPE_MIN5 },
50 { "MAX", CALC_TYPE_MAX6 },
51 { "AVG", CALC_TYPE_AVG7 },
52 { "LOAD", CALC_TYPE_LOAD8 },
53 { NULL((void*)0), 0 }
54};
55
56typedef struct _io_stat_t {
57 uint64_t interval; /* The user-specified time interval (us) */
58 unsigned invl_prec; /* Decimal precision of the time interval (1=10s, 2=100s etc) */
59 unsigned int num_cols; /* The number of columns of stats in the table */
60 struct _io_stat_item_t *items; /* Each item is a single cell in the table */
61 nstime_t start_time; /* Time of first frame matching the filter */
62 uint64_t last_relative_time;
63 /* The following are all per-column fixed information arrays */
64 const char **filters; /* 'io,stat' cmd strings (e.g., "AVG(smb.time)smb.time") */
65 uint64_t *max_vals; /* The max value sans the decimal or nsecs portion in each stat column */
66 uint32_t *max_frame; /* The max frame number displayed in each stat column */
67 int *hf_indexes;
68 int *calc_type; /* The statistic type */
69} io_stat_t;
70
71typedef struct _io_stat_item_t {
72 io_stat_t *parent;
73 struct _io_stat_item_t *next;
74 struct _io_stat_item_t *prev;
75 uint64_t start_time; /* Time since start of capture (us)*/
76 int colnum; /* Column number of this stat (0 to n) */
77 uint32_t frames;
78 uint32_t num; /* The sample size of a given statistic (only needed for AVG) */
79 union { /* The accumulated data for the calculation of that statistic */
80 uint64_t counter;
81 float float_counter;
82 double double_counter;
83 };
84} io_stat_item_t;
85
86static char *io_decimal_point;
87
88#define NANOSECS_PER_SEC1000000000UL UINT64_C(1000000000)1000000000UL
89
90/*
91 * Reset an io_stat_item_t that's presumed to be one of io->items[].
92 * Set its stats to 0 and remove any other items in its linked list.
93 */
94static void
95iostat_item_reset(io_stat_item_t *mit)
96{
97 io_stat_item_t *p, *cur;
98
99 mit->start_time = 0;
100 mit->frames = 0;
101 mit->num = 0;
102 mit->counter = 0;
103
104 /* Free up the linked list in both directions. Reset mit->prev
105 * to point back at mit to match the initialization in register_io_tap().
106 * The list appears to be circular (XXX: is this intentional?)
107 * so it's important to clear the transitive pointer back to the item
108 * being freed, even if we'd think that next item is about to be freed anyway.
109 */
110 cur = mit->prev;
111 mit->prev = mit;
112 while (cur != NULL((void*)0) && cur != mit && cur != cur->prev) {
113 p = cur->prev;
114 p->next = NULL((void*)0);
115 g_free(cur);
116 cur = p;
117 }
118 cur = mit->next;
119 mit->next = NULL((void*)0);
120 while (cur != NULL((void*)0) && cur != mit && cur != cur->next) {
121 p = cur->next;
122 p->prev = NULL((void*)0);
123 g_free(cur);
124 cur = p;
125 }
126}
127
128/*
129 * Free an io_stat_t and all the memory it allocated.
130 * Assumes that the pointers in an incompletely created io_stat_t are null
131 * if they haven't been allocated yet.
132 */
133static void
134iostat_io_free(io_stat_t *io)
135{
136 for (unsigned int i = 0; i < io->num_cols; i++) {
137 g_free((char*)io->filters[i]);
138 iostat_item_reset(&io->items[i]);
139 }
140 g_free(io->items);
141 g_free((gpointer)io->filters);
142 g_free(io->max_vals);
143 g_free(io->max_frame);
144 g_free(io->hf_indexes);
145 g_free(io->calc_type);
146 g_free(io);
147}
148
149/* Tap function: collect statistics of interest from the current packet. */
150static tap_packet_status
151iostat_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U___attribute__((unused)), tap_flags_t flags _U___attribute__((unused)))
152{
153 io_stat_t *parent;
154 io_stat_item_t *mit;
155 io_stat_item_t *it;
156 uint64_t relative_time, rt;
157 const nstime_t *new_time;
158 GPtrArray *gp;
159 unsigned i;
160 int ftype;
161
162 mit = (io_stat_item_t *) arg;
163 parent = mit->parent;
164
165 /* If this frame's relative time is negative, set its relative time to last_relative_time
166 rather than disincluding it from the calculations. */
167 if ((pinfo->rel_ts.secs >= 0) && (pinfo->rel_ts.nsecs >= 0)) {
168 relative_time = ((uint64_t)pinfo->rel_ts.secs * UINT64_C(1000000)1000000UL) +
169 ((uint64_t)((pinfo->rel_ts.nsecs+500)/1000));
170 parent->last_relative_time = relative_time;
171 } else {
172 relative_time = parent->last_relative_time;
173 }
174
175 if (nstime_is_unset(&mit->parent->start_time)) {
176 nstime_delta(&mit->parent->start_time, &pinfo->abs_ts, &pinfo->rel_ts);
177 }
178
179 /* The prev item is always the last interval in which we saw packets. */
180 it = mit->prev;
181
182 /* If we have moved into a new interval (row), create a new io_stat_item_t struct for every interval
183 * between the last struct and this one. If an item was not found in a previous interval, an empty
184 * struct will be created for it. */
185 rt = relative_time;
186 while (rt >= it->start_time + parent->interval) {
187 it->next = g_new(io_stat_item_t, 1)((io_stat_item_t *) g_malloc_n ((1), sizeof (io_stat_item_t))
)
;
188 it->next->prev = it;
189 it->next->next = NULL((void*)0);
190 it = it->next;
191 mit->prev = it;
192
193 it->start_time = it->prev->start_time + parent->interval;
194 it->frames = 0;
195 it->counter = 0; /* 64-bit, type-punning with double is fine */
196 it->num = 0;
197 it->colnum = it->prev->colnum;
198 }
199
200 /* Store info in the current structure */
201 it->frames++;
202
203 switch (parent->calc_type[it->colnum]) {
204 case CALC_TYPE_FRAMES0:
205 case CALC_TYPE_BYTES1:
206 case CALC_TYPE_FRAMES_AND_BYTES2:
207 it->counter += pinfo->fd->pkt_len;
208 break;
209 case CALC_TYPE_COUNT3:
210 gp = proto_get_finfo_ptr_array(edt->tree, parent->hf_indexes[it->colnum]);
211 if (gp) {
212 it->counter += gp->len;
213 }
214 break;
215 case CALC_TYPE_SUM4:
216 gp = proto_get_finfo_ptr_array(edt->tree, parent->hf_indexes[it->colnum]);
217 if (gp) {
218 uint64_t val;
219
220 for (i=0; i<gp->len; i++) {
221 switch (proto_registrar_get_ftype(parent->hf_indexes[it->colnum])) {
222 case FT_UINT8:
223 case FT_UINT16:
224 case FT_UINT24:
225 case FT_UINT32:
226 it->counter += fvalue_get_uinteger(((field_info *)gp->pdata[i])->value);
227 break;
228 case FT_UINT40:
229 case FT_UINT48:
230 case FT_UINT56:
231 case FT_UINT64:
232 it->counter += fvalue_get_uinteger64(((field_info *)gp->pdata[i])->value);
233 break;
234 case FT_INT8:
235 case FT_INT16:
236 case FT_INT24:
237 case FT_INT32:
238 it->counter += fvalue_get_sinteger(((field_info *)gp->pdata[i])->value);
239 break;
240 case FT_INT40:
241 case FT_INT48:
242 case FT_INT56:
243 case FT_INT64:
244 it->counter += (int64_t)fvalue_get_sinteger64(((field_info *)gp->pdata[i])->value);
245 break;
246 case FT_FLOAT:
247 it->float_counter +=
248 (float)fvalue_get_floating(((field_info *)gp->pdata[i])->value);
249 break;
250 case FT_DOUBLE:
251 it->double_counter += fvalue_get_floating(((field_info *)gp->pdata[i])->value);
252 break;
253 case FT_RELATIVE_TIME:
254 new_time = fvalue_get_time(((field_info *)gp->pdata[i])->value);
255 val = ((uint64_t)new_time->secs * NANOSECS_PER_SEC1000000000UL) + (uint64_t)new_time->nsecs;
256 it->counter += val;
257 break;
258 default:
259 /*
260 * "Can't happen"; see the checks
261 * in register_io_tap().
262 */
263 ws_assert_not_reached()ws_log_fatal_full("", LOG_LEVEL_ERROR, "ui/cli/tap-iostat.c",
263, __func__, "assertion \"not reached\" failed")
;
264 break;
265 }
266 }
267 }
268 break;
269 case CALC_TYPE_MIN5:
270 gp = proto_get_finfo_ptr_array(edt->tree, parent->hf_indexes[it->colnum]);
271 if (gp) {
272 uint64_t val;
273 float float_val;
274 double double_val;
275
276 ftype = proto_registrar_get_ftype(parent->hf_indexes[it->colnum]);
277 for (i=0; i<gp->len; i++) {
278 switch (ftype) {
279 case FT_UINT8:
280 case FT_UINT16:
281 case FT_UINT24:
282 case FT_UINT32:
283 val = fvalue_get_uinteger(((field_info *)gp->pdata[i])->value);
284 if ((it->frames == 1 && i == 0) || (val < it->counter)) {
285 it->counter = val;
286 }
287 break;
288 case FT_UINT40:
289 case FT_UINT48:
290 case FT_UINT56:
291 case FT_UINT64:
292 val = fvalue_get_uinteger64(((field_info *)gp->pdata[i])->value);
293 if ((it->frames == 1 && i == 0) || (val < it->counter)) {
294 it->counter = val;
295 }
296 break;
297 case FT_INT8:
298 case FT_INT16:
299 case FT_INT24:
300 case FT_INT32:
301 val = fvalue_get_sinteger(((field_info *)gp->pdata[i])->value);
302 if ((it->frames == 1 && i == 0) || ((int32_t)val < (int32_t)it->counter)) {
303 it->counter = val;
304 }
305 break;
306 case FT_INT40:
307 case FT_INT48:
308 case FT_INT56:
309 case FT_INT64:
310 val = fvalue_get_sinteger64(((field_info *)gp->pdata[i])->value);
311 if ((it->frames == 1 && i == 0) || ((int64_t)val < (int64_t)it->counter)) {
312 it->counter = val;
313 }
314 break;
315 case FT_FLOAT:
316 float_val = (float)fvalue_get_floating(((field_info *)gp->pdata[i])->value);
317 if ((it->frames == 1 && i == 0) || (float_val < it->float_counter)) {
318 it->float_counter = float_val;
319 }
320 break;
321 case FT_DOUBLE:
322 double_val = fvalue_get_floating(((field_info *)gp->pdata[i])->value);
323 if ((it->frames == 1 && i == 0) || (double_val < it->double_counter)) {
324 it->double_counter = double_val;
325 }
326 break;
327 case FT_RELATIVE_TIME:
328 new_time = fvalue_get_time(((field_info *)gp->pdata[i])->value);
329 val = ((uint64_t)new_time->secs * NANOSECS_PER_SEC1000000000UL) + (uint64_t)new_time->nsecs;
330 if ((it->frames == 1 && i == 0) || (val < it->counter)) {
331 it->counter = val;
332 }
333 break;
334 default:
335 /*
336 * "Can't happen"; see the checks
337 * in register_io_tap().
338 */
339 ws_assert_not_reached()ws_log_fatal_full("", LOG_LEVEL_ERROR, "ui/cli/tap-iostat.c",
339, __func__, "assertion \"not reached\" failed")
;
340 break;
341 }
342 }
343 }
344 break;
345 case CALC_TYPE_MAX6:
346 gp = proto_get_finfo_ptr_array(edt->tree, parent->hf_indexes[it->colnum]);
347 if (gp) {
348 uint64_t val;
349 float float_val;
350 double double_val;
351
352 ftype = proto_registrar_get_ftype(parent->hf_indexes[it->colnum]);
353 for (i=0; i<gp->len; i++) {
354 switch (ftype) {
355 case FT_UINT8:
356 case FT_UINT16:
357 case FT_UINT24:
358 case FT_UINT32:
359 val = fvalue_get_uinteger(((field_info *)gp->pdata[i])->value);
360 if (val > it->counter)
361 it->counter = val;
362 break;
363 case FT_UINT40:
364 case FT_UINT48:
365 case FT_UINT56:
366 case FT_UINT64:
367 val = fvalue_get_uinteger64(((field_info *)gp->pdata[i])->value);
368 if (val > it->counter)
369 it->counter = val;
370 break;
371 case FT_INT8:
372 case FT_INT16:
373 case FT_INT24:
374 case FT_INT32:
375 val = fvalue_get_sinteger(((field_info *)gp->pdata[i])->value);
376 if ((int32_t)val > (int32_t)it->counter)
377 it->counter = val;
378 break;
379 case FT_INT40:
380 case FT_INT48:
381 case FT_INT56:
382 case FT_INT64:
383 val = fvalue_get_sinteger64(((field_info *)gp->pdata[i])->value);
384 if ((int64_t)val > (int64_t)it->counter)
385 it->counter = val;
386 break;
387 case FT_FLOAT:
388 float_val = (float)fvalue_get_floating(((field_info *)gp->pdata[i])->value);
389 if (float_val > it->float_counter)
390 it->float_counter = float_val;
391 break;
392 case FT_DOUBLE:
393 double_val = fvalue_get_floating(((field_info *)gp->pdata[i])->value);
394 if (double_val > it->double_counter)
395 it->double_counter = double_val;
396 break;
397 case FT_RELATIVE_TIME:
398 new_time = fvalue_get_time(((field_info *)gp->pdata[i])->value);
399 val = ((uint64_t)new_time->secs * NANOSECS_PER_SEC1000000000UL) + (uint64_t)new_time->nsecs;
400 if (val > it->counter)
401 it->counter = val;
402 break;
403 default:
404 /*
405 * "Can't happen"; see the checks
406 * in register_io_tap().
407 */
408 ws_assert_not_reached()ws_log_fatal_full("", LOG_LEVEL_ERROR, "ui/cli/tap-iostat.c",
408, __func__, "assertion \"not reached\" failed")
;
409 break;
410 }
411 }
412 }
413 break;
414 case CALC_TYPE_AVG7:
415 gp = proto_get_finfo_ptr_array(edt->tree, parent->hf_indexes[it->colnum]);
416 if (gp) {
417 uint64_t val;
418
419 ftype = proto_registrar_get_ftype(parent->hf_indexes[it->colnum]);
420 for (i=0; i<gp->len; i++) {
421 it->num++;
422 switch (ftype) {
423 case FT_UINT8:
424 case FT_UINT16:
425 case FT_UINT24:
426 case FT_UINT32:
427 val = fvalue_get_uinteger(((field_info *)gp->pdata[i])->value);
428 it->counter += val;
429 break;
430 case FT_UINT40:
431 case FT_UINT48:
432 case FT_UINT56:
433 case FT_UINT64:
434 val = fvalue_get_uinteger64(((field_info *)gp->pdata[i])->value);
435 it->counter += val;
436 break;
437 case FT_INT8:
438 case FT_INT16:
439 case FT_INT24:
440 case FT_INT32:
441 val = fvalue_get_sinteger(((field_info *)gp->pdata[i])->value);
442 it->counter += val;
443 break;
444 case FT_INT40:
445 case FT_INT48:
446 case FT_INT56:
447 case FT_INT64:
448 val = fvalue_get_sinteger64(((field_info *)gp->pdata[i])->value);
449 it->counter += val;
450 break;
451 case FT_FLOAT:
452 it->float_counter += (float)fvalue_get_floating(((field_info *)gp->pdata[i])->value);
453 break;
454 case FT_DOUBLE:
455 it->double_counter += fvalue_get_floating(((field_info *)gp->pdata[i])->value);
456 break;
457 case FT_RELATIVE_TIME:
458 new_time = fvalue_get_time(((field_info *)gp->pdata[i])->value);
459 val = ((uint64_t)new_time->secs * NANOSECS_PER_SEC1000000000UL) + (uint64_t)new_time->nsecs;
460 it->counter += val;
461 break;
462 default:
463 /*
464 * "Can't happen"; see the checks
465 * in register_io_tap().
466 */
467 ws_assert_not_reached()ws_log_fatal_full("", LOG_LEVEL_ERROR, "ui/cli/tap-iostat.c",
467, __func__, "assertion \"not reached\" failed")
;
468 break;
469 }
470 }
471 }
472 break;
473 case CALC_TYPE_LOAD8:
474 gp = proto_get_finfo_ptr_array(edt->tree, parent->hf_indexes[it->colnum]);
475 if (gp) {
476 ftype = proto_registrar_get_ftype(parent->hf_indexes[it->colnum]);
477 if (ftype != FT_RELATIVE_TIME) {
478 cmdarg_err("\ntshark: LOAD() is only supported for relative-time fields such as smb.time\n");
479 return TAP_PACKET_FAILED;
480 }
481 for (i=0; i<gp->len; i++) {
482 uint64_t val;
483 int tival;
484 io_stat_item_t *pit;
485
486 new_time = fvalue_get_time(((field_info *)gp->pdata[i])->value);
487 val = ((uint64_t)new_time->secs*UINT64_C(1000000)1000000UL) + (uint64_t)(new_time->nsecs/1000);
488 tival = (int)(val % parent->interval);
489 it->counter += tival;
490 val -= tival;
491 pit = it->prev;
492 while (val > 0) {
493 if (val < (uint64_t)parent->interval) {
494 pit->counter += val;
495 break;
496 }
497 pit->counter += parent->interval;
498 val -= parent->interval;
499 pit = pit->prev;
500 }
501 }
502 }
503 break;
504 }
505 /* Store the highest value for this item in order to determine the width of each stat column.
506 * For real numbers we only need to know its magnitude (the value to the left of the decimal point
507 * so round it up before storing it as an integer in max_vals. For AVG of RELATIVE_TIME fields,
508 * calc the average, round it to the next second and store the seconds. For all other calc types
509 * of RELATIVE_TIME fields, store the counters without modification.
510 * fields. */
511 switch (parent->calc_type[it->colnum]) {
512 case CALC_TYPE_FRAMES0:
513 case CALC_TYPE_FRAMES_AND_BYTES2:
514 parent->max_frame[it->colnum] =
515 MAX(parent->max_frame[it->colnum], it->frames)(((parent->max_frame[it->colnum]) > (it->frames))
? (parent->max_frame[it->colnum]) : (it->frames))
;
516 if (parent->calc_type[it->colnum] == CALC_TYPE_FRAMES_AND_BYTES2)
517 parent->max_vals[it->colnum] =
518 MAX(parent->max_vals[it->colnum], it->counter)(((parent->max_vals[it->colnum]) > (it->counter))
? (parent->max_vals[it->colnum]) : (it->counter))
;
519 break;
520 case CALC_TYPE_BYTES1:
521 case CALC_TYPE_COUNT3:
522 case CALC_TYPE_LOAD8:
523 parent->max_vals[it->colnum] = MAX(parent->max_vals[it->colnum], it->counter)(((parent->max_vals[it->colnum]) > (it->counter))
? (parent->max_vals[it->colnum]) : (it->counter))
;
524 break;
525 case CALC_TYPE_SUM4:
526 case CALC_TYPE_MIN5:
527 case CALC_TYPE_MAX6:
528 ftype = proto_registrar_get_ftype(parent->hf_indexes[it->colnum]);
529 switch (ftype) {
530 case FT_FLOAT:
531 parent->max_vals[it->colnum] =
532 MAX(parent->max_vals[it->colnum], (uint64_t)(it->float_counter+0.5))(((parent->max_vals[it->colnum]) > ((uint64_t)(it->
float_counter+0.5))) ? (parent->max_vals[it->colnum]) :
((uint64_t)(it->float_counter+0.5)))
;
533 break;
534 case FT_DOUBLE:
535 parent->max_vals[it->colnum] =
536 MAX(parent->max_vals[it->colnum], (uint64_t)(it->double_counter+0.5))(((parent->max_vals[it->colnum]) > ((uint64_t)(it->
double_counter+0.5))) ? (parent->max_vals[it->colnum]) :
((uint64_t)(it->double_counter+0.5)))
;
537 break;
538 case FT_RELATIVE_TIME:
539 parent->max_vals[it->colnum] =
540 MAX(parent->max_vals[it->colnum], it->counter)(((parent->max_vals[it->colnum]) > (it->counter))
? (parent->max_vals[it->colnum]) : (it->counter))
;
541 break;
542 default:
543 /* UINT16-64 and INT8-64 */
544 parent->max_vals[it->colnum] =
545 MAX(parent->max_vals[it->colnum], it->counter)(((parent->max_vals[it->colnum]) > (it->counter))
? (parent->max_vals[it->colnum]) : (it->counter))
;
546 break;
547 }
548 break;
549 case CALC_TYPE_AVG7:
550 if (it->num == 0) /* avoid division by zero */
551 break;
552 ftype = proto_registrar_get_ftype(parent->hf_indexes[it->colnum]);
553 switch (ftype) {
554 case FT_FLOAT:
555 parent->max_vals[it->colnum] =
556 MAX(parent->max_vals[it->colnum], (uint64_t)it->float_counter/it->num)(((parent->max_vals[it->colnum]) > ((uint64_t)it->
float_counter/it->num)) ? (parent->max_vals[it->colnum
]) : ((uint64_t)it->float_counter/it->num))
;
557 break;
558 case FT_DOUBLE:
559 parent->max_vals[it->colnum] =
560 MAX(parent->max_vals[it->colnum], (uint64_t)it->double_counter/it->num)(((parent->max_vals[it->colnum]) > ((uint64_t)it->
double_counter/it->num)) ? (parent->max_vals[it->colnum
]) : ((uint64_t)it->double_counter/it->num))
;
561 break;
562 case FT_RELATIVE_TIME:
563 parent->max_vals[it->colnum] =
564 MAX(parent->max_vals[it->colnum], ((it->counter/(uint64_t)it->num) + UINT64_C(500000000)) / NANOSECS_PER_SEC)(((parent->max_vals[it->colnum]) > (((it->counter
/(uint64_t)it->num) + 500000000UL) / 1000000000UL)) ? (parent
->max_vals[it->colnum]) : (((it->counter/(uint64_t)it
->num) + 500000000UL) / 1000000000UL))
;
565 break;
566 default:
567 /* UINT16-64 and INT8-64 */
568 parent->max_vals[it->colnum] =
569 MAX(parent->max_vals[it->colnum], it->counter/it->num)(((parent->max_vals[it->colnum]) > (it->counter/it
->num)) ? (parent->max_vals[it->colnum]) : (it->counter
/it->num))
;
570 break;
571 }
572 }
573 return TAP_PACKET_REDRAW;
574}
575
576static unsigned int
577magnitude (uint64_t val, unsigned int max_w)
578{
579 unsigned int i, mag = 0;
580
581 for (i=0; i<max_w; i++) {
582 mag++;
583 if ((val /= 10) == 0)
584 break;
585 }
586 return(mag);
587}
588
589/*
590* Print the calc_type_table[] function label centered in the column header.
591*/
592static void
593printcenter (const char *label, int lenval, int numpad)
594{
595 int lenlab = (int) strlen(label), len;
596 const char spaces[] = " ", *spaces_ptr;
597
598 len = (int) (strlen(spaces)) - (((lenval-lenlab) / 2) + numpad);
599 if (len > 0 && len < 6) {
600 spaces_ptr = &spaces[len];
601 if ((lenval-lenlab)%2 == 0) {
602 printf("%s%s%s|", spaces_ptr, label, spaces_ptr);
603 } else {
604 printf("%s%s%s|", spaces_ptr-1, label, spaces_ptr);
605 }
606 } else if (len > 0 && len <= 15) {
607 printf("%s|", label);
608 }
609}
610
611typedef struct {
612 int fr; /* Width of this FRAMES column sans padding and border chars */
613 int val; /* Width of this non-FRAMES column sans padding and border chars */
614} column_width;
615
616static void
617fill_abs_time(const nstime_t* the_time, char *time_buf, char *decimal_point, unsigned invl_prec, bool_Bool local)
618{
619 struct tm tm, *tmp;
620 char *ptr;
621 size_t remaining = NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z");
622 int num_bytes;
623
624 if (local) {
625 tmp = ws_localtime_r(&the_time->secs, &tm);
626 } else {
627 tmp = ws_gmtime_r(&the_time->secs, &tm);
628 }
629
630 if (tmp == NULL((void*)0)) {
631 snprintf(time_buf, remaining, "XX:XX:XX");
632 return;
633 }
634
635 ptr = time_buf;
636 num_bytes = snprintf(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"),
637 "%02d:%02d:%02d",
638 tmp->tm_hour,
639 tmp->tm_min,
640 tmp->tm_sec);
641 if (num_bytes < 0) {
642 // snprintf failed
643 snprintf(time_buf, remaining, "XX:XX:XX");
644 return;
645 }
646 ptr += num_bytes;
647 remaining -= num_bytes;
648 if (invl_prec != 0) {
649 num_bytes = format_fractional_part_nsecs(ptr, remaining,
650 (uint32_t)the_time->nsecs, decimal_point, invl_prec);
651 ptr += num_bytes;
652 remaining -= num_bytes;
653 }
654
655 if (!local) {
656 if (remaining == 1 && num_bytes > 0) {
657 /*
658 * If we copied a fractional part but there's only room
659 * for the terminating '\0', replace the last digit of
660 * the fractional part with the "Z". (Remaining is at
661 * least 1, otherwise we would have returned above.)
662 */
663 ptr--;
664 remaining++;
665 }
666 (void)g_strlcpy(ptr, "Z", remaining);
667 }
668 return;
669}
670
671static void
672fill_abs_ydoy_time(const nstime_t* the_time, char *time_buf, char *decimal_point, unsigned invl_prec, bool_Bool local)
673{
674 struct tm tm, *tmp;
675 char *ptr;
676 size_t remaining = NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z");
677 int num_bytes;
678
679 if (local) {
680 tmp = ws_localtime_r(&the_time->secs, &tm);
681 } else {
682 tmp = ws_gmtime_r(&the_time->secs, &tm);
683 }
684
685 if (tmp == NULL((void*)0)) {
686 snprintf(time_buf, remaining, "XXXX/XXX XX:XX:XX");
687 return;
688 }
689
690 ptr = time_buf;
691 num_bytes = snprintf(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"),
692 "%04d/%03d %02d:%02d:%02d",
693 tmp->tm_year + 1900,
694 tmp->tm_yday + 1,
695 tmp->tm_hour,
696 tmp->tm_min,
697 tmp->tm_sec);
698 if (num_bytes < 0) {
699 // snprintf failed
700 snprintf(time_buf, remaining, "XXXX/XXX XX:XX:XX");
701 return;
702 }
703 ptr += num_bytes;
704 remaining -= num_bytes;
705 if (invl_prec != 0) {
706 num_bytes = format_fractional_part_nsecs(ptr, remaining,
707 (uint32_t)the_time->nsecs, decimal_point, invl_prec);
708 ptr += num_bytes;
709 remaining -= num_bytes;
710 }
711
712 if (!local) {
713 if (remaining == 1 && num_bytes > 0) {
714 /*
715 * If we copied a fractional part but there's only room
716 * for the terminating '\0', replace the last digit of
717 * the fractional part with the "Z". (Remaining is at
718 * least 1, otherwise we would have returned above.)
719 */
720 ptr--;
721 remaining++;
722 }
723 (void)g_strlcpy(ptr, "Z", remaining);
724 }
725 return;
726}
727
728static void
729fill_start_time(const io_stat_t *iot, const nstime_t *rel_time, ws_tsprec_e invl_prec, char *time_buf)
730{
731 nstime_t abs_time;
732 nstime_sum(&abs_time, rel_time, &iot->start_time);
733
734 switch (timestamp_get_type()) {
735 case TS_ABSOLUTE:
736 fill_abs_time(&abs_time, time_buf, io_decimal_point, invl_prec, true1);
737 break;
738
739 case TS_ABSOLUTE_WITH_YMD:
740 format_nstime_as_iso8601(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"), &abs_time,
741 io_decimal_point, true1, invl_prec);
742 break;
743
744 case TS_ABSOLUTE_WITH_YDOY:
745 fill_abs_ydoy_time(&abs_time, time_buf, io_decimal_point, invl_prec, true1);
746 break;
747
748 case TS_UTC:
749 fill_abs_time(&abs_time, time_buf, io_decimal_point, invl_prec, false0);
750 break;
751
752 case TS_UTC_WITH_YMD:
753 format_nstime_as_iso8601(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"), &abs_time,
754 io_decimal_point, false0, invl_prec);
755 break;
756
757 case TS_UTC_WITH_YDOY:
758 fill_abs_ydoy_time(&abs_time, time_buf, io_decimal_point, invl_prec, false0);
759 break;
760
761 case TS_RELATIVE:
762 case TS_RELATIVE_CAP:
763 case TS_NOT_SET:
764 display_signed_time(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"), rel_time, invl_prec);
765 break;
766 case TS_DELTA:
767 case TS_DELTA_DIS:
768 case TS_EPOCH:
769 /* Can't happen - see iostat_init. */
770 ws_assert_not_reached()ws_log_fatal_full("", LOG_LEVEL_ERROR, "ui/cli/tap-iostat.c",
770, __func__, "assertion \"not reached\" failed")
;
771 break;
772 default:
773 break;
774 }
775}
776
777static char*
778iostat_get_item_value(const io_stat_t *iot, io_stat_item_t *item, const char *fmt, unsigned j, uint64_t interval)
779{
780 uint32_t num;
781 unsigned type, ftype;
782
783 type = iot->calc_type[j];
784
785 if (item) {
786 switch (type) {
787 case CALC_TYPE_FRAMES0:
788 return g_strdup_printf(fmt, item->frames);
789 case CALC_TYPE_BYTES1:
790 case CALC_TYPE_COUNT3:
791 return g_strdup_printf(fmt, item->counter);
792 case CALC_TYPE_FRAMES_AND_BYTES2:
793 return g_strdup_printf(fmt, item->frames, item->counter);
794
795 case CALC_TYPE_SUM4:
796 case CALC_TYPE_MIN5:
797 case CALC_TYPE_MAX6:
798 ftype = proto_registrar_get_ftype(iot->hf_indexes[j]);
799 switch (ftype) {
800 case FT_FLOAT:
801 return g_strdup_printf(fmt, item->float_counter);
802 case FT_DOUBLE:
803 return g_strdup_printf(fmt, item->double_counter);
804 case FT_RELATIVE_TIME:
805 item->counter = (item->counter + UINT64_C(500)500UL) / UINT64_C(1000)1000UL;
806 return g_strdup_printf(fmt,
807 (int)(item->counter/UINT64_C(1000000)1000000UL),
808 (int)(item->counter%UINT64_C(1000000)1000000UL));
809 default:
810 return g_strdup_printf(fmt, item->counter);
811 }
812 break;
813
814 case CALC_TYPE_AVG7:
815 num = item->num;
816 if (num == 0)
817 num = 1;
818 ftype = proto_registrar_get_ftype(iot->hf_indexes[j]);
819 switch (ftype) {
820 case FT_FLOAT:
821 return g_strdup_printf(fmt, item->float_counter/num);
822 case FT_DOUBLE:
823 return g_strdup_printf(fmt, item->double_counter/num);
824 case FT_RELATIVE_TIME:
825 item->counter = ((item->counter / (uint64_t)num) + UINT64_C(500)500UL) / UINT64_C(1000)1000UL;
826 return g_strdup_printf(fmt,
827 (int)(item->counter/UINT64_C(1000000)1000000UL),
828 (int)(item->counter%UINT64_C(1000000)1000000UL));
829 default:
830 return g_strdup_printf(fmt, item->counter / (uint64_t)num);
831 }
832 break;
833
834 case CALC_TYPE_LOAD8:
835 ftype = proto_registrar_get_ftype(iot->hf_indexes[j]);
836 switch (ftype) {
837 case FT_RELATIVE_TIME:
838 return g_strdup_printf(fmt,
839 (int) (item->counter/interval),
840 (int)((item->counter%interval)*UINT64_C(1000000)1000000UL / interval));
841 }
842 break;
843 }
844 }
845 return g_strdup_printf(fmt, (uint64_t)0, (uint64_t)0);
846}
847
848/* Calc the total width of each row in the stats table and build the printf format string for each
849* column based on its field type, width, and name length.
850* NOTE: The magnitude of all types including float and double are stored in iot->max_vals which
851* is an *integer*. */
852static unsigned
853iostat_calc_cols_width_and_fmt(io_stat_t *iot, uint64_t interval, column_width* col_w, char**fmts)
854{
855 unsigned tabrow_w, type, ftype, namelen;
856 unsigned fr_mag; /* The magnitude of the max frame number in this column */
857 unsigned val_mag; /* The magnitude of the max value in this column */
858 char *fmt = NULL((void*)0);
859
860 tabrow_w = 0;
861 for (unsigned j=0; j < iot->num_cols; j++) {
862 type = iot->calc_type[j];
863 if (type == CALC_TYPE_FRAMES_AND_BYTES2) {
864 namelen = 5;
865 } else {
866 namelen = (unsigned int)strlen(calc_type_table[type].func_name);
867 }
868 if (type == CALC_TYPE_FRAMES0
869 || type == CALC_TYPE_FRAMES_AND_BYTES2) {
870
871 fr_mag = magnitude(iot->max_frame[j], 15);
872 fr_mag = MAX(6, fr_mag)(((6) > (fr_mag)) ? (6) : (fr_mag));
873 col_w[j].fr = fr_mag;
874 tabrow_w += col_w[j].fr + 3;
875
876 if (type == CALC_TYPE_FRAMES0) {
877 fmt = g_strdup_printf("%%%uu", fr_mag);
878 } else {
879 /* CALC_TYPE_FRAMES_AND_BYTES
880 */
881 val_mag = magnitude(iot->max_vals[j], 15);
882 val_mag = MAX(5, val_mag)(((5) > (val_mag)) ? (5) : (val_mag));
883 col_w[j].val = val_mag;
884 tabrow_w += (col_w[j].val + 3);
885 fmt = g_strdup_printf("%%%uu | %%%u"PRIu64"l" "u", fr_mag, val_mag);
886 }
887 if (fmt)
888 fmts[j] = fmt;
889 continue;
890 }
891 switch (type) {
892 case CALC_TYPE_BYTES1:
893 case CALC_TYPE_COUNT3:
894
895 val_mag = magnitude(iot->max_vals[j], 15);
896 val_mag = MAX(5, val_mag)(((5) > (val_mag)) ? (5) : (val_mag));
897 col_w[j].val = val_mag;
898 fmt = g_strdup_printf("%%%u"PRIu64"l" "u", val_mag);
899 break;
900
901 default:
902 ftype = proto_registrar_get_ftype(iot->hf_indexes[j]);
903 switch (ftype) {
904 case FT_FLOAT:
905 case FT_DOUBLE:
906 val_mag = magnitude(iot->max_vals[j], 15);
907 fmt = g_strdup_printf("%%%u.6f", val_mag);
908 col_w[j].val = val_mag + 7;
909 break;
910 case FT_RELATIVE_TIME:
911 /* Convert FT_RELATIVE_TIME field to seconds
912 * CALC_TYPE_LOAD was already converted in iostat_packet() ) */
913 if (type == CALC_TYPE_LOAD8) {
914 iot->max_vals[j] /= interval;
915 } else if (type != CALC_TYPE_AVG7) {
916 iot->max_vals[j] = (iot->max_vals[j] + UINT64_C(500000000)500000000UL) / NANOSECS_PER_SEC1000000000UL;
917 }
918 val_mag = magnitude(iot->max_vals[j], 15);
919 fmt = g_strdup_printf("%%%uu.%%06u", val_mag);
920 col_w[j].val = val_mag + 7;
921 break;
922
923 default:
924 val_mag = magnitude(iot->max_vals[j], 15);
925 val_mag = MAX(namelen, val_mag)(((namelen) > (val_mag)) ? (namelen) : (val_mag));
926 col_w[j].val = val_mag;
927
928 switch (ftype) {
929 case FT_UINT8:
930 case FT_UINT16:
931 case FT_UINT24:
932 case FT_UINT32:
933 case FT_UINT64:
934 fmt = g_strdup_printf("%%%u"PRIu64"l" "u", val_mag);
935 break;
936 case FT_INT8:
937 case FT_INT16:
938 case FT_INT24:
939 case FT_INT32:
940 case FT_INT64:
941 fmt = g_strdup_printf("%%%u"PRId64"l" "d", val_mag);
942 break;
943 }
944 } /* End of ftype switch */
945 } /* End of calc_type switch */
946 tabrow_w += col_w[j].val + 3;
947 if (fmt)
948 fmts[j] = fmt;
949 } /* End of for loop (columns) */
950
951 return tabrow_w;
952}
953
954static void
955iostat_draw_filters(unsigned borderlen, const io_stat_t *iot)
956{
957 const char *filter;
958 size_t len_filt;
959 GString *filt_str;
960
961 /* Display the list of filters and their column numbers vertically */
962 for (unsigned j=0; j<iot->num_cols; j++) {
963 if (j == 0) {
964 filt_str = g_string_new("| Col ");
965 } else {
966 filt_str = g_string_new("| ");
967 };
968 g_string_append_printf(filt_str, "%2u: ", j + 1);
969 if (!iot->filters[j]) {
970 /* An empty (no filter) comma field was specified */
971 g_string_append(filt_str, "Frames and bytes")(__builtin_constant_p ("Frames and bytes") ? __extension__ ({
const char * const __val = ("Frames and bytes"); g_string_append_len_inline
(filt_str, __val, (__val != ((void*)0)) ? (gssize) strlen ((
(__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(filt_str, "Frames and bytes", (gssize) -1))
;
972 } else {
973 filter = iot->filters[j];
974 len_filt = strlen(filter);
975 /* borderlen has been adjusted to try to accommodate the widest
976 * filter, but only up to a limit (currently 102 bytes), and so
977 * filters wider than that must still wrap. */
978 /* 11 is the length of "| Col XX: " plus the trailing "|" */
979 size_t max_w = borderlen - 11;
980
981 while (len_filt > max_w) {
982 const char *pos;
983 size_t len;
984 unsigned int next_start;
985
986 /* Find the pos of the last space in filter up to max_w. If a
987 * space is found, copy up to that space; otherwise, wrap the
988 * filter at max_w. */
989 pos = g_strrstr_len(filter, max_w, " ");
990 if (pos) {
991 len = (size_t)(pos-filter);
992 /* Skip the space when wrapping. */
993 next_start = (unsigned int) len+1;
994 } else {
995 len = max_w;
996 next_start = (unsigned int)len;
997 }
998 g_string_append_len(filt_str, filter, len)g_string_append_len_inline (filt_str, filter, len);
999 g_string_append_printf(filt_str, "%*s", (int)(borderlen - filt_str->len), "|");
1000
1001 puts(filt_str->str);
1002 g_string_free(filt_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(filt_str), ((!(0)))) : g_string_free_and_steal (filt_str)) :
(g_string_free) ((filt_str), ((!(0)))))
;
1003
1004 filt_str = g_string_new("| ");
1005 filter = &filter[next_start];
1006 len_filt = strlen(filter);
1007 }
1008
1009 g_string_append(filt_str, filter)(__builtin_constant_p (filter) ? __extension__ ({ const char *
const __val = (filter); g_string_append_len_inline (filt_str
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (filt_str
, filter, (gssize) -1))
;
1010 }
1011 g_string_append_printf(filt_str, "%*s", (int)(borderlen - filt_str->len), "|");
1012 puts(filt_str->str);
1013 g_string_free(filt_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(filt_str), ((!(0)))) : g_string_free_and_steal (filt_str)) :
(g_string_free) ((filt_str), ((!(0)))))
;
1014 }
1015}
1016
1017static void
1018iostat_draw_header(unsigned borderlen, const io_stat_t *iot, const nstime_t *duration, const nstime_t *interval, ws_tsprec_e invl_prec)
1019{
1020 unsigned i;
1021 char time_buf[NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z")];
1022
1023 /* Display the top border */
1024 printf("\n");
1025 for (i=0; i<borderlen; i++)
1026 printf("=");
1027
1028 printf("\n|%-*s|\n", borderlen - 2, " IO Statistics");
1029 printf("|%-*s|\n", borderlen - 2, "");
1030
1031 /* For some reason, we print the total duration in microsecond precision
1032 * here if the interval is in seconds precision, and use the interval
1033 * precision otherwise.
1034 */
1035 ws_tsprec_e dur_prec = (invl_prec == WS_TSPREC_SEC) ? WS_TSPREC_USEC : invl_prec;
1036 nstime_t dur_rounded;
1037 nstime_rounded(&dur_rounded, duration, dur_prec);
1038 int dur_mag = magnitude(duration->secs, 5);
1039 int dur_w = dur_mag + (invl_prec == 0 ? 0 : invl_prec+1);
1040
1041 GString *dur_str = g_string_new("| Duration: ");
1042 display_signed_time(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"), &dur_rounded, dur_prec);
1043 g_string_append_printf(dur_str, "%*s secs", dur_w, time_buf);
1044 g_string_append_printf(dur_str, "%*s", (int)(borderlen - dur_str->len), "|");
1045 puts(dur_str->str);
1046 g_string_free(dur_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(dur_str), ((!(0)))) : g_string_free_and_steal (dur_str)) : (
g_string_free) ((dur_str), ((!(0)))))
;
1047
1048 GString *invl_str = g_string_new("| Interval: ");
1049 display_signed_time(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"), interval, invl_prec);
1050 g_string_append_printf(invl_str, "%*s secs", dur_w, time_buf);
1051 g_string_append_printf(invl_str, "%*s", (int)(borderlen - invl_str->len), "|");
1052 puts(invl_str->str);
1053 g_string_free(invl_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(invl_str), ((!(0)))) : g_string_free_and_steal (invl_str)) :
(g_string_free) ((invl_str), ((!(0)))))
;
1054
1055 printf("|%-*s|\n", borderlen - 2, "");
1056
1057 iostat_draw_filters(borderlen, iot);
1058
1059 printf("|-");
1060 for (i=0; i<borderlen-3; i++) {
1061 printf("-");
1062 }
1063 printf("|\n");
1064}
1065
1066static void
1067iostat_draw_header_row(unsigned borderlen, const io_stat_t *iot, const column_width *col_w, unsigned invl_col_w, unsigned tabrow_w)
1068{
1069 unsigned j, type, numpad = 1;
1070 char *filler_s = NULL((void*)0);
1071
1072 /* Display spaces above "Interval (s)" label */
1073 printf("|%*s", invl_col_w - 1, "|");
1074
1075 /* Display column number headers */
1076 for (j=0; j < iot->num_cols; j++) {
1077 int padding;
1078 if (iot->calc_type[j] == CALC_TYPE_FRAMES_AND_BYTES2)
1079 padding = col_w[j].fr + col_w[j].val + 3;
1080 else if (iot->calc_type[j] == CALC_TYPE_FRAMES0)
1081 padding = col_w[j].fr;
1082 else
1083 padding = col_w[j].val;
1084
1085 printf("%-2d%*s|", j+1, padding, "");
1086 }
1087 if (tabrow_w < borderlen) {
1088 filler_s = g_strdup_printf("%*s", borderlen - tabrow_w, "|");
1089 printf("%s", filler_s);
1090 }
1091 printf("\n");
1092
1093 GString *timestamp_str;
1094 switch (timestamp_get_type()) {
1095 case TS_ABSOLUTE:
1096 case TS_UTC:
1097 timestamp_str = g_string_new("| Time ");
1098 break;
1099 case TS_ABSOLUTE_WITH_YMD:
1100 case TS_ABSOLUTE_WITH_YDOY:
1101 case TS_UTC_WITH_YMD:
1102 case TS_UTC_WITH_YDOY:
1103 timestamp_str = g_string_new("| Date and time");
1104 break;
1105 case TS_RELATIVE:
1106 case TS_RELATIVE_CAP:
1107 case TS_NOT_SET:
1108 timestamp_str = g_string_new("| Interval");
1109 break;
1110 default:
1111 timestamp_str = g_string_new(NULL((void*)0));
1112 break;
1113 }
1114
1115 printf("%s%*s", timestamp_str->str, (int)(invl_col_w - timestamp_str->len), "|");
1116 g_string_free(timestamp_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(timestamp_str), ((!(0)))) : g_string_free_and_steal (timestamp_str
)) : (g_string_free) ((timestamp_str), ((!(0)))))
;
1117
1118 /* Display the stat label in each column */
1119 for (j=0; j < iot->num_cols; j++) {
1120 type = iot->calc_type[j];
1121 if (type == CALC_TYPE_FRAMES0) {
1122 printcenter (calc_type_table[type].func_name, col_w[j].fr, numpad);
1123 } else if (type == CALC_TYPE_FRAMES_AND_BYTES2) {
1124 printcenter ("Frames", col_w[j].fr, numpad);
1125 printcenter ("Bytes", col_w[j].val, numpad);
1126 } else {
1127 printcenter (calc_type_table[type].func_name, col_w[j].val, numpad);
1128 }
1129 }
1130 if (filler_s) {
1131 printf("%s", filler_s);
1132 }
1133 printf("\n|-");
1134
1135 for (j=0; j<tabrow_w-3; j++)
1136 printf("-");
1137 printf("|");
1138
1139 if (filler_s) {
1140 printf("%s", filler_s);
1141 g_free(filler_s);
1142 }
1143
1144 printf("\n");
1145}
1146
1147static void
1148iostat_draw(void *arg)
1149{
1150 uint64_t interval, duration, t, real_invl, dv;
1151 unsigned int i, j, k, num_cols, num_rows, dur_secs, dur_mag,
1152 invl_mag, invl_prec, tabrow_w, borderlen, invl_col_w, maxfltr_w;
1153 char **fmts, *fmt = NULL((void*)0);
1154 io_stat_item_t *mit, **stat_cols, *item, **item_in_column;
1155 bool_Bool last_row = false0;
1156 io_stat_t *iot;
1157 column_width *col_w;
1158 char time_buf[NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z")];
1159
1160 mit = (io_stat_item_t *)arg;
1161 iot = mit->parent;
1162 num_cols = iot->num_cols;
1163 col_w = g_new(column_width, num_cols)((column_width *) g_malloc_n ((num_cols), sizeof (column_width
)))
;
1164 fmts = g_new0(char *, num_cols)((char * *) g_malloc0_n ((num_cols), sizeof (char *)));
1165 duration = ((uint64_t)cfile.elapsed_time.secs * UINT64_C(1000000)1000000UL) +
1166 (uint64_t)((cfile.elapsed_time.nsecs + 500) / 1000);
1167
1168 /* Store the pointer to each stat column */
1169 stat_cols = (io_stat_item_t **)g_malloc(sizeof(io_stat_item_t *) * num_cols);
1170 for (j=0; j<num_cols; j++)
1171 stat_cols[j] = &iot->items[j];
1172
1173 /* The following prevents gross inaccuracies when the user specifies an interval that is greater
1174 * than the capture duration. */
1175 if (iot->interval > duration || iot->interval == UINT64_MAX(18446744073709551615UL)) {
1176 interval = duration;
1177 iot->interval = UINT64_MAX(18446744073709551615UL);
1178 } else {
1179 interval = iot->interval;
1180 }
1181
1182 /* Calc the capture duration's magnitude (dur_mag) */
1183 dur_secs = (unsigned int)(duration/UINT64_C(1000000)1000000UL);
1184 dur_mag = magnitude((uint64_t)dur_secs, 5);
1185
1186 /* Calc the interval's magnitude */
1187 invl_mag = magnitude(interval/UINT64_C(1000000)1000000UL, 5);
1188
1189 /* Set or get the interval precision */
1190 if (interval == duration) {
1191 /*
1192 * An interval arg of 0 or an interval size exceeding the capture duration was specified.
1193 * Set the decimal precision of duration based on its magnitude. */
1194 if (dur_mag >= 2)
1195 invl_prec = 1;
1196 else if (dur_mag == 1)
1197 invl_prec = 3;
1198 else
1199 invl_prec = 6;
1200
1201 borderlen = 30 + dur_mag + (invl_prec == 0 ? 0 : invl_prec+1);
1202 } else {
1203 invl_prec = iot->invl_prec;
1204 borderlen = 25 + MAX(invl_mag,dur_mag)(((invl_mag) > (dur_mag)) ? (invl_mag) : (dur_mag)) + (invl_prec == 0 ? 0 : invl_prec+1);
1205 }
1206
1207 /* Round the duration according to invl_prec */
1208 dv = 1000000;
1209 for (i=0; i<invl_prec; i++)
1210 dv /= 10;
1211 if ((duration%dv) > 5*(dv/10)) {
1212 duration += 5*(dv/10);
1213 duration = (duration/dv) * dv;
1214 dur_secs = (unsigned int)(duration/UINT64_C(1000000)1000000UL);
1215 /*
1216 * Recalc dur_mag in case rounding has increased its magnitude */
1217 dur_mag = magnitude((uint64_t)dur_secs, 5);
1218 }
1219 if (iot->interval == UINT64_MAX(18446744073709551615UL))
1220 interval = duration;
1221
1222 /* This is the max width of a duration. */
1223 int dur_w = dur_mag + (invl_prec == 0 ? 0 : invl_prec+1);
1224 /* Add a space on the side, and make sure the width is at least as wide
1225 * as "Dur". ("Dur" does not need a space between it and "|".) */
1226 dur_w = MAX(dur_w + 1, 3)(((dur_w + 1) > (3)) ? (dur_w + 1) : (3));
1227
1228 /* Update the width of the time interval column if date is shown */
1229 switch (timestamp_get_type()) {
1230 case TS_ABSOLUTE_WITH_YMD:
1231 case TS_ABSOLUTE_WITH_YDOY:
1232 case TS_UTC_WITH_YMD:
1233 case TS_UTC_WITH_YDOY:
1234 // We don't show more than 6 fractional digits (+Z) currently.
1235 // NSTIME_ISO8601_BUFSIZE is enough room for 9 frac digits + Z + '\0'
1236 // That's 4 extra characters, which leaves room for the "| |".
1237 invl_col_w = NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z") + invl_prec - 6;
1238 break;
1239
1240 default:
1241 /* Calc the width of the time interval column (incl borders and padding,
1242 * which are "|" and " <" on each side.) */
1243 invl_col_w = 2*(dur_w + 3);
1244 break;
1245 }
1246
1247 /* Calculate the width and format string of all the other columns, and add
1248 * the total to the interval column width for the entire total. */
1249 tabrow_w = invl_col_w + iostat_calc_cols_width_and_fmt(iot, interval, col_w, fmts);
1250
1251 borderlen = MAX(borderlen, tabrow_w)(((borderlen) > (tabrow_w)) ? (borderlen) : (tabrow_w));
1252
1253 /* Calc the max width of the list of filters. */
1254 maxfltr_w = 0;
1255 for (j=0; j<num_cols; j++) {
1256 if (iot->filters[j]) {
1257 k = (unsigned int) (strlen(iot->filters[j]) + 11);
1258 maxfltr_w = MAX(maxfltr_w, k)(((maxfltr_w) > (k)) ? (maxfltr_w) : (k));
1259 } else {
1260 maxfltr_w = MAX(maxfltr_w, 26)(((maxfltr_w) > (26)) ? (maxfltr_w) : (26));
1261 }
1262 }
1263 /* The stat table is not wrapped (by tshark) but filter is wrapped at the width of the stats table
1264 * (which currently = borderlen); however, if the filter width exceeds the table width and the
1265 * table width is less than 102 bytes, set borderlen to the lesser of the max filter width and 102.
1266 * The filters will wrap at the lesser of borderlen-2 and the last space in the filter.
1267 * NOTE: 102 is the typical size of a user window when the font is fixed width (e.g., COURIER 10).
1268 * XXX: A pref could be added to change the max width from the default size of 102. */
1269 if (maxfltr_w > borderlen && borderlen < 102)
1270 borderlen = MIN(maxfltr_w, 102)(((maxfltr_w) < (102)) ? (maxfltr_w) : (102));
1271
1272 /* Prevent double right border by adding a space */
1273 if (borderlen-tabrow_w == 1)
1274 borderlen++;
1275
1276 nstime_t invl_time = NSTIME_INIT_SECS_USECS(interval/UINT64_C(1000000), interval%UINT64_C(1000000)){(interval/1000000UL) + ((interval%1000000UL) / 1000000), ((interval
%1000000UL) % 1000000) * 1000}
;
1277 iostat_draw_header(borderlen, iot, &cfile.elapsed_time, &invl_time, invl_prec);
1278
1279 iostat_draw_header_row(borderlen, iot, col_w, invl_col_w, tabrow_w);
1280
1281 t = 0;
1282
1283 if (interval == 0 || duration == 0) {
1284 num_rows = 0;
1285 } else {
1286 num_rows = (unsigned int)(duration/interval) + ((unsigned int)(duration%interval) > 0 ? 1 : 0);
1287 }
1288
1289 /* Load item_in_column with the first item in each column */
1290 item_in_column = (io_stat_item_t **)g_malloc(sizeof(io_stat_item_t *) * num_cols);
1291 for (j=0; j<num_cols; j++) {
1292 item_in_column[j] = stat_cols[j];
1293 }
1294
1295 /* Display the table values
1296 *
1297 * The outer loop is for time interval rows and the inner loop is for stat column items.*/
1298 for (i=0; i<num_rows; i++) {
1299
1300 if (i == num_rows-1)
1301 last_row = true1;
1302
1303 /* Compute the interval for this row */
1304 if (!last_row) {
1305 real_invl = interval;
1306 } else {
1307 real_invl = duration - t;
1308 }
1309
1310 /* Patch for Absolute Time */
1311 /* XXX - has a Y2.038K problem with 32-bit time_t */
1312 nstime_t the_time = NSTIME_INIT_SECS_USECS(t / 1000000, t % 1000000){(t / 1000000) + ((t % 1000000) / 1000000), ((t % 1000000) % 1000000
) * 1000}
;
1313
1314 /* Display the interval for this row */
1315 /* Get the string representing the start time of this interval. */
1316 fill_start_time(iot, &the_time, invl_prec, time_buf);
1317 /* Now add the surrounding column information according to our
1318 * output format (currently, only text table is supported.) */
1319 switch (timestamp_get_type()) {
1320
1321 case TS_RELATIVE:
1322 case TS_RELATIVE_CAP:
1323 case TS_NOT_SET:
1324 /* For relative times, we show both ends of the interval. */
1325 printf("|%*s <", dur_w, time_buf);
1326 if (invl_prec == 0 && last_row) {
1327 g_strlcpy(time_buf, "Dur", NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"));
1328 } else {
1329 nstime_add(&the_time, &invl_time)nstime_sum(&the_time, &the_time, &invl_time);
1330 display_signed_time(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"), &the_time, invl_prec);
1331 }
1332 printf("> %-*s|", dur_w, time_buf);
1333 break;
1334 default:
1335 printf("| %-*s |", invl_col_w - 4, time_buf);
1336 break;
1337 }
1338
1339 /* Display stat values in each column for this row */
1340 for (j=0; j<num_cols; j++) {
1341 fmt = fmts[j];
1342 item = item_in_column[j];
1343
1344 /* To try to optimize speed, we could copy the value string with
1345 * snprintf into a pre-allocated buffer with the maximum column
1346 * width, which we determined (though that's more error-prone.)
1347 */
1348 char *value = iostat_get_item_value(iot, item, fmt, j, real_invl);
1349 printf(" %s |", value);
1350 g_free(value);
1351
1352 if (item)
1353 item_in_column[j] = item_in_column[j]->next;
1354 }
1355 if (tabrow_w < borderlen) {
1356 printf("%*s", borderlen - tabrow_w, "|");
1357 }
1358 printf("\n");
1359 t += interval;
1360
1361 }
1362 for (i=0; i<borderlen; i++) {
1363 printf("=");
1364 }
1365 printf("\n");
1366 g_free(col_w);
1367 for (i=0; i<num_cols; ++i) {
1368 g_free(fmts[i]);
1369 }
1370 g_free(fmts);
1371 g_free(stat_cols);
1372 g_free(item_in_column);
1373}
1374
1375/* A new capture file is being loaded (or the current one reloaded),
1376 * reset our statistics.
1377 */
1378static void
1379iostat_reset(void *arg)
1380{
1381 io_stat_item_t *mit = (io_stat_item_t *)arg;
1382 io_stat_t *io = mit->parent;
1383
1384 nstime_set_unset(&io->start_time);
1385 io->last_relative_time = UINT64_C(0)0UL;
1386 for (unsigned int i=0; i<io->num_cols; i++) {
1387 iostat_item_reset(&io->items[i]);
1388 io->max_vals[i] = 0;
1389 io->max_frame[i] = 0;
1390 }
1391}
1392
1393/* Our listener is being removed, free our memory. */
1394static void
1395iostat_finish(void *arg)
1396{
1397 io_stat_item_t *mit = (io_stat_item_t *)arg;
1398 io_stat_t *io = mit->parent;
1399 iostat_io_free(io);
1400}
1401
1402/*
1403 * Register a new iostat tap for column number i.
1404 * The new tap's tapdata (see doc/README.tapping) is io->items[i], not io itself.
1405 * We only set the draw/reset/finish functions if i == 0 so everything is handled only once.
1406 */
1407static bool_Bool
1408register_io_tap(io_stat_t *io, unsigned int i, const char *filter, GString *err)
1409{
1410 GString *error_string;
1411 const char *flt;
1412 int j;
1413 size_t namelen;
1414 const char *p, *parenp;
1415 char *field;
1416 header_field_info *hfi;
1417
1418 io->items[i].prev = &io->items[i];
1419 io->items[i].next = NULL((void*)0);
1420 io->items[i].parent = io;
1421 io->items[i].start_time = 0;
1422 io->items[i].frames = 0;
1423 io->items[i].counter = 0;
1424 io->items[i].num = 0;
1425
1426 io->filters[i] = filter;
1427 flt = filter;
1428
1429 io->calc_type[i] = CALC_TYPE_FRAMES_AND_BYTES2;
1430 field = NULL((void*)0);
1431 hfi = NULL((void*)0);
1432 for (j=0; calc_type_table[j].func_name; j++) {
1433 namelen = strlen(calc_type_table[j].func_name);
1434 if (filter && strncmp(filter, calc_type_table[j].func_name, namelen) == 0) {
1435 io->calc_type[i] = calc_type_table[j].calc_type;
1436 io->items[i].colnum = i;
1437 if (*(filter+namelen) == '(') {
1438 p = filter+namelen+1;
1439 parenp = strchr(p, ')');
1440 if (!parenp) {
1441 cmdarg_err("\ntshark: Closing parenthesis missing from calculated expression.\n");
1442 return false0;
1443 }
1444
1445 if (io->calc_type[i] == CALC_TYPE_FRAMES0 || io->calc_type[i] == CALC_TYPE_BYTES1) {
1446 if (parenp != p) {
1447 cmdarg_err("\ntshark: %s does not require or allow a field name within the parens.\n",
1448 calc_type_table[j].func_name);
1449 return false0;
1450 }
1451 } else {
1452 if (parenp == p) {
1453 /* bail out if a field name was not specified */
1454 cmdarg_err("\ntshark: You didn't specify a field name for %s(*).\n",
1455 calc_type_table[j].func_name);
1456 return false0;
1457 }
1458 }
1459
1460 field = (char *)g_malloc(parenp-p+1);
1461 memcpy(field, p, parenp-p);
1462 field[parenp-p] = '\0';
1463 flt = parenp + 1;
1464 if (io->calc_type[i] == CALC_TYPE_FRAMES0 || io->calc_type[i] == CALC_TYPE_BYTES1)
1465 break;
1466 hfi = proto_registrar_get_byname(field);
1467 if (!hfi) {
1468 cmdarg_err("\ntshark: There is no field named '%s'.\n", field);
1469 g_free(field);
1470 return false0;
1471 }
1472
1473 io->hf_indexes[i] = hfi->id;
1474 break;
1475 }
1476 } else {
1477 if (io->calc_type[i] == CALC_TYPE_FRAMES0 || io->calc_type[i] == CALC_TYPE_BYTES1)
1478 flt = "";
1479 io->items[i].colnum = i;
1480 }
1481 }
1482 if (hfi && !(io->calc_type[i] == CALC_TYPE_BYTES1 ||
1483 io->calc_type[i] == CALC_TYPE_FRAMES0 ||
1484 io->calc_type[i] == CALC_TYPE_FRAMES_AND_BYTES2)) {
1485 /* check that the type is compatible */
1486 switch (hfi->type) {
1487 case FT_UINT8:
1488 case FT_UINT16:
1489 case FT_UINT24:
1490 case FT_UINT32:
1491 case FT_UINT64:
1492 case FT_INT8:
1493 case FT_INT16:
1494 case FT_INT24:
1495 case FT_INT32:
1496 case FT_INT64:
1497 /* these types support all calculations */
1498 break;
1499 case FT_FLOAT:
1500 case FT_DOUBLE:
1501 /* these types only support SUM, COUNT, MAX, MIN, AVG */
1502 switch (io->calc_type[i]) {
1503 case CALC_TYPE_SUM4:
1504 case CALC_TYPE_COUNT3:
1505 case CALC_TYPE_MAX6:
1506 case CALC_TYPE_MIN5:
1507 case CALC_TYPE_AVG7:
1508 break;
1509 default:
1510 cmdarg_err("\ntshark: %s is a float field, so %s(*) calculations are not supported on it.",
1511 field,
1512 calc_type_table[j].func_name);
1513 return false0;
1514 }
1515 break;
1516 case FT_RELATIVE_TIME:
1517 /* this type only supports SUM, COUNT, MAX, MIN, AVG, LOAD */
1518 switch (io->calc_type[i]) {
1519 case CALC_TYPE_SUM4:
1520 case CALC_TYPE_COUNT3:
1521 case CALC_TYPE_MAX6:
1522 case CALC_TYPE_MIN5:
1523 case CALC_TYPE_AVG7:
1524 case CALC_TYPE_LOAD8:
1525 break;
1526 default:
1527 cmdarg_err("\ntshark: %s is a relative-time field, so %s(*) calculations are not supported on it.",
1528 field,
1529 calc_type_table[j].func_name);
1530 return false0;
1531 }
1532 break;
1533 default:
1534 /*
1535 * XXX - support all operations on floating-point
1536 * numbers?
1537 */
1538 if (io->calc_type[i] != CALC_TYPE_COUNT3) {
1539 cmdarg_err("\ntshark: %s doesn't have integral values, so %s(*) "
1540 "calculations are not supported on it.\n",
1541 field,
1542 calc_type_table[j].func_name);
1543 return false0;
1544 }
1545 break;
1546 }
1547 }
1548 g_free(field);
1549
1550 error_string = register_tap_listener("frame", &io->items[i], flt, TL_REQUIRES_PROTO_TREE0x00000001,
1551 i ? NULL((void*)0) : iostat_reset,
1552 iostat_packet,
1553 i ? NULL((void*)0) : iostat_draw,
1554 i ? NULL((void*)0) : iostat_finish);
1555 if (error_string) {
1556 /* Accumulate errors about all the possible filters tried at the same
1557 * starting character.
1558 */
1559 if (err->len) {
1560 g_string_append_c(err, '\n')g_string_append_c_inline (err, '\n');
1561 }
1562 g_string_append(err, error_string->str)(__builtin_constant_p (error_string->str) ? __extension__ (
{ const char * const __val = (error_string->str); g_string_append_len_inline
(err, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(err, error_string->str, (gssize) -1))
;
1563 g_string_free(error_string, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(error_string), ((!(0)))) : g_string_free_and_steal (error_string
)) : (g_string_free) ((error_string), ((!(0)))))
;
1564 return false0;
1565 }
1566
1567 /* On success, clear old errors (from splitting on internal commas). */
1568 g_string_truncate(err, 0)g_string_truncate_inline (err, 0);
1569 return true1;
1570}
1571
1572static bool_Bool
1573iostat_init(const char *opt_arg, void *userdata _U___attribute__((unused)))
1574{
1575 double interval_float;
1576 uint32_t idx = 0;
1577 unsigned int i;
1578 io_stat_t *io;
1579 const char *filters, *str, *pos;
1580
1581 io_decimal_point = localeconv()->decimal_point;
1582
1583 /* XXX - Why can't the last character be a comma? Shouldn't it be
1584 * fine for the last filter to be empty? Even in the case of locales
1585 * that use ',' for the decimal separator, there shouldn't be any
1586 * difference between interpreting a terminating ',' as a decimal
1587 * point for the interval, and interpreting it as a separator followed
1588 * by an empty filter.
1589 */
1590 if ((*(opt_arg+(strlen(opt_arg)-1)) == ',') ||
1
Assuming the condition is false
4
Taking false branch
1591 (sscanf(opt_arg, "io,stat,%lf%n", &interval_float, (int *)&idx) != 1) ||
2
Assuming the condition is false
1592 (idx < 8)) {
3
Assuming 'idx' is >= 8
1593 cmdarg_err("\ntshark: invalid \"-z io,stat,<interval>[,<filter>][,<filter>]...\" argument\n");
1594 return false0;
1595 }
1596
1597 filters = opt_arg+idx;
1598 if (*filters) {
5
Assuming the condition is true
6
Taking true branch
1599 if (*filters != ',') {
7
Assuming the condition is false
8
Taking false branch
1600 /* For locales that use ',' instead of '.', the comma might
1601 * have been consumed during the floating point conversion. */
1602 --filters;
1603 if (*filters != ',') {
1604 cmdarg_err("\ntshark: invalid \"-z io,stat,<interval>[,<filter>][,<filter>]...\" argument\n");
1605 return false0;
1606 }
1607 }
1608 }
1609 /* filters now either starts with ',' or '\0' */
1610
1611 switch (timestamp_get_type()) {
9
Control jumps to the 'default' case at line 1617
1612 case TS_DELTA:
1613 case TS_DELTA_DIS:
1614 case TS_EPOCH:
1615 cmdarg_err("\ntshark: invalid -t operand. io,stat only supports -t <r|a|ad|adoy|u|ud|udoy>\n");
1616 return false0;
1617 default:
1618 break;
10
Execution continues on line 1621
1619 }
1620
1621 io = g_new0(io_stat_t, 1)((io_stat_t *) g_malloc0_n ((1), sizeof (io_stat_t)));
1622 io->last_relative_time = UINT64_C(0)0UL;
1623
1624 /* If interval is 0, calculate statistics over the whole file by setting the interval to
1625 * UINT64_MAX */
1626 if (interval_float == 0) {
11
Assuming 'interval_float' is equal to 0
12
Taking true branch
1627 io->interval = UINT64_MAX(18446744073709551615UL);
1628 io->invl_prec = 0;
1629 } else {
1630 /* Set interval to the number of us rounded to the nearest integer */
1631 io->interval = (uint64_t)(interval_float * 1000000.0 + 0.5);
1632 /*
1633 * Determine what interval precision the user has specified */
1634 io->invl_prec = 6;
1635 for (i=10; i<10000000; i*=10) {
1636 if (io->interval%i > 0)
1637 break;
1638 io->invl_prec--;
1639 }
1640 if (io->invl_prec == 0) {
1641 /* The precision is zero but if the user specified one of more zeros after the decimal point,
1642 they want that many decimal places shown in the table for all time intervals except
1643 response time values such as smb.time which always have 6 decimal places of precision.
1644 This feature is useful in cases where for example the duration is 9.1, you specify an
1645 interval of 1 and the last interval becomes "9 <> 9". If the interval is instead set to
1646 1.1, the last interval becomes
1647 last interval is rounded up to value that is greater than the duration. */
1648 const char *invl_start = opt_arg+8;
1649 unsigned invl_len;
1650
1651 invl_start = strpbrk(invl_start, ".,");
1652
1653 if (invl_start != NULL((void*)0) && *invl_start == '.') {
1654 invl_len = (unsigned)strcspn(invl_start + 1, ",");
1655 if (invl_len)
1656 io->invl_prec = MIN(invl_len, 6U)(((invl_len) < (6U)) ? (invl_len) : (6U));
1657 }
1658 }
1659 }
1660 if (io->interval
12.1
Field 'interval' is >= 1
< 1) {
13
Taking false branch
1661 cmdarg_err("\ntshark: \"-z\" interval must be >=0.000001 seconds or \"0\" for the entire capture duration.\n");
1662 iostat_io_free(io);
1663 return false0;
1664 }
1665
1666 /* Find how many ',' separated filters we have */
1667 /* Filter can have internal commas, so this is only an upper bound on the
1668 * number of filters. In the display filter grammar, commas only appear
1669 * inside delimiters (quoted strings, slices, sets, and functions), so
1670 * splitting in the wrong place produces an invalid filter. That is, there
1671 * can be at most only one valid interpretation (but might be none).
1672 *
1673 * XXX - If the grammar changes to allow commas in other places, then there
1674 * is ambiguity.
1675 *
1676 * Perhaps ideally we'd verify the filters before doing allocation.
1677 */
1678 io->num_cols = 1;
1679 nstime_set_unset(&io->start_time);
1680
1681 if (*filters != '\0') {
14
Assuming the condition is false
15
Taking false branch
1682 /* Eliminate the first comma. */
1683 filters++;
1684 str = filters;
1685 while ((str = strchr(str, ','))) {
1686 io->num_cols++;
1687 str++;
1688 }
1689 }
1690
1691 io->items = g_new0(io_stat_item_t, io->num_cols)((io_stat_item_t *) g_malloc0_n ((io->num_cols), sizeof (io_stat_item_t
)))
;
1692 io->filters = (const char **)g_malloc(sizeof(char *) * io->num_cols);
1693 io->max_vals = g_new(uint64_t, io->num_cols)((uint64_t *) g_malloc_n ((io->num_cols), sizeof (uint64_t
)))
;
1694 io->max_frame = g_new(uint32_t, io->num_cols)((uint32_t *) g_malloc_n ((io->num_cols), sizeof (uint32_t
)))
;
1695 io->hf_indexes = g_new(int, io->num_cols)((int *) g_malloc_n ((io->num_cols), sizeof (int)));
1696 io->calc_type = g_new(int, io->num_cols)((int *) g_malloc_n ((io->num_cols), sizeof (int)));
1697
1698 for (i=0; i
15.1
'i' is < field 'num_cols'
<io->num_cols
; i++) {
16
Loop condition is true. Entering loop body
17
Assuming 'i' is >= field 'num_cols'
18
Loop condition is false. Execution continues on line 1703
1699 io->max_vals[i] = 0;
1700 io->max_frame[i] = 0;
1701 }
1702
1703 bool_Bool success;
1704 GString *err = g_string_new(NULL((void*)0));
1705
1706 /* Register a tap listener for each filter */
1707 if (filters[0] == '\0') {
19
Assuming the condition is false
20
Taking false branch
1708 success = register_io_tap(io, 0, NULL((void*)0), err);
1709 } else {
1710 char *filter;
1711 i = 0;
1712 str = filters;
1713 pos = str;
1714 while ((pos = strchr(pos, ',')) != NULL((void*)0)) {
21
Assuming the condition is true
22
Loop condition is true. Entering loop body
1715 if (pos == str) {
23
Assuming 'pos' is not equal to 'str'
24
Taking false branch
1716 /* Consecutive commas - an empty filter. */
1717 filter = NULL((void*)0);
1718 } else {
1719 /* Likely a filter. */
1720 filter = (char *)g_malloc((pos-str)+1);
25
Memory is allocated
1721 (void) g_strlcpy( filter, str, (size_t) ((pos-str)+1));
1722 filter = g_strstrip(filter)g_strchomp (g_strchug (filter));
1723 }
1724 success = register_io_tap(io, i, filter, err);
26
Potential leak of memory pointed to by 'filter'
1725 /* Advance to the next position to look for commas. */
1726 pos++;
1727 if (success) {
1728 /* Also advance the filter start on success. */
1729 str = pos;
1730 i++;
1731 } else {
1732 g_free(filter);
1733 }
1734 }
1735 /* No more commas, the rest of the string is the last filter. */
1736 filter = g_strstrip(g_strdup(str))g_strchomp (g_strchug (g_strdup_inline (str)));
1737 if (*filter) {
1738 success = register_io_tap(io, i, filter, err);
1739 } else {
1740 success = register_io_tap(io, i, NULL((void*)0), err);
1741 }
1742 if (success) {
1743 i++;
1744 }
1745 io->num_cols = i;
1746 }
1747
1748 if (!success) {
1749 cmdarg_err("\ntshark: Couldn't register io,stat tap: %s\n",
1750 err->str);
1751 g_string_free(err, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(err), ((!(0)))) : g_string_free_and_steal (err)) : (g_string_free
) ((err), ((!(0)))))
;
1752 iostat_io_free(io);
1753 return false0;
1754 }
1755 g_string_free(err, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(err), ((!(0)))) : g_string_free_and_steal (err)) : (g_string_free
) ((err), ((!(0)))))
;
1756 return true1;
1757
1758}
1759
1760static stat_tap_ui iostat_ui = {
1761 REGISTER_STAT_GROUP_GENERIC,
1762 NULL((void*)0),
1763 "io,stat",
1764 iostat_init,
1765 0,
1766 NULL((void*)0)
1767};
1768
1769void
1770register_tap_listener_iostat(void)
1771{
1772 register_stat_tap_ui(&iostat_ui, NULL((void*)0));
1773}