| /* |
| * swrun_kinfo.c: |
| * hrSWRunTable data access: |
| * kvm_getprocs() interface - FreeBSD, NetBSD, OpenBSD |
| * |
| * NB: later FreeBSD and OpenBSD use different kinfo_proc structures |
| */ |
| #include <net-snmp/net-snmp-config.h> |
| |
| #include <stdio.h> |
| #ifdef HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #ifdef HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif |
| #ifdef HAVE_SYS_TYPES_H |
| #include <sys/types.h> |
| #endif |
| #ifdef HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| |
| #ifdef HAVE_KVM_H |
| #include <kvm.h> |
| #endif |
| #ifdef HAVE_SYS_PARAM_H |
| #include <sys/param.h> |
| #endif |
| #ifdef HAVE_SYS_SYSCTL_H |
| #include <sys/sysctl.h> |
| #endif |
| #ifdef HAVE_SYS_PROC_H |
| #include <sys/proc.h> |
| #endif |
| #ifdef HAVE_SYS_USER_H |
| #include <sys/user.h> |
| #endif |
| #ifdef HAVE_UVM_UVM_EXTERNAL_H |
| #include <uvm/uvm_external.h> |
| #endif |
| |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| #include <net-snmp/library/container.h> |
| #include <net-snmp/library/snmp_debug.h> |
| #include <net-snmp/data_access/swrun.h> |
| |
| extern kvm_t *kd; |
| |
| |
| #if defined(freebsd5) && __FreeBSD_version >= 500014 |
| /* |
| * later FreeBSD kinfo_proc field names |
| */ |
| #define SWRUN_TABLE kinfo_proc |
| #define SWRUN_K_STAT ki_stat |
| #define SWRUN_K_PID ki_pid |
| #define SWRUN_K_PPID ki_ppid |
| #define SWRUN_K_TID ki_tid |
| #define SWRUN_K_COMM ki_comm |
| #define SWRUN_K_FLAG ki_flag |
| #define SWRUN_K_CLASS ki_pri.pri_class |
| |
| #elif HAVE_KVM_GETPROC2 || defined(openbsd5) |
| /* |
| * newer NetBSD, OpenBSD kinfo_proc2 field names |
| */ |
| #if defined(openbsd5) |
| #define SWRUN_TABLE kinfo_proc |
| #else |
| #define SWRUN_TABLE kinfo_proc2 |
| #endif |
| #define SWRUN_K_STAT p_stat |
| #define SWRUN_K_PID p_pid |
| #define SWRUN_K_COMM p_comm |
| #define SWRUN_K_FLAG p_flag |
| /* SWRUN_K_CLASS not defined */ |
| |
| #elif defined(dragonfly) |
| /* |
| * DragonFly is different ... |
| */ |
| #define SWRUN_TABLE kinfo_proc |
| #define SWRUN_K_STAT kp_stat |
| #define SWRUN_K_PID kp_pid |
| #define SWRUN_K_COMM kp_comm |
| #define SWRUN_K_FLAG kp_flags |
| /* SWRUN_K_CLASS not defined */ |
| |
| #else |
| /* |
| * early FreeBSD, NetBSD, OpenBSD kinfo_proc field names |
| */ |
| #define SWRUN_TABLE kinfo_proc |
| #define SWRUN_K_STAT kp_proc.p_stat |
| #define SWRUN_K_PID kp_proc.p_pid |
| #define SWRUN_K_COMM kp_proc.p_comm |
| #define SWRUN_K_FLAG kp_proc.p_flag |
| /* SWRUN_K_CLASS not defined */ |
| #endif |
| |
| /* |
| * Define dummy values if not already provided by the system |
| */ |
| |
| #ifdef dragonfly |
| |
| /* |
| * DragonFly is special. p_stat is an enum! |
| */ |
| |
| #define SRUN 200 |
| #define SSLEEP 202 |
| #define SWAIT 203 |
| #define SLOCK 205 |
| #define SDEAD 208 |
| #define SONPROC 209 |
| |
| |
| #else |
| |
| #ifndef SRUN |
| #define SRUN 200 /* Defined by FreeBSD/OpenBSD, missing in NetBSD */ |
| #endif |
| #ifndef SACTIVE |
| #define SACTIVE 201 /* Defined by NetBSD, missing in FreeBSD/OpenBSD */ |
| #endif |
| #ifndef SSLEEP |
| #define SSLEEP 202 /* Defined by FreeBSD/OpenBSD, missing in NetBSD */ |
| #endif |
| #ifndef SWAIT |
| #define SWAIT 203 /* Defined by FreeBSD, missing in NetBSD/OpenBSD */ |
| #endif |
| #ifndef SSTOP |
| #define SSTOP 204 /* Defined by FreeBSD/NetBSD/OpenBSD */ |
| #endif |
| #ifndef SLOCK |
| #define SLOCK 205 /* Defined by FreeBSD, missing in NetBSD/OpenBSD */ |
| #endif |
| #ifndef SIDL |
| #define SIDL 206 /* Defined by FreeBSD/NetBSD/OpenBSD */ |
| #endif |
| #ifndef SZOMB |
| #define SZOMB 207 /* Defined by FreeBSD/NetBSD/OpenBSD */ |
| #endif |
| #ifndef SDEAD |
| #define SDEAD 208 /* Defined by OpenBSD, missing in FreeBSD/NetBSD */ |
| #endif |
| #ifndef SONPROC |
| #define SONPROC 209 /* Defined by OpenBSD, missing in FreeBSD/NetBSD */ |
| #endif |
| |
| #endif |
| |
| /* --------------------------------------------------------------------- |
| */ |
| void |
| netsnmp_arch_swrun_init(void) |
| { |
| #if NETSNMP_CAN_USE_SYSCTL && defined(CTL_KERN) && defined(KERN_MAXPROC) |
| extern int _swrun_max; |
| size_t max_size = sizeof(_swrun_max); |
| int maxproc_mib[] = { CTL_KERN, KERN_MAXPROC }; |
| sysctl(maxproc_mib, 2, &_swrun_max, &max_size, NULL, 0); |
| #endif |
| |
| return; |
| } |
| |
| /* --------------------------------------------------------------------- |
| */ |
| int |
| netsnmp_arch_swrun_container_load( netsnmp_container *container, u_int flags) |
| { |
| struct SWRUN_TABLE *proc_table; |
| int nprocs, i, rc; |
| char buf[BUFSIZ], **argv; |
| netsnmp_swrun_entry *entry; |
| |
| if ( 0 == kd ) { |
| DEBUGMSGTL(("swrun:load:arch"," Can't query kvm info\n")); |
| return 1; /* No handle for retrieving process table */ |
| } |
| #if defined(openbsd5) |
| proc_table = kvm_getprocs(kd, KERN_PROC_KTHREAD, 0, sizeof(struct kinfo_proc), &nprocs ); |
| #elif defined(HAVE_KVM_GETPROC2) |
| proc_table = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &nprocs ); |
| #else |
| proc_table = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nprocs ); |
| #endif |
| for ( i=0 ; i<nprocs; i++ ) { |
| if ( 0 == proc_table[i].SWRUN_K_STAT ) |
| continue; |
| if ( -1 == proc_table[i].SWRUN_K_PID ) |
| continue; |
| #ifdef SWRUN_K_TID |
| if ( 0 == proc_table[i].SWRUN_K_PPID ) |
| proc_table[i].SWRUN_K_PID = proc_table[i].SWRUN_K_TID; |
| #endif |
| entry = netsnmp_swrun_entry_create(proc_table[i].SWRUN_K_PID); |
| if (NULL == entry) |
| continue; /* error already logged by function */ |
| rc = CONTAINER_INSERT(container, entry); |
| |
| /* |
| * There are two possible sources for the command being run: |
| * - SWRUN_K_COMM (from the proc_table entry directly) |
| * - running kvm_getargv on the process entry. |
| * |
| * We'll use argv[0] (if set) for hrSWRunPath, |
| * since that might potentially contain the |
| * absolute path to the running binary. |
| * We'll use SWRUN_K_COMM for hrSWRunName, |
| * and as an alternative for hrSWRunPath |
| */ |
| #if HAVE_KVM_GETPROC2 |
| argv = kvm_getargv2( kd, &(proc_table[i]), 0); |
| #else |
| argv = kvm_getargv( kd, &(proc_table[i]), BUFSIZ); |
| #endif |
| |
| entry->hrSWRunName_len = snprintf(entry->hrSWRunName, |
| sizeof(entry->hrSWRunName)-1, |
| "%s", proc_table[i].SWRUN_K_COMM); |
| |
| if ( argv && *argv) |
| entry->hrSWRunPath_len = snprintf(entry->hrSWRunPath, |
| sizeof(entry->hrSWRunPath)-1, |
| "%s", argv[0]); |
| else { |
| memcpy( entry->hrSWRunPath, entry->hrSWRunName, |
| entry->hrSWRunName_len ); |
| entry->hrSWRunPath_len = entry->hrSWRunName_len; |
| } |
| |
| /* |
| * Stitch together the rest of argv[] to build hrSWRunParameters |
| * |
| * Note: |
| * We add a separating space before each argv[] parameter, |
| * *including* the first one. So we need to skip this |
| * leading space (buf[0]) when setting hrSWRunParameters. |
| * This is also why we cleared the first *two* characters |
| * in the buffer initially. If there were no command-line |
| * arguments, then buf[1] would still be a null string. |
| */ |
| buf[0] = '\0'; |
| buf[1] = '\0'; |
| if (argv) |
| argv++; /* Skip argv[0] */ |
| while ( argv && *argv ) { |
| strcat(buf, " "); |
| strcat(buf, *argv); |
| argv++; |
| } |
| entry->hrSWRunParameters_len = snprintf(entry->hrSWRunParameters, |
| sizeof(entry->hrSWRunParameters)-1, |
| "%s", buf+1); |
| |
| entry->hrSWRunType = (P_SYSTEM & proc_table[i].SWRUN_K_FLAG) |
| #ifdef SWRUN_K_CLASS |
| ? ((PRI_ITHD == proc_table[i].SWRUN_K_CLASS) |
| ? 3 /* device driver */ |
| : 2 /* operating system */ |
| ) |
| : 4 /* application */ |
| #else |
| ? 2 /* operating system */ |
| : 4 /* application */ |
| #endif |
| ; |
| |
| #ifdef netbsd5 |
| switch (proc_table[i].SWRUN_K_STAT) { |
| case LSONPROC: |
| case LSRUN: entry->hrSWRunStatus = HRSWRUNSTATUS_RUNNING; |
| break; |
| case LSSLEEP: entry->hrSWRunStatus = HRSWRUNSTATUS_RUNNABLE; |
| break; |
| case LSIDL: |
| case LSSUSPENDED: |
| case LSSTOP: entry->hrSWRunStatus = HRSWRUNSTATUS_NOTRUNNABLE; |
| break; |
| case LSDEAD: |
| case LSZOMB: entry->hrSWRunStatus = HRSWRUNSTATUS_INVALID; |
| break; |
| default: |
| entry->hrSWRunStatus = HRSWRUNSTATUS_INVALID; |
| snmp_log(LOG_ERR, "Bad process status %c (0x%x)\n", proc_table[i].SWRUN_K_STAT, proc_table[i].SWRUN_K_STAT); |
| break; |
| } |
| #else |
| switch (proc_table[i].SWRUN_K_STAT & 0xFF) { |
| case SONPROC: |
| case SRUN: entry->hrSWRunStatus = HRSWRUNSTATUS_RUNNING; |
| break; |
| case SSLEEP: |
| case SACTIVE: |
| case SWAIT: entry->hrSWRunStatus = HRSWRUNSTATUS_RUNNABLE; |
| break; |
| case SIDL: |
| case SSTOP: |
| case SLOCK: entry->hrSWRunStatus = HRSWRUNSTATUS_NOTRUNNABLE; |
| break; |
| |
| case SDEAD: |
| case SZOMB: entry->hrSWRunStatus = HRSWRUNSTATUS_INVALID; /* i.e. "not loaded" */ |
| break; |
| |
| default: entry->hrSWRunStatus = HRSWRUNSTATUS_INVALID; /* Actually invalid */ |
| snmp_log(LOG_ERR, "Bad process status %c (0x%x)\n", proc_table[i].SWRUN_K_STAT, proc_table[i].SWRUN_K_STAT); |
| break; |
| } |
| #endif |
| |
| #if defined(freebsd5) && __FreeBSD_version >= 500014 |
| entry->hrSWRunPerfCPU = (proc_table[i].ki_rusage.ru_utime.tv_sec*1000000 + proc_table[i].ki_rusage.ru_utime.tv_usec) / 10000; |
| entry->hrSWRunPerfCPU += (proc_table[i].ki_rusage.ru_stime.tv_sec*1000000 + proc_table[i].ki_rusage.ru_stime.tv_usec) / 10000; |
| entry->hrSWRunPerfCPU += (proc_table[i].ki_rusage_ch.ru_utime.tv_sec*1000000 + proc_table[i].ki_rusage_ch.ru_utime.tv_usec) / 10000; |
| entry->hrSWRunPerfCPU += (proc_table[i].ki_rusage_ch.ru_stime.tv_sec*1000000 + proc_table[i].ki_rusage_ch.ru_stime.tv_usec) / 10000; |
| entry->hrSWRunPerfMem = proc_table[i].ki_rssize * (getpagesize()/1024); /* in kB */ |
| #elif defined(HAVE_KVM_GETPROC2) || defined(openbsd5) |
| /* |
| * newer NetBSD, OpenBSD |
| */ |
| entry->hrSWRunPerfCPU = proc_table[i].p_rtime_sec*100; |
| entry->hrSWRunPerfCPU += proc_table[i].p_rtime_usec / 10000; |
| |
| entry->hrSWRunPerfMem = proc_table[i].p_vm_rssize; |
| entry->hrSWRunPerfMem *= (getpagesize() / 1024); |
| #elif defined(dragonfly) && __DragonFly_version >= 190000 |
| entry->hrSWRunPerfCPU = proc_table[i].kp_lwp.kl_uticks; |
| entry->hrSWRunPerfCPU += proc_table[i].kp_lwp.kl_sticks; |
| entry->hrSWRunPerfCPU += proc_table[i].kp_lwp.kl_iticks; |
| entry->hrSWRunPerfCPU = entry->hrSWRunPerfCPU / 10000; |
| |
| entry->hrSWRunPerfMem = proc_table[i].kp_vm_map_size / 1024; |
| #elif defined(dragonfly) |
| entry->hrSWRunPerfCPU = proc_table[i].kp_eproc.e_uticks; |
| entry->hrSWRunPerfCPU += proc_table[i].kp_eproc.e_sticks; |
| entry->hrSWRunPerfCPU += proc_table[i].kp_eproc.e_iticks; |
| |
| entry->hrSWRunPerfMem = proc_table[i].kp_vm_map_size / 1024; |
| |
| #else |
| /* |
| * early FreeBSD, NetBSD, OpenBSD |
| */ |
| entry->hrSWRunPerfCPU = proc_table[i].kp_proc.p_uticks; |
| entry->hrSWRunPerfCPU += proc_table[i].kp_proc.p_sticks; |
| entry->hrSWRunPerfCPU += proc_table[i].kp_proc.p_iticks; |
| entry->hrSWRunPerfMem = proc_table[i].kp_eproc.e_vm.vm_rssize; |
| entry->hrSWRunPerfMem *= (getpagesize() / 1024); |
| #endif |
| } |
| /* |
| * 'proc_table' is owned by the kvm library, |
| * so shouldn't be freed here. |
| */ |
| |
| DEBUGMSGTL(("swrun:load:arch","loaded %d entries\n", |
| (int)CONTAINER_SIZE(container))); |
| |
| return 0; |
| } |