2015-07-21 10:30:00 +05:30
|
|
|
/*
|
|
|
|
* libprocps - Library to read proc filesystem
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
2015-06-20 03:13:02 +05:30
|
|
|
|
|
|
|
#include <errno.h>
|
2015-07-21 10:30:00 +05:30
|
|
|
#include <fcntl.h>
|
2015-06-20 03:13:02 +05:30
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2015-07-21 10:30:00 +05:30
|
|
|
|
2015-06-20 03:13:02 +05:30
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include <proc/vmstat.h>
|
|
|
|
#include "procps-private.h"
|
|
|
|
|
|
|
|
#define VMSTAT_FILE "/proc/vmstat"
|
|
|
|
#define ROW_NAME_LEN 32
|
|
|
|
|
|
|
|
struct vmstat_data {
|
|
|
|
unsigned long pgpgin;
|
|
|
|
unsigned long pgpgout;
|
|
|
|
unsigned long pswpin;
|
|
|
|
unsigned long pswpout;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mem_table_struct {
|
|
|
|
const char *name;
|
|
|
|
unsigned long *slot;
|
|
|
|
};
|
|
|
|
|
2015-06-21 13:52:28 +05:30
|
|
|
struct procps_vmstat {
|
2015-06-20 03:13:02 +05:30
|
|
|
int refcount;
|
|
|
|
int vmstat_fd;
|
|
|
|
struct vmstat_data data;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* procps_vmstat_new:
|
|
|
|
*
|
|
|
|
* Create a new container to hold the vmstat information
|
|
|
|
*
|
|
|
|
* The initial refcount is 1, and needs to be decremented
|
|
|
|
* to release the resources of the structure.
|
|
|
|
*
|
2015-06-21 13:52:28 +05:30
|
|
|
* Returns: a new procps_vmstat container
|
2015-06-20 03:13:02 +05:30
|
|
|
*/
|
2015-06-28 10:30:00 +05:30
|
|
|
PROCPS_EXPORT int procps_vmstat_new (
|
|
|
|
struct procps_vmstat **info)
|
2015-06-20 03:13:02 +05:30
|
|
|
{
|
2015-06-21 13:52:28 +05:30
|
|
|
struct procps_vmstat *v;
|
|
|
|
v = calloc(1, sizeof(struct procps_vmstat));
|
2015-06-20 03:13:02 +05:30
|
|
|
if (!v)
|
2015-06-28 10:30:00 +05:30
|
|
|
return -ENOMEM;
|
2015-06-20 03:13:02 +05:30
|
|
|
|
|
|
|
v->refcount = 1;
|
|
|
|
v->vmstat_fd = -1;
|
|
|
|
*info = v;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* procps_vmstat_read:
|
|
|
|
*
|
|
|
|
* Read the data out of /proc/vmstat putting the information
|
|
|
|
* into the supplied info structure
|
2015-06-21 13:52:28 +05:30
|
|
|
*
|
|
|
|
* Returns: 0 on success, negative on error
|
2015-06-20 03:13:02 +05:30
|
|
|
*/
|
2015-06-28 10:30:00 +05:30
|
|
|
PROCPS_EXPORT int procps_vmstat_read (
|
|
|
|
struct procps_vmstat *info)
|
2015-06-20 03:13:02 +05:30
|
|
|
{
|
|
|
|
char buf[8192];
|
|
|
|
char *head, *tail;
|
|
|
|
int size;
|
|
|
|
unsigned long *valptr;
|
|
|
|
|
|
|
|
if (info == NULL)
|
2015-06-28 10:30:00 +05:30
|
|
|
return -1;
|
2015-06-20 03:13:02 +05:30
|
|
|
|
|
|
|
memset(&(info->data), 0, sizeof(struct vmstat_data));
|
|
|
|
/* read in the data */
|
|
|
|
|
|
|
|
if (-1 == info->vmstat_fd && (info->vmstat_fd = open(VMSTAT_FILE, O_RDONLY)) == -1) {
|
2015-06-28 10:30:00 +05:30
|
|
|
return -errno;
|
2015-06-20 03:13:02 +05:30
|
|
|
}
|
|
|
|
if (lseek(info->vmstat_fd, 0L, SEEK_SET) == -1) {
|
2015-06-28 10:30:00 +05:30
|
|
|
return -errno;
|
2015-06-20 03:13:02 +05:30
|
|
|
}
|
2015-06-28 10:30:00 +05:30
|
|
|
for (;;) {
|
|
|
|
if ((size = read(info->vmstat_fd, buf, sizeof(buf)-1)) < 0) {
|
|
|
|
if (errno == EINTR || errno == EAGAIN)
|
|
|
|
continue;
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
break;
|
2015-06-20 03:13:02 +05:30
|
|
|
}
|
2015-06-28 10:30:00 +05:30
|
|
|
if (size == 0)
|
|
|
|
return 0;
|
2015-06-20 03:13:02 +05:30
|
|
|
buf[size] = '\0';
|
|
|
|
|
|
|
|
/* Scan the file */
|
|
|
|
head = buf;
|
|
|
|
do {
|
2015-06-28 10:30:00 +05:30
|
|
|
tail = strchr(head, ' ');
|
|
|
|
if (!tail)
|
|
|
|
break;
|
|
|
|
*tail = '\0';
|
|
|
|
valptr = NULL;
|
|
|
|
if (0 == strcmp(head, "pgpgin")) {
|
|
|
|
valptr = &(info->data.pgpgin);
|
|
|
|
}else if (0 == strcmp(head, "pgpgout")) {
|
|
|
|
valptr = &(info->data.pgpgout);
|
|
|
|
}else if (0 == strcmp(head, "pswpin")) {
|
|
|
|
valptr = &(info->data.pswpin);
|
|
|
|
}else if (0 == strcmp(head, "pswpout")) {
|
|
|
|
valptr = &(info->data.pswpout);
|
|
|
|
}
|
|
|
|
head = tail+1;
|
|
|
|
if (valptr) {
|
|
|
|
*valptr = strtoul(head, &tail, 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
tail = strchr(head, '\n');
|
|
|
|
if (!tail)
|
|
|
|
break;
|
|
|
|
head = tail + 1;
|
2015-06-20 03:13:02 +05:30
|
|
|
} while(tail);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-30 10:30:00 +05:30
|
|
|
PROCPS_EXPORT int procps_vmstat_ref (
|
2015-06-28 10:30:00 +05:30
|
|
|
struct procps_vmstat *info)
|
2015-06-20 03:13:02 +05:30
|
|
|
{
|
|
|
|
if (info == NULL)
|
2015-06-30 10:30:00 +05:30
|
|
|
return -EINVAL;
|
2015-06-20 03:13:02 +05:30
|
|
|
info->refcount++;
|
2015-06-30 10:30:00 +05:30
|
|
|
return info->refcount;
|
2015-06-20 03:13:02 +05:30
|
|
|
}
|
|
|
|
|
2015-06-30 10:30:00 +05:30
|
|
|
PROCPS_EXPORT int procps_vmstat_unref (
|
|
|
|
struct procps_vmstat **info)
|
2015-06-20 03:13:02 +05:30
|
|
|
{
|
2015-06-30 10:30:00 +05:30
|
|
|
if (info == NULL || *info == NULL)
|
|
|
|
return -EINVAL;
|
|
|
|
(*info)->refcount--;
|
|
|
|
if ((*info)->refcount == 0) {
|
|
|
|
free(*info);
|
|
|
|
*info = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return (*info)->refcount;
|
2015-06-20 03:13:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* Accessor functions */
|
2015-06-28 10:30:00 +05:30
|
|
|
PROCPS_EXPORT unsigned long procps_vmstat_get (
|
|
|
|
struct procps_vmstat *info,
|
|
|
|
enum vmstat_item item)
|
2015-06-20 03:13:02 +05:30
|
|
|
{
|
2015-06-28 10:30:00 +05:30
|
|
|
switch (item) {
|
|
|
|
case PROCPS_VMSTAT_PGPGIN:
|
|
|
|
return info->data.pgpgin;
|
|
|
|
case PROCPS_VMSTAT_PGPGOUT:
|
|
|
|
return info->data.pgpgout;
|
|
|
|
case PROCPS_VMSTAT_PSWPIN:
|
|
|
|
return info->data.pswpin;
|
|
|
|
case PROCPS_VMSTAT_PSWPOUT:
|
|
|
|
return info->data.pswpout;
|
2015-07-21 10:30:00 +05:30
|
|
|
default:
|
|
|
|
return 0;
|
2015-06-20 03:13:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-21 10:30:00 +05:30
|
|
|
PROCPS_EXPORT int procps_vmstat_getstack (
|
2015-06-28 10:30:00 +05:30
|
|
|
struct procps_vmstat *info,
|
2015-07-21 10:30:00 +05:30
|
|
|
struct vmstat_result *these)
|
2015-06-28 10:30:00 +05:30
|
|
|
{
|
2015-07-21 10:30:00 +05:30
|
|
|
if (these == NULL)
|
2015-06-28 10:30:00 +05:30
|
|
|
return -EINVAL;
|
|
|
|
|
2015-07-21 10:30:00 +05:30
|
|
|
for (;;) {
|
|
|
|
switch (these->item) {
|
2015-06-28 10:30:00 +05:30
|
|
|
case PROCPS_VMSTAT_PGPGIN:
|
2015-07-21 10:30:00 +05:30
|
|
|
these->result.ul_int = info->data.pgpgin;
|
2015-06-28 10:30:00 +05:30
|
|
|
break;
|
|
|
|
case PROCPS_VMSTAT_PGPGOUT:
|
2015-07-21 10:30:00 +05:30
|
|
|
these->result.ul_int = info->data.pgpgout;
|
2015-06-28 10:30:00 +05:30
|
|
|
break;
|
|
|
|
case PROCPS_VMSTAT_PSWPIN:
|
2015-07-21 10:30:00 +05:30
|
|
|
these->result.ul_int = info->data.pswpin;
|
2015-06-28 10:30:00 +05:30
|
|
|
break;
|
|
|
|
case PROCPS_VMSTAT_PSWPOUT:
|
2015-07-21 10:30:00 +05:30
|
|
|
these->result.ul_int = info->data.pswpout;
|
|
|
|
break;
|
|
|
|
case PROCPS_VMSTAT_noop:
|
|
|
|
// don't disturb potential user data in the result struct
|
2015-06-28 10:30:00 +05:30
|
|
|
break;
|
2015-07-21 10:30:00 +05:30
|
|
|
case PROCPS_VMSTAT_stack_end:
|
|
|
|
return 0;
|
2015-06-28 10:30:00 +05:30
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2015-07-21 10:30:00 +05:30
|
|
|
++these;
|
|
|
|
}
|
2015-06-28 10:30:00 +05:30
|
|
|
}
|