예제 #1
0
int get_stats(void)
{
  st.cpu = sg_get_cpu_percents();
  if (!st.cpu) { LOG(LOG_INFO, "could not sg_get_cpu_stats"); }
  st.mem = sg_get_mem_stats();
  if (!st.mem) { LOG(LOG_INFO, "could not sg_get_mem_stats"); }
  st.swap = sg_get_swap_stats();
  if (!st.swap) { LOG(LOG_INFO, "could not get_swap_stats"); }
  st.load = sg_get_load_stats();
  if (!st.load) { LOG(LOG_INFO, "could not get_load_stats"); }
  st.process = sg_get_process_stats(&st.process_entries);
  if (!st.process) { LOG(LOG_INFO, "could not get_process_stats"); }
  st.paging = sg_get_page_stats_diff();
  if (!st.paging) { LOG(LOG_INFO, "could not get_page_stats_diff"); }
  st.network = sg_get_network_io_stats_diff(&(st.network_entries));
  if (!st.network) { LOG(LOG_INFO, "could not get_network_stats_diff"); }
  st.diskio = sg_get_disk_io_stats_diff(&(st.diskio_entries));
  if (!st.diskio) { LOG(LOG_INFO, "could not get_diskio_stats_diff"); }
  st.disk = sg_get_fs_stats(&(st.disk_entries));
  if (!st.disk) { LOG(LOG_INFO, "could not get_disk_stats"); }
  st.hostinfo = sg_get_host_info();
  if (!st.hostinfo) { LOG(LOG_INFO, "could not get_host_info"); }
  st.user = sg_get_user_stats();
  if (!st.user) { LOG(LOG_INFO, "could not get get_user_stats"); }

  return 1;
}
예제 #2
0
파일: process.c 프로젝트: stiks/iteliecd
int *iteliec_get_process_list (SoapCtx *request) {
    sg_process_stats *ps;
    int ps_size;
    int x;
    char *state = NULL;

    /* get process list */
    ps = sg_get_process_stats (&ps_size);    

    if (ps == NULL) {
        iteliec_log (ITELIEC_ERR, "Failed to get process snapshot");
        
        return;
    }

    soap_env_push_item (request->env, "urn:ProcessListSoapArray", "processlist");
    for (x = 0; x < ps_size; x++) {
        switch (ps->state) {
        case SG_PROCESS_STATE_RUNNING:
            state = "RUNNING";
            break;
        case SG_PROCESS_STATE_SLEEPING:
            state = "SLEEPING";
            break;
        case SG_PROCESS_STATE_STOPPED:
            state = "STOPPED";
            break;
        case SG_PROCESS_STATE_ZOMBIE:
            state = "ZOMBIE";
            break;
        case SG_PROCESS_STATE_UNKNOWN:
        default:
            state = "UNKNOWN";
            break;
        }

        soap_env_push_item (request->env, "urn:ProcessListSoap", "processlist");

        soap_env_add_itemf (request->env, "xsd:integer", "pid",     "%d", (int)ps->pid);
        soap_env_add_itemf (request->env, "xsd:integer", "parent",  "%d", (int)ps->parent);
        soap_env_add_itemf (request->env, "xsd:integer", "pgid",    "%d", (int)ps->pgid);
        soap_env_add_itemf (request->env, "xsd:integer", "uid",     "%d", (int)ps->uid);
        soap_env_add_itemf (request->env, "xsd:integer", "euid",    "%d", (int)ps->euid);
        soap_env_add_itemf (request->env, "xsd:integer", "gid",     "%d", (int)ps->gid);
        soap_env_add_itemf (request->env, "xsd:integer", "egid",    "%d", (int)ps->egid);
        soap_env_add_itemf (request->env, "xsd:integer", "nice",    "%d", (int)ps->nice);
        
        soap_env_add_itemf (request->env, "xsd:integer", "proc_size",    "%d", (int)ps->proc_size);
        soap_env_add_itemf (request->env, "xsd:integer", "proc_resident","%d", (int)ps->proc_resident);
        soap_env_add_itemf (request->env, "xsd:float",   "cpu_percent",  "%F", ps->cpu_percent);
        
        soap_env_add_item  (request->env, "xsd:string", "state", state);
        soap_env_add_item  (request->env, "xsd:string", "process_name", ps->process_name);
        soap_env_add_item  (request->env, "xsd:string", "proctitle", ps->proctitle);

        soap_env_pop_item (request->env);

        ps++;
    }
    soap_env_pop_item (request->env);

    return ITELIEC_OK;
}
예제 #3
0
/*
 * Process statistics, see <tt>sg_get_process_stats(3)</tt> manpage.
 *
 * The +sg_process_compare_+ family of related functions is intentionally
 * left out in this binding - it can be done with Enumerable#sort_by in Ruby.
 * The following example corresponds to the <tt>qsort()</tt> example in the
 * <tt>sg_get_process_stats(3)</tt> manpage:
 *
 *   ps.sort_by {|p| p[:pid] }
 */
static VALUE
statgrab_process_stats(VALUE self)
{
	int entries, i;
	sg_process_stats *stats;
	VALUE arr, info, time_now;

	if ((stats = sg_get_process_stats(&entries)) == NULL)
		statgrab_handle_error();

	arr = rb_ary_new();
	for (i = 0; i < entries; i++) {
		info = rb_hash_new();
		rb_hash_aset(info, ID2SYM(rb_intern("process_name")),
				rb_str_new2(stats[i].process_name));

		if (stats[i].proctitle != NULL)
			rb_hash_aset(info, ID2SYM(rb_intern("proctitle")),
					rb_str_new2(stats[i].proctitle));

		rb_hash_aset(info, ID2SYM(rb_intern("pid")),
				INT2FIX(stats[i].pid));
		rb_hash_aset(info, ID2SYM(rb_intern("parent")),
				INT2FIX(stats[i].parent));
		rb_hash_aset(info, ID2SYM(rb_intern("pgid")),
				INT2FIX(stats[i].pgid));
		rb_hash_aset(info, ID2SYM(rb_intern("uid")),
				INT2FIX(stats[i].uid));
		rb_hash_aset(info, ID2SYM(rb_intern("euid")),
				INT2FIX(stats[i].euid));
		rb_hash_aset(info, ID2SYM(rb_intern("gid")),
				INT2FIX(stats[i].gid));
		rb_hash_aset(info, ID2SYM(rb_intern("egid")),
				INT2FIX(stats[i].egid));
		rb_hash_aset(info, ID2SYM(rb_intern("proc_size")),
				INT2NUM(stats[i].proc_size/1024));
		rb_hash_aset(info, ID2SYM(rb_intern("proc_resident")),
				INT2NUM(stats[i].proc_resident/1024));
		rb_hash_aset(info, ID2SYM(rb_intern("time_spent")),
				INT2NUM(stats[i].time_spent));
		rb_hash_aset(info, ID2SYM(rb_intern("cpu_percent")),
				INT2NUM(stats[i].cpu_percent));
		rb_hash_aset(info, ID2SYM(rb_intern("nice")),
				INT2NUM(stats[i].nice));

		switch(stats[i].state) {
		case SG_PROCESS_STATE_RUNNING:
			rb_hash_aset(info, ID2SYM(rb_intern("state")),
					ID2SYM(rb_intern("running")));
			break;
		case SG_PROCESS_STATE_SLEEPING:
			rb_hash_aset(info, ID2SYM(rb_intern("state")),
					ID2SYM(rb_intern("sleeping")));
			break;
		case SG_PROCESS_STATE_STOPPED:
			rb_hash_aset(info, ID2SYM(rb_intern("state")),
					ID2SYM(rb_intern("stopped")));
			break;
		case SG_PROCESS_STATE_ZOMBIE:
			rb_hash_aset(info, ID2SYM(rb_intern("state")),
					ID2SYM(rb_intern("zombie")));
			break;
		case SG_PROCESS_STATE_UNKNOWN:
			rb_hash_aset(info, ID2SYM(rb_intern("state")),
					ID2SYM(rb_intern("unknown")));
			break;
		}

		time_now = rb_funcall(rb_cTime, rb_intern("now"), 0);
		rb_hash_aset(info, ID2SYM(rb_intern("started")),
				rb_funcall(time_now, rb_intern("-"), 1,
					INT2NUM(stats[i].time_spent)));

		rb_ary_push(arr, info);
	}

	return arr;
}
예제 #4
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;
	}
}
예제 #5
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;
	}
}