File: | builds/wireshark/wireshark/ui/cli/tap-iostat.c |
Warning: | line 1551, column 23 Potential leak of memory pointed to by 'filter' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
32 | void register_tap_listener_iostat(void); | |||
33 | ||||
34 | typedef struct { | |||
35 | const char *func_name; | |||
36 | int calc_type; | |||
37 | } calc_type_ent_t; | |||
38 | ||||
39 | static 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 | ||||
52 | typedef 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 | ||||
66 | typedef 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 | ||||
83 | static uint64_t last_relative_time; | |||
84 | ||||
85 | static tap_packet_status | |||
86 | iostat_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 | ||||
512 | static unsigned int | |||
513 | magnitude (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 | */ | |||
528 | static void | |||
529 | printcenter (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 | ||||
547 | typedef 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 | ||||
552 | static void | |||
553 | iostat_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 | ||||
1231 | static bool_Bool | |||
1232 | register_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 | ||||
1399 | static void | |||
1400 | iostat_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)) == ',') || | |||
| ||||
1416 | (sscanf(opt_arg, "io,stat,%lf%n", &interval_float, (int *)&idx) != 1) || | |||
1417 | (idx < 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) { | |||
1424 | if (*filters != ',') { | |||
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()) { | |||
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))); | |||
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) { | |||
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
| |||
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') { | |||
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++) { | |||
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') { | |||
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)) { | |||
1542 | if (pos == str) { | |||
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); | |||
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); | |||
| ||||
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 | ||||
1587 | static 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 | ||||
1596 | void | |||
1597 | register_tap_listener_iostat(void) | |||
1598 | { | |||
1599 | register_stat_tap_ui(&iostat_ui, NULL((void*)0)); | |||
1600 | } |