aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dataservices/Android.mk1
-rwxr-xr-xdataservices/Makefile.am11
-rw-r--r--dataservices/configure.ac51
-rw-r--r--dataservices/data-oss.pc.in10
-rw-r--r--dataservices/datatop/Android.mk2
-rw-r--r--dataservices/datatop/Makefile.am3
-rw-r--r--dataservices/datatop/autogen.sh51
-rw-r--r--dataservices/datatop/configure.ac56
-rw-r--r--dataservices/datatop/src/Android.mk32
-rw-r--r--dataservices/datatop/src/Makefile.am22
-rw-r--r--dataservices/datatop/src/datatop.c283
-rw-r--r--dataservices/datatop/src/datatop_cpu_stats_poll.c182
-rw-r--r--dataservices/datatop/src/datatop_dev_poll.c320
-rw-r--r--dataservices/datatop/src/datatop_dual_line_poll.c319
-rw-r--r--dataservices/datatop/src/datatop_fileops.c167
-rw-r--r--dataservices/datatop/src/datatop_fileops.h48
-rw-r--r--dataservices/datatop/src/datatop_gen_poll.c280
-rw-r--r--dataservices/datatop/src/datatop_gen_poll.h43
-rw-r--r--dataservices/datatop/src/datatop_helpers.c478
-rw-r--r--dataservices/datatop/src/datatop_interface.h166
-rw-r--r--dataservices/datatop/src/datatop_linked_list.c84
-rw-r--r--dataservices/datatop/src/datatop_linked_list.h59
-rw-r--r--dataservices/datatop/src/datatop_meminfo_file_poll.c282
-rw-r--r--dataservices/datatop/src/datatop_opt.c184
-rw-r--r--dataservices/datatop/src/datatop_opt.h88
-rw-r--r--dataservices/datatop/src/datatop_polling.h49
-rw-r--r--dataservices/datatop/src/datatop_single_line_poll.c243
-rw-r--r--dataservices/datatop/src/datatop_stat_poll.c319
-rw-r--r--dataservices/datatop/src/datatop_str.c260
-rw-r--r--dataservices/datatop/src/datatop_str.h70
-rw-r--r--dataservices/datatop/src/datatop_sys_snap.c199
-rw-r--r--dataservices/datatop/src/datatop_value_only_poll.c201
-rw-r--r--dataservices/rmnetctl/Android.mk2
-rw-r--r--dataservices/rmnetctl/cli/Android.mk18
-rw-r--r--dataservices/rmnetctl/cli/Makefile.am9
-rw-r--r--dataservices/rmnetctl/cli/rmnetcli.c415
-rw-r--r--dataservices/rmnetctl/cli/rmnetcli.h61
-rw-r--r--dataservices/rmnetctl/inc/librmnetctl.h499
-rw-r--r--dataservices/rmnetctl/inc/librmnetctl_hndl.h65
-rw-r--r--dataservices/rmnetctl/src/Android.mk26
-rw-r--r--dataservices/rmnetctl/src/Makefile.am16
l---------dataservices/rmnetctl/src/inc1
-rw-r--r--dataservices/rmnetctl/src/librmnetctl.c905
-rw-r--r--dataservices/sockev/Android.mk2
-rw-r--r--dataservices/sockev/src/Android.mk17
-rw-r--r--dataservices/sockev/src/sockev_cli.c96
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], &register_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;
+}
+