/* Must be called before any values can be read. This creates all the * necessary PDH values */ int sg_win32_start_capture() { #ifdef WIN32 PDH_STATUS pdh_status; if(is_started) { return -1; } pdh_status = PdhOpenQuery(NULL, 0, &h_query); if(pdh_status != ERROR_SUCCESS) { char *mess = NULL; if(pdh_status == PDH_INVALID_ARGUMENT) mess = "Invalid argument o.O"; else if(pdh_status == PDH_MEMORY_ALLOCATION_FAILURE) mess = "Memory allocation failure"; sg_set_error(SG_ERROR_PDHOPEN, mess); return -1; } if (add_all_monitors() == -1) { return -1; } is_started = 1; #endif return 0; }
sg_cpu_percents *sg_get_cpu_percents(){ static sg_cpu_percents cpu_usage; #ifndef WIN32 sg_cpu_stats *cs_ptr; cs_ptr=sg_get_cpu_stats_diff(); if(cs_ptr==NULL){ return NULL; } cpu_usage.user = ((float)cs_ptr->user / (float)cs_ptr->total)*100; cpu_usage.kernel = ((float)cs_ptr->kernel / (float)cs_ptr->total)*100; cpu_usage.idle = ((float)cs_ptr->idle / (float)cs_ptr->total)*100; cpu_usage.iowait = ((float)cs_ptr->iowait / (float)cs_ptr->total)*100; cpu_usage.swap = ((float)cs_ptr->swap / (float)cs_ptr->total)*100; cpu_usage.nice = ((float)cs_ptr->nice / (float)cs_ptr->total)*100; cpu_usage.time_taken = cs_ptr->systime; #else double result; if(read_counter_double(SG_WIN32_PROC_USER, &result)) { sg_set_error(SG_ERROR_PDHREAD, PDH_USER); return NULL; } cpu_usage.user = (float)result; if(read_counter_double(SG_WIN32_PROC_PRIV, &result)) { sg_set_error(SG_ERROR_PDHREAD, PDH_PRIV); return NULL; } cpu_usage.kernel = (float)result; if(read_counter_double(SG_WIN32_PROC_IDLE, &result)) { sg_set_error(SG_ERROR_PDHREAD, PDH_IDLE); return NULL; } /* win2000 does not have an idle counter, but does have %activity * so convert it to idle */ cpu_usage.idle = 100 - (float)result; if(read_counter_double(SG_WIN32_PROC_INT, &result)) { sg_set_error(SG_ERROR_PDHREAD, PDH_INTER); return NULL; } cpu_usage.iowait = (float)result; #endif return &cpu_usage; }
sg_page_stats *sg_get_page_stats_diff(){ static sg_page_stats page_stats_diff; #ifndef WIN32 sg_page_stats *page_ptr; if(page_stats_uninit){ page_ptr=sg_get_page_stats(); if(page_ptr==NULL){ return NULL; } page_stats_uninit=0; return page_ptr; } page_stats_diff.pages_pagein=page_stats.pages_pagein; page_stats_diff.pages_pageout=page_stats.pages_pageout; page_stats_diff.systime=page_stats.systime; page_ptr=sg_get_page_stats(); if(page_ptr==NULL){ return NULL; } page_stats_diff.pages_pagein=page_stats.pages_pagein-page_stats_diff.pages_pagein; page_stats_diff.pages_pageout=page_stats.pages_pageout-page_stats_diff.pages_pageout; page_stats_diff.systime=page_stats.systime-page_stats_diff.systime; #else /* WIN32 */ if(read_counter_large(SG_WIN32_PAGEIN, &page_stats_diff.pages_pagein)) { sg_set_error(SG_ERROR_PDHREAD, PDH_PAGEIN); return NULL; } if(read_counter_large(SG_WIN32_PAGEOUT, &page_stats_diff.pages_pageout)) { sg_set_error(SG_ERROR_PDHREAD, PDH_PAGEIN); return NULL; } page_stats_diff.systime = 0; #endif /* WIN32 */ return &page_stats_diff; }
/* Call before trying to get search results back, otherwise it'll be dead data */ int sg_win32_snapshot() { #ifdef WIN32 PDH_STATUS pdh_status; if(!is_started) { return -1; } pdh_status = PdhCollectQueryData(h_query); if(pdh_status != ERROR_SUCCESS) { sg_set_error(SG_ERROR_PDHCOLLECT, NULL); return -1; } #endif return 0; }
char *get_diskio(const int no, long long *read, long long *write) { int result; char *name = NULL; if (no >= diskio_no || no < 0) return NULL; result = read_counter_large_int(diskio_rhan[no], read); result = result + read_counter_large_int(diskio_whan[no], write); if (result) { sg_set_error(SG_ERROR_PDHREAD, "diskio"); return NULL; } if (sg_update_string(&name, diskio_names[no])) return NULL; return name; }
sg_network_io_stats *sg_get_network_io_stats(int *entries){ int interfaces; sg_network_io_stats *network_stat_ptr; #ifdef SOLARIS kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *knp; #endif #ifdef LINUX FILE *f; /* Horrible big enough, but it should be easily big enough */ char line[8096]; regex_t regex; regmatch_t line_match[9]; #endif #ifdef ALLBSD struct ifaddrs *net, *net_ptr; struct if_data *net_data; #endif #ifdef WIN32 PMIB_IFTABLE if_table; MIB_IFROW if_row; int i, no, j; /* used for duplicate interface names. 5 for space, hash, up to two * numbers and terminating slash */ char buf[5]; #endif #ifdef ALLBSD if(getifaddrs(&net) != 0){ sg_set_error_with_errno(SG_ERROR_GETIFADDRS, NULL); return NULL; } interfaces=0; for(net_ptr=net;net_ptr!=NULL;net_ptr=net_ptr->ifa_next){ if(net_ptr->ifa_addr->sa_family != AF_LINK) continue; if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) { return NULL; } network_stat_ptr=network_stats+interfaces; if (sg_update_string(&network_stat_ptr->interface_name, net_ptr->ifa_name) < 0) { return NULL; } net_data=(struct if_data *)net_ptr->ifa_data; network_stat_ptr->rx=net_data->ifi_ibytes; network_stat_ptr->tx=net_data->ifi_obytes; network_stat_ptr->ipackets=net_data->ifi_ipackets; network_stat_ptr->opackets=net_data->ifi_opackets; network_stat_ptr->ierrors=net_data->ifi_ierrors; network_stat_ptr->oerrors=net_data->ifi_oerrors; network_stat_ptr->collisions=net_data->ifi_collisions; network_stat_ptr->systime=time(NULL); interfaces++; } freeifaddrs(net); #endif #ifdef SOLARIS if ((kc = kstat_open()) == NULL) { sg_set_error(SG_ERROR_KSTAT_OPEN, NULL); return NULL; } interfaces=0; for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { if (strcmp(ksp->ks_class, "net") == 0) { kstat_read(kc, ksp, NULL); #ifdef SOL7 #define LRX "rbytes" #define LTX "obytes" #define LIPACKETS "ipackets" #define LOPACKETS "opackets" #define VALTYPE value.ui32 #else #define LRX "rbytes64" #define LTX "obytes64" #define LIPACKETS "ipackets64" #define LOPACKETS "opackets64" #define VALTYPE value.ui64 #endif /* Read rx */ if((knp=kstat_data_lookup(ksp, LRX))==NULL){ /* This is a network interface, but it doesn't * have the rbytes/obytes values; for instance, * the loopback devices have this behaviour * (although they do track packets in/out). */ /* FIXME: Show packet counts when byte counts * not available. */ continue; } /* Create new network_stats */ if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) { return NULL; } network_stat_ptr=network_stats+interfaces; /* Finish reading rx */ network_stat_ptr->rx=knp->VALTYPE; /* Read tx */ if((knp=kstat_data_lookup(ksp, LTX))==NULL){ continue; } network_stat_ptr->tx=knp->VALTYPE; /* Read ipackets */ if((knp=kstat_data_lookup(ksp, LIPACKETS))==NULL){ continue; } network_stat_ptr->ipackets=knp->VALTYPE; /* Read opackets */ if((knp=kstat_data_lookup(ksp, LOPACKETS))==NULL){ continue; } network_stat_ptr->opackets=knp->VALTYPE; /* Read ierrors */ if((knp=kstat_data_lookup(ksp, "ierrors"))==NULL){ continue; } network_stat_ptr->ierrors=knp->value.ui32; /* Read oerrors */ if((knp=kstat_data_lookup(ksp, "oerrors"))==NULL){ continue; } network_stat_ptr->oerrors=knp->value.ui32; /* Read collisions */ if((knp=kstat_data_lookup(ksp, "collisions"))==NULL){ continue; } network_stat_ptr->collisions=knp->value.ui32; /* Read interface name */ if (sg_update_string(&network_stat_ptr->interface_name, ksp->ks_name) < 0) { return NULL; } /* Store systime */ network_stat_ptr->systime=time(NULL); interfaces++; } } kstat_close(kc); #endif #ifdef LINUX f=fopen("/proc/net/dev", "r"); if(f==NULL){ sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/net/dev"); return NULL; } /* read the 2 lines.. Its the title, so we dont care :) */ fgets(line, sizeof(line), f); fgets(line, sizeof(line), f); if((regcomp(®ex, "^ *([^:]+): *([0-9]+) +([0-9]+) +([0-9]+) +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +([0-9]+) +([0-9]+) +([0-9]+) +[0-9]+ +[0-9]+ +([0-9]+)", REG_EXTENDED))!=0){ sg_set_error(SG_ERROR_PARSE, NULL); return NULL; } interfaces=0; while((fgets(line, sizeof(line), f)) != NULL){ if((regexec(®ex, line, 9, line_match, 0))!=0){ continue; } if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) { return NULL; } network_stat_ptr=network_stats+interfaces; if(network_stat_ptr->interface_name!=NULL){ free(network_stat_ptr->interface_name); } network_stat_ptr->interface_name=sg_get_string_match(line, &line_match[1]); network_stat_ptr->rx=sg_get_ll_match(line, &line_match[2]); network_stat_ptr->tx=sg_get_ll_match(line, &line_match[5]); network_stat_ptr->ipackets=sg_get_ll_match(line, &line_match[3]); network_stat_ptr->opackets=sg_get_ll_match(line, &line_match[6]); network_stat_ptr->ierrors=sg_get_ll_match(line, &line_match[4]); network_stat_ptr->oerrors=sg_get_ll_match(line, &line_match[7]); network_stat_ptr->collisions=sg_get_ll_match(line, &line_match[8]); network_stat_ptr->systime=time(NULL); interfaces++; } fclose(f); regfree(®ex); #endif #ifdef CYGWIN sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin"); return NULL; #endif #ifdef HPUX sg_set_error(SG_ERROR_UNSUPPORTED, "HP-UX"); return NULL; #endif #ifdef WIN32 interfaces = 0; if((if_table = win32_get_devices()) == NULL) { sg_set_error(SG_ERROR_DEVICES, "network"); return NULL; } if(VECTOR_RESIZE(network_stats, if_table->dwNumEntries) < 0) { free(if_table); return NULL; } for (i=0; i<if_table->dwNumEntries; i++) { network_stat_ptr=network_stats+i; if_row = if_table->table[i]; if(sg_update_string(&network_stat_ptr->interface_name, if_row.bDescr) < 0) { free(if_table); return NULL; } network_stat_ptr->tx = if_row.dwOutOctets; network_stat_ptr->rx = if_row.dwInOctets; network_stat_ptr->ipackets = if_row.dwInUcastPkts + if_row.dwInNUcastPkts; network_stat_ptr->opackets = if_row.dwOutUcastPkts + if_row.dwOutNUcastPkts; network_stat_ptr->ierrors = if_row.dwInErrors; network_stat_ptr->oerrors = if_row.dwOutErrors; network_stat_ptr->collisions = 0; /* can't do that */ network_stat_ptr->systime = time(NULL); interfaces++; } free(if_table); /* Please say there's a nicer way to do this... If windows has two (or * more) identical network cards, GetIfTable returns them with the same * name, not like in Device Manager where the other has a #2 etc after * it. So, add the #number here. Should we be doing this? Or should the * end programs be dealing with duplicate names? Currently breaks * watch.pl in rrdgraphing. But Unix does not have the issue of * duplicate net device names. */ for (i=0; i<interfaces; i++) { no = 2; for(j=i+1; j<interfaces; j++) { network_stat_ptr=network_stats+j; if(strcmp(network_stats[i].interface_name, network_stat_ptr->interface_name) == 0) { if(snprintf(buf, sizeof(buf), " #%d", no) < 0) { break; } if(sg_concat_string(&network_stat_ptr->interface_name, buf) != 0) { return NULL; } no++; } } } #endif *entries=interfaces; return network_stats; }
sg_cpu_stats *sg_get_cpu_stats(){ #ifdef HPUX struct pst_dynamic pstat_dynamic; int i; #endif #ifdef SOLARIS kstat_ctl_t *kc; kstat_t *ksp; cpu_stat_t cs; #endif #if defined(LINUX) || defined(CYGWIN) FILE *f; #endif #ifdef ALLBSD #if defined(NETBSD) || defined(OPENBSD) int mib[2]; #endif #ifdef NETBSD u_int64_t cp_time[CPUSTATES]; #else long cp_time[CPUSTATES]; #endif size_t size; #endif cpu_now.user=0; /* Not stored in linux or freebsd */ cpu_now.iowait=0; cpu_now.kernel=0; cpu_now.idle=0; /* Not stored in linux, freebsd, hpux or windows */ cpu_now.swap=0; cpu_now.total=0; /* Not stored in solaris or windows */ cpu_now.nice=0; #ifdef HPUX if (pstat_getdynamic(&pstat_dynamic, sizeof(pstat_dynamic), 1, 0) == -1) { sg_set_error_with_errno(SG_ERROR_PSTAT, "pstat_dynamic"); return NULL; } cpu_now.user = pstat_dynamic.psd_cpu_time[CP_USER]; cpu_now.iowait = pstat_dynamic.psd_cpu_time[CP_WAIT]; cpu_now.kernel = pstat_dynamic.psd_cpu_time[CP_SSYS] + pstat_dynamic.psd_cpu_time[CP_SYS]; cpu_now.idle = pstat_dynamic.psd_cpu_time[CP_IDLE]; cpu_now.nice = pstat_dynamic.psd_cpu_time[CP_NICE]; for (i = 0; i < PST_MAX_CPUSTATES; i++) { cpu_now.total += pstat_dynamic.psd_cpu_time[i]; } #endif #ifdef SOLARIS if ((kc = kstat_open()) == NULL) { sg_set_error(SG_ERROR_KSTAT_OPEN, NULL); return NULL; } for (ksp = kc->kc_chain; ksp!=NULL; ksp = ksp->ks_next) { if ((strcmp(ksp->ks_module, "cpu_stat")) != 0) continue; if (kstat_read(kc, ksp, &cs) == -1) { continue; } cpu_now.user+=(long long)cs.cpu_sysinfo.cpu[CPU_USER]; cpu_now.kernel+=(long long)cs.cpu_sysinfo.cpu[CPU_KERNEL]; cpu_now.idle+=(long long)cs.cpu_sysinfo.cpu[CPU_IDLE]; cpu_now.iowait+=(long long)cs.cpu_sysinfo.wait[W_IO]+(long long)cs.cpu_sysinfo.wait[W_PIO]; cpu_now.swap+=(long long)cs.cpu_sysinfo.wait[W_SWAP]; } cpu_now.total=cpu_now.user+cpu_now.iowait+cpu_now.kernel+cpu_now.idle+cpu_now.swap; kstat_close(kc); #endif #if defined(LINUX) || defined(CYGWIN) if ((f=fopen("/proc/stat", "r" ))==NULL) { sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/stat"); return NULL; } /* The very first line should be cpu */ if((fscanf(f, "cpu %lld %lld %lld %lld %lld", \ &cpu_now.user, \ &cpu_now.nice, \ &cpu_now.kernel, \ &cpu_now.idle, \ &cpu_now.iowait)) != 5){ sg_set_error(SG_ERROR_PARSE, "cpu"); fclose(f); return NULL; } fclose(f); cpu_now.total=cpu_now.user+cpu_now.nice+cpu_now.kernel+cpu_now.idle+cpu_now.iowait; #endif #ifdef ALLBSD #if defined(FREEBSD) || defined(DFBSD) size = sizeof cp_time; if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) < 0){ sg_set_error_with_errno(SG_ERROR_SYSCTLBYNAME, "kern.cp_time"); return NULL; } #else mib[0] = CTL_KERN; #ifdef NETBSD mib[1] = KERN_CP_TIME; #else mib[1] = KERN_CPTIME; #endif size = sizeof cp_time; if (sysctl(mib, 2, &cp_time, &size, NULL, 0) < 0) { #ifdef NETBSD sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_CP_TIME"); #else sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_CPTIME"); #endif return NULL; } #endif cpu_now.user=cp_time[CP_USER]; cpu_now.nice=cp_time[CP_NICE]; cpu_now.kernel=cp_time[CP_SYS]; cpu_now.idle=cp_time[CP_IDLE]; cpu_now.total=cpu_now.user+cpu_now.nice+cpu_now.kernel+cpu_now.idle; #endif #ifdef WIN32 sg_set_error(SG_ERROR_UNSUPPORTED, "Win32"); return NULL; #endif cpu_now.systime=time(NULL); cpu_now_uninit=0; return &cpu_now; }
sg_mem_stats *sg_get_mem_stats(){ static sg_mem_stats mem_stat; #ifdef SOLARIS kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *kn; long totalmem; int pagesize; #endif #if defined(LINUX) || defined(CYGWIN) char *line_ptr; unsigned long long value; FILE *f; #endif #if defined(FREEBSD) || defined(DFBSD) int mib[2]; u_long physmem; size_t size; u_int free_count; u_int cache_count; u_int inactive_count; int pagesize; #endif #if defined(NETBSD) || defined(OPENBSD) struct uvmexp *uvm; #endif #ifdef SOLARIS if((pagesize=sysconf(_SC_PAGESIZE)) == -1){ sg_set_error_with_errno(SG_ERROR_SYSCONF, "_SC_PAGESIZE"); return NULL; } if((totalmem=sysconf(_SC_PHYS_PAGES)) == -1){ sg_set_error_with_errno(SG_ERROR_SYSCONF, "_SC_PHYS_PAGES"); return NULL; } if ((kc = kstat_open()) == NULL) { sg_set_error(SG_ERROR_KSTAT_OPEN, NULL); return NULL; } if((ksp=kstat_lookup(kc, "unix", 0, "system_pages")) == NULL){ sg_set_error(SG_ERROR_KSTAT_LOOKUP, "unix,0,system_pages"); return NULL; } if (kstat_read(kc, ksp, 0) == -1) { sg_set_error(SG_ERROR_KSTAT_READ, NULL); return NULL; } if((kn=kstat_data_lookup(ksp, "freemem")) == NULL){ sg_set_error(SG_ERROR_KSTAT_DATA_LOOKUP, "freemem"); return NULL; } kstat_close(kc); mem_stat.total = (long long)totalmem * (long long)pagesize; mem_stat.free = ((long long)kn->value.ul) * (long long)pagesize; mem_stat.used = mem_stat.total - mem_stat.free; #endif #if defined(LINUX) || defined(CYGWIN) if ((f = fopen("/proc/meminfo", "r")) == NULL) { sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/meminfo"); return NULL; } while ((line_ptr = sg_f_read_line(f, "")) != NULL) { if (sscanf(line_ptr, "%*s %llu kB", &value) != 1) { continue; } value *= 1024; if (strncmp(line_ptr, "MemTotal:", 9) == 0) { mem_stat.total = value; } else if (strncmp(line_ptr, "MemFree:", 8) == 0) { mem_stat.free = value; } else if (strncmp(line_ptr, "Cached:", 7) == 0) { mem_stat.cache = value; } } fclose(f); mem_stat.used = mem_stat.total - mem_stat.free; #endif #if defined(FREEBSD) || defined(DFBSD) /* Returns bytes */ mib[0] = CTL_HW; mib[1] = HW_PHYSMEM; size = sizeof physmem; if (sysctl(mib, 2, &physmem, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_PHYSMEM"); return NULL; } mem_stat.total = physmem; /*returns pages*/ size = sizeof free_count; if (sysctlbyname("vm.stats.vm.v_free_count", &free_count, &size, NULL, 0) < 0){ sg_set_error_with_errno(SG_ERROR_SYSCTLBYNAME, "vm.stats.vm.v_free_count"); return NULL; } size = sizeof inactive_count; if (sysctlbyname("vm.stats.vm.v_inactive_count", &inactive_count , &size, NULL, 0) < 0){ sg_set_error_with_errno(SG_ERROR_SYSCTLBYNAME, "vm.stats.vm.v_inactive_count"); return NULL; } size = sizeof cache_count; if (sysctlbyname("vm.stats.vm.v_cache_count", &cache_count, &size, NULL, 0) < 0){ sg_set_error_with_errno(SG_ERROR_SYSCTLBYNAME, "vm.stats.vm.v_cache_count"); return NULL; } /* Because all the vm.stats returns pages, I need to get the page size. * After that I then need to multiple the anything that used vm.stats to * get the system statistics by pagesize */ pagesize = getpagesize(); mem_stat.cache=cache_count*pagesize; /* Of couse nothing is ever that simple :) And I have inactive pages to * deal with too. So I'm going to add them to free memory :) */ mem_stat.free=(free_count*pagesize)+(inactive_count*pagesize); mem_stat.used=physmem-mem_stat.free; #endif #if defined(NETBSD) || defined(OPENBSD) if ((uvm = sg_get_uvmexp()) == NULL) { return NULL; } mem_stat.total = uvm->pagesize * uvm->npages; #ifdef NETBSD mem_stat.cache = uvm->pagesize * (uvm->filepages + uvm->execpages); #else /* Can't find cache memory on OpenBSD */ mem_stat.cache = 0; #endif mem_stat.free = uvm->pagesize * (uvm->free + uvm->inactive); mem_stat.used = mem_stat.total - mem_stat.free; #endif return &mem_stat; }
sg_host_info *sg_get_host_info() { static sg_host_info general_stat; #ifndef WIN32 static struct utsname os; #endif #ifdef HPUX struct pst_static *pstat_static; time_t currtime; long boottime; #endif #ifdef SOLARIS time_t boottime,curtime; kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *kn; #endif #if defined(LINUX) || defined(CYGWIN) FILE *f; #endif #ifdef ALLBSD int mib[2]; struct timeval boottime; time_t curtime; size_t size; #endif #ifdef WIN32 unsigned long nameln; char *name; long long result; OSVERSIONINFOEX osinfo; SYSTEM_INFO sysinfo; char *tmp_name; char tmp[10]; #endif #ifndef WIN32 /* Trust windows to be different */ if((uname(&os)) < 0) { sg_set_error_with_errno(SG_ERROR_UNAME, NULL); return NULL; } general_stat.os_name = os.sysname; general_stat.os_release = os.release; general_stat.os_version = os.version; general_stat.platform = os.machine; general_stat.hostname = os.nodename; #else /* WIN32 */ if (!runonce) { /* these settings are static after boot, so why get them * constantly? */ /* get system name */ nameln = MAX_COMPUTERNAME_LENGTH + 1; name = sg_malloc(nameln); if(name == NULL) { return NULL; } if(GetComputerName(name, &nameln) == 0) { free(name); sg_set_error(SG_ERROR_HOST, "GetComputerName"); return NULL; } if(sg_update_string(&general_stat.hostname, name)) { free(name); return NULL; } free(name); /* get OS name, version and build */ ZeroMemory(&osinfo, sizeof(OSVERSIONINFOEX)); osinfo.dwOSVersionInfoSize = sizeof(osinfo); if(!GetVersionEx(&osinfo)) { sg_set_error(SG_ERROR_HOST, "GetVersionEx"); return NULL; } /* Release - single number */ if(snprintf(tmp, sizeof(tmp), "%ld", osinfo.dwBuildNumber) == -1) { free(tmp); return NULL; } if(sg_update_string(&general_stat.os_release, tmp)) { free(tmp); return NULL; } /* Version */ /* usually a single digit . single digit, eg 5.0 */ if(snprintf(tmp, sizeof(tmp), "%ld.%ld", osinfo.dwMajorVersion, osinfo.dwMinorVersion) == -1) { free(tmp); return NULL; } if(sg_update_string(&general_stat.os_version, tmp)) { free(tmp); return NULL; } /* OS name */ tmp_name = get_os_name(osinfo); if(tmp_name == NULL) { return NULL; } if(sg_update_string(&general_stat.os_name, tmp_name)) { free(tmp_name); return NULL; } free(tmp_name); runonce = 1; /* Platform */ GetSystemInfo(&sysinfo); switch(sysinfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL: if(sg_update_string(&general_stat.platform, "Intel")) { return NULL; } break; case PROCESSOR_ARCHITECTURE_IA64: if(sg_update_string(&general_stat.platform, "IA64")) { return NULL; } break; case PROCESSOR_ARCHITECTURE_AMD64: if(sg_update_string(&general_stat.platform, "AMD64")) { return NULL; } break; default: if(sg_update_string(&general_stat.platform, "Unknown")) { return NULL; } break; } } #endif /* WIN32 */ /* get uptime */ #ifdef HPUX pstat_static = sg_get_pstat_static(); if (pstat_static == NULL) { return NULL; } currtime = time(NULL); boottime = pstat_static->boot_time; general_stat.uptime = currtime - boottime; #endif #ifdef SOLARIS if ((kc = kstat_open()) == NULL) { sg_set_error(SG_ERROR_KSTAT_OPEN, NULL); return NULL; } if((ksp=kstat_lookup(kc, "unix", -1, "system_misc"))==NULL) { sg_set_error(SG_ERROR_KSTAT_LOOKUP, "unix,-1,system_misc"); kstat_close(kc); return NULL; } if (kstat_read(kc, ksp, 0) == -1) { sg_set_error(SG_ERROR_KSTAT_READ, NULL); kstat_close(kc); return NULL; } if((kn=kstat_data_lookup(ksp, "boot_time")) == NULL) { sg_set_error(SG_ERROR_KSTAT_DATA_LOOKUP, "boot_time"); kstat_close(kc); return NULL; } boottime=(kn->value.ui32); kstat_close(kc); time(&curtime); general_stat.uptime = curtime - boottime; #endif #if defined(LINUX) || defined(CYGWIN) if ((f=fopen("/proc/uptime", "r")) == NULL) { sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/uptime"); return NULL; } if((fscanf(f,"%lu %*d",&general_stat.uptime)) != 1) { sg_set_error(SG_ERROR_PARSE, NULL); return NULL; } fclose(f); #endif #ifdef ALLBSD mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; size = sizeof boottime; if (sysctl(mib, 2, &boottime, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_BOOTTIME"); return NULL; } time(&curtime); general_stat.uptime=curtime-boottime.tv_sec; #endif #ifdef WIN32 if(read_counter_large(SG_WIN32_UPTIME, &result)) { sg_set_error(SG_ERROR_PDHREAD, PDH_UPTIME); return NULL; } general_stat.uptime = (time_t) result; #endif return &general_stat; }
sg_load_stats *sg_get_load_stats(){ #if !defined(CYGWIN) && !defined(WIN32) static sg_load_stats load_stat; #ifdef HPUX struct pst_dynamic pstat_dynamic; #else double loadav[3]; #endif #endif /* not CYGWIN or WIN32 */ #ifdef CYGWIN sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin"); return NULL; #elif defined(WIN32) sg_set_error(SG_ERROR_UNSUPPORTED, "Win32"); return NULL; #else #if defined(SOLARIS) && !defined(HAVE_SYS_LOADAVG_H) kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *kn; if ((kc = kstat_open()) == NULL) { sg_set_error(SG_ERROR_KSTAT_OPEN, NULL); return NULL; } if((ksp=kstat_lookup(kc, "unix", 0, "system_misc")) == NULL){ sg_set_error(SG_ERROR_KSTAT_LOOKUP, "unix,0,system_misc"); kstat_close(kc); return NULL; } if (kstat_read(kc, ksp, 0) == -1) { sg_set_error(SG_ERROR_KSTAT_READ, NULL); kstat_close(kc); return NULL; } kstat_close(kc); if((kn=kstat_data_lookup(ksp, "avenrun_1min")) == NULL){ sg_set_error(SG_ERROR_KSTAT_DATA_LOOKUP, "avenrun_1min"); return NULL; } load_stat.min1 = (double)kn->value.ui32 / (double)256; if((kn=kstat_data_lookup(ksp, "avenrun_5min")) == NULL){ sg_set_error(SG_ERROR_KSTAT_DATA_LOOKUP, "avenrun_5min"); return NULL; } load_stat.min5 = (double)kn->value.ui32 / (double)256; if((kn=kstat_data_lookup(ksp, "avenrun_15min")) == NULL){ sg_set_error(SG_ERROR_KSTAT_DATA_LOOKUP, "avenrun_15min"); return NULL; } load_stat.min15 = (double)kn->value.ui32 / (double)256; #elif defined(HPUX) if (pstat_getdynamic(&pstat_dynamic, sizeof(pstat_dynamic), 1, 0) == -1) { sg_set_error_with_errno(SG_ERROR_PSTAT, "pstat_dynamic"); return NULL; } load_stat.min1=pstat_dynamic.psd_avg_1_min; load_stat.min5=pstat_dynamic.psd_avg_5_min; load_stat.min15=pstat_dynamic.psd_avg_15_min; #else getloadavg(loadav,3); load_stat.min1=loadav[0]; load_stat.min5=loadav[1]; load_stat.min15=loadav[2]; #endif return &load_stat; #endif }
static sg_error sg_get_user_stats_int(sg_vector **user_stats_vector_ptr) { size_t num_users = 0; sg_user_stats *user_ptr; time_t now = time(NULL); #if defined (WIN32) LPWKSTA_USER_INFO_0 buf = NULL; LPWKSTA_USER_INFO_0 tmp_buf; unsigned long entries_read = 0; unsigned long entries_tot = 0; unsigned long resumehandle = 0; NET_API_STATUS nStatus; int i; char name[256]; #undef VECTOR_UPDATE_ERROR_CLEANUP #define VECTOR_UPDATE_ERROR_CLEANUP if (buf != NULL) NetApiBufferFree(buf); do { nStatus = NetWkstaUserEnum(NULL, 0, (LPBYTE*)&buf, MAX_PREFERRED_LENGTH, &entries_read, &entries_tot, &resumehandle); if((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)) { if((tmp_buf = buf) == NULL) continue; for( i = 0; i < entries_read; ++i ) { /* assert(tmp_buf != NULL); */ if( tmp_buf == NULL ) { sg_set_error(SG_ERROR_PERMISSION, "User list"); ERROR_LOG("user", "Permission denied fetching user details"); break; /* XXX break and not return? */ } /* It's in unicode. We are not. Convert */ WideCharToMultiByte(CP_ACP, 0, tmp_buf->wkui0_username, -1, name, sizeof(name), NULL, NULL); VECTOR_UPDATE(user_stats_vector_ptr, num_users + 1, user_ptr, sg_user_stats); if( SG_ERROR_NONE != sg_update_string( &user_ptr[num_users].login_name, name ) ) { VECTOR_UPDATE_ERROR_CLEANUP RETURN_FROM_PREVIOUS_ERROR( "user", sg_get_error() ); } user_ptr[num_users].systime = now; ++tmp_buf; ++num_users; } } else { RETURN_WITH_SET_ERROR("user", SG_ERROR_PERMISSION, "User enum"); } if (buf != NULL) { NetApiBufferFree(buf); buf=NULL; } } while (nStatus == ERROR_MORE_DATA); if (buf != NULL) NetApiBufferFree(buf); #elif defined(CAN_USE_UTMPX) || defined(CAN_USE_UTMP) #define SG_LUPDATE_IF(tgt,obj,memb) \ (((void *)(&(obj->memb))) == ((void *)(&(obj->memb[0])))) \ ? sg_lupdate_string(tgt, obj->memb, sizeof(obj->memb))\ : sg_update_string(tgt, obj->memb) #define UTMP_MUTEX_NAME "utmp" #undef VECTOR_UPDATE_ERROR_CLEANUP # if defined(CAN_USE_UTMPX) struct utmpx *utx; # endif # if defined(CAN_USE_UTMP) struct utmp *ut; # endif /* following block contains code for utmpx */ # if defined(CAN_USE_UTMPX) # ifdef ENABLE_THREADS # define VECTOR_UPDATE_ERROR_CLEANUP endutxent(); sg_unlock_mutex(UTMP_MUTEX_NAME); sg_lock_mutex(UTMP_MUTEX_NAME); # else # define VECTOR_UPDATE_ERROR_CLEANUP endutxent(); # endif setutxent(); while( NULL != (utx = getutxent()) ) { if( USER_PROCESS != utx->ut_type ) continue; VECTOR_UPDATE(user_stats_vector_ptr, num_users + 1, user_ptr, sg_user_stats); if( ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].login_name, utx, ut_user ) ) || # if defined(HAVE_UTMPX_HOST) # if defined(HAVE_UTMPX_SYSLEN) ( SG_ERROR_NONE != sg_lupdate_string( &user_ptr[num_users].hostname, utx->ut_host, utx->ut_syslen + 1 ) ) || # else ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].hostname, utx, ut_host ) ) || # endif # endif ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].device, utx, ut_line ) ) || ( SG_ERROR_NONE != sg_update_mem( (void *)(&user_ptr[num_users].record_id), utx->ut_id, sizeof(utx->ut_id) ) ) ) { VECTOR_UPDATE_ERROR_CLEANUP RETURN_FROM_PREVIOUS_ERROR( "user", sg_get_error() ); } user_ptr[num_users].record_id_size = sizeof(utx->ut_id); user_ptr[num_users].pid = utx->ut_pid; user_ptr[num_users].login_time = utx->ut_tv.tv_sec; user_ptr[num_users].systime = now; ++num_users; } endutxent(); if(!num_users) { # endif /* following block contains code for utmp */ # if defined(CAN_USE_UTMP) # undef VECTOR_UPDATE_ERROR_CLEANUP # ifdef ENABLE_THREADS # define VECTOR_UPDATE_ERROR_CLEANUP endutent(); sg_unlock_mutex(UTMP_MUTEX_NAME); # else # define VECTOR_UPDATE_ERROR_CLEANUP endutent(); # endif setutent(); while( NULL != (ut = getutent()) ) { # ifdef HAVE_UTMP_TYPE if( USER_PROCESS != ut->ut_type ) continue; # elif defined(HAVE_UTMP_NAME) if (ut->ut_name[0] == '\0') continue; # elif defined(HAVE_UTMP_USER) if (ut->ut_user[0] == '\0') continue; # endif VECTOR_UPDATE(user_stats_vector_ptr, num_users + 1, user_ptr, sg_user_stats); if( ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].device, ut, ut_line ) ) # if defined(HAVE_UTMP_USER) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].login_name, ut, ut_user ) ) # elif defined(HAVE_UTMP_NAME) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].login_name, ut, ut_name ) ) # endif # if defined(HAVE_UTMP_HOST) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].hostname, ut, ut_host ) ) # endif # if defined(HAVE_UTMP_ID) || ( SG_ERROR_NONE != sg_update_mem( (void **)(&user_ptr[num_users].record_id), ut->ut_id, sizeof(ut->ut_id) ) ) # endif ) { VECTOR_UPDATE_ERROR_CLEANUP RETURN_FROM_PREVIOUS_ERROR( "user", sg_get_error() ); } # if defined(HAVE_UTMP_ID) user_ptr[num_users].record_id_size = sizeof(ut->ut_id); # endif # if defined(HAVE_UTMP_PID) user_ptr[num_users].pid = ut->ut_pid; # endif #if defined(HAVE_UTMP_TIME) user_ptr[num_users].login_time = ut->ut_time; #endif user_ptr[num_users].systime = now; ++num_users; } endutent(); # endif # if defined(CAN_USE_UTMPX) } #endif # ifdef ENABLE_THREADS sg_unlock_mutex(UTMP_MUTEX_NAME); # endif #elif defined(HAVE_STRUCT_UTMP) && defined(_PATH_UTMP) struct utmp entry; FILE *f; if ((f=fopen(_PATH_UTMP, "r")) == NULL) { RETURN_WITH_SET_ERROR_WITH_ERRNO("user", SG_ERROR_OPEN, _PATH_UTMP); } #ifdef SG_LUPDATE_IF #undef SG_LUPDATE_IF #endif #define SG_LUPDATE_IF(tgt,obj,memb) \ (((void *)(&(obj.memb))) == ((void *)(&(obj.memb[0])))) \ ? sg_lupdate_string(tgt, obj.memb, sizeof(obj.memb))\ : sg_update_string(tgt, obj.memb) #undef VECTOR_UPDATE_ERROR_CLEANUP #define VECTOR_UPDATE_ERROR_CLEANUP fclose(f); while((fread(&entry, sizeof(entry),1,f)) != 0){ #ifdef HAVE_UTMP_TYPE if( USER_PROCESS != ut->ut_type ) continue; #elif defined(HAVE_UTMP_NAME) if (entry.ut_name[0] == '\0') continue; #elif defined(HAVE_UTMP_USER) if (entry.ut_user[0] == '\0') continue; #endif VECTOR_UPDATE(user_stats_vector_ptr, num_users + 1, user_ptr, sg_user_stats); if( ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].device, entry, ut_line ) ) #if defined(HAVE_UTMP_USER) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].login_name, entry, ut_user ) ) #elif defined(HAVE_UTMP_NAME) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].login_name, entry, ut_name ) ) #endif #if defined(HAVE_UTMP_HOST) || ( SG_ERROR_NONE != SG_LUPDATE_IF( &user_ptr[num_users].hostname, entry, ut_host ) ) #endif #if defined(HAVE_UTMP_ID) || ( SG_ERROR_NONE != sg_update_mem( &user_ptr[num_users].record_id, entry.ut_id, sizeof(entry.ut_id) ) ) #endif ) { VECTOR_UPDATE_ERROR_CLEANUP RETURN_FROM_PREVIOUS_ERROR( "user", sg_get_error() ); } #if defined(HAVE_UTMP_ID) user_ptr[num_users].record_id_size = sizeof(entry.ut_id); #endif #if defined(HAVE_UTMP_PID) user_ptr[num_users].pid = entry.ut_pid; #endif #if defined(HAVE_UTMP_TIME) user_ptr[num_users].login_time = entry.ut_time; #endif user_ptr[num_users].systime = now; ++num_users; } fclose(f); #else RETURN_WITH_SET_ERROR("user", SG_ERROR_UNSUPPORTED, OS_TYPE); #endif return SG_ERROR_NONE; }
sg_page_stats *sg_get_page_stats() { #ifdef SOLARIS kstat_ctl_t *kc; kstat_t *ksp; cpu_stat_t cs; #endif #if defined(LINUX) || defined(CYGWIN) FILE *f; char *line_ptr; #endif #if defined(FREEBSD) || defined(DFBSD) size_t size; #endif #if defined(NETBSD) || defined(OPENBSD) struct uvmexp *uvm; #endif page_stats.systime = time(NULL); page_stats.pages_pagein=0; page_stats.pages_pageout=0; #ifdef SOLARIS if ((kc = kstat_open()) == NULL) { sg_set_error(SG_ERROR_KSTAT_OPEN, NULL); return NULL; } for (ksp = kc->kc_chain; ksp!=NULL; ksp = ksp->ks_next) { if ((strcmp(ksp->ks_module, "cpu_stat")) != 0) continue; if (kstat_read(kc, ksp, &cs) == -1) { continue; } page_stats.pages_pagein+=(long long)cs.cpu_vminfo.pgpgin; page_stats.pages_pageout+=(long long)cs.cpu_vminfo.pgpgout; } kstat_close(kc); #endif #if defined(LINUX) || defined(CYGWIN) if ((f = fopen("/proc/vmstat", "r")) != NULL) { while ((line_ptr = sg_f_read_line(f, "")) != NULL) { long long value; if (sscanf(line_ptr, "%*s %lld", &value) != 1) { continue; } if (strncmp(line_ptr, "pgpgin ", 7) == 0) { page_stats.pages_pagein = value; } else if (strncmp(line_ptr, "pgpgout ", 8) == 0) { page_stats.pages_pageout = value; } } fclose(f); } else if ((f = fopen("/proc/stat", "r")) != NULL) { if ((line_ptr = sg_f_read_line(f, "page")) == NULL) { sg_set_error(SG_ERROR_PARSE, "page"); fclose(f); return NULL; } if (sscanf(line_ptr, "page %lld %lld", &page_stats.pages_pagein, &page_stats.pages_pageout) != 2) { sg_set_error(SG_ERROR_PARSE, "page"); fclose(f); return NULL; } fclose(f); } else { sg_set_error(SG_ERROR_OPEN, "/proc/stat"); return NULL; } #endif #if defined(FREEBSD) || defined(DFBSD) size = sizeof page_stats.pages_pagein; if (sysctlbyname("vm.stats.vm.v_swappgsin", &page_stats.pages_pagein, &size, NULL, 0) < 0) { sg_set_error(SG_ERROR_SYSCTLBYNAME, "vm.stats.vm.v_swappgsin"); return NULL; } size = sizeof page_stats.pages_pageout; if (sysctlbyname("vm.stats.vm.v_swappgsout", &page_stats.pages_pageout, &size, NULL, 0) < 0) { sg_set_error(SG_ERROR_SYSCTLBYNAME, "vm.stats.vm.v_swappgsout"); return NULL; } #endif #if defined(NETBSD) || defined(OPENBSD) if ((uvm = sg_get_uvmexp()) == NULL) { return NULL; } page_stats.pages_pagein = uvm->pgswapin; page_stats.pages_pageout = uvm->pgswapout; #endif return &page_stats; }
sg_process_stats *sg_get_process_stats(int *entries){ VECTOR_DECLARE_STATIC(proc_state, sg_process_stats, 64, proc_state_init, proc_state_destroy); int proc_state_size = 0; sg_process_stats *proc_state_ptr; #ifdef HPUX struct pst_status pstat_procinfo[PROCESS_BATCH]; long procidx = 0; long long pagesize; int num, i; #endif #ifdef AIX struct procentry64 *procs = NULL; long long pagesize; int fetched = 0; pid_t index = 0; unsigned proc_idx; time_t utime, stime; int ncpus; struct timeval now_tval; double now_time; char cmndline[ARG_MAX]; char comm[ARG_MAX]; struct procentry64 curproc_for_getargs; #define PROCS_TO_FETCH 1000 #endif #ifdef ALLBSD int mib[4]; size_t size; struct kinfo_proc *kp_stats; int procs, i; char *proctitle; #if (defined(FREEBSD) && !defined(FREEBSD5)) || defined(DFBSD) kvm_t *kvmd; char **args, **argsp; int argslen = 0; #else long buflen; char *p, *proctitletmp; #endif #ifdef NETBSD2 int lwps; struct kinfo_lwp *kl_stats; #endif #endif #if defined(SOLARIS) || defined(LINUX) DIR *proc_dir; struct dirent *dir_entry; char filename[MAX_FILE_LENGTH]; FILE *f; #ifdef SOLARIS psinfo_t process_info; #endif #ifdef LINUX char s; /* If someone has a executable of 4k filename length, they deserve to get it truncated :) */ char ps_name[4096]; char *ptr; VECTOR_DECLARE_STATIC(psargs, char, 128, NULL, NULL); unsigned long stime, utime, starttime; int x; int fn; int len; int rc; time_t uptime; long tickspersec; #endif #ifdef LINUX if ((f=fopen("/proc/uptime", "r")) == NULL) { sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/uptime"); return NULL; } if((fscanf(f,"%lu %*d",&uptime)) != 1){ sg_set_error(SG_ERROR_PARSE, NULL); return NULL; } fclose(f); #endif if((proc_dir=opendir(PROC_LOCATION))==NULL){ sg_set_error_with_errno(SG_ERROR_OPENDIR, PROC_LOCATION); return NULL; } while((dir_entry=readdir(proc_dir))!=NULL){ if(atoi(dir_entry->d_name) == 0) continue; #ifdef SOLARIS snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/psinfo", dir_entry->d_name); #endif #ifdef LINUX snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/stat", dir_entry->d_name); #endif if((f=fopen(filename, "r"))==NULL){ /* Open failed.. Process since vanished, or the path was too long. * Ah well, move onwards to the next one */ continue; } #ifdef SOLARIS fread(&process_info, sizeof(psinfo_t), 1, f); fclose(f); #endif if (VECTOR_RESIZE(proc_state, proc_state_size + 1) < 0) { return NULL; } proc_state_ptr = proc_state+proc_state_size; #ifdef SOLARIS proc_state_ptr->pid = process_info.pr_pid; proc_state_ptr->parent = process_info.pr_ppid; proc_state_ptr->pgid = process_info.pr_pgid; proc_state_ptr->uid = process_info.pr_uid; proc_state_ptr->euid = process_info.pr_euid; proc_state_ptr->gid = process_info.pr_gid; proc_state_ptr->egid = process_info.pr_egid; proc_state_ptr->proc_size = (process_info.pr_size) * 1024; proc_state_ptr->proc_resident = (process_info.pr_rssize) * 1024; proc_state_ptr->time_spent = process_info.pr_time.tv_sec; proc_state_ptr->cpu_percent = (process_info.pr_pctcpu * 100.0) / 0x8000; proc_state_ptr->nice = (int)process_info.pr_lwp.pr_nice - 20; if (sg_update_string(&proc_state_ptr->process_name, process_info.pr_fname) < 0) { return NULL; } if (sg_update_string(&proc_state_ptr->proctitle, process_info.pr_psargs) < 0) { return NULL; } switch (process_info.pr_lwp.pr_state) { case 1: proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING; break; case 2: case 5: proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; break; case 3: proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE; break; case 4: proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; break; } #endif #ifdef LINUX x = fscanf(f, "%d %4096s %c %d %d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu %*d %*d %*d %d %*d %*d %lu %llu %llu %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*d\n", &(proc_state_ptr->pid), ps_name, &s, &(proc_state_ptr->parent), &(proc_state_ptr->pgid), &utime, &stime, &(proc_state_ptr->nice), &starttime, &(proc_state_ptr->proc_size), &(proc_state_ptr->proc_resident)); /* +3 becuase man page says "Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes." */ proc_state_ptr->proc_resident = (proc_state_ptr->proc_resident + 3) * getpagesize(); switch (s) { case 'S': proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING; break; case 'R': proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; break; case 'Z': proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE; break; case 'T': case 'D': proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; break; } /* pa_name[0] should = '(' */ ptr = strchr(&ps_name[1], ')'); if(ptr !=NULL) *ptr='\0'; if (sg_update_string(&proc_state_ptr->process_name, &ps_name[1]) < 0) { return NULL; } /* cpu */ proc_state_ptr->cpu_percent = (100.0 * (utime + stime)) / ((uptime * 100.0) - starttime); tickspersec = sysconf (_SC_CLK_TCK); if (tickspersec < 0) { proc_state_ptr->time_spent = 0; } else { proc_state_ptr->time_spent = (utime + stime) / tickspersec; } fclose(f); /* uid / gid */ snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/status", dir_entry->d_name); if ((f=fopen(filename, "r")) == NULL) { /* Open failed.. Process since vanished, or the path was too long. * Ah well, move onwards to the next one */ continue; } if((ptr=sg_f_read_line(f, "Uid:"))==NULL){ fclose(f); continue; } sscanf(ptr, "Uid:\t%d\t%d\t%*d\t%*d\n", &(proc_state_ptr->uid), &(proc_state_ptr->euid)); if((ptr=sg_f_read_line(f, "Gid:"))==NULL){ fclose(f); continue; } sscanf(ptr, "Gid:\t%d\t%d\t%*d\t%*d\n", &(proc_state_ptr->gid), &(proc_state_ptr->egid)); fclose(f); /* proctitle */ snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/cmdline", dir_entry->d_name); if((fn=open(filename, O_RDONLY)) == -1){ /* Open failed.. Process since vanished, or the path was too long. * Ah well, move onwards to the next one */ continue; } #define READ_BLOCK_SIZE 128 len = 0; do { if (VECTOR_RESIZE(psargs, len + READ_BLOCK_SIZE) < 0) { return NULL; } rc = read(fn, psargs + len, READ_BLOCK_SIZE); if (rc > 0) { len += rc; } } while (rc == READ_BLOCK_SIZE); close(fn); if (rc == -1) { /* Read failed; move on. */ continue; } /* Turn \0s into spaces within the command line. */ ptr = psargs; for(x = 0; x < len; x++) { if (*ptr == '\0') *ptr = ' '; ptr++; } if (len == 0) { /* We want psargs to be NULL. */ if (VECTOR_RESIZE(psargs, 0) < 0) { return NULL; } } else { /* Not empty, so append a \0. */ if (VECTOR_RESIZE(psargs, len + 1) < 0) { return NULL; } psargs[len] = '\0'; } if (sg_update_string(&proc_state_ptr->proctitle, psargs) < 0) { return NULL; } #endif proc_state_size++; } closedir(proc_dir); #endif #ifdef ALLBSD mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_ALL; if(sysctl(mib, 3, NULL, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_PROC.KERN_PROC_ALL"); return NULL; } procs = size / sizeof(struct kinfo_proc); kp_stats = sg_malloc(size); if(kp_stats == NULL) { return NULL; } memset(kp_stats, 0, size); if(sysctl(mib, 3, kp_stats, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_PROC.KERN_PROC_ALL"); free(kp_stats); return NULL; } #if (defined(FREEBSD) && !defined(FREEBSD5)) || defined(DFBSD) kvmd = sg_get_kvm2(); #endif for (i = 0; i < procs; i++) { const char *name; #ifdef FREEBSD5 if (kp_stats[i].ki_stat == 0) { #else if (kp_stats[i].kp_proc.p_stat == 0) { #endif /* FreeBSD 5 deliberately overallocates the array that * the sysctl returns, so we'll get a few junk * processes on the end that we have to ignore. (Search * for "overestimate by 5 procs" in * src/sys/kern/kern_proc.c for more details.) */ continue; } if (VECTOR_RESIZE(proc_state, proc_state_size + 1) < 0) { return NULL; } proc_state_ptr = proc_state+proc_state_size; #ifdef FREEBSD5 name = kp_stats[i].ki_comm; #elif defined(DFBSD) name = kp_stats[i].kp_thread.td_comm; #else name = kp_stats[i].kp_proc.p_comm; #endif if (sg_update_string(&proc_state_ptr->process_name, name) < 0) { return NULL; } #if defined(FREEBSD5) || defined(NETBSD) || defined(OPENBSD) #ifdef FREEBSD5 mib[2] = KERN_PROC_ARGS; mib[3] = kp_stats[i].ki_pid; #else mib[1] = KERN_PROC_ARGS; mib[2] = kp_stats[i].kp_proc.p_pid; mib[3] = KERN_PROC_ARGV; #endif free(proc_state_ptr->proctitle); proc_state_ptr->proctitle = NULL; /* Starting size - we'll double this straight away */ #define PROCTITLE_START_SIZE 64 buflen = PROCTITLE_START_SIZE; size = buflen; proctitle = NULL; do { if((long) size >= buflen) { buflen *= 2; size = buflen; proctitletmp = sg_realloc(proctitle, buflen); if(proctitletmp == NULL) { free(proctitle); proctitle = NULL; proc_state_ptr->proctitle = NULL; size = 0; break; } proctitle = proctitletmp; bzero(proctitle, buflen); } if(sysctl(mib, 4, proctitle, &size, NULL, 0) < 0) { free(proctitle); proctitle = NULL; proc_state_ptr->proctitle = NULL; size = 0; break; } } while((long) size >= buflen); if(size > 0) { proc_state_ptr->proctitle = sg_malloc(size+1); if(proc_state_ptr->proctitle == NULL) { return NULL; } p = proctitle; #ifdef OPENBSD /* On OpenBSD, this value has the argv pointers (which * are terminated by a NULL) at the front, so we have * to skip over them to get to the strings. */ while (*(char ***)p != NULL) { p += sizeof(char **); } p += sizeof(char **); #endif proc_state_ptr->proctitle[0] = '\0'; do { sg_strlcat(proc_state_ptr->proctitle, p, size+1); sg_strlcat(proc_state_ptr->proctitle, " ", size+1); p += strlen(p) + 1; } while (p < proctitle + size); free(proctitle); proctitle = NULL; /* remove trailing space */ proc_state_ptr->proctitle[strlen(proc_state_ptr->proctitle)-1] = '\0'; } else { if(proctitle != NULL) { free(proctitle); proctitle = NULL; } proc_state_ptr->proctitle = NULL; } #else free(proc_state_ptr->proctitle); proc_state_ptr->proctitle = NULL; if(kvmd != NULL) { args = kvm_getargv(kvmd, &(kp_stats[i]), 0); if(args != NULL) { argsp = args; while(*argsp != NULL) { argslen += strlen(*argsp) + 1; argsp++; } proctitle = sg_malloc(argslen + 1); proctitle[0] = '\0'; if(proctitle == NULL) { return NULL; } while(*args != NULL) { sg_strlcat(proctitle, *args, argslen + 1); sg_strlcat(proctitle, " ", argslen + 1); args++; } /* remove trailing space */ proctitle[strlen(proctitle)-1] = '\0'; proc_state_ptr->proctitle = proctitle; } else { proc_state_ptr->proctitle = NULL; } } else { proc_state_ptr->proctitle = NULL; } #endif #ifdef FREEBSD5 proc_state_ptr->pid = kp_stats[i].ki_pid; proc_state_ptr->parent = kp_stats[i].ki_ppid; proc_state_ptr->pgid = kp_stats[i].ki_pgid; #else proc_state_ptr->pid = kp_stats[i].kp_proc.p_pid; proc_state_ptr->parent = kp_stats[i].kp_eproc.e_ppid; proc_state_ptr->pgid = kp_stats[i].kp_eproc.e_pgid; #endif #ifdef FREEBSD5 proc_state_ptr->uid = kp_stats[i].ki_ruid; proc_state_ptr->euid = kp_stats[i].ki_uid; proc_state_ptr->gid = kp_stats[i].ki_rgid; proc_state_ptr->egid = kp_stats[i].ki_svgid; #elif defined(DFBSD) proc_state_ptr->uid = kp_stats[i].kp_eproc.e_ucred.cr_ruid; proc_state_ptr->euid = kp_stats[i].kp_eproc.e_ucred.cr_svuid; proc_state_ptr->gid = kp_stats[i].kp_eproc.e_ucred.cr_rgid; proc_state_ptr->egid = kp_stats[i].kp_eproc.e_ucred.cr_svgid; #else proc_state_ptr->uid = kp_stats[i].kp_eproc.e_pcred.p_ruid; proc_state_ptr->euid = kp_stats[i].kp_eproc.e_pcred.p_svuid; proc_state_ptr->gid = kp_stats[i].kp_eproc.e_pcred.p_rgid; proc_state_ptr->egid = kp_stats[i].kp_eproc.e_pcred.p_svgid; #endif #ifdef FREEBSD5 proc_state_ptr->proc_size = kp_stats[i].ki_size; /* This is in pages */ proc_state_ptr->proc_resident = kp_stats[i].ki_rssize * getpagesize(); /* This is in microseconds */ proc_state_ptr->time_spent = kp_stats[i].ki_runtime / 1000000; proc_state_ptr->cpu_percent = ((double)kp_stats[i].ki_pctcpu / FSCALE) * 100.0; proc_state_ptr->nice = kp_stats[i].ki_nice; #else proc_state_ptr->proc_size = kp_stats[i].kp_eproc.e_vm.vm_map.size; /* This is in pages */ proc_state_ptr->proc_resident = kp_stats[i].kp_eproc.e_vm.vm_rssize * getpagesize(); #if defined(NETBSD) || defined(OPENBSD) proc_state_ptr->time_spent = kp_stats[i].kp_proc.p_rtime.tv_sec; #elif defined(DFBSD) proc_state_ptr->time_spent = ( kp_stats[i].kp_thread.td_uticks + kp_stats[i].kp_thread.td_sticks + kp_stats[i].kp_thread.td_iticks ) / 1000000; #else /* This is in microseconds */ proc_state_ptr->time_spent = kp_stats[i].kp_proc.p_runtime / 1000000; #endif proc_state_ptr->cpu_percent = ((double)kp_stats[i].kp_proc.p_pctcpu / FSCALE) * 100.0; proc_state_ptr->nice = kp_stats[i].kp_proc.p_nice; #endif #ifdef NETBSD2 { size_t size; int mib[5]; mib[0] = CTL_KERN; mib[1] = KERN_LWP; mib[2] = kp_stats[i].kp_proc.p_pid; mib[3] = sizeof(struct kinfo_lwp); mib[4] = 0; if(sysctl(mib, 5, NULL, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_LWP.pid.structsize.0"); return NULL; } lwps = size / sizeof(struct kinfo_lwp); mib[4] = lwps; kl_stats = sg_malloc(size); if(kl_stats == NULL) { return NULL; } if(sysctl(mib, 5, kl_stats, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_LWP.pid.structsize.buffersize"); return NULL; } } switch(kp_stats[i].kp_proc.p_stat) { case SIDL: proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; break; case SACTIVE: { int i; for(i = 0; i < lwps; i++) { switch(kl_stats[i].l_stat) { case LSONPROC: case LSRUN: proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; goto end; case LSSLEEP: proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING; goto end; case LSSTOP: case LSSUSPENDED: proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; goto end; } proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN; } end: ; } break; case SSTOP: proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; break; case SZOMB: proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE; break; default: proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN; break; } free(kl_stats); #else #ifdef FREEBSD5 switch (kp_stats[i].ki_stat) { #else switch (kp_stats[i].kp_proc.p_stat) { #endif case SIDL: case SRUN: #ifdef SONPROC case SONPROC: /* NetBSD */ #endif proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; break; case SSLEEP: #ifdef SWAIT case SWAIT: /* FreeBSD 5 */ #endif #ifdef SLOCK case SLOCK: /* FreeBSD 5 */ #endif proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING; break; case SSTOP: proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; break; case SZOMB: #ifdef SDEAD case SDEAD: /* OpenBSD & NetBSD */ #endif proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE; break; default: proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN; break; } #endif proc_state_size++; } free(kp_stats); #endif #ifdef HPUX if ((pagesize = sysconf(_SC_PAGESIZE)) == -1) { sg_set_error_with_errno(SG_ERROR_SYSCONF, "_SC_PAGESIZE"); return NULL; } while (1) { num = pstat_getproc(pstat_procinfo, sizeof pstat_procinfo[0], PROCESS_BATCH, procidx); if (num == -1) { sg_set_error_with_errno(SG_ERROR_PSTAT, "pstat_getproc"); return NULL; } else if (num == 0) { break; } for (i = 0; i < num; i++) { struct pst_status *pi = &pstat_procinfo[i]; if (VECTOR_RESIZE(proc_state, proc_state_size + 1) < 0) { return NULL; } proc_state_ptr = proc_state+proc_state_size; proc_state_ptr->pid = pi->pst_pid; proc_state_ptr->parent = pi->pst_ppid; proc_state_ptr->pgid = pi->pst_pgrp; proc_state_ptr->uid = pi->pst_uid; proc_state_ptr->euid = pi->pst_euid; proc_state_ptr->gid = pi->pst_gid; proc_state_ptr->egid = pi->pst_egid; proc_state_ptr->proc_size = (pi->pst_dsize + pi->pst_tsize + pi->pst_ssize) * pagesize; proc_state_ptr->proc_resident = pi->pst_rssize * pagesize; proc_state_ptr->time_spent = pi->pst_time; proc_state_ptr->cpu_percent = (pi->pst_pctcpu * 100.0) / 0x8000; proc_state_ptr->nice = pi->pst_nice; if (sg_update_string(&proc_state_ptr->process_name, pi->pst_ucomm) < 0) { return NULL; } if (sg_update_string(&proc_state_ptr->proctitle, pi->pst_cmd) < 0) { return NULL; } switch (pi->pst_stat) { case PS_SLEEP: proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING; break; case PS_RUN: proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; break; case PS_STOP: proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; break; case PS_ZOMBIE: proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE; break; case PS_IDLE: case PS_OTHER: proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN; break; } proc_state_size++; } procidx = pstat_procinfo[num - 1].pst_idx + 1; } #endif #ifdef AIX #define TVALU_TO_SEC(x) ((x).tv_sec + ((double)((x).tv_usec) / 1000000.0)) #define TVALN_TO_SEC(x) ((x).tv_sec + ((double)((x).tv_usec) / 1000000000.0)) ncpus = sysconf(_SC_NPROCESSORS_ONLN); if( -1 == ncpus ) { ncpus = 1; /* sysconf error - assume 1 */ } if ((pagesize = sysconf(_SC_PAGESIZE)) == -1) { sg_set_error_with_errno(SG_ERROR_SYSCONF, "_SC_PAGESIZE"); return NULL; } proc_idx = 0; procs = /* (struct procentry64 *) */ malloc(sizeof(*procs) * PROCS_TO_FETCH); if(NULL == procs) { sg_set_error_with_errno(SG_ERROR_MALLOC, "sg_get_process_stats"); return 0; } gettimeofday(&now_tval, 0); now_time = TVALU_TO_SEC(now_tval); /* keep on grabbing chunks of processes until getprocs returns a smaller block than we asked for */ do { int i; fetched = getprocs64(procs, sizeof(*procs), NULL, 0, &index, PROCS_TO_FETCH); if (VECTOR_RESIZE(proc_state, proc_state_size + fetched) < 0) { sg_set_error_with_errno(SG_ERROR_MALLOC, "sg_get_process_stats"); free(procs); return NULL; } for( i = 0; i < fetched; ++i ) { struct procentry64 *pi = procs+i; int zombie = 0; proc_state_ptr = proc_state + proc_idx; zombie = 0; /* set a descriptive name for the process state */ switch( pi->pi_state ) { case SSLEEP: proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING; break; case SRUN: proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; break; case SZOMB: proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE; zombie = 1; break; case SSTOP: proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; break; case SACTIVE: proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; break; case SIDL: default: proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN; break; } if( zombie ) { utime = pi->pi_utime; stime = pi->pi_stime; } else { utime = TVALN_TO_SEC(pi->pi_ru.ru_utime) + TVALN_TO_SEC(pi->pi_cru.ru_utime); stime = TVALN_TO_SEC(pi->pi_ru.ru_stime) + TVALN_TO_SEC(pi->pi_cru.ru_stime); } proc_state_ptr->pid = pi->pi_pid; proc_state_ptr->parent = pi->pi_ppid; proc_state_ptr->pgid = pi->pi_pgrp; proc_state_ptr->uid = pi->pi_cred.crx_ruid; proc_state_ptr->euid = pi->pi_cred.crx_uid; proc_state_ptr->gid = pi->pi_cred.crx_rgid; proc_state_ptr->egid = pi->pi_cred.crx_gid; proc_state_ptr->proc_size = pi->pi_size; proc_state_ptr->proc_resident = pi->pi_drss + pi->pi_trss; /* XXX might be wrong, see P::PT */ proc_state_ptr->time_spent = utime + stime; proc_state_ptr->cpu_percent = (((double)(utime + stime) * 100) / ( now_time - pi->pi_start )) / ncpus; proc_state_ptr->nice = pi->pi_nice; /* determine comm & cmndline */ if( (pi->pi_flags & SKPROC) == SKPROC ) { if( pi->pi_pid == 0 ) { snprintf(comm, ARG_MAX, "kproc (swapper)"); snprintf(cmndline, ARG_MAX, "kproc (swapper)"); } else { snprintf(comm, ARG_MAX, "kproc (%s)", pi->pi_comm); snprintf(cmndline, ARG_MAX, "kproc (%s)", pi->pi_comm); } } else { snprintf(comm, ARG_MAX, "%s", pi->pi_comm); curproc_for_getargs.pi_pid = pi->pi_pid; if( getargs(&curproc_for_getargs, sizeof(curproc_for_getargs), cmndline, ARG_MAX) < 0 ) { snprintf(cmndline, ARG_MAX, "%s", pi->pi_comm); } else { int done = 0; /* replace NUL characters in command line with spaces */ char *c = cmndline; while( ! done ) { if( *c == '\0' ) { if( *(c+1) == '\0' ) { done = 1; } else { *c++ = ' '; } } else { ++c; } } } } if (sg_update_string(&proc_state_ptr->process_name, comm) < 0) { free(procs); return NULL; } if (sg_update_string(&proc_state_ptr->proctitle, cmndline) < 0) { free(procs); return NULL; } proc_idx++; } } while( fetched >= PROCS_TO_FETCH ); proc_state_size = proc_idx; free(procs); #endif #ifdef CYGWIN sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin"); return NULL; #endif #ifdef WIN32 /* FIXME The data needed for this is probably do able with the * "performance registry". Although using this appears to be a black * art and closely guarded secret. * This is not directly used in ihost, so not considered a priority */ sg_set_error(SG_ERROR_UNSUPPORTED, "Win32"); return NULL; #endif *entries = proc_state_size; return proc_state; } sg_process_count *sg_get_process_count() { static sg_process_count process_stat; #ifndef WIN32 sg_process_stats *ps; int ps_size, x; #else DWORD aProcesses[1024]; DWORD cbNeeded; #endif process_stat.sleeping = 0; process_stat.running = 0; process_stat.zombie = 0; process_stat.stopped = 0; process_stat.total = 0; #ifndef WIN32 ps = sg_get_process_stats(&ps_size); if (ps == NULL) { return NULL; } for(x = 0; x < ps_size; x++) { switch (ps->state) { case SG_PROCESS_STATE_RUNNING: process_stat.running++; break; case SG_PROCESS_STATE_SLEEPING: process_stat.sleeping++; break; case SG_PROCESS_STATE_STOPPED: process_stat.stopped++; break; case SG_PROCESS_STATE_ZOMBIE: process_stat.zombie++; break; default: /* currently no mapping for SG_PROCESS_STATE_UNKNOWN in * sg_process_count */ break; } ps++; } process_stat.total = ps_size; #else if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) return NULL; process_stat.total = cbNeeded / sizeof(DWORD); #endif return &process_stat; } int sg_process_compare_name(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; return strcmp(a->process_name, b->process_name); } int sg_process_compare_pid(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->pid < b->pid) { return -1; } else if (a->pid == b->pid) { return 0; } else { return 1; } } int sg_process_compare_uid(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->uid < b->uid) { return -1; } else if (a->uid == b->uid) { return 0; } else { return 1; } } int sg_process_compare_gid(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->gid < b->gid) { return -1; } else if (a->gid == b->gid) { return 0; } else { return 1; } } int sg_process_compare_size(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->proc_size < b->proc_size) { return -1; } else if (a->proc_size == b->proc_size) { return 0; } else { return 1; } } int sg_process_compare_res(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->proc_resident < b->proc_resident) { return -1; } else if (a->proc_resident == b->proc_resident) { return 0; } else { return 1; } } int sg_process_compare_cpu(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->cpu_percent < b->cpu_percent) { return -1; } else if (a->cpu_percent == b->cpu_percent) { return 0; } else { return 1; } } int sg_process_compare_time(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->time_spent < b->time_spent) { return -1; } else if (a->time_spent == b->time_spent) { return 0; } else { return 1; } }
sg_page_stats *sg_get_page_stats(){ #ifdef SOLARIS kstat_ctl_t *kc; kstat_t *ksp; cpu_stat_t cs; #endif #if defined(LINUX) || defined(CYGWIN) FILE *f; char *line_ptr; #endif #if defined(FREEBSD) || defined(DFBSD) size_t size; #endif #if defined(NETBSD) || defined(OPENBSD) struct uvmexp *uvm; #endif #ifdef AIX perfstat_memory_total_t mem; #endif #ifdef HPUX struct pst_vminfo vminfo; #endif page_stats.systime = time(NULL); page_stats.pages_pagein=0; page_stats.pages_pageout=0; #ifdef SOLARIS if ((kc = kstat_open()) == NULL) { sg_set_error(SG_ERROR_KSTAT_OPEN, NULL); return NULL; } for (ksp = kc->kc_chain; ksp!=NULL; ksp = ksp->ks_next) { if ((strcmp(ksp->ks_module, "cpu_stat")) != 0) continue; if (kstat_read(kc, ksp, &cs) == -1) { continue; } page_stats.pages_pagein+=(long long)cs.cpu_vminfo.pgpgin; page_stats.pages_pageout+=(long long)cs.cpu_vminfo.pgpgout; } kstat_close(kc); #endif #if defined(LINUX) || defined(CYGWIN) if ((f = fopen("/proc/vmstat", "r")) != NULL) { while ((line_ptr = sg_f_read_line(f, "")) != NULL) { long long value; if (sscanf(line_ptr, "%*s %lld", &value) != 1) { continue; } if (strncmp(line_ptr, "pgpgin ", 7) == 0) { page_stats.pages_pagein = value; } else if (strncmp(line_ptr, "pgpgout ", 8) == 0) { page_stats.pages_pageout = value; } } fclose(f); } else if ((f = fopen("/proc/stat", "r")) != NULL) { if ((line_ptr = sg_f_read_line(f, "page")) == NULL) { sg_set_error(SG_ERROR_PARSE, "page"); fclose(f); return NULL; } if (sscanf(line_ptr, "page %lld %lld", &page_stats.pages_pagein, &page_stats.pages_pageout) != 2) { sg_set_error(SG_ERROR_PARSE, "page"); fclose(f); return NULL; } fclose(f); } else { sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/stat"); return NULL; } #endif #if defined(FREEBSD) || defined(DFBSD) size = sizeof page_stats.pages_pagein; if (sysctlbyname("vm.stats.vm.v_swappgsin", &page_stats.pages_pagein, &size, NULL, 0) < 0){ sg_set_error_with_errno(SG_ERROR_SYSCTLBYNAME, "vm.stats.vm.v_swappgsin"); return NULL; } size = sizeof page_stats.pages_pageout; if (sysctlbyname("vm.stats.vm.v_swappgsout", &page_stats.pages_pageout, &size, NULL, 0) < 0){ sg_set_error_with_errno(SG_ERROR_SYSCTLBYNAME, "vm.stats.vm.v_swappgsout"); return NULL; } #endif #if defined(NETBSD) || defined(OPENBSD) if ((uvm = sg_get_uvmexp()) == NULL) { return NULL; } page_stats.pages_pagein = uvm->pgswapin; page_stats.pages_pageout = uvm->pgswapout; #endif #ifdef AIX /* return code is number of structures returned */ if(perfstat_memory_total(NULL, &mem, sizeof(perfstat_memory_total_t), 1) != 1) { sg_set_error_with_errno(SG_ERROR_SYSCTLBYNAME, "perfstat_memory_total"); return NULL; } page_stats.pages_pagein = mem.pgins; page_stats.pages_pageout = mem.pgouts; #endif #ifdef HPUX if( pstat_getvminfo( &vminfo, sizeof(vminfo), 1, 0 ) == -1 ) { sg_set_error_with_errno(SG_ERROR_SYSCTLBYNAME, "pstat_getswap"); return NULL; }; page_stats.pages_pagein = vminfo.psv_spgin; page_stats.pages_pageout = vminfo.psv_spgout; #endif #ifdef WIN32 sg_set_error(SG_ERROR_UNSUPPORTED, "Win32"); return NULL; #endif return &page_stats; }
sg_host_info *sg_get_host_info(){ static sg_host_info general_stat; static struct utsname os; #ifdef SOLARIS time_t boottime,curtime; kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *kn; #endif #if defined(LINUX) || defined(CYGWIN) FILE *f; #endif #ifdef ALLBSD int mib[2]; struct timeval boottime; time_t curtime; size_t size; #endif if((uname(&os)) < 0){ sg_set_error(SG_ERROR_UNAME, NULL); return NULL; } general_stat.os_name = os.sysname; general_stat.os_release = os.release; general_stat.os_version = os.version; general_stat.platform = os.machine; general_stat.hostname = os.nodename; /* get uptime */ #ifdef SOLARIS if ((kc = kstat_open()) == NULL) { sg_set_error(SG_ERROR_KSTAT_OPEN, NULL); return NULL; } if((ksp=kstat_lookup(kc, "unix", -1, "system_misc"))==NULL){ sg_set_error(SG_ERROR_KSTAT_LOOKUP, "unix,-1,system_misc"); return NULL; } if (kstat_read(kc, ksp, 0) == -1) { sg_set_error(SG_ERROR_KSTAT_READ, NULL); return NULL; } if((kn=kstat_data_lookup(ksp, "boot_time")) == NULL){ sg_set_error(SG_ERROR_KSTAT_DATA_LOOKUP, "boot_time"); return NULL; } boottime=(kn->value.ui32); kstat_close(kc); time(&curtime); general_stat.uptime = curtime - boottime; #endif #if defined(LINUX) || defined(CYGWIN) if ((f=fopen("/proc/uptime", "r")) == NULL) { sg_set_error(SG_ERROR_OPEN, "/proc/uptime"); return NULL; } if((fscanf(f,"%lu %*d",&general_stat.uptime)) != 1){ sg_set_error(SG_ERROR_PARSE, NULL); return NULL; } fclose(f); #endif #ifdef ALLBSD mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; size = sizeof boottime; if (sysctl(mib, 2, &boottime, &size, NULL, 0) < 0){ sg_set_error(SG_ERROR_SYSCTL, "CTL_KERN.KERN_BOOTTIME"); return NULL; } time(&curtime); general_stat.uptime=curtime-boottime.tv_sec; #endif return &general_stat; }
sg_fs_stats *sg_get_fs_stats(int *entries){ VECTOR_DECLARE_STATIC(disk_stats, sg_fs_stats, 10, disk_stat_init, disk_stat_destroy); int num_disks=0; #if defined(LINUX) || defined (SOLARIS) || defined(CYGWIN) || defined(HPUX) FILE *f; #endif sg_fs_stats *disk_ptr; #ifdef SOLARIS struct mnttab mp; struct statvfs fs; #endif #if defined(LINUX) || defined(CYGWIN) || defined(HPUX) struct mntent *mp; struct statvfs fs; #endif #ifdef ALLBSD int nummnt; #ifdef HAVE_STATVFS struct statvfs *mp, **fs; #else struct statfs *mp, **fs; #endif #endif #ifdef WIN32 char lp_buf[MAX_PATH]; char volume_name_buf[BUFSIZE]; char filesys_name_buf[BUFSIZE]; char drive[4] = " :\\"; char *p; int drive_type; //@ lp_buf[0]='\0'; #endif #ifdef ALLBSD nummnt=getmntinfo(&mp, MNT_WAIT); if (nummnt<=0){ sg_set_error_with_errno(SG_ERROR_GETMNTINFO, NULL); return NULL; } for(fs = ∓ nummnt--; (*fs)++){ #endif #if defined(LINUX) || defined(CYGWIN) || defined(HPUX) #ifdef MNT_MNTTAB if ((f=setmntent(MNT_MNTTAB, "r" ))==NULL){ #else if ((f=setmntent("/etc/mtab", "r" ))==NULL){ #endif sg_set_error(SG_ERROR_SETMNTENT, NULL); return NULL; } while((mp=getmntent(f))){ if((statvfs(mp->mnt_dir, &fs)) !=0){ continue; } #endif #ifdef SOLARIS if ((f=fopen("/etc/mnttab", "r" ))==NULL){ sg_set_error_with_errno(SG_ERROR_OPEN, "/etc/mnttab"); return NULL; } while((getmntent(f, &mp)) == 0){ if ((statvfs(mp.mnt_mountp, &fs)) !=0){ continue; } #endif #ifdef WIN32 if (!(GetLogicalDriveStringsA(BUFSIZE-1, lp_buf))) { sg_set_error(SG_ERROR_GETMNTINFO, "GetLogicalDriveStrings"); return NULL; } p = lp_buf; do { // Copy drive letter to template string *drive = *p; // Only interested in harddrives. drive_type = GetDriveTypeA(drive); if(drive_type == DRIVE_FIXED) { #else if(is_valid_fs_type(SG_MP_FSTYPENAME(mp))){ #endif if (VECTOR_RESIZE(disk_stats, num_disks + 1) < 0) { return NULL; } disk_ptr=disk_stats+num_disks; #ifndef WIN32 /* Maybe make this char[bigenough] and do strncpy's and put a null in the end? * Downside is its a bit hungry for a lot of mounts, as MNT_MAX_SIZE would prob * be upwards of a k each */ if (sg_update_string(&disk_ptr->device_name, SG_MP_DEVNAME(mp)) < 0) { return NULL; } if (sg_update_string(&disk_ptr->fs_type, SG_MP_FSTYPENAME(mp)) < 0) { return NULL; } if (sg_update_string(&disk_ptr->mnt_point, SG_MP_MOUNTP(mp)) < 0) { return NULL; } disk_ptr->size = SG_FS_FRSIZE(fs) * SG_FS_BLOCKS(fs); disk_ptr->avail = SG_FS_FRSIZE(fs) * SG_FS_BAVAIL(fs); disk_ptr->used = (disk_ptr->size) - (SG_FS_FRSIZE(fs) * SG_FS_BFREE(fs)); disk_ptr->total_inodes = SG_FS_FILES(fs); disk_ptr->free_inodes = SG_FS_FFREE(fs); /* Linux, FreeBSD don't have a "available" inodes */ disk_ptr->used_inodes = disk_ptr->total_inodes - disk_ptr->free_inodes; disk_ptr->avail_inodes = SG_FS_FAVAIL(fs); disk_ptr->io_size = SG_FS_BSIZE(fs); disk_ptr->block_size = SG_FS_FRSIZE(fs); disk_ptr->total_blocks = SG_FS_BLOCKS(fs); disk_ptr->free_blocks = SG_FS_BFREE(fs); disk_ptr->avail_blocks = SG_FS_BAVAIL(fs); disk_ptr->used_blocks = disk_ptr->total_blocks - disk_ptr->free_blocks; #else if(!GetVolumeInformationA(drive, volume_name_buf, BUFSIZE, NULL, NULL, NULL, filesys_name_buf, BUFSIZE)) { sg_set_error_with_errno(SG_ERROR_DISKINFO, "GetVolumeInformation"); return NULL; } if (sg_update_string(&disk_ptr->device_name, volume_name_buf) < 0) { return NULL; } if (sg_update_string(&disk_ptr->fs_type, filesys_name_buf) < 0) { return NULL; } if (sg_update_string(&disk_ptr->mnt_point, drive) < 0) { return NULL; } if (!GetDiskFreeSpaceExA(drive, NULL, (PULARGE_INTEGER)&disk_ptr->size, (PULARGE_INTEGER)&disk_ptr->avail)) { sg_set_error_with_errno(SG_ERROR_DISKINFO, "GetDiskFreeSpaceEx"); return NULL; } disk_ptr->used = disk_ptr->size - disk_ptr->avail; disk_ptr->total_inodes = 0; disk_ptr->free_inodes = 0; disk_ptr->used_inodes = 0; disk_ptr->avail_inodes = 0; /* I dunno what to do with these... so have nothing */ disk_ptr->io_size = 0; disk_ptr->block_size = 0; disk_ptr->total_blocks = 0; disk_ptr->free_blocks = 0; disk_ptr->avail_blocks = 0; disk_ptr->used_blocks = 0; #endif num_disks++; } #ifdef WIN32 while(*p++); } while(*p); #else } #endif *entries=num_disks; /* If this fails, there is very little i can do about it, so I'll ignore it :) */ #if defined(LINUX) || defined(CYGWIN) || defined(HPUX) endmntent(f); #endif #if defined(SOLARIS) fclose(f); #endif return disk_stats; } int sg_fs_compare_device_name(const void *va, const void *vb) { const sg_fs_stats *a = (const sg_fs_stats *)va; const sg_fs_stats *b = (const sg_fs_stats *)vb; return strcmp(a->device_name, b->device_name); } int sg_fs_compare_mnt_point(const void *va, const void *vb) { const sg_fs_stats *a = (const sg_fs_stats *)va; const sg_fs_stats *b = (const sg_fs_stats *)vb; return strcmp(a->mnt_point, b->mnt_point); } static void diskio_stat_init(sg_disk_io_stats *d) { d->disk_name = NULL; } static void diskio_stat_destroy(sg_disk_io_stats *d) { free(d->disk_name); } VECTOR_DECLARE_STATIC(diskio_stats, sg_disk_io_stats, 10, diskio_stat_init, diskio_stat_destroy); #ifdef LINUX typedef struct { int major; int minor; } partition; #endif sg_disk_io_stats *sg_get_disk_io_stats(int *entries){ int num_diskio; #ifndef LINUX sg_disk_io_stats *diskio_stats_ptr; #endif #ifdef HPUX long long rbytes = 0, wbytes = 0; struct dirent *dinfo = NULL; struct stat lstatinfo; struct pst_diskinfo pstat_diskinfo[DISK_BATCH]; char fullpathbuf[1024] = {0}; dev_t diskid; DIR *dh = NULL; int diskidx = 0; int num, i; #endif #ifdef SOLARIS kstat_ctl_t *kc; kstat_t *ksp; kstat_io_t kios; #endif #ifdef LINUX FILE *f; char *line_ptr; int major, minor; int has_pp_stats = 1; VECTOR_DECLARE_STATIC(parts, partition, 16, NULL, NULL); int i, n; time_t now; const char *format; static regex_t not_part_re, part_re; static int re_compiled = 0; #endif #if defined(FREEBSD) || defined(DFBSD) static struct statinfo stats; static int stats_init = 0; int counter; struct device_selection *dev_sel = NULL; int n_selected, n_selections; long sel_gen; struct devstat *dev_ptr; #endif #ifdef NETBSD struct disk_sysctl *stats; #endif #ifdef OPENBSD int diskcount; char *disknames, *name, *bufpp; char **dk_name; struct diskstats *stats; #endif #ifdef NETBSD #define MIBSIZE 3 #endif #ifdef OPENBSD #define MIBSIZE 2 #endif #if defined(NETBSD) || defined(OPENBSD) int num_disks, i; int mib[MIBSIZE]; size_t size; #endif #ifdef WIN32 char *name; long long rbytes; long long wbytes; #endif num_diskio=0; #ifdef HPUX while (1) { num = pstat_getdisk(pstat_diskinfo, sizeof pstat_diskinfo[0], DISK_BATCH, diskidx); if (num == -1) { sg_set_error_with_errno(SG_ERROR_PSTAT, "pstat_getdisk"); return NULL; } else if (num == 0) { break; } for (i = 0; i < num; i++) { struct pst_diskinfo *di = &pstat_diskinfo[i]; /* Skip "disabled" disks. */ if (di->psd_status == 0) { continue; } /* We can't seperate the reads from the writes, we'll * just give the same to each. (This value is in * 64-byte chunks according to the pstat header file, * and can wrap to be negative.) */ rbytes = wbytes = ((unsigned long) di->psd_dkwds) * 64LL; /* Skip unused disks. */ if (rbytes == 0 && wbytes == 0) { continue; } if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) { return NULL; } diskio_stats_ptr = diskio_stats + num_diskio; diskio_stats_ptr->read_bytes = rbytes; diskio_stats_ptr->write_bytes = wbytes; diskio_stats_ptr->systime = time(NULL); num_diskio++; /* FIXME This should use a static cache, like the Linux * code below. */ if (diskio_stats_ptr->disk_name == NULL) { dh = opendir("/dev/dsk"); if (dh == NULL) { continue; } diskid = (di->psd_dev.psd_major << 24) | di->psd_dev.psd_minor; while (1) { dinfo = readdir(dh); if (dinfo == NULL) { break; } snprintf(fullpathbuf, sizeof(fullpathbuf), "/dev/dsk/%s", dinfo->d_name); if (lstat(fullpathbuf, &lstatinfo) < 0) { continue; } if (lstatinfo.st_rdev == diskid) { if (sg_update_string(&diskio_stats_ptr->disk_name, dinfo->d_name) < 0) { return NULL; } break; } } closedir(dh); if (diskio_stats_ptr->disk_name == NULL) { if (sg_update_string(&diskio_stats_ptr->disk_name, di->psd_hw_path.psh_name) < 0) { return NULL; } } } } diskidx = pstat_diskinfo[num - 1].psd_idx + 1; } #endif #ifdef OPENBSD mib[0] = CTL_HW; mib[1] = HW_DISKCOUNT; size = sizeof(diskcount); if (sysctl(mib, MIBSIZE, &diskcount, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKCOUNT"); return NULL; } mib[0] = CTL_HW; mib[1] = HW_DISKNAMES; if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKNAMES"); return NULL; } disknames = sg_malloc(size); if (disknames == NULL) { return NULL; } if (sysctl(mib, MIBSIZE, disknames, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKNAMES"); return NULL; } dk_name = sg_malloc(diskcount * sizeof(char *)); bufpp = disknames; for (i = 0; i < diskcount && (name = strsep(&bufpp, ",")) != NULL; i++) { dk_name[i] = name; } #endif #if defined(NETBSD) || defined(OPENBSD) mib[0] = CTL_HW; mib[1] = HW_DISKSTATS; #ifdef NETBSD mib[2] = sizeof(struct disk_sysctl); #endif if (sysctl(mib, MIBSIZE, NULL, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKSTATS"); return NULL; } #ifdef NETBSD num_disks = size / sizeof(struct disk_sysctl); #else num_disks = size / sizeof(struct diskstats); #endif stats = sg_malloc(size); if (stats == NULL) { return NULL; } if (sysctl(mib, MIBSIZE, stats, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_HW.HW_DISKSTATS"); return NULL; } for (i = 0; i < num_disks; i++) { const char *name; u_int64_t rbytes, wbytes; #ifdef NETBSD #ifdef HAVE_DK_RBYTES rbytes = stats[i].dk_rbytes; wbytes = stats[i].dk_wbytes; #else /* Before 2.0, NetBSD merged reads and writes. */ rbytes = wbytes = stats[i].dk_bytes; #endif #else #ifdef HAVE_DS_RBYTES rbytes = stats[i].ds_rbytes; wbytes = stats[i].ds_wbytes; #else /* Before 3.5, OpenBSD merged reads and writes */ rbytes = wbytes = stats[i].ds_bytes; #endif #endif /* Don't keep stats for disks that have never been used. */ if (rbytes == 0 && wbytes == 0) { continue; } if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) { return NULL; } diskio_stats_ptr = diskio_stats + num_diskio; diskio_stats_ptr->read_bytes = rbytes; diskio_stats_ptr->write_bytes = wbytes; #ifdef NETBSD name = stats[i].dk_name; #else name = dk_name[i]; #endif if (sg_update_string(&diskio_stats_ptr->disk_name, name) < 0) { return NULL; } diskio_stats_ptr->systime = time(NULL); num_diskio++; } free(stats); #ifdef OPENBSD free(dk_name); free(disknames); #endif #endif #if defined(FREEBSD) || defined(DFBSD) if (!stats_init) { stats.dinfo=sg_malloc(sizeof(struct devinfo)); if(stats.dinfo==NULL) return NULL; bzero(stats.dinfo, sizeof(struct devinfo)); stats_init = 1; } #ifdef FREEBSD5 if ((devstat_getdevs(NULL, &stats)) < 0) { /* FIXME devstat functions return a string error in devstat_errbuf */ sg_set_error(SG_ERROR_DEVSTAT_GETDEVS, NULL); return NULL; } /* Not aware of a get all devices, so i said 999. If we ever * find a machine with more than 999 disks, then i'll change * this number :) */ if (devstat_selectdevs(&dev_sel, &n_selected, &n_selections, &sel_gen, stats.dinfo->generation, stats.dinfo->devices, stats.dinfo->numdevs, NULL, 0, NULL, 0, DS_SELECT_ONLY, 999, 1) < 0) { sg_set_error(SG_ERROR_DEVSTAT_SELECTDEVS, NULL); return NULL; } #else if ((getdevs(&stats)) < 0) { sg_set_error(SG_ERROR_DEVSTAT_GETDEVS, NULL); return NULL; } /* Not aware of a get all devices, so i said 999. If we ever * find a machine with more than 999 disks, then i'll change * this number :) */ if (selectdevs(&dev_sel, &n_selected, &n_selections, &sel_gen, stats.dinfo->generation, stats.dinfo->devices, stats.dinfo->numdevs, NULL, 0, NULL, 0, DS_SELECT_ONLY, 999, 1) < 0) { sg_set_error(SG_ERROR_DEVSTAT_SELECTDEVS, NULL); return NULL; } #endif for(counter=0;counter<stats.dinfo->numdevs;counter++){ dev_ptr=&stats.dinfo->devices[dev_sel[counter].position]; /* Throw away devices that have done nothing, ever.. Eg "odd" * devices.. like mem, proc.. and also doesn't report floppy * drives etc unless they are doing stuff :) */ #ifdef FREEBSD5 if((dev_ptr->bytes[DEVSTAT_READ]==0) && (dev_ptr->bytes[DEVSTAT_WRITE]==0)) continue; #else if((dev_ptr->bytes_read==0) && (dev_ptr->bytes_written==0)) continue; #endif if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) { return NULL; } diskio_stats_ptr=diskio_stats+num_diskio; #ifdef FREEBSD5 diskio_stats_ptr->read_bytes=dev_ptr->bytes[DEVSTAT_READ]; diskio_stats_ptr->write_bytes=dev_ptr->bytes[DEVSTAT_WRITE]; #else diskio_stats_ptr->read_bytes=dev_ptr->bytes_read; diskio_stats_ptr->write_bytes=dev_ptr->bytes_written; #endif if(diskio_stats_ptr->disk_name!=NULL) free(diskio_stats_ptr->disk_name); if (asprintf((&diskio_stats_ptr->disk_name), "%s%d", dev_ptr->device_name, dev_ptr->unit_number) == -1) { sg_set_error_with_errno(SG_ERROR_ASPRINTF, NULL); return NULL; } diskio_stats_ptr->systime=time(NULL); num_diskio++; } free(dev_sel); #endif #ifdef SOLARIS if ((kc = kstat_open()) == NULL) { sg_set_error(SG_ERROR_KSTAT_OPEN, NULL); return NULL; } for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { if (!strcmp(ksp->ks_class, "disk")) { if(ksp->ks_type != KSTAT_TYPE_IO) continue; /* We dont want metadevices appearins as num_diskio */ if(strcmp(ksp->ks_module, "md")==0) continue; if((kstat_read(kc, ksp, &kios))==-1){ } if (VECTOR_RESIZE(diskio_stats, num_diskio + 1) < 0) { kstat_close(kc); return NULL; } diskio_stats_ptr=diskio_stats+num_diskio; diskio_stats_ptr->read_bytes=kios.nread; diskio_stats_ptr->write_bytes=kios.nwritten; if (sg_update_string(&diskio_stats_ptr->disk_name, sg_get_svr_from_bsd(ksp->ks_name)) < 0) { kstat_close(kc); return NULL; } diskio_stats_ptr->systime=time(NULL); num_diskio++; } } kstat_close(kc); #endif #ifdef LINUX num_diskio = 0; n = 0; /* Read /proc/partitions to find what devices exist. Recent 2.4 kernels have statistics in here too, so we can use those directly. 2.6 kernels have /proc/diskstats instead with almost (but not quite) the same format. */ f = fopen("/proc/diskstats", "r"); format = " %d %d %99s %*d %*d %lld %*d %*d %*d %lld"; if (f == NULL) { f = fopen("/proc/partitions", "r"); format = " %d %d %*d %99s %*d %*d %lld %*d %*d %*d %lld"; } if (f == NULL) goto out; now = time(NULL); if (!re_compiled) { if (regcomp(&part_re, "^(.*/)?[^/]*[0-9]$", REG_EXTENDED | REG_NOSUB) != 0) { sg_set_error(SG_ERROR_PARSE, NULL); goto out; } if (regcomp(¬_part_re, "^(.*/)?[^/0-9]+[0-9]+d[0-9]+$", REG_EXTENDED | REG_NOSUB) != 0) { sg_set_error(SG_ERROR_PARSE, NULL); goto out; } re_compiled = 1; } while ((line_ptr = sg_f_read_line(f, "")) != NULL) { char name[100]; long long rsect, wsect; int nr = sscanf(line_ptr, format, &major, &minor, name, &rsect, &wsect); if (nr < 3) continue; /* Skip device names ending in numbers, since they're partitions, unless they match the c0d0 pattern that some RAID devices use. */ /* FIXME: For 2.6+, we should probably be using sysfs to detect this... */ if ((regexec(&part_re, name, 0, NULL, 0) == 0) && (regexec(¬_part_re, name, 0, NULL, 0) != 0)) { continue; } if (nr < 5) { has_pp_stats = 0; rsect = 0; wsect = 0; } if (VECTOR_RESIZE(diskio_stats, n + 1) < 0) { goto out; } if (VECTOR_RESIZE(parts, n + 1) < 0) { goto out; } if (sg_update_string(&diskio_stats[n].disk_name, name) < 0) { goto out; } diskio_stats[n].read_bytes = rsect * 512; diskio_stats[n].write_bytes = wsect * 512; diskio_stats[n].systime = now; parts[n].major = major; parts[n].minor = minor; n++; } fclose(f); f = NULL; if (!has_pp_stats) { /* This is an older kernel where /proc/partitions doesn't contain stats. Read what we can from /proc/stat instead, and fill in the appropriate bits of the list allocated above. */ f = fopen("/proc/stat", "r"); if (f == NULL) goto out; now = time(NULL); line_ptr = sg_f_read_line(f, "disk_io:"); if (line_ptr == NULL) goto out; while((line_ptr=strchr(line_ptr, ' '))!=NULL){ long long rsect, wsect; if (*++line_ptr == '\0') break; if((sscanf(line_ptr, "(%d,%d):(%*d, %*d, %lld, %*d, %lld)", &major, &minor, &rsect, &wsect)) != 4) { continue; } /* Find the corresponding device from earlier. Just to add to the fun, "minor" is actually the disk number, not the device minor, so we need to figure out the real minor number based on the major! This list is not exhaustive; if you're running an older kernel you probably don't have fancy I2O hardware anyway... */ switch (major) { case 3: case 21: case 22: case 33: case 34: case 36: case 56: case 57: case 88: case 89: case 90: case 91: minor *= 64; break; case 9: case 43: break; default: minor *= 16; break; } for (i = 0; i < n; i++) { if (major == parts[i].major && minor == parts[i].minor) break; } if (i == n) continue; /* We read the number of blocks. Blocks are stored in 512 bytes */ diskio_stats[i].read_bytes = rsect * 512; diskio_stats[i].write_bytes = wsect * 512; diskio_stats[i].systime = now; } } num_diskio = n; out: if (f != NULL) fclose(f); #endif #ifdef CYGWIN sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin"); return NULL; #endif #ifdef WIN32 sg_set_error(SG_ERROR_NONE, NULL); while((name = get_diskio(num_diskio, &rbytes, &wbytes)) != NULL) { if (VECTOR_RESIZE(diskio_stats, num_diskio+1)) { return NULL; } diskio_stats_ptr = diskio_stats + num_diskio; if (sg_update_string(&diskio_stats_ptr->disk_name, name) < 0) { return NULL; } sg_update_string(&name, NULL); diskio_stats_ptr->read_bytes = rbytes; diskio_stats_ptr->write_bytes = wbytes; diskio_stats_ptr->systime = 0; num_diskio++; } #endif *entries=num_diskio; return diskio_stats; } sg_disk_io_stats *sg_get_disk_io_stats_diff(int *entries){ #ifndef WIN32 VECTOR_DECLARE_STATIC(diff, sg_disk_io_stats, 1, diskio_stat_init, diskio_stat_destroy); sg_disk_io_stats *src = NULL, *dest; int i, j, diff_count, new_count; if (diskio_stats == NULL) { /* No previous stats, so we can't calculate a difference. */ return sg_get_disk_io_stats(entries); } /* Resize the results array to match the previous stats. */ diff_count = VECTOR_SIZE(diskio_stats); if (VECTOR_RESIZE(diff, diff_count) < 0) { return NULL; } /* Copy the previous stats into the result. */ for (i = 0; i < diff_count; i++) { src = &diskio_stats[i]; dest = &diff[i]; if (sg_update_string(&dest->disk_name, src->disk_name) < 0) { return NULL; } dest->read_bytes = src->read_bytes; dest->write_bytes = src->write_bytes; dest->systime = src->systime; } /* Get a new set of stats. */ if (sg_get_disk_io_stats(&new_count) == NULL) { return NULL; } /* For each previous stat... */ for (i = 0; i < diff_count; i++) { dest = &diff[i]; /* ... find the corresponding new stat ... */ for (j = 0; j < new_count; j++) { /* Try the new stat in the same position first, since that's most likely to be it. */ src = &diskio_stats[(i + j) % new_count]; if (strcmp(src->disk_name, dest->disk_name) == 0) { break; } } if (j == new_count) { /* No match found. */ continue; } /* ... and subtract the previous stat from it to get the difference. */ dest->read_bytes = src->read_bytes - dest->read_bytes; dest->write_bytes = src->write_bytes - dest->write_bytes; dest->systime = src->systime - dest->systime; } *entries = diff_count; return diff; #else /* WIN32 */ return sg_get_disk_io_stats(entries); #endif } int sg_disk_io_compare_name(const void *va, const void *vb) { const sg_disk_io_stats *a = (const sg_disk_io_stats *)va; const sg_disk_io_stats *b = (const sg_disk_io_stats *)vb; return strcmp(a->disk_name, b->disk_name); }
sg_user_stats *sg_get_user_stats(){ int num_users = 0, pos = 0, new_pos; VECTOR_DECLARE_STATIC(name_list, char, 128, NULL, NULL); static sg_user_stats user_stats; #if defined(SOLARIS) || defined(LINUX) || defined(CYGWIN) struct utmp *entry; #endif #ifdef ALLBSD struct utmp entry; FILE *f; #endif #if defined(SOLARIS) || defined(LINUX) || defined(CYGWIN) setutent(); while((entry=getutent()) != NULL) { if (entry->ut_type != USER_PROCESS) continue; new_pos = pos + strlen(entry->ut_user) + 1; if (VECTOR_RESIZE(name_list, new_pos) < 0) { return NULL; } strcpy(name_list + pos, entry->ut_user); name_list[new_pos - 1] = ' '; pos = new_pos; num_users++; } endutent(); #endif #ifdef ALLBSD if ((f=fopen(_PATH_UTMP, "r")) == NULL){ sg_set_error(SG_ERROR_OPEN, _PATH_UTMP); return NULL; } while((fread(&entry, sizeof(entry),1,f)) != 0){ if (entry.ut_name[0] == '\0') continue; new_pos = pos + strlen(entry.ut_name) + 1; if (VECTOR_RESIZE(name_list, new_pos) < 0) { return NULL; } strcpy(name_list + pos, entry.ut_name); name_list[new_pos - 1] = ' '; pos = new_pos; num_users++; } fclose(f); #endif /* Remove the extra space at the end, and append a \0. */ if (num_users != 0) { pos--; } if (VECTOR_RESIZE(name_list, pos + 1) < 0) { return NULL; } name_list[pos] = '\0'; user_stats.num_entries = num_users; user_stats.name_list = name_list; return &user_stats; }
sg_process_stats *sg_get_process_stats(int *entries){ VECTOR_DECLARE_STATIC(proc_state, sg_process_stats, 64, proc_state_init, proc_state_destroy); int proc_state_size = 0; sg_process_stats *proc_state_ptr; #ifdef ALLBSD int mib[4]; size_t size; struct kinfo_proc *kp_stats; int procs, i; char *proctitle; #if (defined(FREEBSD) && !defined(FREEBSD5)) || defined(DFBSD) kvm_t *kvmd; char **args, **argsp; int argslen = 0; #else long buflen; char *p, *proctitletmp; #endif #ifdef NETBSD2 int lwps; struct kinfo_lwp *kl_stats; #endif #endif #if defined(SOLARIS) || defined(LINUX) DIR *proc_dir; struct dirent *dir_entry; char filename[MAX_FILE_LENGTH]; FILE *f; #ifdef SOLARIS psinfo_t process_info; #endif #ifdef LINUX char s; /* If someone has a executable of 4k filename length, they deserve to get it truncated :) */ char ps_name[4096]; char *ptr; VECTOR_DECLARE_STATIC(psargs, char, 128, NULL, NULL); unsigned long stime, utime, starttime; int x; int fn; int len; int rc; time_t uptime; #endif #ifdef LINUX if ((f=fopen("/proc/uptime", "r")) == NULL) { sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/uptime"); return NULL; } if((fscanf(f,"%lu %*d",&uptime)) != 1){ sg_set_error(SG_ERROR_PARSE, NULL); return NULL; } fclose(f); #endif if((proc_dir=opendir(PROC_LOCATION))==NULL){ sg_set_error_with_errno(SG_ERROR_OPENDIR, PROC_LOCATION); return NULL; } while((dir_entry=readdir(proc_dir))!=NULL){ if(atoi(dir_entry->d_name) == 0) continue; #ifdef SOLARIS snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/psinfo", dir_entry->d_name); #endif #ifdef LINUX snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/stat", dir_entry->d_name); #endif if((f=fopen(filename, "r"))==NULL){ /* Open failed.. Process since vanished, or the path was too long. * Ah well, move onwards to the next one */ continue; } #ifdef SOLARIS fread(&process_info, sizeof(psinfo_t), 1, f); fclose(f); #endif if (VECTOR_RESIZE(proc_state, proc_state_size + 1) < 0) { return NULL; } proc_state_ptr = proc_state+proc_state_size; #ifdef SOLARIS proc_state_ptr->pid = process_info.pr_pid; proc_state_ptr->parent = process_info.pr_ppid; proc_state_ptr->pgid = process_info.pr_pgid; proc_state_ptr->uid = process_info.pr_uid; proc_state_ptr->euid = process_info.pr_euid; proc_state_ptr->gid = process_info.pr_gid; proc_state_ptr->egid = process_info.pr_egid; proc_state_ptr->proc_size = (process_info.pr_size) * 1024; proc_state_ptr->proc_resident = (process_info.pr_rssize) * 1024; proc_state_ptr->time_spent = process_info.pr_time.tv_sec; proc_state_ptr->cpu_percent = (process_info.pr_pctcpu * 100.0) / 0x8000; proc_state_ptr->nice = (int)process_info.pr_lwp.pr_nice - 20; if (sg_update_string(&proc_state_ptr->process_name, process_info.pr_fname) < 0) { return NULL; } if (sg_update_string(&proc_state_ptr->proctitle, process_info.pr_psargs) < 0) { return NULL; } if(process_info.pr_lwp.pr_state==1) proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING; if(process_info.pr_lwp.pr_state==2) proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; if(process_info.pr_lwp.pr_state==3) proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE; if(process_info.pr_lwp.pr_state==4) proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; if(process_info.pr_lwp.pr_state==6) proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; #endif #ifdef LINUX x = fscanf(f, "%d %4096s %c %d %d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu %*d %*d %*d %d %*d %*d %lu %llu %llu %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*d\n", &(proc_state_ptr->pid), ps_name, &s, &(proc_state_ptr->parent), &(proc_state_ptr->pgid), &utime, &stime, &(proc_state_ptr->nice), &starttime, &(proc_state_ptr->proc_size), &(proc_state_ptr->proc_resident)); /* +3 becuase man page says "Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes." */ proc_state_ptr->proc_resident = (proc_state_ptr->proc_resident + 3) * getpagesize(); if(s == 'S') proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING; if(s == 'R') proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; if(s == 'Z') proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE; if(s == 'T') proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; if(s == 'D') proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; /* pa_name[0] should = '(' */ ptr = strchr(&ps_name[1], ')'); if(ptr !=NULL) *ptr='\0'; if (sg_update_string(&proc_state_ptr->process_name, &ps_name[1]) < 0) { return NULL; } /* cpu */ proc_state_ptr->cpu_percent = (100.0 * (utime + stime)) / ((uptime * 100.0) - starttime); fclose(f); /* uid / gid */ snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/status", dir_entry->d_name); if ((f=fopen(filename, "r")) == NULL) { /* Open failed.. Process since vanished, or the path was too long. * Ah well, move onwards to the next one */ continue; } if((ptr=sg_f_read_line(f, "Uid:"))==NULL){ fclose(f); continue; } sscanf(ptr, "Uid:\t%d\t%d\t%*d\t%*d\n", &(proc_state_ptr->uid), &(proc_state_ptr->euid)); if((ptr=sg_f_read_line(f, "Gid:"))==NULL){ fclose(f); continue; } sscanf(ptr, "Gid:\t%d\t%d\t%*d\t%*d\n", &(proc_state_ptr->gid), &(proc_state_ptr->egid)); fclose(f); /* proctitle */ snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/cmdline", dir_entry->d_name); if((fn=open(filename, O_RDONLY)) == -1){ /* Open failed.. Process since vanished, or the path was too long. * Ah well, move onwards to the next one */ continue; } #define READ_BLOCK_SIZE 128 len = 0; do { if (VECTOR_RESIZE(psargs, len + READ_BLOCK_SIZE) < 0) { return NULL; } rc = read(fn, psargs + len, READ_BLOCK_SIZE); if (rc > 0) { len += rc; } } while (rc == READ_BLOCK_SIZE); close(fn); if (rc == -1) { /* Read failed; move on. */ continue; } /* Turn \0s into spaces within the command line. */ ptr = psargs; for(x = 0; x < len; x++) { if (*ptr == '\0') *ptr = ' '; ptr++; } if (len == 0) { /* We want psargs to be NULL. */ if (VECTOR_RESIZE(psargs, 0) < 0) { return NULL; } } else { /* Not empty, so append a \0. */ if (VECTOR_RESIZE(psargs, len + 1) < 0) { return NULL; } psargs[len] = '\0'; } if (sg_update_string(&proc_state_ptr->proctitle, psargs) < 0) { return NULL; } #endif proc_state_size++; } closedir(proc_dir); #endif #ifdef ALLBSD mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_ALL; if(sysctl(mib, 3, NULL, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_PROC.KERN_PROC_ALL"); return NULL; } procs = size / sizeof(struct kinfo_proc); kp_stats = sg_malloc(size); if(kp_stats == NULL) { return NULL; } memset(kp_stats, 0, size); if(sysctl(mib, 3, kp_stats, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_PROC.KERN_PROC_ALL"); free(kp_stats); return NULL; } #if (defined(FREEBSD) && !defined(FREEBSD5)) || defined(DFBSD) kvmd = sg_get_kvm2(); #endif for (i = 0; i < procs; i++) { const char *name; #ifdef FREEBSD5 if (kp_stats[i].ki_stat == 0) { #else if (kp_stats[i].kp_proc.p_stat == 0) { #endif /* FreeBSD 5 deliberately overallocates the array that * the sysctl returns, so we'll get a few junk * processes on the end that we have to ignore. (Search * for "overestimate by 5 procs" in * src/sys/kern/kern_proc.c for more details.) */ continue; } if (VECTOR_RESIZE(proc_state, proc_state_size + 1) < 0) { return NULL; } proc_state_ptr = proc_state+proc_state_size; #ifdef FREEBSD5 name = kp_stats[i].ki_comm; #elif defined(DFBSD) name = kp_stats[i].kp_thread.td_comm; #else name = kp_stats[i].kp_proc.p_comm; #endif if (sg_update_string(&proc_state_ptr->process_name, name) < 0) { return NULL; } #if defined(FREEBSD5) || defined(NETBSD) || defined(OPENBSD) #ifdef FREEBSD5 mib[2] = KERN_PROC_ARGS; mib[3] = kp_stats[i].ki_pid; #else mib[1] = KERN_PROC_ARGS; mib[2] = kp_stats[i].kp_proc.p_pid; mib[3] = KERN_PROC_ARGV; #endif free(proc_state_ptr->proctitle); proc_state_ptr->proctitle = NULL; /* Starting size - we'll double this straight away */ #define PROCTITLE_START_SIZE 64 buflen = PROCTITLE_START_SIZE; size = buflen; proctitle = NULL; do { if(size >= buflen) { buflen *= 2; size = buflen; proctitletmp = sg_realloc(proctitle, buflen); if(proctitletmp == NULL) { free(proctitle); proctitle = NULL; proc_state_ptr->proctitle = NULL; size = 0; break; } proctitle = proctitletmp; bzero(proctitle, buflen); } if(sysctl(mib, 4, proctitle, &size, NULL, 0) < 0) { free(proctitle); proctitle = NULL; proc_state_ptr->proctitle = NULL; size = 0; break; } } while(size >= buflen); if(size > 0) { proc_state_ptr->proctitle = sg_malloc(size+1); if(proc_state_ptr->proctitle == NULL) { return NULL; } p = proctitle; #ifdef OPENBSD /* On OpenBSD, this value has the argv pointers (which * are terminated by a NULL) at the front, so we have * to skip over them to get to the strings. */ while (*(char ***)p != NULL) { p += sizeof(char **); } p += sizeof(char **); #endif proc_state_ptr->proctitle[0] = '\0'; do { sg_strlcat(proc_state_ptr->proctitle, p, size+1); sg_strlcat(proc_state_ptr->proctitle, " ", size+1); p += strlen(p) + 1; } while (p < proctitle + size); free(proctitle); proctitle = NULL; /* remove trailing space */ proc_state_ptr->proctitle[strlen(proc_state_ptr->proctitle)-1] = '\0'; } else { if(proctitle != NULL) { free(proctitle); proctitle = NULL; } proc_state_ptr->proctitle = NULL; } #else free(proc_state_ptr->proctitle); proc_state_ptr->proctitle = NULL; if(kvmd != NULL) { args = kvm_getargv(kvmd, &(kp_stats[i]), 0); if(args != NULL) { argsp = args; while(*argsp != NULL) { argslen += strlen(*argsp) + 1; argsp++; } proctitle = sg_malloc(argslen + 1); proctitle[0] = '\0'; if(proctitle == NULL) { return NULL; } while(*args != NULL) { sg_strlcat(proctitle, *args, argslen + 1); sg_strlcat(proctitle, " ", argslen + 1); args++; } /* remove trailing space */ proctitle[strlen(proctitle)-1] = '\0'; proc_state_ptr->proctitle = proctitle; } else { proc_state_ptr->proctitle = NULL; } } else { proc_state_ptr->proctitle = NULL; } #endif #ifdef FREEBSD5 proc_state_ptr->pid = kp_stats[i].ki_pid; proc_state_ptr->parent = kp_stats[i].ki_ppid; proc_state_ptr->pgid = kp_stats[i].ki_pgid; #else proc_state_ptr->pid = kp_stats[i].kp_proc.p_pid; proc_state_ptr->parent = kp_stats[i].kp_eproc.e_ppid; proc_state_ptr->pgid = kp_stats[i].kp_eproc.e_pgid; #endif #ifdef FREEBSD5 proc_state_ptr->uid = kp_stats[i].ki_ruid; proc_state_ptr->euid = kp_stats[i].ki_uid; proc_state_ptr->gid = kp_stats[i].ki_rgid; proc_state_ptr->egid = kp_stats[i].ki_svgid; #elif defined(DFBSD) proc_state_ptr->uid = kp_stats[i].kp_eproc.e_ucred.cr_ruid; proc_state_ptr->euid = kp_stats[i].kp_eproc.e_ucred.cr_svuid; proc_state_ptr->gid = kp_stats[i].kp_eproc.e_ucred.cr_rgid; proc_state_ptr->egid = kp_stats[i].kp_eproc.e_ucred.cr_svgid; #else proc_state_ptr->uid = kp_stats[i].kp_eproc.e_pcred.p_ruid; proc_state_ptr->euid = kp_stats[i].kp_eproc.e_pcred.p_svuid; proc_state_ptr->gid = kp_stats[i].kp_eproc.e_pcred.p_rgid; proc_state_ptr->egid = kp_stats[i].kp_eproc.e_pcred.p_svgid; #endif #ifdef FREEBSD5 proc_state_ptr->proc_size = kp_stats[i].ki_size; /* This is in pages */ proc_state_ptr->proc_resident = kp_stats[i].ki_rssize * getpagesize(); /* This is in microseconds */ proc_state_ptr->time_spent = kp_stats[i].ki_runtime / 1000000; proc_state_ptr->cpu_percent = ((double)kp_stats[i].ki_pctcpu / FSCALE) * 100.0; proc_state_ptr->nice = kp_stats[i].ki_nice; #else proc_state_ptr->proc_size = kp_stats[i].kp_eproc.e_vm.vm_map.size; /* This is in pages */ proc_state_ptr->proc_resident = kp_stats[i].kp_eproc.e_vm.vm_rssize * getpagesize(); #if defined(NETBSD) || defined(OPENBSD) proc_state_ptr->time_spent = kp_stats[i].kp_proc.p_rtime.tv_sec; #elif defined(DFBSD) proc_state_ptr->time_spent = ( kp_stats[i].kp_thread.td_uticks + kp_stats[i].kp_thread.td_sticks + kp_stats[i].kp_thread.td_iticks ) / 1000000; #else /* This is in microseconds */ proc_state_ptr->time_spent = kp_stats[i].kp_proc.p_runtime / 1000000; #endif proc_state_ptr->cpu_percent = ((double)kp_stats[i].kp_proc.p_pctcpu / FSCALE) * 100.0; proc_state_ptr->nice = kp_stats[i].kp_proc.p_nice; #endif #ifdef NETBSD2 { size_t size; int mib[5]; mib[0] = CTL_KERN; mib[1] = KERN_LWP; mib[2] = kp_stats[i].kp_proc.p_pid; mib[3] = sizeof(struct kinfo_lwp); mib[4] = 0; if(sysctl(mib, 5, NULL, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_LWP.pid.structsize.0"); return NULL; } lwps = size / sizeof(struct kinfo_lwp); mib[4] = lwps; kl_stats = sg_malloc(size); if(kl_stats == NULL) { return NULL; } if(sysctl(mib, 5, kl_stats, &size, NULL, 0) < 0) { sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_LWP.pid.structsize.buffersize"); return NULL; } } switch(kp_stats[i].kp_proc.p_stat) { case SIDL: proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; break; case SACTIVE: { int i; for(i = 0; i < lwps; i++) { switch(kl_stats[i].l_stat) { case LSONPROC: case LSRUN: proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; goto end; case LSSLEEP: proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING; goto end; case LSSTOP: case LSSUSPENDED: proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; goto end; } proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN; } end: ; } break; case SSTOP: proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; break; case SZOMB: proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE; break; default: proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN; break; } free(kl_stats); #else #ifdef FREEBSD5 switch (kp_stats[i].ki_stat) { #else switch (kp_stats[i].kp_proc.p_stat) { #endif case SIDL: case SRUN: #ifdef SONPROC case SONPROC: /* NetBSD */ #endif proc_state_ptr->state = SG_PROCESS_STATE_RUNNING; break; case SSLEEP: #ifdef SWAIT case SWAIT: /* FreeBSD 5 */ #endif #ifdef SLOCK case SLOCK: /* FreeBSD 5 */ #endif proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING; break; case SSTOP: proc_state_ptr->state = SG_PROCESS_STATE_STOPPED; break; case SZOMB: #ifdef SDEAD case SDEAD: /* OpenBSD & NetBSD */ #endif proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE; break; default: proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN; break; } #endif proc_state_size++; } free(kp_stats); #endif #ifdef CYGWIN sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin"); return NULL; #endif *entries = proc_state_size; return proc_state; } sg_process_count *sg_get_process_count() { static sg_process_count process_stat; sg_process_stats *ps; int ps_size, x; process_stat.sleeping = 0; process_stat.running = 0; process_stat.zombie = 0; process_stat.stopped = 0; process_stat.total = 0; ps = sg_get_process_stats(&ps_size); if (ps == NULL) { return NULL; } for(x = 0; x < ps_size; x++) { switch (ps->state) { case SG_PROCESS_STATE_RUNNING: process_stat.running++; break; case SG_PROCESS_STATE_SLEEPING: process_stat.sleeping++; break; case SG_PROCESS_STATE_STOPPED: process_stat.stopped++; break; case SG_PROCESS_STATE_ZOMBIE: process_stat.zombie++; break; default: /* currently no mapping for SG_PROCESS_STATE_UNKNOWN in * sg_process_count */ break; } ps++; } process_stat.total = ps_size; return &process_stat; } int sg_process_compare_name(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; return strcmp(a->process_name, b->process_name); } int sg_process_compare_pid(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->pid < b->pid) { return -1; } else if (a->pid == b->pid) { return 0; } else { return 1; } } int sg_process_compare_uid(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->uid < b->uid) { return -1; } else if (a->uid == b->uid) { return 0; } else { return 1; } } int sg_process_compare_gid(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->gid < b->gid) { return -1; } else if (a->gid == b->gid) { return 0; } else { return 1; } } int sg_process_compare_size(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->proc_size < b->proc_size) { return -1; } else if (a->proc_size == b->proc_size) { return 0; } else { return 1; } } int sg_process_compare_res(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->proc_resident < b->proc_resident) { return -1; } else if (a->proc_resident == b->proc_resident) { return 0; } else { return 1; } } int sg_process_compare_cpu(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->cpu_percent < b->cpu_percent) { return -1; } else if (a->cpu_percent == b->cpu_percent) { return 0; } else { return 1; } } int sg_process_compare_time(const void *va, const void *vb) { const sg_process_stats *a = (sg_process_stats *)va; const sg_process_stats *b = (sg_process_stats *)vb; if (a->time_spent < b->time_spent) { return -1; } else if (a->time_spent == b->time_spent) { return 0; } else { return 1; } }