sigar/src/os/aix/aix_sigar.c
2009-07-01 15:17:38 -07:00

1928 lines
48 KiB
C

/*
* 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.
*/
/* pull in time.h before resource.h does w/ _KERNEL */
#include <sys/time.h>
#define _KERNEL 1
#include <sys/file.h> /* for struct file */
#include <sys/resource.h> /* for rlimit32 in 64-bit mode */
#undef _KERNEL
#include "sigar.h"
#include "sigar_private.h"
#include "sigar_util.h"
#include "sigar_os.h"
#include <dlfcn.h>
#include <nlist.h>
#include <pthread.h>
#include <stdio.h>
#include <utmp.h>
#include <libperfstat.h>
#include <pthread.h>
#include <sys/statfs.h>
#include <sys/systemcfg.h>
#include <sys/sysinfo.h>
#include <sys/var.h>
#include <sys/vminfo.h>
#include <sys/mntctl.h>
#include <sys/stat.h>
#include <sys/user.h>
#include <sys/utsname.h>
#include <sys/vmount.h>
#include <sys/proc.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
/* for proc_port */
#include <netinet/in_pcb.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socketvar.h>
/* for net_connection_list */
#include <netinet/ip_var.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/tcp_fsm.h>
/* for odm api */
#include <sys/cfgodm.h>
#include <sys/cfgdb.h>
#include <cf.h>
#include <sys/ldr.h>
/* not defined in aix 4.3 */
#ifndef SBITS
#define SBITS 16
#endif
#ifndef PTHRDSINFO_RUSAGE_START
#define PTHRDSINFO_RUSAGE_START 0x00000001
#define PTHRDSINFO_RUSAGE_STOP 0x00000002
#define PTHRDSINFO_RUSAGE_COLLECT 0x00000004
#endif
/*
* from libperfstat.h:
* "To calculate the load average, divide the numbers by (1<<SBITS).
* SBITS is defined in <sys/proc.h>."
*/
#define FIXED_TO_DOUBLE(x) (((double)x) / (1<<SBITS))
/* these offsets wont change so just lookup them up during open */
static int get_koffsets(sigar_t *sigar)
{
int i;
/* see man knlist and nlist.h */
struct nlist klist[] = {
{"avenrun", 0, 0, 0, 0, 0}, /* KOFFSET_LOADAVG */
{"v", 0, 0, 0, 0, 0}, /* KOFFSET_VAR */
{"sysinfo", 0, 0, 0, 0, 0}, /* KOFFSET_SYSINFO */
{"ifnet", 0, 0, 0, 0, 0}, /* KOFFSET_IFNET */
{"vmminfo", 0, 0, 0, 0, 0}, /* KOFFSET_VMINFO */
{"cpuinfo", 0, 0, 0, 0, 0}, /* KOFFSET_CPUINFO */
{"tcb", 0, 0, 0, 0, 0}, /* KOFFSET_TCB */
{NULL, 0, 0, 0, 0, 0}
};
if (knlist(klist,
sizeof(klist) / sizeof(klist[0]),
sizeof(klist[0])) != 0)
{
return errno;
}
for (i=0; i<KOFFSET_MAX; i++) {
sigar->koffsets[i] = klist[i].n_value;
}
return SIGAR_OK;
}
static int kread(sigar_t *sigar, void *data, int size, long offset)
{
if (sigar->kmem < 0) {
return SIGAR_EPERM_KMEM;
}
if (lseek(sigar->kmem, offset, SEEK_SET) != offset) {
return errno;
}
if (read(sigar->kmem, data, size) != size) {
return errno;
}
return SIGAR_OK;
}
static int sigar_thread_rusage(struct rusage *usage, int mode)
{
return pthread_getrusage_np(pthread_self(), usage, mode);
}
static int sigar_perfstat_memory(perfstat_memory_total_t *memory)
{
return perfstat_memory_total(NULL, memory, sizeof(*memory), 1);
}
static int sigar_perfstat_cpu(perfstat_cpu_total_t *cpu_total)
{
return perfstat_cpu_total(NULL, cpu_total, sizeof(*cpu_total), 1);
}
int sigar_os_open(sigar_t **sigar)
{
int status, i;
int kmem = -1;
struct utsname name;
kmem = open("/dev/kmem", O_RDONLY);
*sigar = malloc(sizeof(**sigar));
(*sigar)->getprocfd = NULL; /*XXX*/
(*sigar)->kmem = kmem;
(*sigar)->pagesize = 0;
(*sigar)->ticks = sysconf(_SC_CLK_TCK);
(*sigar)->boot_time = 0;
(*sigar)->last_pid = -1;
(*sigar)->pinfo = NULL;
(*sigar)->cpuinfo = NULL;
(*sigar)->cpuinfo_size = 0;
SIGAR_ZERO(&(*sigar)->swaps);
i = getpagesize();
while ((i >>= 1) > 0) {
(*sigar)->pagesize++;
}
if (kmem > 0) {
if ((status = get_koffsets(*sigar)) != SIGAR_OK) {
/* libperfstat only mode (aix 6) */
close((*sigar)->kmem);
(*sigar)->kmem = -1;
}
}
(*sigar)->cpu_mhz = -1;
(*sigar)->model[0] = '\0';
uname(&name);
(*sigar)->aix_version = atoi(name.version);
(*sigar)->thrusage = PTHRDSINFO_RUSAGE_STOP;
(*sigar)->diskmap = NULL;
return SIGAR_OK;
}
static void swaps_free(swaps_t *swaps);
int sigar_os_close(sigar_t *sigar)
{
swaps_free(&sigar->swaps);
if (sigar->kmem > 0) {
close(sigar->kmem);
}
if (sigar->pinfo) {
free(sigar->pinfo);
}
if (sigar->cpuinfo) {
free(sigar->cpuinfo);
}
if (sigar->diskmap) {
sigar_cache_destroy(sigar->diskmap);
}
if (sigar->thrusage == PTHRDSINFO_RUSAGE_START) {
struct rusage usage;
sigar_thread_rusage(&usage,
PTHRDSINFO_RUSAGE_STOP);
}
free(sigar);
return SIGAR_OK;
}
char *sigar_os_error_string(sigar_t *sigar, int err)
{
switch (err) {
case SIGAR_EPERM_KMEM:
return "Failed to open /dev/kmem for reading";
default:
return NULL;
}
}
#define PAGESHIFT(v) \
((v) << sigar->pagesize)
int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
{
int status;
perfstat_memory_total_t minfo;
if (sigar_perfstat_memory(&minfo) == 1) {
mem->total = PAGESHIFT(minfo.real_total);
mem->free = PAGESHIFT(minfo.real_free);
}
else {
return errno;
}
mem->used = mem->total - mem->free;
mem->actual_used = mem->used;
mem->actual_free = mem->free;
sigar_mem_calc_ram(sigar, mem);
return SIGAR_OK;
}
static void swaps_free(swaps_t *swaps)
{
if (swaps->num) {
int i;
for (i=0; i<swaps->num; i++) {
free(swaps->devs[i]);
}
free(swaps->devs);
swaps->num = 0;
}
}
/*
* there is no public api for parsing this file.
* well, there is something, but its super ugly and requires
* linking 2 static libraries (libodm and something else)
* maybe will switch to that if it can add value elsewhere too.
*/
#define SWAPSPACES "/etc/swapspaces"
static int swaps_get(swaps_t *swaps)
{
FILE *fp;
char buf[512];
char *ptr;
struct stat statbuf;
if (stat(SWAPSPACES, &statbuf) < 0) {
return errno;
}
/* only re-parse if file has changed */
if (swaps->mtime == statbuf.st_mtime) {
return 0;
}
swaps->mtime = statbuf.st_mtime;
/* easier to just start from scratch */
swaps_free(swaps);
if (!(fp = fopen(SWAPSPACES, "r"))) {
return errno;
}
while ((ptr = fgets(buf, sizeof(buf), fp))) {
if (!isalpha(*ptr)) {
continue;
}
if (strchr(ptr, ':')) {
int len;
ptr = fgets(buf, sizeof(buf), fp);
while (isspace(*ptr)) {
++ptr;
}
if (strncmp(ptr, "dev", 3)) {
continue;
}
ptr += 3;
while (isspace(*ptr) || (*ptr == '=')) {
++ptr;
}
len = strlen(ptr);
ptr[len-1] = '\0'; /* -1 == chomp \n */
swaps->devs = realloc(swaps->devs, swaps->num+1 * sizeof(char *));
swaps->devs[swaps->num] = malloc(len);
memcpy(swaps->devs[swaps->num], ptr, len);
swaps->num++;
}
}
fclose(fp);
return 0;
}
/*
* documented in aix tech ref,
* but this prototype is not in any friggin header file.
* struct pginfo is in sys/vminfo.h
*/
int swapqry(char *path, struct pginfo *info);
static int sigar_swap_get_swapqry(sigar_t *sigar, sigar_swap_t *swap)
{
int status, i;
if ((status = swaps_get(&sigar->swaps)) != SIGAR_OK) {
return status;
}
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[swap] pagesize=%d, shift=%d",
getpagesize(), sigar->pagesize);
}
swap->total = swap->free = 0;
for (i=0; i<sigar->swaps.num; i++) {
struct pginfo info;
status = swapqry(sigar->swaps.devs[i], &info);
if (status != 0) {
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[swap] swapqry(%s) failed: %s",
sigar->swaps.devs[i],
sigar_strerror(sigar, errno));
}
continue;
}
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[swap] %s total=%d/%d, free=%d/%d",
sigar->swaps.devs[i],
info.size, PAGESHIFT(info.size),
info.free, PAGESHIFT(info.free));
}
swap->total += PAGESHIFT(info.size); /* lsps -a */
swap->free += PAGESHIFT(info.free);
}
swap->used = swap->total - swap->free;
return SIGAR_OK;
}
#define SWAP_DEV(ps) \
((ps.type == LV_PAGING) ? \
ps.u.lv_paging.vgname : \
ps.u.nfs_paging.filename)
#define SWAP_MB_TO_BYTES(v) ((v) * (1024 * 1024))
int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
{
perfstat_memory_total_t minfo;
perfstat_pagingspace_t ps;
perfstat_id_t id;
id.name[0] = '\0';
SIGAR_ZERO(swap);
do {
if (perfstat_pagingspace(&id, &ps, sizeof(ps), 1) != 1) {
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[swap] dev=%s query failed: %s",
SWAP_DEV(ps),
sigar_strerror(sigar, errno));
}
continue;
}
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"[swap] dev=%s: active=%s, "
"total=%lluMb, used=%lluMb",
SWAP_DEV(ps),
((ps.active == 1) ? "yes" : "no"),
ps.mb_size, ps.mb_used);
}
if (ps.active != 1) {
continue;
}
/* convert MB sizes to bytes */
swap->total += SWAP_MB_TO_BYTES(ps.mb_size);
swap->used += SWAP_MB_TO_BYTES(ps.mb_used);
} while (id.name[0] != '\0');
swap->free = swap->total - swap->used;
if (sigar_perfstat_memory(&minfo) == 1) {
swap->page_in = minfo.pgins;
swap->page_out = minfo.pgouts;
}
else {
swap->page_in = swap->page_out = -1;
}
return SIGAR_OK;
}
int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
int i, status;
struct sysinfo data;
perfstat_cpu_total_t cpu_data;
if (sigar_perfstat_cpu(&cpu_data) == 1) {
cpu->user = SIGAR_TICK2MSEC(cpu_data.user);
cpu->nice = SIGAR_FIELD_NOTIMPL; /* N/A */
cpu->sys = SIGAR_TICK2MSEC(cpu_data.sys);
cpu->idle = SIGAR_TICK2MSEC(cpu_data.idle);
cpu->wait = SIGAR_TICK2MSEC(cpu_data.wait);
cpu->irq = 0; /*N/A*/
cpu->soft_irq = 0; /*N/A*/
cpu->stolen = 0; /*N/A*/
cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait;
return SIGAR_OK;
}
else {
return errno;
}
}
/*
* other possible metrics we could add:
* struct cpuinfo {
* long cpu[CPU_NTIMES];
* long pswitch;
* long syscall;
* long sysread;
* long syswrite;
* long sysfork;
* long sysexec;
* long readch;
* long writech;
* long iget;
* long namei;
* long dirblk;
* long msg;
* long sema;
* long bread;
* long bwrite;
* long lread;
* long lwrite;
* long phread;
* long phwrite;
* };
*/
int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
{
perfstat_cpu_t data;
int i, ncpu = _system_configuration.ncpus; /* this can change */
perfstat_id_t id;
id.name[0] = '\0';
sigar_cpu_list_create(cpulist);
for (i=0; i<ncpu; i++) {
sigar_cpu_t *cpu;
SIGAR_CPU_LIST_GROW(cpulist);
cpu = &cpulist->data[cpulist->number++];
if (SIGAR_LOG_IS_DEBUG(sigar)) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"cpu%d perfstat_id='%s'",
i, id.name);
}
if (perfstat_cpu(&id, &data, sizeof(data), 1) == 1) {
cpu->user = SIGAR_TICK2MSEC(data.user);
cpu->nice = SIGAR_FIELD_NOTIMPL; /* N/A */
cpu->sys = SIGAR_TICK2MSEC(data.sys);
cpu->idle = SIGAR_TICK2MSEC(data.idle);
cpu->wait = SIGAR_TICK2MSEC(data.wait);
cpu->irq = 0; /*N/A*/
cpu->soft_irq = 0; /*N/A*/
cpu->stolen = 0; /*N/A*/
cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait;
}
else {
sigar_log_printf(sigar, SIGAR_LOG_ERROR,
"cpu%d perfstat_cpu(%s) failed: %s",
i, id.name, sigar_strerror(sigar, errno));
SIGAR_ZERO(cpu);
}
}
return SIGAR_OK;
}
static int boot_time(sigar_t *sigar, time_t *time)
{
int fd;
struct utmp data;
if ((fd = open(UTMP_FILE, O_RDONLY)) < 0) {
return errno;
}
do {
if (read(fd, &data, sizeof(data)) != sizeof(data)) {
int status = errno;
close(fd);
return status;
}
} while (data.ut_type != BOOT_TIME);
*time = data.ut_time;
close(fd);
return SIGAR_OK;
}
int sigar_uptime_get(sigar_t *sigar,
sigar_uptime_t *uptime)
{
if (sigar->boot_time == 0) {
int status;
time_t time;
if ((status = boot_time(sigar, &time)) != SIGAR_OK) {
return status;
}
sigar->boot_time = time;
}
uptime->uptime = time(NULL) - sigar->boot_time;
return SIGAR_OK;
}
#define WHOCPY(dest, src) \
SIGAR_SSTRCPY(dest, src); \
if (sizeof(src) < sizeof(dest)) \
dest[sizeof(dest)-1] = '\0'
static int sigar_who_utmp(sigar_t *sigar,
sigar_who_list_t *wholist)
{
struct utmp ut;
FILE *fp;
if (!(fp = fopen(UTMP_FILE, "r"))) {
return errno;
}
while (fread(&ut, sizeof(ut), 1, fp) == 1) {
sigar_who_t *who;
if (*ut.ut_name == '\0') {
continue;
}
if (ut.ut_type != USER_PROCESS) {
continue;
}
SIGAR_WHO_LIST_GROW(wholist);
who = &wholist->data[wholist->number++];
WHOCPY(who->user, ut.ut_user);
WHOCPY(who->device, ut.ut_line);
WHOCPY(who->host, ut.ut_host);
who->time = ut.ut_time;
}
fclose(fp);
return SIGAR_OK;
}
int sigar_who_list_get(sigar_t *sigar,
sigar_who_list_t *wholist)
{
int status;
sigar_who_list_create(wholist);
status = sigar_who_utmp(sigar, wholist);
if (status != SIGAR_OK) {
sigar_who_list_destroy(sigar, wholist);
return status;
}
return SIGAR_OK;
}
int sigar_loadavg_get(sigar_t *sigar,
sigar_loadavg_t *loadavg)
{
int status, i;
int data[3];
perfstat_cpu_total_t cpu_data;
if (sigar_perfstat_cpu(&cpu_data) == 1) {
for (i=0; i<3; i++) {
loadavg->loadavg[i] = FIXED_TO_DOUBLE(cpu_data.loadavg[i]);
}
return SIGAR_OK;
}
else {
return errno;
}
}
int sigar_os_proc_list_get(sigar_t *sigar,
sigar_proc_list_t *proclist)
{
pid_t pid = 0;
struct procsinfo info;
for (;;) {
int num = getprocs(&info, sizeof(info),
NULL, 0, &pid, 1);
if (num == 0) {
break;
}
SIGAR_PROC_LIST_GROW(proclist);
proclist->data[proclist->number++] = info.pi_pid;
}
return SIGAR_OK;
}
static int sigar_getprocs(sigar_t *sigar, sigar_pid_t pid)
{
int status, num;
time_t timenow = time(NULL);
if (sigar->pinfo == NULL) {
sigar->pinfo = malloc(sizeof(*sigar->pinfo));
}
if (sigar->last_pid == pid) {
if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) {
return SIGAR_OK;
}
}
sigar->last_pid = pid;
sigar->last_getprocs = timenow;
num = getprocs(sigar->pinfo, sizeof(*sigar->pinfo),
NULL, 0, &pid, 1);
if (num != 1) {
return ESRCH;
}
return SIGAR_OK;
}
int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_mem_t *procmem)
{
int status = sigar_getprocs(sigar, pid);
struct procsinfo64 *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
procmem->size = PAGESHIFT(pinfo->pi_size); /* XXX fold in pi_dvm ? */
procmem->share = PAGESHIFT(pinfo->pi_sdsize);
procmem->resident = PAGESHIFT(pinfo->pi_drss + pinfo->pi_trss);
procmem->minor_faults = pinfo->pi_minflt;
procmem->major_faults = pinfo->pi_majflt;
procmem->page_faults =
procmem->minor_faults +
procmem->major_faults;
return SIGAR_OK;
}
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_cred_t *proccred)
{
int status = sigar_getprocs(sigar, pid);
struct procsinfo64 *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
proccred->uid = pinfo->pi_cred.cr_ruid;
proccred->euid = pinfo->pi_cred.cr_uid;
if (proccred->uid == -1) {
/*
* aix 5.2 has a process named 'jfsz'
* where uid is '-1', getpwuid returns EPERM
*/
proccred->uid = proccred->euid = 0;
}
proccred->gid = pinfo->pi_cred.cr_rgid;
proccred->egid = pinfo->pi_cred.cr_gid;
return SIGAR_OK;
}
int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_time_t *proctime)
{
int status = sigar_getprocs(sigar, pid);
struct procsinfo64 *pinfo = sigar->pinfo;
if (status != SIGAR_OK) {
return status;
}
proctime->start_time = pinfo->pi_start;
proctime->start_time *= SIGAR_MSEC; /* convert to ms */
proctime->user = pinfo->pi_utime * SIGAR_MSEC;
proctime->sys = pinfo->pi_stime * SIGAR_MSEC;
proctime->total = proctime->user + proctime->sys;
return SIGAR_OK;
}
int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_state_t *procstate)
{
int status = sigar_getprocs(sigar, pid);
struct procsinfo64 *pinfo = sigar->pinfo;
tid_t tid = 0;
struct thrdsinfo64 thrinfo;
if (status != SIGAR_OK) {
return status;
}
if (getthrds(pid, &thrinfo, sizeof(thrinfo), &tid, 1) == 1) {
procstate->processor = thrinfo.ti_affinity;
}
else {
procstate->processor = SIGAR_FIELD_NOTIMPL;
}
SIGAR_SSTRCPY(procstate->name, pinfo->pi_comm);
procstate->ppid = pinfo->pi_ppid;
procstate->nice = pinfo->pi_nice;
procstate->tty = pinfo->pi_ttyd;
procstate->priority = pinfo->pi_pri;
procstate->threads = pinfo->pi_thcount;
switch (pinfo->pi_state) {
case SACTIVE:
procstate->state = 'R';
break;
case SIDL:
procstate->state = 'D';
break;
case SSTOP:
procstate->state = 'S';
break;
case SZOMB:
procstate->state = 'Z';
break;
case SSWAP:
procstate->state = 'S';
break;
}
return SIGAR_OK;
}
int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs)
{
/* XXX if buffer is not large enough args are truncated */
char buffer[8192], *ptr;
struct procsinfo pinfo;
pinfo.pi_pid = pid;
if (getargs(&pinfo, sizeof(pinfo),
buffer, sizeof(buffer)) != 0)
{
return errno;
}
ptr = buffer;
while (*ptr) {
int alen = strlen(ptr)+1;
char *arg = malloc(alen);
SIGAR_PROC_ARGS_GROW(procargs);
memcpy(arg, ptr, alen);
procargs->data[procargs->number++] = arg;
ptr += alen;
}
return SIGAR_OK;
}
int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
/* XXX if buffer is not large enough args are truncated */
char buffer[8192], *ptr;
struct procsinfo pinfo;
pinfo.pi_pid = pid;
if (getevars(&pinfo, sizeof(pinfo),
buffer, sizeof(buffer)) != 0)
{
return errno;
}
ptr = buffer;
while (*ptr) {
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 */
procenv->env_getter(procenv->data, ptr, strlen(ptr), NULL, 0);
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)
{
#ifdef SIGAR_64BIT
/* XXX no getuser() in 64-bit mode */
return SIGAR_ENOTIMPL;
#else
int i;
struct procsinfo pinfo;
struct user uinfo;
procfd->total = 0;
pinfo.pi_pid = pid;
if (getuser(&pinfo, sizeof(pinfo),
&uinfo, sizeof(uinfo)) != 0) {
if (errno == EINVAL) {
return SIGAR_ENOTIMPL; /*XXX 5.2+*/
}
}
/* see sys/user.h */
for (i=0; i<uinfo.U_maxofile; i++) {
if (uinfo.U_ofile(i)) {
procfd->total++;
}
}
return SIGAR_OK;
#endif
}
int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_exe_t *procexe)
{
return SIGAR_ENOTIMPL;
}
static int sigar_proc_modules_local_get(sigar_t *sigar,
sigar_proc_modules_t *procmods)
{
struct ld_info *info;
char *buffer;
int size = 2048, status;
unsigned int offset;
buffer = malloc(size);
while ((loadquery(L_GETINFO, buffer, size) == -1) &&
(errno == ENOMEM))
{
size += 2048;
buffer = realloc(buffer, size);
}
info = (struct ld_info *)buffer;
do {
char *name = info->ldinfo_filename;
status =
procmods->module_getter(procmods->data, name, strlen(name));
if (status != SIGAR_OK) {
/* not an error; just stop iterating */
free(buffer);
return status;
}
offset = info->ldinfo_next;
info = (struct ld_info *)((char*)info + offset);
} while(offset);
free(buffer);
return SIGAR_OK;
}
int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_modules_t *procmods)
{
if (pid == sigar_pid_get(sigar)) {
return sigar_proc_modules_local_get(sigar, procmods);
}
else {
return SIGAR_ENOTIMPL;
}
}
#define SIGAR_MICROSEC2NANO(s) \
((sigar_uint64_t)(s) * (sigar_uint64_t)1000)
#define TIME_NSEC(t) \
(SIGAR_SEC2NANO((t).tv_sec) + SIGAR_MICROSEC2NANO((t).tv_usec))
int sigar_thread_cpu_get(sigar_t *sigar,
sigar_uint64_t id,
sigar_thread_cpu_t *cpu)
{
struct rusage usage;
int retval;
if (sigar->thrusage != PTHRDSINFO_RUSAGE_START) {
sigar->thrusage = PTHRDSINFO_RUSAGE_START;
retval =
sigar_thread_rusage(&usage,
PTHRDSINFO_RUSAGE_START);
if (retval != 0) {
return retval;
}
}
retval =
sigar_thread_rusage(&usage,
PTHRDSINFO_RUSAGE_COLLECT);
if (retval != 0) {
return retval;
}
cpu->user = TIME_NSEC(usage.ru_utime);
cpu->sys = TIME_NSEC(usage.ru_stime);
cpu->total = TIME_NSEC(usage.ru_utime) + TIME_NSEC(usage.ru_stime);
return SIGAR_OK;
}
int sigar_os_fs_type_get(sigar_file_system_t *fsp)
{
return fsp->type;
}
#ifndef MNT_NFS4
/* another one documented in aix tech ref
* with no friggin prototype in any header file...
* ...but added in 5.2
*/
int mntctl(int command, int size, char *buffer);
#endif
int sigar_file_system_list_get(sigar_t *sigar,
sigar_file_system_list_t *fslist)
{
int i, size, num;
char *buf, *mntlist;
/* get required size */
if (mntctl(MCTL_QUERY, sizeof(size), (char *)&size) < 0) {
return errno;
}
mntlist = buf = malloc(size);
if ((num = mntctl(MCTL_QUERY, size, buf)) < 0) {
free(buf);
return errno;
}
sigar_file_system_list_create(fslist);
for (i=0; i<num; i++) {
char *devname;
const char *typename = NULL;
sigar_file_system_t *fsp;
struct vmount *ent = (struct vmount *)mntlist;
mntlist += ent->vmt_length;
SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
fsp = &fslist->data[fslist->number++];
switch (ent->vmt_gfstype) {
case MNT_AIX:
typename = "aix";
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
break;
case MNT_JFS:
typename = "jfs";
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
break;
case MNT_NFS:
case MNT_NFS3:
typename = "nfs";
fsp->type = SIGAR_FSTYPE_NETWORK;
break;
case MNT_CDROM:
fsp->type = SIGAR_FSTYPE_CDROM;
break;
case MNT_SFS:
case MNT_CACHEFS:
case MNT_AUTOFS:
default:
if (ent->vmt_flags & MNT_REMOTE) {
fsp->type = SIGAR_FSTYPE_NETWORK;
}
else {
fsp->type = SIGAR_FSTYPE_NONE;
}
}
SIGAR_SSTRCPY(fsp->dir_name, vmt2dataptr(ent, VMT_STUB));
SIGAR_SSTRCPY(fsp->options, vmt2dataptr(ent, VMT_ARGS));
devname = vmt2dataptr(ent, VMT_OBJECT);
if (fsp->type == SIGAR_FSTYPE_NETWORK) {
char *hostname = vmt2dataptr(ent, VMT_HOSTNAME);
#if 0
/* XXX: these do not seem reliable */
int hostname_len = vmt2datasize(ent, VMT_HOSTNAME)-1; /* -1 == skip '\0' */
int devname_len = vmt2datasize(ent, VMT_OBJECT); /* includes '\0' */
#else
int hostname_len = strlen(hostname);
int devname_len = strlen(devname) + 1;
#endif
int total_len = hostname_len + devname_len + 1; /* 1 == strlen(":") */
if (total_len > sizeof(fsp->dev_name)) {
/* justincase - prevent overflow. chances: slim..none */
SIGAR_SSTRCPY(fsp->dev_name, devname);
}
else {
/* sprintf(fsp->devname, "%s:%s", hostname, devname) */
char *ptr = fsp->dev_name;
memcpy(ptr, hostname, hostname_len);
ptr += hostname_len;
*ptr++ = ':';
memcpy(ptr, devname, devname_len);
}
}
else {
SIGAR_SSTRCPY(fsp->dev_name, devname);
}
/* we set fsp->type, just looking up sigar.c:fstype_names[type] */
sigar_fs_type_get(fsp);
if (typename == NULL) {
typename = fsp->type_name;
}
SIGAR_SSTRCPY(fsp->sys_type_name, typename);
}
free(buf);
return SIGAR_OK;
}
typedef struct {
char name[IDENTIFIER_LENGTH];
long addr;
} aix_diskio_t;
static int create_diskmap(sigar_t *sigar)
{
int i, total, num;
perfstat_disk_t *disk;
perfstat_id_t id;
total = perfstat_disk(NULL, NULL, sizeof(*disk), 0);
if (total < 1) {
return ENOENT;
}
disk = malloc(total * sizeof(*disk));
id.name[0] = '\0';
num = perfstat_disk(&id, disk, sizeof(*disk), total);
if (num < 1) {
free(disk);
return ENOENT;
}
sigar->diskmap = sigar_cache_new(25);
odm_initialize();
for (i=0; i<num; i++) {
char query[256];
struct CuDv *dv, *ptr;
struct listinfo info;
sigar_cache_entry_t *ent;
int j;
snprintf(query, sizeof(query),
"parent = '%s'", disk[i].vgname);
ptr = dv = odm_get_list(CuDv_CLASS, query, &info, 256, 1);
if ((int)dv == -1) {
continue; /* XXX */
}
for (j=0; j<info.num; j++, ptr++) {
struct CuAt *attr;
int num, retval;
struct stat sb;
if ((attr = getattr(ptr->name, "label", 0, &num))) {
retval = stat(attr->value, &sb);
if (retval == 0) {
aix_diskio_t *diskio = malloc(sizeof(*diskio));
SIGAR_SSTRCPY(diskio->name, disk[i].name);
diskio->addr = -1;
ent = sigar_cache_get(sigar->diskmap, SIGAR_FSDEV_ID(sb));
ent->value = diskio;
}
free(attr);
}
}
odm_free_list(dv, &info);
}
free(disk);
odm_terminate();
return SIGAR_OK;
}
int sigar_disk_usage_get(sigar_t *sigar, const char *name,
sigar_disk_usage_t *usage)
{
perfstat_disk_t disk;
perfstat_id_t id;
SIGAR_SSTRCPY(id.name, name);
if (perfstat_disk(&id, &disk, sizeof(disk), 1) != 1) {
return ENOENT;
}
usage->reads = disk.rblks;
usage->writes = disk.wblks;
usage->read_bytes = disk.rblks * disk.bsize;
usage->write_bytes = disk.wblks * disk.bsize;
usage->queue = disk.qdepth;
usage->time = disk.time;
usage->rtime = SIGAR_FIELD_NOTIMPL;
usage->wtime = SIGAR_FIELD_NOTIMPL;
return SIGAR_OK;
}
int sigar_file_system_usage_get(sigar_t *sigar,
const char *dirname,
sigar_file_system_usage_t *fsusage)
{
sigar_cache_entry_t *ent;
struct stat sb;
int status;
status = sigar_statvfs(sigar, dirname, fsusage);
if (status != SIGAR_OK) {
return status;
}
fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
SIGAR_DISK_STATS_INIT(&fsusage->disk);
if (!sigar->diskmap) {
status = create_diskmap(sigar);
if (status != SIGAR_OK) {
return SIGAR_OK;
}
}
status = stat(dirname, &sb);
if (status == 0) {
sigar_cache_entry_t *ent =
sigar_cache_get(sigar->diskmap, SIGAR_FSDEV_ID(sb));
if (!ent->value) {
return SIGAR_OK;
}
sigar_disk_usage_get(sigar, ((aix_diskio_t *)ent->value)->name, &fsusage->disk);
}
return SIGAR_OK;
}
/* from sys/systemcfg.h, not defined in 4.3 headers */
#ifndef POWER_4
#define POWER_4 0x0800
#endif
#ifndef POWER_MPC7450
#define POWER_MPC7450 0x1000
#endif
#ifndef POWER_5
#define POWER_5 0x2000
#endif
static char *sigar_get_odm_model(sigar_t *sigar)
{
if (sigar->model[0] == '\0') {
struct CuAt *odm_obj;
int num;
odm_initialize();
if ((odm_obj = getattr("proc0", "type", 0, &num))) {
SIGAR_SSTRCPY(sigar->model, odm_obj->value);
free(odm_obj);
}
odm_terminate();
}
return sigar->model;
}
#define SIGAR_CPU_CACHE_SIZE \
(_system_configuration.L2_cache_size / 1024)
static int sigar_get_cpu_mhz(sigar_t *sigar)
{
if (sigar->cpu_mhz == SIGAR_FIELD_NOTIMPL) {
perfstat_cpu_total_t data;
if (sigar_perfstat_cpu(&data) == 1) {
sigar->cpu_mhz = data.processorHZ / 1000000;
}
else {
sigar_log_printf(sigar, SIGAR_LOG_ERROR,
"perfstat_cpu_total failed: %s",
sigar_strerror(sigar, errno));
}
}
return sigar->cpu_mhz;
}
static char *get_cpu_arch(void)
{
switch (_system_configuration.architecture) {
case POWER_RS:
return "Power Classic";
case POWER_PC:
return "PowerPC";
case IA64:
return "IA64";
default:
return "PowerPC"; /* what else could it be */
}
}
static char *get_ppc_cpu_model(void)
{
switch (_system_configuration.implementation) {
case POWER_RS1:
return "RS1";
case POWER_RSC:
return "RSC";
case POWER_RS2:
return "RS2";
case POWER_601:
return "601";
case POWER_603:
return "603";
case POWER_604:
return "604";
case POWER_620:
return "620";
case POWER_630:
return "630";
case POWER_A35:
return "A35";
case POWER_RS64II:
return "RS64-II";
case POWER_RS64III:
return "RS64-III";
case POWER_4:
return "POWER4";
case POWER_MPC7450:
return "MPC7450";
case POWER_5:
return "POWER5";
default:
return "Unknown";
}
}
static char *get_ia64_cpu_model(void)
{
switch (_system_configuration.implementation) {
case IA64_M1:
return "M1";
case IA64_M2:
return "M2";
default:
return "Unknown";
}
}
static char *get_cpu_model(void)
{
if (_system_configuration.architecture == IA64) {
return get_ia64_cpu_model();
}
else {
return get_ppc_cpu_model();
}
}
int sigar_cpu_info_list_get(sigar_t *sigar,
sigar_cpu_info_list_t *cpu_infos)
{
int i;
int ncpu = _system_configuration.ncpus; /* this can change */
char *arch = get_cpu_arch(), *model = get_cpu_model();
/*XXX should only do this once*/
sigar_cpu_info_list_create(cpu_infos);
for (i=0; i<ncpu; i++) {
sigar_cpu_info_t *info;
SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
info = &cpu_infos->data[cpu_infos->number++];
info->total_cores = ncpu;
info->cores_per_socket = 1; /*XXX*/
info->total_sockets = ncpu; /*XXX*/
info->cache_size = SIGAR_CPU_CACHE_SIZE;
info->mhz = sigar_get_cpu_mhz(sigar);
if (*arch == 'P') {
SIGAR_SSTRCPY(info->vendor, "IBM");
}
else if (*arch == 'I') {
SIGAR_SSTRCPY(info->vendor, "Intel");
}
else {
SIGAR_SSTRCPY(info->vendor, "Unknown");
}
snprintf(info->model, sizeof(info->model),
"%s %s", arch, model);
}
return SIGAR_OK;
}
int sigar_net_route_list_get(sigar_t *sigar,
sigar_net_route_list_t *routelist)
{
return SIGAR_ENOTIMPL;
}
int sigar_net_interface_stat_get(sigar_t *sigar,
const char *name,
sigar_net_interface_stat_t *ifstat)
{
perfstat_id_t id;
perfstat_netinterface_t data;
sigar_log(sigar, SIGAR_LOG_DEBUG, "[ifstat] using libperfstat");
SIGAR_SSTRCPY(id.name, name);
if (perfstat_netinterface(&id, &data, sizeof(data), 1) == 1) {
ifstat->rx_bytes = data.ibytes;
ifstat->rx_packets = data.ipackets;
ifstat->rx_errors = data.ierrors;
ifstat->rx_dropped = SIGAR_FIELD_NOTIMPL;
ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL;
ifstat->rx_frame = SIGAR_FIELD_NOTIMPL;
ifstat->tx_bytes = data.obytes;
ifstat->tx_packets = data.opackets;
ifstat->tx_errors = data.oerrors;
ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL;
ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL;
ifstat->tx_collisions = data.collisions;
ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL;
ifstat->speed = data.bitrate;
return SIGAR_OK;
}
else {
return errno;
}
}
#define IS_TCP_SERVER(state, flags) \
((flags & SIGAR_NETCONN_SERVER) && (state == TCPS_LISTEN))
#define IS_TCP_CLIENT(state, flags) \
((flags & SIGAR_NETCONN_CLIENT) && (state != TCPS_LISTEN))
static int net_conn_get_tcp(sigar_net_connection_walker_t *walker)
{
sigar_t *sigar = walker->sigar;
int flags = walker->flags;
int status;
struct inpcb tcp_inpcb;
struct tcpcb tcpcb;
struct inpcb *entry;
status = kread(sigar, &tcp_inpcb, sizeof(tcp_inpcb),
sigar->koffsets[KOFFSET_TCB]);
if (status != SIGAR_OK) {
return status;
}
entry = tcp_inpcb.inp_next;
while (entry) {
struct inpcb pcb;
int state;
status = kread(sigar, &pcb, sizeof(pcb), (long)entry);
if (status != SIGAR_OK) {
return status;
}
status = kread(sigar, &tcpcb, sizeof(tcpcb), (long)pcb.inp_ppcb);
if (status != SIGAR_OK) {
return status;
}
state = tcpcb.t_state;
if ((IS_TCP_SERVER(state, flags) ||
IS_TCP_CLIENT(state, flags)))
{
sigar_net_connection_t conn;
SIGAR_ZERO(&conn);
conn.type = SIGAR_NETCONN_TCP;
sigar_net_address_set(conn.local_address,
pcb.inp_laddr.s_addr);
sigar_net_address_set(conn.remote_address,
pcb.inp_faddr.s_addr);
conn.local_port = ntohs(pcb.inp_lport);
conn.remote_port = ntohs(pcb.inp_fport);
conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
switch (state) {
case TCPS_CLOSED:
conn.state = SIGAR_TCP_CLOSE;
break;
case TCPS_LISTEN:
conn.state = SIGAR_TCP_LISTEN;
break;
case TCPS_SYN_SENT:
conn.state = SIGAR_TCP_SYN_SENT;
break;
case TCPS_SYN_RECEIVED:
conn.state = SIGAR_TCP_SYN_RECV;
break;
case TCPS_ESTABLISHED:
conn.state = SIGAR_TCP_ESTABLISHED;
break;
case TCPS_CLOSE_WAIT:
conn.state = SIGAR_TCP_CLOSE_WAIT;
break;
case TCPS_FIN_WAIT_1:
conn.state = SIGAR_TCP_FIN_WAIT1;
break;
case TCPS_CLOSING:
conn.state = SIGAR_TCP_CLOSING;
break;
case TCPS_LAST_ACK:
conn.state = SIGAR_TCP_LAST_ACK;
break;
case TCPS_FIN_WAIT_2:
conn.state = SIGAR_TCP_FIN_WAIT2;
break;
case TCPS_TIME_WAIT:
conn.state = SIGAR_TCP_TIME_WAIT;
break;
default:
conn.state = SIGAR_TCP_UNKNOWN;
break;
}
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
}
entry = pcb.inp_next;
if (entry == tcp_inpcb.inp_next) {
break;
}
}
return SIGAR_OK;
}
int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
{
int status;
if (walker->flags & SIGAR_NETCONN_TCP) {
status = net_conn_get_tcp(walker);
if (status != SIGAR_OK) {
return status;
}
}
#if 0
if (walker->flags & SIGAR_NETCONN_UDP) {
status = net_conn_get_udp(walker);
if (status != SIGAR_OK) {
return status;
}
}
#endif
return SIGAR_OK;
}
SIGAR_DECLARE(int)
sigar_tcp_get(sigar_t *sigar,
sigar_tcp_t *tcp)
{
perfstat_id_t id;
perfstat_protocol_t proto;
SIGAR_SSTRCPY(id.name, "tcp");
if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) {
return ENOENT;
}
tcp->active_opens = proto.u.tcp.initiated;
tcp->passive_opens = proto.u.tcp.accepted;
tcp->attempt_fails = proto.u.tcp.dropped;
tcp->estab_resets = proto.u.tcp.dropped;
tcp->curr_estab = proto.u.tcp.established;
tcp->in_segs = proto.u.tcp.ipackets;
tcp->out_segs = proto.u.tcp.opackets;
tcp->retrans_segs = 0;
tcp->in_errs = proto.u.tcp.ierrors;
tcp->out_rsts = 0;
}
#define NFS_V2_STAT_SET(type) \
nfs->null = proto.u.nfsv2.type.null; \
nfs->getattr = proto.u.nfsv2.type.getattr; \
nfs->setattr = proto.u.nfsv2.type.setattr; \
nfs->root = proto.u.nfsv2.type.root; \
nfs->lookup = proto.u.nfsv2.type.lookup; \
nfs->readlink = proto.u.nfsv2.type.readlink; \
nfs->read = proto.u.nfsv2.type.read; \
nfs->writecache = proto.u.nfsv2.type.writecache; \
nfs->write = proto.u.nfsv2.type.write; \
nfs->create = proto.u.nfsv2.type.create; \
nfs->remove = proto.u.nfsv2.type.remove; \
nfs->rename = proto.u.nfsv2.type.rename; \
nfs->link = proto.u.nfsv2.type.link; \
nfs->symlink = proto.u.nfsv2.type.symlink; \
nfs->mkdir = proto.u.nfsv2.type.mkdir; \
nfs->rmdir = proto.u.nfsv2.type.rmdir; \
nfs->readdir = proto.u.nfsv2.type.readdir; \
nfs->fsstat = proto.u.nfsv2.type.statfs
int sigar_nfs_client_v2_get(sigar_t *sigar,
sigar_nfs_client_v2_t *nfs)
{
perfstat_id_t id;
perfstat_protocol_t proto;
SIGAR_SSTRCPY(id.name, "nfsv2");
if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) {
return ENOENT;
}
NFS_V2_STAT_SET(client);
return SIGAR_OK;
}
int sigar_nfs_server_v2_get(sigar_t *sigar,
sigar_nfs_server_v2_t *nfs)
{
perfstat_id_t id;
perfstat_protocol_t proto;
SIGAR_SSTRCPY(id.name, "nfsv2");
if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) {
return ENOENT;
}
NFS_V2_STAT_SET(server);
return SIGAR_OK;
}
#define NFS_V3_STAT_SET(type) \
nfs->null = proto.u.nfsv3.type.null; \
nfs->getattr = proto.u.nfsv3.type.getattr; \
nfs->setattr = proto.u.nfsv3.type.setattr; \
nfs->lookup = proto.u.nfsv3.type.lookup; \
nfs->access = proto.u.nfsv3.type.access; \
nfs->readlink = proto.u.nfsv3.type.readlink; \
nfs->read = proto.u.nfsv3.type.read; \
nfs->write = proto.u.nfsv3.type.write; \
nfs->create = proto.u.nfsv3.type.create; \
nfs->mkdir = proto.u.nfsv3.type.mkdir; \
nfs->symlink = proto.u.nfsv3.type.symlink; \
nfs->mknod = proto.u.nfsv3.type.mknod; \
nfs->remove = proto.u.nfsv3.type.remove; \
nfs->rmdir = proto.u.nfsv3.type.rmdir; \
nfs->rename = proto.u.nfsv3.type.rename; \
nfs->link = proto.u.nfsv3.type.link; \
nfs->readdir = proto.u.nfsv3.type.readdir; \
nfs->readdirplus = proto.u.nfsv3.type.readdirplus; \
nfs->fsstat = proto.u.nfsv3.type.fsstat; \
nfs->fsinfo = proto.u.nfsv3.type.fsinfo; \
nfs->pathconf = proto.u.nfsv3.type.pathconf; \
nfs->commit = proto.u.nfsv3.type.commit
int sigar_nfs_client_v3_get(sigar_t *sigar,
sigar_nfs_client_v3_t *nfs)
{
perfstat_id_t id;
perfstat_protocol_t proto;
SIGAR_SSTRCPY(id.name, "nfsv3");
if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) {
return ENOENT;
}
NFS_V3_STAT_SET(client);
return SIGAR_OK;
}
int sigar_nfs_server_v3_get(sigar_t *sigar,
sigar_nfs_server_v3_t *nfs)
{
perfstat_id_t id;
perfstat_protocol_t proto;
SIGAR_SSTRCPY(id.name, "nfsv3");
if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) {
return ENOENT;
}
NFS_V3_STAT_SET(server);
return SIGAR_OK;
}
/* derived from pidentd's k_aix432.c */
int sigar_proc_port_get(sigar_t *sigar, int protocol,
unsigned long port, sigar_pid_t *pidp)
{
struct procsinfo pinfo;
struct fdsinfo finfo;
pid_t pid = 0;
int type;
switch (protocol) {
case SIGAR_NETCONN_TCP:
type = IPPROTO_TCP;
break;
case SIGAR_NETCONN_UDP:
type = IPPROTO_UDP;
break;
default:
return SIGAR_ENOTIMPL;
}
for (;;) {
int fd, status;
int num = getprocs(&pinfo, sizeof(pinfo),
&finfo, sizeof(finfo),
&pid, 1);
if (num == 0) {
break;
}
if ((pinfo.pi_state == 0) || (pinfo.pi_state == SZOMB)) {
continue;
}
for (fd = 0; fd < pinfo.pi_maxofile; fd++) {
struct file file;
struct socket socket, *sockp;
struct protosw protosw;
struct domain domain;
struct inpcb inpcb;
long ptr;
if (!(ptr = (long)finfo.pi_ufd[fd].fp)) {
continue;
}
status = kread(sigar, &file, sizeof(file), ptr);
if (status != SIGAR_OK) {
continue;
}
if (file.f_type != DTYPE_SOCKET) {
continue;
}
if (!(sockp = (struct socket *)file.f_data)) {
continue;
}
status = kread(sigar, &socket, sizeof(socket), (long)sockp);
if (status != SIGAR_OK) {
continue;
}
if (!(ptr = (long)socket.so_proto)) {
continue;
}
status = kread(sigar, &protosw, sizeof(protosw), ptr);
if (status != SIGAR_OK) {
continue;
}
if (protosw.pr_protocol != type) {
continue;
}
if (!(ptr = (long)protosw.pr_domain)) {
continue;
}
status = kread(sigar, &domain, sizeof(domain), ptr);
if (status != SIGAR_OK) {
continue;
}
if ((domain.dom_family != AF_INET) &&
domain.dom_family != AF_INET6)
{
continue;
}
if (!(ptr = (long)socket.so_pcb)) {
continue;
}
status = kread(sigar, &inpcb, sizeof(inpcb), ptr);
if (status != SIGAR_OK) {
continue;
}
if (sockp != inpcb.inp_socket) {
continue;
}
if (inpcb.inp_lport != port) {
continue;
}
*pidp = pinfo.pi_pid;
return SIGAR_OK;
}
}
return ENOENT;
}
int sigar_os_sys_info_get(sigar_t *sigar,
sigar_sys_info_t *sysinfo)
{
struct utsname name;
uname(&name);
SIGAR_SSTRCPY(sysinfo->vendor, "IBM");
SIGAR_SSTRCPY(sysinfo->arch, get_cpu_arch());
/* utsname.machine is a sequence number */
/* XXX odm might have something better */
snprintf(sysinfo->machine,
sizeof(sysinfo->machine),
"%s %s",
sysinfo->arch, get_cpu_model());
snprintf(sysinfo->version,
sizeof(sysinfo->version),
"%s.%s",
name.version, name.release);
SIGAR_SSTRCPY(sysinfo->vendor_version, sysinfo->version);
snprintf(sysinfo->description,
sizeof(sysinfo->description),
"%s %s",
sysinfo->name, sysinfo->version);
return SIGAR_OK;
}