/*
 *  main.c
 *  
 *
 *  Created by Charles Mercadal on Thu Oct 16 2003.
 *
 */

#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

#include <sys/select.h>


#include "common.h"
#include "psinfo.h"
#include "output.h"


static void printstats(void);
static void runtillinput(void);
static void usage(void);
static void windowresize(int);
static void dropprivileges(void);


static bool sflag;
static int sleeptime;
struct psinfo procs;

int main(int argc, char *argv[])
{
    bool gflag;
    extern char *optarg;
    extern int optind;
    int ch;

    
    sleeptime = 2;
    gflag = sflag = false;
    
    while ((ch = getopt(argc, argv, "w:gs")) != -1) 
        switch (ch) {
            case 'w':
                sleeptime = atoi(optarg);
                break;
            case 'g':
            	/*
            	 * Just in case we are installed setuid or setgid, 
            	 * we might as well revoke those privileges now.
            	 */
            	dropprivileges();
                gflag = true;
                break;
            case 's':
                sflag = true;
                break;
            case '?':
            default:
                usage();
        }
    
    argc -= optind;
    argv += optind;
    
    if (!*argv)	/* no pids specified */
        usage();
    
    setinfo(&procs, atoi(*argv), gflag);	/* get process name, etc. */
    
    if (!procs.valid) {
        (void)fprintf(stderr, "%s:  no such process id (%s)\n", *(argv - optind), *argv);
        exit(1);
    }
    
    (void)signal(SIGWINCH, windowresize);	/* singwinch -> resize */
    
    initscreen();			/* curses setup */
    paintscreen(&procs);	/* draw screen */
    
    runtillinput();	/* event loop */
    
    resetdisplay();
    
    if (!procs.valid)	/* did runtillinput reutrn because process is no longer valid? */
        (void)fprintf(stderr, "%s:  process ended (%s)\n", *(argv - optind), *argv);
    
    removeinfo(&procs);
    
    if (!sflag)
        printstats();
    
    return 0;
}


void dropprivileges(void)
{

	seteuid(getuid());
	setegid(getgid());
}


void usage(void)
{

    (void)fprintf(stderr, "usage:  pscpug [-gs] [-w time] pid\n");
    exit(1);
}


void runtillinput(void)
{
	int ready;
	fd_set readfs;
    struct termios attributes;
	struct timeval timeout;

    /* immediate mode on input */
	tcgetattr(STDIN_FILENO, &attributes);
    attributes.c_lflag &= (~ICANON);
    attributes.c_cc[VMIN] = 1;
    tcsetattr(STDIN_FILENO, TCSANOW, &attributes);
    
    while (procs.valid) {
        /* select setup */
		FD_ZERO(&readfs);
		FD_SET(STDIN_FILENO, &readfs);
		timeout.tv_sec = sleeptime;
		timeout.tv_usec = 0;
		
    	updateinfo(&procs);
    	printinfo(&procs);
    	
    	ready = select(STDIN_FILENO + 1, &readfs, NULL, NULL, &timeout);
    	
    	if (ready > 0) {	/* not a timeout, read a character... */
    		getchar();		/* retrieve character, as not to let it filter through... */
    		break;
    	}
    }
}


void windowresize(int sig)
{

    paintscreen(&procs);
}


void printstats(void)
{

    (void)printf("Statistics:\n");
    (void)printf("Average %%CPU:  %3.1f%%\n", (procs.statistics.cumulative / procs.statistics.increments));
    (void)printf("Maximum %%CPU:  %3.1f%%\n", procs.statistics.maxuse);
    (void)printf("Minimum %%CPU:  %3.1f%%\n", procs.statistics.minuse);
}
