### 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

Show analyzer invocation
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-09-06-100407-3660-1 -x c /builds/wireshark/wireshark/ui/cli/tap-iostat.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

1 | /* tap-iostat.c
2 | * iostat 2002 Ronnie Sahlberg
3 | *
4 | * Wireshark - Network traffic analyzer
5 | * By Gerald Combs <gerald@wireshark.org>
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 |
36 | void register_tap_listener_iostat(void);
37 |
38 | typedef struct {
39 | const char *func_name;
40 | int calc_type;
41 | } calc_type_ent_t;
42 |
43 | static 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 |
56 | typedef 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 |
71 | typedef 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 |
86 | static 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 | */
94 | static void
95 | iostat_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 | */
133 | static void
134 | iostat_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. */
150 | static tap_packet_status
151 | iostat_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 |
576 | static unsigned int
577 | magnitude (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 | */
592 | static void
593 | printcenter (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 |
611 | typedef 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 |
616 | static void
617 | fill_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 |
671 | static void
672 | fill_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 |
728 | static void
729 | fill_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 |
777 | static char*
778 | iostat_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*. */
854 | static unsigned
855 | iostat_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 |
956 | static void
957 | iostat_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 |
1019 | static void
1020 | iostat_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 |
1068 | static void
1069 | iostat_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 |
1149 | static void
1150 | iostat_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 | */
1380 | static void
1381 | iostat_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. */
1396 | static void
1397 | iostat_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 | */
1409 | static bool_Bool
1410 | register_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 |
1574 | static bool_Bool
1575 | iostat_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 |
1762 | static 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 |
1771 | void
1772 | register_tap_listener_iostat(void)
1773 | {
1774 | register_stat_tap_ui(&iostat_ui, NULL((void*)0));
1775 | }