verson 1.4.54b
[polyglot.git] / pipex_posix.c
1 #ifndef _WIN32
2
3 // includes
4
5 #include <string.h>
6 #include <errno.h>
7 #include <wordexp.h>
8 #include <sys/wait.h>
9 #include "pipex.h"
10
11 // constants
12
13 static const unsigned int StringSize = 4096;
14
15 // prototypes
16
17 static void my_close(int fd);
18 static void my_dup2(int old_fd, int new_fd) ;
19
20 // functions
21
22 // pipex_open()
23
24 void pipex_open(pipex_t *pipex,
25                 const char *name,
26                 const char *working_dir,
27                 const char *command){
28     char string[StringSize];
29     int argc;
30     char * ptr;
31     char * argv[256];
32     int from_child[2], to_child[2];
33     wordexp_t p;
34     int i,ret;
35
36     pipex->pid=-1;
37     pipex->io->name=name;
38     pipex->quit_pending=FALSE;
39     pipex->command=command;
40     
41     if(command==NULL){
42         pipex->io->in_fd = STDIN_FILENO;
43         pipex->io->out_fd = STDOUT_FILENO;
44
45             // attach standard error to standard output
46         
47         my_dup2(STDOUT_FILENO,STDERR_FILENO);
48         io_init(pipex->io);
49     }else{
50     
51         // parse the command line and create the argument list
52 #if 0    
53         if (strlen(command) >= StringSize) my_fatal("pipex_open(): buffer overflow\n");
54         strcpy(string,command);
55         argc = 0;
56         
57         for (ptr = strtok(string," "); ptr != NULL; ptr = strtok(NULL," ")) {
58             argv[argc++] = ptr;
59         }
60
61         argv[argc] = NULL;
62 #else
63         //printf("command=[%s]\n",command);
64         //Buffer overflow alert
65         ret=wordexp(command, &p, 0);
66         if(ret!=0){
67           my_fatal("pipex_open(): %s: Unable to parse command.\n",command);
68         }
69         argc = p.we_wordc;
70         if(argc>=256-2){
71           my_fatal("pipex_open(): %s: Too many arguments.\n",command);
72         }
73         for(i=0;i<argc;i++){
74           argv[i] = p.we_wordv[i];
75         }
76         //      int i;
77         //for(i=0;i<argc;i++){
78         //  printf("[%s]",argv[i]);
79         //}
80         //printf("\n");
81         argv[argc] = NULL;
82 #endif        
83       // create the pipes
84         
85         if (pipe(from_child) == -1) {
86             my_fatal("pipex_open(): pipe(): %s\n",strerror(errno));
87         }
88         
89         if (pipe(to_child) == -1) {
90             my_fatal("pipex_open(): pipe(): %s\n",strerror(errno));
91         }
92         
93             // create the child process
94         
95         pipex->pid = fork();
96         
97         if (pipex->pid == -1) {
98             
99             my_fatal("pipex_open(): fork(): %s\n",strerror(errno));
100             
101         } else if (pipex->pid == 0) {
102             
103                 // child 
104             
105                 // close unused pipe descriptors to avoid deadlocks
106             
107             my_close(from_child[0]);
108             my_close(to_child[1]);
109             
110                 // attach the pipe to standard input
111             
112             my_dup2(to_child[0],STDIN_FILENO);
113             my_close(to_child[0]);
114             
115                 // attach the pipe to standard output
116             
117             my_dup2(from_child[1],STDOUT_FILENO);
118             my_close(from_child[1]);
119             
120                 // attach standard error to standard output
121                 // commenting this out gives error messages on the console
122             
123            /* my_dup2(STDOUT_FILENO,STDERR_FILENO); */
124             
125             if(chdir(working_dir)){
126                 my_fatal("pipex_open(): cannot change directory: %s\n",
127                          strerror(errno));
128             }
129             
130             // launch the new executable file
131
132             execvp(argv[0],&argv[0]);
133             
134                 // execvp() only returns when an error has occured
135             
136             my_fatal("engine_open(): execvp(): %s: %s\n",argv[0],strerror(errno));
137             
138         } else { // pid > 0
139             
140             ASSERT(pipex->pid>0);
141             
142                 // parent 
143             
144                 // close unused pipe descriptors to avoid deadlocks
145             
146             my_close(from_child[1]);
147             my_close(to_child[0]);
148             
149                 // fill in the pipex struct
150             
151             pipex->io->in_fd = from_child[0];
152             pipex->io->out_fd = to_child[1];
153             pipex->state|=PIPEX_ACTIVE; // can we test if this really TRUE?
154             
155             io_init(pipex->io);
156         } 
157     }
158 }
159
160 void pipex_wait_event(pipex_t *pipex[]){
161
162     fd_set set[1];
163     pipex_t *p;
164     int fd_max;
165     int val;
166     pipex_t **q;
167
168     q=pipex;
169
170         // init
171
172    FD_ZERO(set);
173    fd_max = -1; // HACK
174    while((p=*(q++))!=NULL){
175        ASSERT(p->io->in_fd>=0);
176        FD_SET(p->io->in_fd,set);
177        if (p->io->in_fd > fd_max){
178            fd_max = p->io->in_fd;
179        }
180    }
181    
182    // wait for something to read (no timeout)
183
184    ASSERT(fd_max>=0);
185    val = select(fd_max+1,set,NULL,NULL,NULL);
186    if (val == -1 && errno != EINTR) my_fatal("pipex_wait_event(): select(): %s\n",strerror(errno));
187
188    q=pipex;
189    if (val > 0) {
190        while((p=*(q++))!=NULL){
191            if (FD_ISSET(p->io->in_fd,set)) io_get_update(p->io); 
192        }
193    }    
194 }
195
196 // pipex_active()
197
198 bool pipex_active(pipex_t *pipex){
199     return (pipex->state&PIPEX_ACTIVE)!=0;
200 }
201
202 // pipex_eof()
203
204 bool pipex_eof(pipex_t *pipex){
205     return (pipex->state&PIPEX_EOF)!=0;
206 }
207
208
209 // pipex_set_priority()
210
211 void pipex_set_priority(pipex_t *pipex, int value){
212     if(pipex->pid!=-1){
213         setpriority(PRIO_PROCESS,pipex->pid,value);
214     }
215 }
216
217 // pipex_set_affinity()
218
219 void pipex_set_affinity(pipex_t *pipex, int value){
220     my_log("POLYGLOT Setting affinity is not yet implemented on posix\n");
221 }
222
223 // pipex_send_eof()
224
225 void pipex_send_eof(pipex_t *pipex){
226     io_close(pipex->io);
227 }
228
229 // pipex_exit()
230
231 void pipex_exit(pipex_t *pipex){
232     int status;
233     my_log("POLYGLOT Waiting for child process to exit.\n");
234     waitpid(pipex->pid,&status,0);
235     if(WIFEXITED(status)){
236       if(pipex->quit_pending){
237         my_log("POLYGLOT Child exited with status %d.\n",WEXITSTATUS(status));
238       }else{
239         // Suppress further messages.
240         pipex->quit_pending=TRUE;
241         my_fatal("pipex_exit(): %s: child exited with status %d.\n",pipex->command,WEXITSTATUS(status));
242       }
243     }else if(WIFSIGNALED(status)){
244       if(pipex->quit_pending){
245         my_log("POLYGLOT pipex_exit(): %s: child terminated with signal %d.\n",pipex->command,WTERMSIG(status));
246       }else{
247         // Suppress further messages.
248         pipex->quit_pending=TRUE;
249           my_fatal("pipex_exit(): %s: child terminated with signal %d.\n",pipex->command,WTERMSIG(status));
250       }
251     }
252     return;
253 }
254
255 // pipex_readln()
256
257 bool pipex_readln(pipex_t *pipex, char *string){
258     while (!io_line_ready(pipex->io)) {
259       io_get_update(pipex->io);
260    }
261    if (!io_get_line(pipex->io,string,StringSize)) { // EOF
262        string[0]='\0';
263        pipex->state|=PIPEX_EOF;
264        return FALSE;
265    }
266    
267
268    return TRUE;
269 }
270
271 // pipex_readln_nb()
272
273 bool pipex_readln_nb(pipex_t *pipex, char *string){
274     if(io_line_ready(pipex->io)){
275         return pipex_readln(pipex,string);
276     }else{  
277         string[0]='\0';
278         return FALSE;
279     }
280 }
281
282 // pipex_write()
283
284 void pipex_write(pipex_t *pipex, const char *string){
285        io_send_queue(pipex->io,"%s",string);
286 }
287
288
289 // pipex_writeln()
290
291 void pipex_writeln(pipex_t *pipex, const char *string){
292        io_send(pipex->io,"%s",string);
293 }
294
295 // my_close()
296
297 static void my_close(int fd) {
298
299    ASSERT(fd>=0);
300
301    if (close(fd) == -1) my_fatal("my_close(): close(): %s\n",strerror(errno));
302 }
303
304 // my_dup2()
305
306 static void my_dup2(int old_fd, int new_fd) {
307
308    ASSERT(old_fd>=0);
309    ASSERT(new_fd>=0);
310
311    if (dup2(old_fd,new_fd) == -1) my_fatal("my_dup2(): dup2(): %s\n",strerror(errno));
312 }
313
314
315 #endif