diff --git a/Makefile.am b/Makefile.am index f7798145..b3558776 100644 --- a/Makefile.am +++ b/Makefile.am @@ -158,6 +158,8 @@ proc_libprocps_la_SOURCES = \ proc/escape.c \ proc/escape.h \ proc/procps-private.h \ + proc/meminfo.c \ + proc/meminfo.h \ proc/procps.h \ proc/pwcache.c \ proc/pwcache.h \ diff --git a/proc/libprocps.sym b/proc/libprocps.sym index 301fdb60..3907f5a8 100644 --- a/proc/libprocps.sym +++ b/proc/libprocps.sym @@ -60,6 +60,11 @@ global: uptime; user_from_uid; procps_linux_version; + procps_meminfo_new; + procps_meminfo_read; + procps_meminfo_ref; + procps_meminfo_unref; + procps_meminfo_get; procps_stat_new; procps_stat_read; procps_stat_ref; diff --git a/proc/meminfo.c b/proc/meminfo.c new file mode 100644 index 00000000..dee1fac6 --- /dev/null +++ b/proc/meminfo.c @@ -0,0 +1,177 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "procps-private.h" + +#define MEMINFO_FILE "/proc/meminfo" + +struct meminfo_data { + unsigned long active; + unsigned long inactive; + unsigned long high_free; + unsigned long high_total; + unsigned long low_free; + unsigned long low_total; + unsigned long main_available; + unsigned long main_buffers; + unsigned long main_cached; + unsigned long main_free; + unsigned long main_shared; + unsigned long main_total; + unsigned long main_used; + unsigned long swap_free; + unsigned long swap_total; + unsigned long swap_used; +}; + +struct procps_meminfo { + int refcount; + int meminfo_fd; + struct meminfo_data data; +}; + + +/* + * procps_meminfo_new: + * + * Create a new container to hold the meminfo information + * + * The initial refcount is 1, and needs to be decremented + * to release the resources of the structure. + * + * Returns: a new meminfo info container + */ +PROCPS_EXPORT int procps_meminfo_new(struct procps_meminfo **info) +{ + struct procps_meminfo *m; + m = calloc(1, sizeof(struct procps_meminfo)); + if (!m) + return -ENOMEM; + + m->refcount = 1; + m->meminfo_fd = -1; + *info = m; + return 0; +} + +/* + * procps_meminfo_read: + * + * Read the data out of /proc/meminfo putting the information + * into the supplied info structure + */ +PROCPS_EXPORT int procps_meminfo_read(struct procps_meminfo *info) +{ + char buf[8192]; + char *head, *tail; + int size; + unsigned long *valptr; + + if (info == NULL) + return -1; + + memset(&(info->data), 0, sizeof(struct meminfo_data)); + /* read in the data */ + + if (-1 == info->meminfo_fd && (info->meminfo_fd = open(MEMINFO_FILE, O_RDONLY)) == -1) { + return -errno; + } + if (lseek(info->meminfo_fd, 0L, SEEK_SET) == -1) { + return -errno; + } + if ((size = read(info->meminfo_fd, buf, sizeof(buf)-1)) < 0) { + return -1; + } + buf[size] = '\0'; + + /* Scan the file */ + head = buf; + do { + tail = strchr(head, ' '); + if (!tail) + break; + *tail = '\0'; + valptr = NULL; + if (0 == strcmp(head, "Active:")) { + valptr = &(info->data.active); + } else if (0 == strcmp(head, "Inactive:")) { + valptr = &(info->data.inactive); + } else if (0 == strcmp(head, "HighFree:")) { + valptr = &(info->data.high_free); + } else if (0 == strcmp(head, "HighTotal:")) { + valptr = &(info->data.high_total); + } else if (0 == strcmp(head, "LowFree:")) { + valptr = &(info->data.low_free); + } else if (0 == strcmp(head, "LowTotal:")) { + valptr = &(info->data.low_total); + } else if (0 == strcmp(head, "MemAvailable:")) { + valptr = &(info->data.main_available); + } else if (0 == strcmp(head, "Buffers:")) { + valptr = &(info->data.main_buffers); + } else if (0 == strcmp(head, "Cached:")) { + valptr = &(info->data.main_cached); + } else if (0 == strcmp(head, "MemFree:")) { + valptr = &(info->data.main_free); + } else if (0 == strcmp(head, "Shmem:")) { + valptr = &(info->data.main_shared); + } else if (0 == strcmp(head, "MemTotal:")) { + valptr = &(info->data.main_total); + } else if (0 == strcmp(head, "SwapFree:")) { + valptr = &(info->data.swap_free); + } else if (0 == strcmp(head, "SwapTotal:")) { + valptr = &(info->data.swap_total); + } + head - tail+1; + if (valptr) { + *valptr = strtoul(head, &tail, 10); + } + + tail = strchr(head, '\n'); + if (!tail) + break; + head = tail + 1; + } while(tail); + return 0; +} + + +PROCPS_EXPORT struct procps_meminfo *procps_meminfo_ref(struct procps_meminfo *info) +{ + if (info == NULL) + return NULL; + info->refcount++; + return info; +} + +PROCPS_EXPORT struct procps_meminfo *procps_meminfo_unref(struct procps_meminfo *info) +{ + if (info == NULL) + return NULL; + info->refcount--; + if (info->refcount > 0) + return NULL; + free(info); + return NULL; +} + +/* Accessor functions */ +PROCPS_EXPORT unsigned long procps_meminfo_get( + struct procps_meminfo *info, + enum meminfo_item item) +{ + switch(item) { + case PROCPS_MEMINFO_ACTIVE: + return info->data.active; + case PROCPS_MEMINFO_SWAP_USED: + if (info->data.swap_free > info->data.swap_total) + return 0; + return info->data.swap_total - info->data.swap_free; + } + return 0; +} diff --git a/proc/meminfo.h b/proc/meminfo.h new file mode 100644 index 00000000..8debb5c7 --- /dev/null +++ b/proc/meminfo.h @@ -0,0 +1,54 @@ +/* + * libprocps - Library to read proc filesystem + * meminfo - Parse /proc/meminfo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef PROC_MEMINFO_H +#define PROC_MEMINFO_H + +#include + +__BEGIN_DECLS + +struct procps_meminfo; +int procps_meminfo_new(struct procps_meminfo **info); +int procps_meminfo_read(struct procps_meminfo *info); +struct procps_meminfo *procps_meminfo_ref(struct procps_meminfo *info); +struct procps_meminfo *procps_meminfo_unref(struct procps_meminfo *info); + +enum meminfo_item { + PROCPS_MEMINFO_ACTIVE, + PROCPS_MEMINFO_INACTIVE, + PROCPS_MEMINFO_HIGH_FREE, + PROCPS_MEMINFO_HIGH_TOTAL, + PROCPS_MEMINFO_LOW_FREE, + PROCPS_MEMINFO_LOW_TOTAL, + PROCPS_MEMINFO_MAIN_AVAILABLE, + PROCPS_MEMINFO_MAIN_BUFFERS, + PROCPS_MEMINFO_MAIN_CACHED, + PROCPS_MEMINFO_MAIN_FREE, + PROCPS_MEMINFO_MAIN_SHARED, + PROCPS_MEMINFO_MAIN_TOTAL, + PROCPS_MEMINFO_MAIN_USED, + PROCPS_MEMINFO_SWAP_FREE, + PROCPS_MEMINFO_SWAP_TOTAL, + PROCPS_MEMINFO_SWAP_USED, +}; +unsigned long procps_meminfo_get(struct procps_meminfo *info, enum meminfo_item item); + +__END_DECLS +#endif +