2006-07-16 01:46:36 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
|
|
|
|
* This file is part of SIGAR.
|
|
|
|
*
|
|
|
|
* SIGAR is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms version 2 of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation. 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
|
|
* USA.
|
|
|
|
*/
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
#include <dirent.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/stat.h>
|
2004-11-17 13:50:18 +08:00
|
|
|
#include <sys/times.h>
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
#include "sigar.h"
|
|
|
|
#include "sigar_private.h"
|
|
|
|
#include "sigar_util.h"
|
2004-12-06 06:31:26 +08:00
|
|
|
#include "sigar_os.h"
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2007-04-21 23:30:14 +08:00
|
|
|
#define pageshift(x) ((x) << sigar->pagesize)
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
#define PROC_MEMINFO PROC_FS_ROOT "meminfo"
|
2007-07-21 02:22:20 +08:00
|
|
|
#define PROC_VMSTAT PROC_FS_ROOT "vmstat"
|
2006-06-13 23:38:43 +08:00
|
|
|
#define PROC_MTRR PROC_FS_ROOT "mtrr"
|
2004-06-22 06:37:04 +08:00
|
|
|
#define PROC_STAT PROC_FS_ROOT "stat"
|
|
|
|
#define PROC_UPTIME PROC_FS_ROOT "uptime"
|
|
|
|
#define PROC_LOADAVG PROC_FS_ROOT "loadavg"
|
|
|
|
|
|
|
|
#define PROC_PSTAT "/stat"
|
|
|
|
#define PROC_PSTATUS "/status"
|
|
|
|
|
2004-12-05 15:10:18 +08:00
|
|
|
#define SYS_BLOCK "/sys/block"
|
2005-10-01 07:05:14 +08:00
|
|
|
#define PROC_PARTITIONS PROC_FS_ROOT "partitions"
|
|
|
|
#define PROC_DISKSTATS PROC_FS_ROOT "diskstats"
|
2004-12-05 15:10:18 +08:00
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
/*
|
|
|
|
* /proc/self/stat fields:
|
|
|
|
* 1 - pid
|
|
|
|
* 2 - comm
|
|
|
|
* 3 - state
|
|
|
|
* 4 - ppid
|
|
|
|
* 5 - pgrp
|
|
|
|
* 6 - session
|
|
|
|
* 7 - tty_nr
|
|
|
|
* 8 - tpgid
|
|
|
|
* 9 - flags
|
|
|
|
* 10 - minflt
|
|
|
|
* 11 - cminflt
|
|
|
|
* 12 - majflt
|
|
|
|
* 13 - cmajflt
|
|
|
|
* 14 - utime
|
2005-11-29 02:24:11 +08:00
|
|
|
* 15 - stime
|
|
|
|
* 16 - cutime
|
|
|
|
* 17 - cstime
|
|
|
|
* 18 - priority
|
|
|
|
* 19 - nice
|
|
|
|
* 20 - 0 (removed field)
|
|
|
|
* 21 - itrealvalue
|
|
|
|
* 22 - starttime
|
|
|
|
* 23 - vsize
|
|
|
|
* 24 - rss
|
|
|
|
* 25 - rlim
|
|
|
|
* 26 - startcode
|
|
|
|
* 27 - endcode
|
|
|
|
* 28 - startstack
|
|
|
|
* 29 - kstkesp
|
|
|
|
* 30 - kstkeip
|
|
|
|
* 31 - signal
|
|
|
|
* 32 - blocked
|
|
|
|
* 33 - sigignore
|
|
|
|
* 34 - sigcache
|
|
|
|
* 35 - wchan
|
|
|
|
* 36 - nswap
|
|
|
|
* 37 - cnswap
|
|
|
|
* 38 - exit_signal <-- looking for this.
|
|
|
|
* 39 - processor
|
2004-06-22 06:37:04 +08:00
|
|
|
* ... more for newer RH
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define PROC_SIGNAL_IX 38
|
|
|
|
|
|
|
|
static int get_proc_signal_offset(void)
|
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr=buffer;
|
|
|
|
int fields = 0;
|
|
|
|
int status = sigar_file2str("/proc/self/stat",
|
|
|
|
buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*ptr) {
|
|
|
|
if (*ptr++ == ' ') {
|
|
|
|
fields++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (fields - PROC_SIGNAL_IX) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sigar_pid_t sigar_pid_get(sigar_t *sigar)
|
|
|
|
{
|
|
|
|
/* XXX cannot safely cache getpid unless using nptl */
|
|
|
|
/* we can however, cache it for optimizations in the
|
|
|
|
* case of proc_env_get for example.
|
|
|
|
*/
|
|
|
|
sigar->pid = getpid();
|
|
|
|
return sigar->pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_os_open(sigar_t **sigar)
|
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr;
|
2007-04-21 23:30:14 +08:00
|
|
|
int i;
|
2004-06-22 06:37:04 +08:00
|
|
|
int status = sigar_file2str(PROC_STAT, buffer, sizeof(buffer));
|
2004-12-05 15:10:18 +08:00
|
|
|
struct stat sb;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
*sigar = malloc(sizeof(**sigar));
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2007-04-21 23:30:14 +08:00
|
|
|
(*sigar)->pagesize = 0;
|
2007-04-21 23:33:03 +08:00
|
|
|
i = getpagesize();
|
2007-04-21 23:30:14 +08:00
|
|
|
while ((i >>= 1) > 0) {
|
|
|
|
(*sigar)->pagesize++;
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
ptr = strstr(buffer, "\nbtime");
|
|
|
|
ptr = sigar_skip_token(ptr);
|
|
|
|
(*sigar)->boot_time = sigar_strtoul(ptr);
|
|
|
|
|
2004-11-15 08:56:34 +08:00
|
|
|
(*sigar)->ticks = sysconf(_SC_CLK_TCK);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
(*sigar)->ram = -1;
|
|
|
|
|
|
|
|
(*sigar)->proc_signal_offset = -1;
|
|
|
|
|
|
|
|
(*sigar)->last_proc_stat.pid = -1;
|
|
|
|
|
2004-06-23 04:52:04 +08:00
|
|
|
(*sigar)->ht_enabled = -1;
|
|
|
|
|
2005-05-07 07:47:22 +08:00
|
|
|
if (stat(PROC_DISKSTATS, &sb) == 0) {
|
|
|
|
(*sigar)->iostat = IOSTAT_DISKSTATS;
|
|
|
|
}
|
|
|
|
else if (stat(SYS_BLOCK, &sb) == 0) {
|
2004-12-05 15:10:18 +08:00
|
|
|
(*sigar)->iostat = IOSTAT_SYS;
|
|
|
|
}
|
2004-12-06 04:34:51 +08:00
|
|
|
else if (stat(PROC_PARTITIONS, &sb) == 0) {
|
|
|
|
/* XXX file exists does not mean is has the fields */
|
|
|
|
(*sigar)->iostat = IOSTAT_PARTITIONS;
|
|
|
|
}
|
2004-12-05 15:10:18 +08:00
|
|
|
else {
|
|
|
|
(*sigar)->iostat = IOSTAT_NONE;
|
|
|
|
}
|
|
|
|
|
2004-12-06 06:31:26 +08:00
|
|
|
(*sigar)->fsdev = NULL;
|
|
|
|
|
2007-04-05 10:26:00 +08:00
|
|
|
/* hook for using mirrored /proc/net/tcp file */
|
|
|
|
(*sigar)->proc_net = getenv("SIGAR_PROC_NET");
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_os_close(sigar_t *sigar)
|
|
|
|
{
|
2004-12-06 06:31:26 +08:00
|
|
|
if (sigar->fsdev) {
|
|
|
|
sigar_cache_destroy(sigar->fsdev);
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
free(sigar);
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-03-12 14:19:34 +08:00
|
|
|
char *sigar_os_error_string(sigar_t *sigar, int err)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-02-24 07:23:27 +08:00
|
|
|
#define INTEL_ID 0x756e6547
|
2007-06-29 02:25:50 +08:00
|
|
|
#define AMD_ID 0x68747541
|
|
|
|
|
|
|
|
#if defined(__i386__)
|
|
|
|
#define SIGAR_HAS_CPUID
|
|
|
|
static void sigar_cpuid(sigar_uint32_t request,
|
|
|
|
sigar_uint32_t *eax,
|
|
|
|
sigar_uint32_t *ebx,
|
|
|
|
sigar_uint32_t *ecx,
|
|
|
|
sigar_uint32_t *edx)
|
2006-02-24 07:23:27 +08:00
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
/* does not compile w/ -fPIC */
|
|
|
|
/* can't find a register in class `BREG' while reloading `asm' */
|
|
|
|
asm volatile ("cpuid" :
|
|
|
|
"=a" (*eax),
|
|
|
|
"=b" (*ebx),
|
|
|
|
"=c" (*ecx),
|
|
|
|
"=d" (*edx)
|
|
|
|
: "a" (request));
|
|
|
|
#else
|
|
|
|
/* derived from: */
|
|
|
|
/* http://svn.red-bean.com/repos/minor/trunk/gc/barriers-ia-32.c */
|
|
|
|
asm volatile ("mov %%ebx, %%esi\n\t"
|
|
|
|
"cpuid\n\t"
|
|
|
|
"xchgl %%ebx, %%esi"
|
|
|
|
: "=a" (*eax),
|
|
|
|
"=S" (*ebx),
|
|
|
|
"=c" (*ecx),
|
|
|
|
"=d" (*edx)
|
|
|
|
: "0" (request)
|
|
|
|
: "memory");
|
|
|
|
#endif
|
|
|
|
}
|
2007-06-29 02:25:50 +08:00
|
|
|
#elif defined(__amd64__)
|
|
|
|
#define SIGAR_HAS_CPUID
|
|
|
|
static void sigar_cpuid(unsigned int request,
|
|
|
|
unsigned int *eax,
|
|
|
|
unsigned int *ebx,
|
|
|
|
unsigned int *ecx,
|
|
|
|
unsigned int *edx)
|
|
|
|
{
|
|
|
|
/* http://svn.red-bean.com/repos/minor/trunk/gc/barriers-amd64.c */
|
|
|
|
asm volatile ("cpuid\n\t"
|
|
|
|
: "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
|
|
|
|
: "0" (request)
|
|
|
|
: "memory");
|
|
|
|
}
|
|
|
|
#endif
|
2006-02-24 07:23:27 +08:00
|
|
|
|
2007-06-29 02:25:50 +08:00
|
|
|
#ifdef SIGAR_HAS_CPUID
|
2004-06-23 04:52:04 +08:00
|
|
|
static int is_ht_enabled(sigar_t *sigar)
|
|
|
|
{
|
2007-06-29 02:25:50 +08:00
|
|
|
sigar_uint32_t eax, ebx, ecx, edx;
|
2006-02-24 07:23:27 +08:00
|
|
|
|
|
|
|
if (sigar->ht_enabled != -1) {
|
2004-06-23 04:52:04 +08:00
|
|
|
/* only check once */
|
2006-02-24 07:23:27 +08:00
|
|
|
return sigar->ht_enabled;
|
|
|
|
}
|
2004-06-23 04:52:04 +08:00
|
|
|
|
2006-02-24 07:23:27 +08:00
|
|
|
sigar->ht_enabled = 0;
|
|
|
|
sigar->lcpu = 0;
|
|
|
|
|
|
|
|
sigar_cpuid(0, &eax, &ebx, &ecx, &edx);
|
|
|
|
|
2007-06-29 02:25:50 +08:00
|
|
|
if ((ebx == INTEL_ID) || (ebx == AMD_ID)) {
|
2006-02-24 07:23:27 +08:00
|
|
|
sigar_cpuid(1, &eax, &ebx, &ecx, &edx);
|
2004-06-23 04:52:04 +08:00
|
|
|
|
2006-02-24 07:23:27 +08:00
|
|
|
if (edx & (1<<28)) {
|
2006-03-22 10:46:11 +08:00
|
|
|
#ifdef DETECT_HT_ENABLED
|
2007-06-29 02:25:50 +08:00
|
|
|
sigar_uint32_t apic_id =
|
2006-03-03 10:01:19 +08:00
|
|
|
(ebx & 0xFF000000) >> 24;
|
2007-06-29 02:25:50 +08:00
|
|
|
sigar_uint32_t log_id, phy_id_mask=0xFF, i=1;
|
2006-03-22 10:46:11 +08:00
|
|
|
#endif
|
2006-02-24 07:23:27 +08:00
|
|
|
sigar->lcpu = (ebx & 0x00FF0000) >> 16;
|
2006-03-22 10:46:11 +08:00
|
|
|
#ifdef DETECT_HT_ENABLED
|
|
|
|
/* XXX disabled. process affinity mask can throw this off? */
|
2006-03-03 10:01:19 +08:00
|
|
|
while (i < sigar->lcpu) {
|
|
|
|
i *= 2;
|
|
|
|
phy_id_mask <<= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_id = apic_id & ~phy_id_mask;
|
|
|
|
|
|
|
|
if (log_id == 0) {
|
|
|
|
sigar->lcpu = 1;
|
|
|
|
}
|
2006-03-22 10:46:11 +08:00
|
|
|
#endif
|
2006-02-24 07:23:27 +08:00
|
|
|
if (sigar->lcpu > 1) {
|
|
|
|
sigar->ht_enabled = 1;
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[cpu] HT enabled, siblings: %d",
|
|
|
|
sigar->lcpu);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sigar_log(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[cpu] HT supported, not enabled.");
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 11:12:59 +08:00
|
|
|
else {
|
|
|
|
sigar_log(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[cpu] HT not supported.");
|
|
|
|
}
|
2006-02-24 07:23:27 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
sigar->lcpu = 1;
|
2004-06-23 04:52:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return sigar->ht_enabled;
|
|
|
|
}
|
2006-07-12 00:32:05 +08:00
|
|
|
#else
|
|
|
|
#define is_ht_enabled(sigar) 0
|
|
|
|
#endif
|
2004-06-23 04:52:04 +08:00
|
|
|
|
2006-06-13 23:38:43 +08:00
|
|
|
static int get_ram(sigar_t *sigar, sigar_mem_t *mem)
|
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr;
|
|
|
|
FILE *fp;
|
|
|
|
int total = 0;
|
2006-06-14 01:59:58 +08:00
|
|
|
sigar_uint64_t sys_total = (mem->total / (1024 * 1024));
|
2006-06-13 23:38:43 +08:00
|
|
|
|
|
|
|
if (sigar->ram > 0) {
|
|
|
|
/* return cached value */
|
|
|
|
mem->ram = sigar->ram;
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sigar->ram == 0) {
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Memory Type Range Registers
|
|
|
|
* write-back registers add up to the total.
|
|
|
|
* Well, they are supposed to add up, but seen
|
|
|
|
* at least one configuration where that is not the
|
|
|
|
* case.
|
|
|
|
*/
|
|
|
|
if (!(fp = fopen(PROC_MTRR, "r"))) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
|
|
|
|
if (!(ptr = strstr(ptr, "size="))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strstr(ptr, "write-back")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr += 5;
|
|
|
|
while (sigar_isspace(*ptr)) {
|
|
|
|
++ptr;
|
|
|
|
}
|
|
|
|
|
2006-06-14 01:59:58 +08:00
|
|
|
total += atoi(ptr);
|
2006-06-13 23:38:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
2006-06-14 01:59:58 +08:00
|
|
|
if ((total - sys_total) > 256) {
|
|
|
|
/* mtrr write-back registers are way off
|
|
|
|
* kernel should not be using more that 256MB of mem
|
|
|
|
*/
|
|
|
|
total = 0; /* punt */
|
|
|
|
}
|
|
|
|
|
2006-06-13 23:38:43 +08:00
|
|
|
if (total == 0) {
|
|
|
|
return ENOENT;
|
|
|
|
}
|
2006-06-14 01:59:58 +08:00
|
|
|
|
2006-06-13 23:38:43 +08:00
|
|
|
mem->ram = sigar->ram = total;
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2004-10-06 04:44:33 +08:00
|
|
|
#define MEMINFO_PARAM(a) a ":", SSTRLEN(a ":")
|
|
|
|
|
|
|
|
static SIGAR_INLINE sigar_uint64_t sigar_meminfo(char *buffer,
|
|
|
|
char *attr, int len)
|
|
|
|
{
|
|
|
|
sigar_uint64_t val = 0;
|
|
|
|
char *ptr, *tok;
|
|
|
|
|
|
|
|
if ((ptr = strstr(buffer, attr))) {
|
|
|
|
ptr += len;
|
|
|
|
val = strtoull(ptr, &tok, 0);
|
|
|
|
while (*tok == ' ') {
|
|
|
|
++tok;
|
|
|
|
}
|
|
|
|
if (*tok == 'k') {
|
|
|
|
val *= 1024;
|
|
|
|
}
|
|
|
|
else if (*tok == 'M') {
|
|
|
|
val *= (1024 * 1024);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
|
|
|
|
{
|
2004-11-20 10:23:57 +08:00
|
|
|
sigar_uint64_t buffers, cached, kern;
|
2004-06-22 06:37:04 +08:00
|
|
|
char buffer[BUFSIZ];
|
|
|
|
|
|
|
|
int status = sigar_file2str(PROC_MEMINFO,
|
|
|
|
buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2004-10-06 04:44:33 +08:00
|
|
|
mem->total = sigar_meminfo(buffer, MEMINFO_PARAM("MemTotal"));
|
|
|
|
mem->free = sigar_meminfo(buffer, MEMINFO_PARAM("MemFree"));
|
|
|
|
mem->used = mem->total - mem->free;
|
2004-11-20 10:08:16 +08:00
|
|
|
|
2004-11-20 10:23:57 +08:00
|
|
|
buffers = sigar_meminfo(buffer, MEMINFO_PARAM("Buffers"));
|
|
|
|
cached = sigar_meminfo(buffer, MEMINFO_PARAM("Cached"));
|
2004-11-20 10:08:16 +08:00
|
|
|
|
2004-11-20 10:23:57 +08:00
|
|
|
kern = buffers + cached;
|
|
|
|
mem->actual_free = mem->free + kern;
|
|
|
|
mem->actual_used = mem->used - kern;
|
2004-11-20 10:08:16 +08:00
|
|
|
|
2006-06-13 23:38:43 +08:00
|
|
|
if (get_ram(sigar, mem) != SIGAR_OK) {
|
|
|
|
/* XXX other options on failure? */
|
|
|
|
sigar_mem_calc_ram(sigar, mem);
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
|
|
|
|
{
|
2007-07-21 02:22:20 +08:00
|
|
|
char buffer[BUFSIZ], *ptr;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
/* XXX: we open/parse the same file here as sigar_mem_get */
|
|
|
|
int status = sigar_file2str(PROC_MEMINFO,
|
|
|
|
buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2004-10-06 04:46:57 +08:00
|
|
|
swap->total = sigar_meminfo(buffer, MEMINFO_PARAM("SwapTotal"));
|
|
|
|
swap->free = sigar_meminfo(buffer, MEMINFO_PARAM("SwapFree"));
|
|
|
|
swap->used = swap->total - swap->free;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2007-07-21 02:02:21 +08:00
|
|
|
swap->page_in = swap->page_out = -1;
|
|
|
|
|
2007-07-21 02:22:20 +08:00
|
|
|
status = sigar_file2str(PROC_VMSTAT,
|
|
|
|
buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
if (status == SIGAR_OK) {
|
|
|
|
/* 2.6+ kernel */
|
|
|
|
if ((ptr = strstr(buffer, "\npswpin"))) {
|
|
|
|
ptr = sigar_skip_token(ptr);
|
|
|
|
swap->page_in = sigar_strtoull(ptr);
|
|
|
|
ptr = sigar_skip_token(ptr);
|
|
|
|
swap->page_out = sigar_strtoull(ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* 2.2, 2.4 kernels */
|
|
|
|
status = sigar_file2str(PROC_STAT,
|
|
|
|
buffer, sizeof(buffer));
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ptr = strstr(buffer, "\nswap"))) {
|
|
|
|
ptr = sigar_skip_token(ptr);
|
|
|
|
swap->page_in = sigar_strtoull(ptr);
|
|
|
|
swap->page_out = sigar_strtoull(ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-05-12 07:17:39 +08:00
|
|
|
static void get_cpu_metrics(sigar_t *sigar, sigar_cpu_t *cpu, char *line)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
|
|
|
char *ptr = sigar_skip_token(line); /* "cpu%d" */
|
|
|
|
|
2006-12-05 02:22:51 +08:00
|
|
|
cpu->user += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
|
|
|
|
cpu->nice += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
|
|
|
|
cpu->sys += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
|
|
|
|
cpu->idle += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
|
2004-11-22 09:58:07 +08:00
|
|
|
if (*ptr == ' ') {
|
|
|
|
/* 2.6+ kernels only */
|
2006-12-05 02:22:51 +08:00
|
|
|
cpu->wait += SIGAR_TICK2MSEC(sigar_strtoull(ptr));
|
2004-11-22 09:58:07 +08:00
|
|
|
}
|
2006-09-07 22:10:24 +08:00
|
|
|
cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->wait;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
|
|
|
|
{
|
|
|
|
char buffer[BUFSIZ];
|
|
|
|
int status = sigar_file2str(PROC_STAT, buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2004-06-23 04:52:04 +08:00
|
|
|
SIGAR_ZERO(cpu);
|
2005-05-12 07:17:39 +08:00
|
|
|
get_cpu_metrics(sigar, cpu, buffer);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
2004-07-02 05:57:26 +08:00
|
|
|
char buffer[BUFSIZ], cpu_total[BUFSIZ], *ptr;
|
2004-06-23 04:52:04 +08:00
|
|
|
int hthread = is_ht_enabled(sigar), i=0;
|
2004-07-02 05:57:26 +08:00
|
|
|
sigar_cpu_t *cpu;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (!(fp = fopen(PROC_STAT, "r"))) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* skip first line */
|
2004-07-02 05:57:26 +08:00
|
|
|
(void)fgets(cpu_total, sizeof(cpu_total), fp);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
sigar_cpu_list_create(cpulist);
|
|
|
|
|
|
|
|
/* XXX: merge times of logical processors if hyperthreading */
|
|
|
|
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
|
|
|
|
if (!strnEQ(ptr, "cpu", 3)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2004-06-23 04:52:04 +08:00
|
|
|
if (hthread && (i % sigar->lcpu)) {
|
|
|
|
/* merge times of logical processors */
|
|
|
|
cpu = &cpulist->data[cpulist->number-1];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SIGAR_CPU_LIST_GROW(cpulist);
|
|
|
|
cpu = &cpulist->data[cpulist->number++];
|
|
|
|
SIGAR_ZERO(cpu);
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-05-12 07:17:39 +08:00
|
|
|
get_cpu_metrics(sigar, cpu, ptr);
|
2004-06-23 04:52:04 +08:00
|
|
|
|
|
|
|
i++;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
2004-07-02 05:57:26 +08:00
|
|
|
if (cpulist->number == 0) {
|
|
|
|
/* likely older kernel where cpu\d is not present */
|
|
|
|
cpu = &cpulist->data[cpulist->number++];
|
|
|
|
SIGAR_ZERO(cpu);
|
2005-05-12 07:17:39 +08:00
|
|
|
get_cpu_metrics(sigar, cpu, cpu_total);
|
2004-07-02 05:57:26 +08:00
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_uptime_get(sigar_t *sigar,
|
|
|
|
sigar_uptime_t *uptime)
|
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr = buffer;
|
|
|
|
int status = sigar_file2str(PROC_UPTIME, buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
uptime->uptime = strtod(buffer, &ptr);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_loadavg_get(sigar_t *sigar,
|
|
|
|
sigar_loadavg_t *loadavg)
|
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr = buffer;
|
|
|
|
int status = sigar_file2str(PROC_LOADAVG, buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
loadavg->loadavg[0] = strtod(buffer, &ptr);
|
|
|
|
loadavg->loadavg[1] = strtod(ptr, &ptr);
|
|
|
|
loadavg->loadavg[2] = strtod(ptr, &ptr);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* seems the easiest/fastest way to tell if a process listed in /proc
|
|
|
|
* is a thread is to check the "exit signal" flag in /proc/num/stat.
|
|
|
|
* any value other than SIGCHLD seems to be a thread. this make hulk mad.
|
|
|
|
* redhat's procps patch (named "threadbadhack.pat") does not use
|
|
|
|
* this flag to filter out threads. instead does much more expensive
|
|
|
|
* comparisions. their patch also bubbles up thread cpu times to the main
|
|
|
|
* process. functionality we currently lack.
|
|
|
|
* when nptl is in use, this is not the case and all threads spawned from
|
|
|
|
* a process have the same pid. however, it seems both old-style linux
|
|
|
|
* threads and nptl threads can be run on the same machine.
|
|
|
|
* there is also the "Tgid" field in /proc/self/status which could be used
|
|
|
|
* to detect threads, but this is not available in older kernels.
|
|
|
|
*/
|
|
|
|
static SIGAR_INLINE int proc_isthread(sigar_t *sigar, char *pidstr, int len)
|
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr=buffer;
|
|
|
|
int fd, n, offset=sigar->proc_signal_offset;
|
|
|
|
|
|
|
|
/* sprintf(buffer, "/proc/%s/stat", pidstr) */
|
2005-10-01 07:05:14 +08:00
|
|
|
memcpy(ptr, PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT));
|
|
|
|
ptr += SSTRLEN(PROCP_FS_ROOT);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
memcpy(ptr, pidstr, len);
|
|
|
|
ptr += len;
|
|
|
|
|
|
|
|
memcpy(ptr, PROC_PSTAT, SSTRLEN(PROC_PSTAT));
|
|
|
|
ptr += SSTRLEN(PROC_PSTAT);
|
|
|
|
|
|
|
|
*ptr = '\0';
|
|
|
|
|
|
|
|
if ((fd = open(buffer, O_RDONLY)) < 0) {
|
|
|
|
/* unlikely if pid was from readdir proc */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = read(fd, buffer, sizeof(buffer));
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (n < 0) {
|
|
|
|
return 0; /* chances: slim..none */
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer[n--] = '\0';
|
|
|
|
|
|
|
|
/* exit_signal is the second to last field so we look backwards.
|
|
|
|
* XXX if newer kernels drop more turds in this file we'll need
|
|
|
|
* to go the other way. luckily linux has no real api for this shit.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* skip trailing crap */
|
|
|
|
while ((n > 0) && !isdigit(buffer[n--])) ;
|
|
|
|
|
|
|
|
while (offset-- > 0) {
|
|
|
|
/* skip last field */
|
|
|
|
while ((n > 0) && isdigit(buffer[n--])) ;
|
|
|
|
|
|
|
|
/* skip whitespace */
|
|
|
|
while ((n > 0) && !isdigit(buffer[n--])) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n < 3) {
|
|
|
|
return 0; /* hulk smashed /proc? */
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = &buffer[n];
|
|
|
|
/*
|
|
|
|
* '17' == SIGCHLD == real process.
|
|
|
|
* '33' and '0' are threads
|
|
|
|
*/
|
|
|
|
if ((*ptr++ == '1') &&
|
|
|
|
(*ptr++ == '7') &&
|
|
|
|
(*ptr++ == ' '))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-04-22 11:54:04 +08:00
|
|
|
int sigar_os_proc_list_get(sigar_t *sigar,
|
|
|
|
sigar_proc_list_t *proclist)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
2005-10-01 07:05:14 +08:00
|
|
|
DIR *dirp = opendir(PROCP_FS_ROOT);
|
2004-06-22 06:37:04 +08:00
|
|
|
struct dirent *ent, dbuf;
|
|
|
|
|
|
|
|
if (!dirp) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sigar->proc_signal_offset == -1) {
|
|
|
|
sigar->proc_signal_offset = get_proc_signal_offset();
|
|
|
|
}
|
|
|
|
|
|
|
|
while (readdir_r(dirp, &dbuf, &ent) == 0) {
|
|
|
|
if (!ent) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sigar_isdigit(*ent->d_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (proc_isthread(sigar, ent->d_name, strlen(ent->d_name)))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: more sanity checking */
|
|
|
|
|
|
|
|
SIGAR_PROC_LIST_GROW(proclist);
|
|
|
|
|
|
|
|
proclist->data[proclist->number++] =
|
|
|
|
strtoul(ent->d_name, NULL, 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dirp);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int proc_stat_read(sigar_t *sigar, sigar_pid_t pid)
|
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr=buffer, *tmp;
|
|
|
|
unsigned int len;
|
|
|
|
linux_proc_stat_t *pstat = &sigar->last_proc_stat;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
time_t timenow = time(NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* short-lived cache read/parse of last /proc/pid/stat
|
|
|
|
* as this info is spread out across a few functions.
|
|
|
|
*/
|
|
|
|
if (pstat->pid == pid) {
|
|
|
|
if ((timenow - pstat->mtime) < SIGAR_LAST_PROC_EXPIRE) {
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pstat->pid = pid;
|
|
|
|
pstat->mtime = timenow;
|
|
|
|
|
|
|
|
status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTAT);
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = strchr(ptr, '(')+1;
|
|
|
|
|
|
|
|
tmp = strrchr(ptr, ')');
|
|
|
|
len = tmp-ptr;
|
|
|
|
|
|
|
|
if (len >= sizeof(pstat->name)) {
|
|
|
|
len = sizeof(pstat->name)-1;
|
|
|
|
}
|
|
|
|
|
2005-11-29 02:24:11 +08:00
|
|
|
/* (1,2) */
|
2004-06-22 06:37:04 +08:00
|
|
|
memcpy(pstat->name, ptr, len);
|
|
|
|
pstat->name[len] = '\0';
|
|
|
|
ptr = tmp+1;
|
|
|
|
|
|
|
|
SIGAR_SKIP_SPACE(ptr);
|
2005-11-29 02:24:11 +08:00
|
|
|
pstat->state = *ptr++; /* (3) */
|
2004-06-22 06:37:04 +08:00
|
|
|
SIGAR_SKIP_SPACE(ptr);
|
|
|
|
|
2005-11-29 02:24:11 +08:00
|
|
|
pstat->ppid = sigar_strtoul(ptr); /* (4) */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (5) pgrp */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (6) session */
|
|
|
|
pstat->tty = sigar_strtoul(ptr); /* (7) */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (8) tty pgrp */
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-11-29 02:24:11 +08:00
|
|
|
ptr = sigar_skip_token(ptr); /* (9) flags */
|
2006-10-11 11:17:34 +08:00
|
|
|
pstat->minor_faults = sigar_strtoull(ptr); /* (10) */
|
2005-11-29 02:24:11 +08:00
|
|
|
ptr = sigar_skip_token(ptr); /* (11) cmin flt */
|
2006-10-11 11:17:34 +08:00
|
|
|
pstat->major_faults = sigar_strtoull(ptr); /* (12) */
|
2005-11-29 02:24:11 +08:00
|
|
|
ptr = sigar_skip_token(ptr); /* (13) cmaj flt */
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-12-04 11:42:27 +08:00
|
|
|
pstat->utime = SIGAR_TICK2MSEC(sigar_strtoull(ptr)); /* (14) */
|
|
|
|
pstat->stime = SIGAR_TICK2MSEC(sigar_strtoull(ptr)); /* (15) */
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-11-29 02:24:11 +08:00
|
|
|
ptr = sigar_skip_token(ptr); /* (16) cutime */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (17) cstime */
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-11-29 02:24:11 +08:00
|
|
|
pstat->priority = sigar_strtoul(ptr); /* (18) */
|
|
|
|
pstat->nice = sigar_strtoul(ptr); /* (19) */
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-11-29 02:24:11 +08:00
|
|
|
ptr = sigar_skip_token(ptr); /* (20) timeout */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (21) it_real_value */
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-11-29 02:24:11 +08:00
|
|
|
pstat->start_time = sigar_strtoul(ptr); /* (22) */
|
2004-06-22 06:37:04 +08:00
|
|
|
pstat->start_time /= sigar->ticks;
|
|
|
|
pstat->start_time += sigar->boot_time; /* seconds */
|
|
|
|
pstat->start_time *= 1000; /* milliseconds */
|
|
|
|
|
2006-10-11 11:17:34 +08:00
|
|
|
pstat->vsize = sigar_strtoull(ptr); /* (23) */
|
|
|
|
pstat->rss = pageshift(sigar_strtoull(ptr)); /* (24) */
|
2005-11-29 02:24:11 +08:00
|
|
|
|
|
|
|
ptr = sigar_skip_token(ptr); /* (25) rlim */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (26) startcode */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (27) endcode */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (28) startstack */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (29) kstkesp */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (30) kstkeip */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (31) signal */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (32) blocked */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (33) sigignore */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (34) sigcache */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (35) wchan */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (36) nswap */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (37) cnswap */
|
|
|
|
ptr = sigar_skip_token(ptr); /* (38) exit_signal */
|
|
|
|
|
|
|
|
pstat->processor = sigar_strtoul(ptr); /* (39) */
|
2005-11-23 11:09:59 +08:00
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_mem_t *procmem)
|
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr=buffer;
|
|
|
|
int status = proc_stat_read(sigar, pid);
|
|
|
|
linux_proc_stat_t *pstat = &sigar->last_proc_stat;
|
|
|
|
|
2005-11-24 01:39:28 +08:00
|
|
|
procmem->minor_faults = pstat->minor_faults;
|
|
|
|
procmem->major_faults = pstat->major_faults;
|
|
|
|
procmem->page_faults =
|
|
|
|
procmem->minor_faults + procmem->major_faults;
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
status = SIGAR_PROC_FILE2STR(buffer, pid, "/statm");
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2006-10-11 11:17:34 +08:00
|
|
|
procmem->size = pageshift(sigar_strtoull(ptr));
|
|
|
|
procmem->resident = pageshift(sigar_strtoull(ptr));
|
|
|
|
procmem->share = pageshift(sigar_strtoull(ptr));
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-21 04:29:44 +08:00
|
|
|
#define NO_ID_MSG "[proc_cred] /proc/%lu" PROC_PSTATUS " missing "
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_cred_t *proccred)
|
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr;
|
|
|
|
int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS);
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2007-07-21 04:29:44 +08:00
|
|
|
if ((ptr = strstr(buffer, "\nUid:"))) {
|
|
|
|
ptr = sigar_skip_token(ptr);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2007-07-21 04:29:44 +08:00
|
|
|
proccred->uid = sigar_strtoul(ptr);
|
|
|
|
proccred->euid = sigar_strtoul(ptr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_WARN,
|
|
|
|
NO_ID_MSG "Uid", pid);
|
|
|
|
return ENOENT;
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2007-07-21 04:29:44 +08:00
|
|
|
if ((ptr = strstr(ptr, "\nGid:"))) {
|
|
|
|
ptr = sigar_skip_token(ptr);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2007-07-21 04:29:44 +08:00
|
|
|
proccred->gid = sigar_strtoul(ptr);
|
|
|
|
proccred->egid = sigar_strtoul(ptr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_WARN,
|
|
|
|
NO_ID_MSG "Gid", pid);
|
|
|
|
return ENOENT;
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_time_t *proctime)
|
|
|
|
{
|
|
|
|
int status = proc_stat_read(sigar, pid);
|
|
|
|
linux_proc_stat_t *pstat = &sigar->last_proc_stat;
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2004-08-21 08:13:13 +08:00
|
|
|
proctime->user = pstat->utime;
|
|
|
|
proctime->sys = pstat->stime;
|
2004-08-21 08:25:07 +08:00
|
|
|
proctime->total = proctime->user + proctime->sys;
|
2004-06-22 06:37:04 +08:00
|
|
|
proctime->start_time = pstat->start_time;
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-11-23 05:45:45 +08:00
|
|
|
static int proc_status_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_state_t *procstate)
|
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr;
|
|
|
|
int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS);
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = strstr(buffer, "\nThreads:");
|
|
|
|
if (ptr) {
|
|
|
|
/* 2.6+ kernel only */
|
|
|
|
ptr = sigar_skip_token(ptr);
|
|
|
|
procstate->threads = sigar_strtoul(ptr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
procstate->threads = SIGAR_FIELD_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_state_t *procstate)
|
|
|
|
{
|
|
|
|
int status = proc_stat_read(sigar, pid);
|
|
|
|
linux_proc_stat_t *pstat = &sigar->last_proc_stat;
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(procstate->name, pstat->name, sizeof(procstate->name));
|
|
|
|
procstate->state = pstat->state;
|
|
|
|
|
|
|
|
procstate->ppid = pstat->ppid;
|
|
|
|
procstate->tty = pstat->tty;
|
|
|
|
procstate->priority = pstat->priority;
|
|
|
|
procstate->nice = pstat->nice;
|
2005-11-23 11:09:59 +08:00
|
|
|
procstate->processor = pstat->processor;
|
|
|
|
|
|
|
|
if (is_ht_enabled(sigar)) {
|
|
|
|
procstate->processor /= sigar->lcpu;
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-11-23 05:45:45 +08:00
|
|
|
proc_status_get(sigar, pid, procstate);
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2007-04-22 13:37:39 +08:00
|
|
|
int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_args_t *procargs)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
2005-02-09 15:29:31 +08:00
|
|
|
return sigar_procfs_args_get(sigar, pid, procargs);
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_env_t *procenv)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
char buffer[ARG_MAX]; /* XXX: ARG_MAX == 130k */
|
|
|
|
char name[BUFSIZ];
|
|
|
|
size_t len;
|
|
|
|
char *ptr, *end;
|
|
|
|
|
|
|
|
/* optimize if pid == $$ and type == ENV_KEY */
|
|
|
|
SIGAR_PROC_ENV_KEY_LOOKUP();
|
|
|
|
|
|
|
|
(void)SIGAR_PROC_FILENAME(name, pid, "/environ");
|
|
|
|
|
|
|
|
if ((fd = open(name, O_RDONLY)) < 0) {
|
|
|
|
if (errno == ENOENT) {
|
|
|
|
return ESRCH;
|
|
|
|
}
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = read(fd, buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
buffer[len] = '\0';
|
|
|
|
ptr = buffer;
|
|
|
|
|
|
|
|
end = buffer + len;
|
|
|
|
while (ptr < end) {
|
|
|
|
char *val = strchr(ptr, '=');
|
|
|
|
int klen, vlen, status;
|
|
|
|
char key[128]; /* XXX is there a max key size? */
|
|
|
|
|
|
|
|
if (val == NULL) {
|
|
|
|
/* not key=val format */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
klen = val - ptr;
|
|
|
|
SIGAR_SSTRCPY(key, ptr);
|
|
|
|
key[klen] = '\0';
|
|
|
|
++val;
|
|
|
|
|
|
|
|
vlen = strlen(val);
|
|
|
|
status = procenv->env_getter(procenv->data,
|
|
|
|
key, klen, val, vlen);
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
/* not an error; just stop iterating */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr += (klen + 1 + vlen + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_fd_t *procfd)
|
|
|
|
{
|
|
|
|
int status =
|
|
|
|
sigar_proc_fd_count(sigar, pid, &procfd->total);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_exe_t *procexe)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
char name[BUFSIZ];
|
|
|
|
|
|
|
|
(void)SIGAR_PROC_FILENAME(name, pid, "/cwd");
|
|
|
|
|
|
|
|
if ((len = readlink(name, procexe->cwd,
|
|
|
|
sizeof(procexe->cwd)-1)) < 0)
|
|
|
|
{
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
procexe->cwd[len] = '\0';
|
|
|
|
|
|
|
|
(void)SIGAR_PROC_FILENAME(name, pid, "/exe");
|
|
|
|
|
|
|
|
if ((len = readlink(name, procexe->name,
|
|
|
|
sizeof(procexe->name)-1)) < 0)
|
|
|
|
{
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
procexe->name[len] = '\0';
|
|
|
|
|
|
|
|
(void)SIGAR_PROC_FILENAME(name, pid, "/root");
|
|
|
|
|
|
|
|
if ((len = readlink(name, procexe->root,
|
|
|
|
sizeof(procexe->root)-1)) < 0)
|
|
|
|
{
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
procexe->root[len] = '\0';
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2004-06-23 03:40:37 +08:00
|
|
|
int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_modules_t *procmods)
|
|
|
|
{
|
2004-06-29 10:23:58 +08:00
|
|
|
FILE *fp;
|
|
|
|
char buffer[BUFSIZ], *ptr;
|
|
|
|
unsigned long inode, last_inode = 0;
|
|
|
|
|
|
|
|
(void)SIGAR_PROC_FILENAME(buffer, pid, "/maps");
|
|
|
|
|
|
|
|
if (!(fp = fopen(buffer, "r"))) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
|
2004-07-01 08:41:03 +08:00
|
|
|
int len, status;
|
2004-06-29 10:23:58 +08:00
|
|
|
/* skip region, flags, offset, dev */
|
|
|
|
ptr = sigar_skip_multiple_token(ptr, 4);
|
|
|
|
inode = sigar_strtoul(ptr);
|
|
|
|
|
|
|
|
if ((inode == 0) || (inode == last_inode)) {
|
|
|
|
last_inode = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_inode = inode;
|
|
|
|
SIGAR_SKIP_SPACE(ptr);
|
|
|
|
len = strlen(ptr);
|
|
|
|
ptr[len-1] = '\0'; /* chop \n */
|
|
|
|
|
2004-07-01 08:41:03 +08:00
|
|
|
status =
|
2004-06-29 10:23:58 +08:00
|
|
|
procmods->module_getter(procmods->data,
|
|
|
|
ptr, len-1);
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
/* not an error; just stop iterating */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
2004-06-23 03:40:37 +08:00
|
|
|
}
|
|
|
|
|
2004-11-17 13:35:17 +08:00
|
|
|
int sigar_thread_cpu_get(sigar_t *sigar,
|
|
|
|
sigar_uint64_t id,
|
|
|
|
sigar_thread_cpu_t *cpu)
|
|
|
|
{
|
2004-11-17 13:50:18 +08:00
|
|
|
struct tms now;
|
|
|
|
|
|
|
|
if (id != 0) {
|
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
times(&now);
|
|
|
|
|
2006-12-05 02:45:01 +08:00
|
|
|
cpu->user = SIGAR_TICK2NSEC(now.tms_utime);
|
|
|
|
cpu->sys = SIGAR_TICK2NSEC(now.tms_stime);
|
|
|
|
cpu->total = SIGAR_TICK2NSEC(now.tms_utime + now.tms_stime);
|
2004-11-17 13:50:18 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
2004-11-17 13:35:17 +08:00
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
#include <mntent.h>
|
|
|
|
#include <sys/statfs.h>
|
|
|
|
|
|
|
|
int sigar_os_fs_type_get(sigar_file_system_t *fsp)
|
|
|
|
{
|
|
|
|
char *type = fsp->sys_type_name;
|
|
|
|
|
|
|
|
switch (*type) {
|
|
|
|
case 'e':
|
|
|
|
if (strnEQ(type, "ext", 3)) {
|
|
|
|
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
if (strEQ(type, "hpfs")) {
|
|
|
|
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
if (strEQ(type, "reiserfs")) {
|
|
|
|
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
if (strEQ(type, "xfs") || strEQ(type, "xiafs")) {
|
|
|
|
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fsp->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_file_system_list_get(sigar_t *sigar,
|
|
|
|
sigar_file_system_list_t *fslist)
|
|
|
|
{
|
|
|
|
struct mntent ent;
|
|
|
|
char buf[1025]; /* buffer for strings within ent */
|
|
|
|
FILE *fp;
|
|
|
|
sigar_file_system_t *fsp;
|
|
|
|
|
|
|
|
if (!(fp = setmntent(MOUNTED, "r"))) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
sigar_file_system_list_create(fslist);
|
|
|
|
|
|
|
|
while (getmntent_r(fp, &ent, buf, sizeof(buf))) {
|
|
|
|
SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
|
|
|
|
|
|
|
|
fsp = &fslist->data[fslist->number++];
|
|
|
|
|
2004-09-27 05:07:26 +08:00
|
|
|
fsp->type = SIGAR_FSTYPE_UNKNOWN; /* unknown, will be set later */
|
2004-06-22 06:37:04 +08:00
|
|
|
SIGAR_SSTRCPY(fsp->dir_name, ent.mnt_dir);
|
|
|
|
SIGAR_SSTRCPY(fsp->dev_name, ent.mnt_fsname);
|
|
|
|
SIGAR_SSTRCPY(fsp->sys_type_name, ent.mnt_type);
|
|
|
|
sigar_fs_type_get(fsp);
|
|
|
|
}
|
|
|
|
|
|
|
|
endmntent(fp);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2004-12-06 06:31:26 +08:00
|
|
|
#define FSDEV_NONE "__NONE__"
|
|
|
|
|
|
|
|
#define FSDEV_ID(sb) (sb.st_ino + sb.st_dev)
|
|
|
|
|
2007-02-22 10:28:21 +08:00
|
|
|
#define FSDEV_IS_DEV(dev) strnEQ(dev, "/dev/", 5)
|
|
|
|
|
|
|
|
#define ST_MAJOR(sb) major((sb).st_rdev)
|
|
|
|
#define ST_MINOR(sb) minor((sb).st_rdev)
|
|
|
|
|
2004-12-06 06:31:26 +08:00
|
|
|
static void fsdev_free(void *ptr)
|
|
|
|
{
|
|
|
|
if (ptr != FSDEV_NONE) {
|
|
|
|
free(ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-12-06 04:34:51 +08:00
|
|
|
static char *get_fsdev(sigar_t *sigar,
|
|
|
|
const char *dirname,
|
|
|
|
char *fsdev)
|
2004-12-05 15:10:18 +08:00
|
|
|
{
|
2004-12-06 06:31:26 +08:00
|
|
|
sigar_cache_entry_t *entry;
|
|
|
|
struct stat sb;
|
|
|
|
sigar_uint64_t id;
|
2006-06-22 00:54:16 +08:00
|
|
|
int debug = SIGAR_LOG_IS_DEBUG(sigar);
|
2004-12-05 15:10:18 +08:00
|
|
|
|
2004-12-06 06:31:26 +08:00
|
|
|
if (stat(dirname, &sb) < 0) {
|
2006-06-22 00:54:16 +08:00
|
|
|
if (debug) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[fsdev] stat(%s) failed",
|
|
|
|
dirname);
|
|
|
|
}
|
2004-12-06 04:34:51 +08:00
|
|
|
return NULL;
|
2004-12-05 15:10:18 +08:00
|
|
|
}
|
|
|
|
|
2004-12-06 06:31:26 +08:00
|
|
|
id = FSDEV_ID(sb);
|
|
|
|
|
|
|
|
if (!sigar->fsdev) {
|
|
|
|
sigar->fsdev = sigar_cache_new(15);
|
|
|
|
sigar->fsdev->free_value = fsdev_free;
|
2004-12-05 15:10:18 +08:00
|
|
|
}
|
|
|
|
|
2004-12-06 06:31:26 +08:00
|
|
|
entry = sigar_cache_get(sigar->fsdev, id);
|
2004-12-05 15:10:18 +08:00
|
|
|
|
2004-12-06 06:31:26 +08:00
|
|
|
if (entry->value == NULL) {
|
|
|
|
sigar_file_system_list_t fslist;
|
|
|
|
int status = sigar_file_system_list_get(sigar, &fslist);
|
|
|
|
int i;
|
2004-12-05 15:10:18 +08:00
|
|
|
|
2004-12-06 06:31:26 +08:00
|
|
|
if (status != SIGAR_OK) {
|
2006-06-22 00:54:16 +08:00
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[fsdev] file_system_list failed: %s",
|
|
|
|
sigar_strerror(sigar, status));
|
2004-12-06 06:31:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<fslist.number; i++) {
|
|
|
|
sigar_file_system_t *fsp = &fslist.data[i];
|
|
|
|
|
|
|
|
if (fsp->type == SIGAR_FSTYPE_LOCAL_DISK) {
|
|
|
|
int retval = stat(fsp->dir_name, &sb);
|
|
|
|
sigar_cache_entry_t *ent;
|
|
|
|
char *ptr;
|
2004-12-05 15:10:18 +08:00
|
|
|
|
2004-12-06 06:31:26 +08:00
|
|
|
if (retval < 0) {
|
2006-06-22 00:54:16 +08:00
|
|
|
if (debug) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[fsdev] inode stat(%s) failed",
|
|
|
|
fsp->dir_name);
|
|
|
|
}
|
2004-12-06 06:31:26 +08:00
|
|
|
return NULL; /* cant cache w/o inode */
|
|
|
|
}
|
2004-12-06 04:34:51 +08:00
|
|
|
|
2004-12-06 06:31:26 +08:00
|
|
|
ent = sigar_cache_get(sigar->fsdev, FSDEV_ID(sb));
|
|
|
|
if (ent->value) {
|
|
|
|
continue; /* already cached */
|
|
|
|
}
|
2004-12-06 04:34:51 +08:00
|
|
|
|
2004-12-06 06:31:26 +08:00
|
|
|
ptr = fsp->dev_name;
|
2007-02-22 10:28:21 +08:00
|
|
|
if (FSDEV_IS_DEV(ptr)) {
|
2005-11-10 02:26:10 +08:00
|
|
|
ent->value = sigar_strdup(ptr);
|
2006-06-22 00:54:16 +08:00
|
|
|
if (debug) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[fsdev] map %s -> %s",
|
|
|
|
fsp->dir_name, (char*)ent->value);
|
|
|
|
}
|
2004-12-06 06:31:26 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ent->value = FSDEV_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sigar_file_system_list_destroy(sigar, &fslist);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry->value == FSDEV_NONE) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (entry->value == NULL) {
|
|
|
|
entry->value = FSDEV_NONE;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
strcpy(fsdev, (char*)entry->value);
|
|
|
|
return fsdev;
|
|
|
|
}
|
2004-12-06 04:34:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int get_iostat_sys(sigar_t *sigar,
|
|
|
|
const char *dirname,
|
|
|
|
sigar_file_system_usage_t *fsusage)
|
|
|
|
{
|
|
|
|
char stat[1025], dev[1025];
|
|
|
|
char *name, *ptr, *fsdev;
|
|
|
|
int partition, status;
|
|
|
|
|
|
|
|
name = fsdev = get_fsdev(sigar, dirname, dev);
|
|
|
|
|
|
|
|
if (!name) {
|
|
|
|
return ENOENT;
|
|
|
|
}
|
2004-12-05 15:10:18 +08:00
|
|
|
|
2007-02-22 10:28:21 +08:00
|
|
|
if (FSDEV_IS_DEV(name)) {
|
|
|
|
name += 5; /* strip "/dev/" */
|
|
|
|
}
|
|
|
|
|
2004-12-05 15:10:18 +08:00
|
|
|
while (!sigar_isdigit(*fsdev)) {
|
|
|
|
fsdev++;
|
|
|
|
}
|
|
|
|
|
|
|
|
partition = strtoul(fsdev, NULL, 0);
|
|
|
|
*fsdev = '\0';
|
|
|
|
|
2006-10-01 01:48:33 +08:00
|
|
|
snprintf(stat, sizeof(stat),
|
|
|
|
SYS_BLOCK "/%s/%s%d/stat", name, name, partition);
|
2004-12-05 15:10:18 +08:00
|
|
|
|
2004-12-06 04:34:51 +08:00
|
|
|
status = sigar_file2str(stat, dev, sizeof(dev));
|
2004-12-05 15:10:18 +08:00
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2004-12-06 04:34:51 +08:00
|
|
|
ptr = dev;
|
2004-12-05 15:10:18 +08:00
|
|
|
ptr = sigar_skip_token(ptr);
|
2006-10-11 11:17:34 +08:00
|
|
|
fsusage->disk_reads = sigar_strtoull(ptr);
|
2004-12-05 15:10:18 +08:00
|
|
|
ptr = sigar_skip_token(ptr);
|
2006-10-11 11:17:34 +08:00
|
|
|
fsusage->disk_writes = sigar_strtoull(ptr);
|
2004-12-05 15:10:18 +08:00
|
|
|
|
2005-04-07 09:28:07 +08:00
|
|
|
fsusage->disk_read_bytes = SIGAR_FIELD_NOTIMPL;
|
|
|
|
fsusage->disk_write_bytes = SIGAR_FIELD_NOTIMPL;
|
|
|
|
fsusage->disk_queue = SIGAR_FIELD_NOTIMPL;
|
|
|
|
|
2004-12-05 15:10:18 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-05-07 07:47:22 +08:00
|
|
|
static int get_iostat_proc_dstat(sigar_t *sigar,
|
|
|
|
const char *dirname,
|
|
|
|
sigar_file_system_usage_t *fsusage)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
char buffer[1025], dev[1025];
|
2007-02-22 10:28:21 +08:00
|
|
|
char *ptr;
|
|
|
|
struct stat sb;
|
2005-05-07 07:47:22 +08:00
|
|
|
|
2007-02-22 10:28:21 +08:00
|
|
|
if (!get_fsdev(sigar, dirname, dev)) {
|
2005-05-07 07:47:22 +08:00
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
2007-02-22 10:28:21 +08:00
|
|
|
if (stat(dev, &sb) < 0) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SIGAR_LOG_IS_DEBUG(sigar)) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
PROC_DISKSTATS " %s -> %s [%d,%d]",
|
|
|
|
dirname, dev, ST_MAJOR(sb), ST_MINOR(sb));
|
|
|
|
}
|
2005-05-07 07:47:22 +08:00
|
|
|
|
|
|
|
if (!(fp = fopen(PROC_DISKSTATS, "r"))) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
|
2007-02-22 10:28:21 +08:00
|
|
|
unsigned long major, minor;
|
2005-05-07 07:47:22 +08:00
|
|
|
|
2007-02-22 10:28:21 +08:00
|
|
|
major = sigar_strtoul(ptr);
|
|
|
|
minor = sigar_strtoul(ptr);
|
|
|
|
|
|
|
|
if ((major == ST_MAJOR(sb)) && (minor == ST_MINOR(sb))) {
|
2005-05-07 07:47:22 +08:00
|
|
|
int num, status=SIGAR_OK;
|
|
|
|
unsigned long
|
|
|
|
rio, rmerge, rsect, ruse,
|
|
|
|
wio, wmerge, wsect, wuse,
|
|
|
|
running, use, aveq;
|
|
|
|
|
2007-02-22 10:28:21 +08:00
|
|
|
ptr = sigar_skip_token(ptr); /* name */
|
2005-05-07 07:47:22 +08:00
|
|
|
|
|
|
|
num = sscanf(ptr,
|
|
|
|
"%lu %lu %lu %lu "
|
|
|
|
"%lu %lu %lu %lu "
|
|
|
|
"%lu %lu %lu",
|
2006-06-22 01:53:15 +08:00
|
|
|
&rio, /* 1 # reads issued */
|
|
|
|
&rmerge, /* 2 # reads merged */
|
|
|
|
&rsect, /* 3 # sectors read */
|
|
|
|
&ruse, /* 4 # millis spent reading */
|
|
|
|
&wio, /* 5 # writes completed */
|
|
|
|
&wmerge, /* 6 # writes merged */
|
|
|
|
&wsect, /* 7 # sectors written */
|
|
|
|
&wuse, /* 8 # millis spent writing */
|
|
|
|
&running, /* 9 # I/Os currently in progress */
|
|
|
|
&use, /* 10 # millis spent doing I/Os */
|
|
|
|
&aveq); /* 11 # of millis spent doing I/Os (weighted) */
|
2005-05-07 07:47:22 +08:00
|
|
|
|
|
|
|
if (num == 11) {
|
|
|
|
fsusage->disk_queue = aveq / 1000;
|
|
|
|
}
|
|
|
|
else if (num == 4) {
|
|
|
|
wio = rsect;
|
|
|
|
rsect = rmerge;
|
|
|
|
wsect = ruse;
|
|
|
|
fsusage->disk_queue = SIGAR_FIELD_NOTIMPL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
status = ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
fsusage->disk_reads = rio;
|
|
|
|
fsusage->disk_writes = wio;
|
|
|
|
fsusage->disk_read_bytes = rsect;
|
|
|
|
fsusage->disk_write_bytes = wsect;
|
|
|
|
|
2006-06-22 10:48:19 +08:00
|
|
|
/* convert sectors to bytes (512 is fixed size in 2.6 kernels) */
|
|
|
|
fsusage->disk_read_bytes *= 512;
|
|
|
|
fsusage->disk_write_bytes *= 512;
|
|
|
|
|
2005-05-07 07:47:22 +08:00
|
|
|
fclose(fp);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
2004-12-06 04:34:51 +08:00
|
|
|
static int get_iostat_procp(sigar_t *sigar,
|
|
|
|
const char *dirname,
|
|
|
|
sigar_file_system_usage_t *fsusage)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
char buffer[1025], dev[1025];
|
2007-02-22 10:28:21 +08:00
|
|
|
char *ptr;
|
|
|
|
struct stat sb;
|
2004-12-06 04:34:51 +08:00
|
|
|
|
2007-02-22 10:28:21 +08:00
|
|
|
if (!get_fsdev(sigar, dirname, dev)) {
|
2004-12-06 04:34:51 +08:00
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
2007-02-22 10:28:21 +08:00
|
|
|
if (stat(dev, &sb) < 0) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SIGAR_LOG_IS_DEBUG(sigar)) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
PROC_PARTITIONS " %s -> %s [%d,%d]",
|
|
|
|
dirname, dev, ST_MAJOR(sb), ST_MINOR(sb));
|
|
|
|
}
|
2004-12-06 04:34:51 +08:00
|
|
|
|
|
|
|
if (!(fp = fopen(PROC_PARTITIONS, "r"))) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void)fgets(buffer, sizeof(buffer), fp); /* skip header */
|
|
|
|
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
|
2007-02-22 10:28:21 +08:00
|
|
|
unsigned long major, minor;
|
|
|
|
|
|
|
|
major = sigar_strtoul(ptr);
|
|
|
|
minor = sigar_strtoul(ptr);
|
2004-12-06 04:34:51 +08:00
|
|
|
|
2007-02-22 10:28:21 +08:00
|
|
|
if ((major == ST_MAJOR(sb)) && (minor == ST_MINOR(sb))) {
|
|
|
|
ptr = sigar_skip_token(ptr); /* blocks */
|
2004-12-06 04:34:51 +08:00
|
|
|
ptr = sigar_skip_token(ptr); /* name */
|
2006-10-11 11:17:34 +08:00
|
|
|
fsusage->disk_reads = sigar_strtoull(ptr); /* rio */
|
2005-05-07 06:51:34 +08:00
|
|
|
ptr = sigar_skip_token(ptr); /* rmerge */
|
2006-10-11 11:17:34 +08:00
|
|
|
fsusage->disk_read_bytes = sigar_strtoull(ptr); /* rsect */
|
2005-05-07 06:51:34 +08:00
|
|
|
ptr = sigar_skip_token(ptr); /* ruse */
|
|
|
|
|
|
|
|
ptr = sigar_skip_token(ptr); /* wmerge */
|
2006-10-11 11:17:34 +08:00
|
|
|
fsusage->disk_write_bytes = sigar_strtoull(ptr); /* wsect */
|
|
|
|
fsusage->disk_writes = sigar_strtoull(ptr); /* wio */
|
2005-05-07 06:51:34 +08:00
|
|
|
/* wuse, running, use */
|
|
|
|
ptr = sigar_skip_multiple_token(ptr, 3);
|
2006-10-11 11:17:34 +08:00
|
|
|
fsusage->disk_queue = sigar_strtoull(ptr); /* aveq */
|
2005-05-07 06:51:34 +08:00
|
|
|
fsusage->disk_queue /= 1000;
|
|
|
|
|
2006-06-22 10:48:19 +08:00
|
|
|
/* convert sectors to bytes (512 is fixed size in 2.6 kernels) */
|
|
|
|
fsusage->disk_read_bytes *= 512;
|
|
|
|
fsusage->disk_write_bytes *= 512;
|
|
|
|
|
2004-12-06 04:34:51 +08:00
|
|
|
fclose(fp);
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
#include <sys/vfs.h>
|
|
|
|
|
|
|
|
#define SIGAR_FS_BLOCKS_TO_BYTES(buf, f) \
|
2006-05-31 08:59:14 +08:00
|
|
|
(((sigar_uint64_t)buf.f * (buf.f_bsize / 512)) >> 1)
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
int sigar_file_system_usage_get(sigar_t *sigar,
|
|
|
|
const char *dirname,
|
|
|
|
sigar_file_system_usage_t *fsusage)
|
|
|
|
{
|
|
|
|
struct statfs buf;
|
|
|
|
|
|
|
|
if (statfs(dirname, &buf) != 0) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
fsusage->total = SIGAR_FS_BLOCKS_TO_BYTES(buf, f_blocks);
|
|
|
|
fsusage->free = SIGAR_FS_BLOCKS_TO_BYTES(buf, f_bfree);
|
|
|
|
fsusage->avail = SIGAR_FS_BLOCKS_TO_BYTES(buf, f_bavail);
|
2005-04-27 03:55:21 +08:00
|
|
|
fsusage->used = fsusage->total - fsusage->free;
|
2004-06-22 06:37:04 +08:00
|
|
|
fsusage->files = buf.f_files;
|
|
|
|
fsusage->free_files = buf.f_ffree;
|
|
|
|
fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
|
|
|
|
|
2004-12-06 04:34:51 +08:00
|
|
|
/*
|
|
|
|
* 2.2 has metrics /proc/stat, but wtf is the device mapping?
|
|
|
|
* 2.4 has /proc/partitions w/ the metrics.
|
|
|
|
* 2.6 has /proc/partitions w/o the metrics.
|
|
|
|
* instead the metrics are within the /proc-like /sys filesystem.
|
|
|
|
* also has /proc/diskstats
|
|
|
|
*/
|
|
|
|
switch (sigar->iostat) {
|
|
|
|
case IOSTAT_SYS:
|
2004-12-05 15:10:18 +08:00
|
|
|
if (get_iostat_sys(sigar, dirname, fsusage) == SIGAR_OK) {
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
2004-12-06 04:34:51 +08:00
|
|
|
break;
|
2005-05-07 07:47:22 +08:00
|
|
|
case IOSTAT_DISKSTATS:
|
|
|
|
if (get_iostat_proc_dstat(sigar, dirname, fsusage) == SIGAR_OK) {
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
break;
|
2004-12-06 04:34:51 +08:00
|
|
|
case IOSTAT_PARTITIONS:
|
|
|
|
if (get_iostat_procp(sigar, dirname, fsusage) == SIGAR_OK) {
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
/*
|
|
|
|
* case IOSTAT_SOME_OTHER_WIERD_THING:
|
|
|
|
* break;
|
|
|
|
*/
|
|
|
|
case IOSTAT_NONE:
|
|
|
|
break;
|
2004-12-05 15:10:18 +08:00
|
|
|
}
|
|
|
|
|
2004-12-06 07:42:23 +08:00
|
|
|
SIGAR_DISK_STATS_NOTIMPL(fsusage);
|
2004-12-05 15:10:18 +08:00
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SIGAR_INLINE char *cpu_info_strval(char *ptr)
|
|
|
|
{
|
|
|
|
if ((ptr = strchr(ptr, ':'))) {
|
|
|
|
ptr++;
|
|
|
|
while (isspace (*ptr)) ptr++;
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SIGAR_INLINE void cpu_info_strcpy(char *ptr, char *buf, int len)
|
|
|
|
{
|
|
|
|
int slen;
|
|
|
|
ptr = cpu_info_strval(ptr);
|
|
|
|
if (!ptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
slen = strlen(ptr);
|
|
|
|
strncpy(buf, ptr, len);
|
|
|
|
buf[len] = '\0';
|
|
|
|
if (slen < len) {
|
|
|
|
buf[slen-1] = '\0'; /* rid \n */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-02 10:52:51 +08:00
|
|
|
static int get_cpu_info(sigar_t *sigar, sigar_cpu_info_t *info,
|
2006-02-24 07:23:27 +08:00
|
|
|
FILE *fp)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr;
|
|
|
|
|
2006-02-24 07:23:27 +08:00
|
|
|
int found = 0;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2007-04-06 02:51:22 +08:00
|
|
|
/* UML vm wont have "cpu MHz" or "cache size" fields */
|
|
|
|
info->mhz = 0;
|
|
|
|
info->cache_size = 0;
|
|
|
|
|
2006-07-12 01:40:18 +08:00
|
|
|
#ifdef __powerpc64__
|
|
|
|
SIGAR_SSTRCPY(info->vendor, "IBM");
|
|
|
|
#endif
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
|
|
|
|
switch (*ptr) {
|
|
|
|
case 'p': /* processor : 0 */
|
|
|
|
if (strnEQ(ptr, "processor", 9)) {
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'v':
|
2006-09-21 06:05:54 +08:00
|
|
|
/* "vendor_id" or "vendor" */
|
|
|
|
if (strnEQ(ptr, "vendor", 6)) {
|
2004-06-22 06:37:04 +08:00
|
|
|
cpu_info_strcpy(ptr, info->vendor, sizeof(info->vendor));
|
2004-07-02 06:07:12 +08:00
|
|
|
if (strEQ(info->vendor, "GenuineIntel")) {
|
|
|
|
SIGAR_SSTRCPY(info->vendor, "Intel");
|
|
|
|
}
|
|
|
|
else if (strEQ(info->vendor, "AuthenticAMD")) {
|
|
|
|
SIGAR_SSTRCPY(info->vendor, "AMD");
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
break;
|
2006-09-21 06:05:54 +08:00
|
|
|
case 'f':
|
|
|
|
if (strnEQ(ptr, "family", 6)) {
|
|
|
|
/* IA64 version of "model name" */
|
|
|
|
cpu_info_strcpy(ptr, info->model, sizeof(info->model));
|
|
|
|
sigar_cpu_model_adjust(sigar, info);
|
|
|
|
}
|
|
|
|
break;
|
2004-06-22 06:37:04 +08:00
|
|
|
case 'm':
|
|
|
|
if (strnEQ(ptr, "model name", 10)) {
|
|
|
|
cpu_info_strcpy(ptr, info->model, sizeof(info->model));
|
2004-07-02 10:52:51 +08:00
|
|
|
sigar_cpu_model_adjust(sigar, info);
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
if (strnEQ(ptr, "cpu MHz", 7)) {
|
|
|
|
ptr = cpu_info_strval(ptr);
|
|
|
|
info->mhz = atoi(ptr);
|
|
|
|
}
|
|
|
|
else if (strnEQ(ptr, "cache size", 10)) {
|
|
|
|
ptr = cpu_info_strval(ptr);
|
|
|
|
info->cache_size = sigar_strtoul(ptr);
|
|
|
|
}
|
2006-07-12 01:40:18 +08:00
|
|
|
#ifdef __powerpc64__
|
|
|
|
/* each /proc/cpuinfo entry looks like so:
|
|
|
|
* processor : 0
|
|
|
|
* cpu : POWER5 (gr)
|
|
|
|
* clock : 1656.392000MHz
|
|
|
|
* revision : 2.2
|
|
|
|
*/
|
|
|
|
else if (strnEQ(ptr, "clock", 5)) {
|
|
|
|
ptr = cpu_info_strval(ptr);
|
|
|
|
info->mhz = atoi(ptr);
|
|
|
|
}
|
|
|
|
else if (strnEQ(ptr, "cpu", 3)) {
|
|
|
|
cpu_info_strcpy(ptr, info->model, sizeof(info->model));
|
|
|
|
|
|
|
|
if ((ptr = strchr(info->model, ' '))) {
|
|
|
|
/* "POWER5 (gr)" -> "POWER5" */
|
|
|
|
*ptr = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2004-06-22 06:37:04 +08:00
|
|
|
break;
|
|
|
|
/* lone \n means end of info for this processor */
|
|
|
|
case '\n':
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2007-06-29 03:07:29 +08:00
|
|
|
/* /proc/cpuinfo MHz will change w/ AMD + PowerNow */
|
|
|
|
static void get_cpuinfo_max_freq(sigar_cpu_info_t *cpu_info, int num)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
char max_freq[PATH_MAX];
|
|
|
|
snprintf(max_freq, sizeof(max_freq),
|
|
|
|
"/sys/devices/system/cpu/cpu%d"
|
|
|
|
"/cpufreq/cpuinfo_max_freq", num);
|
|
|
|
|
|
|
|
status =
|
|
|
|
sigar_file2str(max_freq, max_freq, sizeof(max_freq)-1);
|
|
|
|
|
|
|
|
if (status == SIGAR_OK) {
|
|
|
|
cpu_info->mhz = atoi(max_freq) / 1000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-10 12:44:45 +08:00
|
|
|
int sigar_cpu_info_list_get(sigar_t *sigar,
|
|
|
|
sigar_cpu_info_list_t *cpu_infos)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
|
|
|
FILE *fp;
|
2006-02-24 07:23:27 +08:00
|
|
|
int hthread = is_ht_enabled(sigar), i=0;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-10-01 07:05:14 +08:00
|
|
|
if (!(fp = fopen(PROC_FS_ROOT "cpuinfo", "r"))) {
|
2004-06-22 06:37:04 +08:00
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
2004-07-10 12:44:45 +08:00
|
|
|
sigar_cpu_info_list_create(cpu_infos);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-02-24 07:23:27 +08:00
|
|
|
while (get_cpu_info(sigar, &cpu_infos->data[cpu_infos->number], fp)) {
|
|
|
|
if (hthread && (i++ % sigar->lcpu)) {
|
|
|
|
continue; /* fold logical processors if HT */
|
2004-08-12 06:44:38 +08:00
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2007-06-29 03:07:29 +08:00
|
|
|
get_cpuinfo_max_freq(&cpu_infos->data[cpu_infos->number],
|
|
|
|
cpu_infos->number);
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
++cpu_infos->number;
|
2004-07-10 12:44:45 +08:00
|
|
|
SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
static SIGAR_INLINE unsigned int hex2int(const char *x, int len)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
2006-07-04 04:17:35 +08:00
|
|
|
int i;
|
2004-06-22 06:37:04 +08:00
|
|
|
unsigned int j;
|
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
for (i=0, j=0; i<len; i++) {
|
|
|
|
register int ch = x[i];
|
2004-06-22 06:37:04 +08:00
|
|
|
j <<= 4;
|
|
|
|
if (isdigit(ch)) {
|
|
|
|
j |= ch - '0';
|
|
|
|
}
|
|
|
|
else if (isupper(ch)) {
|
|
|
|
j |= ch - ('A' - 10);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
j |= ch - ('a' - 10);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return j;
|
|
|
|
}
|
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
#define HEX_ENT_LEN 8
|
|
|
|
|
2006-07-12 01:05:48 +08:00
|
|
|
#ifdef SIGAR_64BIT
|
2005-02-17 06:39:10 +08:00
|
|
|
#define ROUTE_FMT "%16s %128s %128s %X %ld %ld %ld %128s %ld %ld %ld\n"
|
|
|
|
#else
|
2004-06-22 06:37:04 +08:00
|
|
|
#define ROUTE_FMT "%16s %128s %128s %X %lld %lld %lld %128s %lld %lld %lld\n"
|
2005-02-17 06:39:10 +08:00
|
|
|
#endif
|
2004-06-22 06:37:04 +08:00
|
|
|
#define RTF_UP 0x0001
|
|
|
|
|
|
|
|
int sigar_net_route_list_get(sigar_t *sigar,
|
|
|
|
sigar_net_route_list_t *routelist)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
char buffer[1024];
|
|
|
|
char net_addr[128], gate_addr[128], mask_addr[128];
|
|
|
|
int flags;
|
|
|
|
sigar_net_route_t *route;
|
|
|
|
|
|
|
|
routelist->size = routelist->number = 0;
|
|
|
|
|
2005-10-01 07:05:14 +08:00
|
|
|
if (!(fp = fopen(PROC_FS_ROOT "net/route", "r"))) {
|
2004-06-22 06:37:04 +08:00
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
sigar_net_route_list_create(routelist);
|
|
|
|
|
|
|
|
(void)fgets(buffer, sizeof(buffer), fp); /* skip header */
|
|
|
|
while (fgets(buffer, sizeof(buffer), fp)) {
|
|
|
|
int num;
|
|
|
|
|
|
|
|
SIGAR_NET_ROUTE_LIST_GROW(routelist);
|
|
|
|
route = &routelist->data[routelist->number++];
|
|
|
|
|
|
|
|
/* XXX rid sscanf */
|
|
|
|
num = sscanf(buffer, ROUTE_FMT,
|
|
|
|
route->ifname, net_addr, gate_addr,
|
|
|
|
&flags, &route->refcnt, &route->use,
|
|
|
|
&route->metric, mask_addr,
|
|
|
|
&route->mtu, &route->window, &route->irtt);
|
|
|
|
|
|
|
|
if ((num < 10) || !(flags & RTF_UP)) {
|
|
|
|
--routelist->number;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
route->flags = flags;
|
2006-07-05 03:22:05 +08:00
|
|
|
|
|
|
|
sigar_net_address_set(route->destination, hex2int(net_addr, HEX_ENT_LEN));
|
|
|
|
sigar_net_address_set(route->gateway, hex2int(gate_addr, HEX_ENT_LEN));
|
|
|
|
sigar_net_address_set(route->mask, hex2int(mask_addr, HEX_ENT_LEN));
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
|
|
|
|
sigar_net_interface_stat_t *ifstat)
|
|
|
|
{
|
|
|
|
int found = 0;
|
|
|
|
char buffer[BUFSIZ];
|
2005-10-01 07:05:14 +08:00
|
|
|
FILE *fp = fopen(PROC_FS_ROOT "net/dev", "r");
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (!fp) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* skip header */
|
|
|
|
fgets(buffer, sizeof(buffer), fp);
|
|
|
|
fgets(buffer, sizeof(buffer), fp);
|
|
|
|
|
|
|
|
while (fgets(buffer, sizeof(buffer), fp)) {
|
|
|
|
char *ptr, *dev;
|
|
|
|
|
|
|
|
dev = buffer;
|
|
|
|
while (isspace(*dev)) {
|
|
|
|
dev++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ptr = strchr(dev, ':'))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ptr++ = 0;
|
|
|
|
|
|
|
|
if (!strEQ(dev, name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
found = 1;
|
2006-10-11 11:17:34 +08:00
|
|
|
ifstat->rx_bytes = sigar_strtoull(ptr);
|
|
|
|
ifstat->rx_packets = sigar_strtoull(ptr);
|
|
|
|
ifstat->rx_errors = sigar_strtoull(ptr);
|
|
|
|
ifstat->rx_dropped = sigar_strtoull(ptr);
|
|
|
|
ifstat->rx_overruns = sigar_strtoull(ptr);
|
|
|
|
ifstat->rx_frame = sigar_strtoull(ptr);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
/* skip: compressed multicast */
|
|
|
|
ptr = sigar_skip_multiple_token(ptr, 2);
|
|
|
|
|
2006-10-11 11:17:34 +08:00
|
|
|
ifstat->tx_bytes = sigar_strtoull(ptr);
|
|
|
|
ifstat->tx_packets = sigar_strtoull(ptr);
|
|
|
|
ifstat->tx_errors = sigar_strtoull(ptr);
|
|
|
|
ifstat->tx_dropped = sigar_strtoull(ptr);
|
|
|
|
ifstat->tx_overruns = sigar_strtoull(ptr);
|
|
|
|
ifstat->tx_collisions = sigar_strtoull(ptr);
|
|
|
|
ifstat->tx_carrier = sigar_strtoull(ptr);
|
2006-03-07 09:08:23 +08:00
|
|
|
|
|
|
|
ifstat->speed = SIGAR_FIELD_NOTIMPL;
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return found ? SIGAR_OK : ENXIO;
|
|
|
|
}
|
|
|
|
|
2006-07-05 00:35:27 +08:00
|
|
|
static SIGAR_INLINE void convert_hex_address(sigar_net_address_t *address,
|
|
|
|
char *ptr, int len)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
2006-07-04 04:17:35 +08:00
|
|
|
if (len > HEX_ENT_LEN) {
|
2004-06-22 06:37:04 +08:00
|
|
|
int i;
|
2006-07-04 04:17:35 +08:00
|
|
|
for (i=0; i<=3; i++, ptr+=HEX_ENT_LEN) {
|
2006-07-05 00:35:27 +08:00
|
|
|
address->addr.in6[i] = hex2int(ptr, HEX_ENT_LEN);
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
2006-07-05 00:35:27 +08:00
|
|
|
|
|
|
|
address->family = SIGAR_AF_INET6;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
else {
|
2006-07-05 00:35:27 +08:00
|
|
|
address->addr.in =
|
|
|
|
(len == HEX_ENT_LEN) ? hex2int(ptr, HEX_ENT_LEN) : 0;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-07-05 00:35:27 +08:00
|
|
|
address->family = SIGAR_AF_INET;
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
sigar_net_connection_list_t *connlist;
|
|
|
|
sigar_net_connection_t *conn;
|
|
|
|
unsigned long port;
|
|
|
|
} net_conn_getter_t;
|
|
|
|
|
2006-06-16 04:50:00 +08:00
|
|
|
static int proc_net_walker(sigar_net_connection_walker_t *walker,
|
|
|
|
sigar_net_connection_t *conn)
|
|
|
|
{
|
|
|
|
net_conn_getter_t *getter =
|
|
|
|
(net_conn_getter_t *)walker->data;
|
|
|
|
|
|
|
|
if (getter->connlist) {
|
|
|
|
SIGAR_NET_CONNLIST_GROW(getter->connlist);
|
|
|
|
memcpy(&getter->connlist->data[getter->connlist->number++],
|
|
|
|
conn, sizeof(*conn));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ((getter->port == conn->local_port) &&
|
|
|
|
(conn->remote_port == 0))
|
|
|
|
{
|
|
|
|
memcpy(getter->conn, conn, sizeof(*conn));
|
|
|
|
return !SIGAR_OK; /* break loop */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK; /* continue loop */
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
#define SKIP_WHILE(p, c) while (*p == c) p++
|
|
|
|
#define SKIP_PAST(p, c) \
|
|
|
|
while(*p && (*p != c)) p++; \
|
|
|
|
SKIP_WHILE(p, c)
|
|
|
|
|
2006-06-16 04:50:00 +08:00
|
|
|
static int proc_net_read(sigar_net_connection_walker_t *walker,
|
2004-06-22 06:37:04 +08:00
|
|
|
const char *fname,
|
2006-06-16 04:50:00 +08:00
|
|
|
int type)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
2007-04-05 10:26:00 +08:00
|
|
|
FILE *fp = NULL;
|
2006-07-04 04:17:35 +08:00
|
|
|
char buffer[8192];
|
2007-04-05 10:26:00 +08:00
|
|
|
sigar_t *sigar = walker->sigar;
|
|
|
|
char *ptr = sigar->proc_net;
|
2006-06-16 04:50:00 +08:00
|
|
|
int flags = walker->flags;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2007-04-05 10:26:00 +08:00
|
|
|
if (ptr) {
|
|
|
|
snprintf(buffer, sizeof(buffer),
|
|
|
|
"%s/%s", ptr,
|
|
|
|
fname + sizeof(PROC_FS_ROOT)-1);
|
|
|
|
|
|
|
|
if ((fp = fopen(buffer, "r"))) {
|
|
|
|
if (SIGAR_LOG_IS_DEBUG(sigar)) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[proc_net] using %s",
|
|
|
|
buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (SIGAR_LOG_IS_DEBUG(sigar)) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"[proc_net] cannot open %s",
|
|
|
|
buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(fp || (fp = fopen(fname, "r")))) {
|
2004-06-22 06:37:04 +08:00
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
fgets(buffer, sizeof(buffer), fp); /* skip header */
|
|
|
|
|
|
|
|
while ((ptr = fgets(buffer, sizeof(buffer), fp))) {
|
|
|
|
sigar_net_connection_t conn;
|
|
|
|
char *laddr, *raddr;
|
2006-07-04 04:17:35 +08:00
|
|
|
int laddr_len=0, raddr_len=0;
|
2006-07-05 00:35:27 +08:00
|
|
|
int more;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
/* skip leading space */
|
|
|
|
SKIP_WHILE(ptr, ' ');
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
/* skip "%d: " */
|
|
|
|
SKIP_PAST(ptr, ' ');
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
laddr = ptr;
|
2006-07-04 04:17:35 +08:00
|
|
|
while (*ptr && (*ptr != ':')) {
|
|
|
|
laddr_len++;
|
2004-06-22 06:37:04 +08:00
|
|
|
ptr++;
|
|
|
|
}
|
2006-07-04 04:17:35 +08:00
|
|
|
SKIP_WHILE(ptr, ':');
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
conn.local_port = (strtoul(ptr, &ptr, 16) & 0xffff);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
SKIP_WHILE(ptr, ' ');
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
raddr = ptr;
|
|
|
|
while (*ptr && (*ptr != ':')) {
|
|
|
|
raddr_len++;
|
2004-06-22 06:37:04 +08:00
|
|
|
ptr++;
|
|
|
|
}
|
2006-07-04 04:17:35 +08:00
|
|
|
SKIP_WHILE(ptr, ':');
|
|
|
|
|
|
|
|
conn.remote_port = (strtoul(ptr, &ptr, 16) & 0xffff);
|
|
|
|
|
|
|
|
SKIP_WHILE(ptr, ' ');
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (!((conn.remote_port && (flags & SIGAR_NETCONN_CLIENT)) ||
|
|
|
|
(!conn.remote_port && (flags & SIGAR_NETCONN_SERVER))))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn.type = type;
|
|
|
|
|
2006-07-05 00:35:27 +08:00
|
|
|
convert_hex_address(&conn.local_address,
|
|
|
|
laddr, laddr_len);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-07-05 00:35:27 +08:00
|
|
|
convert_hex_address(&conn.remote_address,
|
|
|
|
raddr, raddr_len);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-03-12 01:02:30 +08:00
|
|
|
/* SIGAR_TCP_* currently matches TCP_* in linux/tcp.h */
|
2006-07-04 04:17:35 +08:00
|
|
|
conn.state = hex2int(ptr, 2);
|
|
|
|
ptr += 2;
|
|
|
|
SKIP_WHILE(ptr, ' ');
|
2006-04-25 02:18:16 +08:00
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
conn.send_queue = hex2int(ptr, HEX_ENT_LEN);
|
2006-04-25 02:18:16 +08:00
|
|
|
ptr += HEX_ENT_LEN+1; /* tx + ':' */;
|
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
conn.receive_queue = hex2int(ptr, HEX_ENT_LEN);
|
2006-04-25 02:18:16 +08:00
|
|
|
ptr += HEX_ENT_LEN;
|
2006-07-04 04:17:35 +08:00
|
|
|
SKIP_WHILE(ptr, ' ');
|
2006-04-25 02:18:16 +08:00
|
|
|
|
2006-07-04 04:17:35 +08:00
|
|
|
SKIP_PAST(ptr, ' '); /* tr:tm->whem */
|
|
|
|
SKIP_PAST(ptr, ' '); /* retrnsmt */
|
2005-03-12 01:02:30 +08:00
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
conn.uid = sigar_strtoul(ptr);
|
|
|
|
|
2007-06-03 01:25:28 +08:00
|
|
|
SKIP_WHILE(ptr, ' ');
|
2006-07-04 04:17:35 +08:00
|
|
|
SKIP_PAST(ptr, ' '); /* timeout */
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
conn.inode = sigar_strtoul(ptr);
|
|
|
|
|
2006-06-16 04:50:00 +08:00
|
|
|
more = walker->add_connection(walker, &conn);
|
|
|
|
if (more != SIGAR_OK) {
|
|
|
|
fclose(fp);
|
|
|
|
return SIGAR_OK;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2006-06-20 08:28:21 +08:00
|
|
|
int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
2006-06-16 04:50:00 +08:00
|
|
|
int flags = walker->flags;
|
2004-06-22 06:37:04 +08:00
|
|
|
int status;
|
|
|
|
|
|
|
|
if (flags & SIGAR_NETCONN_TCP) {
|
2006-06-16 04:50:00 +08:00
|
|
|
status = proc_net_read(walker,
|
2005-10-01 07:05:14 +08:00
|
|
|
PROC_FS_ROOT "net/tcp",
|
2006-06-16 04:50:00 +08:00
|
|
|
SIGAR_NETCONN_TCP);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2006-06-16 04:50:00 +08:00
|
|
|
status = proc_net_read(walker,
|
2005-10-01 07:05:14 +08:00
|
|
|
PROC_FS_ROOT "net/tcp6",
|
2006-06-16 04:50:00 +08:00
|
|
|
SIGAR_NETCONN_TCP);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (!((status == SIGAR_OK) || (status == ENOENT))) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & SIGAR_NETCONN_UDP) {
|
2006-06-16 04:50:00 +08:00
|
|
|
status = proc_net_read(walker,
|
2005-10-01 07:05:14 +08:00
|
|
|
PROC_FS_ROOT "net/udp",
|
2006-06-16 04:50:00 +08:00
|
|
|
SIGAR_NETCONN_UDP);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2006-06-16 04:50:00 +08:00
|
|
|
status = proc_net_read(walker,
|
2005-10-01 07:05:14 +08:00
|
|
|
PROC_FS_ROOT "net/udp6",
|
2006-06-16 04:50:00 +08:00
|
|
|
SIGAR_NETCONN_UDP);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (!((status == SIGAR_OK) || (status == ENOENT))) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & SIGAR_NETCONN_RAW) {
|
2006-06-16 04:50:00 +08:00
|
|
|
status = proc_net_read(walker,
|
2005-10-01 07:05:14 +08:00
|
|
|
PROC_FS_ROOT "net/raw",
|
2006-06-16 04:50:00 +08:00
|
|
|
SIGAR_NETCONN_RAW);
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2006-06-16 04:50:00 +08:00
|
|
|
status = proc_net_read(walker,
|
2005-10-01 07:05:14 +08:00
|
|
|
PROC_FS_ROOT "net/raw6",
|
2006-06-16 04:50:00 +08:00
|
|
|
SIGAR_NETCONN_RAW);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (!((status == SIGAR_OK) || (status == ENOENT))) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX /proc/net/unix */
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_net_connection_list_get(sigar_t *sigar,
|
|
|
|
sigar_net_connection_list_t *connlist,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
int status;
|
2006-06-16 04:50:00 +08:00
|
|
|
sigar_net_connection_walker_t walker;
|
2004-06-22 06:37:04 +08:00
|
|
|
net_conn_getter_t getter;
|
|
|
|
|
|
|
|
sigar_net_connection_list_create(connlist);
|
|
|
|
|
|
|
|
getter.conn = NULL;
|
|
|
|
getter.connlist = connlist;
|
|
|
|
|
2006-06-16 04:50:00 +08:00
|
|
|
walker.sigar = sigar;
|
|
|
|
walker.flags = flags;
|
|
|
|
walker.data = &getter;
|
|
|
|
walker.add_connection = proc_net_walker;
|
|
|
|
|
2006-06-20 08:28:21 +08:00
|
|
|
status = sigar_net_connection_walk(&walker);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
sigar_net_connection_list_destroy(sigar, connlist);
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sigar_net_connection_get(sigar_t *sigar,
|
|
|
|
sigar_net_connection_t *netconn,
|
|
|
|
unsigned long port,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
int status;
|
2006-06-16 04:50:00 +08:00
|
|
|
sigar_net_connection_walker_t walker;
|
2004-06-22 06:37:04 +08:00
|
|
|
net_conn_getter_t getter;
|
|
|
|
|
|
|
|
getter.conn = netconn;
|
|
|
|
getter.connlist = NULL;
|
|
|
|
getter.port = port;
|
|
|
|
|
2006-06-16 04:50:00 +08:00
|
|
|
walker.sigar = sigar;
|
|
|
|
walker.flags = flags;
|
|
|
|
walker.data = &getter;
|
|
|
|
walker.add_connection = proc_net_walker;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2006-06-20 08:28:21 +08:00
|
|
|
status = sigar_net_connection_walk(&walker);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2007-07-15 00:31:37 +08:00
|
|
|
#define SNMP_TCP_PREFIX "Tcp: "
|
|
|
|
|
2007-07-15 00:01:58 +08:00
|
|
|
SIGAR_DECLARE(int)
|
2007-08-08 13:34:21 +08:00
|
|
|
sigar_tcp_get(sigar_t *sigar,
|
|
|
|
sigar_tcp_t *tcp)
|
2007-07-15 00:01:58 +08:00
|
|
|
{
|
2007-07-15 00:31:37 +08:00
|
|
|
FILE *fp;
|
|
|
|
char buffer[1024], *ptr=buffer;
|
|
|
|
int status = SIGAR_ENOENT;
|
|
|
|
|
|
|
|
if (!(fp = fopen(PROC_FS_ROOT "net/snmp", "r"))) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(buffer, sizeof(buffer), fp)) {
|
|
|
|
if (strnEQ(buffer, SNMP_TCP_PREFIX, sizeof(SNMP_TCP_PREFIX)-1)) {
|
|
|
|
if (fgets(buffer, sizeof(buffer), fp)) {
|
|
|
|
status = SIGAR_OK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
if (status == SIGAR_OK) {
|
|
|
|
/* assuming field order, same in 2.2, 2.4 and 2.6 kernels */
|
2007-08-08 13:05:16 +08:00
|
|
|
/* Tcp: RtoAlgorithm RtoMin RtoMax MaxConn */
|
|
|
|
ptr = sigar_skip_multiple_token(ptr, 5);
|
2007-08-08 13:34:21 +08:00
|
|
|
tcp->active_opens = sigar_strtoull(ptr);
|
|
|
|
tcp->passive_opens = sigar_strtoull(ptr);
|
|
|
|
tcp->attempt_fails = sigar_strtoull(ptr);
|
|
|
|
tcp->estab_resets = sigar_strtoull(ptr);
|
|
|
|
tcp->curr_estab = sigar_strtoull(ptr);
|
|
|
|
tcp->in_segs = sigar_strtoull(ptr);
|
|
|
|
tcp->out_segs = sigar_strtoull(ptr);
|
|
|
|
tcp->retrans_segs = sigar_strtoull(ptr);
|
2007-08-08 14:11:20 +08:00
|
|
|
tcp->in_errs = sigar_strtoull(ptr);
|
2007-08-08 13:34:21 +08:00
|
|
|
tcp->out_rsts = sigar_strtoull(ptr);
|
2007-07-15 00:31:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
2007-07-15 00:01:58 +08:00
|
|
|
}
|
|
|
|
|
2007-07-26 15:42:54 +08:00
|
|
|
static int sigar_proc_nfs_gets(char *file, char *tok,
|
|
|
|
char *buffer, size_t size)
|
|
|
|
{
|
|
|
|
int status = ENOENT;
|
|
|
|
int len = strlen(tok);
|
|
|
|
FILE *fp = fopen(file, "r");
|
|
|
|
|
|
|
|
if (!fp) {
|
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(buffer, size, fp)) {
|
|
|
|
if (strnEQ(buffer, tok, len)) {
|
|
|
|
status = SIGAR_OK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2007-08-08 13:40:58 +08:00
|
|
|
static int sigar_nfs_v2_get(char *file, sigar_nfs_v2_t *nfs)
|
2007-07-26 15:42:54 +08:00
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr=buffer;
|
|
|
|
int status =
|
|
|
|
sigar_proc_nfs_gets(file,
|
|
|
|
"proc2", buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = sigar_skip_multiple_token(ptr, 2);
|
|
|
|
|
2007-08-08 13:40:58 +08:00
|
|
|
nfs->null = sigar_strtoull(ptr);
|
|
|
|
nfs->getattr = sigar_strtoull(ptr);
|
|
|
|
nfs->setattr = sigar_strtoull(ptr);
|
|
|
|
nfs->root = sigar_strtoull(ptr);
|
|
|
|
nfs->lookup = sigar_strtoull(ptr);
|
|
|
|
nfs->readlink = sigar_strtoull(ptr);
|
|
|
|
nfs->read = sigar_strtoull(ptr);
|
|
|
|
nfs->writecache = sigar_strtoull(ptr);
|
|
|
|
nfs->write = sigar_strtoull(ptr);
|
|
|
|
nfs->create = sigar_strtoull(ptr);
|
|
|
|
nfs->remove = sigar_strtoull(ptr);
|
|
|
|
nfs->rename = sigar_strtoull(ptr);
|
|
|
|
nfs->link = sigar_strtoull(ptr);
|
|
|
|
nfs->symlink = sigar_strtoull(ptr);
|
|
|
|
nfs->mkdir = sigar_strtoull(ptr);
|
|
|
|
nfs->rmdir = sigar_strtoull(ptr);
|
|
|
|
nfs->readdir = sigar_strtoull(ptr);
|
|
|
|
nfs->fsstat = sigar_strtoull(ptr);
|
2007-07-26 15:42:54 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-26 14:30:29 +08:00
|
|
|
int sigar_nfs_client_v2_get(sigar_t *sigar,
|
2007-08-08 13:40:58 +08:00
|
|
|
sigar_nfs_client_v2_t *nfs)
|
2007-07-26 14:30:29 +08:00
|
|
|
{
|
2007-07-26 15:42:54 +08:00
|
|
|
return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfs",
|
2007-08-08 13:40:58 +08:00
|
|
|
(sigar_nfs_v2_t *)nfs);
|
2007-07-26 14:30:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_nfs_server_v2_get(sigar_t *sigar,
|
2007-08-08 13:40:58 +08:00
|
|
|
sigar_nfs_server_v2_t *nfs)
|
2007-07-26 14:30:29 +08:00
|
|
|
{
|
2007-07-26 15:42:54 +08:00
|
|
|
return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfsd",
|
2007-08-08 13:40:58 +08:00
|
|
|
(sigar_nfs_v2_t *)nfs);
|
2007-07-26 15:42:54 +08:00
|
|
|
}
|
|
|
|
|
2007-08-08 13:40:58 +08:00
|
|
|
static int sigar_nfs_v3_get(char *file, sigar_nfs_v3_t *nfs)
|
2007-07-26 15:42:54 +08:00
|
|
|
{
|
|
|
|
char buffer[BUFSIZ], *ptr=buffer;
|
|
|
|
int status =
|
|
|
|
sigar_proc_nfs_gets(file,
|
|
|
|
"proc3", buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = sigar_skip_multiple_token(ptr, 2);
|
|
|
|
|
2007-08-08 13:40:58 +08:00
|
|
|
nfs->null = sigar_strtoull(ptr);
|
|
|
|
nfs->getattr = sigar_strtoull(ptr);
|
|
|
|
nfs->setattr = sigar_strtoull(ptr);
|
|
|
|
nfs->lookup = sigar_strtoull(ptr);
|
|
|
|
nfs->access = sigar_strtoull(ptr);
|
|
|
|
nfs->readlink = sigar_strtoull(ptr);
|
|
|
|
nfs->read = sigar_strtoull(ptr);
|
|
|
|
nfs->write = sigar_strtoull(ptr);
|
|
|
|
nfs->create = sigar_strtoull(ptr);
|
|
|
|
nfs->mkdir = sigar_strtoull(ptr);
|
|
|
|
nfs->symlink = sigar_strtoull(ptr);
|
|
|
|
nfs->mknod = sigar_strtoull(ptr);
|
|
|
|
nfs->remove = sigar_strtoull(ptr);
|
|
|
|
nfs->rmdir = sigar_strtoull(ptr);
|
|
|
|
nfs->rename = sigar_strtoull(ptr);
|
|
|
|
nfs->link = sigar_strtoull(ptr);
|
|
|
|
nfs->readdir = sigar_strtoull(ptr);
|
|
|
|
nfs->readdirplus = sigar_strtoull(ptr);
|
|
|
|
nfs->fsstat = sigar_strtoull(ptr);
|
|
|
|
nfs->fsinfo = sigar_strtoull(ptr);
|
|
|
|
nfs->pathconf = sigar_strtoull(ptr);
|
|
|
|
nfs->commit = sigar_strtoull(ptr);
|
2007-07-26 15:42:54 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
2007-07-26 14:30:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_nfs_client_v3_get(sigar_t *sigar,
|
2007-08-08 13:40:58 +08:00
|
|
|
sigar_nfs_client_v3_t *nfs)
|
2007-07-26 14:30:29 +08:00
|
|
|
{
|
2007-07-26 15:42:54 +08:00
|
|
|
return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfs",
|
2007-08-08 13:40:58 +08:00
|
|
|
(sigar_nfs_v3_t *)nfs);
|
2007-07-26 14:30:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_nfs_server_v3_get(sigar_t *sigar,
|
2007-08-08 13:40:58 +08:00
|
|
|
sigar_nfs_server_v3_t *nfs)
|
2007-07-26 14:30:29 +08:00
|
|
|
{
|
2007-07-26 15:42:54 +08:00
|
|
|
return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfsd",
|
2007-08-08 13:40:58 +08:00
|
|
|
(sigar_nfs_v3_t *)nfs);
|
2007-07-26 14:30:29 +08:00
|
|
|
}
|
|
|
|
|
2005-03-16 10:44:52 +08:00
|
|
|
int sigar_proc_port_get(sigar_t *sigar, int protocol,
|
|
|
|
unsigned long port, sigar_pid_t *pid)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
|
|
|
int status;
|
|
|
|
sigar_net_connection_t netconn;
|
|
|
|
DIR *dirp;
|
|
|
|
struct dirent *ent, dbuf;
|
|
|
|
|
|
|
|
SIGAR_ZERO(&netconn);
|
|
|
|
*pid = 0;
|
|
|
|
|
|
|
|
status = sigar_net_connection_get(sigar, &netconn, port,
|
2005-03-16 11:54:05 +08:00
|
|
|
SIGAR_NETCONN_SERVER|protocol);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (netconn.local_port != port) {
|
|
|
|
return SIGAR_OK; /* XXX or ENOENT? */
|
|
|
|
}
|
|
|
|
|
2005-10-01 07:05:14 +08:00
|
|
|
if (!(dirp = opendir(PROCP_FS_ROOT))) {
|
2004-06-22 06:37:04 +08:00
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (readdir_r(dirp, &dbuf, &ent) == 0) {
|
|
|
|
DIR *fd_dirp;
|
|
|
|
struct dirent *fd_ent, fd_dbuf;
|
|
|
|
struct stat sb;
|
|
|
|
char fd_name[BUFSIZ], pid_name[BUFSIZ];
|
|
|
|
int len, slen;
|
|
|
|
|
|
|
|
if (ent == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sigar_isdigit(*ent->d_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sprintf(pid_name, "/proc/%s", ent->d_name) */
|
2005-10-01 07:05:14 +08:00
|
|
|
memcpy(&pid_name[0], PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT));
|
|
|
|
len = SSTRLEN(PROCP_FS_ROOT);
|
2004-06-22 06:37:04 +08:00
|
|
|
pid_name[len++] = '/';
|
|
|
|
|
|
|
|
slen = strlen(ent->d_name);
|
|
|
|
memcpy(&pid_name[len], ent->d_name, slen);
|
|
|
|
len += slen;
|
|
|
|
pid_name[len] = '\0';
|
|
|
|
|
|
|
|
if (stat(pid_name, &sb) < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (sb.st_uid != netconn.uid) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sprintf(fd_name, "%s/fd", pid_name) */
|
|
|
|
memcpy(&fd_name[0], pid_name, len);
|
|
|
|
memcpy(&fd_name[len], "/fd", 3);
|
|
|
|
fd_name[len+=3] = '\0';
|
|
|
|
|
|
|
|
if (!(fd_dirp = opendir(fd_name))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (readdir_r(fd_dirp, &fd_dbuf, &fd_ent) == 0) {
|
|
|
|
char fd_ent_name[BUFSIZ];
|
|
|
|
|
|
|
|
if (fd_ent == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sigar_isdigit(*fd_ent->d_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sprintf(fd_ent_name, "%s/%s", fd_name, fd_ent->d_name) */
|
|
|
|
slen = strlen(fd_ent->d_name);
|
|
|
|
memcpy(&fd_ent_name[0], fd_name, len);
|
|
|
|
fd_ent_name[len] = '/';
|
|
|
|
memcpy(&fd_ent_name[len+1], fd_ent->d_name, slen);
|
|
|
|
fd_ent_name[len+1+slen] = '\0';
|
|
|
|
|
|
|
|
if (stat(fd_ent_name, &sb) < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sb.st_ino == netconn.inode) {
|
|
|
|
closedir(fd_dirp);
|
|
|
|
closedir(dirp);
|
|
|
|
*pid = strtoul(ent->d_name, NULL, 10);
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir(fd_dirp);
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dirp);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
2006-09-25 02:23:04 +08:00
|
|
|
|
|
|
|
static void generic_vendor_parse(char *line, sigar_sys_info_t *info)
|
|
|
|
{
|
|
|
|
char *ptr;
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
while (*line) {
|
|
|
|
SIGAR_SKIP_SPACE(line);
|
|
|
|
if (!isdigit(*line)) {
|
|
|
|
++line;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = line;
|
|
|
|
while ((isdigit(*ptr) || (*ptr == '.'))) {
|
|
|
|
++ptr;
|
|
|
|
++len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len) {
|
|
|
|
/* sanity check */
|
|
|
|
if (len > sizeof(info->vendor_version)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
memcpy(info->vendor_version, line, len);/*XXX*/
|
|
|
|
info->vendor_version[len] = '\0';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void redhat_vendor_parse(char *line, sigar_sys_info_t *info)
|
|
|
|
{
|
|
|
|
char *start, *end;
|
|
|
|
|
|
|
|
generic_vendor_parse(line, info); /* super.parse */
|
|
|
|
|
|
|
|
if ((start = strchr(line, '('))) {
|
|
|
|
++start;
|
|
|
|
if ((end = strchr(start, ')'))) {
|
|
|
|
int len = end-start;
|
|
|
|
memcpy(info->vendor_code_name, start, len);/*XXX*/
|
|
|
|
info->vendor_code_name[len] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define RHEL_PREFIX "Red Hat Enterprise Linux "
|
|
|
|
#define CENTOS_VENDOR "CentOS"
|
|
|
|
if (strnEQ(line, RHEL_PREFIX, sizeof(RHEL_PREFIX)-1)) {
|
2006-10-01 01:48:33 +08:00
|
|
|
snprintf(info->vendor_version,
|
|
|
|
sizeof(info->vendor_version),
|
|
|
|
"Enterprise Linux %c",
|
|
|
|
info->vendor_version[0]);
|
2006-09-25 02:23:04 +08:00
|
|
|
}
|
|
|
|
else if (strnEQ(line, CENTOS_VENDOR, sizeof(CENTOS_VENDOR)-1)) {
|
|
|
|
SIGAR_SSTRCPY(info->vendor, CENTOS_VENDOR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-10 11:26:31 +08:00
|
|
|
#define is_quote(c) ((c == '\'') || (c == '"'))
|
|
|
|
|
|
|
|
static void kv_parse(char *data, sigar_sys_info_t *info,
|
|
|
|
void (*func)(sigar_sys_info_t *, char *, char *))
|
2006-09-25 02:23:04 +08:00
|
|
|
{
|
|
|
|
char *ptr = data;
|
|
|
|
int len = strlen(data);
|
|
|
|
char *end = data+len;
|
|
|
|
|
|
|
|
while (ptr < end) {
|
|
|
|
char *val = strchr(ptr, '=');
|
|
|
|
int klen, vlen;
|
|
|
|
char key[256], *ix;
|
|
|
|
|
|
|
|
if (!val) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
klen = val - ptr;
|
|
|
|
SIGAR_SSTRCPY(key, ptr);
|
|
|
|
key[klen] = '\0';
|
|
|
|
++val;
|
|
|
|
|
|
|
|
if ((ix = strchr(val, '\n'))) {
|
|
|
|
*ix = '\0';
|
|
|
|
}
|
|
|
|
vlen = strlen(val);
|
2007-01-10 11:26:31 +08:00
|
|
|
if (is_quote(*val)) {
|
|
|
|
if (is_quote(val[vlen-1])) {
|
|
|
|
val[vlen-1] = '\0';
|
|
|
|
}
|
|
|
|
++val;
|
2006-09-25 02:23:04 +08:00
|
|
|
}
|
|
|
|
|
2007-01-10 11:26:31 +08:00
|
|
|
func(info, key, val);
|
|
|
|
|
2006-09-25 02:23:04 +08:00
|
|
|
ptr += (klen + 1 + vlen + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-10 11:26:31 +08:00
|
|
|
static void lsb_parse(sigar_sys_info_t *info,
|
|
|
|
char *key, char *val)
|
|
|
|
{
|
|
|
|
if (strEQ(key, "DISTRIB_ID")) {
|
|
|
|
SIGAR_SSTRCPY(info->vendor, val);
|
|
|
|
}
|
|
|
|
else if (strEQ(key, "DISTRIB_RELEASE")) {
|
|
|
|
SIGAR_SSTRCPY(info->vendor_version, val);
|
|
|
|
}
|
|
|
|
else if (strEQ(key, "DISTRIB_CODENAME")) {
|
|
|
|
SIGAR_SSTRCPY(info->vendor_code_name, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void lsb_vendor_parse(char *data, sigar_sys_info_t *info)
|
|
|
|
{
|
|
|
|
kv_parse(data, info, lsb_parse);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xen_parse(sigar_sys_info_t *info,
|
|
|
|
char *key, char *val)
|
|
|
|
{
|
|
|
|
if (strEQ(key, "PRODUCT_VERSION")) {
|
|
|
|
SIGAR_SSTRCPY(info->vendor_version, val);
|
|
|
|
}
|
|
|
|
else if (strEQ(key, "KERNEL_VERSION")) {
|
|
|
|
SIGAR_SSTRCPY(info->version, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xen_vendor_parse(char *data, sigar_sys_info_t *info)
|
|
|
|
{
|
|
|
|
kv_parse(data, info, xen_parse);
|
|
|
|
|
|
|
|
snprintf(info->description,
|
|
|
|
sizeof(info->description),
|
|
|
|
"XenServer %s",
|
|
|
|
info->vendor_version);
|
|
|
|
}
|
|
|
|
|
2006-09-25 02:23:04 +08:00
|
|
|
typedef struct {
|
|
|
|
const char *name;
|
|
|
|
const char *file;
|
|
|
|
void (*parse)(char *, sigar_sys_info_t *);
|
|
|
|
} linux_vendor_info_t;
|
|
|
|
|
|
|
|
static linux_vendor_info_t linux_vendors[] = {
|
|
|
|
{ "Fedora", "/etc/fedora-release", NULL },
|
|
|
|
{ "SuSE", "/etc/SuSE-release", NULL },
|
|
|
|
{ "Gentoo", "/etc/gentoo-release", NULL },
|
|
|
|
{ "Slackware", "/etc/slackware-version", NULL },
|
|
|
|
{ "Mandrake", "/etc/mandrake-release", NULL },
|
|
|
|
{ "VMware", "/proc/vmware/version", NULL },
|
2007-01-10 11:26:31 +08:00
|
|
|
{ "XenSource", "/etc/xensource-inventory", xen_vendor_parse },
|
2006-10-21 22:41:16 +08:00
|
|
|
{ "Red Hat", "/etc/redhat-release", redhat_vendor_parse },
|
2006-09-25 02:23:04 +08:00
|
|
|
{ "lsb", "/etc/lsb-release", lsb_vendor_parse },
|
2006-10-18 01:37:58 +08:00
|
|
|
{ "Debian", "/etc/debian_version", NULL },
|
2006-09-25 02:23:04 +08:00
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static int get_linux_vendor_info(sigar_sys_info_t *info)
|
|
|
|
{
|
|
|
|
int i, status = ENOENT;
|
|
|
|
/* env vars for testing */
|
|
|
|
const char *release_file = getenv("SIGAR_OS_RELEASE_FILE");
|
|
|
|
const char *vendor_name = getenv("SIGAR_OS_VENDOR_NAME");
|
|
|
|
char buffer[8192], *data;
|
|
|
|
linux_vendor_info_t *vendor = NULL;
|
|
|
|
|
|
|
|
for (i=0; linux_vendors[i].name; i++) {
|
|
|
|
struct stat sb;
|
|
|
|
vendor = &linux_vendors[i];
|
|
|
|
|
|
|
|
if (release_file && vendor_name) {
|
|
|
|
if (!strEQ(vendor->name, vendor_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (stat(vendor->file, &sb) < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
release_file = vendor->file;
|
|
|
|
}
|
|
|
|
|
|
|
|
status =
|
|
|
|
sigar_file2str(release_file, buffer, sizeof(buffer)-1);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
data = buffer;
|
|
|
|
|
2006-09-25 08:41:23 +08:00
|
|
|
SIGAR_SSTRCPY(info->vendor, vendor->name);
|
|
|
|
|
2006-09-25 02:23:04 +08:00
|
|
|
if (vendor->parse) {
|
|
|
|
vendor->parse(data, info);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
generic_vendor_parse(data, info);
|
|
|
|
}
|
|
|
|
|
2007-01-10 11:26:31 +08:00
|
|
|
if (info->description[0] == '\0') {
|
|
|
|
snprintf(info->description,
|
|
|
|
sizeof(info->description),
|
|
|
|
"%s %s",
|
|
|
|
info->vendor, info->vendor_version);
|
|
|
|
}
|
2006-09-25 08:41:23 +08:00
|
|
|
|
2006-09-25 02:23:04 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_os_sys_info_get(sigar_t *sigar,
|
|
|
|
sigar_sys_info_t *sysinfo)
|
|
|
|
{
|
|
|
|
|
|
|
|
get_linux_vendor_info(sysinfo);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|