Bug Summary

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