1 /*
2 * The Regina Rexx Interpreter
3 * Copyright (C) 1992-1994 Anders Christensen <anders@pvv.unit.no>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "regina_c.h"
21
22 #if defined(WIN32)
23 # ifdef _MSC_VER
24 # if _MSC_VER >= 1100
25 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
26 # pragma warning(disable: 4115 4201 4214 4514)
27 # endif
28 # endif
29 # include <windows.h>
30 # ifdef _MSC_VER
31 # if _MSC_VER >= 1100
32 # pragma warning(default: 4115 4201 4214)
33 # endif
34 # endif
35 #endif
36
37 #include "rexx.h"
38 #include <stdio.h>
39
40 #include <string.h>
41 #include <signal.h>
42 #include <errno.h>
43 #ifdef HAVE_ASSERT_H
44 # include <assert.h>
45 #endif
46 #ifdef HAVE_UNISTD_H
47 # include <unistd.h>
48 #endif
49
50 #if defined(VMS)
51 # define fork() vfork()
52
53 #if 0
54 /* lets try and see if VMS is smart enough now to do this posixly */
55 # ifdef posix_do_command
56 # undef posix_do_command
57 # endif
58 # define posix_do_command __regina_vms_do_command
59 #endif
60 #endif
61
62 #define STD_IO 0x00
63 #define QUEUE 0x01
64 #define LIFO 0x02
65 #define FIFO 0x04
66 #define STREAM 0x08
67 #define STEM 0x10
68 #define STRING 0x20
69 #define LIFOappend 0x80
70 #define FIFOappend 0x100
71
72 #if defined(_POSIX_PIPE_BUF) && !defined(PIPE_BUF)
73 # define PIPE_BUF _POSIX_PIPE_BUF
74 #endif
75
76 typedef struct { /* shl_tsd: static variables of this module (thread-safe) */
77 char *cbuff ;
78 int child ;
79 int status ;
80 int running ;
81 void *AsyncInfo ;
82 unsigned char IObuf[REGINA_MAX_BUFFER_SIZE]; /* write cache */
83 unsigned IOBused;
84 } shl_tsd_t; /* thread-specific but only needed by this module. see
85 * init_shell
86 */
87
88 /* init_shell initializes the module.
89 * Currently, we set up the thread specific data.
90 * The function returns 1 on success, 0 if memory is short.
91 */
init_shell(tsd_t * TSD)92 int init_shell( tsd_t *TSD )
93 {
94 shl_tsd_t *st;
95
96 if ( TSD->shl_tsd != NULL )
97 return(1);
98
99 if ( ( TSD->shl_tsd = MallocTSD( sizeof(shl_tsd_t) ) ) == NULL )
100 return(0);
101 st = (shl_tsd_t *)TSD->shl_tsd;
102 memset( st, 0, sizeof(shl_tsd_t) ); /* correct for all values */
103 return(1);
104 }
105
stem_access(tsd_t * TSD,environpart * e,int pos,streng * value)106 static const streng *stem_access( tsd_t *TSD, environpart *e, int pos,
107 streng *value )
108 /* appends "."+itoa(pos) to e->currname and accesses this variable.
109 * value is NULL to access the current value or non-NULL to set the new value.
110 * The return value is NULL if a new value is set or the old one.
111 */
112 {
113 int leaflen ;
114
115 leaflen = sprintf( e->currname->value + e->currnamelen, "%d", pos ) ;
116
117 e->currname->len = e->currnamelen + leaflen ;
118
119 /*
120 * FGC: Changed back from get_it_anyway_compound to getvalue.
121 * This will raise a NOVALUE condition if we try to read
122 * unexpected data.
123 * Furthermore we allow the user to use extended stems
124 * like "A.B." if we ever want to allow it. We do so by
125 * changing from [sg]etdirvalue_compound to [sg]etvalue.
126 */
127 if (value == NULL)
128 return( getvalue( TSD, e->currname, -1 ) ) ;
129
130 setvalue( TSD, e->currname, value, -1 ) ;
131 return( NULL ) ;
132 }
133
set_currname(tsd_t * TSD,environpart * e)134 static void set_currname( tsd_t *TSD, environpart *e )
135 /* Sets the initial currname of the environpart from its name. e->currname
136 * will be freed at first if not set to NULL.
137 */
138 {
139 const streng *source = e->name;
140
141 if (e->flags.ant == antSIMSYMBOL)
142 {
143 /*
144 * Just in case of a stem we access the variable directly. Otherwise
145 * we have to resolve the symbol.
146 */
147 if ( (source->len > 0) && ( e->flags.awt != awtSTEM ) )
148 {
149 source = getvalue( TSD, source, -1 ) ;
150 }
151 }
152 else
153 {
154 assert( ( e->flags.ant == antSTRING ) || ( source == NULL ) );
155 }
156
157 if (e->currname != NULL)
158 Free_stringTSD( e->currname ) ;
159
160 /*
161 * We need space for "." and the maximal number, but first check if we
162 * have a "default" value.
163 */
164 if ( source == NULL )
165 {
166 e->currname = NULL ;
167 return ;
168 }
169 e->currnamelen = Str_len( source ) ;
170 e->currname = Str_makeTSD( e->currnamelen + 3*sizeof(int) ) ;
171 memcpy( e->currname->value, source->value, e->currnamelen ) ;
172 e->currname->len = e->currnamelen ; /* pro forma, will be recomputed */
173 }
174
prepare_env_io(environpart * e)175 static void prepare_env_io( environpart *e )
176 /*
177 * Prepares the WITH-IO-redirection from envpart.
178 */
179 {
180 e->SameAsOutput = 0;
181 e->FileRedirected = 0;
182 e->tempname = NULL; /* none as default, might become char* RedirTempFile */
183 e->queue = NULL;
184 e->tmp_queue = NULL;
185 e->type = STD_IO;
186 e->hdls[0] = e->hdls[1] = e->hdls[2] = -1;
187 }
188
open_env_io(tsd_t * TSD,environpart * e,unsigned overwrite,int isString)189 static void open_env_io( tsd_t *TSD, environpart *e, unsigned overwrite, int isString )
190 /* Opens the WITH-IO-redirection from envpart and sets *flag to either
191 * STREAM or STEM. Nothing happens if there isn't a redirection.
192 * The protect-fields are used by the
193 */
194 {
195 const streng *h ;
196 int error ;
197 unsigned awt ;
198 char code ;
199
200 if ( ( e->name == NULL ) && !overwrite && ( e->flags.awt == awtUNKNOWN ) )
201 return ;
202
203 set_currname(TSD, e);
204 if ( overwrite == awtUNKNOWN )
205 awt = e->flags.awt ;
206 else
207 awt = overwrite ;
208 switch (awt)
209 {
210 case awtSTREAM:
211 /*
212 * For a STREAM input/output redirection, set the file reopen
213 * flag, and reopen the file.
214 */
215 e->type = STREAM;
216 if ( e->flags.isinput )
217 code = 'r';
218 else if ( e->flags.append )
219 code = 'A';
220 else /* REPLACE */
221 code = 'R';
222 if ( e->flags.isinput || !e->SameAsOutput )
223 e->file = addr_reopen_file( TSD, e->currname, code,
224 e->flags.iserror );
225 break;
226
227 case awtSTEM:
228 /*
229 * For a STEM input/output redirection, check that existing state of
230 * the stem if appropriate and initialise the stem
231 */
232 e->type = STEM ;
233
234 if (e->flags.isinput || e->flags.append)
235 {
236 /*
237 * For a STEM input redirection, the stem must already exist and be
238 * a valid Rexx "array". This happens to an existing output stem in
239 * the append mode, too.
240 */
241 h = stem_access( TSD, e, 0, NULL ) ;
242 /* h must be a whole positive number */
243 e->maxnum = streng_to_int( TSD, h, &error ) ;
244 if (error || (e->maxnum < 0))
245 exiterror( ERR_INVALID_STEM_OPTION, /* needs stem.0 and */
246 1, /* (stem.0) as arguments */
247 tmpstr_of( TSD, e->currname ),
248 tmpstr_of( TSD, h ) ) ;
249 e->currnum = (e->flags.isinput) ? 1 : e->maxnum + 1;
250 }
251 else /* must be REPLACE */
252 {
253 e->maxnum = 0 ;
254 e->currnum = 1 ;
255 e->base->value[0] = '0' ;
256 e->base->len = 1 ;
257 stem_access( TSD, e, 0, Str_dupTSD( e->base ) ) ;
258 }
259 break;
260
261 case awtLIFO:
262 if ( overwrite != awtUNKNOWN )
263 {
264 if ( e->flags.isinput ) /* "LIFO> cmd ... " */
265 {
266 e->type = QUEUE;
267 e->queue = addr_reopen_queue( TSD, NULL, 'r' ) ; /* current */
268 }
269 else
270 {
271 if ( isString )
272 e->type = STRING ;
273 else
274 {
275 e->type = LIFOappend ;
276 e->queue = addr_reopen_queue( TSD, NULL, 'A' ) ; /* current */
277 }
278 }
279 }
280 else /* "normal" use of WITH ??? LIFO ??? */
281 {
282 if ( e->flags.isinput ) /* "LIFO> cmd ... " */
283 {
284 e->type = QUEUE;
285 e->queue = addr_reopen_queue( TSD, e->currname, 'r' ) ;
286 if ( e->queue == NULL )
287 exiterror( ERR_EXTERNAL_QUEUE, 109, tmpstr_of( TSD, e->currname ) ) ;
288 }
289 else
290 {
291 e->type = LIFO;
292 if (e->flags.append)
293 {
294 e->type = LIFOappend;
295 code = 'A' ;
296 }
297 else /* REPLACE */
298 {
299 e->type = LIFO;
300 code = 'R' ;
301 }
302 e->queue = addr_reopen_queue( TSD, e->currname, code ) ;
303 if ( e->queue == NULL )
304 exiterror( ERR_EXTERNAL_QUEUE, 109, tmpstr_of( TSD, e->currname ) ) ;
305 }
306 }
307 break;
308
309 case awtFIFO:
310 if ( overwrite != awtUNKNOWN )
311 {
312 if ( e->flags.isinput ) /* "FIFO> cmd ... " */
313 {
314 e->type = QUEUE;
315 e->queue = addr_reopen_queue( TSD, NULL, 'r' ) ; /* current */
316 }
317 else
318 {
319 if ( isString )
320 e->type = STRING ;
321 else
322 {
323 e->type = FIFOappend ;
324 e->queue = addr_reopen_queue( TSD, NULL, 'A' ) ; /* current */
325 }
326 }
327 }
328 else /* "normal" use of WITH ??? FIFO ??? */
329 {
330 if ( e->flags.isinput ) /* "FIFO> cmd ... " */
331 {
332 e->type = QUEUE;
333 e->queue = addr_reopen_queue( TSD, e->currname, 'r' ) ;
334 if ( e->queue == NULL )
335 exiterror( ERR_EXTERNAL_QUEUE, 109, tmpstr_of( TSD, e->currname ) ) ;
336 }
337 else
338 {
339 if (e->flags.append)
340 {
341 e->type = FIFOappend;
342 code = 'A' ;
343 }
344 else /* REPLACE */
345 {
346 e->type = FIFO;
347 code = 'R' ;
348 }
349 e->queue = addr_reopen_queue( TSD, e->currname, code ) ;
350 if ( e->queue == NULL )
351 exiterror( ERR_EXTERNAL_QUEUE, 109, tmpstr_of( TSD, e->currname ) ) ;
352 }
353 }
354 break;
355
356 default:
357 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "Illegal address code in open_env_io()" ) ;
358 }
359 }
360
put_stem(tsd_t * TSD,environpart * e,streng * str)361 void put_stem( tsd_t *TSD, environpart *e, streng *str )
362 /* Adds one line to the stem specified in e. */
363 {
364 e->maxnum = e->currnum ;
365 e->currnum++ ;
366 e->base->len = sprintf( e->base->value, "%d", e->maxnum ) ;
367 stem_access( TSD, e, 0, Str_dupTSD( e->base ) ) ;
368 stem_access( TSD, e, e->maxnum, str ) ;
369 }
370
write_buffered(const tsd_t * TSD,int hdl,const void * buf,unsigned size,void * async_info)371 static int write_buffered(const tsd_t *TSD, int hdl, const void *buf,
372 unsigned size, void *async_info)
373 {
374 int rc, done;
375 unsigned todo;
376 shl_tsd_t *st = (shl_tsd_t *)TSD->shl_tsd;
377
378 if ((buf == NULL) || (size == 0)) /* force flush buffers */
379 {
380 do
381 {
382 if (st->IOBused)
383 {
384 /* the following call will return -EAGAIN if not completed */
385 rc = TSD->OS->write(hdl, st->IObuf, st->IOBused, async_info);
386 }
387 else
388 rc = 0;
389 if (rc >= 0)
390 {
391 if (rc == (int) st->IOBused)
392 {
393 st->IOBused = 0;
394 rc = TSD->OS->write(hdl, NULL, 0, async_info);
395 }
396 else
397 {
398 memmove(st->IObuf, st->IObuf + rc, st->IOBused - rc);
399 st->IOBused -= rc;
400 }
401 }
402 else
403 TSD->OS->write(hdl, NULL, 0, async_info);
404 /*
405 * continue until everything written or an error like -EAGAIN
406 * is available. -EAGAIN will let the caller come back to this
407 * function when writing is possible again, so everything
408 * will be written after a while.
409 */
410 } while (st->IOBused && (rc >= 0));
411
412 return(rc);
413 }
414
415 done = 0;
416 while (size) {
417 /* step 1: fill buffer up to the maximum */
418 todo = size;
419 if (todo > sizeof(st->IObuf) - st->IOBused)
420 todo = sizeof(st->IObuf) - st->IOBused;
421 if (todo > 0)
422 {
423 memcpy(st->IObuf + st->IOBused, buf, todo);
424 st->IOBused += todo;
425 }
426 done += todo; /* dropped to the buffer --> done for upper layer */
427
428 /* step 2: flush buffer, if buffer filled */
429 if (st->IOBused < sizeof(st->IObuf))
430 return(done);
431
432 /* step 3: buffer full, giving optimal performance (I hope!) */
433 rc = TSD->OS->write(hdl, st->IObuf, st->IOBused, async_info);
434 if (rc <= 0)
435 {
436 if (done)
437 break; /* something done sucessfully */
438 return(rc);
439 }
440 if (rc == (int) st->IOBused)
441 st->IOBused = 0;
442 else
443 {
444 memmove(st->IObuf, st->IObuf + rc, st->IOBused - rc);
445 st->IOBused -= rc;
446 }
447
448 /* just try another chunk of the input buffer */
449 buf = (const char *) buf + todo;
450 size -= todo;
451 }
452
453 return(done); /* something done sucessfully */
454 }
455
feed(const tsd_t * TSD,streng ** string,int hdl,void * async_info)456 static int feed( const tsd_t *TSD, streng **string, int hdl, void *async_info )
457 /* Writes the content of *string into the file associated with hdl. The
458 * string is shortened and, after the final write, deleted and *string set
459 * to NULL.
460 * async_info is both a structure and a flag. If set, asynchronous IO shall
461 * be used, otherwise blocked IO has to be used.
462 * feed returns 0 on success or an errno value on error.
463 * A return value of EAGAIN is set if we have to wait.
464 */
465 {
466 unsigned total ;
467 int done ;
468
469 if ((string == NULL) || (*string == NULL))
470 return( 0 ) ;
471
472 total = Str_len( *string ) ;
473 if (total == 0)
474 return( 0 ) ;
475
476 done = write_buffered(TSD, hdl, (*string)->value, total, async_info);
477 if (done <= 0)
478 {
479 if (done == 0) /* no error set? */
480 done = ENOSPC ; /* good assumption */
481 else
482 done = -done;
483 if ((done != EAGAIN) && (done != EPIPE))
484 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, strerror(done) ) ;
485 return( done ) ; /* error */
486 }
487
488 if ((unsigned) done < total)
489 {
490 (*string)->len -= done ;
491 memmove((*string)->value, (*string)->value + done, (*string)->len);
492 }
493 else
494 {
495 assert((unsigned)done==total);
496 Free_stringTSD(*string);
497 *string = NULL;
498 }
499 return(0);
500 }
501
reap(const tsd_t * TSD,streng ** string,int hdl,void * async_info)502 static int reap( const tsd_t *TSD, streng **string, int hdl, void *async_info )
503 /* Reads data from the file associated with hdl and returns it in *string.
504 * *string may be NULL or valid, in which case it is expanded.
505 * reap returns 0 on success or an errno value on error. The value -1 indicates
506 * EOF.
507 * async_info is both a structure and a flag. If set, asynchronous IO shall
508 * be used, otherwise blocked IO has to be used.
509 * A maximum chunk of REGINA_MAX_BUFFER_SIZE bytes is read in one operation.
510 * A return value of EAGAIN is set if we have to wait.
511 */
512 {
513 char buf[REGINA_MAX_BUFFER_SIZE] ;
514 unsigned len, total ;
515 streng *s ;
516 int done ;
517
518 if (string == NULL)
519 return( 0 ) ;
520
521 done = TSD->OS->read( hdl, buf, sizeof(buf), async_info ) ;
522 if (done <= 0)
523 {
524 if (done == 0)
525 return( -1 ); /* EOF */
526 else
527 done = -done;
528 /* FGC, FIXME: Not sure, this is the right processing. Setting RS, etc? */
529 if ( done != EAGAIN )
530 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, strerror(done) ) ;
531 return( done ) ; /* error */
532 }
533
534 if (( s = *string ) == NULL)
535 {
536 len = 0 ;
537 s = Str_makeTSD( done ) ;
538 }
539 else
540 {
541 len = Str_len( s ) ;
542 total = Str_max( s ) ;
543 if (len + done > total)
544 {
545 s = Str_makeTSD( len + done ) ;
546 s->len = len ;
547 memcpy( s->value, (*string)->value, len ) ;
548 Free_stringTSD( *string ) ;
549 }
550 }
551 memcpy( s->value + len, buf, done ) ;
552 s->len += done ;
553 *string = s ;
554 return( 0 ) ;
555 }
556
cleanup_envirpart(const tsd_t * TSD,environpart * ep)557 void cleanup_envirpart(const tsd_t *TSD, environpart *ep)
558 /* Closes the associated file handles of ep and deletes a temporary file
559 * if necessary.
560 */
561 {
562 shl_tsd_t *st = (shl_tsd_t *)TSD->shl_tsd;
563
564 if (ep->hdls[0] != -1)
565 {
566 TSD->OS->close(ep->hdls[0], (ep->FileRedirected) ? NULL : st->AsyncInfo);
567 ep->hdls[0] = -1;
568 }
569 if (ep->hdls[1] != -1)
570 {
571 TSD->OS->close(ep->hdls[1], (ep->FileRedirected) ? NULL : st->AsyncInfo);
572 ep->hdls[1] = -1;
573 }
574 if (ep->hdls[2] != -1)
575 {
576 TSD->OS->close_special(ep->hdls[2]);
577 ep->hdls[2] = -1;
578 }
579 if (ep->tempname)
580 {
581 unlink(ep->tempname);
582 FreeTSD(ep->tempname);
583 ep->tempname = NULL;
584 }
585 if ( ep->tmp_queue != NULL )
586 {
587 addr_close_queue( TSD, ep->tmp_queue ) ;
588 ep->tmp_queue = NULL ;
589 }
590 if ( ep->queue != NULL )
591 {
592 addr_close_queue( TSD, ep->queue ) ;
593 ep->queue = NULL ;
594 }
595 }
596
cleanup(tsd_t * TSD,environment * env)597 static void cleanup( tsd_t *TSD, environment *env )
598 /* Closes all open handles in env and deletes temporary files. Already closed
599 * handles are marked by a value of -1.
600 * -1 is set to each handle after closing.
601 */
602 {
603 shl_tsd_t *st = (shl_tsd_t *)TSD->shl_tsd;
604
605 cleanup_envirpart(TSD, &env->input);
606 cleanup_envirpart(TSD, &env->output);
607 cleanup_envirpart(TSD, &env->error);
608
609 if (st->AsyncInfo)
610 TSD->OS->delete_async_info(st->AsyncInfo);
611 st->AsyncInfo = NULL;
612 st->IOBused = 0;
613 }
614
615 /*
616 * CheckAndDealWithSameStems shall be used after opening all IO channels.
617 * It checks whether some of the channels address the same stem. This function
618 * takes care of this circumstances and prevents race conditions. In fact,
619 * in may produce a copy of the input to prevent overwriting.
620 */
CheckAndDealWithSameStems(tsd_t * TSD,environment * env)621 static void CheckAndDealWithSameStems( tsd_t *TSD, environment *env )
622 {
623 if ( ( env->output.type == STEM ) && ( env->error.type == STEM ) )
624 {
625 /* env->output.name and env->error.name must exist here
626 *
627 * We have to take special care if output and error are
628 * redirected to the same stem. We neither want to overwrite
629 * stem values twice nor want to read "stem.0" for every
630 * stem on every access to prevent it.
631 */
632 if ( Str_ccmp( env->output.currname, env->error.currname ) == 0 )
633 {
634 env->error.SameAsOutput = 1;
635 if ( env->error.maxnum == 0 )
636 {
637 /* error may has the REPLACE option while output has not.
638 * Force a silent replace in this case.
639 */
640 env->output.maxnum = 0;
641 env->output.currnum = 1;
642 }
643 }
644 }
645
646 if ( env->input.type == STEM )
647 {
648 /* Same procedure. To prevent overwriting variables while
649 * outputting to a stem wherefrom we have to read, buffer
650 * the input stem if the names do overlap.
651 */
652
653 if ( ( env->output.type == STEM ) &&
654 ( Str_ccmp( env->input.currname, env->output.currname ) == 0 ) )
655 env->input.SameAsOutput |= 1;
656
657 if ( ( env->error.type == STEM ) &&
658 ( Str_ccmp( env->input.currname, env->error.currname ) == 0 ) )
659 env->input.SameAsOutput |= 2;
660
661 if ( env->input.SameAsOutput )
662 {
663 /*
664 * Fixes bug 609017
665 */
666 env->input.currname->len = env->input.currnamelen;
667 env->input.tmp_queue =
668 fill_input_queue_stem( TSD, env->input.currname, env->input.maxnum);
669 }
670 }
671 }
672
673 /*
674 * CheckSameStreams shall be used before opening all IO channels.
675 * It checks whether some of the channels address the same file. This function
676 * takes detects it and prepares the system to reduce file opening.
677 */
CheckSameStreams(tsd_t * TSD,int io_flags,environment * env)678 static void CheckSameStreams( tsd_t *TSD, int io_flags, environment *env )
679 {
680 environpart *e;
681 int i, isFile[3], mask;
682 const streng *name[3];
683 streng *full[3];
684
685 memset( isFile, 0, sizeof( isFile ) );
686 memset( (void *)name, 0, sizeof( name ) );
687
688 for ( i = 0; i < 3; i++ )
689 {
690 switch ( i )
691 {
692 case 0:
693 mask = REDIR_INPUT;
694 e = &env->input;
695 break;
696
697 case 1:
698 mask = REDIR_OUTLIFO | REDIR_OUTFIFO | REDIR_OUTSTRING;
699 e = &env->output;
700 break;
701
702 default:
703 mask = 0;
704 e = &env->error;
705 break;
706
707 }
708
709 e->SameAsOutput = 0;
710 full[i] = NULL;
711 if ( ( io_flags & mask ) ||
712 ( e->flags.awt != awtSTREAM ) )
713 continue;
714
715 name[i] = e->name;
716 if ( ( name[i] != NULL ) && ( name[i]->len == 0 ) )
717 name[i] = NULL;
718
719 if ( ( e->flags.ant == antSIMSYMBOL ) && ( name[i] != NULL ) )
720 {
721 name[i] = getvalue( TSD, name[i], -1 ) ;
722 }
723 else
724 {
725 assert( ( e->flags.ant == antSTRING ) || ( name[i] == NULL ) );
726 }
727
728 isFile[i] = 1;
729 /*
730 * Delay the computation of the fully qualified filename until we
731 * know that it is useful.
732 */
733 }
734 if ( isFile[0] + isFile[1] + isFile[2] > 1 )
735 {
736 for ( i = 0; i < 3; i++ )
737 {
738 full[i] = addr_file_info( TSD, name[i], i );
739 }
740 }
741 if ( ( full[0] != NULL ) && ( full[1] != NULL ) )
742 env->input.SameAsOutput |= filename_cmp( full[0], full[1] ) ? 0 : 1;
743 if ( ( full[0] != NULL ) && ( full[2] != NULL ) )
744 env->input.SameAsOutput |= filename_cmp( full[0], full[2] ) ? 0 : 2;
745 if ( ( full[1] != NULL ) && ( full[2] != NULL ) )
746 env->error.SameAsOutput |= filename_cmp( full[1], full[2] ) ? 0 : 1;
747
748 if ( env->error.SameAsOutput && ( env->error.flags.append == 0 ) )
749 env->output.flags.append = 0;
750 for ( i = 0; i < 3; i++ )
751 {
752 if ( full[i] )
753 {
754 Free_stringTSD( full[i] );
755 }
756 }
757 }
758
759 /*
760 * CheckAndDealWithSameQueues shall be used after opening all IO channels.
761 * It checks whether some of the channels address the same queue. This function
762 * takes care of this circumstances and prevents race conditions. In fact,
763 * in may produce a copy of the input to prevent overwriting.
764 */
CheckAndDealWithSameQueues(tsd_t * TSD,environment * env)765 static void CheckAndDealWithSameQueues( tsd_t *TSD, environment *env )
766 {
767 if ( ( env->output.type & ( LIFO | FIFO | LIFOappend | FIFOappend ) )
768 && ( env->error.type & ( LIFO | FIFO | LIFOappend | FIFOappend ) ) )
769 {
770 /*
771 * We have to take special care if output and error are
772 * redirected to the same queue. We neither want to push
773 * values twice nor want to read our own output for every
774 * stem on every access to prevent it.
775 */
776 if ( addr_same_queue( TSD, env->output.queue, env->error.queue ) )
777 {
778 env->error.SameAsOutput = 1;
779 if ( env->error.type & ( LIFO | FIFO ) )
780 {
781 /* error may has the REPLACE option while output has not.
782 * Force a silent replace in this case.
783 */
784 if ( env->output.type == LIFOappend )
785 env->output.type = LIFO;
786 if ( env->output.type == FIFOappend )
787 env->output.type = FIFO;
788 }
789 }
790 }
791
792 if ( env->input.type == QUEUE )
793 {
794 /* Same procedure. To prevent overwriting values while
795 * outputting to a queue wherefrom we have to read, buffer
796 * the input queue if the queue are same.
797 */
798
799 if ( get_options_flag( TSD->currlevel, EXT_FLUSHSTACK ) == 0 )
800 {
801 if ( ( env->output.type & ( LIFO | FIFO | LIFOappend | FIFOappend ) )
802 && addr_same_queue( TSD, env->input.queue, env->output.queue ) )
803 env->input.SameAsOutput |= 1;
804
805 if ( ( env->error.type & ( LIFO | FIFO | LIFOappend | FIFOappend ) )
806 && addr_same_queue( TSD, env->input.queue, env->error.queue ) )
807 env->input.SameAsOutput |= 2;
808
809 if (env->input.SameAsOutput)
810 env->input.tmp_queue = addr_redir_queue( TSD, env->input.queue );
811 }
812 }
813
814 /* Final stages for queues: if not "append", do a replace by purging */
815 if ( ( env->output.type == FIFO )
816 || ( env->output.type == LIFO ) )
817 addr_purge_queue( TSD, env->output.queue );
818 if ( ( ( env->error.type == FIFO )
819 || ( env->error.type == LIFO ) )
820 && !env->error.SameAsOutput )
821 addr_purge_queue( TSD, env->error.queue );
822 /* reduce used names */
823 if ( env->output.type == FIFOappend )
824 env->output.type = FIFO;
825 if ( env->output.type == LIFOappend )
826 env->output.type = LIFO;
827 if ( env->error.type == FIFOappend )
828 env->error.type = FIFO;
829 if ( env->error.type == LIFOappend )
830 env->error.type = LIFO;
831 }
832
setup_io(tsd_t * TSD,int io_flags,environment * env)833 static int setup_io( tsd_t *TSD, int io_flags, environment *env )
834 /* Sets up the IO-redirections based on the values in io_flags and env.
835 * Each environpart (env->input, env->output, env->error) is set up as follows:
836 * a) The enviroment-based streams and stems are set up if used or not.
837 * env->input.type (or output or error) is set to STREAM, STEM or STD_IO.
838 * b) The io_flags overwrite the different settings and may have
839 * values QUEUE, simLIFO, simFIFO, STRING.
840 * c) If a redirection takes place (type != STD_IO) a pipe() or temporary
841 * file is opened and used.
842 * This function returns 1 on success, 0 on error, in which case an error is
843 * already reported..
844 */
845 {
846 shl_tsd_t *st = (shl_tsd_t *)TSD->shl_tsd;
847 int overwrite;
848
849 cleanup( TSD, env ); /* Useful in case of an undetected previous error */
850
851 prepare_env_io( &env->input );
852 prepare_env_io( &env->output );
853 prepare_env_io( &env->error );
854
855 CheckSameStreams( TSD, io_flags, env );
856 /*
857 * Determine which ANSI redirections are in effect
858 * Use the special io_flags for redirection to overwrite the standard
859 * rules of the environment.
860 */
861 overwrite = ( io_flags & REDIR_INPUT ) ? awtFIFO : awtUNKNOWN;
862 open_env_io( TSD, &env->input, overwrite, 0 );
863 if ( env->input.SameAsOutput )
864 {
865 /*
866 * It must be a file since we don't have checked for stems and queues.
867 * We read the input into a temporary queue, then we can proceed in the
868 * usual way.
869 */
870 env->input.tmp_queue = fill_input_queue_stream( TSD, env->input.file );
871 addr_reset_file( TSD, env->input.file );
872 env->input.file = NULL;
873 }
874
875 if ( io_flags & REDIR_OUTLIFO )
876 overwrite = awtLIFO;
877 else if ( io_flags & REDIR_OUTFIFO )
878 overwrite = awtFIFO;
879 else if ( io_flags & REDIR_OUTSTRING )
880 overwrite = awtFIFO;
881 else
882 overwrite = awtUNKNOWN;
883 open_env_io( TSD, &env->output, overwrite, io_flags & REDIR_OUTSTRING );
884
885 if ( env->error.SameAsOutput )
886 {
887 /*
888 * It must be a file since we don't have checked for stems and queues.
889 * We read the input into a temporary queue or a temporary file.
890 * Then we can proceed in the usual way.
891 */
892 env->error.type = STREAM;
893 }
894 else
895 open_env_io( TSD, &env->error, awtUNKNOWN, 0 );
896
897 CheckAndDealWithSameStems( TSD, env );
898 CheckAndDealWithSameQueues( TSD, env );
899
900 if ( env->input.type != STD_IO )
901 {
902 if ( TSD->OS->open_subprocess_connection( TSD, &env->input ) != 0 )
903 {
904 cleanup( TSD, env );
905 exiterror( ERR_SYSTEM_FAILURE, 920, "creating redirection", "for input", strerror(errno) );
906 return 0;
907 }
908 }
909 if ( env->output.type != STD_IO )
910 {
911 if ( TSD->OS->open_subprocess_connection( TSD, &env->output ) != 0 )
912 {
913 cleanup( TSD, env );
914 exiterror( ERR_SYSTEM_FAILURE, 920, "creating redirection", "for output", strerror(errno) );
915 return 0;
916 }
917 }
918 else
919 fflush( stdout );
920 if ( env->error.type != STD_IO )
921 {
922 if ( TSD->OS->open_subprocess_connection( TSD, &env->error ) != 0 )
923 {
924 cleanup( TSD, env );
925 exiterror( ERR_SYSTEM_FAILURE, 920, "creating redirection", "for error", strerror(errno) );
926 return 0;
927 }
928 }
929 else
930 fflush( stderr );
931 st->AsyncInfo = TSD->OS->create_async_info( TSD );
932 return 1;
933 }
934
fetch_food(tsd_t * TSD,environment * env)935 static streng *fetch_food( tsd_t *TSD, environment *env )
936 /* returns one streng fetched either from a queue (env->input.type == QUEUE) or
937 * from a stem or stream.
938 * Returns NULL if there is no more input to feed the child process.
939 */
940 {
941 const streng *c ;
942 streng *retval ;
943 int delflag = 0 ;
944
945 switch (env->input.type)
946 {
947 case QUEUE:
948 delflag = 1 ;
949 if ( env->input.tmp_queue )
950 c = addr_io_queue( TSD, env->input.tmp_queue, NULL, 0 ) ;
951 else
952 c = addr_io_queue( TSD, env->input.queue, NULL, 0 ) ;
953 if ( c == NULL )
954 return NULL ;
955 break;
956
957 case STREAM:
958 delflag = 1;
959
960 if ( env->input.tmp_queue )
961 {
962 c = addr_io_queue( TSD, env->input.tmp_queue, NULL, 0 );
963 if ( c == NULL )
964 return NULL;
965 break;
966 }
967 if (env->input.file == NULL)
968 return NULL;
969 c = addr_io_file( TSD, env->input.file, NULL );
970 if ( !c )
971 return NULL;
972 if ( c->len == 0 )
973 {
974 Free_stringTSD( (streng *) c );
975 return NULL;
976 }
977 break;
978
979 case STEM:
980 if (!env->input.SameAsOutput)
981 {
982 if (env->input.currnum > env->input.maxnum)
983 return( NULL ) ;
984 c = stem_access( TSD, &env->input, env->input.currnum++, NULL ) ;
985 }
986 else
987 {
988 delflag = 1 ;
989 c = addr_io_queue( TSD, env->input.tmp_queue, NULL, 0 ) ;
990 }
991 if (!c)
992 return( NULL ) ;
993 break;
994
995 default:
996 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "Illegal feeder in fetch_food()" ) ;
997 return( NULL ) ;
998 break ;
999 }
1000
1001 if ( env->input.type != STREAM )
1002 {
1003 if ( env->input.flags.noeol )
1004 {
1005 /* ADDRESS SYSTEM ... WITH INPUT NOEOL ... */
1006 assert( delflag ) ;
1007 retval = (streng *) c ; /* will be destroyed */
1008 }
1009 else
1010 {
1011 /* Append a newline to the end of the line before returning */
1012 #if defined(DOS) || defined(OS2) || defined(WIN32)
1013 retval = Str_makeTSD( c->len + 2 ) ;
1014 memcpy(retval->value, c->value, c->len);
1015 retval->value[c->len] = REGINA_CR;
1016 retval->value[c->len + 1] = REGINA_EOL;
1017 retval->len = c->len + 2;
1018 #else
1019 retval = Str_makeTSD( c->len + 1 ) ;
1020 memcpy(retval->value, c->value, c->len);
1021 retval->value[c->len] = REGINA_EOL;
1022 retval->len = c->len + 1;
1023 #endif
1024 if (delflag)
1025 Free_stringTSD( (streng *) c ) ;
1026 }
1027 }
1028 else
1029 {
1030 /* STREAM mode reads blocks of buffers, usually 4KB ignoring any
1031 * line structure
1032 */
1033 assert( delflag ) ;
1034 retval = (streng *) c ; /* will be destroyed */
1035 }
1036 return( retval ) ;
1037 }
1038
drop_crop_line(tsd_t * TSD,environment * env,const char * data,unsigned length,int is_error)1039 static void drop_crop_line( tsd_t *TSD, environment *env, const char *data,
1040 unsigned length, int is_error )
1041 /* Called while reading the output of the child. The output is in data and
1042 * contains length bytes without the line terminator.
1043 * which may be empty or not yet completed. The exact destination is determined
1044 * by env->x.type, where x is either output or error depending on is_error.
1045 * type may have one of the values simLIFO, simFIFO, STRING, STREAM or STEM.
1046 * is_error is set if the error redirection should happen.
1047 */
1048 {
1049 streng *string ;
1050 int type;
1051
1052 string = Str_makeTSD( length + 1 ) ; /* We need a terminating 0 in some */
1053 /* cases */
1054 memcpy( string->value, data, length ) ;
1055 string->len = length ;
1056 string->value[length] = '\0' ;
1057
1058 if (is_error)
1059 type = env->error.type;
1060 else
1061 type = env->output.type;
1062
1063 switch (type)
1064 {
1065 case LIFO:
1066 if ( is_error && !env->error.SameAsOutput )
1067 {
1068 if ( env->error.tmp_queue != NULL )
1069 addr_io_queue( TSD, env->error.tmp_queue, string, 0 ) ;
1070 else
1071 addr_io_queue( TSD, env->error.queue, string, 0 ) ;
1072 }
1073 else
1074 {
1075 if ( env->output.tmp_queue != NULL )
1076 addr_io_queue( TSD, env->output.tmp_queue, string, 0 ) ;
1077 else
1078 addr_io_queue( TSD, env->output.queue, string, 0 ) ;
1079 }
1080 return; /* consumes the new string */
1081
1082 case FIFO:
1083 case STRING:
1084 if ( is_error && !env->error.SameAsOutput )
1085 {
1086 if ( env->error.tmp_queue != NULL )
1087 addr_io_queue( TSD, env->error.tmp_queue, string, 1 ) ;
1088 else
1089 addr_io_queue( TSD, env->error.queue, string, 1 ) ;
1090 }
1091 else
1092 {
1093 if ( env->output.tmp_queue != NULL )
1094 addr_io_queue( TSD, env->output.tmp_queue, string, 1 ) ;
1095 else
1096 addr_io_queue( TSD, env->output.queue, string, 1 ) ;
1097 }
1098 return; /* consumes the new string */
1099
1100 case STREAM:
1101 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "Illegal STREAM in drop_crop_line()" ) ;
1102 break;
1103
1104 case STEM:
1105 if (is_error && !env->error.SameAsOutput)
1106 put_stem( TSD, &env->error, string ) ;
1107 else
1108 put_stem( TSD, &env->output, string ) ;
1109 return; /* consumes the new string */
1110
1111 default:
1112 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "Illegal crop in drop_crop_line()" ) ;
1113 break ;
1114 }
1115
1116 Free_stringTSD( string ) ;
1117 }
1118
1119 /* line_length tries to find ANY line terminator. This is either \r,
1120 * \n, \r\n or \n\r.
1121 * The lookup happens in line (not 0-terminated) with a length of len.
1122 * The return value is either -1 (not found) or the length of the line
1123 * content. *termlen is set to the number of characters of the line
1124 * terminator, either 1 or 2.
1125 * EOFreached is boolean and indicated a final line if set.
1126 */
line_length(const char * line,int len,int * termlen,int EOFreached)1127 static int line_length(const char *line, int len, int *termlen, int EOFreached)
1128 {
1129 char *ccr;
1130 char *clf;
1131 int h;
1132
1133 ccr = (char *)memchr( line, '\r', len ) ;
1134 clf = (char *)memchr( line, '\n', len ) ;
1135 if ( ccr != NULL )
1136 {
1137 if ( clf != NULL )
1138 {
1139 if ( clf < ccr )
1140 {
1141 *termlen = ( ccr == clf + 1 ) ? 2 : 1 ;
1142 return (int) ( clf - line ) ;
1143 }
1144 else
1145 {
1146 *termlen = ( clf == ccr + 1 ) ? 2 : 1 ;
1147 return (int) ( ccr - line ) ;
1148 }
1149 }
1150 /* else '\r' found, but we must know if it terminates */
1151 h = (int) ( ccr - line ) ;
1152 if ( ( h + 1 < len ) || EOFreached )
1153 {
1154 *termlen = 1 ;
1155 return h ;
1156 }
1157 }
1158 else if ( clf != NULL ) /* simple line feed */
1159 {
1160 h = (int) ( clf - line ) ;
1161 if ( ( h + 1 < len ) || EOFreached )
1162 {
1163 *termlen = 1 ;
1164 return h ;
1165 }
1166 }
1167 return -1 ;
1168 }
1169
drop_crop(tsd_t * TSD,environment * env,streng ** string,int EOFreached,int is_error)1170 static void drop_crop( tsd_t *TSD, environment *env, streng **string,
1171 int EOFreached, int is_error)
1172 /* Called while reading the output of the child. The output is in *string,
1173 * which may be empty or not yet completed. The exact destination is determined
1174 * by env->x.type, where x is either output or error depending on is_error.
1175 * type may have one of the values simLIFO, simFIFO, STRING, STREAM or STEM.
1176 * If EOFreached is set and some data is in *string, this data is interpreted
1177 * as a completed line.
1178 * Completed lines are cut of the string. The string itself isn't deleted.
1179 * is_error is set if the error redirection should happen.
1180 */
1181 {
1182 streng *s ;
1183 char *ptr ;
1184 void *fptr = NULL ;
1185 int max, found, termlen, isStream ;
1186
1187
1188 s = *string;
1189 if (s == NULL) /* might happen on a first call */
1190 return;
1191
1192 if (is_error)
1193 {
1194 isStream = ( env->error.type == STREAM ) ;
1195 fptr = ( env->error.SameAsOutput ) ? env->output.file : env->error.file;
1196 }
1197 else
1198 {
1199 isStream = ( env->output.type == STREAM ) ;
1200 fptr = env->output.file ;
1201 }
1202
1203 if ( isStream )
1204 {
1205 /* very fast bypass, we can simply drop the whole thing */
1206 if ( fptr )
1207 addr_io_file( TSD, fptr, s ) ;
1208
1209 s->len = 0 ;
1210 }
1211 else
1212 {
1213 ptr = s->value ;
1214 max = Str_len( s ) ;
1215
1216 while ( max > 0 )
1217 {
1218 found = line_length( ptr, max, &termlen, EOFreached ) ;
1219
1220 if ( ( found == -1 ) && EOFreached )
1221 {
1222 found = max ;
1223 termlen = 0 ;
1224 }
1225 if ( found < 0 )
1226 break;
1227
1228 drop_crop_line( TSD, env, ptr, (unsigned) found, is_error ) ;
1229 found += termlen ;
1230 max -= found ;
1231 ptr += found ;
1232 }
1233 if (max > 0)
1234 {
1235 if (ptr == s->value)
1236 {
1237 if (max != Str_len(s))
1238 {
1239 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "Illegal memory access");
1240 }
1241 }
1242 else
1243 memmove( s->value, ptr, max ) ;
1244 }
1245 s->len = max ;
1246 }
1247 *string = s ;
1248 }
1249
posix_do_command(tsd_t * TSD,const streng * command,int io_flags,environment * env,Queue * redir)1250 int posix_do_command( tsd_t *TSD, const streng *command, int io_flags, environment *env, Queue *redir )
1251 {
1252 int child, rc ;
1253 int in, out, err;
1254 streng *istring = NULL, *ostring = NULL, *estring = NULL ;
1255 char *cmdline ;
1256 shl_tsd_t *st = (shl_tsd_t *)TSD->shl_tsd;
1257 #ifdef SIGPIPE
1258 signal_handler prev_sig;
1259 #endif
1260
1261 fflush( stdout ) ;
1262 fflush( stderr ) ;
1263
1264 CloseOpenFiles( TSD, fpdRETAIN );
1265
1266 /*
1267 * Fixes bug 615822
1268 */
1269 if (!setup_io(TSD, io_flags, env))
1270 exiterror( ERR_SYSTEM_FAILURE, 0 ) ;
1271
1272 if (env->input.FileRedirected)
1273 {
1274 /* fill up the input file without closing the stream. */
1275
1276 while ((istring = fetch_food(TSD, env)) != NULL)
1277 {
1278 if (feed(TSD, &istring, env->input.hdls[1], NULL) != 0)
1279 break; /* shall not happen! */
1280 }
1281 rc = write_buffered(TSD, env->input.hdls[1], NULL, 0, NULL);
1282 if (rc < 0)
1283 {
1284 errno = -rc;
1285 exiterror( ERR_SYSTEM_FAILURE, 920, "feeding redirection file", "for input", strerror(errno) );
1286 }
1287 /* seek positions of both fdin may have been destroyed */
1288 TSD->OS->restart_file(env->input.hdls[0]);
1289 TSD->OS->close(env->input.hdls[1], NULL);
1290 env->input.hdls[1] = -1;
1291 }
1292
1293 if ( env->output.type == STRING )
1294 env->output.tmp_queue = redir ;
1295
1296 cmdline = str_ofTSD( command ) ;
1297 child = TSD->OS->fork_exec( TSD, env, cmdline, &rc );
1298 FreeTSD( cmdline ) ;
1299 if ( ( child == -1 ) || ( child == 0 ) )
1300 {
1301 err = errno;
1302 cleanup( TSD, env ) ;
1303 if ( child == -1 )
1304 exiterror( ERR_SYSTEM_FAILURE, 1, strerror( err ) );
1305 return ( rc > 0 ) ? -rc : ( rc == 0 ) ? -1000 : rc;
1306 }
1307
1308 /* Close the child part of the handles */
1309 if (env->input.hdls[0] != -1) TSD->OS->close(env->input.hdls[0], NULL) ;
1310 if (env->output.hdls[1] != -1) TSD->OS->close(env->output.hdls[1], NULL) ;
1311 if (env->error.hdls[1] != -1) TSD->OS->close(env->error.hdls[1], NULL) ;
1312 env->input.hdls[0] = env->output.hdls[1] = env->error.hdls[1] = -1;
1313
1314 /* Force our own handles to become nonblocked */
1315 if (!env->input.FileRedirected && ((in = env->input.hdls[1]) != -1))
1316 {
1317 TSD->OS->unblock_handle( &in, st->AsyncInfo ) ;
1318 }
1319 else
1320 in = -1;
1321 if (!env->output.FileRedirected && ((out = env->output.hdls[0]) != -1))
1322 {
1323 TSD->OS->unblock_handle( &out, st->AsyncInfo ) ;
1324 }
1325 else
1326 out = -1;
1327 if (!env->error.FileRedirected && ((err = env->error.hdls[0]) != -1))
1328 {
1329 TSD->OS->unblock_handle( &err, st->AsyncInfo ) ;
1330 }
1331 else
1332 err = -1;
1333
1334 #ifdef SIGPIPE
1335 prev_sig = regina_signal( SIGPIPE, SIG_IGN ) ;
1336 #endif
1337
1338 while ((in != -1) || (out != -1) || (err != -1))
1339 {
1340 TSD->OS->reset_async_info(st->AsyncInfo);
1341 if (in != -1)
1342 {
1343 do {
1344 if (!istring)
1345 istring = fetch_food( TSD, env ) ;
1346 if (!istring)
1347 {
1348 rc = write_buffered(TSD, in, NULL, 0, st->AsyncInfo);
1349 if (rc == -EAGAIN)
1350 TSD->OS->add_async_waiter(st->AsyncInfo, in, 0);
1351 else
1352 {
1353 if ((rc < 0) && (-rc != EPIPE)) /* fixes bug 945218 */
1354 {
1355 errno = -rc;
1356 exiterror( ERR_SYSTEM_FAILURE, 920, "writing to", "input redirection", strerror(errno) );
1357 }
1358 if (TSD->OS->close(in, st->AsyncInfo))
1359 exiterror( ERR_SYSTEM_FAILURE, 920, "closing redirection", "for input", strerror(errno) );
1360 env->input.hdls[1] = in = -1 ;
1361 rc = -1 ; /* indicate a closed stream */
1362 }
1363 }
1364 else /* nothing left in string, but more in the stack */
1365 {
1366 rc = feed( TSD, &istring, in, st->AsyncInfo ) ;
1367 if (rc)
1368 {
1369 if (rc == EAGAIN)
1370 TSD->OS->add_async_waiter(st->AsyncInfo, in, 0);
1371 else
1372 {
1373 TSD->OS->close(in, st->AsyncInfo) ;
1374 env->input.hdls[1] = in = -1 ;
1375 }
1376 }
1377 else if (istring != NULL)
1378 {
1379 /* hasn't written all at once, therefore is blocked.
1380 * do a little performance boost and don't try to write
1381 * once more, perform the wait instead.
1382 */
1383 rc = -1;
1384 TSD->OS->add_async_waiter(st->AsyncInfo, in, 0);
1385 }
1386 }
1387 } while (rc == 0); /* It is best for performance and no penalty for */
1388 /* security to write as much as possible */
1389
1390 } /* if (in != -1) */
1391
1392 if (out != -1)
1393 {
1394 do {
1395 rc = reap( TSD, &ostring, out, st->AsyncInfo );
1396 if (rc)
1397 {
1398 if (rc == EAGAIN)
1399 TSD->OS->add_async_waiter(st->AsyncInfo, out, 1);
1400 else
1401 {
1402 TSD->OS->close(out, st->AsyncInfo) ;
1403 env->output.hdls[0] = out = -1 ;
1404 }
1405 }
1406 else if (ostring != NULL)
1407 drop_crop( TSD, env, &ostring, 0, 0 ) ;
1408 } while (rc == 0); /* It is best for performance and no penalty for */
1409 /* security to write as much as possible */
1410 } /* if (out != -1) */
1411
1412 if (err != -1)
1413 {
1414 do {
1415 rc = reap( TSD, &estring, err, st->AsyncInfo );
1416 if (rc)
1417 {
1418 if (rc == EAGAIN)
1419 TSD->OS->add_async_waiter(st->AsyncInfo, err, 1);
1420 else
1421 {
1422 TSD->OS->close(err, st->AsyncInfo) ;
1423 env->error.hdls[0] = err = -1 ;
1424 }
1425 }
1426 else if (estring != NULL)
1427 drop_crop( TSD, env, &estring, 0, 1 ) ;
1428 } while (rc == 0); /* It is best for performance and no penalty for */
1429 /* security to write as much as possible */
1430 } /* if (err != -1) */
1431
1432 TSD->OS->wait_async_info(st->AsyncInfo); /* wait for any more IO */
1433 } /* end of IO */
1434
1435 if (istring)
1436 Free_stringTSD( istring );
1437
1438 if (ostring)
1439 {
1440 if ( Str_len( ostring ) )
1441 drop_crop( TSD, env, &ostring, 1, 0 );
1442 Free_stringTSD( ostring );
1443 }
1444
1445 if (estring)
1446 {
1447 if ( Str_len( estring ) )
1448 drop_crop( TSD, env, &estring, 1, 1 );
1449 Free_stringTSD( estring );
1450 }
1451
1452 if ( ( env->input.type == QUEUE ) && ( env->input.tmp_queue == NULL ) )
1453 addr_purge_queue( TSD, env->input.queue ) ;
1454
1455 rc = TSD->OS->wait(child);
1456
1457 #ifdef SIGPIPE
1458 regina_signal( SIGPIPE, prev_sig ) ;
1459 // regina_signal( SIGPIPE, SIG_DFL ) ;
1460 #endif
1461
1462 if (env->output.FileRedirected)
1463 {
1464 /* The file position is usually at the end: */
1465 TSD->OS->restart_file(env->output.hdls[0]);
1466 while (reap( TSD, &ostring, env->output.hdls[0], NULL ) == 0)
1467 {
1468 if (ostring != NULL)
1469 drop_crop( TSD, env, &ostring, 0, 0 ) ;
1470 }
1471 if (ostring != NULL)
1472 drop_crop( TSD, env, &ostring, 1, 0 ) ;
1473
1474 /* use the automatted closing feature of cleanup */
1475 }
1476 if (env->error.FileRedirected)
1477 {
1478 /* The file position is usually at the end: */
1479 TSD->OS->restart_file(env->error.hdls[0]);
1480 while (reap( TSD, &estring, env->error.hdls[0], NULL ) == 0) {
1481 if (estring != NULL)
1482 drop_crop( TSD, env, &estring, 0, 1 ) ;
1483 }
1484 if (estring != NULL)
1485 drop_crop( TSD, env, &estring, 1, 1 ) ;
1486 /* use the automatted closing feature of cleanup */
1487 }
1488
1489 if ( env->output.type & ( LIFO | FIFO ) ) /* never use STRING here */
1490 flush_stack( TSD, env->output.tmp_queue, env->output.queue, env->output.type == FIFO ) ;
1491 if ( env->error.type & ( LIFO | FIFO ) )
1492 flush_stack( TSD, env->error.tmp_queue, env->error.queue, env->output.type == FIFO ) ;
1493
1494 if ( ( env->input.type == STREAM ) && ( env->input.file != NULL ) )
1495 addr_reset_file( TSD, env->input.file );
1496 if ( env->output.type == STREAM )
1497 addr_reset_file( TSD, env->output.file );
1498 if ( ( env->error.type == STREAM ) && !env->error.SameAsOutput )
1499 addr_reset_file( TSD, env->error.file );
1500 if ( env->output.type == STRING )
1501 env->output.tmp_queue = NULL ;
1502
1503 cleanup( TSD, env ) ;
1504
1505 return rc ;
1506 }
1507