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