Back to index

avfs  1.0.1
runprog.c
Go to the documentation of this file.
00001 /*
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 2000-2001  Miklos Szeredi <miklos@szeredi.hu>
00004 
00005     This program can be distributed under the terms of the GNU GPL.
00006     See the file COPYING.
00007 */
00008 
00009 #include "runprog.h"
00010 #include "prog.h"
00011 #include "filebuf.h"
00012 
00013 #include <unistd.h>
00014 #include <fcntl.h>
00015 
00016 struct program {
00017     char **prog;
00018     struct proginfo pri;
00019     struct filebuf *fbs[2];
00020 };
00021 
00022 
00023 static char **copy_prog(const char **prog)
00024 {
00025     unsigned int len;
00026     unsigned int i;
00027     const char **p;
00028     char **cp;
00029 
00030     for(len = 0, p = prog; *p != NULL; p++, len++);
00031     cp = av_malloc(sizeof(*cp) * (len + 1));
00032     for(i = 0; i < len; i++)
00033         cp[i] = av_strdup(prog[i]);
00034 
00035     cp[len] = NULL;
00036     return cp;
00037 }
00038 
00039 static void free_prog(char **prog)
00040 {
00041     unsigned int i;
00042     for(i = 0; prog[i] != NULL; i++)
00043         av_free(prog[i]);
00044     av_free(prog);
00045 }
00046 
00047 static void program_delete(struct program *pr)
00048 {
00049     av_wait_prog(&pr->pri, 1, 0);
00050     free_prog(pr->prog);
00051     av_unref_obj(pr->fbs[0]);
00052     av_unref_obj(pr->fbs[1]);
00053 }
00054 
00055 int av_start_program(const char **prog, struct program **resp)
00056 {
00057     int res;
00058     int pipeout[2];
00059     int pipeerr[2];
00060     struct program *pr;
00061 
00062     pipeout[0] = -1;
00063     pipeout[1] = -1;
00064     if(pipe(pipeout) == -1 || pipe(pipeerr) == -1) {
00065         res = -errno;
00066         av_log(AVLOG_ERROR, "RUNPROG: unable to create pipe: %s",
00067                strerror(errno));
00068         close(pipeout[0]);
00069         close(pipeout[1]);
00070         return res;
00071     }
00072     av_registerfd(pipeout[0]);
00073     av_registerfd(pipeerr[0]);
00074 
00075     AV_NEW_OBJ(pr, program_delete);
00076     av_init_proginfo(&pr->pri);
00077     pr->fbs[0] = NULL;
00078     pr->fbs[1] = NULL;
00079     pr->prog = copy_prog(prog);
00080 
00081     pr->pri.prog = (const char **) pr->prog;
00082     pr->pri.ifd = open("/dev/null", O_RDONLY);
00083     if(pr->pri.ifd == -1) {
00084         res = -errno;
00085         av_log(AVLOG_ERROR, "RUNPROG: unable to open '/dev/null': %s",
00086                strerror(errno));
00087         close(pipeout[0]);
00088         close(pipeout[1]);
00089         close(pipeerr[0]);
00090         close(pipeerr[1]);
00091         av_unref_obj(pr);
00092         return res;
00093     }
00094     pr->pri.ofd = pipeout[1];
00095     pr->pri.efd = pipeerr[1];
00096 
00097     res = av_start_prog(&pr->pri);
00098     close(pr->pri.ifd);
00099     close(pr->pri.ofd);
00100     close(pr->pri.efd);
00101 
00102     if(res < 0) {
00103         close(pipeout[0]);
00104         close(pipeerr[0]);
00105         av_unref_obj(pr);
00106         return res;
00107     }
00108     
00109     pr->fbs[0] = av_filebuf_new(pipeout[0], FILEBUF_NONBLOCK);
00110     pr->fbs[1] = av_filebuf_new(pipeerr[0], FILEBUF_NONBLOCK);
00111 
00112     *resp = pr;
00113     return 0;
00114 }
00115 
00116 static int flush_error(struct program *pr)
00117 {
00118     int res;
00119     char *line;
00120 
00121     while((res = av_filebuf_readline(pr->fbs[1], &line)) == 1) {
00122         av_log(AVLOG_WARNING, "%s: stderr: %s", pr->pri.prog[0], line);
00123         av_free(line);
00124     }
00125 
00126     return res;
00127 }
00128 
00129 static int flush_output(struct program *pr)
00130 {
00131     int res;
00132     char *line;
00133 
00134     while((res = av_filebuf_readline(pr->fbs[0], &line)) == 1) {
00135         av_log(AVLOG_WARNING, "%s: stdout: %s", pr->pri.prog[0], line);
00136         av_free(line);
00137     }
00138 
00139     return res;
00140 }
00141 
00142 int av_program_getline(struct program *pr, char **linep, long timeoutms)
00143 {
00144     int res;
00145     char *line;
00146 
00147     *linep = NULL;
00148     while(1) {
00149         res = flush_error(pr);
00150         if(res < 0)
00151             return res;
00152         
00153         res = av_filebuf_readline(pr->fbs[0], &line);
00154         if(res < 0)
00155             return res;
00156         if(res == 1)
00157             break;
00158 
00159         if(av_filebuf_eof(pr->fbs[0]) && av_filebuf_eof(pr->fbs[1])) {
00160             res = av_wait_prog(&pr->pri, 0, 0);
00161             if(res < 0)
00162                 return res;
00163 
00164             return 1;
00165         }
00166 
00167         res = av_filebuf_check(pr->fbs, 2, timeoutms);
00168         if(res <= 0)
00169             return res;
00170     }
00171 
00172     *linep = line;
00173     return 1;
00174 }
00175 
00176 int av_program_log_output(struct program *pr)
00177 {
00178     int res;
00179 
00180     res = av_wait_prog(&pr->pri, 0, 1);
00181     if(res < 0)
00182         return res;
00183     
00184     if(res == 1)
00185         return 0;
00186 
00187     return 1;
00188 }
00189 
00190 static int av_process_program(struct program *pr)
00191 {
00192     int res;
00193 
00194     while(!av_filebuf_eof(pr->fbs[0]) || !av_filebuf_eof(pr->fbs[1])) {
00195         res = av_filebuf_check(pr->fbs, 2, 0);
00196         if(res < 0)
00197             return res;
00198         
00199         if(res == 1) {
00200             res = flush_error(pr);
00201             if(res < 0)
00202                 return res;
00203             res = flush_output(pr);
00204             if(res < 0)
00205                 return res;
00206         }
00207     }
00208     
00209     res = av_wait_prog(&pr->pri, 0, 0);
00210     if(res < 0)
00211         return res;
00212 
00213     return 0;
00214 }
00215 
00216 int av_run_program(const char **prog)
00217 {
00218     int res;
00219     struct program *pr;
00220 
00221     res = av_start_program(prog, &pr);
00222     if(res < 0)
00223         return res;
00224 
00225 
00226     res = av_process_program(pr);
00227     av_unref_obj(pr);
00228 
00229     return res;
00230 }