From: Ilya Zakharevich Date: Tue, 19 Jan 1999 20:06:45 +0000 (-0500) Subject: Pipes and 2>&1 on OS/2 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=5838269bf4d2c9994fe71b290f7afeda12a0d374;p=p5sagit%2Fp5-mst-13.2.git Pipes and 2>&1 on OS/2 To: Mailing list Perl5 Message-ID: <19990119200645.A21154@monk.mps.ohio-state.edu> p4raw-id: //depot/cfgperl@2660 --- diff --git a/os2/Changes b/os2/Changes index f725137..e45a7a6 100644 --- a/os2/Changes +++ b/os2/Changes @@ -287,3 +287,9 @@ after 5.005_53: it is incremented by the number of messages retrieved. Dies with "QUITing..." if WM_QUIT message is obtained. +after 5.005_54: + Opening pipes from/to processes could fail if (un)appropriate + combination of STDIN/STDOUT was closed. + + If the only shell-metachars of a command are ' 2>&1' at the + end of a command, it is executed without calling the external shell. diff --git a/os2/os2.c b/os2/os2.c index 6b814de..7084074 100644 --- a/os2/os2.c +++ b/os2/os2.c @@ -459,11 +459,12 @@ static ULONG os2_mytype; /* global PL_Argv[] contains arguments. */ int -do_spawn_ve(really, flag, execf, inicmd) +do_spawn_ve(really, flag, execf, inicmd, addflag) SV *really; U32 flag; U32 execf; char *inicmd; +U32 addflag; { dTHR; int trueflag = flag; @@ -476,6 +477,7 @@ char *inicmd; char **argsp = fargs; char nargs = 4; int force_shell; + int new_stderr = -1, nostderr = 0, fl_stderr; STRLEN n_a; if (flag == P_WAIT) @@ -558,6 +560,24 @@ char *inicmd; } } + if (addflag) { + addflag = 0; + new_stderr = dup(2); /* Preserve stderr */ + if (new_stderr == -1) { + if (errno == EBADF) + nostderr = 1; + else { + rc = -1; + goto finish; + } + } else + fl_stderr = fcntl(2, F_GETFD); + rc = dup2(1,2); + if (rc == -1) + goto finish; + fcntl(new_stderr, F_SETFD, FD_CLOEXEC); + } + #if 0 rc = result(trueflag, spawnvp(flag,tmps,PL_Argv)); #else @@ -593,7 +613,9 @@ char *inicmd; if (l >= sizeof scrbuf) { Safefree(scr); longbuf: - croak("Size of scriptname too big: %d", l); + warn("Size of scriptname too big: %d", l); + rc = -1; + goto finish; } strcpy(scrbuf, scr); Safefree(scr); @@ -781,6 +803,13 @@ char *inicmd; && ((trueflag & 0xFF) == P_WAIT)) rc = 255 << 8; /* Emulate the fork(). */ + finish: + if (new_stderr != -1) { /* How can we use error codes? */ + dup2(new_stderr, 2); + close(new_stderr); + fcntl(2, F_SETFD, fl_stderr); + } else if (nostderr) + close(2); return rc; } @@ -815,7 +844,7 @@ register SV **sp; } *a = Nullch; - rc = do_spawn_ve(really, flag, EXECF_SPAWN, NULL); + rc = do_spawn_ve(really, flag, EXECF_SPAWN, NULL, 0); } else rc = -1; do_execfree(); @@ -832,7 +861,7 @@ int execf; register char *s; char flags[10]; char *shell, *copt, *news = NULL; - int rc, err, seenspace = 0; + int rc, err, seenspace = 0, mergestderr = 0; char fullcmd[MAXNAMLEN + 1]; #ifdef TRYSHELL @@ -885,6 +914,18 @@ int execf; break; } else if (*s == '\\' && !seenspace) { continue; /* Allow backslashes in names */ + } else if (*s == '>' && s >= cmd + 3 + && s[-1] == '2' && s[1] == '&' && s[2] == '1' + && isSPACE(s[-2]) ) { + char *t = s + 3; + + while (*t && isSPACE(*t)) + t++; + if (!*t) { + s[-2] = '\0'; + mergestderr = 1; + break; /* Allow 2>&1 as the last thing */ + } } /* We do not convert this to do_spawn_ve since shell should be smart enough to start itself gloriously. */ @@ -927,7 +968,7 @@ int execf; } *a = Nullch; if (PL_Argv[0]) - rc = do_spawn_ve(NULL, 0, execf, cmd); + rc = do_spawn_ve(NULL, 0, execf, cmd, mergestderr); else rc = -1; if (news) @@ -977,6 +1018,7 @@ char *mode; register I32 pid, rc; PerlIO *res; SV *sv; + int fh_fl; /* `this' is what we use in the parent, `that' in the child. */ this = (*mode == 'w'); @@ -988,26 +1030,51 @@ char *mode; if (pipe(p) < 0) return Nullfp; /* Now we need to spawn the child. */ + if (p[this] == (*mode == 'r')) { /* if fh 0/1 was initially closed. */ + int new = dup(p[this]); + + if (new == -1) + goto closepipes; + close(p[this]); + p[this] = new; + } newfd = dup(*mode == 'r'); /* Preserve std* */ - if (p[that] != (*mode == 'r')) { + if (newfd == -1) { + /* This cannot happen due to fh being bad after pipe(), since + pipe() should have created fh 0 and 1 even if they were + initially closed. But we closed p[this] before. */ + if (errno != EBADF) { + closepipes: + close(p[0]); + close(p[1]); + return Nullfp; + } + } else + fh_fl = fcntl(*mode == 'r', F_GETFD); + if (p[that] != (*mode == 'r')) { /* if fh 0/1 was initially closed. */ dup2(p[that], *mode == 'r'); close(p[that]); } /* Where is `this' and newfd now? */ fcntl(p[this], F_SETFD, FD_CLOEXEC); - fcntl(newfd, F_SETFD, FD_CLOEXEC); + if (newfd != -1) + fcntl(newfd, F_SETFD, FD_CLOEXEC); pid = do_spawn_nowait(cmd); - if (newfd != (*mode == 'r')) { + if (newfd == -1) + close(*mode == 'r'); /* It was closed initially */ + else if (newfd != (*mode == 'r')) { /* Probably this check is not needed */ dup2(newfd, *mode == 'r'); /* Return std* back. */ close(newfd); - } + fcntl(*mode == 'r', F_SETFD, fh_fl); + } else + fcntl(*mode == 'r', F_SETFD, fh_fl); if (p[that] == (*mode == 'r')) close(p[that]); if (pid == -1) { close(p[this]); - return NULL; + return Nullfp; } - if (p[that] < p[this]) { + if (p[that] < p[this]) { /* Make fh as small as possible */ dup2(p[this], p[that]); close(p[this]); p[this] = p[that];