]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/utilsunx.cpp
Rename wxWebNavigationError to wxWebViewNavigationError and wxWebNavigationEvent...
[wxWidgets.git] / src / unix / utilsunx.cpp
index 282f4392585735b35e034374bb16ffcba280b435..ec550fcf244c9a990bec2e530683fd7418e9533a 100644 (file)
@@ -337,6 +337,45 @@ bool wxPipeInputStream::CanRead() const
     }
 }
 
+size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t size)
+{
+    // We need to suppress error logging here, because on writing to a pipe
+    // which is full, wxFile::Write reports a system error. However, this is
+    // not an extraordinary situation, and it should not be reported to the
+    // user (but if really needed, the program can recognize it by checking
+    // whether LastRead() == 0.) Other errors will be reported below.
+    size_t ret;
+    {
+        wxLogNull logNo;
+        ret = m_file->Write(buffer, size);
+    }
+
+    switch ( m_file->GetLastError() )
+    {
+       // pipe is full
+#ifdef EAGAIN
+       case EAGAIN:
+#endif
+#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
+       case EWOULDBLOCK:
+#endif
+           // do not treat it as an error
+           m_file->ClearLastError();
+           // fall through
+
+       // no error
+       case 0:
+           break;
+
+       // some real error
+       default:
+           wxLogSysError(_("Can't write to child process's stdin"));
+           m_lasterror = wxSTREAM_WRITE_ERROR;
+    }
+
+    return ret;
+}
+
 #endif // HAS_PIPE_STREAMS
 
 // ----------------------------------------------------------------------------
@@ -559,12 +598,6 @@ long wxExecute(char **argv, int flags, wxProcess *process,
         }
 #endif // !__VMS
 
-        // reading side can be safely closed but we should keep the write one
-        // opened, it will be only closed when the process terminates resulting
-        // in a read notification to the parent
-        execData.pipeEndProcDetect.Detach(wxPipe::Write);
-        execData.pipeEndProcDetect.Close();
-
         // redirect stdin, stdout and stderr
         if ( pipeIn.IsOk() )
         {
@@ -580,6 +613,39 @@ long wxExecute(char **argv, int flags, wxProcess *process,
             pipeErr.Close();
         }
 
+        // Close all (presumably accidentally) inherited file descriptors to
+        // avoid descriptor leaks. This means that we don't allow inheriting
+        // them purposefully but this seems like a lesser evil in wx code.
+        // Ideally we'd provide some flag to indicate that none (or some?) of
+        // the descriptors do not need to be closed but for now this is better
+        // than never closing them at all as wx code never used FD_CLOEXEC.
+
+        // Note that while the reading side of the end process detection pipe
+        // can be safely closed, we should keep the write one opened, it will
+        // be only closed when the process terminates resulting in a read
+        // notification to the parent
+        const int fdEndProc = execData.pipeEndProcDetect.Detach(wxPipe::Write);
+        execData.pipeEndProcDetect.Close();
+
+        // TODO: Iterating up to FD_SETSIZE is both inefficient (because it may
+        //       be quite big) and incorrect (because in principle we could
+        //       have more opened descriptions than this number). Unfortunately
+        //       there is no good portable solution for closing all descriptors
+        //       above a certain threshold but non-portable solutions exist for
+        //       most platforms, see [http://stackoverflow.com/questions/899038/
+        //          getting-the-highest-allocated-file-descriptor]
+        for ( int fd = 0; fd < (int)FD_SETSIZE; ++fd )
+        {
+            if ( fd != STDIN_FILENO  &&
+                 fd != STDOUT_FILENO &&
+                 fd != STDERR_FILENO &&
+                 fd != fdEndProc )
+            {
+                close(fd);
+            }
+        }
+
+
         // Process additional options if we have any
         if ( env )
         {
@@ -662,10 +728,13 @@ long wxExecute(char **argv, int flags, wxProcess *process,
                 // it might not be the best idea.
                 wxLogSysError(_("Failed to set up non-blocking pipe, "
                                 "the program might hang."));
+#if wxUSE_LOG
+                wxLog::FlushActive();
+#endif
             }
 
             wxOutputStream *inStream =
-                new wxFileOutputStream(pipeIn.Detach(wxPipe::Write));
+                new wxPipeOutputStream(pipeIn.Detach(wxPipe::Write));
 
             const int fdOut = pipeOut.Detach(wxPipe::Read);
             wxPipeInputStream *outStream = new wxPipeInputStream(fdOut);