diff options
46 files changed, 6695 insertions, 0 deletions
diff --git a/dataservices/Android.mk b/dataservices/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/dataservices/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/dataservices/Makefile.am b/dataservices/Makefile.am new file mode 100755 index 0000000..f2ad6f9 --- /dev/null +++ b/dataservices/Makefile.am @@ -0,0 +1,11 @@ +# Makefile.am - Automake script for Data-opensource +# + +ACLOCAL_AMFLAGS = -I m4 +AUTOMAKE_OPTIONS = foreign +SUBDIRS = rmnetctl/src rmnetctl/cli + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = data-oss.pc +EXTRA_DIST = $(pkgconfig_DATA) + diff --git a/dataservices/configure.ac b/dataservices/configure.ac new file mode 100644 index 0000000..b6901ee --- /dev/null +++ b/dataservices/configure.ac @@ -0,0 +1,51 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. +AC_PREREQ([2.65]) +AC_INIT([data-oss], [1.0.0]) +AM_INIT_AUTOMAKE +AC_OUTPUT(Makefile rmnetctl/src/Makefile rmnetctl/cli/Makefile data-oss.pc) +AC_CONFIG_SRCDIR([rmnetctl/src/librmnetctl.c]) +#AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL +PKG_PROG_PKG_CONFIG + +# Checks for libraries. +AC_ARG_WITH(sanitized-headers, + AS_HELP_STRING([--with-sanitized-headers=DIR], + [Specify the location of the sanitized Linux headers]), + [CPPFLAGS="$CPPFLAGS -idirafter $withval"]) + +AC_ARG_WITH([glib], + AC_HELP_STRING([--with-glib], + [enable glib, building HLOS systems which use glib])) + +if (test "x${with_glib}" = "xyes"); then + AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib]) + PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes, + AC_MSG_ERROR(GThread >= 2.16 is required)) + PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes, + AC_MSG_ERROR(GLib >= 2.16 is required)) + GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS" + GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS" + AC_SUBST(GLIB_CFLAGS) + AC_SUBST(GLIB_LIBS) +fi + +AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes") + +# Checks for header files. +AC_CHECK_HEADERS([sys/socket.h stdint.h linux/netlink.h string.h stdio.h unistd.h stdlib.h linux/rmnet_data.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_OFF_T + +# Checks for library functions. +AC_FUNC_MALLOC + +#AC_FUNC_MMAP +#AC_CHECK_FUNCS([memset malloc sendto recvfrom ]) +AC_OUTPUT diff --git a/dataservices/data-oss.pc.in b/dataservices/data-oss.pc.in new file mode 100644 index 0000000..7c268df --- /dev/null +++ b/dataservices/data-oss.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: data-oss +Description: Data Opensource Components +Version: @VERSION@ +Libs: -L${libdir} -lrmnetctl +Cflags: -I${includedir}/data-oss diff --git a/dataservices/datatop/Android.mk b/dataservices/datatop/Android.mk new file mode 100644 index 0000000..8338432 --- /dev/null +++ b/dataservices/datatop/Android.mk @@ -0,0 +1,2 @@ +include $(call all-subdir-makefiles) + diff --git a/dataservices/datatop/Makefile.am b/dataservices/datatop/Makefile.am new file mode 100644 index 0000000..15ea2b3 --- /dev/null +++ b/dataservices/datatop/Makefile.am @@ -0,0 +1,3 @@ +AUTOMAKE_OPTIONS = foreign + +SUBDIRS = src diff --git a/dataservices/datatop/autogen.sh b/dataservices/datatop/autogen.sh new file mode 100644 index 0000000..7141954 --- /dev/null +++ b/dataservices/datatop/autogen.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +# 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. + +ACLOCAL=`which aclocal` +AUTOCONF=`which autoconf` +AUTOMAKE=`which automake` + +if [ ! -x "$ACLOCAL" ]; then + echo "Missing 'aclocal'; not in path. Make sure it is installed!" + exit -1 +fi + +if [ ! -x "$AUTOCONF" ]; then + echo "Missing 'autoconf'; not in path. Make sure it is installed!" + exit -1 +fi + +if [ ! -x "$AUTOMAKE" ]; then + echo "Missing 'automake'; not in path. Make sure it is installed!" + exit -1 +fi + +$ACLOCAL +$AUTOCONF +$AUTOMAKE -a diff --git a/dataservices/datatop/configure.ac b/dataservices/datatop/configure.ac new file mode 100644 index 0000000..b9f9abf --- /dev/null +++ b/dataservices/datatop/configure.ac @@ -0,0 +1,56 @@ +# -*- Autoconf -*- + +# 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. + +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.68]) +AC_INIT([Data Top], [1.0.4], [harouth@codeaurora.org]) +AC_CONFIG_SRCDIR([src/datatop.c]) +#AC_CONFIG_HEADERS([src/config.h]) +AC_CONFIG_FILES([Makefile + src/Makefile]) + +# Checks for programs. +AC_PROG_CC + +# Checks for libraries. + +# Checks for header files. +AC_CHECK_HEADERS([stdlib.h string.h]) + +# Checks for typedefs, structures, and compiler characteristics. + +# Checks for library functions. +AC_FUNC_MALLOC + + +#### Generate Makefile Data +AM_INIT_AUTOMAKE([datatop], [1.0.4]) + +AC_OUTPUT diff --git a/dataservices/datatop/src/Android.mk b/dataservices/datatop/src/Android.mk new file mode 100644 index 0000000..264f11c --- /dev/null +++ b/dataservices/datatop/src/Android.mk @@ -0,0 +1,32 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := datatop.c +LOCAL_SRC_FILES += datatop_cpu_stats_poll.c +LOCAL_SRC_FILES += datatop_dev_poll.c +LOCAL_SRC_FILES += datatop_dual_line_poll.c +LOCAL_SRC_FILES += datatop_fileops.c +LOCAL_SRC_FILES += datatop_gen_poll.c +LOCAL_SRC_FILES += datatop_helpers.c +LOCAL_SRC_FILES += datatop_linked_list.c +LOCAL_SRC_FILES += datatop_meminfo_file_poll.c +LOCAL_SRC_FILES += datatop_opt.c +LOCAL_SRC_FILES += datatop_single_line_poll.c +LOCAL_SRC_FILES += datatop_stat_poll.c +LOCAL_SRC_FILES += datatop_str.c +LOCAL_SRC_FILES += datatop_sys_snap.c +LOCAL_SRC_FILES += datatop_value_only_poll.c + +LOCAL_CFLAGS := -Wall -Wextra -Werror -pedantic -std=c99 +LOCAL_CFLAGS += -DVERSION="\"1.0.4"\" +LOCAL_CFLAGS += -DHAVE_STRL_FUNCTIONS +LOCAL_CFLAGS += -D _BSD_SOURCE + +LOCAL_C_INCLUDES := $(LOCAL_PATH) + +LOCAL_CLANG := true +LOCAL_MODULE := datatop +LOCAL_MODULE_TAGS := optional + +include $(BUILD_EXECUTABLE) diff --git a/dataservices/datatop/src/Makefile.am b/dataservices/datatop/src/Makefile.am new file mode 100644 index 0000000..5dd0469 --- /dev/null +++ b/dataservices/datatop/src/Makefile.am @@ -0,0 +1,22 @@ +## Makefile.am for main application + +CFLAGS := -std=c99 # Target c99 for portability +CFLAGS += -Wall -Wextra -Werror -pedantic # Strict code quality enforcement +CFLAGS += -g -D _BSD_SOURCE # Enable debugging and BSD time functions + +bin_PROGRAMS = datatop +datatop_SOURCES := datatop.c +datatop_SOURCES += datatop_fileops.c +datatop_SOURCES += datatop_dual_line_poll.c +datatop_SOURCES += datatop_single_line_poll.c +datatop_SOURCES += datatop_meminfo_file_poll.c +datatop_SOURCES += datatop_dev_poll.c +datatop_SOURCES += datatop_stat_poll.c +datatop_SOURCES += datatop_value_only_poll.c +datatop_SOURCES += datatop_str.c +datatop_SOURCES += datatop_cpu_stats_poll.c +datatop_SOURCES += datatop_helpers.c +datatop_SOURCES += datatop_linked_list.c +datatop_SOURCES += datatop_opt.c +datatop_SOURCES += datatop_gen_poll.c +datatop_SOURCES += datatop_sys_snap.c diff --git a/dataservices/datatop/src/datatop.c b/dataservices/datatop/src/datatop.c new file mode 100644 index 0000000..f079c30 --- /dev/null +++ b/dataservices/datatop/src/datatop.c @@ -0,0 +1,283 @@ +/************************************************************************ +Copyright (c) 2015-2016, 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.c +* @brief Executes commands for application. +* +* Contains the main() function where program executes. Calls appropriate +* methods based on user's CLI commands. Executes parsing function to +* determine necessary output and handles errors which may arise during the +* parse. Initiliazes files for data collection. Will call functions designed +* to poll and print the data in understandable format. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include "datatop_interface.h" +#include "datatop_linked_list.h" +#include "datatop_opt.h" +#include "datatop_fileops.h" +#include "datatop_polling.h" +#include "datatop_gen_poll.h" + +struct dtop_linked_list *first_dpg_list; +struct cli_opts usr_cl_opts; + +/** + * @brief Prints the datapoint names and values to the terminal. + * + * @param dpg_list A pointer to the first node of a linked list which + * contains all data_point_gatherer structs to print. + */ +void dtop_print_terminal(struct dtop_linked_list *dpg_list) +{ + struct dtop_linked_list *curr_ptr = dpg_list; + struct dtop_data_point_gatherer *dpset; + + while (curr_ptr) { + dpset = (struct dtop_data_point_gatherer *) curr_ptr->data; + dtop_print_dpg(dpset); + curr_ptr = curr_ptr->next_ptr; + } +} + +/** + * @brief Polls the data periodically and prints to file specified by the user. + * + * Polls the data as often as specified by the user in their CLI arguments + * and outputs the data to a file also specified in CLI arguments. Then prints + * a snapshot of delta(dp_value) to the terminal. + * + * @param dpg_list A pointer to the first node of a linked list which contains + * all data_point_gatherer structs to poll and print. + * @param fw A pointer to the file which will be printed to. + * @return FILE_ERROR - Writing to file was unsuccessful. + * @return FILE_SUCCESS - Writing to file was successful. + */ +int dtop_poll_periodically(struct dtop_linked_list *dpg_list, FILE *fw) +{ + struct timeval tv, timeout; + fd_set rfds; + time_t curtime, endtime; + int inp, quit = 0; + struct dtop_linked_list *curr_ptr = dpg_list; + struct dtop_data_point_gatherer *dpset; + struct timeval ftime, itime, polltime; + + gettimeofday(&tv, NULL); + curtime = tv.tv_sec; + endtime = tv.tv_sec + usr_cl_opts.poll_time; + + /* print all of our datapoint names as column headers in csv format */ + if (fprintf(fw, "\"Time\",") < 0) + return FILE_ERROR; + + while (curr_ptr) { + dpset = (struct dtop_data_point_gatherer *) curr_ptr->data; + if (dtop_print_dpg_names_csv(dpset, fw) == FILE_ERROR) + return FILE_ERROR; + curr_ptr = curr_ptr->next_ptr; + } + if (fprintf(fw, "\n") < 0) + return FILE_ERROR; + + dtop_print_interactive_opts(); + gettimeofday(&itime, NULL); + /* periodically poll the datapoints and print in csv format */ + while (curtime < endtime + || usr_cl_opts.poll_time == POLL_NOT_SPECIFIED) { + FD_ZERO(&rfds); + FD_SET(0, &rfds); + timeout.tv_sec = usr_cl_opts.poll_per; + timeout.tv_usec = 0; + //ftime is right before timeout calculations for most acurate calculations + gettimeofday(&ftime, NULL); + timersub(&ftime, &itime, &polltime); + timersub(&timeout,&polltime, &timeout); + inp = select(1, &rfds, NULL, NULL, &timeout); + gettimeofday(&itime, NULL); + if (inp) { + char s[4]; + scanf("%s", s); + if (strcmp(s, "quit") == 0 + || strcmp(s, "q") == 0) { + quit = QUIT; + break; + } + if (strcmp(s, "i") == 0) { + dtop_print_snapshot_diff(first_dpg_list); + dtop_reset_dp_initial_values(first_dpg_list); + } + if (strcmp(s, "l") == 0) + dtop_print_snapshot_diff(first_dpg_list); + } + gettimeofday(&tv, NULL); + curtime = tv.tv_sec; + dtop_poll(dpg_list); + printf("Polled at %ld.%06ld\n", tv.tv_sec, tv.tv_usec); + if (dtop_print_time_at_poll(fw) == FILE_ERROR) + return FILE_ERROR; + if (dtop_write_pollingdata_csv(dpg_list, fw) == FILE_ERROR) + return FILE_ERROR; + } + + if (quit != QUIT) + dtop_print_snapshot_diff(dpg_list); + return FILE_SUCCESS; +} + +static void dtop_set_niceness(int niceness) +{ + int pid, rc; + pid = getpid(); + printf("Requesting nice %d\n", niceness); + rc = setpriority(PRIO_PROCESS, pid, niceness); + if (rc != 0) + fprintf(stderr, "Error setting priority [%d]\n", errno); + + rc = getpriority(PRIO_PROCESS, pid); + printf("Running with nice %d.\n", rc); +} + +int main(int argc, char **argv) +{ + int parse_status; + printf("DataTop - Version %s\n", VERSION); + printf("(c)2014-2015 Linux Foundation\n"); + + dtop_load_default_options(&usr_cl_opts); + + parse_status = dtop_parse_cli_opts(&usr_cl_opts, argc, argv); + switch (parse_status) { + case PARSE_SUCCESS: + dtop_set_niceness(usr_cl_opts.priority); + break; + + case PARSE_FORCE_EXIT: + exit(EXIT_SUCCESS); + break; + + case PARSE_FAILURE: + default: + printf("Failed to parse command line arguments.\n"); + exit(EXIT_FAILURE); + break; + } + + dtop_dual_line_init("/proc/net/netstat"); + dtop_dual_line_init("/proc/net/snmp"); + dtop_single_line_init("/proc/net/snmp6"); + dtop_gen_init("/proc/sys/net/"); + dtop_gen_init("/sys/module/rmnet_data/parameters/"); + dtop_gen_init("/sys/class/net/rmnet_mhi0/statistics/"); + dtop_gen_init("/sys/class/net/usb_rmnet0/statistics/"); + dtop_gen_init("/sys/class/net/rmnet_ipa0/statistics/"); + dtop_meminfo_init(); + dtop_dev_init(); + dtop_stat_init(); + dtop_cpu_stats_init(); + dtop_gen_init("/sys/kernel/debug/clk/bimc_clk/"); + dtop_gen_init("/sys/kernel/debug/clk/snoc_clk/"); + dtop_gen_init("/sys/kernel/debug/clk/pnoc_clk/"); + + if (usr_cl_opts.print_cl == OPT_CHOSE) { + dtop_poll(first_dpg_list); + dtop_print_terminal(first_dpg_list); + } + + if (usr_cl_opts.print_csv == OPT_CHOSE) { + FILE *to_file = NULL; + if ((dtop_open_writing_file(usr_cl_opts.file_name, + &to_file)) == VALID) { + printf("\nData being polled for %ld seconds.\n", + usr_cl_opts.poll_time); + if (dtop_poll_periodically(first_dpg_list, to_file) + == FILE_ERROR) { + fprintf(stderr, "err=%d: %s\n", errno, + strerror(errno)); + dtop_close_file(to_file); + deconstruct_dpgs(first_dpg_list); + dtop_rem_linked_list(first_dpg_list); + exit(EXIT_FAILURE); + } + dtop_close_file(to_file); + } else { + printf("File Can Not Be Opened\n"); + exit(EXIT_FAILURE); + } + } + + if (usr_cl_opts.snapshot_file) { + if (dtop_print_system_snapshot(usr_cl_opts.snapshot_file) + == FILE_ERROR) { + fprintf(stderr, "err=%d: %s\n", errno, + strerror(errno)); + deconstruct_dpgs(first_dpg_list); + dtop_rem_linked_list(first_dpg_list); + exit(EXIT_FAILURE); + } + } + + if (usr_cl_opts.print_cl == OPT_NOT_CHOSE && + usr_cl_opts.print_csv == OPT_NOT_CHOSE) { + if ((!usr_cl_opts.snapshot_file) + || usr_cl_opts.poll_time_selected == POLL_TIME_SELECTED) { + printf("\nData will now be polled for %ld seconds.\n", + usr_cl_opts.poll_time); + dtop_poll(first_dpg_list); + sleep(usr_cl_opts.poll_time); + dtop_poll(first_dpg_list); + dtop_print_snapshot_diff(first_dpg_list); + } + } + + deconstruct_dpgs(first_dpg_list); + dtop_rem_linked_list(first_dpg_list); + return 0; +} + +/** + * @brief Adds each dpg as a node to a linked list. + * + * Called when a dpg is initialized. + * + * @param dpg A pointer to a data_point_gatherer struct which is to be added to the linked list. + */ +void dtop_register(struct dtop_data_point_gatherer *dpg) +{ + if (dpg) + first_dpg_list = dtop_add_linked_list(dpg, first_dpg_list); +} diff --git a/dataservices/datatop/src/datatop_cpu_stats_poll.c b/dataservices/datatop/src/datatop_cpu_stats_poll.c new file mode 100644 index 0000000..275ddd8 --- /dev/null +++ b/dataservices/datatop/src/datatop_cpu_stats_poll.c @@ -0,0 +1,182 @@ +/************************************************************************ +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_cpu_stats_poll.c + * @brief Calls dtop_value_only_init for necessary cpu datapoints. + * + * File contains methods for determing number of cpu's online and calling + * correct initialization function to gather scaling_cur_freq data point + * for each cpu along with each cpu's online status. + */ + +#include <unistd.h> +#include <stdio.h> +#include <dirent.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <ctype.h> +#include "datatop_interface.h" +#include "datatop_fileops.h" +#include "datatop_str.h" +#include "datatop_polling.h" + +#define DTOP_GEN_SIZE 8192 +#define DTOP_GEN_LINE (DTOP_GEN_SIZE>>2) +#define NO_CPUS_ONLINE -1 + +/** + * @brief Searches /sys/devices/system/cpu/ directory to get find number of CPUs. + * + * @return Number of CPUs found in directory. + */ +static int dtop_cpu_search(void) +{ + DIR *dp; + struct dirent *entry; + struct stat s; + int cpu_amt; + char cwd[1024]; + + if (!getcwd(cwd, sizeof(cwd))) { + fprintf(stderr, "Failed to get current working dir\n"); + return -1; + } + + dp = opendir("/sys/devices/system/cpu/"); + if (dp == NULL) { + fprintf(stderr, "err=%d: %s\n", errno, strerror(errno)); + fprintf(stderr, "Cannot open directory: %s\n", + "/sys/devices/system/cpu/"); + return NO_CPUS_ONLINE; + } + + chdir("/sys/devices/system/cpu/"); + cpu_amt = 0; + while ((entry = readdir(dp))) { + if (stat(entry->d_name, &s)) { + printf("stat err=%d: %s\n", errno, strerror(errno)); + return NO_CPUS_ONLINE; + } + + if (entry->d_name[0] == 'c' && + entry->d_name[1] == 'p' && + entry->d_name[2] == 'u' && + (isdigit(entry->d_name[3]))) { + + cpu_amt++; + } + } + + closedir(dp); + chdir(cwd); + return cpu_amt; +} + +/** + * @brief Creates a dpg designed for CPU online and CPU scaling_cur_freq stats. + * + * @param name Name of file dpg represents. + */ +static void construct_cpu_stat_dpg(char *name) +{ + char *file = malloc(strlen(name) + 1); + struct dtop_data_point *dp = + malloc(sizeof(struct dtop_data_point)); + struct dtop_data_point_gatherer *dpg = malloc + (sizeof(struct dtop_data_point_gatherer)); + + strlcpy(file, name, strlen(name) + 1); + + dp[0].type = DTOP_ULONG; + dp[0].name = malloc(5); + strlcpy(dp[0].name, "", 5); + dp[0].prefix = NULL; + dp[0].data.d_ulong = 0; + dp[0].initial_data.d_ulong = 0; + dp[0].skip = DO_NOT_SKIP; + dp[0].initial_data_populated = NOT_POPULATED; + + dpg->prefix = file; + dpg->file = file; + dpg->poll = dtop_value_only_poll; + dpg->data_points = dp; + dpg->data_points_len = 1; + dpg->deconstruct = dtop_value_only_dpg_deconstructor; + + dtop_register(dpg); +} + +/** + * @brief Calls dpg constructor for necessary CPU stat files. + * + * Creates file names based on number of CPUs found and calls the + * dpg constructor for them. + * + * @param file Directory where the CPUs are found. + * @param add String which is concatenated onto file and represents + * the path after a CPU directory is entered. + * @param cpu_amt Amount of CPUs found on device. + */ +static void cpu_poll_helper(char *file, char *add, int cpu_amt) +{ + int i; + for (i = 0; i < cpu_amt; i++) { + char *cpu_num = malloc(5); + char *newfile; + int nf_len; + snprintf(cpu_num, 5, "%d", i); + nf_len = strlen(file) + strlen(add) + strlen(cpu_num) + 2; + newfile = malloc(nf_len); + strlcpy(newfile, file, nf_len); + strlcat(newfile, cpu_num, nf_len); + strlcat(newfile, add, nf_len); + free(cpu_num); + construct_cpu_stat_dpg(newfile); + free(newfile); + } +} + +/** + * @brief Calls necessary functions for CPU stat dpgs. + */ +void dtop_cpu_stats_init(void) +{ + int cpu_amt; + char *file = "/sys/devices/system/cpu/cpu"; + char *add = "/cpufreq/scaling_cur_freq"; + + cpu_amt = dtop_cpu_search(); + cpu_poll_helper(file, add, cpu_amt); + add = "/online"; + cpu_poll_helper(file, add, cpu_amt); +} diff --git a/dataservices/datatop/src/datatop_dev_poll.c b/dataservices/datatop/src/datatop_dev_poll.c new file mode 100644 index 0000000..0dcab1e --- /dev/null +++ b/dataservices/datatop/src/datatop_dev_poll.c @@ -0,0 +1,320 @@ +/************************************************************************ +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] != ' ' && 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); +} diff --git a/dataservices/datatop/src/datatop_dual_line_poll.c b/dataservices/datatop/src/datatop_dual_line_poll.c new file mode 100644 index 0000000..8ada0c1 --- /dev/null +++ b/dataservices/datatop/src/datatop_dual_line_poll.c @@ -0,0 +1,319 @@ +/************************************************************************ +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_dual_line_poll.c + * @brief Adds ability for data collection from dual line files. + * + * File contains methods for searching and polling data from + * dual line files, meaning the first line contains the dp names + * while the second line contains the corresponding values. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "datatop_interface.h" +#include "datatop_fileops.h" +#include "datatop_str.h" + +#define DTOP_DUAL_SIZE 8192 +#define DTOP_DUAL_LINE (DTOP_DUAL_SIZE>>2) + +/** +* @struct dtop_dual_line_vars +* @brief Struct used to hold necessary variables for dual_line_file dpgs. +* +* @var dtop_dual_line_vars::line +* Array of strings where necessary dp names and values are held. +* @var dtop_dual_line_vars::line2 +* Array of strings where necessary dp names and values are held. +* @var dtop_dual_line_vars::line_count +* Number of lines the file is that the dpg represents. +*/ +struct dtop_dual_line_vars { + char **line; + char **line2; + int line_count; +}; + +/** + * @brief Stores the data collected from a dual_line file. + * + * @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_dual_line_poll(struct dtop_data_point_gatherer *dpg) +{ + char *data; + int *line_len = malloc(sizeof(int) * + ((struct dtop_dual_line_vars *) + (dpg->priv))->line_count); + int *line_len2 = malloc(sizeof(int) * + ((struct dtop_dual_line_vars *) + (dpg->priv))->line_count); + int read; + + struct dt_procdict *dict = malloc(sizeof(struct dt_procdict) + * (((struct dtop_dual_line_vars *) + (dpg->priv))->line_count/2)); + struct dt_procdict *prefix_dict = malloc(sizeof(struct dt_procdict) + * (((struct dtop_dual_line_vars *) + (dpg->priv))->line_count/2)); + int i, j, k, n, sum, sum2; + + read = dt_read_file(dpg->file, &data, DTOP_DUAL_SIZE); + if (read == 0 || data == 0) + return DTOP_POLL_IO_ERR; + + sum = 0; + sum2 = 0; + /* Assigns each line read from the file, a length */ + for (n = 0; n < ((struct dtop_dual_line_vars *) + (dpg->priv))->line_count; n++) { + line_len[n] = dt_read_line(((struct dtop_dual_line_vars *) + (dpg->priv))->line[n], + DTOP_DUAL_LINE, data, + DTOP_DUAL_SIZE, sum); + line_len2[n] = dt_read_line(((struct dtop_dual_line_vars *) + (dpg->priv))->line2[n], + DTOP_DUAL_LINE, data, + DTOP_DUAL_SIZE, sum2); + if (n <= (((struct dtop_dual_line_vars *) + (dpg->priv))->line_count-2)) { + sum += (line_len[n] + 1); + sum2 += (line_len2[n] + 1); + } + + } + + /* Stores dp names and values in dictionary */ + for (i = 0; i < (((struct dtop_dual_line_vars *) + (dpg->priv))->line_count/2); i++) + dt_parse_proc_dictionary(((struct dtop_dual_line_vars *) + (dpg->priv))->line[2*i], + line_len[2*i], + ((struct dtop_dual_line_vars *) + (dpg->priv))->line[(2*i)+1], + line_len[(2*i)+1], + &dict[i]); + + /* Stores dp prefices in dictionary */ + for (i = 0; i < (((struct dtop_dual_line_vars *) + (dpg->priv))->line_count/2); i++) + dt_parse_for_prefix(((struct dtop_dual_line_vars *) + (dpg->priv))->line2[2*i], line_len2[2*i], + &prefix_dict[i]); + + /* Assigns a dp value to each dp struct */ + for (k = 0; k < (((struct dtop_dual_line_vars *) + (dpg->priv))->line_count/2); k++) { + for (j = 0; j < dpg->data_points_len; j++) { + i = dt_find_dict_idx(dpg->data_points[j].name, + &dict[k]); + if (i >= 0 && i < dict[k].max && + (strcmp(dpg->data_points[j].prefix, + prefix_dict[k].val[i]) == 0)) + + dtop_store_dp(&(dpg->data_points[j]), + dict[k].val[i]); + } + } + + dt_free(&data); + free(line_len); + free(line_len2); + free(dict); + free(prefix_dict); + return DTOP_POLL_OK; +} + +/** + * @brief Frees dynamically allocated dual_line_file dpgs. + * + * 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_dual_line_dpg_deconstructor + (struct dtop_data_point_gatherer *dpset) +{ + int i; + free(dpset->data_points); + for (i = 0; i < ((struct dtop_dual_line_vars *) + (dpset->priv))->line_count; i++) { + free(((struct dtop_dual_line_vars *)(dpset->priv))->line[i]); + free(((struct dtop_dual_line_vars *)(dpset->priv))->line2[i]); + } + free(((struct dtop_dual_line_vars *)(dpset->priv))->line); + free(((struct dtop_dual_line_vars *)(dpset->priv))->line2); + free(((struct dtop_dual_line_vars *)(dpset->priv))); + free(dpset); +} + +/** + * @brief Creates a dpg for a dual_line file. + * + * Dynamically allocates memory for dpg which is then added to a linked list + * via the dtop_register(dpg) function call. + * + * @param name Name of file dpg represents. + * @param data_points dtop_data_point struct that dpg points to. + * @param storage dtop_dual_line_vars struct that hold relevant dpg variables. + * @param dp_count Number of datapoints in dtop_data_point struct array. + */ +static void construct_dual_line_file_dpg(char *name, struct dtop_data_point + *data_points, struct dtop_dual_line_vars *storage, int dp_count) +{ + struct dtop_data_point_gatherer *dpg = malloc + (sizeof(struct dtop_data_point_gatherer)); + dpg->prefix = name; + dpg->file = name; + dpg->poll = dtop_dual_line_poll; + dpg->data_points = data_points; + dpg->priv = (struct dtop_dual_line_vars *)storage; + dpg->data_points_len = dp_count; + dpg->deconstruct = dtop_dual_line_dpg_deconstructor; + + dtop_register(dpg); +} + +/** + * @brief Scans a dual_line file for all datapoints and creats dps. + * + * Searches through a dual_line file (Key on one line with value on next line) + * for all available data points to create as dp structs. + * + * @param name Name of file. + * @param storage dtop_dual_line_vars struct where relevant variables are stored. + */ +int dtop_dual_line_search(char *name, struct dtop_dual_line_vars *storage) +{ + int i, j, k, n, sum, sum2; + char *data; + int *line_len = malloc(sizeof(int) * storage->line_count); + int *line_len2 = malloc(sizeof(int) * storage->line_count); + int read; + struct dt_procdict *dict, *prefix_dict; + struct dtop_data_point *data_points; + int dp_count = 0; + + storage->line = malloc(storage->line_count * sizeof(*storage->line)); + storage->line2 = malloc(storage->line_count * sizeof(*storage->line2)); + for (i = 0; i < storage->line_count; i++) { + storage->line[i] = malloc(sizeof(char) * DTOP_DUAL_LINE); + storage->line2[i] = malloc(sizeof(char) * DTOP_DUAL_LINE); + } + dict = malloc(sizeof(struct dt_procdict) * (storage->line_count/2)); + prefix_dict = malloc(sizeof(struct dt_procdict) + * (storage->line_count/2)); + + read = dt_read_file(name, &data, DTOP_DUAL_SIZE); + if (read == 0 || data == 0) + return DTOP_POLL_IO_ERR; + + sum = 0; + sum2 = 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_DUAL_LINE, data, + DTOP_DUAL_SIZE, sum); + line_len2[n] = dt_read_line(storage->line2[n], + DTOP_DUAL_LINE, data, + DTOP_DUAL_SIZE, sum2); + if (n <= (storage->line_count-2)) { + sum += (line_len[n] + 1); + sum2 += (line_len2[n] + 1); + } + + } + + /* Stores dp names and prefixes in dictionaries */ + for (i = 0; i < (storage->line_count/2); i++) + dt_parse_proc_dictionary(storage->line[2*i], line_len[2*i], + storage->line[(2*i)+1], line_len[(2*i)+1], &dict[i]); + + for (i = 0; i < (storage->line_count/2); i++) + dt_parse_for_prefix(storage->line2[2*i], line_len2[2*i], + &prefix_dict[i]); + + /* Finds how many data points were gathered from the file */ + for (j = 0; j < (storage->line_count/2); j++) { + for (i = 0; i < dict[j].max; i++) + dp_count++; + } + + data_points = malloc(dp_count * sizeof(struct dtop_data_point)); + + k = 0; + /* Creates a dtop_data_point struct for each dp found in the file */ + for (j = 0; j < (storage->line_count/2); j++) + for (i = 0; i < dict[j].max; i++) { + if (dict[j].val[i][0] == '-') + data_points[k].type = DTOP_LONG; + else + data_points[k].type = DTOP_ULONG; + data_points[k].name = dict[j].key[i]; + data_points[k].prefix = prefix_dict[j].val[i]; + data_points[k].skip = DO_NOT_SKIP; + data_points[k].initial_data_populated = NOT_POPULATED; + k++; + } + + /* Calls dpg constructor, dpg will point to the dp struct */ + construct_dual_line_file_dpg(name, data_points, storage, dp_count); + + free(line_len); + free(line_len2); + free(dict); + free(prefix_dict); + dt_free(&data); + + return DTOP_POLL_OK; +} + +/** + * @brief Calls dtop_search for a file with dual line pairs. + */ +void dtop_dual_line_init(char *name) +{ + struct dtop_dual_line_vars *storage = malloc + (sizeof(struct dtop_dual_line_vars)); + storage->line_count = dtop_get_file_line_amount(name); + + if (storage->line_count%2 != 0) { + printf("Dual line file, %s, contains error.\n", name); + printf("Data will not be collected from %s\n", name); + return; + } + dtop_dual_line_search(name, storage); +} diff --git a/dataservices/datatop/src/datatop_fileops.c b/dataservices/datatop/src/datatop_fileops.c new file mode 100644 index 0000000..b4c866c --- /dev/null +++ b/dataservices/datatop/src/datatop_fileops.c @@ -0,0 +1,167 @@ +/************************************************************************ +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_fileops.c + * @brief Declares functions for reading and writing to files. + * + * Declares functions called when reading from files which data is collected. + * Also contains methods to handle files which will be written to. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "datatop_interface.h" +#include "datatop_linked_list.h" +#include "datatop_opt.h" +#include "datatop_fileops.h" + +/** + * @brief Reads the lines from files which we are collecting data from. + * + * @param file File which is read from + * @param buffer Pointer to buffer where data will be read. The buffer is allocated + * in dt_read_file() and passed back to the caller. Caller should + * free this when done. + * @param len Maximum amount of data which should be read from the file. + * @return Number of bytes of data placed in *buffer. + */ +int dt_read_file(const char *file, char **buffer, int len) +{ + int read; + FILE *fp; + + *buffer = (char *)malloc(len); + if (!(*buffer)) { + fprintf(stderr, "%s(): malloc(%d) failed\n", __func__, len); + return 0; + } + + fp = fopen(file, "r"); + if (!fp) { + fprintf(stderr, "%s(): Failed to open %s: ", __func__, file); + fprintf(stderr, "Error: %s\n", strerror(errno)); + free(*buffer); + *buffer = 0; + return 0; + } + read = fread(*buffer, sizeof(char), len, fp); + fclose(fp); + + return read; +} + +/** + * @brief Deallocates memory no longer being used. + * + * @param buffer Buffer to be deallocated. + */ +void dt_free(char **buffer) +{ + free(*buffer); + *buffer = 0; +} + +/** + * @brief Checks for access to a file for writing. + * + * @param fw File to check access of. + * @return INVALID - File already exists or write access denied. + * @return VALID - File does not exist and can be written to. + */ +int dtop_check_writefile_access(char *fw) +{ + if (!access(fw, F_OK)) { + printf("File specified already exists\n"); + return INVALID; + } + + if (!access(fw, W_OK)) { + printf("Permission to write to specified file denied\n"); + return INVALID; + } + + return VALID; +} + +/** + * @brief Opens file and handles possible errors. + * + * @param fw File path to be opened. + * @param to_file Pointer to the *file that is opened. + * @return VALID - File opened successfully. + * @return INVALID - File could not be opened. + */ +int dtop_open_writing_file(char *fw, FILE **to_file) +{ + *to_file = fopen(fw, "w"); + if (*to_file) { + return VALID; + } else { + fprintf(stderr, "Value of errno: %d\n", errno); + fprintf(stderr, "Error opening file: %s\n", strerror(errno)); + fprintf(stderr, "Please try writing to a non-existent file\n"); + printf("See datatop -h for help\n"); + return INVALID; + } +} + +/** + * @brief Closes a file if not a standard stream. + * + * @param fw File to be closed. + */ +void dtop_close_file(FILE *fw) +{ + if (fw != stdout && fw != stderr && fw != stdin) + fclose(fw); +} + +/** + * @brief Helper function to find number of lines in dual_line file. + * + * @return Number of lines in a dual_line file. + */ +int dtop_get_file_line_amount(char *name) +{ + signed char rc = 0; + int line_count = 0; + FILE *file = fopen(name, "r"); + while (rc != EOF) { + if (rc == '\n') + line_count++; + rc = fgetc(file); + } + + fclose(file); + return line_count; +} diff --git a/dataservices/datatop/src/datatop_fileops.h b/dataservices/datatop/src/datatop_fileops.h new file mode 100644 index 0000000..0078e06 --- /dev/null +++ b/dataservices/datatop/src/datatop_fileops.h @@ -0,0 +1,48 @@ +/************************************************************************ +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_fileops.h + * @brief Declares functions held within datatop_fileops.h + */ + +#ifndef DATATOP_FILEOPS_H +#define DATATOP_FILEOPS_H + +#include "datatop_interface.h" +#include "datatop_linked_list.h" +#include "datatop_opt.h" + +int dt_read_file(const char *file, char **buffer, int len); +void dt_free(char **buffer); +int dtop_check_writefile_access(char *fw); +int dtop_open_writing_file(char *fw, FILE **to_file); +void dtop_close_file(FILE *fw); +int dtop_get_file_line_amount(char *file); +#endif /* DATATOP_FILEOPS_H */ diff --git a/dataservices/datatop/src/datatop_gen_poll.c b/dataservices/datatop/src/datatop_gen_poll.c new file mode 100644 index 0000000..c3eb09d --- /dev/null +++ b/dataservices/datatop/src/datatop_gen_poll.c @@ -0,0 +1,280 @@ +/************************************************************************ +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_gen_poll.c + * @brief Contains functions which add ability to scan directories for data points. + * + * Contains functions that search through a directory and create dpg's for any + * important data values found which can then be polled for data collection. + */ + +#include <unistd.h> +#include <stdio.h> +#include <dirent.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "datatop_interface.h" +#include "datatop_fileops.h" +#include "datatop_str.h" +#include "datatop_gen_poll.h" + +#define DTOP_GEN_SIZE 8192 +#define DTOP_GEN_LINE (DTOP_GEN_SIZE>>2) + +/** + * @brief Searches a file to find the number of data values it contains. + * + * @param dpg The struct which contains the file to search. + * @return Number of datapoints found in the file. + */ +static int get_number_of_values(struct dtop_data_point_gatherer *dpg) +{ + char *data; + int read; + char line[DTOP_GEN_LINE]; + int line_len; + int i, num; + + read = dt_read_file(dpg->file, &data, DTOP_GEN_SIZE); + line_len = dt_read_line(line, DTOP_GEN_LINE, data, DTOP_GEN_SIZE, 0); + + if (read == 0) { + return 0; + } + + if (line_len < 1) { + dt_free(&data); + return 0; + } + + num = 1; + for (i = 0; i < line_len; i++) { + if ((line[i] == ' ' || line[i] == ',' + || line[i] == ' ') &&line[i+1] != 0) + num++; + } + + dt_free(&data); + return num; +} + +/** + * @brief Stores the data collected from a dpg that was constructed during dtop_search. + * + * @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_gen_poll(struct dtop_data_point_gatherer *dpg) +{ + char *data; + int read; + char line[DTOP_GEN_LINE]; + int line_len; + struct dt_procdict dict; + int i; + + read = dt_read_file(dpg->file, &data, DTOP_GEN_SIZE); + line_len = dt_read_line(line, DTOP_GEN_LINE, data, DTOP_GEN_SIZE, 0); + + if (read == 0 || data == 0) + return DTOP_POLL_IO_ERR; + + dt_single_line_parse(line, line_len, &dict); + + for (i = 0; i < dpg->data_points_len; i++) { + if (dict.val[i][0] == '-') + dpg->data_points[i].type = DTOP_LONG; + dtop_store_dp(&(dpg->data_points[i]), dict.val[i]); + } + + dt_free(&data); + return DTOP_POLL_OK; +} + +/** + * @brief Frees dynamically allocated dpg's. + * + * Frees the memory of dpg variables and the dpg for all dynamically allocated + * dpgs. + * + * @param dpg Dpg to deconstruct and deallocate memory for. + */ +static void dtop_gen_dpg_deconstructor(struct dtop_data_point_gatherer *dpset) +{ + int i; + for (i = 0; i < dpset->data_points_len; i++) + free(dpset->data_points[i].name); + free(dpset->data_points); + free(dpset->file); + free(dpset->prefix); + free(dpset); +} + +/** + * @brief Creates a dpg and all necessary dp's corresponding to it. + * + * Dynamically allocates memory for dpg and dp structs which are then + * created and added to a linked_list of dpgs through the dtop_register + * function. + * + * @param dir Directory which file is located in, assigned to the dpg prefix. + * @param name Name of file that dpg represents, assigned to a dp name. + */ +static void dpg_construction(char *dir, char *name) +{ + int num, i; + int both_len = strlen(dir) + strlen(name) + 1; + char *both = malloc(both_len); + char *maindir; + struct dtop_data_point_gatherer *dpg = malloc + (sizeof(struct dtop_data_point_gatherer)); + strlcpy(both, dir, both_len); + strlcat(both, name, both_len); + maindir = malloc(strlen(dir) + 1); + strlcpy(maindir, dir, strlen(dir) + 1); + + dpg->prefix = maindir; + dpg->file = both; + dpg->poll = dtop_gen_poll; + dpg->deconstruct = dtop_gen_dpg_deconstructor; + num = get_number_of_values(dpg); + + if (num != 0) { + struct dtop_data_point *dp = malloc + (num * sizeof(struct dtop_data_point)); + for (i = 0; i < num; i++) { + if (num == 1) { + dp[i].name = malloc(strlen(name) + 1); + strlcpy(dp[i].name, name, strlen(name) + 1); + } else { + char *add = malloc(7 * sizeof(char)); + char *newname; + int nn_len, dpn_len; + snprintf(add, 7 * sizeof(char), "[%d]:", i); + nn_len = strlen(name) + strlen(add) + 1; + newname = malloc(nn_len); + strlcpy(newname, name, nn_len); + strlcat(newname, add, nn_len); + dpn_len = strlen(newname) + 1; + dp[i].name = malloc(dpn_len); + strlcpy(dp[i].name, newname, dpn_len); + free(add); + free(newname); + } + dp[i].prefix = NULL; + dp[i].type = DTOP_ULONG; + dp[i].skip = DO_NOT_SKIP; + dp[i].initial_data_populated = NOT_POPULATED; + } + + dpg->data_points = dp; + dpg->data_points_len = num; + + dtop_register(dpg); + } else { + free(dpg->prefix); + free(dpg->file); + free(dpg); + } +} + +/** + * @brief Scans a directory for all important datapoints to be collected. + * + * Recursively scans a directory and locates all files which data will be + * collected from. + * + * @param dir Directory to search. + */ +static int dtop_search(char *dir) +{ + DIR *dp; + struct dirent *entry; + struct stat s; + char cwd[1024]; + + if (!getcwd(cwd, sizeof(cwd))) { + fprintf(stderr, "Failed to get current working dir\n"); + return -1; + } + + dp = opendir(dir); + if (dp == NULL) { + fprintf(stderr, "err=%d: %s\n", errno, strerror(errno)); + fprintf(stderr, "Cannot open directory: %s\n", dir); + return DIR_FAILURE; + } + + chdir(dir); + + while ((entry = readdir(dp))) { + if (stat(entry->d_name, &s)) { + printf("stat err=%d: %s\n", errno, strerror(errno)); + return DIR_FAILURE; + } + + if (strcmp(".", entry->d_name) != 0 && + strcmp("..", entry->d_name) != 0 && + S_ISREG(s.st_mode)) { + + dpg_construction(dir, entry->d_name); + + } else if (strcmp(".", entry->d_name) != 0 && + strcmp("..", entry->d_name) != 0 && + S_ISDIR(s.st_mode)) { + int nd_len = strlen(dir) + strlen(entry->d_name) + 2; + char *newdir = malloc(nd_len); + strlcpy(newdir, dir, nd_len); + strlcat(newdir, entry->d_name, nd_len); + strlcat(newdir, "/", nd_len); + dtop_search(newdir); + free(newdir); + } + } + + closedir(dp); + chdir(cwd); + return DIR_SUCCESS; +} + +/** + * @brief Calls dtop_search for any specified directory. + * + * @param dir Directory to search. + */ +void dtop_gen_init(char *dir) +{ + dtop_search(dir); +} diff --git a/dataservices/datatop/src/datatop_gen_poll.h b/dataservices/datatop/src/datatop_gen_poll.h new file mode 100644 index 0000000..6baffc9 --- /dev/null +++ b/dataservices/datatop/src/datatop_gen_poll.h @@ -0,0 +1,43 @@ +/************************************************************************ +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_gen_poll.h + * @brief Declares functions held within datatop_gen_poll.c + */ + +#ifndef DATATOP_GEN_POLL_H +#define DATATOP_GEN_POLL_H + +#define DIR_SUCCESS 0 +#define DIR_FAILURE 1 + +void dtop_gen_init(char *dir); +#endif /* DATATOP_GEN_POLL_H */ + diff --git a/dataservices/datatop/src/datatop_helpers.c b/dataservices/datatop/src/datatop_helpers.c new file mode 100644 index 0000000..325b824 --- /dev/null +++ b/dataservices/datatop/src/datatop_helpers.c @@ -0,0 +1,478 @@ +/************************************************************************ +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_helpers.c + * @brief Contains functions which output data. + * + * Contains functions which are used for printing data to output streams. + * Handles all formatting for data output. Also contains functions which + * are responsible for data gathering and collection. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <time.h> +#include <sys/time.h> +#include <string.h> +#include <errno.h> +#include "datatop_interface.h" +#include "datatop_linked_list.h" +#include "datatop_fileops.h" + +/** + * @brief Prints the name and prefix of a datapoint. + * + * @param dp Dp whose name and prefix is printed. + * @param prefix Directory where dp is contained. + * @param fw File to print the information to. + * @return FILE_ERROR - Writing to file was unsuccessful. + * @return FILE_SUCCESS - Writing to file was successful. + */ +static int dtop_format_dp_names(struct dtop_data_point *dp, const char + *prefix, FILE *fw) +{ + if (dp->prefix) { + if (fprintf(fw, "\"%s:%s:%s\",", prefix, dp->prefix, + dp->name) < 0) + return FILE_ERROR; + } else { + if (fprintf(fw, "\"%s::%s\",", prefix, dp->name) < 0) + return FILE_ERROR; + } + return FILE_SUCCESS; +} + +/** + * @brief Prints the value of a datapoint. + * + * Checks the type of the value and will print it accordingly. + * + * @param dp Pointer to the data_point struct which holds the value that will + * be printed. + * @param fw File to print the information to. + * @return FILE_ERROR - Writing to file was unsuccessful. + * @return FILE_SUCCESS - Writing to file was successful. + */ +static int dtop_format_dp_values(struct dtop_data_point *dp, FILE *fw) +{ + switch (dp->type) { + case DTOP_ULONG: + if (fprintf(fw, "%"PRIu64, dp->data.d_ulong) < 0) + return FILE_ERROR; + break; + case DTOP_LONG: + if (fprintf(fw, "%"PRId64, dp->data.d_long) < 0) + return FILE_ERROR; + break; + case DTOP_UINT: + if (fprintf(fw, "%d", dp->data.d_uint) < 0) + return FILE_ERROR; + break; + case DTOP_INT: + if (fprintf(fw, "%u", dp->data.d_uint) < 0) + return FILE_ERROR; + break; + case DTOP_UCHAR: + if (fprintf(fw, "%c,", dp->data.d_uchar) < 0) + return FILE_ERROR; + if (fprintf(fw, "(0x%02X)", dp->data.d_uchar) < 0) + return FILE_ERROR; + break; + case DTOP_CHAR: + if (fprintf(fw, "%c,", dp->data.d_char) < 0) + return FILE_ERROR; + if (fprintf(fw, "(%d)", dp->data.d_char) < 0) + return FILE_ERROR; + break; + case DTOP_STR: + if (fprintf(fw, "\"%s\"", dp->data.d_str) < 0) + return FILE_ERROR; + break; + default: + if (fprintf(fw, "UNKNOWN_TYPE") < 0) + return FILE_ERROR; + break; + } + return FILE_SUCCESS; +} + +/** + * @brief Prints the name and prefix of a dp, formatted appropriately. + * + * @param dpset data_point_gatherer used to access dp directory. + * @param dp data_point used to get datapoint prefix if available. + */ +static void dtop_format_text_for_snapshot + (struct dtop_data_point_gatherer *dpset, struct dtop_data_point dp) +{ + printf("%s:", dpset->prefix); + if (dp.prefix) + printf("%s:", dp.prefix); + + printf("%s::", dp.name); +} + +/** + * @brief Prints a datapoint value to a specified csv file. + * + * @param dp Datapoint that holds the value to be printed. + * @param fw File to print to. + * @return FILE_ERROR - Writing to file was unsuccessful. + * @return FILE_SUCCESS - Writing to file was successful. + */ +static int dtop_print_dp_csv(struct dtop_data_point *dp, FILE *fw) +{ + if (dtop_format_dp_values(dp, fw) == FILE_ERROR) + return FILE_ERROR; + if (fprintf(fw, ",") < 0) + return FILE_ERROR; + return FILE_SUCCESS; +} + +/** + * @brief Prints a datapoint value to the terminal. + * + * @param dp Holds the value to be printed print. + * @param prefix Used to print prefix of the data_point. + */ +static void dtop_print_dp(struct dtop_data_point *dp, const char *prefix) +{ + dtop_format_dp_names(dp, prefix, stdout); + printf(" "); + dtop_format_dp_values(dp, stdout); + printf("\n"); +} + +/** + * @brief Finds delta(value) of a datapoint. + * + * Function accounts for different types that values may be. + * + * @param dpset Pointer to a data_point used as another parameter for printing. + * @param dp Datapoint which contains the value to find the difference of. + */ +static void dtop_handle_dp_type_for_snapshot( + struct dtop_data_point_gatherer *dpset, struct dtop_data_point dp) +{ + int64_t int64; + + switch (dp.type) { + case DTOP_ULONG: + default: + /* This is less than ideal. Replace with 128-bit ops later */ + int64 = (int64_t)dp.data.d_ulong + - (int64_t)dp.initial_data.d_ulong; + if (int64 != 0) { + dtop_format_text_for_snapshot(dpset, dp); + printf("%"PRId64"\n", int64); + } + break; + + case DTOP_LONG: + /* This is less than ideal. Replace with 128-bit ops later */ + int64 = (int64_t)dp.data.d_long + - (int64_t)dp.initial_data.d_long; + if (int64 != 0) { + dtop_format_text_for_snapshot(dpset, dp); + printf("%"PRId64"\n", int64); + } + break; + + case DTOP_UINT: + int64 = (int64_t)dp.data.d_uint + - (int64_t)dp.initial_data.d_uint; + if (int64 != 0) { + dtop_format_text_for_snapshot(dpset, dp); + printf("%"PRId64"\n", int64); + } + break; + + case DTOP_INT: + int64 = (int64_t)dp.data.d_int + - (int64_t)dp.initial_data.d_int; + if (int64 != 0) { + dtop_format_text_for_snapshot(dpset, dp); + printf("%"PRId64"\n", int64); + } + break; + } +} + +/** + * @brief Calls the dtop_print_dp_csv function for each data_point a dpg has access to. + * + * @param dpg A data_point_gatherer struct that is iterated through for each datapoint. + * @param fw File to print datapoint values to. + * @return FILE_ERROR - Writing to file was unsuccessful. + * @return FILE_SUCCESS - Writing to file was successful. + */ +static int dtop_print_dpg_csv(struct dtop_data_point_gatherer *dpg, FILE *fw) +{ + int i; + + for (i = 0; i < dpg->data_points_len; i++) + if (dtop_print_dp_csv(&(dpg->data_points[i]), fw) == FILE_ERROR) + return FILE_ERROR; + return FILE_SUCCESS; +} + +/** + * @brief Calls the dtop_format_dp_names function for each data_point a dpg has access to. + * + * @param dpg A data_point_gatherer struct that is iterated through for each datapoint. + * @param fw File to printg datapoint names and prefixes to. + * @return FILE_ERROR - Writing to file was unsuccessful. + * @return FILE_SUCCESS - Writing to file was successful. + */ +int dtop_print_dpg_names_csv(struct dtop_data_point_gatherer *dpg, FILE *fw) +{ + int i; + + for (i = 0; i < dpg->data_points_len; i++) + if (dtop_format_dp_names(&(dpg->data_points[i]), + dpg->prefix, fw) == FILE_ERROR) + return FILE_ERROR; + + return FILE_SUCCESS; +} + +/** + * @brief Prints all dp values to a specified file. + * + * This function is responsible for the printing of all data_point values + * to a specified file. It will iterate through the linked list which contains + * all of the dpgs and will print each dp value, being sure to flush the buffer. + * + * @param dpg_list Pointer to first node of linked list which contains all dpgs. + * @param fw File that data prints to. + * @return FILE_ERROR - Writing to file was unsuccessful. + * @return FILE_SUCCESS - Writing to file was successful. + */ +int dtop_write_pollingdata_csv(struct dtop_linked_list *dpg_list, FILE *fw) +{ + struct dtop_linked_list *curr_ptr = dpg_list; + struct dtop_data_point_gatherer *dpset; + + while (curr_ptr) { + dpset = (struct dtop_data_point_gatherer *) curr_ptr->data; + if (dtop_print_dpg_csv(dpset, fw) == FILE_ERROR) + return FILE_ERROR; + curr_ptr = curr_ptr->next_ptr; + fflush(fw); + } + + if (fprintf(fw, "\n") < 0) + return FILE_ERROR; + + return FILE_SUCCESS; +} + +/** + * @brief Calls the dtop_print_dp function for each data_point a dpg has access to. + * + * @param dpg A data_point_gatherer struct that is iterated through for each datapoint. + */ +void dtop_print_dpg(struct dtop_data_point_gatherer *dpg) +{ + int i; + for (i = 0; i < dpg->data_points_len; i++) + dtop_print_dp(&(dpg->data_points[i]), dpg->prefix); +} + +/** + * @brief Stores the values for the datapoints and populates the initial value. + * + * @param dp A datapoint whose value will be stored. + * @param str Str used for sscanf function call to find value of dp. + */ +void dtop_store_dp(struct dtop_data_point *dp, const char *str) +{ + switch (dp->type) { + case DTOP_ULONG: + sscanf(str, "%"PRIu64, &(dp->data.d_ulong)); + if (dp->initial_data_populated == NOT_POPULATED) { + dp->initial_data.d_ulong = dp->data.d_ulong; + dp->initial_data_populated = POPULATED; + } + break; + case DTOP_LONG: + sscanf(str, "%"PRId64, &(dp->data.d_long)); + if (dp->initial_data_populated == NOT_POPULATED) { + dp->initial_data.d_long = dp->data.d_long; + dp->initial_data_populated = POPULATED; + } + break; + case DTOP_UINT: + sscanf(str, "%u", &(dp->data.d_uint)); + if (dp->initial_data_populated == NOT_POPULATED) { + dp->initial_data.d_uint = dp->data.d_uint; + dp->initial_data_populated = POPULATED; + } + break; + case DTOP_INT: + sscanf(str, "%d", &(dp->data.d_int)); + if (dp->initial_data_populated == NOT_POPULATED) { + dp->initial_data.d_int = dp->data.d_int; + dp->initial_data_populated = POPULATED; + } + break; + case DTOP_UCHAR: + sscanf(str, "%c", &(dp->data.d_uchar)); + if (dp->initial_data_populated == NOT_POPULATED) { + dp->initial_data.d_uchar = dp->data.d_uchar; + dp->initial_data_populated = POPULATED; + } + break; + case DTOP_CHAR: + sscanf(str, "%c", &(dp->data.d_char)); + if (dp->initial_data_populated == NOT_POPULATED) { + dp->initial_data.d_char = dp->data.d_char; + dp->initial_data_populated = POPULATED; + } + break; + case DTOP_STR: + sscanf(str, "%s", dp->data.d_str); + if (dp->initial_data_populated == NOT_POPULATED) { + memcpy(dp->initial_data.d_str, dp->data.d_str, + DTOP_DP_MAX_STR_LEN); + dp->initial_data_populated = POPULATED; + } + break; + default: + break; + } +} + +/** + * @brief Responsible for calculating and printing current time to file. + * + * Prints the time since 1970, in Seconds and Milliseconds. + * + * @param fw File that time is printed to. + * @return FILE_ERROR - Writing to file was unsuccessful. + * @return FILE_SUCCESS - Writing to file was successful. + */ +int dtop_print_time_at_poll(FILE *fw) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + + if (fprintf(fw, "%10ld", tv.tv_sec) < 0) + return FILE_ERROR; + + if (fprintf(fw, ".%06ld,", tv.tv_usec) < 0) + return FILE_ERROR; + + return FILE_SUCCESS; +} + +/** + * @brief Polls all dp values and updates each value. + * + * @param dpg_list Pointer to first node of linked list which contains all dpgs. + */ +void dtop_poll(struct dtop_linked_list *dpg_list) +{ + struct dtop_linked_list *curr_ptr = dpg_list; + struct dtop_data_point_gatherer *dpset; + + while (curr_ptr) { + dpset = (struct dtop_data_point_gatherer *) curr_ptr->data; + dpset->poll(dpset); + curr_ptr = curr_ptr->next_ptr; + } +} + +/** + * @brief Prints the delta(value) of all data_points to terminal. + * + * @param dpg_list Pointer to first node of linked list which contains all dpgs. + */ +void dtop_print_snapshot_diff(struct dtop_linked_list *dpg_list) +{ + int i; + + struct dtop_linked_list *curr_ptr = dpg_list; + struct dtop_data_point_gatherer *dpset; + printf("\n"); + printf("Change In Datapoint Values\n"); + printf("---------------------------\n"); + while (curr_ptr) { + dpset = (struct dtop_data_point_gatherer *) curr_ptr->data; + for (i = 0; i < dpset->data_points_len; i++) + dtop_handle_dp_type_for_snapshot(dpset, + dpset->data_points[i]); + curr_ptr = curr_ptr->next_ptr; + } + printf("\n"); +} + +/** + * @brief Resets the initial values of all data_points. + * + * @param dpg_list Pointer to first node of linked list which contains all dpgs. + */ +void dtop_reset_dp_initial_values(struct dtop_linked_list *dpg_list) +{ + int i; + + struct dtop_linked_list *curr_ptr = dpg_list; + struct dtop_data_point_gatherer *dpset; + + while (curr_ptr) { + dpset = (struct dtop_data_point_gatherer *) curr_ptr->data; + for (i = 0; i < dpset->data_points_len; i++) + dpset->data_points[i].initial_data_populated + = NOT_POPULATED; + curr_ptr = curr_ptr->next_ptr; + } +} + +/** + * @brief Calls deconstructor method for all dpgs dynamically created. + * + * Checks to see if each dpg created has a deconstructor method. If not null, + * function calls the appropiate deconstructor method to deallocate memory. + * + * @param dpg_list Pointer to first node of linked list which contains all dpgs. + */ +void deconstruct_dpgs(struct dtop_linked_list *dpg_list) +{ + struct dtop_linked_list *curr_ptr = dpg_list; + struct dtop_data_point_gatherer *dpset; + + while (curr_ptr) { + dpset = (struct dtop_data_point_gatherer *) curr_ptr->data; + if (dpset->deconstruct) + dpset->deconstruct(dpset); + curr_ptr = curr_ptr->next_ptr; + } +} diff --git a/dataservices/datatop/src/datatop_interface.h b/dataservices/datatop/src/datatop_interface.h new file mode 100644 index 0000000..2928c26 --- /dev/null +++ b/dataservices/datatop/src/datatop_interface.h @@ -0,0 +1,166 @@ +/************************************************************************ +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_interface.h + * @brief Declares functions held within datatop.c and datatop_helpers.c + * + * Declares functions which are held within datatop.c and datatop_helpers.c. + * Also defines data structures used for storing data gathered during polling + * such as datapoint names, values, and prefixes along with other valuable + * information. + */ + +#ifndef DATATOP_INTERFACE_H +#define DATATOP_INTERFACE_H + +#include <inttypes.h> +#include "datatop_linked_list.h" + +#define DTOP_ULONG 0 +#define DTOP_LONG 1 +#define DTOP_UINT 2 +#define DTOP_INT 3 +#define DTOP_UCHAR 4 +#define DTOP_CHAR 5 +#define DTOP_STR 6 + +#define FILE_ERROR -1 +#define FILE_SUCCESS 0 +#define SKIP 1 +#define DO_NOT_SKIP 0 +#define POPULATED 1 +#define NOT_POPULATED 0 + +#define DTOP_POLL_OK 0 +#define DTOP_POLL_IO_ERR 1 +#define NOT_CHECKED 0 + +#define QUIT 1 + +#define DTOP_DP_MAX_STR_LEN 32 + +#define DTOP_DP_HFILL .initial_data_populated = NOT_POPULATED, \ + .skip = 0 + +/** + * @struct dtop_data_union + * @brief Provides the type for dp value. + */ +union dtop_data_union { + uint64_t d_ulong; + int64_t d_long; + uint32_t d_uint; + int32_t d_int; + uint8_t d_uchar; + int8_t d_char; + char d_str[DTOP_DP_MAX_STR_LEN]; +}; + +/** + * @struct dtop_data_point + * @brief Individual datapoint in a file. + * + * @var dtop_data_point::name + * Stores the datapoints name. + * @var dtop_data_point::prefix + * Stores the individual prefix for the dp. + * @var dtop_data_point::type + * Type dp value is, see definitions. + * @var dtop_data_point::initial_data + * Holds the initial value of the dp the first time it was polled. + * @var dtop_data_point::initial_data_populated + * Variable that is changed when initial_data is populated. + * @var dtop_data_point::data + * Value of the dp at the most recent poll. + */ +struct dtop_data_point { + char *name; + char *prefix; + + /* Results of polling */ + char type; + union dtop_data_union initial_data; + char initial_data_populated; + union dtop_data_union data; + + /* Skip on subsequent polls */ + char skip; +}; + +/** + * @struct dtop_data_point_gatherer + * @brief Struct used to hold data about a set of collected data. + * + * @var dtop_data_point_gatherer::prefix + * Name of directory which data is collected from. + * @var dtop_data_point_gatherer::file + * File path that data is collected from. + * @var dtop_data_point_gatherer::poll + * Poll function takes a dtop_data_point_gatherer as parameter. + * int equals, DTOP_POLL_IO_ERR - Poll of dpg unsuccessful, or + * DTOP_POLL_OK - Poll of dpg successful. + * @var dtop_data_point_gatherer::data_points + * Pointer to a dtop_data_point struct (dp). + * @var dtop_data_point_gatherer::data_points_len + * Number of elements in the array of dp's the dpg accesses. + */ +struct dtop_data_point_gatherer { + char *prefix; + char *file; + int (*poll)(struct dtop_data_point_gatherer *dpg); + void (*deconstruct)(struct dtop_data_point_gatherer *dpg); + + struct dtop_data_point *data_points; + int data_points_len; + + /* Private data */ + void *priv; +}; + +void dtop_register(struct dtop_data_point_gatherer *dpg); +void dtop_store_dp(struct dtop_data_point *dp, const char *str); +void dtop_print_dpg(struct dtop_data_point_gatherer *dpg); +void get_snapshot_diff(struct dtop_linked_list *dpg_list); +void dtop_print_snapshot_diff(struct dtop_linked_list *dpg_list); +void dtop_poll(struct dtop_linked_list *dpg_list); +int dtop_print_time_at_poll(FILE *fw); +int dtop_print_dpg_names_csv(struct dtop_data_point_gatherer *dpg, FILE *fw); +int dtop_write_pollingdata_csv(struct dtop_linked_list *dpg_list, FILE *fw); +void dtop_reset_dp_initial_values(struct dtop_linked_list *dpg_list); +void deconstruct_dpgs(struct dtop_linked_list *dpg_list); +int dtop_print_system_snapshot(char *file); + + +#ifndef HAVE_STRL_FUNCTIONS +#define strlcpy(X,Y,Z) strcpy(X,Y) +#define strlcat(X,Y,Z) strcat(X,Y) +#endif /* HAVE_STRL_FUNCTIONS */ + +#endif /* DATATOP_INTERFACE_H */ diff --git a/dataservices/datatop/src/datatop_linked_list.c b/dataservices/datatop/src/datatop_linked_list.c new file mode 100644 index 0000000..7e5b632 --- /dev/null +++ b/dataservices/datatop/src/datatop_linked_list.c @@ -0,0 +1,84 @@ +/************************************************************************ +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_linked_list.c + * @brief Necessary linked_list functions created. + * + * Holds function which adds to or creates a linked list + * used for storing dtop_data_point_gatherer's (dpg's). + * Datapoints are stored in linked list for ability to + * iteratively poll and print efficiently. Handles creation + * and deletion of memory for linked list nodes. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "datatop_linked_list.h" + +/** + * @brief Adds a node to the beginning of a linked list. + * + * @param data A void pointer which can hold any data in the node. + * @param list The list that is added to. + * @return Updated linked list struct. + */ +struct dtop_linked_list *dtop_add_linked_list(void *data, + struct dtop_linked_list *list) +{ + struct dtop_linked_list *list_node; + list_node = malloc(sizeof(struct dtop_linked_list)); + + if (!list_node) { + fprintf(stderr, "failed to allocate memory.\n"); + exit(EXIT_FAILURE); + } + + list_node->data = data; + list_node->next_ptr = list; + list = list_node; + return list; +} + +/** + * @brief Deletes a linked list. + * + * @param head_ptr Pointer to the first node in the linked list that is to be deleted. + */ +void dtop_rem_linked_list(struct dtop_linked_list *head_ptr) +{ + struct dtop_linked_list *tmp_ptr = NULL; + while (head_ptr) { + tmp_ptr = head_ptr; + head_ptr = head_ptr->next_ptr; + free(tmp_ptr); + } +} diff --git a/dataservices/datatop/src/datatop_linked_list.h b/dataservices/datatop/src/datatop_linked_list.h new file mode 100644 index 0000000..4386d02 --- /dev/null +++ b/dataservices/datatop/src/datatop_linked_list.h @@ -0,0 +1,59 @@ +/************************************************************************ +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_linked_list.h + * @brief Defines linked list struct and declares linked list methods. + * + * Defines linked list struct which can be used for any data + * storage. Declares methods held within datatop_linked_list.c. + */ + +#ifndef DATATOP_LINKED_LIST_H +#define DATATOP_LINKED_LIST_H + +/** + * @struct dtop_linked_list + * @brief Struct used to represent linked list node that stores a pointer with any type. + * + * @var dtop_linked_list::next_ptr + * Pointer to next node in the list. + * @var dtop_linked_list::data + * Pointer to data the node stores. + */ +struct dtop_linked_list { + struct dtop_linked_list *next_ptr; + void *data; +}; + +struct dtop_linked_list *dtop_add_linked_list(void *data, + struct dtop_linked_list *list); +void dtop_rem_linked_list(struct dtop_linked_list *head_ptr); +#endif /* DATATOP_LINKED_LIST_H */ + diff --git a/dataservices/datatop/src/datatop_meminfo_file_poll.c b/dataservices/datatop/src/datatop_meminfo_file_poll.c new file mode 100644 index 0000000..078b825 --- /dev/null +++ b/dataservices/datatop/src/datatop_meminfo_file_poll.c @@ -0,0 +1,282 @@ +/************************************************************************ +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_meminfo_file_poll.c + * @brief Adds ability for data collection from /proc/meminfo + * + * File contains methods for searching and polling data from + * "/proc/meminfo" + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <inttypes.h> +#include "datatop_interface.h" +#include "datatop_fileops.h" +#include "datatop_str.h" + +#define DTOP_MEM_SIZE 8192 +#define DTOP_MEM_LINE (DTOP_MEM_SIZE>>2) + +/** +* @struct dtop_meminfo_vars +* @brief Struct used to hold necessary variables for /proc/meminfo dpg +* +* @var dtop_meminfo_vars::line +* Array of strings where necessary dp names and values are held. +* @var dtop_meminfo_vars::line_count +* Number of lines the file is that the dpg represents. +*/ +struct dtop_meminfo_vars { + char **line; + int line_count; +}; + +/** + * @brief Parses lines with data in "/proc/meminfo" + * + * @param line1 Line to parse to find datapoint names and values. + * @param len1 Length of line1. + * @param l Index in the dictionary the key/value pair is added to. + * @param dict Dictionary the keys and values are added to. + */ +int dt_meminfo_parse(char *line1, int len1, + int l, struct dt_procdict *dict) +{ + int i, k, n; + if (len1 < 1) + return 0; + + if (line1 == 0 || dict == 0) + return 0; + + k = l; + dict->key[k] = &line1[0]; + for (i = 0; i < len1 && k < DTOP_DICT_SIZE; i++) { + if (line1[i] == ' ' || line1[i] == ' ') { + line1[i] = 0; + n = i+1; + while (line1[n] == ' ' || line1[n] == ' ') + n++; + dict->val[k] = &line1[n]; + while (line1[n] != ' ') + n++; + line1[n] = 0; + break; + } + } + k++; + dict->max = k; + return k; +} + +/** + * @brief Stores the data collected from a "/proc/meminfo" + * + * @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_meminfo_poll(struct dtop_data_point_gatherer *dpg) +{ + char *data; + int *line_len = malloc(sizeof(int) * + ((struct dtop_meminfo_vars *) + (dpg->priv))->line_count); + int read; + struct dt_procdict dict; + int i, j, n, sum; + + read = dt_read_file(dpg->file, &data, DTOP_MEM_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_meminfo_vars *) + (dpg->priv))->line_count; n++) { + line_len[n] = dt_read_line(((struct dtop_meminfo_vars *) + (dpg->priv))->line[n], + DTOP_MEM_LINE, data, + DTOP_MEM_SIZE, sum); + if (n <= (((struct dtop_meminfo_vars *) + (dpg->priv))->line_count - 1)) { + sum += (line_len[n] + 1); + } + + } + + /* Stores dp names and values in dictionary */ + for (i = 0; i < dpg->data_points_len; i++) + dt_meminfo_parse(((struct dtop_meminfo_vars *) + (dpg->priv))->line[i], line_len[i], i, &dict); + + /* Assigns the dp value to the dp struct */ + for (j = 0; j < dpg->data_points_len; j++) { + i = dt_find_dict_idx(dpg->data_points[j].name, &dict); + if (i >= 0 && i < dict.max) { + sscanf(dict.val[i], "%" PRIu64, + &(dpg->data_points[i].data.d_ulong)); + dpg->data_points[i].data.d_ulong *= 1024; + if (dpg->data_points[i]. + initial_data_populated == NOT_POPULATED) { + dpg->data_points[i].initial_data.d_ulong + = dpg->data_points[i].data.d_ulong; + dpg->data_points[i].initial_data_populated + = POPULATED; + } + } + } + + dt_free(&data); + free(line_len); + return DTOP_POLL_OK; +} + +/** + * @brief Frees dynamically allocated "/proc/meminfo" 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_meminfo_dpg_deconstructor + (struct dtop_data_point_gatherer *dpset) +{ + int i; + free(dpset->data_points); + for (i = 0; i < ((struct dtop_meminfo_vars *) + (dpset->priv))->line_count; i++) + free(((struct dtop_meminfo_vars *)(dpset->priv))->line[i]); + free(((struct dtop_meminfo_vars *)(dpset->priv))->line); + free(((struct dtop_meminfo_vars *)(dpset->priv))); + free(dpset); +} + +/** + * @brief Creates a dpg for "/proc/meminfo" 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_meminfo_vars struct that holds relevant dpg variables. + */ +static void construct_meminfo_file_dpg(struct dtop_data_point + *data_points, struct dtop_meminfo_vars *storage) +{ + struct dtop_data_point_gatherer *dpg = malloc + (sizeof(struct dtop_data_point_gatherer)); + dpg->prefix = "/proc/meminfo"; + dpg->file = "/proc/meminfo"; + dpg->poll = dtop_meminfo_poll; + dpg->data_points = data_points; + dpg->priv = (struct dtop_meminfo_vars *)storage; + dpg->data_points_len = storage->line_count; + dpg->deconstruct = dtop_meminfo_dpg_deconstructor; + + dtop_register(dpg); +} + +/** + * @brief Scans "/proc/meminfo in order to autodetect dps. + * + * Searches through "/proc/meminfo" file for all available data + * points to create as dp structs. + * + * @param storage dtop_meminfo_vars struct where relevant variables are stored. + */ +int dtop_meminfo_search(struct dtop_meminfo_vars *storage) +{ + int i, k, n, sum; + char *data; + int *line_len = malloc(sizeof(int) * storage->line_count); + int read; + struct dt_procdict dict; + struct dtop_data_point *data_points; + + storage->line = malloc(storage->line_count * sizeof(*storage->line)); + + for (i = 0; i < storage->line_count; i++) + storage->line[i] = malloc(sizeof(char) * DTOP_MEM_LINE); + + read = dt_read_file("/proc/meminfo", &data, DTOP_MEM_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_MEM_LINE, data, + DTOP_MEM_SIZE, sum); + if (n < (storage->line_count - 1)) + sum += (line_len[n] + 1); + } + + /* Stores dp names in dictionary */ + for (i = 0; i < (storage->line_count); i++) + dt_parse_proc_same_line_key_and_val(storage->line[i], + line_len[i], i, &dict); + + data_points = malloc + (storage->line_count * sizeof(struct dtop_data_point)); + + k = 0; + /* Creates a dtop_data_point struct for each dp found in the file */ + for (i = 0; i < dict.max; i++) { + data_points[i].name = dict.key[i]; + data_points[i].prefix = NULL; + data_points[i].type = DTOP_ULONG; + k++; + } + + /* Calls dpg constructor, dpg will point to the dp struct */ + construct_meminfo_file_dpg(data_points, storage); + + free(line_len); + dt_free(&data); + + return DTOP_POLL_OK; +} + +/** + * @brief Calls dtop_search for "/proc/meminfo" file. + */ +void dtop_meminfo_init(void) +{ + struct dtop_meminfo_vars *storage = malloc + (sizeof(struct dtop_meminfo_vars)); + storage->line_count = dtop_get_file_line_amount("/proc/meminfo"); + dtop_meminfo_search(storage); +} diff --git a/dataservices/datatop/src/datatop_opt.c b/dataservices/datatop/src/datatop_opt.c new file mode 100644 index 0000000..c2bb366 --- /dev/null +++ b/dataservices/datatop/src/datatop_opt.c @@ -0,0 +1,184 @@ +/************************************************************************ +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_opt.c + * @brief Adds getopt functionality for CLI commands. + * + * Contains method for getopt functionality used for parsing + * the CLI arguments into executable commands. Handles + * errors which arise when parsing. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <getopt.h> +#include "datatop_opt.h" +#include "datatop_interface.h" +#include "datatop_linked_list.h" +#include "datatop_fileops.h" + +/** + * @brief Populate the comand line options with sane defaults + * + * @param clopts Struct used to hold data regarding CLI arguments. + */ +void dtop_load_default_options(struct cli_opts *clopts) +{ + memset(clopts, 0, sizeof(struct cli_opts)); + + clopts->priority = DEFAULT_NICE; +} + +/** + * @brief Parses all CLI commands for main() to execute. + * + * @param clopts Struct used to hold data regarding CLI arguments. + * @param argc Parameter used to read CLI commands from. + * @param argv Parameter used to read CLI arguments from. + * @return PARSE_SUCCESS - CLI arguments read successfully, + * @return PARSE_FAILURE - CLI arguments and/or input not valid. + * @return PARSE_FORCE_EXIT - Exit immediately, print help options. + */ +int dtop_parse_cli_opts(struct cli_opts *clopts, int argc, char **argv) +{ + int option; + + if (!clopts || !*argv) { + printf("Internal Error: Null Pointer\n"); + goto error; + } + + while ((option = getopt(argc, argv, "phi:t:w:s:n:")) != -1) { + switch (option) { + case 'p': + clopts->print_cl = OPT_CHOSE; + break; + + case 'h': + dtop_print_help_opts(); + return PARSE_FORCE_EXIT; + break; + + case 'n': + clopts->priority = strtol(optarg, 0, 10); + if (clopts->priority > 19 || clopts->priority < -20) { + printf("Argument for -n is not valid. "); + printf("Must be between -20 and 19.\n"); + goto error; + } + break; + + case 'i': + clopts->poll_per = strtol(optarg, 0, 10); + if (clopts->poll_per <= 0) { + printf("Argument for -i is not valid. "); + printf("Must be positive integer.\n"); + goto error; + } + break; + + case 't': + clopts->poll_time = strtol(optarg, 0, 10); + clopts->poll_time_selected = POLL_TIME_SELECTED; + if (clopts->poll_time <= 0) { + printf("Argument for -t is not valid. "); + printf("Must be positive integer.\n"); + goto error; + } + break; + + case 'w': + if (dtop_check_writefile_access(optarg) == VALID) { + clopts->file_name = optarg; + clopts->print_csv = OPT_CHOSE; + } else { + goto error; + } + break; + + case 's': + if (dtop_check_writefile_access(optarg) == VALID) + clopts->snapshot_file = optarg; + else + goto error; + break; + + case '?': + default: + goto error; + } + } + + if (clopts->poll_time == 0) { + if (clopts->print_csv == 1) + clopts->poll_time = POLL_NOT_SPECIFIED; + else + clopts->poll_time = POLL_TIME_DEFAULT; + } + if (clopts->poll_per == 0) + clopts->poll_per = DEFAULT_POLL_INTERVAL; + + return PARSE_SUCCESS; + +error: + printf("See datatop -h for help\n"); + return PARSE_FAILURE; +} + +/** + * @brief Prints the options the user has for the program to terminal. + */ +void dtop_print_help_opts(void) +{ + printf("The following datatop commands are:\n"); + printf("\t-p\t\t\tPrint output to terminal\n"); + printf("\t-i , seconds\t\tSpecify polling period\n"); + printf("\t-t , seconds\t\tSpecify polling duration\n"); + printf("\t-w , file name (.csv)\tWrite output to a file\n"); + printf("\t-s , file name\t\tPrint system snapshot to a file\n"); + printf("\t-n , nice value\t\tSet niceness (default 19)\n"); + printf("\t-h\t\t\tGet help\n"); +} + + +/** +* @brief Prints the interactive options the user can enter during runtime. +*/ +void dtop_print_interactive_opts(void) +{ + printf("The following interactive commands are:\n"); + printf("\tq | quit\tTerminate program at any time\n"); + printf("\ti\t\tPrint dp differences, reset initial dp values\n"); + printf("\tl\t\tPrint dp differences since last reset\n"); + printf("\n"); +} diff --git a/dataservices/datatop/src/datatop_opt.h b/dataservices/datatop/src/datatop_opt.h new file mode 100644 index 0000000..8f2d855 --- /dev/null +++ b/dataservices/datatop/src/datatop_opt.h @@ -0,0 +1,88 @@ +/************************************************************************ +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_opt.h + * @brief Declares methods and defines struct used within datatop_opt.c + * + * Struct defined is used when parsing the CLI arguments. + */ + +#ifndef DATATOP_OPT_H +#define DATATOP_OPT_H + +#define OPT_CHOSE 1 +#define OPT_NOT_CHOSE 0 +#define DEFAULT_POLL_INTERVAL 1 +#define POLL_NOT_SPECIFIED -1 +#define POLL_TIME_DEFAULT 30 +#define POLL_TIME_SELECTED 1 +#define PARSE_SUCCESS 0 +#define PARSE_FAILURE -1 +#define PARSE_FORCE_EXIT -2 +#define VALID 0 +#define INVALID -1 +#define DEFAULT_NICE 19 /* Lowest priority */ + +/** + * @struct cli_opts + * @brief Struct used to store arguments from CLI input. + * + * @var cli_opts::print_cl + * Represents -p argument. + * @var cli_opts::poll_per + * Polling frequency argument. + * @var cli_opts::poll_time + * Polling duration argument. + * @var cli_opts::cli_help + * Represents -h argument. + * @var cli_opts::file_name + * File name argument. + * @var cli_opts::print_csv + * Represents -w argument. + */ +struct cli_opts { + int print_cl; /* -p option */ + long int poll_per; /* -i option */ + long int poll_time; /* -t option */ + int cli_help; /* -h option */ + char *file_name; /* -w option */ + char *snapshot_file; /* -s option */ + int print_csv; + int poll_time_selected; + int priority; /* -n option (niceness) */ +}; + +int dtop_parse_cli_opts(struct cli_opts *clopts, int argc, char **argv); +void dtop_print_help_opts(void); +void dtop_print_interactive_opts(void); +void dtop_load_default_options(struct cli_opts *clopts); + +#endif /* DATATOP_OPT_H */ + diff --git a/dataservices/datatop/src/datatop_polling.h b/dataservices/datatop/src/datatop_polling.h new file mode 100644 index 0000000..d917474 --- /dev/null +++ b/dataservices/datatop/src/datatop_polling.h @@ -0,0 +1,49 @@ +/************************************************************************ +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_dual_line_poll.h + * @brief Declares methods held in datatop_dual_line_poll.c + */ + +#ifndef DATATOP_DUAL_LINE_POLL_H +#define DATATOP_DUAL_LINE_POLL_H + +void dtop_dual_line_init(char *name); +void dtop_single_line_init(char *name); +void dtop_value_only_init(char *name); +void dtop_meminfo_init(void); +void dtop_dev_init(void); +void dtop_stat_init(void); +void dtop_cpu_stats_init(void); +int dtop_value_only_poll(struct dtop_data_point_gatherer *dpg); +void dtop_value_only_dpg_deconstructor + (struct dtop_data_point_gatherer *dpset); + +#endif /* DATATOP_DUAL_LINE_POLL_H */ diff --git a/dataservices/datatop/src/datatop_single_line_poll.c b/dataservices/datatop/src/datatop_single_line_poll.c new file mode 100644 index 0000000..a43036f --- /dev/null +++ b/dataservices/datatop/src/datatop_single_line_poll.c @@ -0,0 +1,243 @@ +/************************************************************************ +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_single_line_poll.c + * @brief Adds ability for data collection from single line files + * + * File contains methods for searching and polling data from + * single line files, meaning a file with multiple lines, but each + * line contains the name of the dp, followed by the value. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "datatop_interface.h" +#include "datatop_fileops.h" +#include "datatop_str.h" + +#define DTOP_SINGLE_SIZE 8192 +#define DTOP_SINGLE_LINE (DTOP_SINGLE_SIZE>>2) + +/** +* @struct dtop_single_line_vars +* @brief Struct used to hold necessary variables for dual_line_file dpgs. +* +* @var dtop_single_line_vars::line +* Array of strings where necessary dp names and values are held. +* @var dtop_single_line_vars::line_count +* Number of lines the file is that the dpg represents. +*/ +struct dtop_single_line_vars { + char **line; + int line_count; +}; + +/** + * @brief Stores the data collected from a single_line files. + * + * @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_single_line_poll(struct dtop_data_point_gatherer *dpg) +{ + char *data; + int *line_len = malloc(sizeof(int) * + ((struct dtop_single_line_vars *) + (dpg->priv))->line_count); + int read; + struct dt_procdict dict; + int i, j, n, sum; + + read = dt_read_file(dpg->file, &data, DTOP_SINGLE_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_single_line_vars *) + (dpg->priv))->line_count; n++) { + line_len[n] = dt_read_line(((struct dtop_single_line_vars *) + (dpg->priv))->line[n], + DTOP_SINGLE_LINE, data, + DTOP_SINGLE_SIZE, sum); + if (n <= (((struct dtop_single_line_vars *) + (dpg->priv))->line_count - 1)) { + sum += (line_len[n] + 1); + } + + } + + /* Stores dp names and values in dictionary */ + for (i = 0; i < dpg->data_points_len; i++) + dt_parse_proc_same_line_key_and_val(( + (struct dtop_single_line_vars *) + (dpg->priv))->line[i], line_len[i], i, &dict); + + /* Assigns the dp value to the dp struct */ + for (j = 0; j < dpg->data_points_len; j++) { + i = dt_find_dict_idx(dpg->data_points[j].name, &dict); + if (i >= 0 && i < dict.max) + dtop_store_dp(&(dpg->data_points[j]), + dict.val[i]); + } + + dt_free(&data); + free(line_len); + return DTOP_POLL_OK; +} + +/** + * @brief Frees dynamically allocated single_line_file dpgs. + * + * 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_single_line_dpg_deconstructor + (struct dtop_data_point_gatherer *dpset) +{ + int i; + free(dpset->data_points); + for (i = 0; i < ((struct dtop_single_line_vars *) + (dpset->priv))->line_count; i++) + free(((struct dtop_single_line_vars *)(dpset->priv))->line[i]); + free(((struct dtop_single_line_vars *)(dpset->priv))->line); + free(((struct dtop_single_line_vars *)(dpset->priv))); + free(dpset); +} + +/** + * @brief Creates a dpg for a single_line file. + * + * Dynamically allocates memory for dpg which is then added to a linked list + * via the dtop_register(dpg) function call. + * + * @param name Name of file dpg represents. + * @param data_points dtop_data_point struct that dpg points to. + * @param storage dtop_single_line_vars struct that holds relevant dpg variables. + */ +static void construct_single_line_file_dpg(char *name, struct dtop_data_point + *data_points, struct dtop_single_line_vars *storage) +{ + struct dtop_data_point_gatherer *dpg = malloc + (sizeof(struct dtop_data_point_gatherer)); + dpg->prefix = name; + dpg->file = name; + dpg->poll = dtop_single_line_poll; + dpg->data_points = data_points; + dpg->priv = (struct dtop_single_line_vars *)storage; + dpg->data_points_len = storage->line_count; + dpg->deconstruct = dtop_single_line_dpg_deconstructor; + + dtop_register(dpg); +} + +/** + * @brief Scans a single_line file for all datapoints and creats dps. + * + * Searches through a single_line file (Key followed by value on the + * same line) for all available data points to create as dp structs. + * + * @param name Name of file. + * @param storage dtop_single_line_vars struct where relevant variables are stored. + */ +int dtop_single_line_search(char *name, struct dtop_single_line_vars *storage) +{ + int i, k, n, sum; + char *data; + int *line_len = malloc(sizeof(int) * storage->line_count); + int read; + struct dt_procdict dict; + struct dtop_data_point *data_points; + + storage->line = malloc(storage->line_count * sizeof(*storage->line)); + + for (i = 0; i < storage->line_count; i++) + storage->line[i] = malloc(sizeof(char) * DTOP_SINGLE_LINE); + + read = dt_read_file(name, &data, DTOP_SINGLE_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_SINGLE_LINE, data, + DTOP_SINGLE_SIZE, sum); + if (n < (storage->line_count - 1)) + sum += (line_len[n] + 1); + } + + /* Stores dp names and values in dictionary */ + for (i = 0; i < (storage->line_count); i++) + dt_parse_proc_same_line_key_and_val(storage->line[i], + line_len[i], i, &dict); + + data_points = malloc + (storage->line_count * sizeof(struct dtop_data_point)); + + k = 0; + /* Creates a dtop_data_point struct for each dp found in the file */ + for (i = 0; i < dict.max; i++) { + if (dict.val[i][0] == '-') + data_points[k].type = DTOP_LONG; + else + data_points[k].type = DTOP_ULONG; + data_points[i].name = dict.key[i]; + data_points[i].prefix = NULL; + k++; + } + + /* Calls dpg constructor, dpg will point to the dp struct */ + construct_single_line_file_dpg(name, data_points, storage); + + free(line_len); + dt_free(&data); + + return DTOP_POLL_OK; +} + +/** + * @brief Calls dtop_search for a files with single line format. + * + * Single line format refers to a file, where each line contains + * the name of a dp, followed by the value of a dp. + */ +void dtop_single_line_init(char *name) +{ + struct dtop_single_line_vars *storage = malloc + (sizeof(struct dtop_single_line_vars)); + storage->line_count = dtop_get_file_line_amount(name); + dtop_single_line_search(name, storage); +} diff --git a/dataservices/datatop/src/datatop_stat_poll.c b/dataservices/datatop/src/datatop_stat_poll.c new file mode 100644 index 0000000..88320b5 --- /dev/null +++ b/dataservices/datatop/src/datatop_stat_poll.c @@ -0,0 +1,319 @@ +/************************************************************************ +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_stat_poll.c + * @brief Adds ability for data collection from /proc/stat + * + * File contains methods for searching and polling data from + * "/proc/stat" + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "datatop_interface.h" +#include "datatop_fileops.h" +#include "datatop_str.h" + +#define DTOP_STAT_SIZE 16384 +#define DTOP_STAT_LINE (DTOP_STAT_SIZE>>2) + +/** +* @struct dtop_stat_vars +* @brief Struct used to hold necessary variables for /proc/stat dpg +* +* @var dtop_stat_vars::line +* Array of strings where necessary dp names and values are held. +* @var dtop_stat_vars::line_count +* Number of lines the file is that the dpg represents. +*/ +struct dtop_stat_vars { + char **line; + int line_count; +}; + +/** + * @brief Parses lines with data in "/proc/stat" + * + * @param line1 Line to parse to find datapoint names and values. + * @param len1 Length of line1. + * @param n_index Index in the dictionary the key (name) is added to. + * @param v_index Index in the dictionary the value is added to. + * @param dict Dictionary the keys and values are added to. + */ +static int dt_stat_parse(char *line1, int len1, + int n_index, int v_index, struct dt_procdict *dict) +{ + int i, k, j, start = 0; + if (len1 < 1) + return 0; + + if (line1 == 0 || dict == 0) + return 0; + + dict->key[n_index] = &line1[0]; + for (i = 0; i < len1; i++) { + if (line1[i] == ' ') { + line1[i] = 0; + start = (i+1); + break; + } + } + + k = v_index; + for (i = start; i < len1 && k < DTOP_DICT_SIZE; i++) { + if (line1[i] != ' ') { + dict->val[k] = &line1[i]; + for (j = i; j < len1; j++) { + if (line1[j] == ' ') { + line1[j] = 0; + break; + } + } + i = j; + k++; + } + } + + dict->max = k; + return k; +} + +/** + * @brief Stores the data collected from "/proc/stat" + * + * @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_stat_poll(struct dtop_data_point_gatherer *dpg) +{ + char *data; + int *line_len = malloc(sizeof(int) * + ((struct dtop_stat_vars *) + (dpg->priv))->line_count); + int read; + struct dt_procdict dict; + int i, n, sum; + int dp_count = 0; + + read = dt_read_file(dpg->file, &data, DTOP_STAT_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_stat_vars *) + (dpg->priv))->line_count; n++) { + line_len[n] = dt_read_line(((struct dtop_stat_vars *) + (dpg->priv))->line[n], + DTOP_STAT_LINE, data, + DTOP_STAT_SIZE, sum); + if (n <= (((struct dtop_stat_vars *) + (dpg->priv))->line_count - 1)) { + sum += (line_len[n] + 1); + } + + } + + /* Stores dp names and values in dictionary */ + for (i = 0; i < ((struct dtop_stat_vars *)(dpg->priv))->line_count; i++) + dp_count = dt_stat_parse(((struct dtop_stat_vars *) + (dpg->priv))->line[i], line_len[i], i, dp_count, &dict); + + /* Assigns the dp value to the dp struct */ + for (n = 0; n < dp_count; n++) { + dtop_store_dp(&(dpg->data_points[n]), + dict.val[n]); + } + + dt_free(&data); + free(line_len); + return DTOP_POLL_OK; +} + +/** + * @brief Frees dynamically allocated "/proc/stat" 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_stat_dpg_deconstructor + (struct dtop_data_point_gatherer *dpset) +{ + int i; + for (i = 0; i < dpset->data_points_len; i++) + free(dpset->data_points[i].name); + free(dpset->data_points); + for (i = 0; i < ((struct dtop_stat_vars *) + (dpset->priv))->line_count; i++) + free(((struct dtop_stat_vars *)(dpset->priv))->line[i]); + free(((struct dtop_stat_vars *)(dpset->priv))->line); + free(((struct dtop_stat_vars *)(dpset->priv))); + + free(dpset); +} + +/** + * @brief Creates a dpg for "/proc/stat" 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_stat_vars struct that holds relevant dpg variables. + * @param dp_count Number of data_points in data_points array + */ +static void construct_stat_file_dpg(struct dtop_data_point + *data_points, struct dtop_stat_vars *storage, int dp_count) +{ + struct dtop_data_point_gatherer *dpg = malloc + (sizeof(struct dtop_data_point_gatherer)); + dpg->prefix = "/proc/stat"; + dpg->file = "/proc/stat"; + dpg->poll = dtop_stat_poll; + dpg->data_points = data_points; + dpg->priv = (struct dtop_stat_vars *)storage; + dpg->data_points_len = dp_count; + dpg->deconstruct = dtop_stat_dpg_deconstructor; + + dtop_register(dpg); +} + +/** + * @brief Scans "/proc/stat" in order to autodetect dps. + * + * Searches through "/proc/stat" file for all available data + * points to create as dp structs. + * + * @param storage dtop_stat_vars struct where relevant variables are stored. + */ +int dtop_stat_search(struct dtop_stat_vars *storage) +{ + int i, n, sum; + char *data; + int *line_len = malloc(sizeof(int) * storage->line_count); + int read; + struct dt_procdict dict; + int dp_count = 0; + int end; + int *dp_per_line; + struct dtop_data_point *data_points; + int count = 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_STAT_LINE); + + read = dt_read_file("/proc/stat", &data, DTOP_STAT_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_STAT_LINE, data, + DTOP_STAT_SIZE, sum); + if (n < (storage->line_count - 1)) + sum += (line_len[n] + 1); + } + + dp_per_line = malloc(sizeof(int) * (storage->line_count)); + /* Stores dp names in dictionary */ + + for (i = 0; i < (storage->line_count); i++) { + end = dp_count; + dp_count = dt_stat_parse(storage->line[i], + line_len[i], i, dp_count, &dict); + dp_per_line[i] = (dp_count - end); + } + + data_points = malloc(dp_count * sizeof(struct dtop_data_point)); + + for (i = 0; i < (storage->line_count); i++) { + for (n = 0; n < dp_per_line[i]; n++) { + if (dp_per_line[i] == 1) { + int dk_len = strlen(dict.key[i]) + 1; + int dp_len; + char *newname = malloc(dk_len); + strlcpy(newname, dict.key[i], dk_len); + dp_len = strlen(newname) + 1; + data_points[count].name = malloc(dp_len); + strlcpy(data_points[count].name, newname, + dp_len); + free(newname); + } else { + char *add = malloc(15 * sizeof(char)); + char *newname; + int nn_len, dpn_len; + snprintf(add, 15 * sizeof(char), "[%d]:", n); + nn_len = strlen(dict.key[i]) + strlen(add) + 1; + newname = malloc(nn_len); + strlcpy(newname, dict.key[i], nn_len); + strlcat(newname, add, nn_len); + dpn_len = strlen(newname) + 1; + data_points[count].name = malloc(dpn_len); + strlcpy(data_points[count].name, newname, + dpn_len); + free(newname); + free(add); + } + data_points[count].prefix = NULL; + data_points[count].type = DTOP_ULONG; + data_points[count].initial_data_populated + = NOT_POPULATED; + data_points[count].skip = DO_NOT_SKIP; + count++; + } + } + + /* Calls dpg constructor, dpg will point to the dp struct */ + construct_stat_file_dpg(data_points, storage, dp_count); + free(dp_per_line); + free(line_len); + dt_free(&data); + + return DTOP_POLL_OK; +} + +/** + * @brief Calls dtop_search for "/proc/stat" file. + */ +void dtop_stat_init(void) +{ + struct dtop_stat_vars *storage = malloc + (sizeof(struct dtop_stat_vars)); + storage->line_count = dtop_get_file_line_amount("/proc/stat"); + dtop_stat_search(storage); +} diff --git a/dataservices/datatop/src/datatop_str.c b/dataservices/datatop/src/datatop_str.c new file mode 100644 index 0000000..3d25751 --- /dev/null +++ b/dataservices/datatop/src/datatop_str.c @@ -0,0 +1,260 @@ +/************************************************************************ +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_str.c + * @brief Algorithms used for storing and polling data created. + * + * Methods created which store collected data from files in + * dictionaries for many different file formats. + */ + +#include <stdio.h> +#include <string.h> +#include "datatop_str.h" + +/** @brief Reads an individual line from a file. + * + * Will read from buf2 until either a '\n' is reached, or the end of buf1 + * or buf2 is reached. The result is guaranteed to be null terminated. + * + * @param buf1 Destination buffer to store the read line. + * @param len1 Size of destination buffer. + * @param buf2 Source buffer to read lines from. Const, will not be + * modified by this function. + * @param len2 Size of the source buffer. + * @param start Offset (in bytes) to start reading from source buffer. + * @return Length of line (of chars). + */ +int dt_read_line(char *buf1, int len1, const char *buf2, int len2, int start) +{ + int i, j; + + if (len1 < 1 || len2 < 1 || start < 0 || start > len2) + return 0; + + if (buf1 == 0 || buf2 == 0) + return 0; + + i = 0; + j = start; + + while ((i < (len1-1)) && (j < len2)) { + buf1[i] = buf2[j]; + if (buf1[i] == '\n') + break; + i++; + j++; + } + buf1[i] = 0; + return i; +} + +/** + * @brief Parses files that have Names and Values on separate lines. + * + * Use this method to parse files that have names on one line, followed by + * the corresponding values on the next line. Such as "/proc/net/netstat" + * + * @param line1 First line that is parsed to store the datapoint names as keys. + * @param len1 Length of line1. + * @param line2 Second line that is parsed to store the datapoint values as dictionary values. + * @param len2 Length of line2. + * @param dict Dictionary that keys and values are added to. + * @return Number of key/val pairs in the dictionary. + */ +int dt_parse_proc_dictionary(char *line1, int len1, char *line2, + int len2, struct dt_procdict *dict) +{ + int i, j, k; + + if (len1 < 1 || len2 < 1) + return 0; + + if (line1 == 0 || line2 == 0 || dict == 0) + return 0; + + k = 0; + for (i = 0; i < len1 && k < DTOP_DICT_SIZE; i++) { + if (line1[i] == ' ') { + dict->key[k] = &line1[i+1]; + line1[i] = 0; + k++; + } + } + j = k; + + k = 0; + for (i = 0; i < len2 && k < DTOP_DICT_SIZE; i++) { + if (line2[i] == ' ') { + dict->val[k] = &line2[i+1]; + line2[i] = 0; + k++; + } + } + if (j != k) { + if (k < j) + j = k; + fprintf(stderr, "Warning, list index length mismatch\n"); + } + dict->max = j; + return j; +} + +/** + * @brief Parses line for prefixes for files that have individual data_point prefixes. + * + * Use this method for lines that have a prefix before data begins. Such as + * "/proc/net/snmp" + * + * @param line1 Line to parse to find datapoint prefix. + * @param len1 Length of line1. + * @param dict Dictionary prefix is being added to. + */ +void dt_parse_for_prefix(char *line1, int len1, struct dt_procdict *dict) +{ + int i, j, k; + + if (len1 < 1) + return; + + if (line1 == 0 || dict == 0) + return; + + k = 0; + for (i = 0; i < len1 && k < DTOP_DICT_SIZE; i++) { + if (line1[i] == ' ') { + dict->key[k] = &line1[i+1]; + line1[i] = 0; + k++; + } + } + + for (j = 0; j < k; j++) + dict->val[j] = &line1[0]; + + for (j = 0; j < len1; j++) { + if (line1[j] == ':') + line1[j] = 0; + } +} + +/** + * @brief Finds the dictionary index of a data_point name. + * + * @param str Name of data_point that is to be located in dict. + * @param dict Dictionary to look through for dp name. + * @return Dictionary index of name if found. + * @return -1 if name not found in dictionary keys. + */ +int dt_find_dict_idx(const char *str, struct dt_procdict *dict) +{ + int i; + if (str == 0 || dict == 0) + return -1; + + for (i = 0; i < dict->max; i++) { + if (dict->key[i] && !strcmp(str, dict->key[i])) + return i; + } + return -1; +} + +/** + * @brief Parses files that have Names and Values on same line. + * + * Use this method to parse lines that have a dp name followed + * by a dp value. Such as "/proc/net/snmp6" + * + * @param line1 Line to parse to find datapoint names and values. + * @param len1 Length of line1. + * @param l Index in the dictionary the key/val pair is added to. + * @param dict Dictionary the keys and values are added to. + * @return Number of key/val pairs in the dictionary. + */ +int dt_parse_proc_same_line_key_and_val(char *line1, int len1, + int l, struct dt_procdict *dict) +{ + int i, k, n; + if (len1 < 1) + return 0; + + if (line1 == 0 || dict == 0) + return 0; + + k = l; + for (i = 0; i < len1 && k < DTOP_DICT_SIZE; i++) { + if (line1[i] == ' ') { + dict->key[k] = &line1[0]; + line1[i] = 0; + for (n = i+1; n < len1; n++) { + if (line1[n] != ' ') { + dict->val[k] = &line1[n+1]; + break; + } + } + break; + } + } + k++; + dict->max = k; + return k; +} + +/** + * @brief Parses files that have a single line. + * + * Parses a single line file for csv, tab-separated, space-separated, and single + * value formats and adds values to a dictionary. Such as + * "/proc/sys/net/ipv4/ping_group_range" + * + * Use this method to parse lines that contain only values. + * + * @param line1 Line to parse. + * @param len1 Length of line1. + * @param dict Dictionary datapoints are added to. + * @return Number of values dictionary holds. + */ +int dt_single_line_parse(char *line1, int len1, struct dt_procdict *dict) +{ + int i, k; + k = 0; + dict->val[k] = &line1[0]; + k++; + + for (i = 0; i < len1; i++) { + if (line1[i] == ' ' || line1[i] == ',' || line1[i] == ' ') { + line1[i] = 0; + dict->val[k] = &line1[i+1]; + k++; + } + } + dict->max = k; + return k; +} diff --git a/dataservices/datatop/src/datatop_str.h b/dataservices/datatop/src/datatop_str.h new file mode 100644 index 0000000..1f30370 --- /dev/null +++ b/dataservices/datatop/src/datatop_str.h @@ -0,0 +1,70 @@ +/************************************************************************ +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_str.h + * @brief Declares methods held in datatop_str.c and defines dictionary struct. + */ + +#ifndef DATATOP_STR_H +#define DATATOP_STR_H + +#define DTOP_DICT_SIZE 2048 + +/** + * @struct dt_procdict + * @brief Struct used to create dictionary for parsing purposes. + * + * @var dt_procdict::max + * Number of key/val pairs in dictionary. + * @var dt_procdict::key + * Holds the key that is used to access the value. + * @var dt_procdict::val + * Value that the key accesses. + */ +struct dt_procdict { + int max; + char *key[DTOP_DICT_SIZE]; + char *val[DTOP_DICT_SIZE]; +}; + +int dt_read_line(char *buf1, int len1, const char *buf2, int len2, int start); + +int dt_parse_proc_dictionary(char *line1, int len1, char *line2, int len2, + struct dt_procdict *dict); + +int dt_find_dict_idx(const char *str, struct dt_procdict *dict); + +int dt_parse_proc_same_line_key_and_val(char *line1, int len1, int l, + struct dt_procdict *dict); + +void dt_parse_for_prefix(char *line1, int len1, struct dt_procdict *dict); + +int dt_single_line_parse(char *line1, int len1, struct dt_procdict *dict); +#endif /* DATATOP_STR_H */ diff --git a/dataservices/datatop/src/datatop_sys_snap.c b/dataservices/datatop/src/datatop_sys_snap.c new file mode 100644 index 0000000..ee9ea95 --- /dev/null +++ b/dataservices/datatop/src/datatop_sys_snap.c @@ -0,0 +1,199 @@ +/************************************************************************ +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. +************************************************************************/ + +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> + +#include "datatop_interface.h" +#include "datatop_fileops.h" +#include "datatop_str.h" +#include "datatop_opt.h" + +#define DTOP_SNAP_SIZE 8192 +#define DTOP_SNAP_LINE (DTOP_SNAP_SIZE>>2) + +static int dtop_system_snapshot_helper_print(char *file, const char *str) +{ + FILE *snap_file = fopen(file, "a"); + + if (snap_file) { + if (fprintf(snap_file, "%s", str) < 0) { + fclose(snap_file); + return FILE_ERROR; + } + } else { + return FILE_ERROR; + } + fflush(snap_file); + fclose(snap_file); + return FILE_SUCCESS; +} + +/** + * @brief A helper function to dtop_print_system_snapshot. + * + * @param fw File that desired system data is printed to. + * @return FILE_ERROR - Writing to file was unsuccessful. + * @return FILE_SUCCESS - Writing to file was successful. + */ +static int dtop_run_and_log(char *file, const char *c1, const char **args) +{ + int i; + pid_t child_pid; + + i = 0; + dtop_system_snapshot_helper_print(file, "\n" + "--------------------------------------------------------------\n" + "Command: "); + while(args[i] != 0) { + dtop_system_snapshot_helper_print(file, args[i++]); + dtop_system_snapshot_helper_print(file, " "); + } + dtop_system_snapshot_helper_print(file, "\n"); + + + child_pid = fork(); + if (child_pid == 0) { + int fd = open(file, O_WRONLY | O_APPEND | O_CREAT, + S_IRUSR | S_IWUSR); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + execvp(c1, (char * const *)args); + printf("Failed to execute %s\n", c1); + printf("errno=%d error=%s\n", errno, strerror(errno)); + close(STDOUT_FILENO); + close(STDERR_FILENO); + exit(0); + } else if (child_pid < 0) { + return FILE_ERROR; + } else { + int return_status; + waitpid(child_pid, &return_status, 0); + + if (return_status != 0) + return FILE_ERROR; + } + + return FILE_SUCCESS; +} + + + +/* IPv4 */ +const char *ip_addr_cmd[] = {"ip", "addr", 0}; +const char *ip_route_cmd[] = {"ip", "route", 0}; +const char *ip_route_all_tables_cmd[] = {"ip", "route", "show", "table", "all", 0}; +const char *ip_rule_cmd[] = {"ip", "rule", "show", 0}; +const char *ip_tables_cmd[] = {"iptables", "-L", "-n", "-v", 0}; +const char *ip_tables_nat_cmd[] = {"iptables", "-t", "nat", "-L", "-n", "-v", 0}; +const char *ip_tables_mangle_cmd[] = {"iptables", "-t", "mangle", "-L", "-n", "-v", 0}; +const char *ip_tables_raw_cmd[] = {"iptables", "-t", "raw", "-L", "-n", "-v", 0}; + +/* IPv6 */ +const char *ip6_addr_cmd[] = {"ip", "-6", "addr", 0}; +const char *ip6_route_cmd[] = {"ip", "-6", "route", 0}; +const char *ip6_route_all_tables_cmd[] = {"ip", "-6", "route", "show", "table", "all", 0}; +const char *ip6_rule_cmd[] = {"ip", "-6", "rule", "show", 0}; +const char *ip6_tables_cmd[] = {"ip6tables", "-L", "-n", "-v", 0}; +const char *ip6_tables_nat_cmd[] = {"ip6tables", "-t", "nat", "-L", "-n", "-v", 0}; +const char *ip6_tables_mangle_cmd[] = {"ip6tables", "-t", "mangle", "-L", "-n", "-v", 0}; +const char *ip6_tables_raw_cmd[] = {"ip6tables", "-t", "raw", "-L", "-n", "-v", 0}; + +/* Misc */ +const char *rps_config[] = {"cat", "/sys/class/net/rmnet_mhi0/queues/rx-0/rps_cpus", 0}; +const char *if_config[] = {"/data/busybox/busybox", "ifconfig", 0}; +const char *netcfg[] = {"netcfg", 0}; +const char *softnet_stat[] = {"cat", "/proc/net/softnet_stat", 0}; + +/* XFRM logging */ +const char *xfrm_state[] = {"ip", "xfrm", "state", "show", 0}; +const char *xfrm_policy[] = {"ip", "xfrm", "policy", "show", 0}; +const char *xfrm_netstat[] = {"cat", "/proc/net/xfrm_stat", 0}; + +#define DO_DTOP_RUN_AND_LOG(X) \ + dtop_run_and_log(file, X[0], X); +/** + * @brief Prints a System snapshot to a file specified by the user. + * + * @param fw File that system snapshot is printed to. + * @return FILE_ERROR - Writing to file was unsuccessful. + * @return FILE_SUCCESS - Writing to file was successful. + */ +int dtop_print_system_snapshot(char *file) +{ + dtop_system_snapshot_helper_print(file, + "==============================================================\n" + " System Data Snapshot - Captured with Data Top \n" + " Version "); + dtop_system_snapshot_helper_print(file, VERSION); + dtop_system_snapshot_helper_print(file, "\n" + "==============================================================\n" + "\n"); + + /* IPv4 */ + DO_DTOP_RUN_AND_LOG(ip_addr_cmd); + DO_DTOP_RUN_AND_LOG(ip_route_cmd); + DO_DTOP_RUN_AND_LOG(ip_route_all_tables_cmd); + DO_DTOP_RUN_AND_LOG(ip_rule_cmd); + DO_DTOP_RUN_AND_LOG(ip_tables_cmd); + DO_DTOP_RUN_AND_LOG(ip_tables_nat_cmd); + DO_DTOP_RUN_AND_LOG(ip_tables_mangle_cmd); + DO_DTOP_RUN_AND_LOG(ip_tables_raw_cmd); + + /* IPv6 */ + DO_DTOP_RUN_AND_LOG(ip6_addr_cmd); + DO_DTOP_RUN_AND_LOG(ip6_route_cmd); + DO_DTOP_RUN_AND_LOG(ip6_route_all_tables_cmd); + DO_DTOP_RUN_AND_LOG(ip6_rule_cmd); + DO_DTOP_RUN_AND_LOG(ip6_tables_cmd); + DO_DTOP_RUN_AND_LOG(ip6_tables_nat_cmd); + DO_DTOP_RUN_AND_LOG(ip6_tables_mangle_cmd); + DO_DTOP_RUN_AND_LOG(ip6_tables_raw_cmd); + + /* Misc */ + DO_DTOP_RUN_AND_LOG(rps_config); + DO_DTOP_RUN_AND_LOG(if_config); + DO_DTOP_RUN_AND_LOG(netcfg); + DO_DTOP_RUN_AND_LOG(softnet_stat); + + /* XFRM logging */ + DO_DTOP_RUN_AND_LOG(xfrm_state); + DO_DTOP_RUN_AND_LOG(xfrm_policy); + DO_DTOP_RUN_AND_LOG(xfrm_netstat); + + return FILE_SUCCESS; +} diff --git a/dataservices/datatop/src/datatop_value_only_poll.c b/dataservices/datatop/src/datatop_value_only_poll.c new file mode 100644 index 0000000..bf6fc54 --- /dev/null +++ b/dataservices/datatop/src/datatop_value_only_poll.c @@ -0,0 +1,201 @@ +/************************************************************************ +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_value_only_poll.c + * @brief Adds ability for data collection from files with only values + * + * File contains methods for searching and polling data from + * value_only files, meaning a file with a single line, containing + * only values. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "datatop_interface.h" +#include "datatop_fileops.h" +#include "datatop_str.h" + +#define DTOP_SINGLE_SIZE 8192 +#define DTOP_SINGLE_LINE (DTOP_SINGLE_SIZE>>2) + +/** + * @brief Stores the data collected from a value_only files. + * + * @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_value_only_poll(struct dtop_data_point_gatherer *dpg) +{ + char *data; + int line_len; + char line[DTOP_SINGLE_LINE]; + int read; + struct dt_procdict dict; + int j; + FILE *check = fopen(dpg->file, "r"); + if (check) { + fclose(check); + read = dt_read_file(dpg->file, &data, DTOP_SINGLE_SIZE); + } else { + return DTOP_POLL_IO_ERR; + } + + if (read == 0 || data == 0) + return DTOP_POLL_IO_ERR; + + line_len = dt_read_line(line, DTOP_SINGLE_LINE, data, + DTOP_SINGLE_SIZE, 0); + + /* Stores dp values in dictionary */ + dt_single_line_parse(line, line_len, &dict); + + /* Assigns the dp value to the dp struct */ + for (j = 0; j < dpg->data_points_len; j++) + dtop_store_dp(&(dpg->data_points[j]), dict.val[j]); + + dt_free(&data); + return DTOP_POLL_OK; +} + +/** + * @brief Frees dynamically allocated single line 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. + */ +void dtop_value_only_dpg_deconstructor + (struct dtop_data_point_gatherer *dpset) +{ + int i; + for (i = 0; i < dpset->data_points_len; i++) + free(dpset->data_points[i].name); + free(dpset->data_points); + free(dpset->file); + free(dpset); +} + +/** + * @brief Creates a dpg for a single line file. + * + * Dynamically allocates memory for dpg which is then added to a linked list + * via the dtop_register(dpg) function call. + * + * @param name Name of file dpg represents. + * @param data_points dtop_data_point struct that dpg points to. + * @param dp_count Number of data_points in data_points array + */ +static void construct_value_only_dpg(char *name, struct dtop_data_point + *data_points, int dp_count) +{ + struct dtop_data_point_gatherer *dpg = malloc + (sizeof(struct dtop_data_point_gatherer)); + dpg->prefix = name; + dpg->file = name; + dpg->poll = dtop_value_only_poll; + dpg->data_points = data_points; + dpg->data_points_len = dp_count; + dpg->deconstruct = dtop_value_only_dpg_deconstructor; + + dtop_register(dpg); +} + +/** + * @brief Scans a single line file in order to autodetect dps. + * + * Searches through a file that contains a single line and only + * values in order to detect and create dp's/ + * + * @param name Name of file to scan. + */ +int dtop_value_only_search(char *name) +{ + int i; + char *data; + char line[DTOP_SINGLE_LINE]; + int line_len; + int read; + struct dt_procdict dict; + struct dtop_data_point *data_points; + + + read = dt_read_file(name, &data, DTOP_SINGLE_SIZE); + if (read == 0 || data == 0) { + free(name); + return DTOP_POLL_IO_ERR; + } + + line_len = dt_read_line(line, + DTOP_SINGLE_LINE, data, + DTOP_SINGLE_SIZE, 0); + + /* Stores dp values in dictionary */ + dt_single_line_parse(line, line_len, &dict); + + data_points = malloc(dict.max * sizeof(struct dtop_data_point)); + + /* Creates a dtop_data_point struct for each dp found in the file */ + for (i = 0; i < dict.max; i++) { + char *newname = malloc(sizeof(10)); + if (dict.val[i][0] == '-') + data_points[i].type = DTOP_LONG; + else + data_points[i].type = DTOP_ULONG; + data_points[i].name = malloc(sizeof(10)); + if (dict.max > 1) + snprintf(newname, sizeof(10), "[%d]:", i); + else + strlcpy(newname, "", sizeof(10)); + strlcpy(data_points[i].name, newname, sizeof(10)); + free(newname); + data_points[i].prefix = NULL; + data_points[i].skip = DO_NOT_SKIP; + data_points[i].initial_data_populated = NOT_POPULATED; + } + + /* Calls dpg constructor, dpg will point to the dp struct */ + construct_value_only_dpg(name, data_points, dict.max); + + dt_free(&data); + return DTOP_POLL_OK; +} + +/** + * @brief Calls dtop_search for files with a single line and only values. + */ +void dtop_value_only_init(char *name) +{ + char *file = malloc(strlen(name) + 1); + strlcpy(file, name, strlen(name) + 1); + dtop_value_only_search(file); +} diff --git a/dataservices/rmnetctl/Android.mk b/dataservices/rmnetctl/Android.mk new file mode 100644 index 0000000..8338432 --- /dev/null +++ b/dataservices/rmnetctl/Android.mk @@ -0,0 +1,2 @@ +include $(call all-subdir-makefiles) + diff --git a/dataservices/rmnetctl/cli/Android.mk b/dataservices/rmnetctl/cli/Android.mk new file mode 100644 index 0000000..92503c2 --- /dev/null +++ b/dataservices/rmnetctl/cli/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := rmnetcli.c +LOCAL_CFLAGS := -Wall -Werror + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../inc +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../src +LOCAL_C_INCLUDES += $(LOCAL_PATH) + +LOCAL_MODULE := rmnetcli +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_OWNER := qcom +LOCAL_PROPRIETARY_MODULE := true + +LOCAL_SHARED_LIBRARIES := librmnetctl +include $(BUILD_EXECUTABLE) diff --git a/dataservices/rmnetctl/cli/Makefile.am b/dataservices/rmnetctl/cli/Makefile.am new file mode 100644 index 0000000..a17b79e --- /dev/null +++ b/dataservices/rmnetctl/cli/Makefile.am @@ -0,0 +1,9 @@ +AM_CFLAGS = -Wall -Werror -Wundef -Wstrict-prototypes -Wno-trigraphs +AM_CFLAGS += -I./../inc +rmnetcli_SOURCES = rmnetcli.c +bin_PROGRAMS = rmnetcli +requiredlibs = ../src/librmnetctl.la +rmnetcli_LDADD = $(requiredlibs) +LOCAL_MODULE := librmnetctl +LOCAL_PRELINK_MODULE := false +include $(BUILD_SHARED_LIBRARY) diff --git a/dataservices/rmnetctl/cli/rmnetcli.c b/dataservices/rmnetctl/cli/rmnetcli.c new file mode 100644 index 0000000..2275ec2 --- /dev/null +++ b/dataservices/rmnetctl/cli/rmnetcli.c @@ -0,0 +1,415 @@ +/****************************************************************************** + + R M N E T C L I . C + +Copyright (c) 2013-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 rmnetcli.c + @brief command line interface to expose rmnet control API's + + DESCRIPTION + File containing implementation of the command line interface to expose the + rmnet control configuration . + +******************************************************************************/ + +/*=========================================================================== + INCLUDE FILES +===========================================================================*/ + +#include <sys/socket.h> +#include <stdint.h> +#include <linux/netlink.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include "rmnetcli.h" +#include "librmnetctl.h" + +#define RMNET_MAX_STR_LEN 16 + +#define _RMNETCLI_CHECKNULL(X) do { if (!X) { \ +print_rmnet_api_status(RMNETCTL_INVALID_ARG, RMNETCTL_CFG_FAILURE_NO_COMMAND); \ + rmnetctl_cleanup(handle); \ + return RMNETCTL_INVALID_ARG; \ + } } while (0); +#define _STRTOUI32(X) (uint32_t)strtoul(X, NULL, 0) +#define _STRTOUI16(X) (uint16_t)strtoul(X, NULL, 0) +#define _STRTOUI8(X) (uint8_t)strtoul(X, NULL, 0) +#define _STRTOI32(X) (int32_t)strtol(X, NULL, 0) + +#define _5TABS "\n\t\t\t\t\t" +#define _2TABS "\n\t\t" + +/*! +* @brief Contains a list of error message from CLI +*/ +char rmnetcfg_error_code_text +[RMNETCFG_TOTAL_ERR_MSGS][RMNETCTL_ERR_MSG_SIZE] = { + "Help option Specified", + "ERROR: No\\Invalid command was specified\n", + "ERROR: Could not allocate buffer for Egress device\n" +}; + +/*! +* @brief Method to display the syntax for the commands +* @details Displays the syntax and usage for the commands +* @param void +* @return void +*/ +static void rmnet_api_usage(void) +{ + printf("RmNet API Usage:\n\n"); + printf("rmnetcli help Displays this help\n"); + printf("\n"); + printf("rmnetcli assocnetdev <dev_name> Registers the RmNet"); + printf(_5TABS" data driver on a particular"); + printf(_5TABS" device.dev_name cannot"); + printf(_5TABS" be larger than 15"); + printf(_5TABS" characters. Returns"); + printf(_5TABS" the status code.\n\n"); + printf("rmnetcli unassocnetdev <dev_name> Unregisters the"); + printf(_5TABS" RmNet data driver on a particular"); + printf(_5TABS" device. dev_name cannot"); + printf(_5TABS" be larger than 15"); + printf(_5TABS" characters. Returns"); + printf(_5TABS" the status code.\n\n"); + printf("rmnetcli getnetdevassoc <dev_name> Get if the RmNet"); + printf(_5TABS" data driver is registered on"); + printf(_5TABS" a particular device."); + printf(_5TABS" dev_name cannot be"); + printf(_5TABS" larger than 15"); + printf(_5TABS" characters. Returns 1"); + printf(_5TABS" if is registered and"); + printf(_5TABS" 0 if it is not"); + printf(_5TABS" registered\n\n"); + printf("rmnetcli setledf <egress_flags> Sets the egress data"); + printf(_2TABS" <agg_size> format for a particular link."); + printf(_2TABS" <agg_count> dev_name cannot be larger"); + printf(_2TABS" <dev_name> than 15 characters."); + printf(_5TABS" Returns the status code\n\n"); + printf("rmnetcli getledf <dev_name> Gets the egress data"); + printf(_5TABS" format for a particular link."); + printf(_5TABS" dev_name cannot be larger"); + printf(_5TABS" than 15. Returns the 4"); + printf(_5TABS" byte unsigned integer"); + printf(_5TABS" egress_flags\n\n"); + printf("rmnetcli setlidf <ingress_flags> Sets the ingress"); + printf(_2TABS" <tail_spacing> data format for a particular"); + printf(_2TABS" <dev_name> link. ingress_flags is 4"); + printf(_5TABS" byte unsigned integer."); + printf(_5TABS" tail_spacing is a one."); + printf(_5TABS" byte unsigned integer."); + printf(_5TABS" dev_name cannot be"); + printf(_5TABS" larger than 15."); + printf(_5TABS" characters. Returns"); + printf(_5TABS" the status code\n\n"); + printf("rmnetcli getlidf <dev_name> Gets the ingress"); + printf(_5TABS" data format for a particular"); + printf(_5TABS" link. dev_name cannot be"); + printf(_5TABS" larger than 15. Returns"); + printf(_5TABS" the 4 byte unsigned"); + printf(_5TABS" integer ingress_flags\n\n"); + printf("rmnetcli setlepc <logical_ep_id> Sets the logical"); + printf(_2TABS" <rmnet_mode> endpoint configuration for"); + printf(_2TABS" <dev_name> a particular link."); + printf(_2TABS" <egress_dev_name> logical_ep_id are 32bit"); + printf(_5TABS" integers from -1 to 31."); + printf(_5TABS" rmnet_mode is a 1 byte"); + printf(_5TABS" unsigned integer of"); + printf(_5TABS" value none, vnd or"); + printf(_5TABS" bridged. dev_name"); + printf(_5TABS" and egress_dev_name"); + printf(_5TABS" cannot be larger"); + printf(_5TABS" than 15 characters"); + printf(_5TABS" Returns the status code\n\n"); + printf("rmnetcli unsetlepc <logical_ep_id> Un-sets the logical"); + printf(_2TABS" <dev_name> endpoint configuration for"); + printf(_5TABS" a particular link."); + printf(_5TABS" integers from -1 to 31."); + printf(_5TABS" dev_name cannot be larger"); + printf(_5TABS" than 15 characters"); + printf(_5TABS" Returns the status code\n\n"); + printf("rmnetcli getlepc <logical_ep_id> Sets the logical"); + printf(_2TABS" <dev_name> endpoint configuration for a"); + printf(_5TABS" particular link."); + printf(_5TABS" logical_ep_id are 32bit"); + printf(_5TABS" integers from -1 to 31."); + printf(_5TABS" Returns the rmnet_mode"); + printf(_5TABS" and egress_dev_name."); + printf(_5TABS" rmnet_mode is a 1"); + printf(_5TABS" byte unsigned integer"); + printf(_5TABS" of value none, vnd or"); + printf(_5TABS" bridged. dev_name and"); + printf(_5TABS" egress_dev_name cannot be"); + printf(_5TABS" larger than 15 "); + printf(_5TABS" characters. Returns the"); + printf(_5TABS" status code\n\n"); + printf("rmnetcli newvnd <dev_id> Creates a new"); + printf(_5TABS" virtual network device node."); + printf(_5TABS" dev_id is an int"); + printf(_5TABS" less than 32. Returns"); + printf(_5TABS" the status code\n\n"); + printf("rmnetcli newvndprefix <dev_id> <name_prefix> Creates"); + printf(_5TABS" virtual network device node."); + printf(_5TABS" dev_id is an int"); + printf(_5TABS" less than 32. Prefix"); + printf(_5TABS" must be less than"); + printf(_5TABS" 15 chars. Returns"); + printf(_5TABS" the status code\n\n"); + printf("rmnetcli getvndname <dev_id> Get name of"); + printf(_5TABS" network device node from id\n\n"); + printf("rmnetcli freevnd <dev_id> Removes virtual"); + printf(_5TABS" network device node. dev_name"); + printf(_5TABS" cannot be larger than 15."); + printf(_5TABS" Returns the status code\n\n"); + printf("rmnetcli addvnctcflow <dev_id> Add a modem flow"); + printf(_2TABS" <mdm_flow_hndl> handle - tc flow handle"); + printf(_2TABS" <tc_flow_hndl> mapping for a virtual network"); + printf(_2TABS" device node\n\n"); + printf("rmnetcli delvnctcflow <dev_id> Delete a modem flow"); + printf(_2TABS" <mdm_flow_hndl> handle - tc flow handle"); + printf(_2TABS" <tc_flow_hndl> mapping for a virtual network"); + printf(_2TABS" device node\n\n"); +} + +static void print_rmnetctl_lib_errors(uint16_t error_number) +{ + if ((error_number > RMNETCTL_API_SUCCESS) && + (error_number < RMNETCTL_API_ERR_ENUM_LENGTH)) { + printf("%s", rmnetctl_error_code_text[error_number]); + } + if ((error_number >= RMNETCFG_ERR_NUM_START) && + (error_number < RMNETCFG_ERR_NUM_START + RMNETCFG_TOTAL_ERR_MSGS)) { + printf("%s", rmnetcfg_error_code_text + [error_number - RMNETCFG_ERR_NUM_START]); + if ((error_number == RMNETCTL_CFG_SUCCESS_HELP_COMMAND) || + (error_number == RMNETCTL_CFG_FAILURE_NO_COMMAND)) + rmnet_api_usage(); + } +} + +/*! +* @brief Method to check the error numbers generated from API calls +* @details Displays the error messages based on each error code +* @param error_number Error number returned from the API and the CLI +* @return void +*/ +static void print_rmnet_api_status(int return_code, uint16_t error_number) +{ + if (return_code == RMNETCTL_SUCCESS) + printf("SUCCESS\n"); + else if (return_code == RMNETCTL_LIB_ERR) { + printf("LIBRARY "); + print_rmnetctl_lib_errors(error_number); + } else if (return_code == RMNETCTL_KERNEL_ERR) + printf("KERNEL %s", rmnetctl_error_code_text[error_number]); + else if (return_code == RMNETCTL_INVALID_ARG) + printf("INVALID_ARG\n"); +} + +/*! +* @brief Method to make the API calls +* @details Checks for each type of parameter and calls the appropriate +* function based on the number of parameters and parameter type +* @param argc Number of arguments which vary based on the commands +* @param argv Value of the arguments which vary based on the commands +* @return RMNETCTL_SUCCESS if successful. Relevant data might be printed +* based on the message type +* @return RMNETCTL_LIB_ERR if there was a library error. Error code will be +* printed +* @return RMNETCTL_KERNEL_ERR if there was a error in the kernel. Error code will be +* printed +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ + +static int rmnet_api_call(int argc, char *argv[]) +{ + struct rmnetctl_hndl_s *handle = NULL; + uint16_t error_number = RMNETCTL_CFG_FAILURE_NO_COMMAND; + int return_code = RMNETCTL_LIB_ERR; + if ((!argc) || (!*argv)) { + print_rmnet_api_status(RMNETCTL_LIB_ERR, + RMNETCTL_CFG_FAILURE_NO_COMMAND); + return RMNETCTL_LIB_ERR; + } + if (!strcmp(*argv, "help")) { + print_rmnet_api_status(RMNETCTL_LIB_ERR, + RMNETCTL_CFG_SUCCESS_HELP_COMMAND); + return RMNETCTL_LIB_ERR; + } + return_code = rmnetctl_init(&handle, &error_number); + if (return_code!= RMNETCTL_SUCCESS) { + print_rmnet_api_status(return_code, error_number); + return RMNETCTL_LIB_ERR; + } + error_number = RMNETCTL_CFG_FAILURE_NO_COMMAND; + return_code = RMNETCTL_LIB_ERR; + if (!strcmp(*argv, "assocnetdev")) { + return_code = rmnet_associate_network_device(handle, + argv[1], &error_number, RMNETCTL_DEVICE_ASSOCIATE); + } else if (!strcmp(*argv, "unassocnetdev")) { + return_code = rmnet_associate_network_device(handle, + argv[1], &error_number, RMNETCTL_DEVICE_UNASSOCIATE); + } else if (!strcmp(*argv, "getnetdevassoc")) { + int register_status; + return_code = rmnet_get_network_device_associated(handle, + argv[1], ®ister_status, &error_number); + if (return_code == RMNETCTL_SUCCESS) + printf("register_status is %d\n", register_status); + } else if (!strcmp(*argv, "getledf")) { + uint32_t egress_flags; + uint16_t agg_size, agg_count; + return_code = rmnet_get_link_egress_data_format(handle, + argv[1], &egress_flags, &agg_size, &agg_count, &error_number); + if (return_code == RMNETCTL_SUCCESS) { + printf("egress_flags is %u\n", egress_flags); + printf("agg_size is %u\n", agg_size); + printf("agg_count is %u\n", agg_count); + } + } else if (!strcmp(*argv, "getlidf")) { + uint32_t ingress_flags; + uint8_t tail_spacing; + return_code = rmnet_get_link_ingress_data_format_tailspace( + handle, argv[1], &ingress_flags, &tail_spacing, &error_number); + if (return_code == RMNETCTL_SUCCESS) { + printf("ingress_flags is %u\n", ingress_flags); + printf("tail_spacing is %u\n", tail_spacing); + } + } else if (!strcmp(*argv, "newvndprefix")) { + _RMNETCLI_CHECKNULL(argv[1]); + _RMNETCLI_CHECKNULL(argv[2]); + return_code = rmnet_new_vnd_prefix(handle, + _STRTOUI32(argv[1]), &error_number, RMNETCTL_NEW_VND, argv[2]); + } else if (!strcmp(*argv, "newvnd")) { + _RMNETCLI_CHECKNULL(argv[1]); + return_code = rmnet_new_vnd(handle, + _STRTOUI32(argv[1]), &error_number, RMNETCTL_NEW_VND); + } else if (!strcmp(*argv, "getvndname")) { + char buffer[32]; + memset(buffer, 0, 32); + _RMNETCLI_CHECKNULL(argv[1]); + return_code = rmnet_get_vnd_name(handle, _STRTOUI32(argv[1]), + &error_number, buffer, 32); + if (return_code == RMNETCTL_SUCCESS) { + printf("VND name: %s\n", buffer); + } + } else if (!strcmp(*argv, "freevnd")) { + _RMNETCLI_CHECKNULL(argv[1]); + return_code = rmnet_new_vnd(handle, + _STRTOUI32(argv[1]), &error_number, RMNETCTL_FREE_VND); + } else if (!strcmp(*argv, "setlidf")) { + _RMNETCLI_CHECKNULL(argv[1]); + _RMNETCLI_CHECKNULL(argv[2]); + _RMNETCLI_CHECKNULL(argv[3]); + return_code = rmnet_set_link_ingress_data_format_tailspace( + handle, _STRTOUI32(argv[1]), _STRTOUI8(argv[2]), argv[3], + &error_number); + } else if (!strcmp(*argv, "delvnctcflow")) { + _RMNETCLI_CHECKNULL(argv[1]); + _RMNETCLI_CHECKNULL(argv[2]); + _RMNETCLI_CHECKNULL(argv[3]); + return_code = rmnet_add_del_vnd_tc_flow(handle, + _STRTOUI32(argv[1]), _STRTOUI32(argv[2]), _STRTOUI32(argv[3]), + RMNETCTL_DEL_FLOW, &error_number); + } else if (!strcmp(*argv, "getlepc")) { + _RMNETCLI_CHECKNULL(argv[1]); + uint8_t rmnet_mode; + char *egress_dev_name; + egress_dev_name = NULL; + egress_dev_name = (char *)malloc(RMNET_MAX_STR_LEN + * sizeof(char)); + if (!egress_dev_name) { + print_rmnet_api_status(RMNETCTL_LIB_ERR, + RMNETCTL_CFG_FAILURE_EGRESS_DEV_NAME_NULL); + rmnetctl_cleanup(handle); + return RMNETCTL_LIB_ERR; + } + return_code = rmnet_get_logical_ep_config(handle, + _STRTOI32(argv[1]), argv[2], &rmnet_mode, + &egress_dev_name, RMNET_MAX_STR_LEN, &error_number); + if (return_code == RMNETCTL_SUCCESS) { + printf("rmnet_mode is %u\n", rmnet_mode); + printf("egress_dev_name is %s\n", egress_dev_name); + } + free(egress_dev_name); + } else if (!strcmp(*argv, "addvnctcflow")) { + _RMNETCLI_CHECKNULL(argv[1]); + _RMNETCLI_CHECKNULL(argv[2]); + _RMNETCLI_CHECKNULL(argv[3]); + return_code = rmnet_add_del_vnd_tc_flow(handle, + _STRTOUI32(argv[1]), _STRTOUI32(argv[2]), _STRTOUI32(argv[3]), + RMNETCTL_ADD_FLOW, &error_number); + } else if (!strcmp(*argv, "setledf")) { + _RMNETCLI_CHECKNULL(argv[1]); + _RMNETCLI_CHECKNULL(argv[2]); + _RMNETCLI_CHECKNULL(argv[3]); + return_code = rmnet_set_link_egress_data_format(handle, + _STRTOUI32(argv[1]), _STRTOUI16(argv[2]), _STRTOUI16(argv[3]), + argv[4], &error_number); + } else if (!strcmp(*argv, "setlepc")) { + _RMNETCLI_CHECKNULL(argv[1]); + _RMNETCLI_CHECKNULL(argv[2]); + return_code = rmnet_set_logical_ep_config(handle, + _STRTOI32(argv[1]), _STRTOUI8(argv[2]), argv[3], argv[4], + &error_number); + } else if (!strcmp(*argv, "unsetlepc")) { + _RMNETCLI_CHECKNULL(argv[1]); + return_code = rmnet_unset_logical_ep_config(handle, + _STRTOI32(argv[1]), argv[2], &error_number); + } + print_rmnet_api_status(return_code, error_number); + rmnetctl_cleanup(handle); + return return_code; +} + +/*! +* @brief Method which serves as en entry point to the rmnetcli function +* @details Entry point for the RmNet Netlink API. This is the command line +* interface for the RmNet API +* @param argc Number of arguments which vary based on the commands +* @param argv Value of the arguments which vary based on the commands +* @return RMNETCTL_SUCCESS if successful. Relevant data might be printed +* based on the message type +* @return RMNETCTL_LIB_ERR if there was a library error. Error code will be +* printed +* @return RMNETCTL_KERNEL_ERR if there was a error in the kernel. Error code will be +* printed +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int main(int argc, char *argv[]) +{ + argc--; + argv++; + return rmnet_api_call(argc, argv); +} diff --git a/dataservices/rmnetctl/cli/rmnetcli.h b/dataservices/rmnetctl/cli/rmnetcli.h new file mode 100644 index 0000000..6375082 --- /dev/null +++ b/dataservices/rmnetctl/cli/rmnetcli.h @@ -0,0 +1,61 @@ +/****************************************************************************** + + R M N E T C L I . H + +Copyright (c) 2013, 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 rmnetcli.h + @brief headers for the command line interface to expose rmnet control API's + + DESCRIPTION + Header file containing definition for the command line interface to expose + rmnet control API's + +******************************************************************************/ + +#ifndef RMNETCLI_H +#define RMNETCLI_H + +/* Print the help for the commands since the help flag was used. */ +#define RMNETCTL_CFG_SUCCESS_HELP_COMMAND 100 +/* No/invalid API call was specified. So return an error. */ +#define RMNETCTL_CFG_FAILURE_NO_COMMAND 101 +/* The buffer for egress device name was NULL */ +#define RMNETCTL_CFG_FAILURE_EGRESS_DEV_NAME_NULL 102 + +/* This should always be the value of the starting element */ +#define RMNETCFG_ERR_NUM_START 100 + +/* This should always be the total number of error message from CLI */ +#define RMNETCFG_TOTAL_ERR_MSGS 3 + +#endif /* not defined RMNETCLI_H */ diff --git a/dataservices/rmnetctl/inc/librmnetctl.h b/dataservices/rmnetctl/inc/librmnetctl.h new file mode 100644 index 0000000..ff78011 --- /dev/null +++ b/dataservices/rmnetctl/inc/librmnetctl.h @@ -0,0 +1,499 @@ +/****************************************************************************** + + L I B R M N E T C T L . H + +Copyright (c) 2013-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 librmnetctl.h +* @brief rmnet control API's header file +*/ + +#ifndef LIBRMNETCTL_H +#define LIBRMNETCTL_H + +/* RMNET API succeeded */ +#define RMNETCTL_SUCCESS 0 +/* RMNET API encountered an error while executing within the library. Check the +* error code in this case */ +#define RMNETCTL_LIB_ERR 1 +/* RMNET API encountered an error while executing in the kernel. Check the +* error code in this case */ +#define RMNETCTL_KERNEL_ERR 2 +/* RMNET API encountered an error because of invalid arguments*/ +#define RMNETCTL_INVALID_ARG 3 + +/* Flag to associate a network device*/ +#define RMNETCTL_DEVICE_ASSOCIATE 1 +/* Flag to unassociate a network device*/ +#define RMNETCTL_DEVICE_UNASSOCIATE 0 +/* Flag to create a new virtual network device*/ +#define RMNETCTL_NEW_VND 1 +/* Flag to free a new virtual network device*/ +#define RMNETCTL_FREE_VND 0 +/* Flag to add a new flow*/ +#define RMNETCTL_ADD_FLOW 1 +/* Flag to delete an existing flow*/ +#define RMNETCTL_DEL_FLOW 0 + +enum rmnetctl_error_codes_e { + /* API succeeded. This should always be the first element. */ + RMNETCTL_API_SUCCESS = 0, + + RMNETCTL_API_FIRST_ERR = 1, + /* API failed because not enough memory to create buffer to send + * message */ + RMNETCTL_API_ERR_REQUEST_INVALID = RMNETCTL_API_FIRST_ERR, + /* API failed because not enough memory to create buffer for the + * response message */ + RMNETCTL_API_ERR_RESPONSE_INVALID = 2, + /* API failed because could not send the message to kernel */ + RMNETCTL_API_ERR_MESSAGE_SEND = 3, + /* API failed because could not receive message from the kernel */ + RMNETCTL_API_ERR_MESSAGE_RECEIVE = 4, + + RMNETCTL_INIT_FIRST_ERR = 5, + /* Invalid process id. So return an error. */ + RMNETCTL_INIT_ERR_PROCESS_ID = RMNETCTL_INIT_FIRST_ERR, + /* Invalid socket descriptor id. So return an error. */ + RMNETCTL_INIT_ERR_NETLINK_FD = 6, + /* Could not bind the socket to the Netlink file descriptor */ + RMNETCTL_INIT_ERR_BIND = 7, + /* Invalid user id. Only root has access to this function. (NA) */ + RMNETCTL_INIT_ERR_INVALID_USER = 8, + + RMNETCTL_API_SECOND_ERR = 9, + /* API failed because the RmNet handle for the transaction was NULL */ + RMNETCTL_API_ERR_HNDL_INVALID = RMNETCTL_API_SECOND_ERR, + /* API failed because the request buffer for the transaction was NULL */ + RMNETCTL_API_ERR_REQUEST_NULL = 10, + /* API failed because the response buffer for the transaction was NULL*/ + RMNETCTL_API_ERR_RESPONSE_NULL = 11, + /* API failed because the request and response type do not match*/ + RMNETCTL_API_ERR_MESSAGE_TYPE = 12, + /* API failed because the return type is invalid */ + RMNETCTL_API_ERR_RETURN_TYPE = 13, + /* API failed because the string was truncated */ + RMNETCTL_API_ERR_STRING_TRUNCATION = 14, + + /* These error are 1-to-1 with rmnet_data config errors in rmnet_data.h + for each conversion. + please keep the enums synced. + */ + RMNETCTL_KERNEL_FIRST_ERR = 15, + /* No error */ + RMNETCTL_KERNEL_ERROR_NO_ERR = RMNETCTL_KERNEL_FIRST_ERR, + /* Invalid / unsupported message */ + RMNETCTL_KERNEL_ERR_UNKNOWN_MESSAGE = 16, + /* Internal problem in the kernel module */ + RMNETCTL_KERNEL_ERR_INTERNAL = 17, + /* Kernel is temporarily out of memory */ + RMNETCTL_KERNEL_ERR_OUT_OF_MEM = 18, + /* Device already exists / Still in use */ + RMETNCTL_KERNEL_ERR_DEVICE_IN_USE = 19, + /* Invalid request / Unsupported scenario */ + RMNETCTL_KERNEL_ERR_INVALID_REQUEST = 20, + /* Device doesn't exist */ + RMNETCTL_KERNEL_ERR_NO_SUCH_DEVICE = 21, + /* One or more of the arguments is invalid */ + RMNETCTL_KERNEL_ERR_BAD_ARGS = 22, + /* Egress device is invalid */ + RMNETCTL_KERNEL_ERR_BAD_EGRESS_DEVICE = 23, + /* TC handle is full */ + RMNETCTL_KERNEL_ERR_TC_HANDLE_FULL = 24, + + /* This should always be the last element */ + RMNETCTL_API_ERR_ENUM_LENGTH +}; + +#define RMNETCTL_ERR_MSG_SIZE 100 + +/*! +* @brief Contains a list of error message from API +*/ +char rmnetctl_error_code_text +[RMNETCTL_API_ERR_ENUM_LENGTH][RMNETCTL_ERR_MSG_SIZE] = { + "ERROR: API succeeded\n", + "ERROR: Unable to allocate the buffer to send message\n", + "ERROR: Unable to allocate the buffer to receive message\n", + "ERROR: Could not send the message to kernel\n", + "ERROR: Unable to receive message from the kernel\n", + "ERROR: Invalid process id\n", + "ERROR: Invalid socket descriptor id\n", + "ERROR: Could not bind to netlink socket\n", + "ERROR: Only root can access this API\n", + "ERROR: RmNet handle for the transaction was NULL\n", + "ERROR: Request buffer for the transaction was NULL\n", + "ERROR: Response buffer for the transaction was NULL\n", + "ERROR: Request and response type do not match\n", + "ERROR: Return type is invalid\n", + "ERROR: String was truncated\n", + /* Kernel errors */ + "ERROR: Kernel call succeeded\n", + "ERROR: Invalid / Unsupported directive\n", + "ERROR: Internal problem in the kernel module\n", + "ERROR: The kernel is temporarily out of memory\n", + "ERROR: Device already exists / Still in use\n", + "ERROR: Invalid request / Unsupported scenario\n", + "ERROR: Device doesn't exist\n", + "ERROR: One or more of the arguments is invalid\n", + "ERROR: Egress device is invalid\n", + "ERROR: TC handle is full\n" +}; + +/*=========================================================================== + DEFINITIONS AND DECLARATIONS +===========================================================================*/ +typedef struct rmnetctl_hndl_s rmnetctl_hndl_t; + +/*! +* @brief Public API to initialize the RMNET control driver +* @details Allocates memory for the RmNet handle. Creates and binds to a and +* netlink socket if successful +* @param **rmnetctl_hndl_t_val RmNet handle to be initialized +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnetctl_init(rmnetctl_hndl_t **hndl, uint16_t *error_code); + +/*! +* @brief Public API to clean up the RmNeT control handle +* @details Close the socket and free the RmNet handle +* @param *rmnetctl_hndl_t_val RmNet handle to be initialized +* @return void +*/ +void rmnetctl_cleanup(rmnetctl_hndl_t *hndl); + +/*! +* @brief Public API to register/unregister a RMNET driver on a particular device +* @details Message type is RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE or +* RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE based on the flag for assoc_dev +* @param *rmnetctl_hndl_t_val RmNet handle for the Netlink message +* @param dev_name Device on which to register the RmNet driver +* @param error_code Status code of this operation +* @param assoc_dev registers the device if RMNETCTL_DEVICE_ASSOCIATE or +* unregisters the device if RMNETCTL_DEVICE_UNASSOCIATE +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnet_associate_network_device(rmnetctl_hndl_t *hndl, + const char *dev_name, + uint16_t *error_code, + uint8_t assoc_dev); + +/*! +* @brief Public API to get if a RMNET driver is registered on a particular +* device +* @details Message type is RMNET_NETLINK_GET_NETWORK_DEVICE_ASSOCIATED. +* @param *rmnetctl_hndl_t_val RmNet handle for the Netlink message +* @param dev_name Device on which to check if the RmNet driver is registered +* @param register_status 1 if RmNet data driver is registered on a particular +* device, 0 if not +* @param error_code Status code of this operation +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnet_get_network_device_associated(rmnetctl_hndl_t *hndl, + const char *dev_name, + int *register_status, + uint16_t *error_code); + +/*! +* @brief Public API to set the egress data format for a particular link. +* @details Message type is RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT. +* @param *rmnetctl_hndl_t_val RmNet handle for the Netlink message +* @param egress_flags Egress flags to be set on the device +* @param agg_size Max size of aggregated packets +* @param agg_count Number of packets to be aggregated +* @param dev_name Device on which to set the egress data format +* @param error_code Status code of this operation returned from the kernel +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnet_set_link_egress_data_format(rmnetctl_hndl_t *hndl, + uint32_t egress_flags, + uint16_t agg_size, + uint16_t agg_count, + const char *dev_name, + uint16_t *error_code); + +/*! +* @brief Public API to get the egress data format for a particular link. +* @details Message type is RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT. +* @param *rmnetctl_hndl_t_val RmNet handle for the Netlink message +* @param dev_name Device on which to get the egress data format +* @param egress_flags Egress flags from the device +* @param agg_count Number of packets to be aggregated +* @param error_code Status code of this operation returned from the kernel +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnet_get_link_egress_data_format(rmnetctl_hndl_t *hndl, + const char *dev_name, + uint32_t *egress_flags, + uint16_t *agg_size, + uint16_t *agg_count, + uint16_t *error_code); + +/*! +* @brief Public API to set the ingress data format for a particular link. +* @details Message type is RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT. +* @param *rmnetctl_hndl_t_val RmNet handle for the Netlink message +* @param ingress_flags Ingress flags from the device +* @param tail_spacing Tail spacing needed for the packet +* @param dev_name Device on which to set the ingress data format +* @param error_code Status code of this operation returned from the kernel +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnet_set_link_ingress_data_format_tailspace(rmnetctl_hndl_t *hndl, + uint32_t ingress_flags, + uint8_t tail_spacing, + const char *dev_name, + uint16_t *error_code); + +/*! +* @brief Public API to get the ingress data format for a particular link. +* @details Message type is RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT. +* @param *rmnetctl_hndl_t_val RmNet handle for the Netlink message +* @param dev_name Device on which to get the ingress data format +* @param ingress_flags Ingress flags from the device +* @param tail_spacing Tail spacing needed for the packet +* @param error_code Status code of this operation returned from the kernel +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnet_get_link_ingress_data_format_tailspace(rmnetctl_hndl_t *hndl, + const char *dev_name, + uint32_t *ingress_flags, + uint8_t *tail_spacing, + uint16_t *error_code); + +inline int rmnet_set_link_ingress_data_format(rmnetctl_hndl_t *hndl, + uint32_t ingress_flags, + const char *dev_name, + uint16_t *error_code) +{ + return rmnet_set_link_ingress_data_format_tailspace(hndl, + ingress_flags, + 0, + dev_name, + error_code); +} + +inline int rmnet_get_link_ingress_data_format(rmnetctl_hndl_t *hndl, + const char *dev_name, + uint32_t *ingress_flags, + uint16_t *error_code) +{ + return rmnet_get_link_ingress_data_format_tailspace(hndl, + dev_name, + ingress_flags, + 0, + error_code); +} + +/*! +* @brief Public API to set the logical endpoint configuration for a +* particular link. +* @details Message type is RMNET_NETLINK_SET_LOGICAL_EP_CONFIG. +* @param *rmnetctl_hndl_t_val RmNet handle for the Netlink message +* @param logical_ep_id Logical end point id on which the configuration is to be +* set +* @param rmnet_mode RmNet mode to be set on the device +* @param dev_name Device on which to set the logical end point configuration +* @param egress_dev_name Egress Device if operating in bridge mode +* @param error_code Status code of this operation returned from the kernel +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnet_set_logical_ep_config(rmnetctl_hndl_t *hndl, + int32_t ep_id, + uint8_t operating_mode, + const char *dev_name, + const char *next_dev, + uint16_t *error_code); + +/*! +* @brief Public API to un-set the logical endpoint configuration for a +* particular link. +* @details Message type is RMNET_NETLINK_UNSET_LOGICAL_EP_CONFIG. +* @param *rmnetctl_hndl_t_val RmNet handle for the Netlink message +* @param logical_ep_id Logical end point id on which the configuration is to be +* un-set +* @param dev_name Device on which to un-set the logical end point configuration +* @param error_code Status code of this operation returned from the kernel +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnet_unset_logical_ep_config(rmnetctl_hndl_t *hndl, + int32_t ep_id, + const char *dev_name, + uint16_t *error_code); +/*! +* @brief Public API to get the logical endpoint configuration for a +* particular link. +* @details Message type is RMNET_NETLINK_GET_LOGICAL_EP_CONFIG. +* @param *rmnetctl_hndl_t_val RmNet handle for the Netlink message +* @param logical_ep_id Logical end point id from which to get the configuration +* @param dev_name Device on which to get the logical end point configuration +* @param rmnet_mode RmNet mode from the device +* @param next_dev Egress Device name +* @param next_dev_len Egress Device I/O string len +* @param error_code Status code of this operation returned from the kernel +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnet_get_logical_ep_config(rmnetctl_hndl_t *hndl, + int32_t ep_id, + const char *dev_name, + uint8_t *operating_mode, + char **next_dev, + uint32_t next_dev_len, + uint16_t *error_code); + +/*! +* @brief Public API to create a new virtual device node +* @details Message type is RMNET_NETLINK_NEW_VND or +* RMNETCTL_FREE_VND based on the flag for new_vnd +* @param hndl RmNet handle for the Netlink message +* @param id Node number to create the virtual network device node +* @param error_code Status code of this operation returned from the kernel +* @param new_vnd creates a new virtual network device if RMNETCTL_NEW_VND or +* frees the device if RMNETCTL_FREE_VND +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnet_new_vnd(rmnetctl_hndl_t *hndl, + uint32_t id, + uint16_t *error_code, + uint8_t new_vnd); + +/*! + * @brief Public API to create a new virtual device node with a custom prefix + * @details Message type is RMNET_NETLINK_NEW_VND or + * RMNETCTL_FREE_VND based on the flag for new_vnd + * @param hndl RmNet handle for the Netlink message + * @param id Node number to create the virtual network device node + * @param error_code Status code of this operation returned from the kernel + * @param new_vnd creates a new virtual network device if RMNETCTL_NEW_VND or + * frees the device if RMNETCTL_FREE_VND + * @param prefix Prefix to be used when naming the network interface + * @return RMNETCTL_SUCCESS if successful + * @return RMNETCTL_LIB_ERR if there was a library error. Check error_code + * @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. + * Check error_code + * @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API + */ +int rmnet_new_vnd_prefix(rmnetctl_hndl_t *hndl, + uint32_t id, + uint16_t *error_code, + uint8_t new_vnd, + const char *prefix); +/*! + * @brief API to get the ASCII name of a virtual network device from its ID + * @param hndl RmNet handle for the Netlink message + * @param id Node number to create the virtual network device node + * @param error_code Status code of this operation returned from the kernel + * @param buf Buffer to store ASCII representation of device name + * @param buflen Length of the buffer + * @param prefix Prefix to be used when naming the network interface + * @return RMNETCTL_SUCCESS if successful + * @return RMNETCTL_LIB_ERR if there was a library error. Check error_code + * @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. + * Check error_code + * @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API + */ + +int rmnet_get_vnd_name(rmnetctl_hndl_t *hndl, + uint32_t id, + uint16_t *error_code, + char *buf, + uint32_t buflen); + +/*! +* @brief Public API to set or clear a flow +* @details Message type is RMNET_NETLINK_ADD_VND_TC_FLOW or +* RMNET_NETLINK_DEL_VND_TC_FLOW based on the flag for set_flow +* @param *rmnetctl_hndl_t_val RmNet handle for the Netlink message +* @param id Node number to set or clear the flow on the virtual network +* device node +* @param map_flow_id Flow handle of the modem +* @param tc_flow_id Software flow handle +* @param set_flow sets the flow if RMNET_NETLINK_SET_FLOW or +* clears the flow if RMNET_NETLINK_CLEAR_FLOW +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +int rmnet_add_del_vnd_tc_flow(rmnetctl_hndl_t *hndl, + uint32_t id, + uint32_t map_flow_id, + uint32_t tc_flow_id, + uint8_t set_flow, + uint16_t *error_code); + +#endif /* not defined LIBRMNETCTL_H */ + diff --git a/dataservices/rmnetctl/inc/librmnetctl_hndl.h b/dataservices/rmnetctl/inc/librmnetctl_hndl.h new file mode 100644 index 0000000..1a435ed --- /dev/null +++ b/dataservices/rmnetctl/inc/librmnetctl_hndl.h @@ -0,0 +1,65 @@ +/****************************************************************************** + + L I B R M N E T C T L _ H N D L. H + +Copyright (c) 2013, 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 librmnetctl_hndl.h +* @brief rmnet control API's handle file +*/ + +#ifndef LIBRMNETCTL_HNDL_H +#define LIBRMNETCTL_HNDL_H + +/*=========================================================================== + DEFINITIONS AND DECLARATIONS +===========================================================================*/ + +/*! +* @brief Structure for RMNET control handles. A rmnet hndl contains the caller +* process id, the transaction id which is initialized to 0 for each new +* initialized handle and the netlink file descriptor for this handle. +* @var pid process id to be used for the netlink message +* @var transaction_id message number for debugging +* @var netlink_fd netlink file descriptor to be used +* @var src_addr source socket address properties for this message +* @var dest_addr destination socket address properties for this message +*/ + +struct rmnetctl_hndl_s { + uint32_t pid; + uint32_t transaction_id; + int netlink_fd; + struct sockaddr_nl src_addr, dest_addr; +}; + +#endif /* not defined LIBRMNETCTL_HNDL_H */ + diff --git a/dataservices/rmnetctl/src/Android.mk b/dataservices/rmnetctl/src/Android.mk new file mode 100644 index 0000000..6be3d74 --- /dev/null +++ b/dataservices/rmnetctl/src/Android.mk @@ -0,0 +1,26 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := librmnetctl_headers +LOCAL_EXPORT_C_INCLUDE_DIRS:=$(LOCAL_PATH)/inc +include $(BUILD_HEADER_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := librmnetctl.c +LOCAL_CFLAGS := -Wall -Werror + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/inc +LOCAL_C_INCLUDES += $(LOCAL_PATH) +ifeq ($(TARGET_COMPILE_WITH_MSM_KERNEL),true) +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +endif + +LOCAL_CLANG := true +LOCAL_MODULE := librmnetctl +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_OWNER := qcom +LOCAL_PROPRIETARY_MODULE := true +LOCAL_PRELINK_MODULE := false + +include $(BUILD_SHARED_LIBRARY) diff --git a/dataservices/rmnetctl/src/Makefile.am b/dataservices/rmnetctl/src/Makefile.am new file mode 100644 index 0000000..5f4ff95 --- /dev/null +++ b/dataservices/rmnetctl/src/Makefile.am @@ -0,0 +1,16 @@ +AM_CFLAGS = -Wall -Werror -Wundef -Wstrict-prototypes -Wno-trigraphs +AM_CFLAGS += -I./../inc + +librmnetctl_la_C = @C@ +librmnetctl_la_SOURCES = librmnetctl.c + +common_CFLAGS = -DUSE_GLIB @GLIB_CFLAGS@ +common_LDFLAGS = -lpthread -lrt @GLIB_LIBS@ + +librmnetctl_la_CFLAGS := $(AM_CFLAGS) $(common_CFLAGS) +librmnetctl_la_LDFLAGS := -shared $(common_LDFLAGS) + +library_includedir = $(pkgincludedir) +library_include_HEADERS = ./../inc/librmnetctl.h + +lib_LTLIBRARIES = librmnetctl.la diff --git a/dataservices/rmnetctl/src/inc b/dataservices/rmnetctl/src/inc new file mode 120000 index 0000000..456aecc --- /dev/null +++ b/dataservices/rmnetctl/src/inc @@ -0,0 +1 @@ +../inc/
\ No newline at end of file diff --git a/dataservices/rmnetctl/src/librmnetctl.c b/dataservices/rmnetctl/src/librmnetctl.c new file mode 100644 index 0000000..8432a93 --- /dev/null +++ b/dataservices/rmnetctl/src/librmnetctl.c @@ -0,0 +1,905 @@ +/****************************************************************************** + + L I B R M N E T C T L . C + +Copyright (c) 2013-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 librmnetctl.c +* @brief rmnet control API's implementation file +*/ + +/*=========================================================================== + INCLUDE FILES +===========================================================================*/ + +#include <sys/socket.h> +#include <stdint.h> +#include <linux/netlink.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <linux/rmnet_data.h> +#include "librmnetctl_hndl.h" +#include "librmnetctl.h" + +#ifdef USE_GLIB +#include <glib.h> +#define strlcpy g_strlcpy +#endif + +#define RMNETCTL_SOCK_FLAG 0 +#define ROOT_USER_ID 0 +#define MIN_VALID_PROCESS_ID 0 +#define MIN_VALID_SOCKET_FD 0 +#define KERNEL_PROCESS_ID 0 +#define UNICAST 0 +#define MAX_BUF_SIZE sizeof(struct nlmsghdr) + sizeof(struct rmnet_nl_msg_s) +#define INGRESS_FLAGS_MASK (RMNET_INGRESS_FIX_ETHERNET | \ + RMNET_INGRESS_FORMAT_MAP | \ + RMNET_INGRESS_FORMAT_DEAGGREGATION | \ + RMNET_INGRESS_FORMAT_DEMUXING | \ + RMNET_INGRESS_FORMAT_MAP_COMMANDS | \ + RMNET_INGRESS_FORMAT_MAP_CKSUMV3 | \ + RMNET_INGRESS_FORMAT_MAP_CKSUMV4) +#define EGRESS_FLAGS_MASK (RMNET_EGRESS_FORMAT__RESERVED__ | \ + RMNET_EGRESS_FORMAT_MAP | \ + RMNET_EGRESS_FORMAT_AGGREGATION | \ + RMNET_EGRESS_FORMAT_MUXING | \ + RMNET_EGRESS_FORMAT_MAP_CKSUMV3 | \ + RMNET_EGRESS_FORMAT_MAP_CKSUMV4) + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +/*=========================================================================== + LOCAL FUNCTION DEFINITIONS +===========================================================================*/ +/*! +* @brief Synchronous method to send and receive messages to and from the kernel +* using netlink sockets +* @details Increments the transaction id for each message sent to the kernel. +* Sends the netlink message to the kernel and receives the response from the +* kernel. +* @param *hndl RmNet handle for this transaction +* @param request Message to be sent to the kernel +* @param response Message received from the kernel +* @return RMNETCTL_API_SUCCESS if successfully able to send and receive message +* from the kernel +* @return RMNETCTL_API_ERR_HNDL_INVALID if RmNet handle for the transaction was +* NULL +* @return RMNETCTL_API_ERR_REQUEST_NULL not enough memory to create buffer for +* sending the message +* @return RMNETCTL_API_ERR_MESSAGE_SEND if could not send the message to kernel +* @return RMNETCTL_API_ERR_MESSAGE_RECEIVE if could not receive message from the +* kernel +* @return RMNETCTL_API_ERR_MESSAGE_TYPE if the request and response type do not +* match +*/ +static uint16_t rmnetctl_transact(rmnetctl_hndl_t *hndl, + struct rmnet_nl_msg_s *request, + struct rmnet_nl_msg_s *response) { + uint8_t *request_buf, *response_buf; + struct nlmsghdr *nlmsghdr_val; + struct rmnet_nl_msg_s *rmnet_nl_msg_s_val; + ssize_t bytes_read = -1; + uint16_t return_code = RMNETCTL_API_ERR_HNDL_INVALID; + struct sockaddr_nl* __attribute__((__may_alias__)) saddr_ptr; + request_buf = NULL; + response_buf = NULL; + nlmsghdr_val = NULL; + rmnet_nl_msg_s_val = NULL; + do { + if (!hndl){ + break; + } + if (!request){ + return_code = RMNETCTL_API_ERR_REQUEST_NULL; + break; + } + if (!response){ + return_code = RMNETCTL_API_ERR_RESPONSE_NULL; + break; + } + request_buf = (uint8_t *)malloc(MAX_BUF_SIZE * sizeof(uint8_t)); + if (!request_buf){ + return_code = RMNETCTL_API_ERR_REQUEST_NULL; + break; + } + + response_buf = (uint8_t *)malloc(MAX_BUF_SIZE * sizeof(uint8_t)); + if (!response_buf) { + free(request_buf); + return_code = RMNETCTL_API_ERR_RESPONSE_NULL; + break; + } + + nlmsghdr_val = (struct nlmsghdr *)request_buf; + rmnet_nl_msg_s_val = (struct rmnet_nl_msg_s *)NLMSG_DATA(request_buf); + + memset(request_buf, 0, MAX_BUF_SIZE*sizeof(uint8_t)); + memset(response_buf, 0, MAX_BUF_SIZE*sizeof(uint8_t)); + + nlmsghdr_val->nlmsg_seq = hndl->transaction_id; + nlmsghdr_val->nlmsg_pid = hndl->pid; + nlmsghdr_val->nlmsg_len = MAX_BUF_SIZE; + + memcpy((void *)NLMSG_DATA(request_buf), request, + sizeof(struct rmnet_nl_msg_s)); + + rmnet_nl_msg_s_val->crd = RMNET_NETLINK_MSG_COMMAND; + hndl->transaction_id++; + + saddr_ptr = &hndl->dest_addr; + socklen_t addrlen = sizeof(struct sockaddr_nl); + if (sendto(hndl->netlink_fd, + request_buf, + MAX_BUF_SIZE, + RMNETCTL_SOCK_FLAG, + (struct sockaddr*)saddr_ptr, + sizeof(struct sockaddr_nl)) < 0) { + return_code = RMNETCTL_API_ERR_MESSAGE_SEND; + free(request_buf); + free(response_buf); + break; + } + + saddr_ptr = &hndl->src_addr; + bytes_read = recvfrom(hndl->netlink_fd, + response_buf, + MAX_BUF_SIZE, + RMNETCTL_SOCK_FLAG, + (struct sockaddr*)saddr_ptr, + &addrlen); + if (bytes_read < 0) { + return_code = RMNETCTL_API_ERR_MESSAGE_RECEIVE; + free(request_buf); + free(response_buf); + break; + } + + memcpy(response, (void *)NLMSG_DATA(response_buf), + sizeof(struct rmnet_nl_msg_s)); + if (sizeof(*response) < sizeof(struct rmnet_nl_msg_s)) { + return_code = RMNETCTL_API_ERR_RESPONSE_NULL; + free(request_buf); + free(response_buf); + break; + } + + if (request->message_type != response->message_type) { + return_code = RMNETCTL_API_ERR_MESSAGE_TYPE; + free(request_buf); + free(response_buf); + break; + } + return_code = RMNETCTL_SUCCESS; + free(request_buf); + free(response_buf); + } while(0); + return return_code; +} + +/*! +* @brief Static function to check the dev name +* @details Checks if the name is not NULL and if the name is less than the +* RMNET_MAX_STR_LEN +* @param dev_name Name of the device +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_INVALID_ARG if invalid arguments were passed to the API +*/ +static inline int _rmnetctl_check_dev_name(const char *dev_name) { + int return_code = RMNETCTL_INVALID_ARG; + do { + if (!dev_name) + break; + if (strlen(dev_name) >= RMNET_MAX_STR_LEN) + break; + return_code = RMNETCTL_SUCCESS; + } while(0); + return return_code; +} + +/*! +* @brief Static function to check the string length after a copy +* @details Checks if the string length is not lesser than zero and lesser than +* RMNET_MAX_STR_LEN +* @param str_len length of the string after a copy +* @param error_code Status code of this operation +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +*/ +static inline int _rmnetctl_check_len(size_t str_len, uint16_t *error_code) { + int return_code = RMNETCTL_LIB_ERR; + do { + if (str_len > RMNET_MAX_STR_LEN) { + *error_code = RMNETCTL_API_ERR_STRING_TRUNCATION; + break; + } + return_code = RMNETCTL_SUCCESS; + } while(0); + return return_code; +} + +/*! +* @brief Static function to check the response type +* @details Checks if the response type of this message was return code +* @param crd The crd field passed +* @param error_code Status code of this operation +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +*/ +static inline int _rmnetctl_check_code(int crd, uint16_t *error_code) { + int return_code = RMNETCTL_LIB_ERR; + do { + if (crd != RMNET_NETLINK_MSG_RETURNCODE) { + *error_code = RMNETCTL_API_ERR_RETURN_TYPE; + break; + } + return_code = RMNETCTL_SUCCESS; + } while(0); + return return_code; +} + +/*! +* @brief Static function to check the response type +* @details Checks if the response type of this message was data +* @param crd The crd field passed +* @param error_code Status code of this operation +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_LIB_ERR if there was a library error. Check error_code +*/ +static inline int _rmnetctl_check_data(int crd, uint16_t *error_code) { + int return_code = RMNETCTL_LIB_ERR; + do { + if (crd != RMNET_NETLINK_MSG_RETURNDATA) { + *error_code = RMNETCTL_API_ERR_RETURN_TYPE; + break; + } + return_code = RMNETCTL_SUCCESS; + } while(0); + return return_code; +} + +/*! +* @brief Static function to set the return value +* @details Checks if the error_code from the transaction is zero for a return +* code type message and sets the message type as RMNETCTL_SUCCESS +* @param crd The crd field passed +* @param error_code Status code of this operation +* @return RMNETCTL_SUCCESS if successful +* @return RMNETCTL_KERNEL_ERR if there was an error in the kernel. +* Check error_code +*/ +static inline int _rmnetctl_set_codes(int error_val, uint16_t *error_code) { + int return_code = RMNETCTL_KERNEL_ERR; + if (error_val == RMNET_CONFIG_OK) + return_code = RMNETCTL_SUCCESS; + else + *error_code = (uint16_t)error_val + RMNETCTL_KERNEL_FIRST_ERR; + return return_code; +} + +/*=========================================================================== + EXPOSED API +===========================================================================*/ + +int rmnetctl_init(rmnetctl_hndl_t **hndl, uint16_t *error_code) +{ + pid_t pid = 0; + int netlink_fd = -1, return_code = RMNETCTL_LIB_ERR; + struct sockaddr_nl* __attribute__((__may_alias__)) saddr_ptr; + do { + if ((!hndl) || (!error_code)){ + return_code = RMNETCTL_INVALID_ARG; + break; + } + + *hndl = (rmnetctl_hndl_t *)malloc(sizeof(rmnetctl_hndl_t)); + if (!*hndl) { + *error_code = RMNETCTL_API_ERR_HNDL_INVALID; + break; + } + + memset(*hndl, 0, sizeof(rmnetctl_hndl_t)); + + pid = getpid(); + if (pid < MIN_VALID_PROCESS_ID) { + free(*hndl); + *error_code = RMNETCTL_INIT_ERR_PROCESS_ID; + break; + } + (*hndl)->pid = (uint32_t)pid; + netlink_fd = socket(PF_NETLINK, SOCK_RAW, RMNET_NETLINK_PROTO); + if (netlink_fd < MIN_VALID_SOCKET_FD) { + free(*hndl); + *error_code = RMNETCTL_INIT_ERR_NETLINK_FD; + break; + } + + (*hndl)->netlink_fd = netlink_fd; + + memset(&(*hndl)->src_addr, 0, sizeof(struct sockaddr_nl)); + + (*hndl)->src_addr.nl_family = AF_NETLINK; + (*hndl)->src_addr.nl_pid = (*hndl)->pid; + + saddr_ptr = &(*hndl)->src_addr; + if (bind((*hndl)->netlink_fd, + (struct sockaddr*)saddr_ptr, + sizeof(struct sockaddr_nl)) < 0) { + close((*hndl)->netlink_fd); + free(*hndl); + *error_code = RMNETCTL_INIT_ERR_BIND; + break; + } + + memset(&(*hndl)->dest_addr, 0, sizeof(struct sockaddr_nl)); + + (*hndl)->dest_addr.nl_family = AF_NETLINK; + (*hndl)->dest_addr.nl_pid = KERNEL_PROCESS_ID; + (*hndl)->dest_addr.nl_groups = UNICAST; + + return_code = RMNETCTL_SUCCESS; + } while(0); + return return_code; +} + +void rmnetctl_cleanup(rmnetctl_hndl_t *hndl) +{ + if (!hndl) + return; + close(hndl->netlink_fd); + free(hndl); +} + +int rmnet_associate_network_device(rmnetctl_hndl_t *hndl, + const char *dev_name, + uint16_t *error_code, + uint8_t assoc_dev) +{ + struct rmnet_nl_msg_s request, response; + size_t str_len = 0; + int return_code = RMNETCTL_LIB_ERR; + do { + if ((!hndl) || (!error_code) || _rmnetctl_check_dev_name(dev_name) || + ((assoc_dev != RMNETCTL_DEVICE_ASSOCIATE) && + (assoc_dev != RMNETCTL_DEVICE_UNASSOCIATE))) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + + if (assoc_dev == RMNETCTL_DEVICE_ASSOCIATE) + request.message_type = RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE; + else + request.message_type = RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE; + + request.arg_length = RMNET_MAX_STR_LEN; + str_len = strlcpy((char *)(request.data), dev_name, (size_t)RMNET_MAX_STR_LEN); + if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) + break; + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) + break; + return_code = _rmnetctl_set_codes(response.return_code, error_code); + } while(0); + return return_code; +} + +int rmnet_get_network_device_associated(rmnetctl_hndl_t *hndl, + const char *dev_name, + int *register_status, + uint16_t *error_code) { + struct rmnet_nl_msg_s request, response; + size_t str_len = 0; + int return_code = RMNETCTL_LIB_ERR; + do { + if ((!hndl) || (!register_status) || (!error_code) || + _rmnetctl_check_dev_name(dev_name)) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + + request.message_type = RMNET_NETLINK_GET_NETWORK_DEVICE_ASSOCIATED; + + request.arg_length = RMNET_MAX_STR_LEN; + str_len = strlcpy((char *)(request.data), dev_name, RMNET_MAX_STR_LEN); + if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) + break; + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + + if (_rmnetctl_check_data(response.crd, error_code) + != RMNETCTL_SUCCESS) { + if (_rmnetctl_check_code(response.crd, error_code) + == RMNETCTL_SUCCESS) + return_code = _rmnetctl_set_codes(response.return_code, + error_code); + break; + } + + *register_status = response.return_code; + return_code = RMNETCTL_SUCCESS; + } while(0); + return return_code; +} + +int rmnet_set_link_egress_data_format(rmnetctl_hndl_t *hndl, + uint32_t egress_flags, + uint16_t agg_size, + uint16_t agg_count, + const char *dev_name, + uint16_t *error_code) { + struct rmnet_nl_msg_s request, response; + size_t str_len = 0; + int return_code = RMNETCTL_LIB_ERR; + do { + if ((!hndl) || (!error_code) || _rmnetctl_check_dev_name(dev_name) || + ((~EGRESS_FLAGS_MASK) & egress_flags)) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + + request.message_type = RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT; + + request.arg_length = RMNET_MAX_STR_LEN + + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t); + str_len = strlcpy((char *)(request.data_format.dev), + dev_name, + RMNET_MAX_STR_LEN); + if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) + break; + + request.data_format.flags = egress_flags; + request.data_format.agg_size = agg_size; + request.data_format.agg_count = agg_count; + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + + if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) + break; + + return_code = _rmnetctl_set_codes(response.return_code, error_code); + } while(0); + return return_code; +} + +int rmnet_get_link_egress_data_format(rmnetctl_hndl_t *hndl, + const char *dev_name, + uint32_t *egress_flags, + uint16_t *agg_size, + uint16_t *agg_count, + uint16_t *error_code) { + struct rmnet_nl_msg_s request, response; + size_t str_len = 0; + int return_code = RMNETCTL_LIB_ERR; + do { + if ((!hndl) || (!egress_flags) || (!agg_size) || (!agg_count) || + (!error_code) || _rmnetctl_check_dev_name(dev_name)) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + request.message_type = RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT; + + request.arg_length = RMNET_MAX_STR_LEN; + str_len = strlcpy((char *)(request.data_format.dev), + dev_name, + RMNET_MAX_STR_LEN); + if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) + break; + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + + if (_rmnetctl_check_data(response.crd, error_code) + != RMNETCTL_SUCCESS) { + if (_rmnetctl_check_code(response.crd, error_code) + == RMNETCTL_SUCCESS) + return_code = _rmnetctl_set_codes(response.return_code, + error_code); + break; + } + + *egress_flags = response.data_format.flags; + *agg_size = response.data_format.agg_size; + *agg_count = response.data_format.agg_count; + return_code = RMNETCTL_SUCCESS; + } while(0); + return return_code; +} + +int rmnet_set_link_ingress_data_format_tailspace(rmnetctl_hndl_t *hndl, + uint32_t ingress_flags, + uint8_t tail_spacing, + const char *dev_name, + uint16_t *error_code) { + struct rmnet_nl_msg_s request, response; + size_t str_len = 0; + int return_code = RMNETCTL_LIB_ERR; + do { + if ((!hndl) || (!error_code) || _rmnetctl_check_dev_name(dev_name) || + ((~INGRESS_FLAGS_MASK) & ingress_flags)) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + + request.message_type = RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT; + + request.arg_length = RMNET_MAX_STR_LEN + + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t); + str_len = strlcpy((char *)(request.data_format.dev), + dev_name, + RMNET_MAX_STR_LEN); + if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) + break; + request.data_format.flags = ingress_flags; + request.data_format.tail_spacing = tail_spacing; + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + + if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) + break; + + return_code = _rmnetctl_set_codes(response.return_code, error_code); + } while(0); + return return_code; +} + +int rmnet_get_link_ingress_data_format_tailspace(rmnetctl_hndl_t *hndl, + const char *dev_name, + uint32_t *ingress_flags, + uint8_t *tail_spacing, + uint16_t *error_code) { + struct rmnet_nl_msg_s request, response; + size_t str_len = 0; + int return_code = RMNETCTL_LIB_ERR; + do { + if ((!hndl) || (!error_code) || + _rmnetctl_check_dev_name(dev_name)) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + + request.message_type = RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT; + + request.arg_length = RMNET_MAX_STR_LEN; + str_len = strlcpy((char *)(request.data_format.dev), + dev_name, + RMNET_MAX_STR_LEN); + if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) + break; + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + + if (_rmnetctl_check_data(response.crd, error_code) + != RMNETCTL_SUCCESS) { + if (_rmnetctl_check_code(response.crd, error_code) + == RMNETCTL_SUCCESS) + return_code = _rmnetctl_set_codes(response.return_code, + error_code); + break; + } + + if (ingress_flags) + *ingress_flags = response.data_format.flags; + + if (tail_spacing) + *tail_spacing = response.data_format.tail_spacing; + + return_code = RMNETCTL_SUCCESS; + } while(0); + return return_code; +} + +int rmnet_set_logical_ep_config(rmnetctl_hndl_t *hndl, + int32_t ep_id, + uint8_t operating_mode, + const char *dev_name, + const char *next_dev, + uint16_t *error_code) { + struct rmnet_nl_msg_s request, response; + size_t str_len = 0; + int return_code = RMNETCTL_LIB_ERR; + do { + if ((!hndl) || ((ep_id < -1) || (ep_id > 31)) || (!error_code) || + _rmnetctl_check_dev_name(dev_name) || + _rmnetctl_check_dev_name(next_dev) || + operating_mode >= RMNET_EPMODE_LENGTH) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + + request.message_type = RMNET_NETLINK_SET_LOGICAL_EP_CONFIG; + + request.arg_length = RMNET_MAX_STR_LEN + + RMNET_MAX_STR_LEN + sizeof(int32_t) + sizeof(uint8_t); + str_len = strlcpy((char *)(request.local_ep_config.dev), + dev_name, + RMNET_MAX_STR_LEN); + if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) + break; + + str_len = strlcpy((char *)(request.local_ep_config.next_dev), + next_dev, + RMNET_MAX_STR_LEN); + if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) + break; + request.local_ep_config.ep_id = ep_id; + request.local_ep_config.operating_mode = operating_mode; + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) + break; + + return_code = _rmnetctl_set_codes(response.return_code, error_code); + } while(0); + return return_code; +} + +int rmnet_unset_logical_ep_config(rmnetctl_hndl_t *hndl, + int32_t ep_id, + const char *dev_name, + uint16_t *error_code) { + struct rmnet_nl_msg_s request, response; + size_t str_len = 0; + int return_code = RMNETCTL_LIB_ERR; + do { + + if ((!hndl) || ((ep_id < -1) || (ep_id > 31)) || (!error_code) || + _rmnetctl_check_dev_name(dev_name)) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + + request.message_type = RMNET_NETLINK_UNSET_LOGICAL_EP_CONFIG; + + request.arg_length = RMNET_MAX_STR_LEN + sizeof(int32_t); + str_len = strlcpy((char *)(request.local_ep_config.dev), + dev_name, + RMNET_MAX_STR_LEN); + + if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) + break; + + request.local_ep_config.ep_id = ep_id; + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) + break; + + return_code = _rmnetctl_set_codes(response.return_code, error_code); + } while(0); + + return return_code; +} + +int rmnet_get_logical_ep_config(rmnetctl_hndl_t *hndl, + int32_t ep_id, + const char *dev_name, + uint8_t *operating_mode, + char **next_dev, + uint32_t next_dev_len, + uint16_t *error_code) { + struct rmnet_nl_msg_s request, response; + size_t str_len = 0; + int return_code = RMNETCTL_LIB_ERR; + do { + if ((!hndl) || (!operating_mode) || (!error_code) || ((ep_id < -1) || + (ep_id > 31)) || _rmnetctl_check_dev_name(dev_name) || (!next_dev) + || (0 == next_dev_len)) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + + request.message_type = RMNET_NETLINK_GET_LOGICAL_EP_CONFIG; + + request.arg_length = RMNET_MAX_STR_LEN + sizeof(int32_t); + str_len = strlcpy((char *)(request.local_ep_config.dev), + dev_name, + RMNET_MAX_STR_LEN); + if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) + break; + + request.local_ep_config.ep_id = ep_id; + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + + if (_rmnetctl_check_data(response.crd, error_code) + != RMNETCTL_SUCCESS) { + if (_rmnetctl_check_code(response.crd, error_code) + == RMNETCTL_SUCCESS) + return_code = _rmnetctl_set_codes(response.return_code, + error_code); + break; + } + + str_len = strlcpy(*next_dev, + (char *)(response.local_ep_config.next_dev), + min(RMNET_MAX_STR_LEN, next_dev_len)); + if (_rmnetctl_check_len(str_len, error_code) != RMNETCTL_SUCCESS) + break; + + *operating_mode = response.local_ep_config.operating_mode; + return_code = RMNETCTL_SUCCESS; + } while(0); + return return_code; +} + +int rmnet_new_vnd_prefix(rmnetctl_hndl_t *hndl, + uint32_t id, + uint16_t *error_code, + uint8_t new_vnd, + const char *prefix) +{ + struct rmnet_nl_msg_s request, response; + int return_code = RMNETCTL_LIB_ERR; + size_t str_len = 0; + do { + if ((!hndl) || (!error_code) || + ((new_vnd != RMNETCTL_NEW_VND) && (new_vnd != RMNETCTL_FREE_VND))) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + + memset(request.vnd.vnd_name, 0, RMNET_MAX_STR_LEN); + if (new_vnd == RMNETCTL_NEW_VND) { + if (prefix) { + request.message_type =RMNET_NETLINK_NEW_VND_WITH_PREFIX; + str_len = strlcpy((char *)request.vnd.vnd_name, + prefix, RMNET_MAX_STR_LEN); + if (_rmnetctl_check_len(str_len, error_code) + != RMNETCTL_SUCCESS) + break; + } else { + request.message_type = RMNET_NETLINK_NEW_VND; + } + } else { + request.message_type = RMNET_NETLINK_FREE_VND; + } + + request.arg_length = sizeof(uint32_t); + request.vnd.id = id; + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) + break; + + return_code = _rmnetctl_set_codes(response.return_code, error_code); + } while(0); + return return_code; +} + +int rmnet_new_vnd(rmnetctl_hndl_t *hndl, + uint32_t id, + uint16_t *error_code, + uint8_t new_vnd) +{ + return rmnet_new_vnd_prefix(hndl, id, error_code, new_vnd, 0); +} + +int rmnet_get_vnd_name(rmnetctl_hndl_t *hndl, + uint32_t id, + uint16_t *error_code, + char *buf, + uint32_t buflen) +{ + struct rmnet_nl_msg_s request, response; + uint32_t str_len; + int return_code = RMNETCTL_LIB_ERR; + do { + if ((!hndl) || (!error_code) || (!buf) || (0 == buflen)) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + + request.message_type = RMNET_NETLINK_GET_VND_NAME; + request.arg_length = sizeof(uint32_t); + request.vnd.id = id; + + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + + if (_rmnetctl_check_data(response.crd, error_code) + != RMNETCTL_SUCCESS) { + if (_rmnetctl_check_code(response.crd, error_code) + == RMNETCTL_SUCCESS) + return_code = _rmnetctl_set_codes(response.return_code, + error_code); + break; + } + + str_len = (uint32_t)strlcpy(buf, + (char *)(response.vnd.vnd_name), + buflen); + if (str_len >= buflen) { + *error_code = RMNETCTL_API_ERR_STRING_TRUNCATION; + break; + } + + return_code = RMNETCTL_SUCCESS; + } while (0); + return return_code; +} + +int rmnet_add_del_vnd_tc_flow(rmnetctl_hndl_t *hndl, + uint32_t id, + uint32_t map_flow_id, + uint32_t tc_flow_id, + uint8_t set_flow, + uint16_t *error_code) { + struct rmnet_nl_msg_s request, response; + int return_code = RMNETCTL_LIB_ERR; + do { + if ((!hndl) || (!error_code) || ((set_flow != RMNETCTL_ADD_FLOW) && + (set_flow != RMNETCTL_DEL_FLOW))) { + return_code = RMNETCTL_INVALID_ARG; + break; + } + if (set_flow == RMNETCTL_ADD_FLOW) + request.message_type = RMNET_NETLINK_ADD_VND_TC_FLOW; + else + request.message_type = RMNET_NETLINK_DEL_VND_TC_FLOW; + + request.arg_length = (sizeof(uint32_t))*3; + request.flow_control.id = id; + request.flow_control.map_flow_id = map_flow_id; + request.flow_control.tc_flow_id = tc_flow_id; + + if ((*error_code = rmnetctl_transact(hndl, &request, &response)) + != RMNETCTL_SUCCESS) + break; + if (_rmnetctl_check_code(response.crd, error_code) != RMNETCTL_SUCCESS) + break; + return_code = _rmnetctl_set_codes(response.return_code, error_code); + } while(0); + return return_code; +} + diff --git a/dataservices/sockev/Android.mk b/dataservices/sockev/Android.mk new file mode 100644 index 0000000..8338432 --- /dev/null +++ b/dataservices/sockev/Android.mk @@ -0,0 +1,2 @@ +include $(call all-subdir-makefiles) + diff --git a/dataservices/sockev/src/Android.mk b/dataservices/sockev/src/Android.mk new file mode 100644 index 0000000..27af310 --- /dev/null +++ b/dataservices/sockev/src/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := sockev_cli.c +LOCAL_CFLAGS := -Wall -Werror + +ifeq ($(TARGET_COMPILE_WITH_MSM_KERNEL),true) +LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +endif + +LOCAL_CLANG := true +LOCAL_MODULE := sockev +LOCAL_MODULE_TAGS := optional + +include $(BUILD_EXECUTABLE) diff --git a/dataservices/sockev/src/sockev_cli.c b/dataservices/sockev/src/sockev_cli.c new file mode 100644 index 0000000..2bd2710 --- /dev/null +++ b/dataservices/sockev/src/sockev_cli.c @@ -0,0 +1,96 @@ +/****************************************************************************** + S O C K E V _ C L I . C +Copyright (c) 2013, 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 sockev_cli.c + @brief command line test utility to receive sockev netlink messages. +******************************************************************************/ + +#include <sys/socket.h> +#include <linux/netlink.h> +#include <linux/sockev.h> +#include <stdlib.h> +#include <stdio.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <string.h> + +#define SOCKEVCLI_ERROR -1 + +int main(void) +{ + int skfd, rc; + socklen_t addrlen; + struct sockaddr_nl my_addr, src_addr; + struct nlmsghdr *nlh = NULL; + struct sknlsockevmsg *msg; + + nlh = (struct nlmsghdr *) + malloc(NLMSG_SPACE(sizeof(struct sknlsockevmsg) + 16)); + if (!nlh) { + fprintf(stderr, "malloc() failed\n"); + return SOCKEVCLI_ERROR; + } + + skfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCKEV); + if (skfd < 0) { + fprintf(stderr, "nl_open_sock: socket failed\n"); + return SOCKEVCLI_ERROR; + } + + memset(&my_addr, 0, sizeof(struct sockaddr_nl)); + + my_addr.nl_family = AF_NETLINK; + my_addr.nl_pid = getpid(); + my_addr.nl_groups = SKNLGRP_SOCKEV; + + rc = bind(skfd, (struct sockaddr *)&my_addr, + sizeof(struct sockaddr_nl)); + if (rc < 0) { + fprintf(stderr, "nl_open_sock: bind failed\n"); + close(skfd); + return SOCKEVCLI_ERROR; + } + + while (1) { + recvfrom(skfd, nlh, sizeof(struct sknlsockevmsg) + 16, 0, + (struct sockaddr *)&src_addr, &addrlen); + msg = NLMSG_DATA(nlh); + printf("----------------------------\n"); + printf("pid:\t%d\n", msg->pid); + printf("event:\t%s\n", msg->event); + printf("skfamily:\t0x%04X\n", msg->skfamily); + printf("skstate:\t%03d\n", msg->skstate); + printf("skprotocol:\t%03d\n", msg->skprotocol); + printf("sktype:\t0x%04X\n", msg->sktype); + printf("skflags:\t0x%016llX\n", msg->skflags); + } + + return 0; +} + |