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