The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/libresource/pull/1

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
1: System resource Information related to  memory, CPU, stat, networking,
security etc.
2: Currently most of such information is read from /proc and /sys.
3: Add basic infrastructure and code for some of memory and network related
information.
4: Update README file with the use cases and design details.
5: Added example codes in README.

Signed-off-by: Rahul Yadav <rahul.x.ya...@oracle.com>
From 1439e3e188fe38b3f2201f2f2cfa44f69e6baa53 Mon Sep 17 00:00:00 2001
From: Rahul Yadav <rahul.x.ya...@oracle.com>
Date: Wed, 7 Mar 2018 18:05:50 -0800
Subject: [PATCH] library of interfaces to fetch system resource information

1: System resource Information related to  memory, CPU, stat, networking,
security etc.
2: Currently most of such information is read from /proc and /sys.
3: Add basic infrastructure and code for some of memory and network related
information.
4: Update README file with the use cases and design details.
5: Added example codes in README.

Signed-off-by: Rahul Yadav <rahul.x.ya...@oracle.com>
---
 Makefile        |  18 ++++
 resmem.c        | 218 ++++++++++++++++++++++++++++++++++++++
 resmem.h        |  16 +++
 resnet.c        | 316 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 resnet.h        |  14 +++
 resource.c      | 211 +++++++++++++++++++++++++++++++++++++
 resource.h      | 142 +++++++++++++++++++++++++
 resource_impl.h |  47 +++++++++
 8 files changed, 982 insertions(+)
 create mode 100644 Makefile
 create mode 100644 resmem.c
 create mode 100644 resmem.h
 create mode 100644 resnet.c
 create mode 100644 resnet.h
 create mode 100644 resource.c
 create mode 100644 resource.h
 create mode 100644 resource_impl.h

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2c71328
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,18 @@
+CC = gcc
+CFLAGS = -g -Wall -Werror -fPIC
+DEPS = resource.h res_impl.h resmem.h resnet.h
+OBJ = resource.o resmem.o resnet.o
+LIB = libresource.so
+TEST = test
+RM = rm -rf
+CP = cp
+
+%.o: %.c $(DEPS)
+       $(CC) -c -o $@ $< $(CFLAGS)
+
+all: $(OBJ)
+       $(CC) -shared -o $(LIB) $^ $(CFLAGS)
+
+.PHONY : clean
+clean:
+       $(RM) $(LIB) $(OBJ) $(TEST)
diff --git a/resmem.c b/resmem.c
new file mode 100644
index 0000000..df7d261
--- /dev/null
+++ b/resmem.c
@@ -0,0 +1,218 @@
+#ifndef _RESOURCE_H
+#include "resource.h"
+#endif
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "resmem.h"
+#include "resource_impl.h"
+#include <errno.h>
+
+int meminfo_fd = -1;
+
+/* read a specific information from file on the basis of a string.
+ * String should tell what information is being read.
+ */
+static inline int get_info_infile(char *fname, char *res, void *out)
+{
+       const char *loc;
+       char buf[MEMBUF_2048];
+
+       if (file_to_buf(fname, buf) == -1)
+               return -1;
+
+       loc = strstr(buf, res);
+       if (loc == NULL) {
+               eprintf("%s is not found in buffer of file %s", res, fname);
+               errno = ENODATA;
+               return -1;
+       }
+
+       sscanf(loc, "%*s%zu", (size_t *)out);
+       return 0;
+}
+
+/* Read resource information corresponding to res_id */
+int getmeminfo(int res_id, void *out, void *hint, int pid, int flags)
+{
+       char buf[MEMBUF_128];
+       FILE *fp;
+       int err = 0;
+
+       switch (res_id) {
+
+       case RES_MEM_FREE:
+               return get_info_infile(MEMINFO_FILE, "MemFree:", out);
+
+       case RES_MEM_AVAILABLE:
+               return get_info_infile(MEMINFO_FILE, "MemAvailable:", out);
+
+       case RES_MEM_TOTAL:
+               return get_info_infile(MEMINFO_FILE, "MemTotal:", out);
+
+       case RES_MEM_ACTIVE:
+               return get_info_infile(MEMINFO_FILE, "Active:", out);
+
+       case RES_MEM_INACTIVE:
+               return get_info_infile(MEMINFO_FILE, "Inactive:", out);
+
+       case RES_MEM_SWAPTOTAL:
+               return get_info_infile(MEMINFO_FILE, "SwapTotal:", out);
+
+       case RES_MEM_SWAPFREE:
+               return get_info_infile(MEMINFO_FILE, "SwapFree:", out);
+
+       case RES_MEM_INFOALL:
+               fp = fopen(MEMINFO_FILE, "r");
+               if (fp == NULL) {
+                       err = errno;
+                       eprintf("while opening File %s with errno: %d",
+                               MEMINFO_FILE, errno);
+                       errno = err;
+                       return -1;
+               }
+               /* Read through file and populate all information which
+                * is required.
+                */
+               while (fgets(buf, sizeof(buf), fp) != NULL) {
+                       if (strncmp("MemTotal:", buf, MEMBUF_8) == 0)
+                               sscanf(buf, "%*s%zu",
+                               &((res_mem_infoall_t *)out)->memtotal);
+
+                       else if (strncmp("MemFree:", buf, MEMBUF_8) == 0)
+                               sscanf(buf, "%*s%zu",
+                               &((res_mem_infoall_t *)out)->memfree);
+
+                       else if (strncmp("MemAvailable:", buf, MEMBUF_8) == 0)
+                               sscanf(buf, "%*s%zu",
+                               &((res_mem_infoall_t *)out)->memavailable);
+
+                       else if (strncmp("Active:", buf, MEMBUF_8) == 0)
+                               sscanf(buf, "%*s%zu",
+                               &((res_mem_infoall_t *)out)->active);
+
+                       else if (strncmp("Inactive:", buf, MEMBUF_8) == 0)
+                               sscanf(buf, "%*s%zu",
+                               &((res_mem_infoall_t *)out)->inactive);
+
+                       else if (strncmp("SwapTotal:", buf, MEMBUF_8) == 0)
+                               sscanf(buf, "%*s%zu",
+                               &((res_mem_infoall_t *)out)->swaptotal);
+
+                       else if (strncmp("SwapFree:", buf, MEMBUF_8) == 0)
+                               sscanf(buf, "%*s%zu",
+                               &((res_mem_infoall_t *)out)->swapfree);
+               }
+               fclose(fp);
+               break;
+
+       case RES_MEM_PAGESIZE:
+               *(size_t *)out = sysconf(_SC_PAGESIZE);
+               break;
+
+       default:
+               eprintf("Resource Id is invalid");
+               errno = EINVAL;
+               return -1;
+       }
+
+       return 0;
+}
+
+int populate_meminfo(res_blk_t *res, int pid, int flags)
+{
+       size_t temp;
+       const char *loc;
+       char buf[MEMBUF_2048];
+
+       if (file_to_buf(MEMINFO_FILE, buf) == -1) {
+               for (int i = 0 ; i < res->res_count; i++)
+                       res->res_unit[i]->status = errno;
+               return -1;
+       }
+
+/* Macro to read memory related information corresponding to a string
+ * from buffer.
+ */
+#define SCANMEMSTR(str) do {\
+       loc = strstr(buf, str);\
+       if (loc == NULL) {\
+               eprintf("%s is not found in file %s", str, MEMINFO_FILE);\
+                       res->res_unit[i]->status = ENODATA;\
+       } else {\
+               sscanf(loc, "%*s%zu", &temp);\
+               (res->res_unit[i]->data).sz = temp;\
+               res->res_unit[i]->status = RES_STATUS_FILLED;\
+       } \
+} while (0)\
+
+
+       for (int i = 0; i < res->res_count; i++) {
+               loc = NULL;
+               switch (res->res_unit[i]->res_id) {
+               case RES_MEM_FREE:
+                       SCANMEMSTR("MemFree:");
+                       break;
+
+               case RES_MEM_AVAILABLE:
+                       SCANMEMSTR("MemAvailable:");
+                       break;
+
+               case RES_MEM_TOTAL:
+                       SCANMEMSTR("MemTotal:");
+                       break;
+
+               case RES_MEM_ACTIVE:
+                       SCANMEMSTR("Active:");
+                       break;
+
+               case RES_MEM_INACTIVE:
+                       SCANMEMSTR("Inactive:");
+                       break;
+
+               case RES_MEM_SWAPTOTAL:
+                       SCANMEMSTR("SwapTotal:");
+                       break;
+
+               case RES_MEM_SWAPFREE:
+                       SCANMEMSTR("SwapFree:");
+                       break;
+
+               case RES_MEM_PAGESIZE:
+                       (res->res_unit[i]->data).sz = sysconf(_SC_PAGESIZE);
+                       break;
+
+               case RES_MEM_INFOALL:
+                       loc = strstr(buf, "MemTotal:");
+                       sscanf(loc, "%*s%zu", &((res_mem_infoall_t *)
+                               (res->res_unit[i]->data).ptr)->memtotal);
+                       loc = strstr(buf, "MemFree:");
+                       sscanf(loc, "%*s%zu", &((res_mem_infoall_t *)
+                               (res->res_unit[i]->data).ptr)->memfree);
+                       loc = strstr(buf, "MemAvailable:");
+                       sscanf(loc, "%*s%zu", &((res_mem_infoall_t *)
+                               (res->res_unit[i]->data).ptr)->memavailable);
+                       loc = strstr(buf, "Active:");
+                       sscanf(loc, "%*s%zu", &((res_mem_infoall_t *)
+                               (res->res_unit[i]->data).ptr)->active);
+                       loc = strstr(buf, "Inactive:");
+                       sscanf(loc, "%*s%zu", &((res_mem_infoall_t *)
+                               (res->res_unit[i]->data).ptr)->inactive);
+                       loc = strstr(buf, "SwapTotal:");
+                       sscanf(loc, "%*s%zu", &((res_mem_infoall_t *)
+                               (res->res_unit[i]->data).ptr)->swaptotal);
+                       loc = strstr(buf, "SwapFree:");
+                       sscanf(loc, "%*s%zu", &((res_mem_infoall_t *)
+                               (res->res_unit[i]->data).ptr)->swapfree);
+
+                       res->res_unit[i]->status = RES_STATUS_FILLED;
+                       break;
+               default:
+                       res->res_unit[i]->status = RES_STATUS_NOTSUPPORTED;
+               }
+       }
+       return 0;
+}
+
diff --git a/resmem.h b/resmem.h
new file mode 100644
index 0000000..817b9ec
--- /dev/null
+++ b/resmem.h
@@ -0,0 +1,16 @@
+#ifndef _RESMEM_H
+#define _RESMEM_H
+
+#define MEMINFO_FILE "/proc/meminfo"
+extern int meminfo_fd;
+
+#define VMINFO_FILE "/proc/vmstat"
+
+#define MEMBUF_8       8
+#define MEMBUF_128     128
+#define MEMBUF_2048    2048
+
+extern int populate_meminfo(struct res_blk *res, int pid, int flags);
+extern int getmeminfo(int res_id, void *out, void *hint, int pid, int flags);
+
+#endif /* _RESMEM_H */
diff --git a/resnet.c b/resnet.c
new file mode 100644
index 0000000..56269bf
--- /dev/null
+++ b/resnet.c
@@ -0,0 +1,316 @@
+#ifndef _RESOURCE_H
+#include "resource.h"
+#endif
+#include <string.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <errno.h>
+#include <ctype.h>
+#include <net/if.h>
+#include "resnet.h"
+#include "resource_impl.h"
+
+int netdev_fd = -1;
+
+static inline int procnetdev_ver(char *buf)
+{
+       if (strstr(buf, "compressed"))
+               return 3;
+       if (strstr(buf, "bytes"))
+               return 2;
+       return 1;
+}
+
+static inline char *get_ifname(char *name, char *p)
+{
+       char *d;
+       char *dname;
+
+       while (isspace(*p))
+               p++;
+
+       while (*p) {
+               if (isspace(*p))
+                       break;
+               if (*p == ':') {
+                       d = p, dname = name;
+                       *name++ = *p++;
+                       while (isdigit(*p))
+                               *name++ = *p++;
+                       if (*p != ':') {
+                               p = d;
+                               name = dname;
+                       }
+                       if (*p == '\0')
+                               return NULL;
+                       p++;
+                       break;
+               }
+               *name++ = *p++;
+       }
+       *name++ = '\0';
+       return p;
+}
+
+static inline int scan_net_stat(char *buf, res_net_ifstat_t *i, int ver)
+{
+       switch (ver) {
+       case 3:
+               sscanf(buf,
+                       "%llu %llu %lu %lu %lu %lu %lu %lu %llu %llu %lu %lu 
%lu %lu %lu %lu",
+                       &i->rx_bytes,
+                       &i->rx_packets,
+                       &i->rx_errors,
+                       &i->rx_dropped,
+                       &i->rx_fifo_err,
+                       &i->rx_frame_err,
+                       &i->rx_compressed,
+                       &i->rx_multicast,
+
+                       &i->tx_bytes,
+                       &i->tx_packets,
+                       &i->tx_errors,
+                       &i->tx_dropped,
+                       &i->tx_fifo_err,
+                       &i->tx_collisions,
+                       &i->tx_carrier_err,
+                       &i->tx_compressed);
+               break;
+       case 2:
+               sscanf(buf,
+                       "%llu %llu %lu %lu %lu %lu %llu %llu %lu %lu %lu %lu 
%lu",
+                       &i->rx_bytes,
+                       &i->rx_packets,
+                       &i->rx_errors,
+                       &i->rx_dropped,
+                       &i->rx_fifo_err,
+                       &i->rx_frame_err,
+
+                       &i->tx_bytes,
+                       &i->tx_packets,
+                       &i->tx_errors,
+                       &i->tx_dropped,
+                       &i->tx_fifo_err,
+                       &i->tx_collisions,
+                       &i->tx_carrier_err);
+               i->rx_multicast = 0;
+               break;
+       case 1:
+               sscanf(buf,
+                       "%llu %lu %lu %lu %lu %llu %lu %lu %lu %lu %lu",
+                       &i->rx_packets,
+                       &i->rx_errors,
+                       &i->rx_dropped,
+                       &i->rx_fifo_err,
+                       &i->rx_frame_err,
+
+                       &i->tx_packets,
+                       &i->tx_errors,
+                       &i->tx_dropped,
+                       &i->tx_fifo_err,
+                       &i->tx_collisions,
+                       &i->tx_carrier_err);
+               i->rx_bytes = 0;
+               i->tx_bytes = 0;
+               i->rx_multicast = 0;
+               break;
+       }
+       return 0;
+}
+
+static inline int getallnetinfo(void *out, void *hint)
+{      char buf[NETBUF_1024];
+       FILE *fp;
+       char ifname[IFNAMSIZ];
+       int ver = 0;
+       char *p;
+       int inum = 0;
+       int i;
+       res_net_ifstat_t *lst;
+       size_t msz = 0;
+       int err;
+
+       /* Hint should not be null */
+       if (hint == NULL) {
+               eprintf(
+                       "Hint should be provided for RES_NET_ALLIFSTAT");
+               errno = EINVAL;
+               return -1;
+       }
+
+       fp = fopen(NETDEV_FILE, "r");
+       if (fp == NULL) {
+               err = errno;
+               eprintf("while opening File %s with errno: %d",
+                       NETDEV_FILE, errno);
+               errno = err;
+               return -1;
+       }
+
+       fgets(buf, sizeof(buf), fp);
+       fgets(buf, sizeof(buf), fp);
+       ver = procnetdev_ver(buf);
+       inum = *(int *)hint;
+
+       /* Hint should hold number of interfaces for which memory is
+        * allocated in out. If number of interfaces is 0 then allocated
+        * memory for all interfaces and fill it with interface stat.
+        */
+       if (inum == 0) {
+               i = 0;
+
+               /* Memory is allocated for NET_ALLIFSTAT_SZ interfaces
+                * initially and then reallocated in chunks of
+                * NET_ALLIFSTAT_SZ till all information is read.
+                */
+               msz = sizeof(res_net_ifstat_t) * NET_ALLIFSTAT_SZ;
+               lst = (res_net_ifstat_t *)malloc(msz);
+
+               while (fgets(buf, sizeof(buf), fp) != NULL) {
+                       if (i == NET_ALLIFSTAT_SZ) {
+                               msz = (sizeof(res_net_ifstat_t) * inum) +
+                                       NET_ALLIFSTAT_SZ;
+                               lst = (res_net_ifstat_t *)realloc(lst, msz);
+                               i = 0;
+                       }
+                       p = get_ifname(ifname, buf);
+                       strcpy(lst[inum].ifname, ifname);
+                       scan_net_stat(p, &lst[inum], ver);
+                       inum++;
+                       i++;
+               }
+               *((res_net_ifstat_t **)out) = lst;
+               *(int *)hint = inum;
+       } else {
+               /* If number of interfaces is not 0 then read interfaces
+                * stat sequentially and put it in memory allocated
+                * by user in out. Memory might be allocated for more interfaces
+                * than there are on system. So read sequentially till either
+                * all interfaces are read or memory allocated is totally
+                * filled.
+                */
+               if (out == NULL) {
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               for (i = 0;
+                       fgets(buf, sizeof(buf), fp) != NULL && i < inum;
+                       i++) {
+                       p = get_ifname(ifname, buf);
+                       strcpy(((res_net_ifstat_t *)out)[i].ifname, ifname);
+                       scan_net_stat(p, &(((res_net_ifstat_t *)out)[i]), ver);
+               }
+
+               /* Write how many interfaces are read */
+               *(int *)hint = i;
+       }
+       fclose(fp);
+       return 0;
+}
+
+/* Get resource information related to network */
+int getnetinfo(int res_id, void *out, void *hint, int pid, int flags)
+{
+       char buf[NETBUF_1024];
+       FILE *fp;
+       int err = 0;
+       char ifname[IFNAMSIZ];
+       int ver = 0;
+       char *p;
+
+       switch (res_id) {
+       case RES_NET_IFSTAT:
+               /* Interface name should be provided */
+               if (hint == NULL) {
+                       eprintf(
+                               "Interface name is not provided for 
RES_NET_IFSTAT");
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               /* Interface name is provided. Open /proc/net/dev and read
+                * through it.
+                */
+               fp = fopen(NETDEV_FILE, "r");
+               if (fp == NULL) {
+                       err = errno;
+                       eprintf("while opening File %s with errno: %d",
+                               NETDEV_FILE, errno);
+                       errno = err;
+                       return -1;
+               }
+
+               /* Skip first line */
+               fgets(buf, sizeof(buf), fp);
+
+               fgets(buf, sizeof(buf), fp);
+               /* Get what information /proc/net/dev holds so that we can
+                * read it in correct format.
+                */
+               ver = procnetdev_ver(buf);
+
+               /* Read each interface till we find the interface which we
+                * are looking for.
+                */
+               while (fgets(buf, sizeof(buf), fp) != NULL) {
+                       /* get interface name in the line */
+                       p = get_ifname(ifname, buf);
+
+                       if ((strncasecmp((char *)hint, ifname,
+                               sizeof(*(char *)hint))) == 0) {
+                               /* Interface found, scan information */
+                               strcpy(((res_net_ifstat_t *)out)->ifname,
+                                       ifname);
+                               scan_net_stat(p, (res_net_ifstat_t *)out, ver);
+                               break;
+                       }
+               }
+
+               fclose(fp);
+               break;
+
+       /* Information for all interfaces is asked for */
+       case RES_NET_ALLIFSTAT:
+               return getallnetinfo(out, hint);
+
+       default:
+               eprintf("Resource Id is invalid");
+               errno = EINVAL;
+               return -1;
+       }
+
+       return 0;
+}
+
+int populate_netinfo(res_blk_t *res, int pid, int flags)
+{
+       void *p = NULL;
+
+       for (int i = 0; i < res->res_count; i++) {
+               switch (res->res_unit[i]->res_id) {
+               case RES_NET_IFSTAT:
+                       if (getnetinfo(RES_NET_IFSTAT,
+                               res->res_unit[i]->data.ptr,
+                               res->res_unit[i]->hint, 0, 0) == -1) {
+                               res->res_unit[i]->status = errno;
+                       } else
+                               res->res_unit[i]->status = RES_STATUS_FILLED;
+                       break;
+               case RES_NET_ALLIFSTAT:
+                       res->res_unit[i]->hint = (int)0;
+
+                       if (getnetinfo(RES_NET_ALLIFSTAT, &p,
+                               &(res->res_unit[i]->hint), 0, 0) == -1) {
+                               res->res_unit[i]->status = errno;
+                       } else {
+                               res->res_unit[i]->status = RES_STATUS_FILLED;
+                               res->res_unit[i]->data.ptr = p;
+                       }
+                       break;
+               default:
+                       res->res_unit[i]->status = RES_STATUS_NOTSUPPORTED;
+               }
+       }
+       return 0;
+}
diff --git a/resnet.h b/resnet.h
new file mode 100644
index 0000000..164ce16
--- /dev/null
+++ b/resnet.h
@@ -0,0 +1,14 @@
+#ifndef _RESNET_H
+#define _RESNET_H
+
+#define NETDEV_FILE "/proc/net/dev"
+
+#define NET_ALLIFSTAT_SZ    4
+#define NETBUF_1024            1024
+
+extern int netdev_fd;
+
+extern int populate_netinfo(struct res_blk *res, int pid, int flags);
+extern int getnetinfo(int res_id, void *out, void *hint, int pid, int flags);
+
+#endif /* _RESNET_H */
diff --git a/resource.c b/resource.c
new file mode 100644
index 0000000..e0c4e42
--- /dev/null
+++ b/resource.c
@@ -0,0 +1,211 @@
+#include "resource.h"
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+
+#include "resource_impl.h"
+#include "resmem.h"
+#include "resnet.h"
+
+/* Allocate memory for bulk resource information and initiate it
+ * properly.
+ */
+res_blk_t *res_build_blk(int *res_ids, int res_count)
+{
+       res_unit_t *temp;
+       res_blk_t *res = NULL;
+
+       if (!res_ids || res_count <= 0) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       /* Allocate memory to hold addresses of individual resource
+        * information.
+        */
+       res = (res_blk_t *)
+               malloc(sizeof(res_blk_t) + (sizeof(res_unit_t *)) * res_count);
+       res->res_count = res_count;
+
+       /* Allocate and set each resource information properly */
+       for (int i = 0; i < res_count; i++) {
+               /* Allocate memory for resource info */
+               temp = (res_unit_t *)malloc(sizeof(res_unit_t));
+               memset(temp, 0, sizeof(res_unit_t));
+               temp->status = RES_STATUS_EMPTY;
+
+               /* Some resource information are big and need extra allocation.
+                * In these cases an address is returned which hold actual
+                * resource information.
+                */
+               switch (res_ids[i]) {
+               case RES_MEM_ACTIVE:
+               case RES_MEM_INACTIVE:
+               case RES_MEM_AVAILABLE:
+               case RES_MEM_FREE:
+               case RES_MEM_TOTAL:
+               case RES_MEM_PAGESIZE:
+               case RES_MEM_SWAPFREE:
+               case RES_MEM_SWAPTOTAL:
+               case RES_KERN_COMPILE_TIME:
+               case RES_KERN_RELEASE:
+               case RES_NET_ALLIFSTAT:
+                       break;
+
+               case RES_NET_IFSTAT:
+                       temp->data.ptr = (res_net_ifstat_t *)
+                               malloc(sizeof(res_net_ifstat_t));
+                       break;
+
+               case RES_MEM_INFOALL:
+                       temp->data.ptr = (res_mem_infoall_t *)
+                               malloc(sizeof(res_mem_infoall_t));
+                       break;
+
+               default:
+                       eprintf("Invalid resource ID: %d", res_ids[i]);
+                       while (--i >= 0)
+                               free(res->res_unit[i]);
+                       free(temp);
+                       free(res);
+                       errno = EINVAL;
+                       return NULL;
+               }
+
+               temp->res_id = res_ids[i];
+               res->res_unit[i] = temp;
+       }
+
+       return res;
+}
+
+/* Free resources allocated in res_build */
+void res_destroy_blk(res_blk_t *res)
+{
+       for (int i = 0; i < res->res_count; i++) {
+               /* Some resource information are big and needed extra
+                * Free memory allocated for that.
+                */
+               switch (res->res_unit[i]->res_id) {
+               case RES_NET_IFSTAT:
+               case RES_MEM_INFOALL:
+                       free((res->res_unit[i])->data.ptr);
+                       break;
+               }
+
+               /* Free memory tho hold this resource info */
+               free(res->res_unit[i]);
+       }
+       free(res);
+}
+
+/* read resource information corresponding to res_id, out should have been
+ * properly allocated by caller if required.
+ */
+int res_read(int res_id, void *out, void *hint, int pid, int flags)
+{
+       struct utsname t;
+
+       if (out == NULL) {
+               switch (res_id) {
+               /* In case of RES_NET_ALLIFSTAT memory is allocated on the
+                * basis of number of interfaces available on system.
+                * So out can be NULL in that case.
+                */
+               case RES_NET_ALLIFSTAT:
+                       break;
+
+               default:
+                       eprintf("out argument cannot be NULL");
+                       errno = EINVAL;
+                       return -1;
+               }
+       }
+
+       /* Check if memory proc file is needed to open */
+       if (res_id >= MEM_MIN && res_id < MEM_MAX)
+               return getmeminfo(res_id, out, hint, pid, flags);
+
+       /* Check if net proc file is needed to open */
+       if (res_id >= NET_MIN && res_id < NET_MAX)
+               return getnetinfo(res_id, out, hint, pid, flags);
+
+       switch (res_id) {
+       case RES_KERN_RELEASE:
+               uname(&t);
+               strcpy(out, t.release);
+               break;
+
+       case RES_KERN_COMPILE_TIME:
+               uname(&t);
+               sscanf(t.version, "%*s%*s%*s%[^\t\n]", (char *) out);
+               break;
+
+       default:
+               eprintf("Resource Id is invalid");
+               errno = EINVAL;
+               return -1;
+       }
+       return 0;
+}
+
+/* Read bulk resource information */
+int res_read_blk(res_blk_t *res, int pid, int flags)
+{
+       int ismeminforeq = 0;
+       int isnetdevreq = 0;
+       struct utsname t;
+
+       /* Loop through all resource information. If it can be filled through
+        * a syscall or such method then fill it. Else set flags which tell
+        * what files might have the information.
+        */
+       for (int i = 0; i < res->res_count; i++) {
+               switch (res->res_unit[i]->res_id) {
+               case RES_MEM_TOTAL:
+               case RES_MEM_FREE:
+               case RES_MEM_AVAILABLE:
+               case RES_MEM_ACTIVE:
+               case RES_MEM_INACTIVE:
+               case RES_MEM_SWAPFREE:
+               case RES_MEM_SWAPTOTAL:
+               case RES_MEM_INFOALL:
+                       ismeminforeq = 1;
+                       break;
+
+               case RES_MEM_PAGESIZE:
+                       (res->res_unit[i]->data).sz = sysconf(_SC_PAGESIZE);
+                       res->res_unit[i]->status = RES_STATUS_FILLED;
+                       break;
+
+               case RES_KERN_RELEASE:
+                       uname(&t);
+                       strcpy((res->res_unit[i]->data).str, t.release);
+                       res->res_unit[i]->status = RES_STATUS_FILLED;
+                       break;
+
+               case RES_KERN_COMPILE_TIME:
+                       uname(&t);
+                       sscanf(t.version, "%*s%*s%*s%[^\t\n]",
+                               (res->res_unit[i]->data).str);
+                       break;
+
+               case RES_NET_IFSTAT:
+               case RES_NET_ALLIFSTAT:
+                       isnetdevreq = 1;
+                       break;
+
+               default:
+                       res->res_unit[i]->status = RES_STATUS_NOTSUPPORTED;
+               }
+       }
+
+       if (ismeminforeq)
+               populate_meminfo(res, pid, flags);
+
+       if (isnetdevreq)
+               populate_netinfo(res, pid, flags);
+
+       return 0;
+}
diff --git a/resource.h b/resource.h
new file mode 100644
index 0000000..c95b724
--- /dev/null
+++ b/resource.h
@@ -0,0 +1,142 @@
+#ifndef        _RESOURCE_H
+#define        _RESOURCE_H
+
+#include <net/if.h>
+
+/* libresource version */
+#define LIBRESOURCE_API_VERSION 1
+
+/* Possible status for libresource information returned */
+/* libresource information was fetched correctly */
+#define RES_STATUS_FILLED 0
+/* There was some error in fetching libresource information. In most cases
+ * errno will be set.
+ */
+#define RES_STATUS_EMPTY -1
+/* Resource information is not supported yet, or Invalid resource
+ * information.
+ */
+#define RES_STATUS_NOTSUPPORTED        -2
+/* If partial information was read for a libresource information. For example
+ * a string was read partially.
+ */
+#define RES_STATUS_TRUNCATED -3
+
+
+/* Maximum size of a resource information data type which can be returned
+ * without explicitly allocating memory for it. If resource information
+ * size is larger than this this a pointer to allocated memory will be
+ * returned.
+ */
+#define RES_UNIT_OUT_SIZE      256
+
+/* This union is used to return resource information of various types */
+union r_data {
+       int i;
+       size_t sz;
+       long l;
+       char str[RES_UNIT_OUT_SIZE];
+       void *ptr;
+};
+
+/* In case of res_read_blk, each resource information will be represented by
+ * following structure.
+ */
+typedef struct res_unit {
+       int status;
+       unsigned int res_id;
+       void *hint;
+       union r_data data;
+} res_unit_t;
+
+/* In case of bulk read (res_read_blk), this structure will hold all required
+ * information needed to do so.
+ */
+typedef struct res_blk {
+       int res_count;
+       res_unit_t *res_unit[0];
+} res_blk_t;
+
+/* Resource information is divided in broad categories and each
+ * category is assigned a number range for its resource information
+ * Memory related                      (RES_MEM_*)             1024-
+ * Network related                     (RES_NET_*)             2048-
+ * General kernel related              (RES_KERN_*)            3072-
+ * This is done to facilitate any future optimization which can be made
+ * on the basis of resource information (hashing etc ?)
+ */
+#define MEM_MIN                                1024
+#define RES_MEM_HUGEPAGEALL            1025
+#define RES_MEM_HUGEPAGESIZE           1026
+#define RES_MEM_INACTIVE               1027
+#define RES_MEM_INFOALL                        1028
+#define RES_MEM_AVAILABLE              1029
+#define RES_MEM_FREE                   1030
+#define RES_MEM_TOTAL                  1031
+#define RES_MEM_PAGESIZE               1032
+#define RES_MEM_SWAPFREE               1037
+#define RES_MEM_SWAPTOTAL              1038
+#define RES_MEM_ACTIVE                 1039
+#define MEM_MAX                                1040
+
+#define NET_MIN                                2048
+#define RES_NET_IFSTAT                 2049
+#define RES_NET_ALLIFSTAT              2050
+#define NET_MAX                                2051
+
+#define KERN_MIN                       3072
+#define RES_KERN_COMPILE_TIME          3073
+#define RES_KERN_RELEASE               3074
+#define KERN_MAX                       3075
+
+/* Structure to return RES_MEM_INFOALL resource information */
+typedef struct res_mem_infoall {
+       size_t memfree;
+       size_t memtotal;
+       size_t memavailable;
+       size_t active;
+       size_t inactive;
+       size_t swaptotal;
+       size_t swapfree;
+} res_mem_infoall_t;
+
+/* Structure to return RES_MEM_ALLIFSTAT resource information */
+typedef struct res_net_ifstat {
+       char ifname[IFNAMSIZ];
+       unsigned long long rx_bytes;
+       unsigned long long rx_packets;
+       unsigned long rx_errors;
+       unsigned long rx_dropped;
+       unsigned long rx_fifo_err;
+       unsigned long rx_frame_err;
+       unsigned long rx_compressed;
+       unsigned long rx_multicast;
+       unsigned long long tx_bytes;
+       unsigned long long tx_packets;
+       unsigned long tx_errors;
+       unsigned long tx_dropped;
+       unsigned long tx_fifo_err;
+       unsigned long tx_collisions;
+       unsigned long tx_carrier_err;
+       unsigned long tx_compressed;
+} res_net_ifstat_t;
+
+/* Allocating memory and building a res_blk structure to return bulk
+ * resource information.
+ */
+extern res_blk_t *res_build_blk(int *res_ids, int res_count);
+
+/* Reading bulk resource information. Memory must be properly allocated and
+ * all fields should be properly filled to return error free resource
+ * information. res_build_blk call is suggested to allocate build res_blk_t
+ * structure.
+ */
+extern int res_read_blk(res_blk_t *resblk, int pid, int flags);
+
+/* Free allocated memory from res_build_blk */
+extern void res_destroy_blk(res_blk_t *resblk);
+
+/* Read a resource information. Memory for out should be properly allocated */
+extern int res_read(int res_id, void *out, void *hint, int pid, int flags);
+
+#endif /* RESOURCE_H */
diff --git a/resource_impl.h b/resource_impl.h
new file mode 100644
index 0000000..e40e1d7
--- /dev/null
+++ b/resource_impl.h
@@ -0,0 +1,47 @@
+#ifndef _RESOURCE_IMPL_H
+#define _RESOURCE_IMPL_H
+
+#include <fcntl.h>
+#include <errno.h>
+#define SIZE_OF_TEMP_BUF       2048
+#define eprintf(msg, ...)      fprintf(stderr,\
+                                       "Err at line %d in file %s: "msg"\n",\
+                                       __LINE__, __FILE__, ##__VA_ARGS__)\
+
+
+static inline int file_to_buf(char *fname, char *buf)
+{
+       int fd = 0;
+       size_t rdsz = 0;
+       int err = 0;
+
+       fd = open(fname, O_RDONLY);
+       if (fd == -1) {
+               err = errno;
+               eprintf("in opening File %s with errno: %d", fname, errno);
+               errno = err;
+               return -1;
+       }
+
+       if (lseek(fd, 0L, SEEK_SET) == -1) {
+               err = errno;
+               eprintf("in lseek for File %s with errno: %d", fname, errno);
+               close(fd);
+               errno = err;
+               return -1;
+       }
+
+       rdsz = read(fd, buf, SIZE_OF_TEMP_BUF - 1);
+       if (rdsz < 0) {
+               err = errno;
+               eprintf("in read from File %s with errno: %d", fname, errno);
+               close(fd);
+               errno = err;
+               return -1;
+       }
+       buf[rdsz] = '\0';
+       close(fd);
+       return rdsz;
+}
+
+#endif /* _RESOURCE_IMPL_H */
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to