Last active
January 29, 2020 07:13
-
-
Save thoni56/4fc8238e38f05d53f5c611d576c0b4c8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***********************************************************************\ | |
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