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: