1
0
Fork 0

psroute(1)

This commit is contained in:
dtb 2024-01-13 13:38:09 -07:00
parent 4477d25693
commit eae95ebfca
3 changed files with 119 additions and 0 deletions

3
psroute/Makefile Normal file
View File

@ -0,0 +1,3 @@
CFLAGS += -I../libpsargs
psroute: psroute.o ../libpsargs/libpsargs.o

44
psroute/psroute.1 Normal file
View File

@ -0,0 +1,44 @@
.TH PSROUTE 1
.SH NAME
psroute \(en pipe standard output and standard error, independently
.SH SYNOPSIS
psroute
"["
.RB [ command
.RB ( argument... )]
"]"
"["
.RB [ command
.RB ( argument... )]
"]"
"["
.RB [ command
.RB ( argument... )]
"]"
.SH DESCRIPTION
Psroute runs the first given command, piping its standard output to the
standard input of the second given command, and piping the first command's
standard error to the standard input of the third given command.
.PP
Psroute's standard input is piped to the first given command. The second and
third commands' standard output and error stream out of psroute normally.
.SH DIAGNOSTICS
Psroute will print an error message and exit with the appropriate status from
sysexits(3) in the event of improper invocation or operating system error.
Psroute will exit with the status of the first given command.
.SH BUGS
See psrelay(1).
.SH COPYRIGHT
Public domain.

72
psroute/psroute.c Normal file
View File

@ -0,0 +1,72 @@
#include <stdio.h> /* fprintf(3), perror(3), stderr */
#if !defined EX_OSERR || !defined EX_USAGE
# include <sysexits.h>
#endif
#include <unistd.h> /* dup2(2), fork(2), pipe(2), STDERR_FILENO,
* STDOUT_FILENO */
#include <sys/types.h> /* <sys/wait.h> */
#include <sys/wait.h> /* waitpid(2), WEXITSTATUS */
#include "libpsargs.h" /* check_arg(3), corresponding_arg(3) */
int oserr(char *s){
perror(s);
return EX_OSERR;
}
int main(int argc, char *argv[]){
int child;
char **corr;
char **curr;
int e[2];
int efd;
int i;
int o[2];
int ofd;
int pid;
if(argc < 2 || check_arg(curr = &argv[1]) != 3){
fprintf(stderr,
"Usage: %s \"[\" [command] (arguments...) \"]\""
"\t" "\"[\" [command] (arguments...) \"]\""
" \"[\" [command (arguments...) \"]\"\n",
argc == 0 ? "<no argv[0]>" : argv[0]);
return EX_USAGE;
}
if( (ofd = dup(STDOUT_FILENO)) < 0 /* preserve stdout */
|| (efd = dup(STDERR_FILENO)) < 0 /* and stderr */
|| pipe(o) < 0 /* establish out pipe */
|| pipe(e) < 0 /* and err pipe, and use them: */
|| dup2(o[1], STDOUT_FILENO) != STDOUT_FILENO
|| dup2(e[1], STDERR_FILENO) != STDERR_FILENO)
return oserr(argv[0]);
/* start the source command first because it's the most critical point
* of failure */
*(corr = corresponding_arg(curr++)) = NULL;
switch(pid = fork()){
case 0: execvp(curr[0], curr);
case -1: return oserr(argv[0]);
}
/* restore preserved stdout/stderr */
if( dup2(ofd, STDOUT_FILENO) != STDOUT_FILENO
|| dup2(efd, STDERR_FILENO) != STDERR_FILENO)
return oserr(argv[0]);
for(i = 1; i <= 2; ++i){
curr = corr + 1;
*(corr = corresponding_arg(curr++)) = NULL;
if(dup2(((i == 1) ? o : e)[0], STDIN_FILENO != STDIN_FILENO))
return oserr(argv[0]);
switch(fork()){
case 0: execvp(curr[0], curr);
case -1: return oserr(argv[0]);
}
}
waitpid(pid, &child, 0);
return WEXITSTATUS(child);
}