Пример #1
0
static PMIB_IFTABLE win32_get_devices()
{
	PMIB_IFTABLE if_table;
	PMIB_IFTABLE tmp;
	unsigned long dwSize = 0;

	// Allocate memory for pointers
	if_table = sg_malloc(sizeof(MIB_IFTABLE));
	if(if_table == NULL) {
		return NULL;
	}

	// Get necessary size for the buffer
	if(GetIfTable(if_table, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
		tmp = sg_realloc(if_table, dwSize);
		if(tmp == NULL) {
			free(if_table);
			return NULL;
		}
		if_table = tmp;
	}

	// Get the data
	if(GetIfTable(if_table, &dwSize, 0) != NO_ERROR) {
		free(if_table);
		return NULL;
	}
	return if_table;
}
Пример #2
0
void sg_vector_remove(SgVector *v, SgSize i)
{
    if (i >= v->size || !v->size)
        return;
    memcpy(&v->head[i], &v->head[i+1], (v->size - i) * sizeof(void*));
    if (v->_rtail - v->tail-- == VBLSZ) {
        v->head = sg_realloc(v->head, v->size * sizeof(void*));
        v->_rtail = v->head + v->size;
        v->tail = v->_rtail - 1;
    }
    v->size--;
}
Пример #3
0
void sg_vector_push(SgVector *v, void *data)
{
    SgSize s;
    *v->tail = data;
    v->size++;
    if (++v->tail == v->_rtail) {
        s = v->size + VBLSZ;
        v->head = sg_realloc(v->head, s * sizeof(void*));
        v->_rtail = v->head + s;
        v->tail = v->_rtail - VBLSZ;
    }
    *v->tail = NULL;
}
Пример #4
0
struct sg_vector *
sg_vector_resize(struct sg_vector *vector, size_t new_count) {

	size_t round_count;

	assert(vector);
	if( !vector ) {
		SET_ERROR("vector", SG_ERROR_INVALID_ARGUMENT, "sg_vector_resize: invalid argument value for vector");
		return NULL;
	}

	if(SG_ERROR_NONE != sg_prove_vector(vector)) {
		SET_ERROR("vector", SG_ERROR_INVALID_ARGUMENT, "sg_vector_resize: invalid vector");
		return NULL;
	}

	TRACE_LOG_FMT("vector", "resizing vector(%p) using %lu items to fit %lu items", vector, vector->used_count, new_count);

	if( 0U == new_count ){
		sg_vector_free(vector);
		sg_clear_error();
		return NULL;
	}

	sg_vector_destroy_unused(vector, new_count);

	/* Round up the desired size to the next multiple of the block size. */
	round_count = NEXT_POWER2_IN(new_count, vector->block_shift);

	/* Resize the vector if necessary. */
	if (round_count != vector->alloc_count) {
		sg_vector *new_vector;

		new_vector = sg_realloc(vector, VECTOR_SIZE + round_count * vector->info.item_size);
		if (new_vector == NULL && round_count != 0U) {
			/* Out of memory -- free the contents of the vector. */
			sg_vector_free(vector);
			return NULL;
		}

		vector = new_vector;
		vector->alloc_count = round_count;
	}

	sg_vector_init_new(vector, new_count);

	TRACE_LOG_FMT("vector", "resized vector(%p) to fit %lu items", vector, round_count);

	return vector;
}
Пример #5
0
void *sg_vector_pop(SgVector *v)
{
    void *p;
    if (!v->size)
        return NULL;
    if (v->_rtail - v->tail-- == VBLSZ) {
        v->head = sg_realloc(v->head, v->size * sizeof(void*));
        v->_rtail = v->head + v->size;
        v->tail = v->_rtail - 1;
    }
    p = *v->tail;
    *v->tail = NULL;
    v->size--;
    return p;
}
Пример #6
0
void *sg_vector_resize(void *vector, vector_header *h, int count) {
	int new_count, i;

	/* Destroy any now-unused items.
	 *
	 * Note that there's an assumption here that making the vector smaller
	 * will never fail; if it did, then we would have destroyed items here
	 * but not actually got rid of the vector pointing to them before the
	 * error return.) */
	if (count < h->used_count && h->destroy_fn != NULL) {
		for (i = count; i < h->used_count; i++) {
			//h->destroy_fn((void *) (vector + i * h->item_size));
			h->destroy_fn((void *) ((char *) vector + i * h->item_size));
		}
	}

	/* Round up the desired size to the next multiple of the block size. */
	new_count =  ((count - 1 + h->block_size) / h->block_size)
		     * h->block_size;

	/* Resize the vector if necessary. */
	if (new_count != h->alloc_count) {
		char *new_vector;

		new_vector = sg_realloc(vector, new_count * h->item_size);
		if (new_vector == NULL && new_count != 0) {
			/* Out of memory -- free the contents of the vector. */
			sg_vector_resize(vector, h, 0);
			h->error = -1;
			return vector;
		}

		vector = new_vector;
		h->alloc_count = new_count;
	}

	/* Initialise any new items. */
	if (count > h->used_count && h->init_fn != NULL) {
		for (i = h->used_count; i < count; i++) {
			//h->init_fn((void *) (vector + i * h->item_size));
			h->init_fn((void *) ((char *) vector + i * h->item_size));
		}
	}

	h->used_count = count;
	h->error = 0;
	return vector;
}
Пример #7
0
static struct sg_vector *
sg_vector_create_int(size_t block_shift, size_t alloc_count, size_t initial_used,
		     const sg_vector_init_info * const info) {

	size_t round_count = NEXT_POWER2_IN(MAX(alloc_count, initial_used), block_shift);
	struct sg_vector *vector = sg_realloc(NULL, VECTOR_SIZE + round_count * info->item_size);
	if(vector) {
		TRACE_LOG_FMT("vector", "vector for %lu items allocated at %p", round_count, vector);
#ifndef NDEBUG
		vector->start_eye = SG_VECTOR_START_EYE;
		vector->final_eye = SG_VECTOR_FINAL_EYE;
#endif
		vector->info = *info;
		vector->block_shift = block_shift;
		vector->alloc_count = 1LU << block_shift;
		vector->used_count = 0;

		sg_vector_init_new(vector, initial_used);
	}

	return vector;
}
Пример #8
0
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;
	}
}
Пример #9
0
static sg_error
sg_get_host_info_int(sg_host_info *host_info_buf) {

#ifdef WIN32
	unsigned long nameln;
	char *name;
	long long result;
	OSVERSIONINFOEX osinfo;
	SYSTEM_INFO sysinfo;
	char *tmp_name;
	char tmp[10];
#else
	struct utsname os;
# if defined(HPUX)
	struct pst_static pstat_static;
	struct pst_dynamic pstat_dynamic;
	time_t currtime;
	long boottime;
# elif defined(SOLARIS)
	time_t boottime, curtime;
	kstat_ctl_t *kc;
	kstat_t *ksp;
	kstat_named_t *kn;
	char *isainfo = NULL;
	long isabufsz, rc;
# elif defined(LINUX) || defined(CYGWIN)
	FILE *f;
# elif defined(ALLBSD)
	int mib[2];
	struct timeval boottime;
	time_t curtime;
	size_t size;
	int ncpus;
#  if defined(HW_MACHINE_ARCH) || defined(HW_MACHINE)
	char arch_name[16];
#  endif
# elif defined(AIX)
	static perfstat_cpu_total_t cpu_total;
	sg_error rc;
#  if defined(HAVE_GETUTXENT)
	struct utmpx *ut;
#  else
	struct utmp *ut;
#  endif
# endif
#endif

	host_info_buf->ncpus = 0;
	host_info_buf->maxcpus = 0;
	host_info_buf->bitwidth = 0;
	host_info_buf->host_state = sg_unknown_configuration;
	host_info_buf->uptime = 0;
	host_info_buf->systime = 0;

#ifdef WIN32
	/* these settings are static after boot, so why get them
	 * constantly?
	 *
	 * Because we want to know some changes anyway - at least
	 * when the hostname (DNS?) changes
	 */

	/* get system name */
	nameln = MAX_COMPUTERNAME_LENGTH + 1;
	name = sg_malloc(nameln);
	if(name == NULL) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}

	/*
	 * XXX probably GetComputerNameEx() is a better entry point ...
	 */
	if( GetComputerName(name, &nameln) == 0 ) {
		free(name);
		RETURN_WITH_SET_ERROR("os", SG_ERROR_HOST, "GetComputerName");
	}

	if(SG_ERROR_NONE != sg_update_string(&host_info_buf->hostname, name)) {
		free(name);
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}
	free(name);

	/* get OS name, version and build */
	ZeroMemory(&osinfo, sizeof(OSVERSIONINFOEX));
	osinfo.dwOSVersionInfoSize = sizeof(osinfo);
	if(!GetVersionEx(&osinfo)) {
		RETURN_WITH_SET_ERROR("os", SG_ERROR_HOST, "GetVersionEx");
	}
	GetSystemInfo(&sysinfo);

	/* Release - single number */
	if(snprintf(tmp, sizeof(tmp), "%ld", osinfo.dwBuildNumber) == -1) {
		RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SPRINTF, NULL);
	}
	if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_release, tmp)) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}

	/* Version */
	/* usually a single digit . single digit, eg 5.0 */
	if(snprintf(tmp, sizeof(tmp), "%ld.%ld", osinfo.dwMajorVersion,
				osinfo.dwMinorVersion) == -1) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}
	if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_version, tmp)) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}

	/* OS name */
	tmp_name = get_os_name(osinfo, sysinfo);
	if(tmp_name == NULL) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}

	if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_name, tmp_name)) {
		free(tmp_name);
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}
	free(tmp_name);

	/* Platform */
	switch(sysinfo.wProcessorArchitecture) {
		case PROCESSOR_ARCHITECTURE_INTEL:
			if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform,
						"Intel")) {
				RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
			}
			break;
		case PROCESSOR_ARCHITECTURE_IA64:
			if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform,
						"IA64")) {
				RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
			}
			break;
		case PROCESSOR_ARCHITECTURE_AMD64:
			if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform,
						"AMD64")) {
				RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
			}
			break;
		default:
			if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform,
						"Unknown")){
				RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
			}
			break;
	}

	if(read_counter_large(SG_WIN32_UPTIME, &result)) {
		RETURN_WITH_SET_ERROR("os", SG_ERROR_PDHREAD, PDH_UPTIME);
	}

	host_info_buf->uptime = (time_t) result;
#else
	if((uname(&os)) < 0) {
		RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_UNAME, NULL);
	}

	if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_name, os.sysname)) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}

	if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_release, os.release)) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}

	if(SG_ERROR_NONE != sg_update_string(&host_info_buf->os_version, os.version)) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}

	if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform, os.machine)) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}

	if(SG_ERROR_NONE != sg_update_string(&host_info_buf->hostname, os.nodename)) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}

	/* get uptime */
#ifdef HPUX
	if (pstat_getstatic(&pstat_static, sizeof(pstat_static), 1, 0) == -1) {
		RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_PSTAT, "pstat_static");
	}

	if (pstat_getdynamic(&pstat_dynamic, sizeof(pstat_dynamic), 1, 0) == -1) {
		RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_PSTAT, "pstat_dynamic");
	}

	currtime = time(NULL);

	boottime = pstat_static.boot_time;

	host_info_buf->uptime = currtime - boottime;
	host_info_buf->ncpus = pstat_dynamic.psd_proc_cnt;
	host_info_buf->maxcpus = pstat_dynamic.psd_max_proc_cnt;
	host_info_buf->bitwidth = sysconf(_SC_KERNEL_BITS);

	/*
	 * TODO: getting virtualization state
	 *       1) on boostrapping this component, try loading /opt/hpvm/lib/libhpvm.so (or so)
	 *       2) get function addresses for
	 *          a) HPVM_boolean hpvm_api_server_check()
	 *          b) HPVM_boolean hpvm_api_virtmach_check()
	 *
	 * Seems to be hardware virtualization ...
	 * See: http://docstore.mik.ua/manuals/hp-ux/en/T2767-90141/index.html (hpvmpubapi(3))
	 *      http://jreypo.wordpress.com/tag/hpvm/
	 *      http://jreypo.wordpress.com/category/hp-ux/page/3/
	 *      http://h20338.www2.hp.com/enterprise/us/en/os/hpux11i-partitioning-integrity-vm.html
	 */

#elif defined(SOLARIS)
	if ((kc = kstat_open()) == NULL) {
		RETURN_WITH_SET_ERROR("os", SG_ERROR_KSTAT_OPEN, NULL);
	}

	if((ksp=kstat_lookup(kc, "unix", -1, "system_misc"))==NULL){
		kstat_close(kc);
		RETURN_WITH_SET_ERROR("os", SG_ERROR_KSTAT_LOOKUP, "unix,-1,system_misc");
	}
	if (kstat_read(kc, ksp, 0) == -1) {
		kstat_close(kc);
		RETURN_WITH_SET_ERROR("os", SG_ERROR_KSTAT_READ, NULL);
	}
	if((kn=kstat_data_lookup(ksp, "boot_time")) == NULL){
		kstat_close(kc);
		RETURN_WITH_SET_ERROR("os", SG_ERROR_KSTAT_DATA_LOOKUP, "boot_time");
	}
	/* XXX verify on Solaris 10 if it's still ui32 */
	boottime = (kn->value.ui32);

	kstat_close(kc);

	time(&curtime);
	host_info_buf->uptime = curtime - boottime;

	host_info_buf->ncpus = sysconf(_SC_NPROCESSORS_ONLN);
	host_info_buf->maxcpus = sysconf(_SC_NPROCESSORS_CONF);
	isainfo = sg_malloc( isabufsz = (32 * sizeof(*isainfo)) );
	if( NULL == isainfo ) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}
# define MKSTR(x) #x
# if defined(SI_ARCHITECTURE_K)
#  define SYSINFO_CMD SI_ARCHITECTURE_K
# elif defined(SI_ISALIST)
#  define SYSINFO_CMD SI_ISALIST
# else
#  define SYSINFO_CMD SI_ARCHITECTURE
# endif
sysinfo_again:
	if( -1 == ( rc = sysinfo( SYSINFO_CMD, isainfo, isabufsz ) ) ) {
		free(isainfo);
		RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSINFO, MKSTR(SYSINFO_CMD) );
	}
	else if( rc > isabufsz ) {
		char *tmp = sg_realloc(isainfo, rc);
		if( NULL == tmp ) {
			free(isainfo);
			RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
		}
		isabufsz = rc;
		isainfo = tmp;
		goto sysinfo_again;
	}

	host_info_buf->bitwidth = get_bitwidth_by_arch_name(isainfo);
	free(isainfo);
	host_info_buf->host_state = sg_unknown_configuration;

#elif defined(LINUX) || defined(CYGWIN)
	if ((f=fopen("/proc/uptime", "r")) == NULL) {
		RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_OPEN, "/proc/uptime");
	}

#define TIME_T_SCANF_FMT (sizeof(int[(((time_t)-1)/2)%4+1]) == sizeof(int[1]) ? "%ld %*d" : "%lu %*d" )
	if((fscanf(f,TIME_T_SCANF_FMT,&host_info_buf->uptime)) != 1){
		fclose(f);
		RETURN_WITH_SET_ERROR("os", SG_ERROR_PARSE, NULL);
	}
	fclose(f);

# if defined(LINUX)
	host_info_buf->ncpus = sysconf(_SC_NPROCESSORS_ONLN);
	host_info_buf->maxcpus = sysconf(_SC_NPROCESSORS_CONF);
	if( access( "/proc/sys/kernel/vsyscall64", F_OK ) == 0 ||
	    access( "/proc/sys/abi/vsyscall32", F_OK ) == 0 ) {
		host_info_buf->bitwidth = 64;
	}
	else {
		host_info_buf->bitwidth = sysconf(_SC_LONG_BIT); // well, maybe 64-bit disabled 128-bit system o.O
	}
	host_info_buf->host_state = sg_unknown_configuration;
# endif

#elif defined(ALLBSD)
	mib[0] = CTL_KERN;
	mib[1] = KERN_BOOTTIME;
	size = sizeof(boottime);
	if (sysctl(mib, 2, &boottime, &size, NULL, 0) < 0) {
		RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "CTL_KERN.KERN_BOOTTIME");
	}
	time(&curtime);
	host_info_buf->uptime= curtime - boottime.tv_sec;

# if defined(HW_NCPU)
	mib[0] = CTL_HW;
	mib[1] = HW_NCPU;
	size = sizeof(int);
	if( sysctl( mib, 2, &ncpus, &size, NULL, 0 ) < 0 ) {
		RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "CTL_HW.HW_NCPU" );
	}
# endif
# if defined(HW_MACHINE_ARCH)
	mib[0] = CTL_HW;
	mib[1] = HW_MACHINE_ARCH;
	size = sizeof(arch_name);
	if( sysctl( mib, 2, arch_name, &size, NULL, 0 ) == 0 ) {
		host_info_buf->bitwidth = get_bitwidth_by_arch_name(arch_name);
	}
	else {
# endif
# if defined(HW_MACHINE)
	mib[0] = CTL_HW;
	mib[1] = HW_MACHINE;
	size = sizeof(arch_name);
	if( sysctl( mib, 2, arch_name, &size, NULL, 0 ) == 0 ) {
		host_info_buf->bitwidth = get_bitwidth_by_arch_name(arch_name);
	}
	else {
		SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "CTL_HW.HW_MACHINE" );
	}
# elif defined(HW_MACHINE_ARCH)
		SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "CTL_HW.HW_MACHINE_ARCH" );
# endif
# if defined(HW_MACHINE_ARCH)
	}
# endif
	host_info_buf->host_state = sg_unknown_configuration; /* details must be analysed "manually", no syscall */
	host_info_buf->maxcpus = (unsigned)ncpus;
# if defined(HW_NCPUONLINE)
	/* use knowledge about number of cpu's online, when available instead of assuming all of them */
	mib[0] = CTL_HW;
	mib[1] = HW_NCPUONLINE;
	size = sizeof(int);
	if( sysctl( mib, 2, &ncpus, &size, NULL, 0 ) < 0 ) {
		RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "CTL_HW.HW_NCPUONLINE" );
	}
# endif
	host_info_buf->ncpus = (unsigned)ncpus;

#elif defined(AIX)
	if(perfstat_cpu_total(NULL, &cpu_total, sizeof(cpu_total), 1) != 1) {
		RETURN_WITH_SET_ERROR_WITH_ERRNO("os", SG_ERROR_SYSCTL, "perfstat_cpu_total");
	}

	if(SG_ERROR_NONE != sg_update_string(&host_info_buf->platform, cpu_total.description)) {
		RETURN_FROM_PREVIOUS_ERROR( "os", sg_get_error() );
	}

	host_info_buf->ncpus = cpu_total.ncpus;
	host_info_buf->maxcpus = cpu_total.ncpus_cfg;
	host_info_buf->bitwidth = sysconf(_SC_AIX_KERNEL_BITMODE);
	if( sysconf(_SC_LPAR_ENABLED) > 0 ) {
		host_info_buf->host_state = sg_hardware_virtualized;
	}
	else {
		host_info_buf->host_state = sg_physical_host;
	}

#ifdef ENABLE_THREADS
	if( SG_ERROR_NONE != ( rc = sg_lock_mutex("utmp") ) ) {
		RETURN_FROM_PREVIOUS_ERROR( "os", rc );
	}
#endif
# if defined(HAVE_GETUTXENT)
#  define UTENTFN getutxent
#  define UTENTTM ut->ut_tv.tv_sec
	setutxent();
# else
#  define UTENTFN getutent
#  define UTENTTM ut->ut_time
	setutent();
# endif
	while( NULL != ( ut = UTENTFN() ) ) {
		if( ut->ut_type == BOOT_TIME ) {
			host_info_buf->uptime = time(NULL) - UTENTTM;
			break;
		}
	}
# if defined(HAVE_GETUTXENT)
	endutxent();
# else
	endutent();
# endif
#ifdef ENABLE_THREADS
	if( SG_ERROR_NONE != ( rc = sg_unlock_mutex("utmp") ) ) {
		RETURN_FROM_PREVIOUS_ERROR( "os", rc );
	}
#endif
#else
	RETURN_WITH_SET_ERROR("os", SG_ERROR_UNSUPPORTED, OS_TYPE);
#endif
#endif /* WIN32 */

	host_info_buf->systime = time(NULL);

	return SG_ERROR_NONE;
}
Пример #10
0
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;
	}
}