Bug Summary

File:ui/cli/tap-iostat.c
Warning:line 1721, 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-20/lib/clang/20 -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-20/lib/clang/20/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-09-12-100405-3933-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_NOT_SET:
763 display_signed_time(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"), rel_time, invl_prec);
764 break;
765 case TS_DELTA:
766 case TS_DELTA_DIS:
767 case TS_EPOCH:
768 /* Can't happen - see iostat_init. */
769 ws_assert_not_reached()ws_log_fatal_full("", LOG_LEVEL_ERROR, "ui/cli/tap-iostat.c",
769, __func__, "assertion \"not reached\" failed")
;
770 break;
771 default:
772 break;
773 }
774}
775
776static char*
777iostat_get_item_value(const io_stat_t *iot, io_stat_item_t *item, const char *fmt, unsigned j, uint64_t interval)
778{
779 uint32_t num;
780 unsigned type, ftype;
781
782 type = iot->calc_type[j];
783
784 if (item) {
785 switch (type) {
786 case CALC_TYPE_FRAMES0:
787 return g_strdup_printf(fmt, item->frames);
788 case CALC_TYPE_BYTES1:
789 case CALC_TYPE_COUNT3:
790 return g_strdup_printf(fmt, item->counter);
791 case CALC_TYPE_FRAMES_AND_BYTES2:
792 return g_strdup_printf(fmt, item->frames, item->counter);
793
794 case CALC_TYPE_SUM4:
795 case CALC_TYPE_MIN5:
796 case CALC_TYPE_MAX6:
797 ftype = proto_registrar_get_ftype(iot->hf_indexes[j]);
798 switch (ftype) {
799 case FT_FLOAT:
800 return g_strdup_printf(fmt, item->float_counter);
801 case FT_DOUBLE:
802 return g_strdup_printf(fmt, item->double_counter);
803 case FT_RELATIVE_TIME:
804 item->counter = (item->counter + UINT64_C(500)500UL) / UINT64_C(1000)1000UL;
805 return g_strdup_printf(fmt,
806 (int)(item->counter/UINT64_C(1000000)1000000UL),
807 (int)(item->counter%UINT64_C(1000000)1000000UL));
808 default:
809 return g_strdup_printf(fmt, item->counter);
810 }
811 break;
812
813 case CALC_TYPE_AVG7:
814 num = item->num;
815 if (num == 0)
816 num = 1;
817 ftype = proto_registrar_get_ftype(iot->hf_indexes[j]);
818 switch (ftype) {
819 case FT_FLOAT:
820 return g_strdup_printf(fmt, item->float_counter/num);
821 case FT_DOUBLE:
822 return g_strdup_printf(fmt, item->double_counter/num);
823 case FT_RELATIVE_TIME:
824 item->counter = ((item->counter / (uint64_t)num) + UINT64_C(500)500UL) / UINT64_C(1000)1000UL;
825 return g_strdup_printf(fmt,
826 (int)(item->counter/UINT64_C(1000000)1000000UL),
827 (int)(item->counter%UINT64_C(1000000)1000000UL));
828 default:
829 return g_strdup_printf(fmt, item->counter / (uint64_t)num);
830 }
831 break;
832
833 case CALC_TYPE_LOAD8:
834 ftype = proto_registrar_get_ftype(iot->hf_indexes[j]);
835 switch (ftype) {
836 case FT_RELATIVE_TIME:
837 return g_strdup_printf(fmt,
838 (int) (item->counter/interval),
839 (int)((item->counter%interval)*UINT64_C(1000000)1000000UL / interval));
840 }
841 break;
842 }
843 }
844 return g_strdup_printf(fmt, (uint64_t)0, (uint64_t)0);
845}
846
847/* Calc the total width of each row in the stats table and build the printf format string for each
848* column based on its field type, width, and name length.
849* NOTE: The magnitude of all types including float and double are stored in iot->max_vals which
850* is an *integer*. */
851static unsigned
852iostat_calc_cols_width_and_fmt(io_stat_t *iot, uint64_t interval, column_width* col_w, char**fmts)
853{
854 unsigned tabrow_w, type, ftype, namelen;
855 unsigned fr_mag; /* The magnitude of the max frame number in this column */
856 unsigned val_mag; /* The magnitude of the max value in this column */
857 char *fmt = NULL((void*)0);
858
859 tabrow_w = 0;
860 for (unsigned j=0; j < iot->num_cols; j++) {
861 type = iot->calc_type[j];
862 if (type == CALC_TYPE_FRAMES_AND_BYTES2) {
863 namelen = 5;
864 } else {
865 namelen = (unsigned int)strlen(calc_type_table[type].func_name);
866 }
867 if (type == CALC_TYPE_FRAMES0
868 || type == CALC_TYPE_FRAMES_AND_BYTES2) {
869
870 fr_mag = magnitude(iot->max_frame[j], 15);
871 fr_mag = MAX(6, fr_mag)(((6) > (fr_mag)) ? (6) : (fr_mag));
872 col_w[j].fr = fr_mag;
873 tabrow_w += col_w[j].fr + 3;
874
875 if (type == CALC_TYPE_FRAMES0) {
876 fmt = g_strdup_printf("%%%uu", fr_mag);
877 } else {
878 /* CALC_TYPE_FRAMES_AND_BYTES
879 */
880 val_mag = magnitude(iot->max_vals[j], 15);
881 val_mag = MAX(5, val_mag)(((5) > (val_mag)) ? (5) : (val_mag));
882 col_w[j].val = val_mag;
883 tabrow_w += (col_w[j].val + 3);
884 fmt = g_strdup_printf("%%%uu | %%%u"PRIu64"l" "u", fr_mag, val_mag);
885 }
886 if (fmt)
887 fmts[j] = fmt;
888 continue;
889 }
890 switch (type) {
891 case CALC_TYPE_BYTES1:
892 case CALC_TYPE_COUNT3:
893
894 val_mag = magnitude(iot->max_vals[j], 15);
895 val_mag = MAX(5, val_mag)(((5) > (val_mag)) ? (5) : (val_mag));
896 col_w[j].val = val_mag;
897 fmt = g_strdup_printf("%%%u"PRIu64"l" "u", val_mag);
898 break;
899
900 default:
901 ftype = proto_registrar_get_ftype(iot->hf_indexes[j]);
902 switch (ftype) {
903 case FT_FLOAT:
904 case FT_DOUBLE:
905 val_mag = magnitude(iot->max_vals[j], 15);
906 fmt = g_strdup_printf("%%%u.6f", val_mag);
907 col_w[j].val = val_mag + 7;
908 break;
909 case FT_RELATIVE_TIME:
910 /* Convert FT_RELATIVE_TIME field to seconds
911 * CALC_TYPE_LOAD was already converted in iostat_packet() ) */
912 if (type == CALC_TYPE_LOAD8) {
913 iot->max_vals[j] /= interval;
914 } else if (type != CALC_TYPE_AVG7) {
915 iot->max_vals[j] = (iot->max_vals[j] + UINT64_C(500000000)500000000UL) / NANOSECS_PER_SEC1000000000UL;
916 }
917 val_mag = magnitude(iot->max_vals[j], 15);
918 fmt = g_strdup_printf("%%%uu.%%06u", val_mag);
919 col_w[j].val = val_mag + 7;
920 break;
921
922 default:
923 val_mag = magnitude(iot->max_vals[j], 15);
924 val_mag = MAX(namelen, val_mag)(((namelen) > (val_mag)) ? (namelen) : (val_mag));
925 col_w[j].val = val_mag;
926
927 switch (ftype) {
928 case FT_UINT8:
929 case FT_UINT16:
930 case FT_UINT24:
931 case FT_UINT32:
932 case FT_UINT64:
933 fmt = g_strdup_printf("%%%u"PRIu64"l" "u", val_mag);
934 break;
935 case FT_INT8:
936 case FT_INT16:
937 case FT_INT24:
938 case FT_INT32:
939 case FT_INT64:
940 fmt = g_strdup_printf("%%%u"PRId64"l" "d", val_mag);
941 break;
942 }
943 } /* End of ftype switch */
944 } /* End of calc_type switch */
945 tabrow_w += col_w[j].val + 3;
946 if (fmt)
947 fmts[j] = fmt;
948 } /* End of for loop (columns) */
949
950 return tabrow_w;
951}
952
953static void
954iostat_draw_filters(unsigned borderlen, const io_stat_t *iot)
955{
956 const char *filter;
957 size_t len_filt;
958 GString *filt_str;
959
960 /* Display the list of filters and their column numbers vertically */
961 for (unsigned j=0; j<iot->num_cols; j++) {
962 if (j == 0) {
963 filt_str = g_string_new("| Col ");
964 } else {
965 filt_str = g_string_new("| ");
966 };
967 g_string_append_printf(filt_str, "%2u: ", j + 1);
968 if (!iot->filters[j]) {
969 /* An empty (no filter) comma field was specified */
970 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))
;
971 } else {
972 filter = iot->filters[j];
973 len_filt = strlen(filter);
974 /* borderlen has been adjusted to try to accommodate the widest
975 * filter, but only up to a limit (currently 102 bytes), and so
976 * filters wider than that must still wrap. */
977 /* 11 is the length of "| Col XX: " plus the trailing "|" */
978 size_t max_w = borderlen - 11;
979
980 while (len_filt > max_w) {
981 const char *pos;
982 size_t len;
983 unsigned int next_start;
984
985 /* Find the pos of the last space in filter up to max_w. If a
986 * space is found, copy up to that space; otherwise, wrap the
987 * filter at max_w. */
988 pos = g_strrstr_len(filter, max_w, " ");
989 if (pos) {
990 len = (size_t)(pos-filter);
991 /* Skip the space when wrapping. */
992 next_start = (unsigned int) len+1;
993 } else {
994 len = max_w;
995 next_start = (unsigned int)len;
996 }
997 g_string_append_len(filt_str, filter, len)g_string_append_len_inline (filt_str, filter, len);
998 g_string_append_printf(filt_str, "%*s", (int)(borderlen - filt_str->len), "|");
999
1000 puts(filt_str->str);
1001 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)))))
;
1002
1003 filt_str = g_string_new("| ");
1004 filter = &filter[next_start];
1005 len_filt = strlen(filter);
1006 }
1007
1008 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))
;
1009 }
1010 g_string_append_printf(filt_str, "%*s", (int)(borderlen - filt_str->len), "|");
1011 puts(filt_str->str);
1012 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)))))
;
1013 }
1014}
1015
1016static void
1017iostat_draw_header(unsigned borderlen, const io_stat_t *iot, const nstime_t *duration, const nstime_t *interval, ws_tsprec_e invl_prec)
1018{
1019 unsigned i;
1020 char time_buf[NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z")];
1021
1022 /* Display the top border */
1023 printf("\n");
1024 for (i=0; i<borderlen; i++)
1025 printf("=");
1026
1027 printf("\n|%-*s|\n", borderlen - 2, " IO Statistics");
1028 printf("|%-*s|\n", borderlen - 2, "");
1029
1030 /* For some reason, we print the total duration in microsecond precision
1031 * here if the interval is in seconds precision, and use the interval
1032 * precision otherwise.
1033 */
1034 ws_tsprec_e dur_prec = (invl_prec == WS_TSPREC_SEC) ? WS_TSPREC_USEC : invl_prec;
1035 nstime_t dur_rounded;
1036 nstime_rounded(&dur_rounded, duration, dur_prec);
1037 int dur_mag = magnitude(duration->secs, 5);
1038 int dur_w = dur_mag + (invl_prec == 0 ? 0 : invl_prec+1);
1039
1040 GString *dur_str = g_string_new("| Duration: ");
1041 display_signed_time(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"), &dur_rounded, dur_prec);
1042 g_string_append_printf(dur_str, "%*s secs", dur_w, time_buf);
1043 g_string_append_printf(dur_str, "%*s", (int)(borderlen - dur_str->len), "|");
1044 puts(dur_str->str);
1045 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)))))
;
1046
1047 GString *invl_str = g_string_new("| Interval: ");
1048 display_signed_time(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"), interval, invl_prec);
1049 g_string_append_printf(invl_str, "%*s secs", dur_w, time_buf);
1050 g_string_append_printf(invl_str, "%*s", (int)(borderlen - invl_str->len), "|");
1051 puts(invl_str->str);
1052 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)))))
;
1053
1054 printf("|%-*s|\n", borderlen - 2, "");
1055
1056 iostat_draw_filters(borderlen, iot);
1057
1058 printf("|-");
1059 for (i=0; i<borderlen-3; i++) {
1060 printf("-");
1061 }
1062 printf("|\n");
1063}
1064
1065static void
1066iostat_draw_header_row(unsigned borderlen, const io_stat_t *iot, const column_width *col_w, unsigned invl_col_w, unsigned tabrow_w)
1067{
1068 unsigned j, type, numpad = 1;
1069 char *filler_s = NULL((void*)0);
1070
1071 /* Display spaces above "Interval (s)" label */
1072 printf("|%*s", invl_col_w - 1, "|");
1073
1074 /* Display column number headers */
1075 for (j=0; j < iot->num_cols; j++) {
1076 int padding;
1077 if (iot->calc_type[j] == CALC_TYPE_FRAMES_AND_BYTES2)
1078 padding = col_w[j].fr + col_w[j].val + 3;
1079 else if (iot->calc_type[j] == CALC_TYPE_FRAMES0)
1080 padding = col_w[j].fr;
1081 else
1082 padding = col_w[j].val;
1083
1084 printf("%-2d%*s|", j+1, padding, "");
1085 }
1086 if (tabrow_w < borderlen) {
1087 filler_s = g_strdup_printf("%*s", borderlen - tabrow_w, "|");
1088 printf("%s", filler_s);
1089 }
1090 printf("\n");
1091
1092 GString *timestamp_str;
1093 switch (timestamp_get_type()) {
1094 case TS_ABSOLUTE:
1095 case TS_UTC:
1096 timestamp_str = g_string_new("| Time ");
1097 break;
1098 case TS_ABSOLUTE_WITH_YMD:
1099 case TS_ABSOLUTE_WITH_YDOY:
1100 case TS_UTC_WITH_YMD:
1101 case TS_UTC_WITH_YDOY:
1102 timestamp_str = g_string_new("| Date and time");
1103 break;
1104 case TS_RELATIVE:
1105 case TS_NOT_SET:
1106 timestamp_str = g_string_new("| Interval");
1107 break;
1108 default:
1109 timestamp_str = g_string_new(NULL((void*)0));
1110 break;
1111 }
1112
1113 printf("%s%*s", timestamp_str->str, (int)(invl_col_w - timestamp_str->len), "|");
1114 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)))))
;
1115
1116 /* Display the stat label in each column */
1117 for (j=0; j < iot->num_cols; j++) {
1118 type = iot->calc_type[j];
1119 if (type == CALC_TYPE_FRAMES0) {
1120 printcenter (calc_type_table[type].func_name, col_w[j].fr, numpad);
1121 } else if (type == CALC_TYPE_FRAMES_AND_BYTES2) {
1122 printcenter ("Frames", col_w[j].fr, numpad);
1123 printcenter ("Bytes", col_w[j].val, numpad);
1124 } else {
1125 printcenter (calc_type_table[type].func_name, col_w[j].val, numpad);
1126 }
1127 }
1128 if (filler_s) {
1129 printf("%s", filler_s);
1130 }
1131 printf("\n|-");
1132
1133 for (j=0; j<tabrow_w-3; j++)
1134 printf("-");
1135 printf("|");
1136
1137 if (filler_s) {
1138 printf("%s", filler_s);
1139 g_free(filler_s);
1140 }
1141
1142 printf("\n");
1143}
1144
1145static void
1146iostat_draw(void *arg)
1147{
1148 uint64_t interval, duration, t, real_invl, dv;
1149 unsigned int i, j, k, num_cols, num_rows, dur_secs, dur_mag,
1150 invl_mag, invl_prec, tabrow_w, borderlen, invl_col_w, maxfltr_w;
1151 char **fmts, *fmt = NULL((void*)0);
1152 io_stat_item_t *mit, **stat_cols, *item, **item_in_column;
1153 bool_Bool last_row = false0;
1154 io_stat_t *iot;
1155 column_width *col_w;
1156 char time_buf[NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z")];
1157
1158 mit = (io_stat_item_t *)arg;
1159 iot = mit->parent;
1160 num_cols = iot->num_cols;
1161 col_w = g_new(column_width, num_cols)((column_width *) g_malloc_n ((num_cols), sizeof (column_width
)))
;
1162 fmts = g_new0(char *, num_cols)((char * *) g_malloc0_n ((num_cols), sizeof (char *)));
1163 duration = ((uint64_t)cfile.elapsed_time.secs * UINT64_C(1000000)1000000UL) +
1164 (uint64_t)((cfile.elapsed_time.nsecs + 500) / 1000);
1165
1166 /* Store the pointer to each stat column */
1167 stat_cols = (io_stat_item_t **)g_malloc(sizeof(io_stat_item_t *) * num_cols);
1168 for (j=0; j<num_cols; j++)
1169 stat_cols[j] = &iot->items[j];
1170
1171 /* The following prevents gross inaccuracies when the user specifies an interval that is greater
1172 * than the capture duration. */
1173 if (iot->interval > duration || iot->interval == UINT64_MAX(18446744073709551615UL)) {
1174 interval = duration;
1175 iot->interval = UINT64_MAX(18446744073709551615UL);
1176 } else {
1177 interval = iot->interval;
1178 }
1179
1180 /* Calc the capture duration's magnitude (dur_mag) */
1181 dur_secs = (unsigned int)(duration/UINT64_C(1000000)1000000UL);
1182 dur_mag = magnitude((uint64_t)dur_secs, 5);
1183
1184 /* Calc the interval's magnitude */
1185 invl_mag = magnitude(interval/UINT64_C(1000000)1000000UL, 5);
1186
1187 /* Set or get the interval precision */
1188 if (interval == duration) {
1189 /*
1190 * An interval arg of 0 or an interval size exceeding the capture duration was specified.
1191 * Set the decimal precision of duration based on its magnitude. */
1192 if (dur_mag >= 2)
1193 invl_prec = 1;
1194 else if (dur_mag == 1)
1195 invl_prec = 3;
1196 else
1197 invl_prec = 6;
1198
1199 borderlen = 30 + dur_mag + (invl_prec == 0 ? 0 : invl_prec+1);
1200 } else {
1201 invl_prec = iot->invl_prec;
1202 borderlen = 25 + MAX(invl_mag,dur_mag)(((invl_mag) > (dur_mag)) ? (invl_mag) : (dur_mag)) + (invl_prec == 0 ? 0 : invl_prec+1);
1203 }
1204
1205 /* Round the duration according to invl_prec */
1206 dv = 1000000;
1207 for (i=0; i<invl_prec; i++)
1208 dv /= 10;
1209 if ((duration%dv) > 5*(dv/10)) {
1210 duration += 5*(dv/10);
1211 duration = (duration/dv) * dv;
1212 dur_secs = (unsigned int)(duration/UINT64_C(1000000)1000000UL);
1213 /*
1214 * Recalc dur_mag in case rounding has increased its magnitude */
1215 dur_mag = magnitude((uint64_t)dur_secs, 5);
1216 }
1217 if (iot->interval == UINT64_MAX(18446744073709551615UL))
1218 interval = duration;
1219
1220 /* This is the max width of a duration. */
1221 int dur_w = dur_mag + (invl_prec == 0 ? 0 : invl_prec+1);
1222 /* Add a space on the side, and make sure the width is at least as wide
1223 * as "Dur". ("Dur" does not need a space between it and "|".) */
1224 dur_w = MAX(dur_w + 1, 3)(((dur_w + 1) > (3)) ? (dur_w + 1) : (3));
1225
1226 /* Update the width of the time interval column if date is shown */
1227 switch (timestamp_get_type()) {
1228 case TS_ABSOLUTE_WITH_YMD:
1229 case TS_ABSOLUTE_WITH_YDOY:
1230 case TS_UTC_WITH_YMD:
1231 case TS_UTC_WITH_YDOY:
1232 // We don't show more than 6 fractional digits (+Z) currently.
1233 // NSTIME_ISO8601_BUFSIZE is enough room for 9 frac digits + Z + '\0'
1234 // That's 4 extra characters, which leaves room for the "| |".
1235 invl_col_w = NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z") + invl_prec - 6;
1236 break;
1237
1238 default:
1239 /* Calc the width of the time interval column (incl borders and padding,
1240 * which are "|" and " <" on each side.) */
1241 invl_col_w = 2*(dur_w + 3);
1242 break;
1243 }
1244
1245 /* Calculate the width and format string of all the other columns, and add
1246 * the total to the interval column width for the entire total. */
1247 tabrow_w = invl_col_w + iostat_calc_cols_width_and_fmt(iot, interval, col_w, fmts);
1248
1249 borderlen = MAX(borderlen, tabrow_w)(((borderlen) > (tabrow_w)) ? (borderlen) : (tabrow_w));
1250
1251 /* Calc the max width of the list of filters. */
1252 maxfltr_w = 0;
1253 for (j=0; j<num_cols; j++) {
1254 if (iot->filters[j]) {
1255 k = (unsigned int) (strlen(iot->filters[j]) + 11);
1256 maxfltr_w = MAX(maxfltr_w, k)(((maxfltr_w) > (k)) ? (maxfltr_w) : (k));
1257 } else {
1258 maxfltr_w = MAX(maxfltr_w, 26)(((maxfltr_w) > (26)) ? (maxfltr_w) : (26));
1259 }
1260 }
1261 /* The stat table is not wrapped (by tshark) but filter is wrapped at the width of the stats table
1262 * (which currently = borderlen); however, if the filter width exceeds the table width and the
1263 * table width is less than 102 bytes, set borderlen to the lesser of the max filter width and 102.
1264 * The filters will wrap at the lesser of borderlen-2 and the last space in the filter.
1265 * NOTE: 102 is the typical size of a user window when the font is fixed width (e.g., COURIER 10).
1266 * XXX: A pref could be added to change the max width from the default size of 102. */
1267 if (maxfltr_w > borderlen && borderlen < 102)
1268 borderlen = MIN(maxfltr_w, 102)(((maxfltr_w) < (102)) ? (maxfltr_w) : (102));
1269
1270 /* Prevent double right border by adding a space */
1271 if (borderlen-tabrow_w == 1)
1272 borderlen++;
1273
1274 nstime_t invl_time = NSTIME_INIT_SECS_USECS(interval/UINT64_C(1000000), interval%UINT64_C(1000000)){interval/1000000UL, interval%1000000UL*1000};
1275 iostat_draw_header(borderlen, iot, &cfile.elapsed_time, &invl_time, invl_prec);
1276
1277 iostat_draw_header_row(borderlen, iot, col_w, invl_col_w, tabrow_w);
1278
1279 t = 0;
1280
1281 if (interval == 0 || duration == 0) {
1282 num_rows = 0;
1283 } else {
1284 num_rows = (unsigned int)(duration/interval) + ((unsigned int)(duration%interval) > 0 ? 1 : 0);
1285 }
1286
1287 /* Load item_in_column with the first item in each column */
1288 item_in_column = (io_stat_item_t **)g_malloc(sizeof(io_stat_item_t *) * num_cols);
1289 for (j=0; j<num_cols; j++) {
1290 item_in_column[j] = stat_cols[j];
1291 }
1292
1293 /* Display the table values
1294 *
1295 * The outer loop is for time interval rows and the inner loop is for stat column items.*/
1296 for (i=0; i<num_rows; i++) {
1297
1298 if (i == num_rows-1)
1299 last_row = true1;
1300
1301 /* Compute the interval for this row */
1302 if (!last_row) {
1303 real_invl = interval;
1304 } else {
1305 real_invl = duration - t;
1306 }
1307
1308 /* Patch for Absolute Time */
1309 /* XXX - has a Y2.038K problem with 32-bit time_t */
1310 nstime_t the_time = NSTIME_INIT_SECS_USECS(t / 1000000, t % 1000000){t / 1000000, t % 1000000*1000};
1311
1312 /* Display the interval for this row */
1313 /* Get the string representing the start time of this interval. */
1314 fill_start_time(iot, &the_time, invl_prec, time_buf);
1315 /* Now add the surrounding column information according to our
1316 * output format (currently, only text table is supported.) */
1317 switch (timestamp_get_type()) {
1318
1319 case TS_RELATIVE:
1320 case TS_NOT_SET:
1321 /* For relative times, we show both ends of the interval. */
1322 printf("|%*s <", dur_w, time_buf);
1323 if (invl_prec == 0 && last_row) {
1324 g_strlcpy(time_buf, "Dur", NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"));
1325 } else {
1326 nstime_add(&the_time, &invl_time)nstime_sum(&the_time, &the_time, &invl_time);
1327 display_signed_time(time_buf, NSTIME_ISO8601_BUFSIZEsizeof("YYYY-MM-DDTHH:MM:SS.123456789Z"), &the_time, invl_prec);
1328 }
1329 printf("> %-*s|", dur_w, time_buf);
1330 break;
1331 default:
1332 printf("| %-*s |", invl_col_w - 4, time_buf);
1333 break;
1334 }
1335
1336 /* Display stat values in each column for this row */
1337 for (j=0; j<num_cols; j++) {
1338 fmt = fmts[j];
1339 item = item_in_column[j];
1340
1341 /* To try to optimize speed, we could copy the value string with
1342 * snprintf into a pre-allocated buffer with the maximum column
1343 * width, which we determined (though that's more error-prone.)
1344 */
1345 char *value = iostat_get_item_value(iot, item, fmt, j, real_invl);
1346 printf(" %s |", value);
1347 g_free(value);
1348
1349 if (item)
1350 item_in_column[j] = item_in_column[j]->next;
1351 }
1352 if (tabrow_w < borderlen) {
1353 printf("%*s", borderlen - tabrow_w, "|");
1354 }
1355 printf("\n");
1356 t += interval;
1357
1358 }
1359 for (i=0; i<borderlen; i++) {
1360 printf("=");
1361 }
1362 printf("\n");
1363 g_free(col_w);
1364 for (i=0; i<num_cols; ++i) {
1365 g_free(fmts[i]);
1366 }
1367 g_free(fmts);
1368 g_free(stat_cols);
1369 g_free(item_in_column);
1370}
1371
1372/* A new capture file is being loaded (or the current one reloaded),
1373 * reset our statistics.
1374 */
1375static void
1376iostat_reset(void *arg)
1377{
1378 io_stat_item_t *mit = (io_stat_item_t *)arg;
1379 io_stat_t *io = mit->parent;
1380
1381 nstime_set_unset(&io->start_time);
1382 io->last_relative_time = UINT64_C(0)0UL;
1383 for (unsigned int i=0; i<io->num_cols; i++) {
1384 iostat_item_reset(&io->items[i]);
1385 io->max_vals[i] = 0;
1386 io->max_frame[i] = 0;
1387 }
1388}
1389
1390/* Our listener is being removed, free our memory. */
1391static void
1392iostat_finish(void *arg)
1393{
1394 io_stat_item_t *mit = (io_stat_item_t *)arg;
1395 io_stat_t *io = mit->parent;
1396 iostat_io_free(io);
1397}
1398
1399/*
1400 * Register a new iostat tap for column number i.
1401 * The new tap's tapdata (see doc/README.tapping) is io->items[i], not io itself.
1402 * We only set the draw/reset/finish functions if i == 0 so everything is handled only once.
1403 */
1404static bool_Bool
1405register_io_tap(io_stat_t *io, unsigned int i, const char *filter, GString *err)
1406{
1407 GString *error_string;
1408 const char *flt;
1409 int j;
1410 size_t namelen;
1411 const char *p, *parenp;
1412 char *field;
1413 header_field_info *hfi;
1414
1415 io->items[i].prev = &io->items[i];
1416 io->items[i].next = NULL((void*)0);
1417 io->items[i].parent = io;
1418 io->items[i].start_time = 0;
1419 io->items[i].frames = 0;
1420 io->items[i].counter = 0;
1421 io->items[i].num = 0;
1422
1423 io->filters[i] = filter;
1424 flt = filter;
1425
1426 io->calc_type[i] = CALC_TYPE_FRAMES_AND_BYTES2;
1427 field = NULL((void*)0);
1428 hfi = NULL((void*)0);
1429 for (j=0; calc_type_table[j].func_name; j++) {
1430 namelen = strlen(calc_type_table[j].func_name);
1431 if (filter && strncmp(filter, calc_type_table[j].func_name, namelen) == 0) {
1432 io->calc_type[i] = calc_type_table[j].calc_type;
1433 io->items[i].colnum = i;
1434 if (*(filter+namelen) == '(') {
1435 p = filter+namelen+1;
1436 parenp = strchr(p, ')');
1437 if (!parenp) {
1438 cmdarg_err("\ntshark: Closing parenthesis missing from calculated expression.\n");
1439 return false0;
1440 }
1441
1442 if (io->calc_type[i] == CALC_TYPE_FRAMES0 || io->calc_type[i] == CALC_TYPE_BYTES1) {
1443 if (parenp != p) {
1444 cmdarg_err("\ntshark: %s does not require or allow a field name within the parens.\n",
1445 calc_type_table[j].func_name);
1446 return false0;
1447 }
1448 } else {
1449 if (parenp == p) {
1450 /* bail out if a field name was not specified */
1451 cmdarg_err("\ntshark: You didn't specify a field name for %s(*).\n",
1452 calc_type_table[j].func_name);
1453 return false0;
1454 }
1455 }
1456
1457 field = (char *)g_malloc(parenp-p+1);
1458 memcpy(field, p, parenp-p);
1459 field[parenp-p] = '\0';
1460 flt = parenp + 1;
1461 if (io->calc_type[i] == CALC_TYPE_FRAMES0 || io->calc_type[i] == CALC_TYPE_BYTES1)
1462 break;
1463 hfi = proto_registrar_get_byname(field);
1464 if (!hfi) {
1465 cmdarg_err("\ntshark: There is no field named '%s'.\n", field);
1466 g_free(field);
1467 return false0;
1468 }
1469
1470 io->hf_indexes[i] = hfi->id;
1471 break;
1472 }
1473 } else {
1474 if (io->calc_type[i] == CALC_TYPE_FRAMES0 || io->calc_type[i] == CALC_TYPE_BYTES1)
1475 flt = "";
1476 io->items[i].colnum = i;
1477 }
1478 }
1479 if (hfi && !(io->calc_type[i] == CALC_TYPE_BYTES1 ||
1480 io->calc_type[i] == CALC_TYPE_FRAMES0 ||
1481 io->calc_type[i] == CALC_TYPE_FRAMES_AND_BYTES2)) {
1482 /* check that the type is compatible */
1483 switch (hfi->type) {
1484 case FT_UINT8:
1485 case FT_UINT16:
1486 case FT_UINT24:
1487 case FT_UINT32:
1488 case FT_UINT64:
1489 case FT_INT8:
1490 case FT_INT16:
1491 case FT_INT24:
1492 case FT_INT32:
1493 case FT_INT64:
1494 /* these types support all calculations */
1495 break;
1496 case FT_FLOAT:
1497 case FT_DOUBLE:
1498 /* these types only support SUM, COUNT, MAX, MIN, AVG */
1499 switch (io->calc_type[i]) {
1500 case CALC_TYPE_SUM4:
1501 case CALC_TYPE_COUNT3:
1502 case CALC_TYPE_MAX6:
1503 case CALC_TYPE_MIN5:
1504 case CALC_TYPE_AVG7:
1505 break;
1506 default:
1507 cmdarg_err("\ntshark: %s is a float field, so %s(*) calculations are not supported on it.",
1508 field,
1509 calc_type_table[j].func_name);
1510 return false0;
1511 }
1512 break;
1513 case FT_RELATIVE_TIME:
1514 /* this type only supports SUM, COUNT, MAX, MIN, AVG, LOAD */
1515 switch (io->calc_type[i]) {
1516 case CALC_TYPE_SUM4:
1517 case CALC_TYPE_COUNT3:
1518 case CALC_TYPE_MAX6:
1519 case CALC_TYPE_MIN5:
1520 case CALC_TYPE_AVG7:
1521 case CALC_TYPE_LOAD8:
1522 break;
1523 default:
1524 cmdarg_err("\ntshark: %s is a relative-time field, so %s(*) calculations are not supported on it.",
1525 field,
1526 calc_type_table[j].func_name);
1527 return false0;
1528 }
1529 break;
1530 default:
1531 /*
1532 * XXX - support all operations on floating-point
1533 * numbers?
1534 */
1535 if (io->calc_type[i] != CALC_TYPE_COUNT3) {
1536 cmdarg_err("\ntshark: %s doesn't have integral values, so %s(*) "
1537 "calculations are not supported on it.\n",
1538 field,
1539 calc_type_table[j].func_name);
1540 return false0;
1541 }
1542 break;
1543 }
1544 }
1545 g_free(field);
1546
1547 error_string = register_tap_listener("frame", &io->items[i], flt, TL_REQUIRES_PROTO_TREE0x00000001,
1548 i ? NULL((void*)0) : iostat_reset,
1549 iostat_packet,
1550 i ? NULL((void*)0) : iostat_draw,
1551 i ? NULL((void*)0) : iostat_finish);
1552 if (error_string) {
1553 /* Accumulate errors about all the possible filters tried at the same
1554 * starting character.
1555 */
1556 if (err->len) {
1557 g_string_append_c(err, '\n')g_string_append_c_inline (err, '\n');
1558 }
1559 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))
;
1560 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)))))
;
1561 return false0;
1562 }
1563
1564 /* On success, clear old errors (from splitting on internal commas). */
1565 g_string_truncate(err, 0)g_string_truncate_inline (err, 0);
1566 return true1;
1567}
1568
1569static bool_Bool
1570iostat_init(const char *opt_arg, void *userdata _U___attribute__((unused)))
1571{
1572 double interval_float;
1573 uint32_t idx = 0;
1574 unsigned int i;
1575 io_stat_t *io;
1576 const char *filters, *str, *pos;
1577
1578 io_decimal_point = localeconv()->decimal_point;
1579
1580 /* XXX - Why can't the last character be a comma? Shouldn't it be
1581 * fine for the last filter to be empty? Even in the case of locales
1582 * that use ',' for the decimal separator, there shouldn't be any
1583 * difference between interpreting a terminating ',' as a decimal
1584 * point for the interval, and interpreting it as a separator followed
1585 * by an empty filter.
1586 */
1587 if ((*(opt_arg+(strlen(opt_arg)-1)) == ',') ||
1
Assuming the condition is false
4
Taking false branch
1588 (sscanf(opt_arg, "io,stat,%lf%n", &interval_float, (int *)&idx) != 1) ||
2
Assuming the condition is false
1589 (idx < 8)) {
3
Assuming 'idx' is >= 8
1590 cmdarg_err("\ntshark: invalid \"-z io,stat,<interval>[,<filter>][,<filter>]...\" argument\n");
1591 return false0;
1592 }
1593
1594 filters = opt_arg+idx;
1595 if (*filters) {
5
Assuming the condition is true
6
Taking true branch
1596 if (*filters != ',') {
7
Assuming the condition is false
8
Taking false branch
1597 /* For locales that use ',' instead of '.', the comma might
1598 * have been consumed during the floating point conversion. */
1599 --filters;
1600 if (*filters != ',') {
1601 cmdarg_err("\ntshark: invalid \"-z io,stat,<interval>[,<filter>][,<filter>]...\" argument\n");
1602 return false0;
1603 }
1604 }
1605 }
1606 /* filters now either starts with ',' or '\0' */
1607
1608 switch (timestamp_get_type()) {
9
Control jumps to the 'default' case at line 1614
1609 case TS_DELTA:
1610 case TS_DELTA_DIS:
1611 case TS_EPOCH:
1612 cmdarg_err("\ntshark: invalid -t operand. io,stat only supports -t <r|a|ad|adoy|u|ud|udoy>\n");
1613 return false0;
1614 default:
1615 break;
10
Execution continues on line 1618
1616 }
1617
1618 io = g_new0(io_stat_t, 1)((io_stat_t *) g_malloc0_n ((1), sizeof (io_stat_t)));
1619 io->last_relative_time = UINT64_C(0)0UL;
1620
1621 /* If interval is 0, calculate statistics over the whole file by setting the interval to
1622 * UINT64_MAX */
1623 if (interval_float == 0) {
11
Assuming 'interval_float' is equal to 0
12
Taking true branch
1624 io->interval = UINT64_MAX(18446744073709551615UL);
1625 io->invl_prec = 0;
1626 } else {
1627 /* Set interval to the number of us rounded to the nearest integer */
1628 io->interval = (uint64_t)(interval_float * 1000000.0 + 0.5);
1629 /*
1630 * Determine what interval precision the user has specified */
1631 io->invl_prec = 6;
1632 for (i=10; i<10000000; i*=10) {
1633 if (io->interval%i > 0)
1634 break;
1635 io->invl_prec--;
1636 }
1637 if (io->invl_prec == 0) {
1638 /* The precision is zero but if the user specified one of more zeros after the decimal point,
1639 they want that many decimal places shown in the table for all time intervals except
1640 response time values such as smb.time which always have 6 decimal places of precision.
1641 This feature is useful in cases where for example the duration is 9.1, you specify an
1642 interval of 1 and the last interval becomes "9 <> 9". If the interval is instead set to
1643 1.1, the last interval becomes
1644 last interval is rounded up to value that is greater than the duration. */
1645 const char *invl_start = opt_arg+8;
1646 unsigned invl_len;
1647
1648 invl_start = strpbrk(invl_start, ".,");
1649
1650 if (invl_start != NULL((void*)0) && *invl_start == '.') {
1651 invl_len = (unsigned)strcspn(invl_start + 1, ",");
1652 if (invl_len)
1653 io->invl_prec = MIN(invl_len, 6U)(((invl_len) < (6U)) ? (invl_len) : (6U));
1654 }
1655 }
1656 }
1657 if (io->interval
12.1
Field 'interval' is >= 1
< 1) {
13
Taking false branch
1658 cmdarg_err("\ntshark: \"-z\" interval must be >=0.000001 seconds or \"0\" for the entire capture duration.\n");
1659 iostat_io_free(io);
1660 return false0;
1661 }
1662
1663 /* Find how many ',' separated filters we have */
1664 /* Filter can have internal commas, so this is only an upper bound on the
1665 * number of filters. In the display filter grammar, commas only appear
1666 * inside delimiters (quoted strings, slices, sets, and functions), so
1667 * splitting in the wrong place produces an invalid filter. That is, there
1668 * can be at most only one valid interpretation (but might be none).
1669 *
1670 * XXX - If the grammar changes to allow commas in other places, then there
1671 * is ambiguity.
1672 *
1673 * Perhaps ideally we'd verify the filters before doing allocation.
1674 */
1675 io->num_cols = 1;
1676 nstime_set_unset(&io->start_time);
1677
1678 if (*filters != '\0') {
14
Assuming the condition is false
15
Taking false branch
1679 /* Eliminate the first comma. */
1680 filters++;
1681 str = filters;
1682 while ((str = strchr(str, ','))) {
1683 io->num_cols++;
1684 str++;
1685 }
1686 }
1687
1688 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
)))
;
1689 io->filters = (const char **)g_malloc(sizeof(char *) * io->num_cols);
1690 io->max_vals = g_new(uint64_t, io->num_cols)((uint64_t *) g_malloc_n ((io->num_cols), sizeof (uint64_t
)))
;
1691 io->max_frame = g_new(uint32_t, io->num_cols)((uint32_t *) g_malloc_n ((io->num_cols), sizeof (uint32_t
)))
;
1692 io->hf_indexes = g_new(int, io->num_cols)((int *) g_malloc_n ((io->num_cols), sizeof (int)));
1693 io->calc_type = g_new(int, io->num_cols)((int *) g_malloc_n ((io->num_cols), sizeof (int)));
1694
1695 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 1700
1696 io->max_vals[i] = 0;
1697 io->max_frame[i] = 0;
1698 }
1699
1700 bool_Bool success;
1701 GString *err = g_string_new(NULL((void*)0));
1702
1703 /* Register a tap listener for each filter */
1704 if (filters[0] == '\0') {
19
Assuming the condition is false
20
Taking false branch
1705 success = register_io_tap(io, 0, NULL((void*)0), err);
1706 } else {
1707 char *filter;
1708 i = 0;
1709 str = filters;
1710 pos = str;
1711 while ((pos = strchr(pos, ',')) != NULL((void*)0)) {
21
Assuming the condition is true
22
Loop condition is true. Entering loop body
1712 if (pos == str) {
23
Assuming 'pos' is not equal to 'str'
24
Taking false branch
1713 /* Consecutive commas - an empty filter. */
1714 filter = NULL((void*)0);
1715 } else {
1716 /* Likely a filter. */
1717 filter = (char *)g_malloc((pos-str)+1);
25
Memory is allocated
1718 (void) g_strlcpy( filter, str, (size_t) ((pos-str)+1));
1719 filter = g_strstrip(filter)g_strchomp (g_strchug (filter));
1720 }
1721 success = register_io_tap(io, i, filter, err);
26
Potential leak of memory pointed to by 'filter'
1722 /* Advance to the next position to look for commas. */
1723 pos++;
1724 if (success) {
1725 /* Also advance the filter start on success. */
1726 str = pos;
1727 i++;
1728 } else {
1729 g_free(filter);
1730 }
1731 }
1732 /* No more commas, the rest of the string is the last filter. */
1733 filter = g_strstrip(g_strdup(str))g_strchomp (g_strchug (g_strdup_inline (str)));
1734 if (*filter) {
1735 success = register_io_tap(io, i, filter, err);
1736 } else {
1737 success = register_io_tap(io, i, NULL((void*)0), err);
1738 }
1739 if (success) {
1740 i++;
1741 }
1742 io->num_cols = i;
1743 }
1744
1745 if (!success) {
1746 cmdarg_err("\ntshark: Couldn't register io,stat tap: %s\n",
1747 err->str);
1748 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)))))
;
1749 iostat_io_free(io);
1750 return false0;
1751 }
1752 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)))))
;
1753 return true1;
1754
1755}
1756
1757static stat_tap_ui iostat_ui = {
1758 REGISTER_STAT_GROUP_GENERIC,
1759 NULL((void*)0),
1760 "io,stat",
1761 iostat_init,
1762 0,
1763 NULL((void*)0)
1764};
1765
1766void
1767register_tap_listener_iostat(void)
1768{
1769 register_stat_tap_ui(&iostat_ui, NULL((void*)0));
1770}