| /************************************************************************ |
| Copyright (c) 2015, The Linux Foundation. All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are |
| met: |
| * Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| * Redistributions in binary form must reproduce the above |
| copyright notice, this list of conditions and the following |
| disclaimer in the documentation and/or other materials provided |
| with the distribution. |
| * Neither the name of The Linux Foundation nor the names of its |
| contributors may be used to endorse or promote products derived |
| from this software without specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| ************************************************************************/ |
| |
| /** |
| * @file datatop_dev_poll.c |
| * @brief Adds ability for data collection from /proc/net/dev |
| * |
| * File contains methods for searching and polling data from |
| * "/proc/net/dev" |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include "datatop_interface.h" |
| #include "datatop_fileops.h" |
| #include "datatop_str.h" |
| |
| #define DTOP_DEV_SIZE 8192 |
| #define DTOP_DEV_LINE (DTOP_DEV_SIZE>>2) |
| |
| /** |
| * @struct dtop_dev_vars |
| * @brief Struct used to hold necessary variables for /proc/net/dev dpg |
| * |
| * @var dtop_dev_vars::line |
| * Array of strings where necessary dp names and values are held. |
| * @var dtop_dev_vars::line_count |
| * Number of lines the file is that the dpg represents. |
| */ |
| struct dtop_dev_vars { |
| char **line; |
| int line_count; |
| }; |
| |
| /** |
| * @brief Parses lines with data in "/proc/net/dev" |
| * |
| * @param line1 Line to parse to find datapoint names and values. |
| * @param len1 Length of line1. |
| * @param index Index in the dictionary the key (name) is added to. |
| * @param dict Dictionary the keys and values are added to. |
| */ |
| static void dt_dev_parse(char *line1, int len1, |
| int index, struct dt_procdict *dict) |
| { |
| int i, start = 0; |
| int j, k, n; |
| i = 0; |
| while (line1[i] == ' ' || line1[i] == ' ') |
| i++; |
| dict->key[index] = &line1[i]; |
| for (i = 0; i < len1; i++) { |
| if (line1[i] == ':') { |
| line1[i+1] = 0; |
| start = i+2; |
| break; |
| } |
| } |
| |
| k = 0; |
| for (j = start; j < len1; j++) { |
| if (line1[j] != ' ' && line1[j] != ' ') { |
| dict->val[k] = &line1[j]; |
| n = j; |
| while (line1[n] != 0 && line1[n] != ' ' && line1[n] != ' ') |
| n++; |
| if (n < len1) |
| line1[n] = 0; |
| j = n; |
| k++; |
| } |
| } |
| } |
| |
| /** |
| * @brief Stores the data collected from "/proc/net/dev" |
| * |
| * @param dpg Struct that polled data is added to. |
| * @return DTOP_POLL_IO_ERR - Poll of dpg unsuccessful. |
| * @return DTOP_POLL_OK - Poll of dpg successful. |
| */ |
| int dtop_dev_poll(struct dtop_data_point_gatherer *dpg) |
| { |
| char *data; |
| int *line_len = malloc(sizeof(int) * |
| ((struct dtop_dev_vars *) |
| (dpg->priv))->line_count); |
| int read; |
| struct dt_procdict *dict = malloc(sizeof(struct dt_procdict) |
| *((struct dtop_dev_vars *) |
| (dpg->priv))->line_count-2); |
| int j, n, sum; |
| int index = 0; |
| int dp = 0; |
| |
| read = dt_read_file(dpg->file, &data, DTOP_DEV_SIZE); |
| if (read == 0 || data == 0) |
| return DTOP_POLL_IO_ERR; |
| |
| sum = 0; |
| /* Assigns each line read from the file, a length */ |
| for (n = 0; n < ((struct dtop_dev_vars *) |
| (dpg->priv))->line_count; n++) { |
| line_len[n] = dt_read_line(((struct dtop_dev_vars *) |
| (dpg->priv))->line[n], |
| DTOP_DEV_LINE, data, |
| DTOP_DEV_SIZE, sum); |
| if (n <= (((struct dtop_dev_vars *) |
| (dpg->priv))->line_count - 1)) { |
| sum += (line_len[n] + 1); |
| } |
| |
| } |
| |
| for (n = 2; n < ((struct dtop_dev_vars *) |
| (dpg->priv))->line_count; n++) { |
| dt_dev_parse(((struct dtop_dev_vars *) |
| (dpg->priv))->line[n], line_len[n], |
| index, &dict[index]); |
| index++; |
| } |
| |
| |
| /* Assigns the dp value to the dp struct */ |
| for (n = 2; n < ((struct dtop_dev_vars *) |
| (dpg->priv))->line_count; n++) { |
| for (j = 0; j < 16; j++) { |
| dtop_store_dp(&(dpg->data_points[dp]), |
| dict[n-2].val[j]); |
| dp++; |
| } |
| } |
| |
| dt_free(&data); |
| free(line_len); |
| free(dict); |
| return DTOP_POLL_OK; |
| } |
| |
| /** |
| * @brief Frees dynamically allocated "/proc/net/dev" dpg. |
| * |
| * Frees the memory of the dpg along with it's data_points |
| * and other malloc'd memory no longer needed. |
| * |
| * @param dpg Dpg to deconstruct and deallocate memory for. |
| */ |
| static void dtop_dev_dpg_deconstructor |
| (struct dtop_data_point_gatherer *dpset) |
| { |
| int i, j, dp; |
| dp = 0; |
| for (j = 0; j < ((((struct dtop_dev_vars *) |
| (dpset->priv))->line_count)-2); j++) { |
| for (i = 0; i < 16; i++) { |
| free(dpset->data_points[dp].prefix); |
| dp++; |
| } |
| } |
| free(dpset->data_points); |
| for (i = 0; i < ((struct dtop_dev_vars *) |
| (dpset->priv))->line_count; i++) |
| free(((struct dtop_dev_vars *)(dpset->priv))->line[i]); |
| free(((struct dtop_dev_vars *)(dpset->priv))->line); |
| free(((struct dtop_dev_vars *)(dpset->priv))); |
| free(dpset); |
| } |
| |
| /** |
| * @brief Creates a dpg for "/proc/net/dev" file |
| * |
| * Dynamically allocates memory for dpg which is then added to a linked list |
| * via the dtop_register(dpg) function call. |
| * |
| * @param data_points dtop_data_point struct that dpg points to. |
| * @param storage dtop_dev_vars struct that holds relevant dpg variables. |
| */ |
| static void construct_dev_file_dpg(struct dtop_dev_vars *storage, |
| int dp_count, struct dtop_data_point *data_points) |
| { |
| struct dtop_data_point_gatherer *dpg = malloc |
| (sizeof(struct dtop_data_point_gatherer)); |
| |
| dpg->prefix = "/proc/net/dev"; |
| dpg->file = "/proc/net/dev"; |
| dpg->poll = dtop_dev_poll; |
| dpg->data_points = data_points; |
| dpg->priv = (struct dtop_dev_vars *)storage; |
| dpg->data_points_len = dp_count; |
| dpg->deconstruct = dtop_dev_dpg_deconstructor; |
| |
| dtop_register(dpg); |
| } |
| |
| /** |
| * @brief Scans "/proc/net/dev in order to autodetect dps. |
| * |
| * Searches through "/proc/net/dev" file for all available data |
| * points to create as dp structs. |
| * |
| * @param name This is the file name "/proc/net/dev" passed in by dtop_dev_init |
| * @param storage dtop_dev_vars struct where relevant variables are stored. |
| */ |
| int dtop_dev_search(char *name, struct dtop_dev_vars *storage) |
| { |
| int i, n, sum; |
| char *data; |
| int *line_len = malloc(sizeof(int) * storage->line_count); |
| int read; |
| struct dt_procdict dict; |
| struct dt_procdict dev_dict; |
| struct dtop_data_point *data_points = malloc |
| (sizeof(struct dtop_data_point) * 16 * (storage->line_count-2)); |
| int dp_count = (16 * (storage->line_count - 2)); |
| int index = 0; |
| int dp = 0; |
| |
| storage->line = malloc(storage->line_count * sizeof(*storage->line)); |
| |
| for (i = 0; i < storage->line_count; i++) |
| storage->line[i] = malloc(sizeof(char) * DTOP_DEV_LINE); |
| |
| dev_dict.val[0] = "bytes"; |
| dev_dict.val[1] = "packets"; |
| dev_dict.val[2] = "errs"; |
| dev_dict.val[3] = "drop"; |
| dev_dict.val[4] = "fifo"; |
| dev_dict.val[5] = "frame"; |
| dev_dict.val[6] = "compressed"; |
| dev_dict.val[7] = "multicast"; |
| dev_dict.val[8] = "bytes"; |
| dev_dict.val[9] = "packets"; |
| dev_dict.val[10] = "errs"; |
| dev_dict.val[11] = "drop"; |
| dev_dict.val[12] = "fifo"; |
| dev_dict.val[13] = "colls"; |
| dev_dict.val[14] = "carrier"; |
| dev_dict.val[15] = "compressed"; |
| |
| read = dt_read_file(name, &data, DTOP_DEV_SIZE); |
| if (read == 0 || data == 0) |
| return DTOP_POLL_IO_ERR; |
| |
| sum = 0; |
| /* Assigns each line read from the file, a length */ |
| for (n = 0; n < storage->line_count; n++) { |
| line_len[n] = dt_read_line(storage->line[n], |
| DTOP_DEV_LINE, data, |
| DTOP_DEV_SIZE, sum); |
| if (n < (storage->line_count - 1)) |
| sum += (line_len[n] + 1); |
| } |
| |
| construct_dev_file_dpg(storage, dp_count, data_points); |
| |
| for (n = 2; n < storage->line_count; n++) { |
| dt_dev_parse(storage->line[n], line_len[n], index, &dict); |
| index++; |
| } |
| |
| for (n = 2; n < storage->line_count; n++) { |
| for (i = 0; i < 16; i++) { |
| char *pref = malloc(30 * sizeof(char)); |
| data_points[dp].skip = 0; |
| data_points[dp].initial_data_populated = NOT_POPULATED; |
| if (i < 8) |
| strlcpy(pref, "Receive:", 30 * sizeof(char)); |
| else if (i >= 8) |
| strlcpy(pref, "Transmit:", 30 * sizeof(char)); |
| strlcat(pref, dev_dict.val[i], 30 * sizeof(char)); |
| data_points[dp].prefix = pref; |
| data_points[dp].name = dict.key[n-2]; |
| data_points[dp].type = DTOP_ULONG; |
| dp++; |
| } |
| index++; |
| } |
| |
| free(line_len); |
| dt_free(&data); |
| return DTOP_POLL_OK; |
| } |
| |
| /** |
| * @brief Calls dtop_search for "/proc/net/dev" file. |
| */ |
| void dtop_dev_init(void) |
| { |
| struct dtop_dev_vars *storage = malloc |
| (sizeof(struct dtop_dev_vars)); |
| storage->line_count = dtop_get_file_line_amount("/proc/net/dev"); |
| dtop_dev_search("/proc/net/dev", storage); |
| } |