/****************************************************************************
**
** Copyright (C) 2004-2006 Frank Hemer <frank@hemer.org>
**
*****************************************************************************/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <limits.h>
#include <termios.h>
#include <fcntl.h>
#include <signal.h>
//#define WRAPPER_DEBUG
#define PIPE_ERR_ONLY
static void sig_pipe(int signr) {
fprintf(stderr,"ERROR: rsh: received broken pipe signal\n");
exit(-1);
}
int main(int argc, char *argv[]) {
int pid;
#ifndef PIPE_ERR_ONLY
int pipeStdout[2];
int pipeStdin[2];
#endif
int pipeStderr[2];
int failed = 0;
#ifdef WRAPPER_DEBUG
FILE * log = fopen("/home/frank/work/projects/LinCVS/contrib/cvswrapper/log.txt","a");
if (log) {
int i;
for (i=0; i<argc; ++i) {
fprintf(log,"startup arg[%d]: %s\n",i,argv[i]);fflush(log);
}
}
#endif
if (signal(SIGPIPE, sig_pipe) == SIG_ERR) {
perror("can't sig_pipe\n");
}
#ifndef PIPE_ERR_ONLY
if (pipe(pipeStdin)<0) {perror("can't pipeStdin\n");failed=1;}
if (pipe(pipeStdout)<0) {perror("can't pipeStdout\n");failed=1;}
#endif
if (pipe(pipeStderr)<0) {perror("can't pipeStderr\n");failed=1;}
if (failed) exit(-1);
if ((pid = fork()) == 0) {
#ifdef WRAPPER_DEBUG
if (log) {
fprintf(log,"forked child\n");fflush(log);
}
#endif
#ifndef PIPE_ERR_ONLY
close(pipeStdin[1]);
close(pipeStdout[0]);
#endif
close(pipeStderr[0]);
#ifndef PIPE_ERR_ONLY
if (pipeStdin[0] != STDIN_FILENO) {
if (dup2(pipeStdin[0],STDIN_FILENO) != STDIN_FILENO) {
perror("can't dup2 stdin\n");
failed = 1;
} else {
close(pipeStdin[0]);
}
}
if (pipeStdout[1] != STDOUT_FILENO) {
if (dup2(pipeStdout[1],STDOUT_FILENO) != STDOUT_FILENO) {
perror("can't dup2 stdout\n");
failed = 1;
} else {
close(pipeStdout[1]);
}
}
#endif
if (pipeStderr[1] != STDERR_FILENO) {
if (dup2(pipeStderr[1],STDERR_FILENO) != STDERR_FILENO) {
perror("can't dup2 stderr\n");
failed = 1;
} else {
close(pipeStderr[1]);
}
}
if (failed) exit(-1);
argv[0] = getenv("WRAPPER_RSH");
#ifdef WRAPPER_DEBUG
if (log) {
fprintf(log,"starting cmd ...\n");fflush(log);
for (i=0; i<argc; ++i) {
fprintf(log,"execv arg[%d]: %s\n",i,argv[i]);fflush(log);
}
}
#endif
execvp(argv[0],argv);
fprintf(stderr,"ERROR: Cannot execute rsh: %s\n",argv[0]);
perror("ERROR: Call to rsh returned");
fflush(stdout);
fflush(stderr);
exit (-1);
} else if (pid > 0) {
fd_set rfdset;
fd_set rfds;
int s;
char buff[PIPE_BUF];
int wait = 1;
int retval;
#ifdef WRAPPER_DEBUG
if (log) {
fprintf(log,"forked parent\n");fflush(log);
}
#endif
#ifndef PIPE_ERR_ONLY
close(pipeStdin[0]);
close(pipeStdout[1]);
#endif
close(pipeStderr[1]);
FD_ZERO(&rfds);
FD_ZERO(&rfdset);
#ifndef PIPE_ERR_ONLY
FD_SET(STDIN_FILENO, &rfdset);
FD_SET(pipeStdout[0], &rfdset);
wait += 1;
#endif
FD_SET(pipeStderr[0], &rfdset);
do {
rfds = rfdset;
s = select(pipeStderr[0]+1,&rfds,NULL,NULL,NULL);
#ifndef PIPE_ERR_ONLY
if ( FD_ISSET(STDIN_FILENO,&rfds) ) {
int c;
#ifdef WRAPPER_DEBUG
if (log) fprintf(log,"select STDIN_FILENO\n");
#endif
c = read(STDIN_FILENO,buff,PIPE_BUF);
if (c <= 0) {
#ifdef WRAPPER_DEBUG
if (log) {
fprintf(log,"exit stdin\n");fflush(log);
}
#endif
FD_CLR(STDIN_FILENO,&rfdset);
close(pipeStdin[1]);
continue;
}
write(pipeStdin[1],buff,c);
}
if ( FD_ISSET(pipeStdout[0],&rfds) ) {
int c;
#ifdef WRAPPER_DEBUG
if (log) fprintf(log,"select STDOUT_FILENO\n");
#endif
c = read(pipeStdout[0],buff,PIPE_BUF);
if (c <= 0) {
#ifdef WRAPPER_DEBUG
if (log) {
fprintf(log,"exit pipeStdout\n");fflush(log);
}
#endif
--wait;
FD_CLR(pipeStdout[0],&rfdset);
continue;
}
write(STDOUT_FILENO,buff,c);
}
#endif
if ( FD_ISSET(pipeStderr[0],&rfds) ) {
int c;
#ifdef WRAPPER_DEBUG
if (log) fprintf(log,"select STDERR_FILENO\n");
#endif
c = read(pipeStderr[0],buff,PIPE_BUF);
if (c <= 0) {
#ifdef WRAPPER_DEBUG
if (log) {
fprintf(log,"exit pipeStderr\n");fflush(log);
}
#endif
--wait;
FD_CLR(pipeStderr[0],&rfdset);
continue;
}
write(STDERR_FILENO,buff,c);
}
} while (s>-1 && wait>0);
#ifdef WRAPPER_DEBUG
if (log) {
fprintf(log,"wrapper done\n");fflush(log);
fflush(log);
fclose(log);
}
#endif
if (waitpid(pid,&retval,0)<0) {
perror("ERROR: rsh: waitpid error\n");
}
return !WIFEXITED(retval);
} else {
perror("ERROR: rsh: can't fork\n");
}
return (-1);
}
syntax highlighted by Code2HTML, v. 0.9.1