/*
* Copyright (C), 2000-2007 by the monit project group.
* All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef TIME_WITH_SYS_TIME
#include <time.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#else
#include <time.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_ASM_PARAM_H
#include <asm/param.h>
#endif
#ifdef HAVE_GLOB_H
#include <glob.h>
#endif
#ifndef HZ
# define HZ sysconf(_SC_CLK_TCK)
#endif
#include "monitor.h"
#include "process.h"
#include "process_sysdep.h"
/**
* System dependent resource gathering code for Linux.
*
* @author Jan-Henrik Haukeland, <hauk@tildeslash.com>
* @author Christian Hopp <chopp@iei.tu-clausthal.de>
* @author Martin Pala <martinp@tildeslash.com>
* @author Arkadiusz Miskiewicz <arekm@pld-linux.org>
*
* @version \$Id: sysdep_LINUX.c,v 1.44 2007/07/25 12:54:32 hauk Exp $
*
* @file
*/
/* ----------------------------------------------------------------- Private */
#define MEMTOTAL "MemTotal:"
#define MEMFREE "MemFree:"
#define MEMBUF "Buffers:"
#define MEMCACHE "Cached:"
static unsigned long long old_cpu_user = 0;
static unsigned long long old_cpu_syst = 0;
static unsigned long long old_cpu_wait = 0;
static unsigned long long old_cpu_total = 0;
static int page_shift_to_kb = 0;
/* ------------------------------------------------------------------ Public */
int init_process_info_sysdep(void) {
char *ptr;
char buf[1024];
long page_size;
int page_shift;
if(!read_proc_file(buf, 1024, "meminfo", -1))
{
return FALSE;
}
if(!(ptr= strstr(buf, MEMTOTAL)))
{
DEBUG("system statistic error -- cannot get real memory amount\n");
return FALSE;
}
if(sscanf(ptr+strlen(MEMTOTAL), "%ld", &systeminfo.mem_kbyte_max) != 1)
{
DEBUG("system statistic error -- cannot get real memory amount\n");
return FALSE;
}
if((num_cpus = sysconf(_SC_NPROCESSORS_CONF)) == -1)
{
DEBUG("system statistic error -- cannot get cpu count: %s\n", STRERROR);
return FALSE;
}
if((page_size = sysconf(_SC_PAGESIZE)) <= 0) {
DEBUG("system statistic error -- cannot get page size: %s\n", STRERROR);
return FALSE;
}
for(page_shift=0; page_size!=1; page_size>>=1, page_shift++);
page_shift_to_kb=page_shift-10;
return TRUE;
}
/**
* Read all processes of the proc files system to initialize
* the process tree (sysdep version... but should work for
* all procfs based unices)
* @param reference reference of ProcessTree
* @return treesize>0 if succeeded otherwise =0.
*/
int initprocesstree_sysdep(ProcessTree_T ** reference) {
int i = 0;
int treesize = 0;
int stat_ppid = 0;
char *tmp = NULL;
char buf[4096];
char stat_item_state;
long stat_item_cutime = 0;
long stat_item_cstime = 0;
long stat_item_rss = 0;
glob_t globbuf;
unsigned long stat_item_utime = 0;
unsigned long stat_item_stime = 0;
ProcessTree_T *pt = NULL;
ASSERT(reference);
/* Find all processes in the /proc directory */
if(glob("/proc/[0-9]*", GLOB_ONLYDIR, NULL, &globbuf))
{
LogError("system statistic error -- glob failed\n");
return FALSE;
}
treesize = globbuf.gl_pathc;
pt = xcalloc(sizeof(ProcessTree_T), treesize);
/* Insert data from /proc directory */
for(i = 0; i < treesize; i++)
{
pt[i].pid = atoi(globbuf.gl_pathv[i] + strlen("/proc/"));
if(!read_proc_file(buf, 4096, "stat", pt[i].pid))
{
DEBUG(
"system statistic error -- cannot read /proc/%d/stat\n",
pt[i].pid);
continue;
}
pt[i].time = get_float_time();
/* Move along the buffer to get past the process name */
if(!(tmp = strrchr(buf, ')')))
{
DEBUG(
"system statistic error -- file /proc/%d/stat parse error\n",
pt[i].pid);
continue;
}
tmp += 2;
/* This implementation is done by using fs/procfs/array.c as a basis
* it is also worth looking into the source of the procps utils */
if(sscanf(tmp,
"%c %d %*d %*d %*d %*d %*u %*u"
"%*u %*u %*u %lu %lu %ld %ld %*d %*d %*d "
"%*d %*u %*u %ld %*u %*u %*u %*u %*u "
"%*u %*u %*u %*u %*u %*u %*u %*u %*d %*d\n",
&stat_item_state,
&stat_ppid,
&stat_item_utime,
&stat_item_stime,
&stat_item_cutime,
&stat_item_cstime,
&stat_item_rss) != 7)
{
DEBUG(
"system statistic error -- file /proc/%d/stat parse error\n",
pt[i].pid);
continue;
}
/* abs to please the compiler... we dont want to shift negatively.
* why doesn't C understand this??? */
pt[i].ppid = stat_ppid;
/* jiffies -> seconds = 1 / HZ
* HZ is defined in "asm/param.h" and it is usually 1/100s but on
* alpha system it is 1/1024s */
pt[i].cputime =
((float)(stat_item_utime + stat_item_stime) * 10.0) / HZ;
/* State is Zombie -> then we are a Zombie ... clear or? (-: */
if(stat_item_state == 'Z')
{
pt[i].status_flag |= PROCESS_ZOMBIE;
}
if(page_shift_to_kb < 0)
{
pt[i].mem_kbyte = (stat_item_rss >> abs(page_shift_to_kb));
}
else
{
pt[i].mem_kbyte = (stat_item_rss << abs(page_shift_to_kb));
}
}
*reference = pt;
globfree(&globbuf);
return treesize;
}
/**
* This routine returns 'nelem' double precision floats containing
* the load averages in 'loadv'; at most 3 values will be returned.
* @param loadv destination of the load averages
* @param nelem number of averages
* @return: 0 if successful, -1 if failed (and all load averages are 0).
*/
int getloadavg_sysdep (double *loadv, int nelem) {
return getloadavg(loadv, nelem);
}
/**
* This routine returns kbyte of real memory in use.
* @return: TRUE if successful, FALSE if failed
*/
int used_system_memory_sysdep(SystemInfo_T *si) {
char *ptr;
char buf[1024];
unsigned long mem_free;
unsigned long buffers;
unsigned long cached;
if(!read_proc_file(buf, 1024, "meminfo", -1))
{
LogError("system statistic error -- cannot get real memory free amount\n");
goto error;
}
if(!(ptr= strstr(buf, MEMFREE)))
{
LogError("system statistic error -- cannot get real memory free amount\n");
goto error;
}
if(sscanf(ptr + strlen(MEMFREE), "%ld", &mem_free) != 1)
{
LogError("system statistic error -- cannot get real memory free amount\n");
goto error;
}
if(!(ptr= strstr(buf, MEMBUF)))
{
LogError("system statistic error -- cannot get real memory buffers "
"amount\n");
goto error;
}
if(sscanf(ptr + strlen(MEMBUF), "%ld", &buffers) != 1)
{
LogError("system statistic error -- cannot get real memory buffers "
"amount\n");
goto error;
}
if(!(ptr= strstr(buf, MEMCACHE)))
{
LogError("system statistic error -- cannot get real memory cache amount\n");
goto error;
}
if(sscanf(ptr + strlen(MEMCACHE), "%ld", &cached) != 1)
{
LogError("system statistic error -- cannot get real memory cache free "
"amount\n");
goto error;
}
si->total_mem_kbyte = systeminfo.mem_kbyte_max - mem_free - buffers - cached;
if(si->total_mem_kbyte < 0)
{
LogError("system statistic error -- memory usage statistic error\n");
goto error;
}
return TRUE;
error:
LogError("system statistic error -- memory usage gathering failed\n");
si->total_mem_kbyte = 0;
return FALSE;
}
/**
* This routine returns system/user CPU time in use.
* @return: TRUE if successful, FALSE if failed (or not available)
*/
int used_system_cpu_sysdep(SystemInfo_T *si) {
int rv;
unsigned long long cpu_total;
unsigned long long cpu_user;
unsigned long long cpu_nice;
unsigned long long cpu_syst;
unsigned long long cpu_idle;
unsigned long long cpu_wait;
unsigned long long cpu_irq;
unsigned long long cpu_softirq;
char buf[1024];
if(!read_proc_file(buf, 1024, "stat", -1))
{
LogError("system statistic error -- cannot read /proc/stat\n");
goto error;
}
rv = sscanf(buf, "cpu %llu %llu %llu %llu %llu %llu %llu",
&cpu_user,
&cpu_nice,
&cpu_syst,
&cpu_idle,
&cpu_wait,
&cpu_irq,
&cpu_softirq);
if(rv < 4)
{
LogError("system statistic error -- cannot read cpu usage\n");
goto error;
}
else if(rv == 4)
{
/* linux 2.4.x doesn't support these values */
cpu_wait = 0;
cpu_irq = 0;
cpu_softirq = 0;
}
cpu_total= cpu_user + cpu_nice + cpu_syst + cpu_idle + cpu_wait + cpu_irq + cpu_softirq;
cpu_user = cpu_user + cpu_nice;
if(old_cpu_total == 0)
{
si->total_cpu_user_percent = 0;
si->total_cpu_syst_percent = 0;
si->total_cpu_wait_percent = 0;
}
else
{
unsigned long long delta = cpu_total - old_cpu_total;
si->total_cpu_user_percent =
(int)(1000 * (double)(cpu_user - old_cpu_user) / delta);
si->total_cpu_syst_percent =
(int)(1000 * (double)(cpu_syst - old_cpu_syst) / delta);
si->total_cpu_wait_percent =
(int)(1000 * (double)(cpu_wait - old_cpu_wait) / delta);
}
old_cpu_user = cpu_user;
old_cpu_syst = cpu_syst;
old_cpu_wait = cpu_wait;
old_cpu_total= cpu_total;
return TRUE;
error:
si->total_cpu_user_percent = 0;
si->total_cpu_syst_percent = 0;
si->total_cpu_wait_percent = 0;
return FALSE;
}
syntax highlighted by Code2HTML, v. 0.9.1