/*
* 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 .
*/
#include
#ifdef HAVE_STDIO_H
#include
#endif
#ifdef HAVE_ERRNO_H
#include
#endif
#ifdef HAVE_SYS_TYPES_H
#include
#endif
#ifdef HAVE_UNISTD_H
#include
#endif
#ifdef HAVE_SYS_STAT_H
#include
#endif
#ifdef HAVE_FCNTL_H
#include
#endif
#ifdef HAVE_STDLIB_H
#include
#endif
#ifdef TIME_WITH_SYS_TIME
#include
#ifdef HAVE_SYS_TIME_H
#include
#endif
#else
#include
#endif
#ifdef HAVE_SYS_LOADAVG_H
#include
#endif
#ifdef HAVE_STRING_H
#include
#endif
#ifdef HAVE_PROCFS_H
#include
#endif
#ifdef HAVE_GLOB_H
#include
#endif
#ifdef HAVE_KSTAT_H
#include
#endif
#include
#include "monitor.h"
#include "process.h"
#include "process_sysdep.h"
/**
* System dependent resource gathering code for Solaris.
*
* @author Jan-Henrik Haukeland,
* @author Christian Hopp
*
* @version \$Id: sysdep_SOLARIS.c,v 1.21 2007/07/25 12:54:32 hauk Exp $
*
* @file
*/
#define pagetok(size) ((size) << pageshift)
static int pageshift=0;
static long old_cpu_user=0;
static long old_cpu_syst=0;
static long old_cpu_wait=0;
static long old_total=0;
#ifndef LOG1024
#define LOG1024 10
#endif
int init_process_info_sysdep(void) {
register int pagesize;
num_cpus= sysconf( _SC_NPROCESSORS_ONLN);
pagesize = sysconf(_SC_PAGESIZE);
pageshift = 0;
while (pagesize > 1) {
pageshift++;
pagesize >>= 1;
}
/* we only need the amount of log(2)1024 for our conversion */
pageshift -= LOG1024;
systeminfo.mem_kbyte_max=pagetok(sysconf(_SC_PHYS_PAGES));
return (getuid()==0);
}
double timestruc_to_tseconds(timestruc_t t) {
return t.tv_sec * 10 + t.tv_nsec / 100000000.0;
}
/**
* 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) {
char buf[4096];
psinfo_t * psinfo= (psinfo_t *)&buf;
pstatus_t * pstatus= (pstatus_t *)&buf;
int pid;
int i;
int treesize;
ProcessTree_T * pt;
glob_t globbuf;
ASSERT(reference);
/* Find all processes in the /proc directory */
if (glob("/proc/[0-9]*", 0, NULL, &globbuf) != 0 ) {
return 0;
}
treesize = globbuf.gl_pathc;
/* Allocate the tree */
pt = xcalloc(sizeof(ProcessTree_T), treesize);
/* Insert data from /proc directory */
for ( i = 0; i < treesize; i ++ ) {
pid=atoi(globbuf.gl_pathv[i]+strlen("/proc/"));
pt[i].pid=pid;
/* get the actual time */
pt[i].time = get_float_time();
if (!read_proc_file(buf,4096, "psinfo", pt[i].pid)) {
pt[i].cputime = 0;
pt[i].mem_kbyte= 0;
continue;
}
pt[i].ppid = psinfo->pr_ppid;
/* If we don't have any light-weight processes (LWP) then we
are definitely a zombie */
if ( psinfo->pr_nlwp == 0 ) {
pt[i].status_flag = PROCESS_ZOMBIE;
/* We can't access /proc/$pid/status of a zombie */
/* and does it anyway matter? */
pt[i].cputime = 0;
pt[i].mem_kbyte= 0;
continue;
}
pt[i].mem_kbyte = psinfo->pr_rssize;
if (!read_proc_file(buf,4096, "status", pt[i].pid)) {
pt[i].cputime=0;
} else {
pt[i].cputime= ( timestruc_to_tseconds(pstatus->pr_utime) +
timestruc_to_tseconds(pstatus->pr_stime) );
}
}
* reference = pt;
/* Free globbing buffer */
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 (or not available)
*/
int used_system_memory_sysdep(SystemInfo_T *si) {
kstat_ctl_t *kctl;
kstat_named_t *knamed;
kstat_t *kstat;
kctl = kstat_open();
kstat = kstat_lookup(kctl, "unix", 0, "system_pages");
if (kstat_read(kctl, kstat, 0) == -1) {
LogError("system statistic error -- memory usage gathering failed\n");
kstat_close(kctl);
return FALSE;
}
knamed = kstat_data_lookup(kstat, "freemem");
if (knamed) {
si->total_mem_kbyte = systeminfo.mem_kbyte_max-pagetok(knamed->value.ul);
}
kstat_close(kctl);
return TRUE;
}
/**
* 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) {
kstat_ctl_t *kctl;
kstat_named_t *knamed;
kstat_t *kstat;
kstat_t **cpu_ks;
cpu_stat_t *cpu_stat;
int i, ncpu=0, ncpus;
long cpu_user=0, cpu_syst=0, cpu_wait=0;
long total=0;
si->total_cpu_user_percent=0;
si->total_cpu_syst_percent=0;
si->total_cpu_wait_percent=0;
kctl = kstat_open();
kstat = kstat_lookup(kctl, "unix", 0, "system_misc");
if (kstat_read(kctl, kstat, 0) == -1) {
goto error;
}
if (NULL == (knamed = kstat_data_lookup(kstat, "ncpus"))) {
goto error;
}
ncpus = knamed->value.ui32;
cpu_ks = (kstat_t **) xmalloc(ncpus * sizeof (kstat_t *));
cpu_stat = (cpu_stat_t *) xmalloc (ncpus * sizeof (cpu_stat_t));
for (kstat = kctl->kc_chain; kstat;
kstat = kstat->ks_next)
{
if (strncmp(kstat->ks_name, "cpu_stat", 8) == 0)
{
if (-1 == kstat_read(kctl, kstat, NULL)) {
goto error2;
}
cpu_ks[ncpu] = kstat;
ncpu++;
if (ncpu > ncpus) {
goto error2;
}
}
}
for (i = 0; i < ncpu; i++)
{
if ( -1 == kstat_read(kctl, cpu_ks[i], &cpu_stat[i])) {
goto error2;
}
cpu_user+=cpu_stat[i].cpu_sysinfo.cpu[CPU_USER];
cpu_syst+=cpu_stat[i].cpu_sysinfo.cpu[CPU_KERNEL];
cpu_wait+=cpu_stat[i].cpu_sysinfo.cpu[CPU_WAIT];
total += ( cpu_stat[i].cpu_sysinfo.cpu[0]+
cpu_stat[i].cpu_sysinfo.cpu[1]+
cpu_stat[i].cpu_sysinfo.cpu[2]+
cpu_stat[i].cpu_sysinfo.cpu[3]+
cpu_stat[i].cpu_sysinfo.cpu[4] );
}
if ( old_total == 0.0 ) {
si->total_cpu_user_percent=0;
si->total_cpu_syst_percent=0;
si->total_cpu_wait_percent=0;
} else {
si->total_cpu_user_percent=(int)((1000*(cpu_user-old_cpu_user))/
(total-old_total));
si->total_cpu_syst_percent=(int)((1000*(cpu_syst-old_cpu_syst))/
(total-old_total));
si->total_cpu_wait_percent=(int)((1000*(cpu_wait-old_cpu_wait))/
(total-old_total));
}
old_cpu_user=cpu_user;
old_cpu_syst=cpu_syst;
old_cpu_wait=cpu_wait;
old_total=total;
FREE(cpu_ks);
FREE(cpu_stat);
kstat_close(kctl);
return TRUE;
error2:
old_total=0;
FREE(cpu_ks);
FREE(cpu_stat);
error:
kstat_close(kctl);
return FALSE;
}