This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
amigaos4: save and restore stdio handles around exec
[perl5.git] / doio.c
diff --git a/doio.c b/doio.c
index 6087612..d8ea076 100644 (file)
--- a/doio.c
+++ b/doio.c
@@ -377,6 +377,7 @@ Perl_do_open6(pTHX_ GV *gv, const char *oname, STRLEN len,
                else {
                    PerlIO *that_fp = NULL;
                     int wanted_fd;
+                    UV uv;
                    if (num_svs > 1) {
                        /* diag_listed_as: More than one argument to '%s' open */
                        Perl_croak(aTHX_ "More than one argument to '%c&' open",IoTYPE(io));
@@ -390,8 +391,11 @@ Perl_do_open6(pTHX_ GV *gv, const char *oname, STRLEN len,
                         wanted_fd = SvUV(*svp);
                        num_svs = 0;
                    }
-                   else if (isDIGIT(*type)) {
-                        wanted_fd = grok_atou(type, NULL);
+                   else if (isDIGIT(*type)
+                        && grok_atoUV(type, &uv, NULL)
+                        && uv <= INT_MAX
+                    ) {
+                        wanted_fd = (int)uv;
                    }
                    else {
                        const IO* thatio;
@@ -434,8 +438,11 @@ Perl_do_open6(pTHX_ GV *gv, const char *oname, STRLEN len,
                            else if (IoTYPE(thatio) == IoTYPE_SOCKET)
                                IoTYPE(io) = IoTYPE_SOCKET;
                        }
-                       else
-                           wanted_fd = -1;
+                        else {
+                            SETERRNO(EBADF, RMS_IFI);
+                            fp = NULL;
+                            goto say_false;
+                        }
                    }
                    if (!num_svs)
                        type = NULL;
@@ -734,9 +741,10 @@ S_openn_cleanup(pTHX_ GV *gv, IO *io, PerlIO *fp, char *mode, const char *oname,
                 int ofd = PerlIO_fileno(fp);
                 int dupfd = ofd >= 0 ? PerlLIO_dup(ofd) : -1;
 #if defined(HAS_FCNTL) && defined(F_SETFD)
-               /* Assume if we have F_SETFD we have F_GETFD */
-                int coe = ofd >= 0 ? fcntl(ofd, F_GETFD) : -1;
-                if (coe < 0) {
+               /* Assume if we have F_SETFD we have F_GETFD. */
+                /* Get a copy of all the fd flags. */
+                int fd_flags = ofd >= 0 ? fcntl(ofd, F_GETFD) : -1;
+                if (fd_flags < 0) {
                     if (dupfd >= 0)
                         PerlLIO_close(dupfd);
                     goto say_false;
@@ -750,8 +758,9 @@ S_openn_cleanup(pTHX_ GV *gv, IO *io, PerlIO *fp, char *mode, const char *oname,
                 PerlIO_close(fp);
                 PerlLIO_dup2(dupfd, ofd);
 #if defined(HAS_FCNTL) && defined(F_SETFD)
-               /* The dup trick has lost close-on-exec on ofd */
-               fcntl(ofd,F_SETFD, coe);
+               /* The dup trick has lost close-on-exec on ofd,
+                 * and possibly any other flags, so restore them. */
+               fcntl(ofd,F_SETFD, fd_flags);
 #endif
                 PerlLIO_close(dupfd);
            }
@@ -762,12 +771,10 @@ S_openn_cleanup(pTHX_ GV *gv, IO *io, PerlIO *fp, char *mode, const char *oname,
        PerlIO_clearerr(fp);
        fd = PerlIO_fileno(fp);
     }
-#if defined(HAS_FCNTL) && defined(F_SETFD)
-    if (fd >= 0) {
-        if (fcntl(fd, F_SETFD, fd > PL_maxsysfd) < 0) {
-            PerlLIO_close(fd);
-            goto say_false;
-        }
+#if defined(HAS_FCNTL) && defined(F_SETFD) && defined(FD_CLOEXEC)
+    if (fd > PL_maxsysfd && fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
+        PerlLIO_close(fd);
+        goto say_false;
     }
 #endif
     IoIFP(io) = fp;
@@ -790,7 +797,7 @@ S_openn_cleanup(pTHX_ GV *gv, IO *io, PerlIO *fp, char *mode, const char *oname,
     }
     return TRUE;
 
-say_false:
+  say_false:
     IoIFP(io) = saveifp;
     IoOFP(io) = saveofp;
     IoTYPE(io) = savetype;
@@ -806,7 +813,7 @@ Perl_nextargv(pTHX_ GV *gv, bool nomagicopen)
 
     if (!PL_argvoutgv)
        PL_argvoutgv = gv_fetchpvs("ARGVOUT", GV_ADD|GV_NOTQUAL, SVt_PVIO);
-    if (io && (IoFLAGS(io) & IOf_ARGV) && (IoFLAGS(io) & IOf_START)) {
+    if (io && (IoFLAGS(io) & (IOf_ARGV|IOf_START)) == (IOf_ARGV|IOf_START)) {
        IoFLAGS(io) &= ~IOf_START;
        if (PL_inplace) {
            assert(PL_defoutgv);
@@ -1099,12 +1106,13 @@ Perl_io_close(pTHX_ IO *io, GV *gv, bool not_implicit, bool warn_on_fail)
                Perl_ck_warner_d(aTHX_ packWARN(WARN_IO),
                                "Warning: unable to close filehandle %"
                                 HEKf" properly: %"SVf,
-                                GvNAME_HEK(gv), get_sv("!",GV_ADD));
+                                HEKfARG(GvNAME_HEK(gv)),
+                                 SVfARG(get_sv("!",GV_ADD)));
            else
                Perl_ck_warner_d(aTHX_ packWARN(WARN_IO),
                                "Warning: unable to close filehandle "
                                "properly: %"SVf,
-                                get_sv("!",GV_ADD));
+                                SVfARG(get_sv("!",GV_ADD)));
        }
     }
     else if (not_implicit) {
@@ -1198,7 +1206,10 @@ Perl_do_sysseek(pTHX_ GV *gv, Off_t pos, int whence)
 
     if (io && (fp = IoIFP(io))) {
         int fd = PerlIO_fileno(fp);
-        if (fd >= 0) {
+        if (fd < 0 || (whence == SEEK_SET && pos < 0)) {
+            SETERRNO(EINVAL,LIB_INVARG);
+            return -1;
+        } else {
             return PerlLIO_lseek(fd, pos, whence);
         }
     }
@@ -1246,7 +1257,7 @@ Perl_mode_from_discipline(pTHX_ const char *s, STRLEN len)
            }
            else {
                const char *end;
-fail_discipline:
+  fail_discipline:
                end = strchr(s+1, ':');
                if (!end)
                    end = s+len;
@@ -1517,9 +1528,14 @@ S_exec_failed(pTHX_ const char *cmd, int fd, int do_report)
 {
     const int e = errno;
     PERL_ARGS_ASSERT_EXEC_FAILED;
-    if (ckWARN(WARN_EXEC))
-       Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't exec \"%s\": %s",
-                   cmd, Strerror(e));
+#ifdef __amigaos4__
+    if (e)
+#endif
+    {
+       if (ckWARN(WARN_EXEC))
+           Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't exec \"%s\": %s",
+                       cmd, Strerror(e));
+    }
     if (do_report) {
         /* XXX silently ignore failures */
         PERL_UNUSED_RESULT(PerlLIO_write(fd, (void*)&e, sizeof(int)));
@@ -1527,12 +1543,14 @@ S_exec_failed(pTHX_ const char *cmd, int fd, int do_report)
     }
 }
 
-bool
+DO_EXEC_TYPE
 Perl_do_aexec5(pTHX_ SV *really, SV **mark, SV **sp,
               int fd, int do_report)
 {
     dVAR;
+    DO_EXEC_TYPE result = DO_EXEC_FAILURE;
     PERL_ARGS_ASSERT_DO_AEXEC5;
+    PERL_UNUSED_VAR(result); /* if DO_EXEC_TYPE is bool */
 #if defined(__SYMBIAN32__) || defined(__LIBCATAMOUNT__)
     Perl_croak(aTHX_ "exec? I'm not *that* kind of operating system");
 #else
@@ -1555,16 +1573,21 @@ Perl_do_aexec5(pTHX_ SV *really, SV **mark, SV **sp,
            (really && *tmps != '/'))           /* will execvp use PATH? */
            TAINT_ENV();                /* testing IFS here is overkill, probably */
        PERL_FPU_PRE_EXEC
-       if (really && *tmps)
-           PerlProc_execvp(tmps,EXEC_ARGV_CAST(PL_Argv));
-       else
-           PerlProc_execvp(PL_Argv[0],EXEC_ARGV_CAST(PL_Argv));
+       if (really && *tmps) {
+            result =
+              (DO_EXEC_TYPE)
+              PerlProc_execvp(tmps,EXEC_ARGV_CAST(PL_Argv));
+       } else {
+           result =
+              (DO_EXEC_TYPE)
+              PerlProc_execvp(PL_Argv[0],EXEC_ARGV_CAST(PL_Argv));
+       }
        PERL_FPU_POST_EXEC
        S_exec_failed(aTHX_ (really ? tmps : PL_Argv[0]), fd, do_report);
     }
     do_execfree();
 #endif
-    return FALSE;
+    return DO_EXEC_RETVAL(result);
 }
 
 void
@@ -1578,7 +1601,7 @@ Perl_do_execfree(pTHX)
 
 #ifdef PERL_DEFAULT_DO_EXEC3_IMPLEMENTATION
 
-bool
+DO_EXEC_TYPE
 Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
 {
     dVAR;
@@ -1588,6 +1611,8 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
     char *cmd;
     /* Make a copy so we can change it */
     const Size_t cmdlen = strlen(incmd) + 1;
+    DO_EXEC_TYPE result = DO_EXEC_FAILURE;
+    PERL_UNUSED_VAR(result); /* if DO_EXEC_TYPE is bool */
 
     PERL_ARGS_ASSERT_DO_EXEC3;
 
@@ -1623,12 +1648,14 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
              if (s[-1] == '\'') {
                  *--s = '\0';
                  PERL_FPU_PRE_EXEC
-                 PerlProc_execl(PL_cshname, "csh", flags, ncmd, (char*)NULL);
+                 result =
+                    (DO_EXEC_TYPE)
+                    PerlProc_execl(PL_cshname, "csh", flags, ncmd, (char*)NULL);
                  PERL_FPU_POST_EXEC
                  *s = '\'';
                  S_exec_failed(aTHX_ PL_cshname, fd, do_report);
                  Safefree(buf);
-                 return FALSE;
+                 return DO_EXEC_RETVAL(result);
              }
          }
        }
@@ -1672,11 +1699,16 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
            }
          doshell:
            PERL_FPU_PRE_EXEC
-           PerlProc_execl(PL_sh_path, "sh", "-c", cmd, (char *)NULL);
+           result =
+              (DO_EXEC_TYPE)
+              PerlProc_execl(PL_sh_path, "sh", "-c", cmd, (char *)NULL);
            PERL_FPU_POST_EXEC
            S_exec_failed(aTHX_ PL_sh_path, fd, do_report);
+#if defined (__amigaos4__)
+            amigaos_post_exec(fd, do_report);
+#endif
            Safefree(buf);
-           return FALSE;
+           return DO_EXEC_RETVAL(result);
        }
     }
 
@@ -1696,7 +1728,9 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
     *a = NULL;
     if (PL_Argv[0]) {
        PERL_FPU_PRE_EXEC
-       PerlProc_execvp(PL_Argv[0],EXEC_ARGV_CAST(PL_Argv));
+       result =
+          (DO_EXEC_TYPE)
+          PerlProc_execvp(PL_Argv[0],EXEC_ARGV_CAST(PL_Argv));
        PERL_FPU_POST_EXEC
        if (errno == ENOEXEC) {         /* for system V NIH syndrome */
            do_execfree();
@@ -1706,7 +1740,7 @@ Perl_do_exec3(pTHX_ const char *incmd, int fd, int do_report)
     }
     do_execfree();
     Safefree(buf);
-    return FALSE;
+    return DO_EXEC_RETVAL(result);
 }
 
 #endif /* OS2 || WIN32 */
@@ -2332,7 +2366,12 @@ Perl_do_msgsnd(pTHX_ SV **mark, SV **sp)
     if (msize < 0)
        Perl_croak(aTHX_ "Arg too short for msgsnd");
     SETERRNO(0,0);
-    return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
+    if (id >= 0 && flags >= 0) {
+      return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
+    } else {
+      SETERRNO(EINVAL,LIB_INVARG);
+      return -1;
+    }
 #else
     PERL_UNUSED_ARG(sp);
     PERL_UNUSED_ARG(mark);
@@ -2365,7 +2404,12 @@ Perl_do_msgrcv(pTHX_ SV **mark, SV **sp)
     mbuf = SvGROW(mstr, sizeof(long)+msize+1);
 
     SETERRNO(0,0);
-    ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
+    if (id >= 0 && msize >= 0 && flags >= 0) {
+        ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
+    } else {
+        SETERRNO(EINVAL,LIB_INVARG);
+        ret = -1;
+    }
     if (ret >= 0) {
        SvCUR_set(mstr, sizeof(long)+ret);
        *SvEND(mstr) = '\0';
@@ -2449,7 +2493,12 @@ Perl_do_shmio(pTHX_ I32 optype, SV **mark, SV **sp)
        SETERRNO(EFAULT,SS_ACCVIO);             /* can't do as caller requested */
        return -1;
     }
-    shm = (char *)shmat(id, NULL, (optype == OP_SHMREAD) ? SHM_RDONLY : 0);
+    if (id >= 0) {
+        shm = (char *)shmat(id, NULL, (optype == OP_SHMREAD) ? SHM_RDONLY : 0);
+    } else {
+        SETERRNO(EINVAL,LIB_INVARG);
+        return -1;
+    }
     if (shm == (char *)-1)     /* I hate System V IPC, I really do */
        return -1;
     if (optype == OP_SHMREAD) {
@@ -2496,7 +2545,7 @@ Perl_do_shmio(pTHX_ I32 optype, SV **mark, SV **sp)
 Function called by C<do_readline> to spawn a glob (or do the glob inside
 perl on VMS).  This code used to be inline, but now perl uses C<File::Glob>
 this glob starter is only used by miniperl during the build process.
-Moving it away shrinks pp_hot.c; shrinking pp_hot.c helps speed perl up.
+Moving it away shrinks F<pp_hot.c>; shrinking F<pp_hot.c> helps speed perl up.
 
 =cut
 */
@@ -2579,11 +2628,5 @@ Perl_vms_start_glob
 }
 
 /*
- * Local variables:
- * c-indentation-style: bsd
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
  * ex: set ts=8 sts=4 sw=4 et:
  */