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