/*
 *========================================================================
 * $Id: xmlsysd_utils.c 97 2002-04-17 18:28:31Z rgb $
 *
 * See copyright in copyright.h and the accompanying file COPYING
 *========================================================================
 */


#include "xmlsysd.h"

/* 
 *==================================================================
 * Utility routines that might be reusable.
 *==================================================================
 */


/*
 * readline() reads one LF NULL terminate line and converts all
 * terminating LF's to NULL
 */
readline(int fd, char *str, int maxstrlen)
{

 int n,nread = 0;
 char *strptr;

 strptr = &(*str);

 /* Read characters until NULL or end-of-input */
 if((verbose == D_ALL) || (verbose == D_READLINE)){
   printf("D_READLINE: Starting D_READLINE.  Use -v %d to focus.\n",D_READLINE);
 }
 do{
   n = read(fd,str,1);	/* read in next character */
   if(n <= 0) {
     if((verbose == D_ALL) || (verbose == D_READLINE)){
       printf("D_READLINE: Socket is Dead! Closing socket...\n");
     }
     xmlsysd_quit();
   }
   if((verbose == D_ALL) || (verbose == D_READLINE)){
     if(str[0] != 10) printf("D_READLINE: %c\n",str[0]);
   }
   nread += n;		/* increment the count on success */
 } while (n > 0 && *str++ != (char) 10 && nread < maxstrlen);

 /* step back to last character and strip of any trailing LF's */
 *str--;
 while(*str == (char)10){
    *str-- = (char) 0;	/* Terminate the string over the LF */
    nread--;		/* decrement the count */
 }
 if((verbose == D_ALL) || (verbose == D_READLINE)){
   printf("D_READLINE: Got %s\n",strptr);
 }
 return(nread);

}

int sendline(int fd, char *buffer, int length)
{

 int buflen;

 buflen = sizeof(buffer);

 /* 
  * Note:  If buffer is filled with sprintf, length will typically NOT
  * include the terminating 0.  We therefore have to send at least one
  * more character (the trailing 0) since it is expected at the read
  * end.  Recalling that buffer runs from 0-buflen-1 (maximum), this 
  * makes this routine fairly complicated if we try to guard against
  * all possible problems.
  */

 if(length >= buflen-2) {
   buffer[buflen - 2] = (char) 10;	/* MUST be LF */
   buffer[buflen - 1] = (char) 0;	/* MUST terminate string */
   length = buflen;			/* This is truncated length */
 } else 
 if(buffer[length-1] != (char) 10){	/* If no terminating LF */
   buffer[length-1] = (char) 10;	/* add one, there is room */
   buffer[length++] = (char) 0;		/* and then RETERMINATE STRING! */
 }
 /* buffer now terminated by LF,0, and length no longer than buflen */

 /* Too noisy even for verbose -- use only to debug sendline()
  if(verbose) printf("client = %d, sending %s",client_fd,buffer);
  */
 write(fd,buffer,length);		/* So send it */

 return 1;				/* Normal return is "true" */

}

/*
 * readn - read exactly n bytes 
 */
int readn(int fd, char *bp, size_t len)
{

 int cnt;
 int rc;

 cnt = len;
 while ( cnt > 0 ) {
   if(verbose == 14){
     printf("At start of loop\n");
   }
   rc = recv( fd, bp, cnt, 0 );
   if(verbose == 14){
     printf("readn got %d characters:\n%s\n",rc,bp);
   }
   if( rc < 0 )	{				/* read error? */
     if( errno == EINTR )	/* interrupted? */
       continue;			/* restart the read */
     if( errno == EAGAIN )	/* would block? */
       continue;			/* restart the read */
     return -1;				/* return error */
   }
   if( rc == 0 ) {				/* EOF? */
     if(verbose == 14){
       printf("Finished: readn got %d characters:\n",rc);
     }
     return len - cnt;		/* return short count */
   }
   bp += rc;
   cnt -= rc;
   if(verbose == 14){
     printf("At end of loop\n");
   }
 }

 if(verbose == 14){
   printf("Finished: readn got %d characters:\n",rc);
 }
 return len;

}

void send_error(char *msg)
{

 strncpy(outbuf,"Start Error Message\n",K64);
 strncat(outbuf,msg,K64);
 strncpy(outbuf,"\nEnd Error Message\n",K64);
 send(client_fd,outbuf,strlen(outbuf),0);

}


/* SIGCHLD handler.  This is called whenever a child dies.  This will then 
   reap any zombies left by exited c. */

void sigchld_handler(int sig)
{
  int status;
  /* Reap all children */
#ifdef HAVE_WAITPID
  while (waitpid(-1, &status, WNOHANG) > 0)
    ;
#else
  wait(&status);
#endif
  signal(SIGCHLD, sigchld_handler);
}

/*
 * stolen directly from top.c
 */
char *scale_time(int time,int width) 
{
        static char buf[100];

        /* Try successively higher units until it fits */

        sprintf(buf,"%d:%02d",time/60,time%60); /* minutes:seconds */
        if (strlen(buf)<=width) 
                return buf;

        time/=60;       /* minutes */
        sprintf(buf,"%dm",time);
        if (strlen(buf)<=width) 
                return buf;

        time/=60;       /* hours */
        sprintf(buf,"%dh",time);
        if (strlen(buf)<=width) 
                return buf;

        time/=24;       /* days */
        sprintf(buf,"%dd",time);
        if (strlen(buf)<=width) 
                return buf;
        
        time/=7;        /* weeks */
        sprintf(buf,"%dw",time);
        return buf;     /* this is our last try; 
                                if it still doesn't fit, too bad. */

        /* :-) I suppose if someone has a SMP version of Linux with a few
           thousand processors, they could accumulate 18 years of CPU time... */
           
}

char *scale_k(int k,int width,int unit) 
{
                /* kilobytes, megabytes, gigabytes, too-big-for-int-bytes */
        static double scale[]={1024,1024*1024,1024*1024*1024,0};
                /* kilo, mega, giga, tera */
        static char unitletters[]={'K','M','G','T',0};
        static char buf[100];
        char *up;
        double *dp;

        /* Try successively higher units until it fits */

        sprintf(buf,"%d",k);
        if (strlen(buf)<=width) 
                return buf;

        for (up=unitletters+unit,dp=scale ; *dp ; ++dp,++up) {
                sprintf(buf,"%.1f%c",k / *dp,*up);
                if (strlen(buf)<=width) 
                        return buf;
                sprintf(buf,"%d%c",(int)(k / *dp),*up);
                if (strlen(buf)<=width) 
                        return buf;
	}

        /* Give up; give them what we got on our shortest attempt */
        return buf;
}

void save_dctl()
{

 /* save the old */
 dctl_save.identity = dctl.identity;	/* save identity */
 dctl_save.time = dctl.time;		/* save time */
 dctl_save.users = dctl.users;		/* save users */
 dctl_save.cpuinfo = dctl.cpuinfo;	/* save cpuinfo */
 dctl_save.loadavg = dctl.loadavg;	/* save loadavg */
 dctl_save.meminfo = dctl.meminfo;	/* save meminfo */
 dctl_save.net = dctl.net;		/* save net */
 dctl_save.stat = dctl.stat;		/* save stat */
 dctl_save.sysvipc = dctl.sysvipc;	/* save sysvipc */
 dctl_save.uptime = dctl.uptime;	/* save uptime */
 dctl_save.version = dctl.version;	/* save version */

 /* set dctl to send everything */
 dctl.identity = 1;	/* send identity */
 dctl.time = 1;		/* send time */
 dctl.users = 1;	/* send users */
 dctl.cpuinfo = 1;	/* send cpuinfo */
 dctl.loadavg = 1;	/* send loadavg */
 dctl.meminfo = 1;	/* send meminfo */
 dctl.net = 1;		/* send net */
 dctl.stat = 1;		/* send stat */
 dctl.sysvipc = 1;	/* send sysvipc */
 dctl.uptime = 1;	/* send uptime */
 dctl.version = 1;	/* send version */

}

void restore_dctl()
{

 /* restore the old */
 dctl.identity = dctl_save.identity;	/* restore identity */
 dctl.time = dctl_save.time;		/* restore time */
 dctl.users = dctl_save.users;		/* restore users */
 dctl.cpuinfo = dctl_save.cpuinfo;	/* restore cpuinfo */
 dctl.loadavg = dctl_save.loadavg;	/* restore loadavg */
 dctl.meminfo = dctl_save.meminfo;	/* restore meminfo */
 dctl.net = dctl_save.net;		/* restore net */
 dctl.stat = dctl_save.stat;		/* restore stat */
 dctl.sysvipc = dctl_save.sysvipc;	/* restore sysvipc */
 dctl.uptime = dctl_save.uptime;	/* restore uptime */
 dctl.version = dctl_save.version;	/* restore version */

}
