/*
 * $Id: procutils.c,v 1.1 2001/03/15 22:16:13 jpormann Exp jpormann $
 *
 * procstatd - Copyright (c) 1999 by Robert G. Brown, rgb@phy.duke.edu
 *         GPL version 2b (b for beverage) granted.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * procstatd - A daemon to extract statistics from /proc/stat and publish them
 *         on demand via a socket connection or broadcast.
 */

#include "procstatd.h"

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

void send_error(char *msg)
{

 int msglen;

 buflen = sprintf(outbuf,"Start Error Message\n");
 sendline(client_fd,outbuf,buflen);
 buflen = sprintf(outbuf,"%s\n",msg);
 sendline(client_fd,outbuf,buflen);
 buflen = sprintf(outbuf,"End Error Message\n");
 sendline(client_fd,outbuf,buflen);

}

/*
 *========================================================================
 * The following is a stable/reliable routine for reading single, LF
 * terminated lines from the socket file descriptor.
 *========================================================================
 */
int readline(int fd, char *buffer, int bufsize)
{

 int i,n;

/* 
 * Read characters until (char)10 (LF).  Wait/loop, blocking, until a full
 * line is returned or the client dies and/or closes the fd.  Note that I
 * require a terminating /n (LF), not a /r (CR) or 0 (NULL).  It is this or
 * deal with fixed length reads.
 */
 i = 0;
 n = read(fd,&buffer[i++],1);		/* Check the first character */
 if(n == -1 || buffer[0] == (char)10) {	/* If none, return null string */
   buffer[0] = (char)0;
   return 0;
 }

 /*
  * Otherwise, read from the file descriptor until a mandatory LF is
  * encountered.  Convert this to a NULL (string terminator) and return
  * the length of the string received > 0.
  */
 do {
   n = read(fd,&buffer[i],1);
   if(n == 0) return -1;		/* Return negative if client closes */
 } while(buffer[i++] != (char)10 && i != bufsize);	/* Read up to (mandatory) LF */
 buffer[--i] = (char)0;			/* Convert the final LF to NULL */

 return(i);				/* Return number correctly read */

}

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

 /* 
  * 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" */

}

/* 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);
}

