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