Skip to content

Instantly share code, notes, and snippets.

@thoni56
Last active January 29, 2020 07:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thoni56/4fc8238e38f05d53f5c611d576c0b4c8 to your computer and use it in GitHub Desktop.
Save thoni56/4fc8238e38f05d53f5c611d576c0b4c8 to your computer and use it in GitHub Desktop.
/***********************************************************************\
Program to spy on a stdin/stdout pipe communication between two
processes, the caller and the target.
thoni56/Thomas Nilefalk - January 2020
Make the caller call this program instead of the real target and
ensure that the TARGET variable points to the target using a full
path.
Then, when called, this program, the parent, will set up three
child processes, one spy for each of the downstream and upstream
communication flows and a third which will exec the real target.
The downstream and upstream childs will hook in to the stdin and
stdout of the parent and thus read from the output pipe of the
caller and write to the input pipe it has set up.
The parent process will setup pipes so that the spy childs can
hook their pipes to the exec'ed target process.
While propagating the communication the children will also copy
that to a logfile.
\**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <stdbool.h>
#define READ_END 0
#define WRITE_END 1
FILE *logFile;
/* You need to define TARGET as a compile-time constant using -DTARGET=... */
//#define TARGET "../../src/c-xref"
int main(int argc, char **argv) {
logFile = fopen("/tmp/pipespy.log", "w");
for (int a=0; a<argc; a++)
fprintf(logFile, "%s ", argv[a]);
fprintf(logFile, "\n");
fflush(logFile);
/* Create the pipes for the sub-spies to the target */
int downstream_pipe[2];
int upstream_pipe[2];
if (pipe(downstream_pipe) < 0) {
perror("pipe(downstream_pipe)");
_exit(-1);
}
if (pipe(upstream_pipe) < 0) {
close(downstream_pipe[READ_END]);
close(downstream_pipe[WRITE_END]);
perror("pipe(upstream_pipe)");
_exit(-1);
}
/* Fork a sub-spy to listen, log and propagate stdin */
pid_t downstream_pid = fork();
if (downstream_pid == 0) {
char buffer[10000];
FILE *toTarget = fdopen(downstream_pipe[WRITE_END], "w");
/* Close the pipe ends we don't use */
close(downstream_pipe[READ_END]);
close(upstream_pipe[READ_END]);
close(upstream_pipe[WRITE_END]);
/* Read from stdin which is the same as the parent has */
while (fgets(buffer, 10000, stdin) != NULL) {
fprintf(logFile, "<-:%s", buffer); fflush(logFile);
fputs(buffer, toTarget); fflush(toTarget);
}
fprintf(logFile, "** downstream child got NULL\n");
_exit(1);
}
/* Fork a sub-spy to listen, log and propagate stdout */
pid_t upstream_pid = fork();
if (upstream_pid == 0) {
char buffer[10000];
FILE *fromTarget = fdopen(upstream_pipe[READ_END], "r");
/* Close the pipe ends we don't use */
close(downstream_pipe[READ_END]);
close(downstream_pipe[WRITE_END]);
close(upstream_pipe[WRITE_END]);
while (fgets(buffer, 10000, fromTarget) != NULL) {
fprintf(logFile, "<-:%s", buffer); fflush(logFile);
/* Write to stdout which is the same as the parent has */
fputs(buffer, stdout); fflush(stdout);
}
fprintf(logFile, "** upstream child got NULL\n"); fflush(logFile);
_exit(1);
}
/* Fork & exec the target with stdin & stdout pipes connected to
the upstream and downstream pipes */
pid_t target_pid = fork();
if (target_pid == 0) {
/* In the target, so... */
/* ... connect the stdin to the downstream pipes read end... */
if (dup2(downstream_pipe[READ_END], STDIN_FILENO) == -1) exit(errno);
/* ... the stdout to the upstream pipes write end... */
if (dup2(upstream_pipe[WRITE_END], STDOUT_FILENO) == -1) exit(errno);
/* ... and exec ... */
execv(TARGET, argv);
/* ... if we get here execv failed... */
perror(TARGET);
_exit(1);
}
/* Parent need to close all pipes... */
close(downstream_pipe[READ_END]);
close(downstream_pipe[WRITE_END]);
close(upstream_pipe[READ_END]);
close(upstream_pipe[WRITE_END]);
int status;
waitpid(downstream_pid, &status, 0);
waitpid(upstream_pid, &status, 0);
waitpid(target_pid, &status, 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment