Bug Summary

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