3308 lines
84 KiB
C
3308 lines
84 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.
|
|
*/
|
|
|
|
#include "sigar.h"
|
|
#include "sigar_private.h"
|
|
#include "sigar_util.h"
|
|
#include "sigar_os.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/mount.h>
|
|
#include <nfs/rpcv2.h>
|
|
#include <nfs/nfsproto.h>
|
|
|
|
#ifdef DARWIN
|
|
#include <dlfcn.h>
|
|
#include <mach/mach_init.h>
|
|
#include <mach/message.h>
|
|
#include <mach/kern_return.h>
|
|
#include <mach/mach_host.h>
|
|
#include <mach/mach_traps.h>
|
|
#include <mach/mach_port.h>
|
|
#include <mach/task.h>
|
|
#include <mach/thread_act.h>
|
|
#include <mach/thread_info.h>
|
|
#include <mach/vm_map.h>
|
|
#include <mach/shared_memory_server.h>
|
|
#define __OPENTRANSPORTPROVIDERS__
|
|
#include <Gestalt.h>
|
|
#include <CFString.h>
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
#include <IOKit/IOBSD.h>
|
|
#include <IOKit/IOKitLib.h>
|
|
#include <IOKit/IOTypes.h>
|
|
#include <IOKit/storage/IOBlockStorageDriver.h>
|
|
#else
|
|
#include <sys/dkstat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/user.h>
|
|
#include <sys/vmmeter.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
#if defined(__FreeBSD__) && (__FreeBSD_version >= 500013)
|
|
#define SIGAR_FREEBSD5_NFSSTAT
|
|
#include <nfsclient/nfs.h>
|
|
#include <nfsserver/nfs.h>
|
|
#else
|
|
#include <nfs/nfs.h>
|
|
#endif
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/sockio.h>
|
|
|
|
#include <net/if.h>
|
|
#include <net/if_dl.h>
|
|
#include <net/if_types.h>
|
|
#include <net/route.h>
|
|
#include <netinet/in.h>
|
|
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
|
|
#include <sys/socketvar.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/in_systm.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/in_pcb.h>
|
|
#include <netinet/tcp.h>
|
|
#include <netinet/tcp_timer.h>
|
|
#ifdef __NetBSD__
|
|
#include <netinet/ip_var.h>
|
|
#include <sys/lwp.h>
|
|
#include <sys/mount.h>
|
|
#define SRUN LSRUN
|
|
#define SSLEEP LSSLEEP
|
|
#define SDEAD LSDEAD
|
|
#define SONPROC LSONPROC
|
|
#define SSUSPENDED LSSUSPENDED
|
|
#include <sys/sched.h>
|
|
#endif
|
|
#include <netinet/tcp_var.h>
|
|
#include <netinet/tcp_fsm.h>
|
|
|
|
#define NMIB(mib) (sizeof(mib)/sizeof(mib[0]))
|
|
|
|
#ifdef __FreeBSD__
|
|
# if (__FreeBSD_version >= 500013)
|
|
# define SIGAR_FREEBSD5
|
|
# else
|
|
# define SIGAR_FREEBSD4
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(SIGAR_FREEBSD5)
|
|
|
|
#define KI_FD ki_fd
|
|
#define KI_PID ki_pid
|
|
#define KI_PPID ki_ppid
|
|
#define KI_PRI ki_pri.pri_user
|
|
#define KI_NICE ki_nice
|
|
#define KI_COMM ki_comm
|
|
#define KI_STAT ki_stat
|
|
#define KI_UID ki_ruid
|
|
#define KI_GID ki_rgid
|
|
#define KI_EUID ki_svuid
|
|
#define KI_EGID ki_svgid
|
|
#define KI_SIZE ki_size
|
|
#define KI_RSS ki_rssize
|
|
#define KI_TSZ ki_tsize
|
|
#define KI_DSZ ki_dsize
|
|
#define KI_SSZ ki_ssize
|
|
#define KI_FLAG ki_flag
|
|
#define KI_START ki_start
|
|
|
|
#elif defined(DARWIN) || defined(SIGAR_FREEBSD4) || defined(__OpenBSD__) || defined(__NetBSD__)
|
|
|
|
#define KI_FD kp_proc.p_fd
|
|
#define KI_PID kp_proc.p_pid
|
|
#define KI_PPID kp_eproc.e_ppid
|
|
#define KI_PRI kp_proc.p_priority
|
|
#define KI_NICE kp_proc.p_nice
|
|
#define KI_COMM kp_proc.p_comm
|
|
#define KI_STAT kp_proc.p_stat
|
|
#define KI_UID kp_eproc.e_pcred.p_ruid
|
|
#define KI_GID kp_eproc.e_pcred.p_rgid
|
|
#define KI_EUID kp_eproc.e_pcred.p_svuid
|
|
#define KI_EGID kp_eproc.e_pcred.p_svgid
|
|
#define KI_SIZE XXX
|
|
#define KI_RSS kp_eproc.e_vm.vm_rssize
|
|
#define KI_TSZ kp_eproc.e_vm.vm_tsize
|
|
#define KI_DSZ kp_eproc.e_vm.vm_dsize
|
|
#define KI_SSZ kp_eproc.e_vm.vm_ssize
|
|
#define KI_FLAG kp_eproc.e_flag
|
|
#define KI_START kp_proc.p_starttime
|
|
|
|
#endif
|
|
|
|
#ifndef DARWIN
|
|
|
|
#define PROCFS_STATUS(status) \
|
|
((((status) != SIGAR_OK) && !sigar->proc_mounted) ? \
|
|
SIGAR_ENOTIMPL : status)
|
|
|
|
static int get_koffsets(sigar_t *sigar)
|
|
{
|
|
int i;
|
|
struct nlist klist[] = {
|
|
{ "_cp_time" },
|
|
{ "_cnt" },
|
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
|
{ "_tcpstat" },
|
|
{ "_tcbtable" },
|
|
#endif
|
|
{ NULL }
|
|
};
|
|
|
|
if (!sigar->kmem) {
|
|
return SIGAR_EPERM_KMEM;
|
|
}
|
|
|
|
kvm_nlist(sigar->kmem, klist);
|
|
|
|
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) {
|
|
return SIGAR_EPERM_KMEM;
|
|
}
|
|
|
|
if (kvm_read(sigar->kmem, offset, data, size) != size) {
|
|
return errno;
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
#endif
|
|
|
|
int sigar_os_open(sigar_t **sigar)
|
|
{
|
|
int mib[2];
|
|
int ncpu;
|
|
size_t len;
|
|
struct timeval boottime;
|
|
#ifndef DARWIN
|
|
struct stat sb;
|
|
#endif
|
|
|
|
len = sizeof(ncpu);
|
|
mib[0] = CTL_HW;
|
|
mib[1] = HW_NCPU;
|
|
if (sysctl(mib, NMIB(mib), &ncpu, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
len = sizeof(boottime);
|
|
mib[0] = CTL_KERN;
|
|
mib[1] = KERN_BOOTTIME;
|
|
if (sysctl(mib, NMIB(mib), &boottime, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
*sigar = malloc(sizeof(**sigar));
|
|
|
|
#ifdef DARWIN
|
|
(*sigar)->mach_port = mach_host_self();
|
|
# ifdef DARWIN_HAS_LIBPROC_H
|
|
if (((*sigar)->libproc = dlopen("/usr/lib/libproc.dylib", 0))) {
|
|
(*sigar)->proc_pidinfo = dlsym((*sigar)->libproc, "proc_pidinfo");
|
|
(*sigar)->proc_pidfdinfo = dlsym((*sigar)->libproc, "proc_pidfdinfo");
|
|
}
|
|
# endif
|
|
#else
|
|
(*sigar)->kmem = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
|
|
if (stat("/proc/curproc", &sb) < 0) {
|
|
(*sigar)->proc_mounted = 0;
|
|
}
|
|
else {
|
|
(*sigar)->proc_mounted = 1;
|
|
}
|
|
#endif
|
|
|
|
#ifndef DARWIN
|
|
get_koffsets(*sigar);
|
|
#endif
|
|
|
|
(*sigar)->ncpu = ncpu;
|
|
(*sigar)->lcpu = -1;
|
|
|
|
(*sigar)->boot_time = boottime.tv_sec; /* XXX seems off a bit */
|
|
|
|
(*sigar)->pagesize = getpagesize();
|
|
#ifdef __FreeBSD__
|
|
(*sigar)->ticks = 100; /* sysconf(_SC_CLK_TCK) == 128 !? */
|
|
#else
|
|
(*sigar)->ticks = sysconf(_SC_CLK_TCK);
|
|
#endif
|
|
(*sigar)->last_pid = -1;
|
|
|
|
(*sigar)->pinfo = NULL;
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
int sigar_os_close(sigar_t *sigar)
|
|
{
|
|
if (sigar->pinfo) {
|
|
free(sigar->pinfo);
|
|
}
|
|
#ifndef DARWIN
|
|
if (sigar->kmem) {
|
|
kvm_close(sigar->kmem);
|
|
}
|
|
#endif
|
|
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";
|
|
case SIGAR_EPROC_NOENT:
|
|
return "/proc filesystem is not mounted";
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
#if defined(DARWIN)
|
|
static int sigar_vmstat(sigar_t *sigar, vm_statistics_data_t *vmstat)
|
|
{
|
|
kern_return_t status;
|
|
mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t);
|
|
|
|
status = host_statistics(sigar->mach_port, HOST_VM_INFO,
|
|
(host_info_t)vmstat, &count);
|
|
|
|
if (status == KERN_SUCCESS) {
|
|
return SIGAR_OK;
|
|
}
|
|
else {
|
|
return errno;
|
|
}
|
|
}
|
|
#elif defined(__FreeBSD__)
|
|
static int sigar_vmstat(sigar_t *sigar, struct vmmeter *vmstat)
|
|
{
|
|
int status;
|
|
size_t size = sizeof(unsigned int);
|
|
|
|
status = kread(sigar, vmstat, sizeof(*vmstat),
|
|
sigar->koffsets[KOFFSET_VMMETER]);
|
|
|
|
if (status == SIGAR_OK) {
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
SIGAR_ZERO(vmstat);
|
|
|
|
/* derived from src/usr.bin/vmstat/vmstat.c */
|
|
/* only collect the ones we actually use */
|
|
#define GET_VM_STATS(cat, name, used) \
|
|
if (used) sysctlbyname("vm.stats." #cat "." #name, &vmstat->name, &size, NULL, 0)
|
|
|
|
/* sys */
|
|
GET_VM_STATS(sys, v_swtch, 0);
|
|
GET_VM_STATS(sys, v_trap, 0);
|
|
GET_VM_STATS(sys, v_syscall, 0);
|
|
GET_VM_STATS(sys, v_intr, 0);
|
|
GET_VM_STATS(sys, v_soft, 0);
|
|
|
|
/* vm */
|
|
GET_VM_STATS(vm, v_vm_faults, 0);
|
|
GET_VM_STATS(vm, v_cow_faults, 0);
|
|
GET_VM_STATS(vm, v_cow_optim, 0);
|
|
GET_VM_STATS(vm, v_zfod, 0);
|
|
GET_VM_STATS(vm, v_ozfod, 0);
|
|
GET_VM_STATS(vm, v_swapin, 1);
|
|
GET_VM_STATS(vm, v_swapout, 1);
|
|
GET_VM_STATS(vm, v_swappgsin, 0);
|
|
GET_VM_STATS(vm, v_swappgsout, 0);
|
|
GET_VM_STATS(vm, v_vnodein, 1);
|
|
GET_VM_STATS(vm, v_vnodeout, 1);
|
|
GET_VM_STATS(vm, v_vnodepgsin, 0);
|
|
GET_VM_STATS(vm, v_vnodepgsout, 0);
|
|
GET_VM_STATS(vm, v_intrans, 0);
|
|
GET_VM_STATS(vm, v_reactivated, 0);
|
|
GET_VM_STATS(vm, v_pdwakeups, 0);
|
|
GET_VM_STATS(vm, v_pdpages, 0);
|
|
GET_VM_STATS(vm, v_dfree, 0);
|
|
GET_VM_STATS(vm, v_pfree, 0);
|
|
GET_VM_STATS(vm, v_tfree, 0);
|
|
GET_VM_STATS(vm, v_page_size, 0);
|
|
GET_VM_STATS(vm, v_page_count, 0);
|
|
GET_VM_STATS(vm, v_free_reserved, 0);
|
|
GET_VM_STATS(vm, v_free_target, 0);
|
|
GET_VM_STATS(vm, v_free_min, 0);
|
|
GET_VM_STATS(vm, v_free_count, 1);
|
|
GET_VM_STATS(vm, v_wire_count, 0);
|
|
GET_VM_STATS(vm, v_active_count, 0);
|
|
GET_VM_STATS(vm, v_inactive_target, 0);
|
|
GET_VM_STATS(vm, v_inactive_count, 0);
|
|
GET_VM_STATS(vm, v_cache_count, 0);
|
|
GET_VM_STATS(vm, v_cache_min, 0);
|
|
GET_VM_STATS(vm, v_cache_max, 0);
|
|
GET_VM_STATS(vm, v_pageout_free_min, 0);
|
|
GET_VM_STATS(vm, v_interrupt_free_min, 0);
|
|
GET_VM_STATS(vm, v_forks, 0);
|
|
GET_VM_STATS(vm, v_vforks, 0);
|
|
GET_VM_STATS(vm, v_rforks, 0);
|
|
GET_VM_STATS(vm, v_kthreads, 0);
|
|
GET_VM_STATS(vm, v_forkpages, 0);
|
|
GET_VM_STATS(vm, v_vforkpages, 0);
|
|
GET_VM_STATS(vm, v_rforkpages, 0);
|
|
GET_VM_STATS(vm, v_kthreadpages, 0);
|
|
#undef GET_VM_STATS
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
|
static int sigar_vmstat(sigar_t *sigar, struct uvmexp *vmstat)
|
|
{
|
|
size_t size = sizeof(*vmstat);
|
|
int mib[] = { CTL_VM, VM_UVMEXP };
|
|
if (sysctl(mib, NMIB(mib), vmstat, &size, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
else {
|
|
return SIGAR_OK;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
|
|
{
|
|
#ifdef DARWIN
|
|
vm_statistics_data_t vmstat;
|
|
uint64_t mem_total;
|
|
#else
|
|
unsigned long mem_total;
|
|
#endif
|
|
#if defined(__FreeBSD__)
|
|
struct vmmeter vmstat;
|
|
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
|
struct uvmexp vmstat;
|
|
#endif
|
|
int mib[2];
|
|
size_t len;
|
|
int status;
|
|
|
|
mib[0] = CTL_HW;
|
|
|
|
mib[1] = HW_PAGESIZE;
|
|
len = sizeof(sigar->pagesize);
|
|
if (sysctl(mib, NMIB(mib), &sigar->pagesize, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
#ifdef DARWIN
|
|
mib[1] = HW_MEMSIZE;
|
|
#else
|
|
mib[1] = HW_PHYSMEM;
|
|
#endif
|
|
len = sizeof(mem_total);
|
|
if (sysctl(mib, NMIB(mib), &mem_total, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
mem->total = mem_total;
|
|
|
|
#if defined(DARWIN)
|
|
if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
mem->free = vmstat.free_count * sigar->pagesize;
|
|
#elif defined(__FreeBSD__)
|
|
if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) {
|
|
mem->free = vmstat.v_free_count;
|
|
mem->free *= sigar->pagesize;
|
|
}
|
|
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
|
if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
mem->free = vmstat.free;
|
|
#endif
|
|
|
|
mem->used = mem->total - mem->free;
|
|
|
|
mem->actual_free = mem->free;
|
|
mem->actual_used = mem->used;
|
|
|
|
sigar_mem_calc_ram(sigar, mem);
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#define SWI_MAXMIB 3
|
|
|
|
#ifdef SIGAR_FREEBSD5
|
|
/* code in this function is based on FreeBSD 5.3 kvm_getswapinfo.c */
|
|
static int getswapinfo_sysctl(struct kvm_swap *swap_ary,
|
|
int swap_max)
|
|
{
|
|
int ti, ttl;
|
|
size_t mibi, len, size;
|
|
int soid[SWI_MAXMIB];
|
|
struct xswdev xsd;
|
|
struct kvm_swap tot;
|
|
int unswdev, dmmax;
|
|
|
|
/* XXX this can be optimized by using os_open */
|
|
size = sizeof(dmmax);
|
|
if (sysctlbyname("vm.dmmax", &dmmax, &size, NULL, 0) == -1) {
|
|
return errno;
|
|
}
|
|
|
|
mibi = SWI_MAXMIB - 1;
|
|
if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) {
|
|
return errno;
|
|
}
|
|
|
|
bzero(&tot, sizeof(tot));
|
|
for (unswdev = 0;; unswdev++) {
|
|
soid[mibi] = unswdev;
|
|
len = sizeof(xsd);
|
|
if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) {
|
|
if (errno == ENOENT) {
|
|
break;
|
|
}
|
|
return errno;
|
|
}
|
|
#if 0
|
|
if (len != sizeof(xsd)) {
|
|
_kvm_err(kd, kd->program, "struct xswdev has unexpected "
|
|
"size; kernel and libkvm out of sync?");
|
|
return -1;
|
|
}
|
|
if (xsd.xsw_version != XSWDEV_VERSION) {
|
|
_kvm_err(kd, kd->program, "struct xswdev version "
|
|
"mismatch; kernel and libkvm out of sync?");
|
|
return -1;
|
|
}
|
|
#endif
|
|
ttl = xsd.xsw_nblks - dmmax;
|
|
if (unswdev < swap_max - 1) {
|
|
bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev]));
|
|
swap_ary[unswdev].ksw_total = ttl;
|
|
swap_ary[unswdev].ksw_used = xsd.xsw_used;
|
|
swap_ary[unswdev].ksw_flags = xsd.xsw_flags;
|
|
}
|
|
tot.ksw_total += ttl;
|
|
tot.ksw_used += xsd.xsw_used;
|
|
}
|
|
|
|
ti = unswdev;
|
|
if (ti >= swap_max) {
|
|
ti = swap_max - 1;
|
|
}
|
|
if (ti >= 0) {
|
|
swap_ary[ti] = tot;
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
#else
|
|
#define getswapinfo_sysctl(swap_ary, swap_max) SIGAR_ENOTIMPL
|
|
#endif
|
|
|
|
#define SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) ((val * bsize) >> 1)
|
|
|
|
#ifdef DARWIN
|
|
#define VM_DIR "/private/var/vm"
|
|
#define SWAPFILE "swapfile"
|
|
|
|
static int sigar_swap_fs_get(sigar_t *sigar, sigar_swap_t *swap) /* <= 10.3 */
|
|
{
|
|
DIR *dirp;
|
|
struct dirent *ent;
|
|
char swapfile[SSTRLEN(VM_DIR) + SSTRLEN("/") + SSTRLEN(SWAPFILE) + 12];
|
|
struct stat swapstat;
|
|
struct statfs vmfs;
|
|
sigar_uint64_t val, bsize;
|
|
|
|
swap->used = swap->total = swap->free = 0;
|
|
|
|
if (!(dirp = opendir(VM_DIR))) {
|
|
return errno;
|
|
}
|
|
|
|
/* looking for "swapfile0", "swapfile1", etc. */
|
|
while ((ent = readdir(dirp))) {
|
|
char *ptr = swapfile;
|
|
|
|
if ((ent->d_namlen < SSTRLEN(SWAPFILE)+1) || /* n/a, see comment above */
|
|
(ent->d_namlen > SSTRLEN(SWAPFILE)+11)) /* ensure no overflow */
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!strnEQ(ent->d_name, SWAPFILE, SSTRLEN(SWAPFILE))) {
|
|
continue;
|
|
}
|
|
|
|
/* sprintf(swapfile, "%s/%s", VM_DIR, ent->d_name) */
|
|
|
|
memcpy(ptr, VM_DIR, SSTRLEN(VM_DIR));
|
|
ptr += SSTRLEN(VM_DIR);
|
|
|
|
*ptr++ = '/';
|
|
|
|
memcpy(ptr, ent->d_name, ent->d_namlen+1);
|
|
|
|
if (stat(swapfile, &swapstat) < 0) {
|
|
continue;
|
|
}
|
|
|
|
swap->used += swapstat.st_size;
|
|
}
|
|
|
|
closedir(dirp);
|
|
|
|
if (statfs(VM_DIR, &vmfs) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
bsize = vmfs.f_bsize / 512;
|
|
val = vmfs.f_bfree;
|
|
swap->total = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) + swap->used;
|
|
|
|
swap->free = swap->total - swap->used;
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
static int sigar_swap_sysctl_get(sigar_t *sigar, sigar_swap_t *swap)
|
|
|
|
{
|
|
#ifdef VM_SWAPUSAGE /* => 10.4 */
|
|
struct xsw_usage sw_usage;
|
|
size_t size = sizeof(sw_usage);
|
|
int mib[] = { CTL_VM, VM_SWAPUSAGE };
|
|
|
|
if (sysctl(mib, NMIB(mib), &sw_usage, &size, NULL, 0) != 0) {
|
|
return errno;
|
|
}
|
|
|
|
swap->total = sw_usage.xsu_total;
|
|
swap->used = sw_usage.xsu_used;
|
|
swap->free = sw_usage.xsu_avail;
|
|
|
|
return SIGAR_OK;
|
|
#else
|
|
return SIGAR_ENOTIMPL; /* <= 10.3 */
|
|
#endif
|
|
}
|
|
#endif /* DARWIN */
|
|
|
|
int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
|
|
{
|
|
int status;
|
|
#if defined(DARWIN)
|
|
vm_statistics_data_t vmstat;
|
|
|
|
if (sigar_swap_sysctl_get(sigar, swap) != SIGAR_OK) {
|
|
status = sigar_swap_fs_get(sigar, swap); /* <= 10.3 */
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
swap->page_in = vmstat.pageins;
|
|
swap->page_out = vmstat.pageouts;
|
|
#elif defined(__FreeBSD__)
|
|
struct kvm_swap kswap[1];
|
|
struct vmmeter vmstat;
|
|
|
|
if (getswapinfo_sysctl(kswap, 1) != SIGAR_OK) {
|
|
if (!sigar->kmem) {
|
|
return SIGAR_EPERM_KMEM;
|
|
}
|
|
|
|
if (kvm_getswapinfo(sigar->kmem, kswap, 1, 0) < 0) {
|
|
return errno;
|
|
}
|
|
}
|
|
|
|
if (kswap[0].ksw_total == 0) {
|
|
swap->total = 0;
|
|
swap->used = 0;
|
|
swap->free = 0;
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
swap->total = kswap[0].ksw_total * sigar->pagesize;
|
|
swap->used = kswap[0].ksw_used * sigar->pagesize;
|
|
swap->free = swap->total - swap->used;
|
|
|
|
if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) {
|
|
swap->page_in = vmstat.v_swapin + vmstat.v_vnodein;
|
|
swap->page_out = vmstat.v_swapout + vmstat.v_vnodeout;
|
|
}
|
|
else {
|
|
swap->page_in = swap->page_out = -1;
|
|
}
|
|
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
|
struct uvmexp vmstat;
|
|
|
|
if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
swap->total = vmstat.swpages * sigar->pagesize;
|
|
swap->used = vmstat.swpginuse * sigar->pagesize;
|
|
swap->free = swap->total - swap->used;
|
|
swap->page_in = vmstat.pageins;
|
|
swap->page_out = vmstat.pdpageouts;
|
|
#endif
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#ifndef KERN_CPTIME
|
|
#define KERN_CPTIME KERN_CP_TIME
|
|
#endif
|
|
|
|
#if defined(__NetBSD__)
|
|
typedef uint64_t cp_time_t;
|
|
#else
|
|
typedef unsigned long cp_time_t;
|
|
#endif
|
|
|
|
int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
|
|
{
|
|
#if defined(DARWIN)
|
|
kern_return_t status;
|
|
mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
|
|
host_cpu_load_info_data_t cpuload;
|
|
|
|
status = host_statistics(sigar->mach_port, HOST_CPU_LOAD_INFO,
|
|
(host_info_t)&cpuload, &count);
|
|
|
|
if (status != KERN_SUCCESS) {
|
|
return errno;
|
|
}
|
|
|
|
cpu->user = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_USER]);
|
|
cpu->sys = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_SYSTEM]);
|
|
cpu->idle = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_IDLE]);
|
|
cpu->nice = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_NICE]);
|
|
cpu->wait = 0; /*N/A*/
|
|
cpu->irq = 0; /*N/A*/
|
|
cpu->soft_irq = 0; /*N/A*/
|
|
cpu->stolen = 0; /*N/A*/
|
|
cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle;
|
|
|
|
#elif defined(__FreeBSD__) || (__OpenBSD__) || defined(__NetBSD__)
|
|
int status;
|
|
cp_time_t cp_time[CPUSTATES];
|
|
size_t size = sizeof(cp_time);
|
|
|
|
# if defined(__OpenBSD__) || defined(__NetBSD__)
|
|
int mib[] = { CTL_KERN, KERN_CPTIME };
|
|
if (sysctl(mib, NMIB(mib), &cp_time, &size, NULL, 0) == -1) {
|
|
status = errno;
|
|
}
|
|
# else
|
|
/* try sysctl first, does not require /dev/kmem perms */
|
|
if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) == -1) {
|
|
status = kread(sigar, &cp_time, sizeof(cp_time),
|
|
sigar->koffsets[KOFFSET_CPUINFO]);
|
|
}
|
|
# endif
|
|
else {
|
|
status = SIGAR_OK;
|
|
}
|
|
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]);
|
|
cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]);
|
|
cpu->sys = SIGAR_TICK2MSEC(cp_time[CP_SYS]);
|
|
cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]);
|
|
cpu->wait = 0; /*N/A*/
|
|
cpu->irq = SIGAR_TICK2MSEC(cp_time[CP_INTR]);
|
|
cpu->soft_irq = 0; /*N/A*/
|
|
cpu->stolen = 0; /*N/A*/
|
|
cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->irq;
|
|
#endif
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
|
|
{
|
|
#ifdef DARWIN
|
|
kern_return_t status;
|
|
mach_msg_type_number_t count;
|
|
processor_cpu_load_info_data_t *cpuload;
|
|
natural_t i, ncpu;
|
|
|
|
status = host_processor_info(sigar->mach_port,
|
|
PROCESSOR_CPU_LOAD_INFO,
|
|
&ncpu,
|
|
(processor_info_array_t*)&cpuload,
|
|
&count);
|
|
|
|
if (status != KERN_SUCCESS) {
|
|
return errno;
|
|
}
|
|
|
|
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++];
|
|
|
|
cpu->user = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_USER]);
|
|
cpu->sys = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_SYSTEM]);
|
|
cpu->idle = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_IDLE]);
|
|
cpu->nice = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_NICE]);
|
|
cpu->wait = 0; /*N/A*/
|
|
cpu->irq = 0; /*N/A*/
|
|
cpu->soft_irq = 0; /*N/A*/
|
|
cpu->stolen = 0; /*N/A*/
|
|
cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle;
|
|
}
|
|
|
|
vm_deallocate(mach_task_self(), (vm_address_t)cpuload, count);
|
|
|
|
return SIGAR_OK;
|
|
#else
|
|
int status, i;
|
|
sigar_cpu_t *cpu;
|
|
|
|
sigar_cpu_list_create(cpulist);
|
|
|
|
/* XXX howto multi cpu in freebsd?
|
|
* for now just report all metrics on the 1st cpu
|
|
* 0's for the rest
|
|
*/
|
|
cpu = &cpulist->data[cpulist->number++];
|
|
|
|
status = sigar_cpu_get(sigar, cpu);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
for (i=1; i<sigar->ncpu; i++) {
|
|
SIGAR_CPU_LIST_GROW(cpulist);
|
|
|
|
cpu = &cpulist->data[cpulist->number++];
|
|
SIGAR_ZERO(cpu);
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
#endif
|
|
}
|
|
|
|
int sigar_uptime_get(sigar_t *sigar,
|
|
sigar_uptime_t *uptime)
|
|
{
|
|
uptime->uptime = time(NULL) - sigar->boot_time;
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
int sigar_loadavg_get(sigar_t *sigar,
|
|
sigar_loadavg_t *loadavg)
|
|
{
|
|
getloadavg(loadavg->loadavg, 3);
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#if defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H)
|
|
|
|
static int proc_fdinfo_get(sigar_t *sigar, sigar_pid_t pid, int *num)
|
|
{
|
|
int rsize;
|
|
const int init_size = PROC_PIDLISTFD_SIZE * 32;
|
|
|
|
if (!sigar->libproc) {
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
if (sigar->ifconf_len == 0) {
|
|
sigar->ifconf_len = init_size;
|
|
sigar->ifconf_buf = malloc(sigar->ifconf_len);
|
|
}
|
|
|
|
while (1) {
|
|
rsize = sigar->proc_pidinfo(pid, PROC_PIDLISTFDS, 0,
|
|
sigar->ifconf_buf, sigar->ifconf_len);
|
|
if (rsize <= 0) {
|
|
return errno;
|
|
}
|
|
if ((rsize + PROC_PIDLISTFD_SIZE) < sigar->ifconf_len) {
|
|
break;
|
|
}
|
|
|
|
sigar->ifconf_len += init_size;
|
|
sigar->ifconf_buf = realloc(sigar->ifconf_buf, sigar->ifconf_len);
|
|
}
|
|
|
|
*num = rsize / PROC_PIDLISTFD_SIZE;
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef KERN_PROC_PROC
|
|
/* freebsd 4.x */
|
|
#define KERN_PROC_PROC KERN_PROC_ALL
|
|
#endif
|
|
|
|
int sigar_os_proc_list_get(sigar_t *sigar,
|
|
sigar_proc_list_t *proclist)
|
|
{
|
|
#if defined(DARWIN) || defined(SIGAR_FREEBSD5) || defined(__OpenBSD__) || defined(__NetBSD__)
|
|
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
|
|
int i, num;
|
|
size_t len;
|
|
struct kinfo_proc *proc;
|
|
|
|
if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
proc = malloc(len);
|
|
|
|
if (sysctl(mib, NMIB(mib), proc, &len, NULL, 0) < 0) {
|
|
free(proc);
|
|
return errno;
|
|
}
|
|
|
|
num = len/sizeof(*proc);
|
|
|
|
for (i=0; i<num; i++) {
|
|
if (proc[i].KI_FLAG & P_SYSTEM) {
|
|
continue;
|
|
}
|
|
if (proc[i].KI_PID == 0) {
|
|
continue;
|
|
}
|
|
SIGAR_PROC_LIST_GROW(proclist);
|
|
proclist->data[proclist->number++] = proc[i].KI_PID;
|
|
}
|
|
|
|
free(proc);
|
|
|
|
return SIGAR_OK;
|
|
#else
|
|
int i, num;
|
|
struct kinfo_proc *proc;
|
|
|
|
if (!sigar->kmem) {
|
|
return SIGAR_EPERM_KMEM;
|
|
}
|
|
|
|
proc = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &num);
|
|
|
|
for (i=0; i<num; i++) {
|
|
if (proc[i].KI_FLAG & P_SYSTEM) {
|
|
continue;
|
|
}
|
|
SIGAR_PROC_LIST_GROW(proclist);
|
|
proclist->data[proclist->number++] = proc[i].KI_PID;
|
|
}
|
|
#endif
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
static int sigar_get_pinfo(sigar_t *sigar, sigar_pid_t pid)
|
|
{
|
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
|
int mib[] = { CTL_KERN, KERN_PROC2, KERN_PROC_PID, 0, sizeof(*sigar->pinfo), 1 };
|
|
#else
|
|
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
|
|
#endif
|
|
size_t len = sizeof(*sigar->pinfo);
|
|
time_t timenow = time(NULL);
|
|
mib[3] = pid;
|
|
|
|
if (sigar->pinfo == NULL) {
|
|
sigar->pinfo = malloc(len);
|
|
}
|
|
|
|
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;
|
|
|
|
if (sysctl(mib, NMIB(mib), sigar->pinfo, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#ifdef DARWIN
|
|
#define GLOBAL_SHARED_SIZE (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE)
|
|
#endif
|
|
|
|
int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
|
|
sigar_proc_mem_t *procmem)
|
|
{
|
|
#if defined(DARWIN)
|
|
mach_port_t task, self = mach_task_self();
|
|
kern_return_t status;
|
|
task_basic_info_data_t info;
|
|
task_events_info_data_t events;
|
|
mach_msg_type_number_t count;
|
|
# ifdef DARWIN_HAS_LIBPROC_H
|
|
struct proc_taskinfo pti;
|
|
struct proc_regioninfo pri;
|
|
|
|
if (sigar->libproc) {
|
|
int sz =
|
|
sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti));
|
|
|
|
if (sz == sizeof(pti)) {
|
|
procmem->size = pti.pti_virtual_size;
|
|
procmem->resident = pti.pti_resident_size;
|
|
procmem->page_faults = pti.pti_faults;
|
|
procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
|
|
procmem->major_faults = SIGAR_FIELD_NOTIMPL;
|
|
procmem->share = SIGAR_FIELD_NOTIMPL;
|
|
|
|
sz = sigar->proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, &pri, sizeof(pri));
|
|
if (sz == sizeof(pri)) {
|
|
if ((pri.pri_share_mode == SM_EMPTY) &&
|
|
(procmem->size > GLOBAL_SHARED_SIZE))
|
|
{
|
|
procmem->size -= GLOBAL_SHARED_SIZE; /* SIGAR-123 */
|
|
}
|
|
}
|
|
return SIGAR_OK;
|
|
}
|
|
}
|
|
# endif
|
|
|
|
status = task_for_pid(self, pid, &task);
|
|
|
|
if (status != KERN_SUCCESS) {
|
|
return errno;
|
|
}
|
|
|
|
count = TASK_BASIC_INFO_COUNT;
|
|
status = task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count);
|
|
if (status != KERN_SUCCESS) {
|
|
return errno;
|
|
}
|
|
|
|
count = TASK_EVENTS_INFO_COUNT;
|
|
status = task_info(task, TASK_EVENTS_INFO, (task_info_t)&events, &count);
|
|
if (status == KERN_SUCCESS) {
|
|
procmem->page_faults = events.faults;
|
|
}
|
|
else {
|
|
procmem->page_faults = SIGAR_FIELD_NOTIMPL;
|
|
}
|
|
|
|
procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
|
|
procmem->major_faults = SIGAR_FIELD_NOTIMPL;
|
|
|
|
if (task != self) {
|
|
mach_port_deallocate(self, task);
|
|
}
|
|
|
|
procmem->size = info.virtual_size;
|
|
procmem->resident = info.resident_size;
|
|
procmem->share = SIGAR_FIELD_NOTIMPL;
|
|
|
|
return SIGAR_OK;
|
|
#elif defined(__FreeBSD__)
|
|
int status = sigar_get_pinfo(sigar, pid);
|
|
bsd_pinfo_t *pinfo = sigar->pinfo;
|
|
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
procmem->size =
|
|
(pinfo->KI_TSZ + pinfo->KI_DSZ + pinfo->KI_SSZ) * sigar->pagesize;
|
|
|
|
procmem->resident = pinfo->KI_RSS * sigar->pagesize;
|
|
|
|
procmem->share = SIGAR_FIELD_NOTIMPL;
|
|
|
|
procmem->page_faults = SIGAR_FIELD_NOTIMPL;
|
|
procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
|
|
procmem->major_faults = SIGAR_FIELD_NOTIMPL;
|
|
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
|
int status = sigar_get_pinfo(sigar, pid);
|
|
bsd_pinfo_t *pinfo = sigar->pinfo;
|
|
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
procmem->size =
|
|
(pinfo->p_vm_tsize + pinfo->p_vm_dsize + pinfo->p_vm_ssize) * sigar->pagesize;
|
|
|
|
procmem->resident = pinfo->p_vm_rssize * sigar->pagesize;
|
|
|
|
procmem->share = SIGAR_FIELD_NOTIMPL;
|
|
|
|
procmem->minor_faults = pinfo->p_uru_minflt;
|
|
procmem->major_faults = pinfo->p_uru_majflt;
|
|
procmem->page_faults = procmem->minor_faults + procmem->major_faults;
|
|
#endif
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
|
|
sigar_proc_cred_t *proccred)
|
|
{
|
|
int status = sigar_get_pinfo(sigar, pid);
|
|
bsd_pinfo_t *pinfo = sigar->pinfo;
|
|
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
|
proccred->uid = pinfo->p_ruid;
|
|
proccred->gid = pinfo->p_rgid;
|
|
proccred->euid = pinfo->p_uid;
|
|
proccred->egid = pinfo->p_gid;
|
|
#else
|
|
proccred->uid = pinfo->KI_UID;
|
|
proccred->gid = pinfo->KI_GID;
|
|
proccred->euid = pinfo->KI_EUID;
|
|
proccred->egid = pinfo->KI_EGID;
|
|
#endif
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#define tv2msec(tv) \
|
|
(((sigar_uint64_t)tv.tv_sec * SIGAR_MSEC) + (((sigar_uint64_t)tv.tv_usec) / 1000))
|
|
|
|
#ifdef DARWIN
|
|
#define tval2msec(tval) \
|
|
((tval.seconds * SIGAR_MSEC) + (tval.microseconds / 1000))
|
|
|
|
#define tval2nsec(tval) \
|
|
(SIGAR_SEC2NANO((tval).seconds) + SIGAR_MICROSEC2NANO((tval).microseconds))
|
|
|
|
static int get_proc_times(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *time)
|
|
{
|
|
unsigned int count;
|
|
time_value_t utime = {0, 0}, stime = {0, 0};
|
|
task_basic_info_data_t ti;
|
|
task_thread_times_info_data_t tti;
|
|
task_port_t task, self;
|
|
kern_return_t status;
|
|
# ifdef DARWIN_HAS_LIBPROC_H
|
|
if (sigar->libproc) {
|
|
struct proc_taskinfo pti;
|
|
int sz =
|
|
sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti));
|
|
|
|
if (sz == sizeof(pti)) {
|
|
time->user = SIGAR_NSEC2MSEC(pti.pti_total_user);
|
|
time->sys = SIGAR_NSEC2MSEC(pti.pti_total_system);
|
|
time->total = time->user + time->sys;
|
|
return SIGAR_OK;
|
|
}
|
|
}
|
|
# endif
|
|
|
|
self = mach_task_self();
|
|
status = task_for_pid(self, pid, &task);
|
|
if (status != KERN_SUCCESS) {
|
|
return errno;
|
|
}
|
|
|
|
count = TASK_BASIC_INFO_COUNT;
|
|
status = task_info(task, TASK_BASIC_INFO,
|
|
(task_info_t)&ti, &count);
|
|
if (status != KERN_SUCCESS) {
|
|
if (task != self) {
|
|
mach_port_deallocate(self, task);
|
|
}
|
|
return errno;
|
|
}
|
|
|
|
count = TASK_THREAD_TIMES_INFO_COUNT;
|
|
status = task_info(task, TASK_THREAD_TIMES_INFO,
|
|
(task_info_t)&tti, &count);
|
|
if (status != KERN_SUCCESS) {
|
|
if (task != self) {
|
|
mach_port_deallocate(self, task);
|
|
}
|
|
return errno;
|
|
}
|
|
|
|
time_value_add(&utime, &ti.user_time);
|
|
time_value_add(&stime, &ti.system_time);
|
|
time_value_add(&utime, &tti.user_time);
|
|
time_value_add(&stime, &tti.system_time);
|
|
|
|
time->user = tval2msec(utime);
|
|
time->sys = tval2msec(stime);
|
|
time->total = time->user + time->sys;
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
#endif
|
|
|
|
int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
|
|
sigar_proc_time_t *proctime)
|
|
{
|
|
#ifdef SIGAR_FREEBSD4
|
|
struct user user;
|
|
#endif
|
|
int status = sigar_get_pinfo(sigar, pid);
|
|
bsd_pinfo_t *pinfo = sigar->pinfo;
|
|
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
#if defined(DARWIN)
|
|
if ((status = get_proc_times(sigar, pid, proctime)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
proctime->start_time = tv2msec(pinfo->KI_START);
|
|
#elif defined(SIGAR_FREEBSD5)
|
|
proctime->user = tv2msec(pinfo->ki_rusage.ru_utime);
|
|
proctime->sys = tv2msec(pinfo->ki_rusage.ru_stime);
|
|
proctime->total = proctime->user + proctime->sys;
|
|
proctime->start_time = tv2msec(pinfo->KI_START);
|
|
#elif defined(SIGAR_FREEBSD4)
|
|
if (!sigar->kmem) {
|
|
return SIGAR_EPERM_KMEM;
|
|
}
|
|
|
|
status = kread(sigar, &user, sizeof(user),
|
|
(u_long)pinfo->kp_proc.p_addr);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
proctime->user = tv2msec(user.u_stats.p_ru.ru_utime);
|
|
proctime->sys = tv2msec(user.u_stats.p_ru.ru_stime);
|
|
proctime->total = proctime->user + proctime->sys;
|
|
proctime->start_time = tv2msec(user.u_stats.p_start);
|
|
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
|
/* XXX *_usec */
|
|
proctime->user = pinfo->p_uutime_sec * SIGAR_MSEC;
|
|
proctime->sys = pinfo->p_ustime_sec * SIGAR_MSEC;
|
|
proctime->total = proctime->user + proctime->sys;
|
|
proctime->start_time = pinfo->p_ustart_sec * SIGAR_MSEC;
|
|
#endif
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#ifdef DARWIN
|
|
/* thread state mapping derived from ps.tproj */
|
|
static const char const thread_states[] = {
|
|
/*0*/ '-',
|
|
/*1*/ SIGAR_PROC_STATE_RUN,
|
|
/*2*/ SIGAR_PROC_STATE_ZOMBIE,
|
|
/*3*/ SIGAR_PROC_STATE_SLEEP,
|
|
/*4*/ SIGAR_PROC_STATE_IDLE,
|
|
/*5*/ SIGAR_PROC_STATE_STOP,
|
|
/*6*/ SIGAR_PROC_STATE_STOP,
|
|
/*7*/ '?'
|
|
};
|
|
|
|
static int thread_state_get(thread_basic_info_data_t *info)
|
|
{
|
|
switch (info->run_state) {
|
|
case TH_STATE_RUNNING:
|
|
return 1;
|
|
case TH_STATE_UNINTERRUPTIBLE:
|
|
return 2;
|
|
case TH_STATE_WAITING:
|
|
return (info->sleep_time > 20) ? 4 : 3;
|
|
case TH_STATE_STOPPED:
|
|
return 5;
|
|
case TH_STATE_HALTED:
|
|
return 6;
|
|
default:
|
|
return 7;
|
|
}
|
|
}
|
|
|
|
static int sigar_proc_threads_get(sigar_t *sigar, sigar_pid_t pid,
|
|
sigar_proc_state_t *procstate)
|
|
{
|
|
mach_port_t task, self = mach_task_self();
|
|
kern_return_t status;
|
|
thread_array_t threads;
|
|
mach_msg_type_number_t count, i;
|
|
int state = TH_STATE_HALTED + 1;
|
|
|
|
status = task_for_pid(self, pid, &task);
|
|
if (status != KERN_SUCCESS) {
|
|
return errno;
|
|
}
|
|
|
|
status = task_threads(task, &threads, &count);
|
|
if (status != KERN_SUCCESS) {
|
|
return errno;
|
|
}
|
|
|
|
procstate->threads = count;
|
|
|
|
for (i=0; i<count; i++) {
|
|
mach_msg_type_number_t info_count = THREAD_BASIC_INFO_COUNT;
|
|
thread_basic_info_data_t info;
|
|
|
|
status = thread_info(threads[i], THREAD_BASIC_INFO,
|
|
(thread_info_t)&info, &info_count);
|
|
if (status == KERN_SUCCESS) {
|
|
int tstate = thread_state_get(&info);
|
|
if (tstate < state) {
|
|
state = tstate;
|
|
}
|
|
}
|
|
}
|
|
|
|
vm_deallocate(self, (vm_address_t)threads, sizeof(thread_t) * count);
|
|
|
|
procstate->state = thread_states[state];
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
#endif
|
|
|
|
int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
|
|
sigar_proc_state_t *procstate)
|
|
{
|
|
int status = sigar_get_pinfo(sigar, pid);
|
|
bsd_pinfo_t *pinfo = sigar->pinfo;
|
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
|
int state = pinfo->p_stat;
|
|
#else
|
|
int state = pinfo->KI_STAT;
|
|
#endif
|
|
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
|
SIGAR_SSTRCPY(procstate->name, pinfo->p_comm);
|
|
procstate->ppid = pinfo->p_ppid;
|
|
procstate->priority = pinfo->p_priority;
|
|
procstate->nice = pinfo->p_nice;
|
|
procstate->tty = pinfo->p_tdev;
|
|
procstate->threads = SIGAR_FIELD_NOTIMPL;
|
|
procstate->processor = pinfo->p_cpuid;
|
|
#else
|
|
SIGAR_SSTRCPY(procstate->name, pinfo->KI_COMM);
|
|
procstate->ppid = pinfo->KI_PPID;
|
|
procstate->priority = pinfo->KI_PRI;
|
|
procstate->nice = pinfo->KI_NICE;
|
|
procstate->tty = SIGAR_FIELD_NOTIMPL; /*XXX*/
|
|
procstate->threads = SIGAR_FIELD_NOTIMPL;
|
|
procstate->processor = SIGAR_FIELD_NOTIMPL;
|
|
#endif
|
|
|
|
#ifdef DARWIN
|
|
status = sigar_proc_threads_get(sigar, pid, procstate);
|
|
if (status == SIGAR_OK) {
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
switch (state) {
|
|
case SIDL:
|
|
procstate->state = 'D';
|
|
break;
|
|
case SRUN:
|
|
#ifdef SONPROC
|
|
case SONPROC:
|
|
#endif
|
|
procstate->state = 'R';
|
|
break;
|
|
case SSLEEP:
|
|
procstate->state = 'S';
|
|
break;
|
|
case SSTOP:
|
|
procstate->state = 'T';
|
|
break;
|
|
case SZOMB:
|
|
procstate->state = 'Z';
|
|
break;
|
|
default:
|
|
procstate->state = '?';
|
|
break;
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#if defined(DARWIN)
|
|
typedef struct {
|
|
char buffer[8096], *ptr, *end;
|
|
int count;
|
|
} sigar_kern_proc_args_t;
|
|
|
|
/* re-usable hack for use by proc_args and proc_env */
|
|
static int sigar_kern_proc_args_get(sigar_pid_t pid,
|
|
char *exe,
|
|
sigar_kern_proc_args_t *kargs)
|
|
{
|
|
/*
|
|
* derived from:
|
|
* http://darwinsource.opendarwin.org/10.4.1/adv_cmds-79.1/ps.tproj/print.c
|
|
*/
|
|
int mib[3], len;
|
|
size_t size = sizeof(kargs->buffer);
|
|
char *args = kargs->buffer;
|
|
|
|
mib[0] = CTL_KERN;
|
|
mib[1] = KERN_PROCARGS2;
|
|
mib[2] = pid;
|
|
|
|
if (sysctl(mib, NMIB(mib), args, &size, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
kargs->end = &args[size];
|
|
|
|
memcpy(&kargs->count, args, sizeof(kargs->count));
|
|
kargs->ptr = args + sizeof(kargs->count);
|
|
|
|
len = strlen(kargs->ptr);
|
|
if (exe) {
|
|
memcpy(exe, kargs->ptr, len+1);
|
|
}
|
|
kargs->ptr += len+1;
|
|
|
|
if (kargs->ptr == kargs->end) {
|
|
return exe ? SIGAR_OK : ENOENT;
|
|
}
|
|
|
|
for (; kargs->ptr < kargs->end; kargs->ptr++) {
|
|
if (*kargs->ptr != '\0') {
|
|
break; /* start of argv[0] */
|
|
}
|
|
}
|
|
|
|
if (kargs->ptr == kargs->end) {
|
|
return exe ? SIGAR_OK : ENOENT;
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
static int kern_proc_args_skip_argv(sigar_kern_proc_args_t *kargs)
|
|
{
|
|
char *ptr = kargs->ptr;
|
|
char *end = kargs->end;
|
|
int count = kargs->count;
|
|
|
|
/* skip over argv */
|
|
while ((ptr < end) && (count-- > 0)) {
|
|
int alen = strlen(ptr)+1;
|
|
|
|
ptr += alen;
|
|
}
|
|
|
|
kargs->ptr = ptr;
|
|
kargs->end = end;
|
|
kargs->count = 0;
|
|
|
|
if (ptr >= end) {
|
|
return ENOENT;
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
#endif
|
|
|
|
/* ARG_MAX in FreeBSD 6.0 == 262144, which blows up the stack */
|
|
#define SIGAR_ARG_MAX 65536
|
|
|
|
int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
|
|
sigar_proc_args_t *procargs)
|
|
{
|
|
#if defined(DARWIN)
|
|
int status, count;
|
|
sigar_kern_proc_args_t kargs;
|
|
char *ptr, *end;
|
|
|
|
status = sigar_kern_proc_args_get(pid, NULL, &kargs);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
count = kargs.count;
|
|
ptr = kargs.ptr;
|
|
end = kargs.end;
|
|
|
|
while ((ptr < end) && (count-- > 0)) {
|
|
int slen = strlen(ptr);
|
|
int alen = slen+1;
|
|
char *arg;
|
|
|
|
/*
|
|
* trim trailing whitespace.
|
|
* seen w/ postgresql, probably related
|
|
* to messing with argv[0]
|
|
*/
|
|
while (*(ptr + (slen-1)) == ' ') {
|
|
if (--slen <= 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
arg = malloc(slen+1);
|
|
|
|
SIGAR_PROC_ARGS_GROW(procargs);
|
|
memcpy(arg, ptr, slen);
|
|
*(arg+slen) = '\0';
|
|
|
|
procargs->data[procargs->number++] = arg;
|
|
|
|
ptr += alen;
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
|
char buffer[SIGAR_ARG_MAX+1], *ptr=buffer;
|
|
size_t len = sizeof(buffer);
|
|
# ifdef __NetBSD__
|
|
int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV };
|
|
mib[2] = pid;
|
|
# else
|
|
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, 0 };
|
|
mib[3] = pid;
|
|
# endif
|
|
|
|
if (sysctl(mib, NMIB(mib), buffer, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
if (len == 0) {
|
|
procargs->number = 0;
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
buffer[len] = '\0';
|
|
|
|
while (len > 0) {
|
|
int alen = strlen(ptr)+1;
|
|
char *arg = malloc(alen);
|
|
|
|
SIGAR_PROC_ARGS_GROW(procargs);
|
|
memcpy(arg, ptr, alen);
|
|
|
|
procargs->data[procargs->number++] = arg;
|
|
|
|
len -= alen;
|
|
if (len > 0) {
|
|
ptr += alen;
|
|
}
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
#elif defined(__OpenBSD__)
|
|
char buffer[SIGAR_ARG_MAX+1], **ptr=(char **)buffer;
|
|
size_t len = sizeof(buffer);
|
|
int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV };
|
|
mib[2] = pid;
|
|
|
|
if (sysctl(mib, NMIB(mib), buffer, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
if (len == 0) {
|
|
procargs->number = 0;
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
for (; *ptr; ptr++) {
|
|
int alen = strlen(*ptr)+1;
|
|
char *arg = malloc(alen);
|
|
|
|
SIGAR_PROC_ARGS_GROW(procargs);
|
|
memcpy(arg, *ptr, alen);
|
|
|
|
procargs->data[procargs->number++] = arg;
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
#else
|
|
return SIGAR_ENOTIMPL;
|
|
#endif
|
|
}
|
|
|
|
int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
|
|
sigar_proc_env_t *procenv)
|
|
{
|
|
#ifdef DARWIN
|
|
int status, count;
|
|
sigar_kern_proc_args_t kargs;
|
|
char *ptr, *end;
|
|
|
|
status = sigar_kern_proc_args_get(pid, NULL, &kargs);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
status = kern_proc_args_skip_argv(&kargs);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
count = kargs.count;
|
|
ptr = kargs.ptr;
|
|
end = kargs.end;
|
|
|
|
/* into environ */
|
|
while (ptr < end) {
|
|
char *val = strchr(ptr, '=');
|
|
int klen, vlen, status;
|
|
char key[256]; /* 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);
|
|
|
|
if (*ptr == '\0') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
#else
|
|
char **env;
|
|
struct kinfo_proc *pinfo;
|
|
int num;
|
|
|
|
if (!sigar->kmem) {
|
|
return SIGAR_EPERM_KMEM;
|
|
}
|
|
|
|
pinfo = kvm_getprocs(sigar->kmem, KERN_PROC_PID, pid, &num);
|
|
if (!pinfo || (num < 1)) {
|
|
return errno;
|
|
}
|
|
|
|
if (!(env = kvm_getenvv(sigar->kmem, pinfo, 9086))) {
|
|
return errno;
|
|
}
|
|
|
|
while (*env) {
|
|
char *ptr = *env++;
|
|
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;
|
|
#endif
|
|
}
|
|
|
|
int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
|
|
sigar_proc_fd_t *procfd)
|
|
{
|
|
#ifdef __FreeBSD__
|
|
int status;
|
|
bsd_pinfo_t *pinfo;
|
|
struct filedesc filed;
|
|
#if 0
|
|
struct file **ofiles;
|
|
int nfiles, i;
|
|
size_t size;
|
|
#endif
|
|
if (!sigar->kmem) {
|
|
return SIGAR_EPERM_KMEM;
|
|
}
|
|
|
|
if ((status = sigar_get_pinfo(sigar, pid)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
pinfo = sigar->pinfo;
|
|
|
|
status = kread(sigar, &filed, sizeof(filed), (u_long)pinfo->KI_FD);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
#if 0
|
|
nfiles = filed.fd_lastfile+1;
|
|
size = sizeof(*ofiles) * nfiles;
|
|
ofiles = malloc(size);
|
|
status = kread(sigar, ofiles, size, (u_long)filed.fd_ofiles);
|
|
if (status != SIGAR_OK) {
|
|
free(ofiles);
|
|
return status;
|
|
}
|
|
|
|
procfd->total = 0;
|
|
for (i=0; i<filed.fd_lastfile; i++) {
|
|
if (!ofiles[i]) {
|
|
continue;
|
|
}
|
|
procfd->total++;
|
|
}
|
|
|
|
free(ofiles);
|
|
#else
|
|
/* seems the same as the above */
|
|
procfd->total = filed.fd_lastfile;
|
|
#endif
|
|
|
|
return SIGAR_OK;
|
|
#else
|
|
return SIGAR_ENOTIMPL;
|
|
#endif
|
|
}
|
|
|
|
int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
|
|
sigar_proc_exe_t *procexe)
|
|
{
|
|
#ifdef DARWIN
|
|
int status;
|
|
sigar_kern_proc_args_t kargs;
|
|
|
|
status = sigar_kern_proc_args_get(pid, procexe->name, &kargs);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
procexe->cwd[0] = '\0';
|
|
procexe->root[0] = '\0';
|
|
|
|
/* attempt to determine cwd from $PWD */
|
|
status = kern_proc_args_skip_argv(&kargs);
|
|
if (status == SIGAR_OK) {
|
|
char *ptr = kargs.ptr;
|
|
char *end = kargs.end;
|
|
|
|
/* into environ */
|
|
while (ptr < end) {
|
|
int len = strlen(ptr);
|
|
|
|
if ((len > 4) &&
|
|
(ptr[0] == 'P') &&
|
|
(ptr[1] == 'W') &&
|
|
(ptr[2] == 'D') &&
|
|
(ptr[3] == '='))
|
|
{
|
|
memcpy(procexe->cwd, ptr+4, len-3);
|
|
break;
|
|
}
|
|
|
|
ptr += len+1;
|
|
}
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
#else
|
|
int len;
|
|
char name[1024];
|
|
|
|
procexe->cwd[0] = '\0';
|
|
procexe->root[0] = '\0';
|
|
|
|
(void)SIGAR_PROC_FILENAME(name, pid, "/file");
|
|
|
|
if ((len = readlink(name, procexe->name,
|
|
sizeof(procexe->name)-1)) < 0)
|
|
{
|
|
return PROCFS_STATUS(errno);
|
|
}
|
|
|
|
procexe->name[len] = '\0';
|
|
|
|
return SIGAR_OK;
|
|
#endif
|
|
}
|
|
|
|
int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
|
|
sigar_proc_modules_t *procmods)
|
|
{
|
|
#ifdef SIGAR_HAS_DLINFO_MODULES
|
|
if (pid == sigar_pid_get(sigar)) {
|
|
return sigar_dlinfo_modules(sigar, procmods);
|
|
}
|
|
#endif
|
|
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)
|
|
{
|
|
#ifdef DARWIN
|
|
mach_port_t self = mach_thread_self();
|
|
thread_basic_info_data_t info;
|
|
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
|
|
kern_return_t status;
|
|
|
|
status = thread_info(self, THREAD_BASIC_INFO,
|
|
(thread_info_t)&info, &count);
|
|
if (status != KERN_SUCCESS) {
|
|
return errno;
|
|
}
|
|
|
|
mach_port_deallocate(mach_task_self(), self);
|
|
|
|
cpu->user = tval2nsec(info.user_time);
|
|
cpu->sys = tval2nsec(info.system_time);
|
|
cpu->total = cpu->user + cpu->sys;
|
|
#else
|
|
/* XXX this is not per-thread, it is for the whole-process.
|
|
* just want to use for the shell time command at the moment.
|
|
*/
|
|
struct rusage usage;
|
|
getrusage(RUSAGE_SELF, &usage);
|
|
|
|
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);
|
|
#endif
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
int sigar_os_fs_type_get(sigar_file_system_t *fsp)
|
|
{
|
|
char *type = fsp->sys_type_name;
|
|
|
|
/* see sys/disklabel.h */
|
|
switch (*type) {
|
|
case 'f':
|
|
if (strEQ(type, "ffs")) {
|
|
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
|
|
}
|
|
break;
|
|
case 'h':
|
|
if (strEQ(type, "hfs")) {
|
|
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
|
|
}
|
|
break;
|
|
case 'u':
|
|
if (strEQ(type, "ufs")) {
|
|
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return fsp->type;
|
|
}
|
|
|
|
static void get_fs_options(char *opts, int osize, long flags)
|
|
{
|
|
*opts = '\0';
|
|
if (flags & MNT_RDONLY) strncat(opts, "ro", osize);
|
|
else strncat(opts, "rw", osize);
|
|
if (flags & MNT_SYNCHRONOUS) strncat(opts, ",sync", osize);
|
|
if (flags & MNT_NOEXEC) strncat(opts, ",noexec", osize);
|
|
if (flags & MNT_NOSUID) strncat(opts, ",nosuid", osize);
|
|
#ifdef MNT_NODEV
|
|
if (flags & MNT_NODEV) strncat(opts, ",nodev", osize);
|
|
#endif
|
|
#ifdef MNT_UNION
|
|
if (flags & MNT_UNION) strncat(opts, ",union", osize);
|
|
#endif
|
|
if (flags & MNT_ASYNC) strncat(opts, ",async", osize);
|
|
#ifdef MNT_NOATIME
|
|
if (flags & MNT_NOATIME) strncat(opts, ",noatime", osize);
|
|
#endif
|
|
#ifdef MNT_NOCLUSTERR
|
|
if (flags & MNT_NOCLUSTERR) strncat(opts, ",noclusterr", osize);
|
|
#endif
|
|
#ifdef MNT_NOCLUSTERW
|
|
if (flags & MNT_NOCLUSTERW) strncat(opts, ",noclusterw", osize);
|
|
#endif
|
|
#ifdef MNT_NOSYMFOLLOW
|
|
if (flags & MNT_NOSYMFOLLOW) strncat(opts, ",nosymfollow", osize);
|
|
#endif
|
|
#ifdef MNT_SUIDDIR
|
|
if (flags & MNT_SUIDDIR) strncat(opts, ",suiddir", osize);
|
|
#endif
|
|
#ifdef MNT_SOFTDEP
|
|
if (flags & MNT_SOFTDEP) strncat(opts, ",soft-updates", osize);
|
|
#endif
|
|
if (flags & MNT_LOCAL) strncat(opts, ",local", osize);
|
|
if (flags & MNT_QUOTA) strncat(opts, ",quota", osize);
|
|
if (flags & MNT_ROOTFS) strncat(opts, ",rootfs", osize);
|
|
#ifdef MNT_USER
|
|
if (flags & MNT_USER) strncat(opts, ",user", osize);
|
|
#endif
|
|
#ifdef MNT_IGNORE
|
|
if (flags & MNT_IGNORE) strncat(opts, ",ignore", osize);
|
|
#endif
|
|
if (flags & MNT_EXPORTED) strncat(opts, ",nfs", osize);
|
|
}
|
|
|
|
#ifdef __NetBSD__
|
|
#define sigar_statfs statvfs
|
|
#define sigar_getfsstat getvfsstat
|
|
#define sigar_f_flags f_flag
|
|
#else
|
|
#define sigar_statfs statfs
|
|
#define sigar_getfsstat getfsstat
|
|
#define sigar_f_flags f_flags
|
|
#endif
|
|
|
|
int sigar_file_system_list_get(sigar_t *sigar,
|
|
sigar_file_system_list_t *fslist)
|
|
{
|
|
struct sigar_statfs *fs;
|
|
int num, i;
|
|
int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
|
|
long len;
|
|
|
|
if ((num = sigar_getfsstat(NULL, 0, MNT_NOWAIT)) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
len = sizeof(*fs) * num;
|
|
fs = malloc(len);
|
|
|
|
if ((num = sigar_getfsstat(fs, len, MNT_NOWAIT)) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
sigar_file_system_list_create(fslist);
|
|
|
|
for (i=0; i<num; i++) {
|
|
sigar_file_system_t *fsp;
|
|
|
|
#ifdef MNT_AUTOMOUNTED
|
|
if (fs[i].sigar_f_flags & MNT_AUTOMOUNTED) {
|
|
if (is_debug) {
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
"[file_system_list] skipping automounted %s: %s",
|
|
fs[i].f_fstypename, fs[i].f_mntonname);
|
|
}
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
#ifdef MNT_RDONLY
|
|
if (fs[i].sigar_f_flags & MNT_RDONLY) {
|
|
/* e.g. ftp mount or .dmg image */
|
|
if (is_debug) {
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
"[file_system_list] skipping readonly %s: %s",
|
|
fs[i].f_fstypename, fs[i].f_mntonname);
|
|
}
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
|
|
|
|
fsp = &fslist->data[fslist->number++];
|
|
|
|
SIGAR_SSTRCPY(fsp->dir_name, fs[i].f_mntonname);
|
|
SIGAR_SSTRCPY(fsp->dev_name, fs[i].f_mntfromname);
|
|
SIGAR_SSTRCPY(fsp->sys_type_name, fs[i].f_fstypename);
|
|
get_fs_options(fsp->options, sizeof(fsp->options)-1, fs[i].sigar_f_flags);
|
|
|
|
sigar_fs_type_init(fsp);
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#ifdef DARWIN
|
|
#define IoStatGetValue(key, val) \
|
|
if ((number = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatistics##key)))) \
|
|
CFNumberGetValue(number, kCFNumberSInt64Type, &val)
|
|
#endif
|
|
|
|
int sigar_disk_usage_get(sigar_t *sigar, const char *name,
|
|
sigar_disk_usage_t *disk)
|
|
{
|
|
#if defined(DARWIN)
|
|
kern_return_t status;
|
|
io_registry_entry_t parent;
|
|
io_service_t service;
|
|
CFDictionaryRef props;
|
|
CFNumberRef number;
|
|
sigar_iodev_t *iodev = sigar_iodev_get(sigar, name);
|
|
char dname[256], *ptr;
|
|
|
|
SIGAR_DISK_STATS_INIT(disk);
|
|
|
|
if (!iodev) {
|
|
return ESRCH;
|
|
}
|
|
|
|
/* "/dev/disk0s1" -> "disk0" */ /* XXX better way? */
|
|
ptr = &iodev->name[SSTRLEN(SIGAR_DEV_PREFIX)];
|
|
SIGAR_SSTRCPY(dname, ptr);
|
|
ptr = dname;
|
|
if (strnEQ(ptr, "disk", 4)) {
|
|
ptr += 4;
|
|
if ((ptr = strchr(ptr, 's')) && isdigit(*(ptr+1))) {
|
|
*ptr = '\0';
|
|
}
|
|
}
|
|
|
|
if (SIGAR_LOG_IS_DEBUG(sigar)) {
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
"[disk_usage] map %s -> %s",
|
|
iodev->name, dname);
|
|
}
|
|
|
|
/* e.g. name == "disk0" */
|
|
service = IOServiceGetMatchingService(kIOMasterPortDefault,
|
|
IOBSDNameMatching(kIOMasterPortDefault, 0, dname));
|
|
|
|
if (!service) {
|
|
return errno;
|
|
}
|
|
|
|
status = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
|
|
if (status != KERN_SUCCESS) {
|
|
IOObjectRelease(service);
|
|
return status;
|
|
}
|
|
|
|
status = IORegistryEntryCreateCFProperties(parent,
|
|
(CFMutableDictionaryRef *)&props,
|
|
kCFAllocatorDefault,
|
|
kNilOptions);
|
|
if (props) {
|
|
CFDictionaryRef stats =
|
|
(CFDictionaryRef)CFDictionaryGetValue(props,
|
|
CFSTR(kIOBlockStorageDriverStatisticsKey));
|
|
|
|
if (stats) {
|
|
IoStatGetValue(ReadsKey, disk->reads);
|
|
IoStatGetValue(BytesReadKey, disk->read_bytes);
|
|
IoStatGetValue(TotalReadTimeKey, disk->rtime);
|
|
IoStatGetValue(WritesKey, disk->writes);
|
|
IoStatGetValue(BytesWrittenKey, disk->write_bytes);
|
|
IoStatGetValue(TotalWriteTimeKey, disk->wtime);
|
|
disk->time = disk->rtime + disk->wtime;
|
|
}
|
|
|
|
CFRelease(props);
|
|
}
|
|
|
|
IOObjectRelease(service);
|
|
IOObjectRelease(parent);
|
|
|
|
return SIGAR_OK;
|
|
#else
|
|
return SIGAR_ENOTIMPL;
|
|
#endif
|
|
}
|
|
|
|
int sigar_file_system_usage_get(sigar_t *sigar,
|
|
const char *dirname,
|
|
sigar_file_system_usage_t *fsusage)
|
|
{
|
|
struct sigar_statfs buf;
|
|
sigar_uint64_t val, bsize;
|
|
|
|
if (sigar_statfs(dirname, &buf) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
bsize = buf.f_bsize / 512;
|
|
val = buf.f_blocks;
|
|
fsusage->total = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize);
|
|
val = buf.f_bfree;
|
|
fsusage->free = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize);
|
|
val = buf.f_bavail;
|
|
fsusage->avail = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize);
|
|
fsusage->used = fsusage->total - fsusage->free;
|
|
fsusage->files = buf.f_files;
|
|
fsusage->free_files = buf.f_ffree;
|
|
fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
|
|
|
|
#if defined(__FreeBSD__)
|
|
fsusage->disk_reads = buf.f_syncreads + buf.f_asyncreads;
|
|
fsusage->disk_writes = buf.f_syncwrites + buf.f_asyncwrites;
|
|
fsusage->disk_read_bytes = SIGAR_FIELD_NOTIMPL;
|
|
fsusage->disk_write_bytes = SIGAR_FIELD_NOTIMPL;
|
|
fsusage->disk_queue = SIGAR_FIELD_NOTIMPL;
|
|
#elif defined(DARWIN)
|
|
sigar_disk_usage_get(sigar, dirname, &fsusage->disk);
|
|
#else
|
|
SIGAR_DISK_STATS_INIT(&fsusage->disk);
|
|
#endif
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#ifdef DARWIN
|
|
#define CTL_HW_FREQ "hw.cpufrequency"
|
|
#else
|
|
/* XXX FreeBSD 5.x+ only? */
|
|
#define CTL_HW_FREQ "machdep.tsc_freq"
|
|
#endif
|
|
|
|
int sigar_cpu_info_list_get(sigar_t *sigar,
|
|
sigar_cpu_info_list_t *cpu_infos)
|
|
{
|
|
int i;
|
|
unsigned int mhz;
|
|
int cache_size=SIGAR_FIELD_NOTIMPL;
|
|
size_t size;
|
|
char model[128], vendor[128], *ptr;
|
|
|
|
size = sizeof(mhz);
|
|
|
|
(void)sigar_cpu_core_count(sigar);
|
|
|
|
#if defined(DARWIN)
|
|
{
|
|
int mib[] = { CTL_HW, HW_CPU_FREQ };
|
|
size = sizeof(mhz);
|
|
if (sysctl(mib, NMIB(mib), &mhz, &size, NULL, 0) < 0) {
|
|
mhz = SIGAR_FIELD_NOTIMPL;
|
|
}
|
|
}
|
|
#elif defined(__FreeBSD__)
|
|
if (sysctlbyname(CTL_HW_FREQ, &mhz, &size, NULL, 0) < 0) {
|
|
mhz = SIGAR_FIELD_NOTIMPL;
|
|
}
|
|
#else
|
|
/*XXX OpenBSD*/
|
|
mhz = SIGAR_FIELD_NOTIMPL;
|
|
#endif
|
|
|
|
if (mhz != SIGAR_FIELD_NOTIMPL) {
|
|
mhz /= 1000000;
|
|
}
|
|
|
|
size = sizeof(model);
|
|
#ifdef __OpenBSD__
|
|
if (1) {
|
|
#else
|
|
if (sysctlbyname("hw.model", &model, &size, NULL, 0) < 0) {
|
|
#endif
|
|
int mib[] = { CTL_HW, HW_MODEL };
|
|
size = sizeof(model);
|
|
if (sysctl(mib, NMIB(mib), &model[0], &size, NULL, 0) < 0) {
|
|
#ifdef DARWIN
|
|
strcpy(model, "powerpc");
|
|
#else
|
|
strcpy(model, "Unknown");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (mhz == SIGAR_FIELD_NOTIMPL) {
|
|
/* freebsd4 */
|
|
mhz = sigar_cpu_mhz_from_model(model);
|
|
}
|
|
|
|
#ifdef DARWIN
|
|
size = sizeof(vendor);
|
|
if (sysctlbyname("machdep.cpu.vendor", &vendor, &size, NULL, 0) < 0) {
|
|
SIGAR_SSTRCPY(vendor, "Apple");
|
|
}
|
|
else {
|
|
/* GenuineIntel -> Intel */
|
|
if (strstr(vendor, "Intel")) {
|
|
SIGAR_SSTRCPY(vendor, "Intel");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ((ptr = strchr(model, ' '))) {
|
|
if (strstr(model, "Intel")) {
|
|
SIGAR_SSTRCPY(vendor, "Intel");
|
|
}
|
|
else if (strstr(model, "AMD")) {
|
|
SIGAR_SSTRCPY(vendor, "AMD");
|
|
}
|
|
else {
|
|
SIGAR_SSTRCPY(vendor, "Unknown");
|
|
}
|
|
SIGAR_SSTRCPY(model, ptr+1);
|
|
}
|
|
|
|
#ifdef DARWIN
|
|
{
|
|
int mib[] = { CTL_HW, HW_L2CACHESIZE }; /* in bytes */
|
|
size = sizeof(cache_size);
|
|
if (sysctl(mib, NMIB(mib), &cache_size, &size, NULL, 0) < 0) {
|
|
cache_size = SIGAR_FIELD_NOTIMPL;
|
|
}
|
|
else {
|
|
cache_size /= 1024; /* convert to KB */
|
|
}
|
|
}
|
|
#endif
|
|
|
|
sigar_cpu_info_list_create(cpu_infos);
|
|
|
|
for (i=0; i<sigar->ncpu; i++) {
|
|
sigar_cpu_info_t *info;
|
|
|
|
SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
|
|
|
|
info = &cpu_infos->data[cpu_infos->number++];
|
|
|
|
SIGAR_SSTRCPY(info->vendor, vendor);
|
|
SIGAR_SSTRCPY(info->model, model);
|
|
sigar_cpu_model_adjust(sigar, info);
|
|
|
|
info->mhz = mhz;
|
|
info->cache_size = cache_size;
|
|
info->total_cores = sigar->ncpu;
|
|
info->cores_per_socket = sigar->lcpu;
|
|
info->total_sockets = sigar_cpu_socket_count(sigar);
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#define rt_s_addr(sa) ((struct sockaddr_in *)(sa))->sin_addr.s_addr
|
|
|
|
#ifndef SA_SIZE
|
|
#define SA_SIZE(sa) \
|
|
( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
|
|
sizeof(long) : \
|
|
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
|
|
#endif
|
|
|
|
int sigar_net_route_list_get(sigar_t *sigar,
|
|
sigar_net_route_list_t *routelist)
|
|
{
|
|
size_t needed;
|
|
int bit;
|
|
char *buf, *next, *lim;
|
|
struct rt_msghdr *rtm;
|
|
int mib[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 };
|
|
|
|
if (sysctl(mib, NMIB(mib), NULL, &needed, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
buf = malloc(needed);
|
|
|
|
if (sysctl(mib, NMIB(mib), buf, &needed, NULL, 0) < 0) {
|
|
free(buf);
|
|
return errno;
|
|
}
|
|
|
|
sigar_net_route_list_create(routelist);
|
|
|
|
lim = buf + needed;
|
|
for (next = buf; next < lim; next += rtm->rtm_msglen) {
|
|
struct sockaddr *sa;
|
|
sigar_net_route_t *route;
|
|
rtm = (struct rt_msghdr *)next;
|
|
|
|
if (rtm->rtm_type != RTM_GET) {
|
|
continue;
|
|
}
|
|
|
|
sa = (struct sockaddr *)(rtm + 1);
|
|
|
|
if (sa->sa_family != AF_INET) {
|
|
continue;
|
|
}
|
|
|
|
SIGAR_NET_ROUTE_LIST_GROW(routelist);
|
|
route = &routelist->data[routelist->number++];
|
|
SIGAR_ZERO(route);
|
|
|
|
route->flags = rtm->rtm_flags;
|
|
|
|
for (bit=RTA_DST;
|
|
bit && ((char *)sa < lim);
|
|
bit <<= 1)
|
|
{
|
|
if ((rtm->rtm_addrs & bit) == 0) {
|
|
continue;
|
|
}
|
|
switch (bit) {
|
|
case RTA_DST:
|
|
sigar_net_address_set(route->destination,
|
|
rt_s_addr(sa));
|
|
break;
|
|
case RTA_GATEWAY:
|
|
if (sa->sa_family == AF_INET) {
|
|
sigar_net_address_set(route->gateway,
|
|
rt_s_addr(sa));
|
|
}
|
|
break;
|
|
case RTA_NETMASK:
|
|
sigar_net_address_set(route->mask,
|
|
rt_s_addr(sa));
|
|
break;
|
|
case RTA_IFA:
|
|
break;
|
|
}
|
|
|
|
sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
|
|
}
|
|
}
|
|
|
|
free(buf);
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
typedef enum {
|
|
IFMSG_ITER_LIST,
|
|
IFMSG_ITER_GET
|
|
} ifmsg_iter_e;
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
ifmsg_iter_e type;
|
|
union {
|
|
sigar_net_interface_list_t *iflist;
|
|
struct if_msghdr *ifm;
|
|
} data;
|
|
} ifmsg_iter_t;
|
|
|
|
static int sigar_ifmsg_init(sigar_t *sigar)
|
|
{
|
|
int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 };
|
|
size_t len;
|
|
|
|
if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
if (sigar->ifconf_len < len) {
|
|
sigar->ifconf_buf = realloc(sigar->ifconf_buf, len);
|
|
sigar->ifconf_len = len;
|
|
}
|
|
|
|
if (sysctl(mib, NMIB(mib), sigar->ifconf_buf, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
static int sigar_ifmsg_iter(sigar_t *sigar, ifmsg_iter_t *iter)
|
|
{
|
|
char *end = sigar->ifconf_buf + sigar->ifconf_len;
|
|
char *ptr = sigar->ifconf_buf;
|
|
|
|
if (iter->type == IFMSG_ITER_LIST) {
|
|
sigar_net_interface_list_create(iter->data.iflist);
|
|
}
|
|
|
|
while (ptr < end) {
|
|
char *name;
|
|
struct sockaddr_dl *sdl;
|
|
struct if_msghdr *ifm = (struct if_msghdr *)ptr;
|
|
|
|
if (ifm->ifm_type != RTM_IFINFO) {
|
|
break;
|
|
}
|
|
|
|
ptr += ifm->ifm_msglen;
|
|
|
|
while (ptr < end) {
|
|
struct if_msghdr *next = (struct if_msghdr *)ptr;
|
|
|
|
if (next->ifm_type != RTM_NEWADDR) {
|
|
break;
|
|
}
|
|
|
|
ptr += next->ifm_msglen;
|
|
}
|
|
|
|
sdl = (struct sockaddr_dl *)(ifm + 1);
|
|
if (sdl->sdl_family != AF_LINK) {
|
|
continue;
|
|
}
|
|
if (!((sdl->sdl_type == IFT_ETHER) ||
|
|
(sdl->sdl_type == IFT_LOOP)))
|
|
{
|
|
continue; /* XXX deal w/ other weirdo interfaces */
|
|
}
|
|
|
|
switch (iter->type) {
|
|
case IFMSG_ITER_LIST:
|
|
SIGAR_NET_IFLIST_GROW(iter->data.iflist);
|
|
|
|
name = malloc(sdl->sdl_nlen+1);
|
|
memcpy(name, sdl->sdl_data, sdl->sdl_nlen+1);
|
|
|
|
iter->data.iflist->data[iter->data.iflist->number++] = name;
|
|
break;
|
|
|
|
case IFMSG_ITER_GET:
|
|
if (strEQ(iter->name, sdl->sdl_data)) {
|
|
iter->data.ifm = ifm;
|
|
return SIGAR_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (iter->type) {
|
|
case IFMSG_ITER_LIST:
|
|
return SIGAR_OK;
|
|
|
|
case IFMSG_ITER_GET:
|
|
default:
|
|
return ENXIO;
|
|
}
|
|
}
|
|
|
|
int sigar_net_interface_list_get(sigar_t *sigar,
|
|
sigar_net_interface_list_t *iflist)
|
|
{
|
|
int status;
|
|
ifmsg_iter_t iter;
|
|
|
|
if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
iter.type = IFMSG_ITER_LIST;
|
|
iter.data.iflist = iflist;
|
|
|
|
return sigar_ifmsg_iter(sigar, &iter);
|
|
}
|
|
|
|
int sigar_net_interface_config_get(sigar_t *sigar, const char *name,
|
|
sigar_net_interface_config_t *ifconfig)
|
|
{
|
|
int sock;
|
|
int status;
|
|
ifmsg_iter_t iter;
|
|
struct if_msghdr *ifm;
|
|
struct sockaddr_dl *sdl;
|
|
struct ifreq ifr;
|
|
|
|
if (!name) {
|
|
return sigar_net_interface_config_primary_get(sigar, ifconfig);
|
|
}
|
|
|
|
if (sigar->ifconf_len == 0) {
|
|
if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
SIGAR_ZERO(ifconfig);
|
|
|
|
iter.type = IFMSG_ITER_GET;
|
|
iter.name = name;
|
|
|
|
if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
ifm = iter.data.ifm;
|
|
|
|
SIGAR_SSTRCPY(ifconfig->name, name);
|
|
|
|
sdl = (struct sockaddr_dl *)(ifm + 1);
|
|
|
|
sigar_net_address_mac_set(ifconfig->hwaddr,
|
|
LLADDR(sdl),
|
|
sdl->sdl_alen);
|
|
|
|
ifconfig->flags = ifm->ifm_flags;
|
|
ifconfig->mtu = ifm->ifm_data.ifi_mtu;
|
|
ifconfig->metric = ifm->ifm_data.ifi_metric;
|
|
|
|
SIGAR_SSTRCPY(ifr.ifr_name, name);
|
|
|
|
#define ifr_s_addr(ifr) \
|
|
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr
|
|
|
|
if (!ioctl(sock, SIOCGIFADDR, &ifr)) {
|
|
sigar_net_address_set(ifconfig->address,
|
|
ifr_s_addr(ifr));
|
|
}
|
|
|
|
if (!ioctl(sock, SIOCGIFNETMASK, &ifr)) {
|
|
sigar_net_address_set(ifconfig->netmask,
|
|
ifr_s_addr(ifr));
|
|
}
|
|
|
|
if (ifconfig->flags & IFF_LOOPBACK) {
|
|
sigar_net_address_set(ifconfig->destination,
|
|
ifconfig->address.addr.in);
|
|
sigar_net_address_set(ifconfig->broadcast, 0);
|
|
SIGAR_SSTRCPY(ifconfig->type,
|
|
SIGAR_NIC_LOOPBACK);
|
|
}
|
|
else {
|
|
if (!ioctl(sock, SIOCGIFDSTADDR, &ifr)) {
|
|
sigar_net_address_set(ifconfig->destination,
|
|
ifr_s_addr(ifr));
|
|
}
|
|
|
|
if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) {
|
|
sigar_net_address_set(ifconfig->broadcast,
|
|
ifr_s_addr(ifr));
|
|
}
|
|
SIGAR_SSTRCPY(ifconfig->type,
|
|
SIGAR_NIC_ETHERNET);
|
|
}
|
|
|
|
close(sock);
|
|
|
|
/* XXX can we get a better description like win32? */
|
|
SIGAR_SSTRCPY(ifconfig->description,
|
|
ifconfig->name);
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
int sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
|
|
sigar_net_interface_stat_t *ifstat)
|
|
{
|
|
int status;
|
|
ifmsg_iter_t iter;
|
|
struct if_msghdr *ifm;
|
|
|
|
if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
iter.type = IFMSG_ITER_GET;
|
|
iter.name = name;
|
|
|
|
if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
ifm = iter.data.ifm;
|
|
|
|
ifstat->rx_bytes = ifm->ifm_data.ifi_ibytes;
|
|
ifstat->rx_packets = ifm->ifm_data.ifi_ipackets;
|
|
ifstat->rx_errors = ifm->ifm_data.ifi_ierrors;
|
|
ifstat->rx_dropped = ifm->ifm_data.ifi_iqdrops;
|
|
ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL;
|
|
ifstat->rx_frame = SIGAR_FIELD_NOTIMPL;
|
|
|
|
ifstat->tx_bytes = ifm->ifm_data.ifi_obytes;
|
|
ifstat->tx_packets = ifm->ifm_data.ifi_opackets;
|
|
ifstat->tx_errors = ifm->ifm_data.ifi_oerrors;
|
|
ifstat->tx_collisions = ifm->ifm_data.ifi_collisions;
|
|
ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL;
|
|
ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL;
|
|
ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL;
|
|
|
|
ifstat->speed = ifm->ifm_data.ifi_baudrate;
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
static int net_connection_state_get(int state)
|
|
{
|
|
switch (state) {
|
|
case TCPS_CLOSED:
|
|
return SIGAR_TCP_CLOSE;
|
|
case TCPS_LISTEN:
|
|
return SIGAR_TCP_LISTEN;
|
|
case TCPS_SYN_SENT:
|
|
return SIGAR_TCP_SYN_SENT;
|
|
case TCPS_SYN_RECEIVED:
|
|
return SIGAR_TCP_SYN_RECV;
|
|
case TCPS_ESTABLISHED:
|
|
return SIGAR_TCP_ESTABLISHED;
|
|
case TCPS_CLOSE_WAIT:
|
|
return SIGAR_TCP_CLOSE_WAIT;
|
|
case TCPS_FIN_WAIT_1:
|
|
return SIGAR_TCP_FIN_WAIT1;
|
|
case TCPS_CLOSING:
|
|
return SIGAR_TCP_CLOSING;
|
|
case TCPS_LAST_ACK:
|
|
return SIGAR_TCP_LAST_ACK;
|
|
case TCPS_FIN_WAIT_2:
|
|
return SIGAR_TCP_FIN_WAIT2;
|
|
case TCPS_TIME_WAIT:
|
|
return SIGAR_TCP_TIME_WAIT;
|
|
default:
|
|
return SIGAR_TCP_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
|
static int net_connection_get(sigar_net_connection_walker_t *walker, int proto)
|
|
{
|
|
int status;
|
|
int istcp = 0, type;
|
|
int flags = walker->flags;
|
|
struct inpcbtable table;
|
|
struct inpcb *head, *next, *prev;
|
|
sigar_t *sigar = walker->sigar;
|
|
u_long offset;
|
|
|
|
switch (proto) {
|
|
case IPPROTO_TCP:
|
|
offset = sigar->koffsets[KOFFSET_TCBTABLE];
|
|
istcp = 1;
|
|
type = SIGAR_NETCONN_TCP;
|
|
break;
|
|
case IPPROTO_UDP:
|
|
default:
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
|
|
status = kread(sigar, &table, sizeof(table), offset);
|
|
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
prev = head =
|
|
(struct inpcb *)&CIRCLEQ_FIRST(&((struct inpcbtable *)offset)->inpt_queue);
|
|
|
|
next = (struct inpcb *)CIRCLEQ_FIRST(&table.inpt_queue);
|
|
|
|
while (next != head) {
|
|
struct inpcb inpcb;
|
|
struct tcpcb tcpcb;
|
|
struct socket socket;
|
|
|
|
status = kread(sigar, &inpcb, sizeof(inpcb), (long)next);
|
|
prev = next;
|
|
next = (struct inpcb *)CIRCLEQ_NEXT(&inpcb, inp_queue);
|
|
|
|
kread(sigar, &socket, sizeof(socket), (u_long)inpcb.inp_socket);
|
|
|
|
if ((((flags & SIGAR_NETCONN_SERVER) && socket.so_qlimit) ||
|
|
((flags & SIGAR_NETCONN_CLIENT) && !socket.so_qlimit)))
|
|
{
|
|
sigar_net_connection_t conn;
|
|
|
|
SIGAR_ZERO(&conn);
|
|
|
|
if (istcp) {
|
|
kread(sigar, &tcpcb, sizeof(tcpcb), (u_long)inpcb.inp_ppcb);
|
|
}
|
|
|
|
#ifdef __NetBSD__
|
|
if (inpcb.inp_af == AF_INET6) {
|
|
/*XXX*/
|
|
continue;
|
|
}
|
|
#else
|
|
if (inpcb.inp_flags & INP_IPV6) {
|
|
sigar_net_address6_set(conn.local_address,
|
|
&inpcb.inp_laddr6.s6_addr);
|
|
|
|
sigar_net_address6_set(conn.remote_address,
|
|
&inpcb.inp_faddr6.s6_addr);
|
|
}
|
|
#endif
|
|
else {
|
|
sigar_net_address_set(conn.local_address,
|
|
inpcb.inp_laddr.s_addr);
|
|
|
|
sigar_net_address_set(conn.remote_address,
|
|
inpcb.inp_faddr.s_addr);
|
|
}
|
|
|
|
conn.local_port = ntohs(inpcb.inp_lport);
|
|
conn.remote_port = ntohs(inpcb.inp_fport);
|
|
conn.receive_queue = socket.so_rcv.sb_cc;
|
|
conn.send_queue = socket.so_snd.sb_cc;
|
|
conn.uid = socket.so_pgid;
|
|
conn.type = type;
|
|
|
|
if (!istcp) {
|
|
conn.state = SIGAR_TCP_UNKNOWN;
|
|
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
conn.state = net_connection_state_get(tcpcb.t_state);
|
|
|
|
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
#else
|
|
static int net_connection_get(sigar_net_connection_walker_t *walker, int proto)
|
|
{
|
|
int flags = walker->flags;
|
|
int type, istcp = 0;
|
|
char *buf;
|
|
const char *mibvar;
|
|
struct tcpcb *tp = NULL;
|
|
struct inpcb *inp;
|
|
struct xinpgen *xig, *oxig;
|
|
struct xsocket *so;
|
|
size_t len;
|
|
|
|
switch (proto) {
|
|
case IPPROTO_TCP:
|
|
mibvar = "net.inet.tcp.pcblist";
|
|
istcp = 1;
|
|
type = SIGAR_NETCONN_TCP;
|
|
break;
|
|
case IPPROTO_UDP:
|
|
mibvar = "net.inet.udp.pcblist";
|
|
type = SIGAR_NETCONN_UDP;
|
|
break;
|
|
default:
|
|
mibvar = "net.inet.raw.pcblist";
|
|
type = SIGAR_NETCONN_RAW;
|
|
break;
|
|
}
|
|
|
|
len = 0;
|
|
if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
|
|
return errno;
|
|
}
|
|
if ((buf = malloc(len)) == 0) {
|
|
return errno;
|
|
}
|
|
if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
|
|
free(buf);
|
|
return errno;
|
|
}
|
|
|
|
oxig = xig = (struct xinpgen *)buf;
|
|
for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
|
|
xig->xig_len > sizeof(struct xinpgen);
|
|
xig = (struct xinpgen *)((char *)xig + xig->xig_len))
|
|
{
|
|
if (istcp) {
|
|
struct xtcpcb *cb = (struct xtcpcb *)xig;
|
|
tp = &cb->xt_tp;
|
|
inp = &cb->xt_inp;
|
|
so = &cb->xt_socket;
|
|
}
|
|
else {
|
|
struct xinpcb *cb = (struct xinpcb *)xig;
|
|
inp = &cb->xi_inp;
|
|
so = &cb->xi_socket;
|
|
}
|
|
|
|
if (so->xso_protocol != proto) {
|
|
continue;
|
|
}
|
|
|
|
if (inp->inp_gencnt > oxig->xig_gen) {
|
|
continue;
|
|
}
|
|
|
|
if ((((flags & SIGAR_NETCONN_SERVER) && so->so_qlimit) ||
|
|
((flags & SIGAR_NETCONN_CLIENT) && !so->so_qlimit)))
|
|
{
|
|
sigar_net_connection_t conn;
|
|
|
|
SIGAR_ZERO(&conn);
|
|
|
|
if (inp->inp_vflag & INP_IPV6) {
|
|
sigar_net_address6_set(conn.local_address,
|
|
&inp->in6p_laddr.s6_addr);
|
|
|
|
sigar_net_address6_set(conn.remote_address,
|
|
&inp->in6p_faddr.s6_addr);
|
|
}
|
|
else {
|
|
sigar_net_address_set(conn.local_address,
|
|
inp->inp_laddr.s_addr);
|
|
|
|
sigar_net_address_set(conn.remote_address,
|
|
inp->inp_faddr.s_addr);
|
|
}
|
|
|
|
conn.local_port = ntohs(inp->inp_lport);
|
|
conn.remote_port = ntohs(inp->inp_fport);
|
|
conn.receive_queue = so->so_rcv.sb_cc;
|
|
conn.send_queue = so->so_snd.sb_cc;
|
|
conn.uid = so->so_pgid;
|
|
conn.type = type;
|
|
|
|
if (!istcp) {
|
|
conn.state = SIGAR_TCP_UNKNOWN;
|
|
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
conn.state = net_connection_state_get(tp->t_state);
|
|
|
|
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
free(buf);
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
#endif
|
|
|
|
int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
|
|
{
|
|
int flags = walker->flags;
|
|
int status;
|
|
|
|
if (flags & SIGAR_NETCONN_TCP) {
|
|
status = net_connection_get(walker, IPPROTO_TCP);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
if (flags & SIGAR_NETCONN_UDP) {
|
|
status = net_connection_get(walker, IPPROTO_UDP);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
SIGAR_DECLARE(int)
|
|
sigar_tcp_get(sigar_t *sigar,
|
|
sigar_tcp_t *tcp)
|
|
{
|
|
struct tcpstat mib;
|
|
#if !defined(TCPCTL_STATS) && (defined(__OpenBSD__) || defined(__NetBSD__))
|
|
int status =
|
|
kread(sigar, &mib, sizeof(mib),
|
|
sigar->koffsets[KOFFSET_TCPSTAT]);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
#else
|
|
int var[4] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS };
|
|
size_t len = sizeof(mib);
|
|
|
|
if (sysctl(var, NMIB(var), &mib, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
#endif
|
|
|
|
tcp->active_opens = mib.tcps_connattempt;
|
|
tcp->passive_opens = mib.tcps_accepts;
|
|
tcp->attempt_fails = mib.tcps_conndrops;
|
|
tcp->estab_resets = mib.tcps_drops;
|
|
if (sigar_tcp_curr_estab(sigar, tcp) != SIGAR_OK) {
|
|
tcp->curr_estab = -1;
|
|
}
|
|
tcp->in_segs = mib.tcps_rcvtotal;
|
|
tcp->out_segs = mib.tcps_sndtotal - mib.tcps_sndrexmitpack;
|
|
tcp->retrans_segs = mib.tcps_sndrexmitpack;
|
|
tcp->in_errs =
|
|
mib.tcps_rcvbadsum +
|
|
mib.tcps_rcvbadoff +
|
|
mib.tcps_rcvmemdrop +
|
|
mib.tcps_rcvshort;
|
|
tcp->out_rsts = -1; /* XXX mib.tcps_sndctrl - mib.tcps_closed; ? */
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#ifndef SIGAR_FREEBSD5_NFSSTAT
|
|
static int get_nfsstats(struct nfsstats *stats)
|
|
{
|
|
size_t len = sizeof(*stats);
|
|
int mib[] = { CTL_VFS, 2, NFS_NFSSTATS };
|
|
|
|
if (sysctl(mib, NMIB(mib), stats, &len, NULL, 0) < 0) {
|
|
return errno;
|
|
}
|
|
else {
|
|
return SIGAR_OK;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(__OpenBSD__)
|
|
typedef uint64_t rpc_cnt_t;
|
|
#else
|
|
typedef int rpc_cnt_t;
|
|
#endif
|
|
|
|
static void map_nfs_stats(sigar_nfs_v3_t *nfs, rpc_cnt_t *rpc)
|
|
{
|
|
nfs->null = rpc[NFSPROC_NULL];
|
|
nfs->getattr = rpc[NFSPROC_GETATTR];
|
|
nfs->setattr = rpc[NFSPROC_SETATTR];
|
|
nfs->lookup = rpc[NFSPROC_LOOKUP];
|
|
nfs->access = rpc[NFSPROC_ACCESS];
|
|
nfs->readlink = rpc[NFSPROC_READLINK];
|
|
nfs->read = rpc[NFSPROC_READ];
|
|
nfs->write = rpc[NFSPROC_WRITE];
|
|
nfs->create = rpc[NFSPROC_CREATE];
|
|
nfs->mkdir = rpc[NFSPROC_MKDIR];
|
|
nfs->symlink = rpc[NFSPROC_SYMLINK];
|
|
nfs->mknod = rpc[NFSPROC_MKNOD];
|
|
nfs->remove = rpc[NFSPROC_REMOVE];
|
|
nfs->rmdir = rpc[NFSPROC_RMDIR];
|
|
nfs->rename = rpc[NFSPROC_RENAME];
|
|
nfs->link = rpc[NFSPROC_LINK];
|
|
nfs->readdir = rpc[NFSPROC_READDIR];
|
|
nfs->readdirplus = rpc[NFSPROC_READDIRPLUS];
|
|
nfs->fsstat = rpc[NFSPROC_FSSTAT];
|
|
nfs->fsinfo = rpc[NFSPROC_FSINFO];
|
|
nfs->pathconf = rpc[NFSPROC_PATHCONF];
|
|
nfs->commit = rpc[NFSPROC_COMMIT];
|
|
}
|
|
|
|
int sigar_nfs_client_v2_get(sigar_t *sigar,
|
|
sigar_nfs_client_v2_t *nfs)
|
|
{
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
int sigar_nfs_server_v2_get(sigar_t *sigar,
|
|
sigar_nfs_server_v2_t *nfs)
|
|
{
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
int sigar_nfs_client_v3_get(sigar_t *sigar,
|
|
sigar_nfs_client_v3_t *nfs)
|
|
{
|
|
#ifdef SIGAR_FREEBSD5_NFSSTAT
|
|
struct nfsstats stats;
|
|
size_t size = sizeof(stats);
|
|
|
|
if (sysctlbyname("vfs.nfs.nfsstats", &stats, &size, NULL, 0) == -1) {
|
|
return errno;
|
|
}
|
|
|
|
map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.rpccnt[0]);
|
|
#else
|
|
int status;
|
|
struct nfsstats stats;
|
|
|
|
if ((status = get_nfsstats(&stats)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.rpccnt[0]);
|
|
#endif
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
int sigar_nfs_server_v3_get(sigar_t *sigar,
|
|
sigar_nfs_server_v3_t *nfs)
|
|
{
|
|
#ifdef SIGAR_FREEBSD5_NFSSTAT
|
|
struct nfsrvstats stats;
|
|
size_t size = sizeof(stats);
|
|
|
|
if (sysctlbyname("vfs.nfsrv.nfsrvstats", &stats, &size, NULL, 0) == -1) {
|
|
return errno;
|
|
}
|
|
|
|
map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.srvrpccnt[0]);
|
|
#else
|
|
int status;
|
|
struct nfsstats stats;
|
|
|
|
if ((status = get_nfsstats(&stats)) != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.srvrpccnt[0]);
|
|
#endif
|
|
|
|
return SIGAR_OK;
|
|
}
|
|
|
|
#if defined(__FreeBSD__)
|
|
|
|
#define _KERNEL
|
|
#include <sys/file.h>
|
|
#undef _KERNEL
|
|
|
|
/* derived from
|
|
* /usr/ports/security/pidentd/work/pidentd-3.0.16/src/k_freebsd2.c
|
|
*/
|
|
int sigar_proc_port_get(sigar_t *sigar, int protocol,
|
|
unsigned long port, sigar_pid_t *pid)
|
|
{
|
|
struct nlist nl[2];
|
|
struct inpcbhead tcb;
|
|
struct socket *sockp = NULL;
|
|
struct kinfo_proc *pinfo;
|
|
struct inpcb *head, pcbp;
|
|
int i, nentries, status;
|
|
|
|
if (protocol != SIGAR_NETCONN_TCP) {
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
if (!sigar->kmem) {
|
|
return SIGAR_EPERM_KMEM;
|
|
}
|
|
|
|
nl[0].n_name = "_tcb"; /* XXX cache */
|
|
nl[1].n_name = "";
|
|
if (kvm_nlist(sigar->kmem, nl) < 0) {
|
|
return errno;
|
|
}
|
|
|
|
status = kread(sigar, &tcb, sizeof(tcb), nl[0].n_value);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
for (head = tcb.lh_first; head != NULL;
|
|
head = pcbp.inp_list.le_next)
|
|
{
|
|
status = kread(sigar, &pcbp, sizeof(pcbp), (long)head);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
if (!(pcbp.inp_vflag & INP_IPV4)) {
|
|
continue;
|
|
}
|
|
if (pcbp.inp_fport != 0) {
|
|
continue;
|
|
}
|
|
if (ntohs(pcbp.inp_lport) == port) {
|
|
sockp = pcbp.inp_socket;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!sockp) {
|
|
return ENOENT;
|
|
}
|
|
|
|
pinfo = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &nentries);
|
|
if (!pinfo) {
|
|
return errno;
|
|
}
|
|
|
|
for (i=0; i<nentries; i++) {
|
|
if (pinfo[i].KI_FLAG & P_SYSTEM) {
|
|
continue;
|
|
}
|
|
if (pinfo[i].KI_FD) {
|
|
struct filedesc pfd;
|
|
struct file **ofiles, ofile;
|
|
int j, osize;
|
|
|
|
status = kread(sigar, &pfd, sizeof(pfd), (long)pinfo[i].KI_FD);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
osize = pfd.fd_nfiles * sizeof(struct file *);
|
|
ofiles = malloc(osize); /* XXX reuse */
|
|
if (!ofiles) {
|
|
return errno;
|
|
}
|
|
|
|
status = kread(sigar, ofiles, osize, (long)pfd.fd_ofiles);
|
|
if (status != SIGAR_OK) {
|
|
free(ofiles);
|
|
return status;
|
|
}
|
|
|
|
for (j=0; j<pfd.fd_nfiles; j++) {
|
|
if (!ofiles[j]) {
|
|
continue;
|
|
}
|
|
|
|
status = kread(sigar, &ofile, sizeof(ofile), (long)ofiles[j]);
|
|
if (status != SIGAR_OK) {
|
|
free(ofiles);
|
|
return status;
|
|
}
|
|
|
|
if (ofile.f_count == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (ofile.f_type == DTYPE_SOCKET &&
|
|
(struct socket *)ofile.f_data == sockp)
|
|
{
|
|
*pid = pinfo[i].KI_PID;
|
|
free(ofiles);
|
|
return SIGAR_OK;
|
|
}
|
|
}
|
|
|
|
free(ofiles);
|
|
}
|
|
}
|
|
|
|
return ENOENT;
|
|
}
|
|
|
|
#elif defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H)
|
|
|
|
int sigar_proc_port_get(sigar_t *sigar, int protocol,
|
|
unsigned long port, sigar_pid_t *pid)
|
|
{
|
|
sigar_proc_list_t pids;
|
|
int i, status, found=0;
|
|
|
|
if (!sigar->libproc) {
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
status = sigar_proc_list_get(sigar, &pids);
|
|
if (status != SIGAR_OK) {
|
|
return status;
|
|
}
|
|
|
|
for (i=0; i<pids.number; i++) {
|
|
int n, num=0;
|
|
struct proc_fdinfo *fdinfo;
|
|
|
|
status = proc_fdinfo_get(sigar, pids.data[i], &num);
|
|
if (status != SIGAR_OK) {
|
|
continue;
|
|
}
|
|
fdinfo = (struct proc_fdinfo *)sigar->ifconf_buf;
|
|
|
|
for (n=0; n<num; n++) {
|
|
struct proc_fdinfo *fdp = &fdinfo[n];
|
|
struct socket_fdinfo si;
|
|
int rsize, family;
|
|
unsigned long lport;
|
|
|
|
if (fdp->proc_fdtype != PROX_FDTYPE_SOCKET) {
|
|
continue;
|
|
}
|
|
rsize = sigar->proc_pidfdinfo(pids.data[i], fdp->proc_fd,
|
|
PROC_PIDFDSOCKETINFO, &si, sizeof(si));
|
|
if (rsize != sizeof(si)) {
|
|
continue;
|
|
}
|
|
if (si.psi.soi_kind != SOCKINFO_TCP) {
|
|
continue;
|
|
}
|
|
if (si.psi.soi_proto.pri_tcp.tcpsi_state != TSI_S_LISTEN) {
|
|
continue;
|
|
}
|
|
family = si.psi.soi_family;
|
|
if (!((family == AF_INET) || (family == AF_INET6))) {
|
|
continue;
|
|
}
|
|
lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport);
|
|
if (lport == port) {
|
|
*pid = pids.data[i];
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
sigar_proc_list_destroy(sigar, &pids);
|
|
|
|
return found ? SIGAR_OK : ENOENT;
|
|
}
|
|
|
|
#else
|
|
|
|
int sigar_proc_port_get(sigar_t *sigar, int protocol,
|
|
unsigned long port, sigar_pid_t *pid)
|
|
{
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
#endif
|
|
|
|
int sigar_os_sys_info_get(sigar_t *sigar,
|
|
sigar_sys_info_t *sysinfo)
|
|
{
|
|
#ifdef DARWIN
|
|
char *codename = NULL;
|
|
long version, version_major, version_minor, version_fix;
|
|
|
|
SIGAR_SSTRCPY(sysinfo->name, "MacOSX");
|
|
SIGAR_SSTRCPY(sysinfo->vendor_name, "Mac OS X");
|
|
SIGAR_SSTRCPY(sysinfo->vendor, "Apple");
|
|
|
|
if (Gestalt(gestaltSystemVersion, &version) == noErr) {
|
|
if (version >= 0x00001040) {
|
|
Gestalt('sys1' /*gestaltSystemVersionMajor*/, &version_major);
|
|
Gestalt('sys2' /*gestaltSystemVersionMinor*/, &version_minor);
|
|
Gestalt('sys3' /*gestaltSystemVersionBugFix*/, &version_fix);
|
|
}
|
|
else {
|
|
version_fix = version & 0xf;
|
|
version >>= 4;
|
|
version_minor = version & 0xf;
|
|
version >>= 4;
|
|
version_major = version - (version >> 4) * 6;
|
|
}
|
|
}
|
|
else {
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
snprintf(sysinfo->vendor_version,
|
|
sizeof(sysinfo->vendor_version),
|
|
"%ld.%ld",
|
|
version_major, version_minor);
|
|
|
|
snprintf(sysinfo->version,
|
|
sizeof(sysinfo->version),
|
|
"%s.%ld",
|
|
sysinfo->vendor_version, version_fix);
|
|
|
|
if (version_major == 10) {
|
|
switch (version_minor) {
|
|
case 2:
|
|
codename = "Jaguar";
|
|
break;
|
|
case 3:
|
|
codename = "Panther";
|
|
break;
|
|
case 4:
|
|
codename = "Tiger";
|
|
break;
|
|
case 5:
|
|
codename = "Leopard";
|
|
break;
|
|
default:
|
|
codename = "Unknown";
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
return SIGAR_ENOTIMPL;
|
|
}
|
|
|
|
SIGAR_SSTRCPY(sysinfo->vendor_code_name, codename);
|
|
|
|
snprintf(sysinfo->description,
|
|
sizeof(sysinfo->description),
|
|
"%s %s",
|
|
sysinfo->vendor_name, sysinfo->vendor_code_name);
|
|
#else
|
|
char *ptr;
|
|
|
|
#if defined(__FreeBSD__)
|
|
SIGAR_SSTRCPY(sysinfo->name, "FreeBSD");
|
|
#elif defined(__OpenBSD__)
|
|
SIGAR_SSTRCPY(sysinfo->name, "OpenBSD");
|
|
#elif defined(__NetBSD__)
|
|
SIGAR_SSTRCPY(sysinfo->name, "NetBSD");
|
|
#else
|
|
SIGAR_SSTRCPY(sysinfo->name, "Unknown");
|
|
#endif
|
|
SIGAR_SSTRCPY(sysinfo->vendor_name, sysinfo->name);
|
|
SIGAR_SSTRCPY(sysinfo->vendor, sysinfo->name);
|
|
SIGAR_SSTRCPY(sysinfo->vendor_version,
|
|
sysinfo->version);
|
|
|
|
if ((ptr = strstr(sysinfo->vendor_version, "-"))) {
|
|
/* STABLE, RELEASE, CURRENT */
|
|
*ptr++ = '\0';
|
|
SIGAR_SSTRCPY(sysinfo->vendor_code_name, ptr);
|
|
}
|
|
|
|
snprintf(sysinfo->description,
|
|
sizeof(sysinfo->description),
|
|
"%s %s",
|
|
sysinfo->name, sysinfo->version);
|
|
#endif
|
|
|
|
return SIGAR_OK;
|
|
}
|