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