/*
 * slmon
 *
 * Copyright (C) 2000, 2001, 2002 Krzysztof Luks <m00se@iq.pl>
 *
 * This program is distributed under the GPL license. For details see
 * COPYING text.
 *
 * Author: Krzysztof Luks <m00se@iq.pl>
 *
 * $Date: 2004/06/24 19:38:35 $
 * $Revision: 1.3 $
 *
 */

#include "stat.h"

/*
 * Calculate count'th cpu usage.
 */

int cpu_calc(int count)
{
    int value;
    double t = 0, i = 0;

    glibtop_cpu cpu;

    glibtop_get_cpu(&cpu);
    if (count == 0) {
	t = ((unsigned long) cpu.total) ? ((double) cpu.total) : 1.0;
	i = ((unsigned long) cpu.idle) ? ((double) cpu.idle) : 1.0;
    } else {
	t = ((unsigned long) cpu.xcpu_total[count - 1]) ? ((double) cpu.
							   xcpu_total[count
								      -
								      1]) :
	    1.0;
	i = ((unsigned long) cpu.
	     xcpu_idle[count - 1]) ? ((double) cpu.xcpu_idle[count -
							     1]) : 1.0;
    }
    t /= conf.freq;
    i /= conf.freq;

    value =
	(int) ((t - i - l[count].totallast) * 100) /
	((t - i - l[count].totallast) + (i - l[count].idlelast));

    if (value > 100)		/* FIXME: is this really needed? */
	value = 100;

    l[count].totallast = t - i;
    l[count].idlelast = i;

    return value;
}

/*
 * Get system uptime
 */

void get_uptime(int *days, int *hours, int *minutes, int *seconds)
{
    double total;
    glibtop_uptime up;

    glibtop_get_uptime(&up);
    total = up.uptime;

    *seconds = (int) total % 60;
    total /= 60.0;
    *minutes = (int) total % 60;
    total /= 60.0;
    *hours = (int) total % 24;
    total /= 24.0;
    *days = (int) total;
}

/*
 * Count users logged in on the system
 */

int users(void)
{
    int count = 0;
#ifdef HAVE_UTMP
    struct utmp *ut;

    setutent();
    while ((ut = getutent()) != NULL)
	if (ut->ut_type == USER_PROCESS)
	    count++;
    endutent();
#endif				/* !HAVE_UTMP */
    return count;
}

/*
 * Make cption for graph etc. Return pointer to that string
 */

char *cpu_caption(int num)
{
    char *t = calloc(20, 1);

    if (num == 0) {
	strcpy(t, "Total CPU usage");
    } else {
        sprintf(t, "CPU%d usage", num);
    }
    return t;
}

slmon_proc *slmon_get_proclist(int *len)
{
    slmon_proc *result = NULL;
    glibtop_proclist plist;
    glibtop_proc_state pstate;
    glibtop_proc_mem pmem;
    glibtop_proc_args pargs;
    glibtop_proc_time ptime;
    glibtop_uptime upt;
    glibtop_mem mem;
    struct passwd *pwd;
    unsigned *pids;
    int i, j, num = 0, tmp;
    float p_total, p_time;
    char *args1;

    /* we can't get process's controlling tty singe libgtop doesn't support
     * this :( */

    pids = glibtop_get_proclist(&plist, 0, 0);

    if(pids) {
	glibtop_get_uptime(&upt);
	glibtop_get_mem(&mem);
	num = plist.number;
	result = (slmon_proc *) malloc(num * sizeof(slmon_proc));
	for(i = 0; i < num; i++) {
	    result[i].pid = pids[i];

	    glibtop_get_proc_state(&pstate, pids[i]);
	    glibtop_get_proc_mem(&pmem, pids[i]);
	    glibtop_get_proc_time(&ptime, pids[i]);
	    p_time = (float) (upt.uptime * 100 - ptime.start_time) / conf.freq;
	    p_total = (float) (ptime.utime + ptime.stime) / 10.0;

	    result[i].pcpu = p_total * 100 / p_time;
	    result[i].pmem = pmem.rss * 1000 / mem.total;
	    result[i].state = pstate.state;

	    args1 = glibtop_get_proc_args(&pargs, pids[i], 0);
	    if (args1) {
		result[i].args = (char *) malloc(pargs.size + 1);
		memcpy(result[i].args, args1, pargs.size);
		result[i].args[pargs.size] = '\0';
		for (j = 0; j < pargs.size; j++)
		    if (result[i].args[j] == '\0')
			result[i].args[j] = ' ';
		g_free(args1);
	    } else {
		tmp = strlen(pstate.cmd) * sizeof(char);
		result[i].args = (char *) malloc(tmp+1);
                result[i].args = calloc(tmp + 1, 1);
	    }

	    result[i].vsz = (int) pmem.vsize >> 10;
	    result[i].rss = (int) pmem.rss >> 10;

	    pwd = getpwuid(pstate.uid);
	    tmp = strlen(pwd->pw_name) * sizeof(char);
	    result[i].user = (char *) malloc(tmp + 1);
            result[i].user = calloc(tmp + 1, 1);
	}
	g_free(pids);
    }
    memcpy(len, &num, sizeof(int));
    return result;
}

int slmon_cmp_pcpu_asc(const void *one, const void *two)
{
    slmon_proc *tmp1, *tmp2;

    tmp1 = (slmon_proc *) one;
    tmp2 = (slmon_proc *) two;

    return tmp1->pcpu - tmp2->pcpu;
}

int slmon_cmp_pcpu_desc(const void *one, const void *two)
{
    return slmon_cmp_pcpu_asc(two, one);
}

int slmon_cmp_pmem_asc(const void *one, const void *two)
{
    slmon_proc *tmp1, *tmp2;

    tmp1 = (slmon_proc *) one;
    tmp2 = (slmon_proc *) two;

    return tmp1->pmem - tmp2->pmem;
}

int slmon_cmp_pmem_desc(const void *one, const void *two)
{
    return slmon_cmp_pmem_asc(two, one);
}

int slmon_cmp_pid_asc(const void *one, const void *two)
{
    /* this function is pretty useless since glibtop_get_proclist()
       already returns processes sorted by pid */

    slmon_proc *tmp1, *tmp2;

    tmp1 = (slmon_proc *) one;
    tmp2 = (slmon_proc *) two;

    return tmp1->pid - tmp2->pid;
}

int slmon_cmp_pid_desc(const void *one, const void *two)
{
    /* this one isn't useless though ;) */
    return slmon_cmp_pid_asc(two, one);
}

int slmon_cmp_user_asc(const void *one, const void *two)
{
    slmon_proc *tmp1, *tmp2;

    tmp1 = (slmon_proc *) one;
    tmp2 = (slmon_proc *) two;

    return strcmp(tmp1->user , tmp2->user);
}

int slmon_cmp_user_desc(const void *one, const void *two)
{
    return slmon_cmp_user_asc(two, one);
}

void slmon_update_net_throughput(char *name, long in, long out)
{
	struct slmon_net *tmp;
        const size_t len = strlen(name);
	
	tmp = conf.iface;
	
	while(tmp != NULL) {
		if(!strncmp(name, tmp->name, len)) {
			tmp->last_in = in;
			tmp->last_out = out;
			return;
		}
		tmp = tmp->next;
	}
}

struct slmon_net *slmon_net_new(void)
{
    struct slmon_net *tmp;

    tmp = (struct slmon_net *) malloc(sizeof(struct slmon_net));
    tmp->name = NULL;
    tmp->next = tmp->prev = NULL;
    
    return tmp;
}

struct slmon_net *slmon_net_append(struct slmon_net *l, char *name)
{
    struct slmon_net *j, *tmp;
    int len;

    tmp = slmon_net_new();
    len = strlen(name);
    tmp->name = calloc(len + 1, 1);
    memcpy(tmp->name, name, len);
    tmp->last_in = tmp->last_out = 0;

    if(l != NULL) {
	j = (struct slmon_net *) slmon_net_find(l, name);
	if(j != NULL) {
	    slmon_net_free(tmp);
	    return l;
	}
	j = (struct slmon_net *) slmon_net_last(l);
	j->next = tmp;
	tmp->prev = j;
	conf.iface_count++;
	return l;
    } else
       return tmp;
}

struct slmon_net *slmon_net_remove(struct slmon_net * l, char *name)
{
    struct slmon_net *j, *tmp;

    j = l;

    if(!strcmp(j->name, name)) {
	l = j->next;
	l->prev = NULL;
	free(j);
	conf.iface_count--;
	return l;
    }

    while(j->next != NULL) {
	j = j->next;
	if(!strcmp(j->name, name)) {
	    j->prev->next = j->next;
	    j->next->prev = j->prev;
	    free(j);
	    break;
	}
    }

}

void slmon_net_free(struct slmon_net * l)
{
    struct slmon_net *j;

    j = l->next;
    free(l);

    while(j != NULL) {
	j = l->next;
	free(l);
    }
}

struct slmon_net *slmon_net_last(struct slmon_net *l)
{
    struct slmon_net *tmp = l;

    if(tmp != NULL)
	while(tmp->next != NULL)
	    tmp = tmp->next;

    return tmp;
}

struct slmon_net *slmon_net_find(struct slmon_net *l, char *name)
{
    struct slmon_net *j;

    j = l;

    while(j != NULL) {
	if(!strcmp(name, j->name))
	    break;
	j = j->next;
    }

    return j;
}



syntax highlighted by Code2HTML, v. 0.9.1