00001
00002 #include <signal.h>
00003 #include <stdio.h>
00004 #include <stdlib.h>
00005 #include <sys/types.h>
00006 #include <sys/stat.h>
00007 #include <sys/select.h>
00008 #include <fcntl.h>
00009 #include <errno.h>
00010 #include <sys/wait.h>
00011 #include <unistd.h>
00012 #include <zlib.h>
00013 #include "tee.h"
00014
00015 #define BUFSZ 1024
00016
00017 static gzFile gz_fd_e, gz_fd_o;
00018 static int stdout_sav, stderr_sav;
00019
00020 static void sighandler(int signo)
00021 {
00022 fprintf(stderr,"Process received signal %d. Aborting.\n",signo);
00023 gzclose(gz_fd_e);
00024 gzclose(gz_fd_o);
00025 _exit(1);
00026 }
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 pid_t tee_stdio(const char *stdout_file, mode_t stdout_mode,
00053 const char *stderr_file, mode_t stderr_mode)
00054 {
00055 pid_t pid;
00056 static struct sigaction act;
00057
00058 pid = getpid();
00059 #ifdef DEBUG
00060 fprintf(stderr,"teeing...\n");
00061 #endif
00062 int pipe_fd_e[2], pipe_fd_o[2];
00063 if (pipe(pipe_fd_e) < 0 ||
00064 pipe(pipe_fd_o) < 0) {
00065 perror("pipe error");
00066 return -1;
00067 }
00068
00069
00070 act.sa_handler = sighandler;
00071 sigfillset(&(act.sa_mask));
00072 sigaction(SIGINT, &act, NULL);
00073 sigaction(SIGTERM, &act, NULL);
00074
00075
00076
00077 if ((pid = fork()) == -1)
00078 {
00079 fprintf(stderr,"Fork system call failed, aborting\n");
00080 exit(-1);
00081 }
00082 if (pid == 0)
00083 {
00084 int nread,closed_e=0, closed_o=0;
00085 int numfd;
00086 fd_set readset;
00087 char buf[BUFSZ];
00088 int fd_e, fd_o;
00089
00090
00091
00092
00093 close(pipe_fd_e[1]);
00094 close(pipe_fd_o[1]);
00095
00096
00097 if ((fd_e = creat(stderr_file, stderr_mode)) == -1)
00098 {
00099 fprintf(stderr,"Couldn't create file '%s'\n",stderr_file);
00100 exit(-1);
00101 }
00102 gz_fd_e = gzdopen(fd_e, GZFMODE);
00103 #ifdef DEBUG
00104 printf("created file '%s'\n",stderr_file);
00105 #endif
00106
00107 if ((fd_o = creat(stdout_file, stdout_mode)) == -1)
00108 {
00109 fprintf(stderr,"Couldn't create file '%s'\n",stdout_file);
00110 exit(-1);
00111 }
00112 gz_fd_o = gzdopen(fd_o, GZFMODE);
00113 #ifdef DEBUG
00114 printf("created file '%s'\n",stdout_file);
00115 write(STDOUT_FILENO, "STARTING TEE\n", sizeof("STARTING TEE\n"));
00116 #endif
00117 numfd = pipe_fd_o[0]>pipe_fd_e[0] ? pipe_fd_o[0]+1 : pipe_fd_e[0]+1;
00118 while(!closed_e || !closed_o)
00119 {
00120 FD_ZERO(&readset);
00121 if (!closed_o)
00122 FD_SET(pipe_fd_o[0],&readset);
00123 if (!closed_e)
00124 FD_SET(pipe_fd_e[0],&readset);
00125 if (select(numfd, &readset, NULL, NULL, NULL) < 0)
00126 {
00127 if (errno == EINTR)
00128 continue;
00129 else
00130 {
00131 perror("Select failed with error code");
00132 exit(-1);
00133 }
00134 }
00135 if (FD_ISSET(pipe_fd_o[0], &readset))
00136 {
00137 if ((nread = read(pipe_fd_o[0],buf,BUFSZ)) < 0)
00138 {
00139
00140 if (errno == EINTR)
00141 continue;
00142 else
00143 break;
00144 }
00145 else
00146 {
00147 if (nread==0)
00148 {
00149 #ifdef DEBUG
00150 write(STDOUT_FILENO, "GOT CLOSE ON STDOUT\n",
00151 sizeof("GOT CLOSE ON STDERR\n"));
00152 #endif
00153 closed_o++;
00154 }
00155 else
00156 {
00157
00158 while( gzwrite(gz_fd_o, buf,nread) < 0 )
00159 {
00160 if (errno != EINTR)
00161 break;
00162 }
00163 while( write(STDOUT_FILENO, buf, nread) < 0 )
00164 {
00165 if (errno != EINTR)
00166 break;
00167 }
00168 }
00169 }
00170 }
00171 if (FD_ISSET(pipe_fd_e[0], &readset))
00172 {
00173 if ((nread = read(pipe_fd_e[0],buf,BUFSZ)) < 0)
00174 {
00175
00176 if (errno == EINTR)
00177 continue;
00178 else
00179 break;
00180 }
00181 else
00182 {
00183 if (nread==0)
00184 {
00185 #ifdef DEBUG
00186 write(STDOUT_FILENO, "GOT CLOSE ON STDERR\n",
00187 sizeof("GOT CLOSE ON STDERR\n"));
00188 #endif
00189 closed_e++;
00190 }
00191 else
00192 {
00193
00194 while( gzwrite(gz_fd_e, buf,nread) < 0)
00195 {
00196 if (errno != EINTR)
00197 break;
00198 }
00199 while( write(STDERR_FILENO, buf, nread) < 0)
00200 {
00201 if (errno != EINTR)
00202 break;
00203 }
00204 }
00205 }
00206 }
00207 }
00208 gzclose(gz_fd_e);
00209 gzclose(gz_fd_o);
00210 _exit(0);
00211 }
00212 else {
00213
00214
00215 close(pipe_fd_e[0]);
00216 close(pipe_fd_o[0]);
00217 if (!redirect_stdeo(pipe_fd_e[1], pipe_fd_o[1]))
00218 return pid;
00219 return -1;
00220 }
00221 }
00222
00223
00224
00225
00226
00227
00228
00229 int redirect_stdio(const char *stdout_file, mode_t stdout_mode,
00230 const char *stderr_file, mode_t stderr_mode)
00231 {
00232 int fd_e,fd_o, isterm;
00233
00234
00235 if ((fd_e = open(stderr_file,O_WRONLY | O_CREAT, stderr_mode)) == -1)
00236 {
00237 fprintf(stderr,"Couldn't open file '%s'\n",stderr_file);
00238 return -1;
00239 }
00240 fflush(stderr);
00241
00242 if( dup2(fd_e, STDERR_FILENO) == -1)
00243 {
00244 perror("dup2 call failed for stderr");
00245 return -1;
00246 }
00247 close(fd_e);
00248
00249 setbuf(stderr,NULL);
00250
00251
00252 if ((fd_o = open(stdout_file,O_WRONLY | O_CREAT, stdout_mode)) == -1)
00253 {
00254 fprintf(stderr,"Couldn't open file '%s'\n",stdout_file);
00255 return -1;
00256 }
00257 fflush(stdout);
00258 isterm = isatty(STDOUT_FILENO);
00259 if (dup2(fd_o, STDOUT_FILENO)==-1)
00260 {
00261 perror("dup2 call failed for stdout");
00262 return -1;
00263 }
00264 close(fd_o);
00265
00266 if (isterm)
00267 setlinebuf(stdout);
00268 return 0;
00269 }
00270
00271 int redirect_stdeo(int fd_e, int fd_o)
00272 {
00273 int isterm;
00274
00275
00276 fflush(stderr);
00277
00278 if(dup2(fd_e, STDERR_FILENO) == -1)
00279 {
00280 perror("dup2 call failed for stderr");
00281 return -1;
00282 }
00283 close(fd_e);
00284
00285 setbuf(stderr,NULL);
00286
00287
00288 fflush(stdout);
00289 isterm = isatty(STDOUT_FILENO);
00290 if (dup2(fd_o, STDOUT_FILENO)==-1)
00291 {
00292 perror("dup2 call failed for stdout");
00293 return -1;
00294 }
00295 close(fd_o);
00296
00297 if (isterm)
00298 setlinebuf(stdout);
00299 return 0;
00300 }
00301
00302
00303 int save_stdeo() {
00304 stderr_sav = dup(STDERR_FILENO);
00305 if (stderr_sav < 0) {
00306 perror("dup failed. failed to save stderr");
00307 return 1;
00308 }
00309 stdout_sav = dup(STDOUT_FILENO);
00310 if (stdout_sav < 0) {
00311 perror("dup failed. failed to save stdout");
00312 return 1;
00313 }
00314 return 0;
00315 }
00316
00317
00318 int restore_stdeo() {
00319 if (dup2(stderr_sav, STDERR_FILENO) == -1) {
00320 perror("dup2 call failed for stderr");
00321 return 1;
00322 }
00323 close(stderr_sav);
00324
00325 if (dup2(stdout_sav, STDOUT_FILENO) == -1) {
00326 perror("dup2 call failed for stdout");
00327 return 1;
00328 }
00329 close(stdout_sav);
00330
00331 return 0;
00332 }
00333