/* * 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 */ #include #include #include #include #include #include #include #include #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; }; struct procps_vmstat { 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. * * Returns: a new procps_vmstat container */ PROCPS_EXPORT int procps_vmstat_new ( struct procps_vmstat **info) { struct procps_vmstat *v; v = calloc(1, sizeof(struct procps_vmstat)); if (!v) return -ENOMEM; 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 * * Returns: 0 on success, negative on error */ PROCPS_EXPORT int procps_vmstat_read ( struct procps_vmstat *info) { char buf[8192]; char *head, *tail; int size; unsigned long *valptr; if (info == NULL) return -1; 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) { return -errno; } if (lseek(info->vmstat_fd, 0L, SEEK_SET) == -1) { return -errno; } for (;;) { if ((size = read(info->vmstat_fd, buf, sizeof(buf)-1)) < 0) { if (errno == EINTR || errno == EAGAIN) continue; return -errno; } break; } if (size == 0) return 0; buf[size] = '\0'; /* Scan the file */ head = buf; do { 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; } while(tail); return 0; } PROCPS_EXPORT int procps_vmstat_ref ( struct procps_vmstat *info) { if (info == NULL) return -EINVAL; info->refcount++; return info->refcount; } PROCPS_EXPORT int procps_vmstat_unref ( struct procps_vmstat **info) { if (info == NULL || *info == NULL) return -EINVAL; (*info)->refcount--; if ((*info)->refcount == 0) { free(*info); *info = NULL; return 0; } return (*info)->refcount; } /* Accessor functions */ PROCPS_EXPORT unsigned long procps_vmstat_get ( struct procps_vmstat *info, enum vmstat_item item) { 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; default: return 0; } } PROCPS_EXPORT int procps_vmstat_getstack ( struct procps_vmstat *info, struct vmstat_result *these) { if (these == NULL) return -EINVAL; for (;;) { switch (these->item) { case PROCPS_VMSTAT_PGPGIN: these->result.ul_int = info->data.pgpgin; break; case PROCPS_VMSTAT_PGPGOUT: these->result.ul_int = info->data.pgpgout; break; case PROCPS_VMSTAT_PSWPIN: these->result.ul_int = info->data.pswpin; break; case PROCPS_VMSTAT_PSWPOUT: these->result.ul_int = info->data.pswpout; break; case PROCPS_VMSTAT_noop: // don't disturb potential user data in the result struct break; case PROCPS_VMSTAT_stack_end: return 0; default: return -EINVAL; } ++these; } }