[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: [logcheck] I hear you...



I demand that Martijn van Oosterhout may or may not have written...

[snip]
> The way I suggest is to simply standardize init.d scripts so that they
> return 0 for success and 1 for failure and otherwise work as they do now.

And the scripts or binaries called from them to write errors on stderr. I
note that apachectl (apache 1.3.22-2) writes errors to stdout - hmm, bug
report?

> Then someone can write a fancy-sysvinitrc that replaces the current startup
> loop with a program that execs the init.d scripts and attaches itself to
> STDOUT and STDERR and formats/colours appropriatly.

You'll find, attached, a short program which does this; it's intended as a
wrapper around calls to those programs/scripts which are linked from
/etc/rc?.d.

-- 
| Darren Salt       | linux (or ds) at | nr. Ashington,
| Linux PC, Risc PC | youmustbejoking  | Northumberland
| No Wodniws here   | demon co uk      | Toon Army
|   I don't ask for much, just untold riches...

Hackers of the world, unite!
/* colourout --  colour output according to whether it's for stdout or stderr
 * Written by Darren Salt <linux@youmustbejoking.demon.co.uk>
 * GPL
 *
 * Changelog
 * 2001/11/25	Initial release
 */

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>


static const char *program_name = "";
static int done = 0;		/* Non-0 if the child task has quit. */


/* Exit with error (in errno). */
static void
quit (const char *what)
{
  fprintf (stderr, "%s: %s: (%i) %s\n", program_name, what, errno,
	   strerror (errno));
  exit (EXIT_FAILURE);
}


/* Copy from an input stream (i.e. the child task's stdout and stderr) and
 * write to stdout. */
static void
output (int fd)
{
  char buffer[1024];
  ssize_t length;
  while ((length = read (fd, buffer, sizeof (buffer))) > 0)
  {
    if (fwrite (buffer, 1, length, stdout) != length)
      quit ("output");
  }
  if (length < 0 && errno != EAGAIN)
    quit ("output");
}


/* The child task has quit, so flag that this is so. */
static void
reap (int sig)
{
  done = 1;
}


int
main (int argc, char *argv[])
{
  int p_out[2], p_err[2];	/* Pipes for child->parent communication.
				 * stdin needs no special handling. */
  pid_t child;

  program_name = argv[0];

  if (argc < 2)
  {
    /* Nothing to run, so print a usage message. */
    fprintf (stderr, "%s: usage: %s /full/command [arg]...\n",
	     program_name, program_name);
    exit (0);
  }

  if (pipe (p_out) || pipe (p_err))
    quit ("can't create pipes");

  /* Mark the input ends as non-blocking. */
  {
    int i = 1;
    if (ioctl (p_out[0], FIONBIO, &i) || ioctl (p_err[0], FIONBIO, &i))
      quit ("ioctl on fire");
  }
  signal (SIGCHLD, reap);

  /* Split: one to execute, one to print. */
  child = fork ();
  if (child == -1)
    quit ("can't fork");
  else if (child == 0)
  {
    /* Child task */
    /* Don't close the output ends on exec. */
    if (ioctl (p_out[1], FIONCLEX, 0) ||ioctl (p_err[1], FIONCLEX, 0))
      quit ("ioctl on fire");

    /* Make stdout and stderr point at the pipes. */
    if (dup2 (p_out[1], 1) < 0)
      quit ("can't dup stdout");
    if (dup2 (p_err[1], 2) < 0)
      quit ("can't dup stderr");

    /* Execute... */
    execv (argv[1], &argv[1]);
    quit (argv[1]);
  }
  else
  {
    /* Parent task */
    int maxh = ((p_out[0] > p_err[0]) ? p_out[0] : p_err[0]) + 1;
    int is_err = 0;

    /* Set the default colours.*/
    printf ("\x1B[m");

    while (done < 3)
    {
      fd_set rfds;
      struct timeval tv = { done ? 0 : 255, 0 }; /* Long enough */
      int i;

      FD_ZERO (&rfds);
      FD_SET (p_out[0], &rfds);
      FD_SET (p_err[0], &rfds);

      /* Wait for input... */
      i = select (maxh, &rfds, 0, 0, &tv);
      if (i == -1 && errno != EINTR)
	quit ("select");
      else if (i)
      {
	/* Do we have something for stdout? */
	if (FD_ISSET (p_out[0], &rfds))
	{
	  if (is_err)
	  {
	    printf ("\x1B[25;37m");	/* Medium white text. */
	    is_err = 0;
	  }
	  output (p_out[0]);
	}
	/* Do we have something for stderr? */
	if (p_err[0] >= 0 && FD_ISSET (p_err[0], &rfds))
	{
	  if (!is_err)
	  {
	    printf ("\x1B[5;31m");	/* Bold red text. */
	    is_err = 1;
	  }
	  output (p_err[0]);
	}
      }
      /* If the child has exited, loop a few times more to ensure that we've
       * handled all of its output. */
      if (done)
	done++;
    }
    /* Reset colours, ready for whatever's next. */
    printf ("\x1B[m");
  }
}

Reply to: