Skip to content

Instantly share code, notes, and snippets.

@RavuAlHemio
Created November 10, 2012 16:56
Show Gist options
  • Save RavuAlHemio/4051694 to your computer and use it in GitHub Desktop.
Save RavuAlHemio/4051694 to your computer and use it in GitHub Desktop.
fork-and-pipe debugging utility
/**
* @file pipes-are-evil.c
* @author Ondřej Hošek <[email protected]>
*/
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
enum
{
/** Number of bytes for the output filename buffer. */
FNBUFSIZE = 128,
/** Length of one hex line. */
HEXLINELEN = 16
};
/** Name of the program. */
static const char *progname = "pipes-are-evil";
/**
* Outputs an error message (taken from errno) and terminates the program.
*
* This function does not return.
*
* @param func Name of the function which failed.
*/
__attribute__((noreturn))
static void bail_out(const char *func)
{
(void)fprintf(stderr, "%s: %s: [%d] %s\n", progname, func, errno, strerror(errno));
exit(EXIT_FAILURE);
}
/** The file being written to. */
static FILE *f = NULL;
/**
* Outputs a hexadecimal dump of the given line at the given file.
*
* @param f File into which to dump.
* @param pos Byte position of this line within the file. The first byte is at
* 00000000.
* @param line The line to hex-dump.
* @param linelen The length of the line to hex-dump.
* @param maxlinelen The maximum length of a line, for formatting purposes.
*/
static void dump_line(FILE *f, size_t pos, const char *line, size_t linelen, size_t maxlinelen)
{
size_t i;
/* output position */
(void)fprintf(f, "%08zx ", pos);
/* output hexed bytes */
for (i = 0; i < linelen; ++i)
{
(void)fprintf(f, "%02x ", line[i]);
}
/* output padding */
for (i = linelen; i < maxlinelen; ++i)
{
(void)fputs(" ", f);
}
(void)fputc('|', f);
/* output characters */
for (i = 0; i < linelen; ++i)
{
(void)fputc(isprint(line[i]) ? line[i] : '.', f);
}
/* traditionally no padding here */
/* end of line */
(void)fputs("|\n", f);
/* flush */
(void)fflush(f);
}
/**
* Signal handler. Tries to close f before exiting the program.
* @param signum Number of the signal that was raised.
* @param info Assorted information about the signal.
* @param ctx Assorted information about the machine context.
*/
static void sighandler(int signum, siginfo_t *info, void *ctx)
{
if (f != NULL)
{
(void)fclose(f);
}
exit(EXIT_FAILURE);
}
/**
* The main entry point of the program.
* @param argc Number of arguments.
* @param argv Array of argument strings.
* @return 0 on success, non-zero on failure.
*/
int main(int argc, char **argv)
{
size_t i;
char outfn[FNBUFSIZE];
char buf[HEXLINELEN];
if (argc > 0)
{
progname = argv[0];
}
/* try handling signals */
struct sigaction act;
sigset_t mask;
(void)sigemptyset(&mask);
act.sa_sigaction = sighandler;
act.sa_flags = SA_SIGINFO;
act.sa_mask = mask;
if (sigaction(SIGINT, &act, NULL) == -1)
{
(void)fprintf(stderr, "%s: sigaction: [%d] %s\n", progname, errno, strerror(errno));
/* continue */
}
/* construct output file name */
(void)snprintf(outfn, sizeof(outfn), "pae-%u.txt", getpid());
/* open output file */
f = fopen(outfn, "a");
if (f == NULL)
{
bail_out("fopen");
}
/* output arguments */
for (i = 0; i < argc; ++i)
{
size_t l;
size_t pos = 0;
const char *arg = argv[i];
(void)fprintf(f, "Argument %zu:\n", i);
while ((l = strlen(arg)) > HEXLINELEN)
{
dump_line(f, pos, arg, HEXLINELEN, HEXLINELEN);
pos += HEXLINELEN;
arg += HEXLINELEN;
}
dump_line(f, pos, arg, strlen(arg), HEXLINELEN);
(void)fputc('\n', f);
(void)fflush(f);
}
/* read and output stdin */
i = 0;
(void)fputs("stdin:\n", f);
for (;;)
{
/* read */
int locerr;
size_t got = fread(buf, sizeof(char), HEXLINELEN, stdin);
/* check for error */
if (got < HEXLINELEN && ferror(stdin))
{
/* remember for later */
locerr = errno;
}
/* output */
dump_line(f, i, buf, got, HEXLINELEN);
/* check for trouble */
if (got < HEXLINELEN)
{
if (ferror(stdin))
{
/* alright then */
(void)fprintf(f, "stdin raised error: [%d] %s\n", locerr, strerror(locerr));
}
else if (ferror(stdin))
{
/* no worries */
(void)fputs("stdin reached EOF\n", f);
}
break;
}
i += got;
}
/* that is quite enough */
if (fclose(f) == EOF)
{
bail_out("fclose");
}
/* aaaaaaand we're done. */
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment