예제 #1
0
 /// <summary>Gets the wait state for this Process object.</summary>
 private ProcessWaitState GetWaitState()
 {
     if (_waitStateHolder == null)
     {
         EnsureState(State.HaveId);
         _waitStateHolder = new ProcessWaitState.Holder(_processId);
     }
     return(_waitStateHolder._state);
 }
예제 #2
0
 protected override void Dispose(bool explicitDisposing)
 {
     if (explicitDisposing)
     {
         if (_waitStateHolder != null)
         {
             _waitStateHolder.Dispose();
             _waitStateHolder = null;
         }
     }
     base.Dispose(explicitDisposing);
 }
예제 #3
0
 protected override void Dispose(bool explicitDisposing)
 {
     if (explicitDisposing)
     {
         if (_waitStateHolder != null)
         {
             _waitStateHolder.Dispose();
             _waitStateHolder = null;
         }
     }
     base.Dispose(explicitDisposing);
 }
예제 #4
0
 protected override void Dispose(bool explicitDisposing)
 {
     // ProcessWaitState will dispose the handle
     this.SafeWaitHandle = null;
     if (explicitDisposing)
     {
         if (_waitStateHolder != null)
         {
             _waitStateHolder.Dispose();
             _waitStateHolder = null;
         }
     }
     base.Dispose(explicitDisposing);
 }
예제 #5
0
        internal ProcessWaitHandle(SafeProcessHandle processHandle)
        {
            // Get the process ID from the process handle.  The handle is just a facade that wraps
            // the process ID, and closing the handle won't affect the process or its ID at all.
            // So we can grab it, and it's not "dangerous".
            int processId = (int)processHandle.DangerousGetHandle();

            // Create a wait state holder for this process ID.  This gives us access to the shared
            // wait state associated with this process.
            _waitStateHolder = new ProcessWaitState.Holder(processId);

            // Get the wait state's event, and use that event's safe wait handle
            // in place of ours.  This will let code register for completion notifications
            // on this ProcessWaitHandle and be notified when the wait state's handle completes.
            ManualResetEvent mre = _waitStateHolder._state.EnsureExitedEvent();
            this.SetSafeWaitHandle(mre.GetSafeWaitHandle());
        }
예제 #6
0
        internal ProcessWaitHandle(SafeProcessHandle processHandle)
        {
            // Get the process ID from the process handle.  The handle is just a facade that wraps
            // the process ID, and closing the handle won't affect the process or its ID at all.
            // So we can grab it, and it's not "dangerous".
            int processId = (int)processHandle.DangerousGetHandle();

            // Create a wait state holder for this process ID.  This gives us access to the shared
            // wait state associated with this process.
            _waitStateHolder = new ProcessWaitState.Holder(processId);

            // Get the wait state's event, and use that event's safe wait handle
            // in place of ours.  This will let code register for completion notifications
            // on this ProcessWaitHandle and be notified when the wait state's handle completes.
            ManualResetEvent mre = _waitStateHolder._state.EnsureExitedEvent();

            this.SetSafeWaitHandle(mre.GetSafeWaitHandle());
        }
예제 #7
0
 /// <summary>Gets the wait state for this Process object.</summary>
 private ProcessWaitState GetWaitState()
 {
     if (_waitStateHolder == null)
     {
         EnsureState(State.HaveId);
         _waitStateHolder = new ProcessWaitState.Holder(_processId);
     }
     return _waitStateHolder._state;
 }
예제 #8
0
        private bool ForkAndExecProcess(
            ProcessStartInfo startInfo, string?resolvedFilename, string[] argv,
            string[] envp, string?cwd, bool setCredentials, uint userId,
            uint groupId, uint[]?groups,
            out int stdinFd, out int stdoutFd, out int stderrFd,
            bool usesTerminal, bool throwOnNoExec = true)
        {
            if (string.IsNullOrEmpty(resolvedFilename))
            {
                Interop.ErrorInfo errno = Interop.Error.ENOENT.Info();
                throw CreateExceptionForErrorStartingProcess(errno.GetErrorMessage(), errno.RawErrno, startInfo.FileName, cwd);
            }

            // Lock to avoid races with OnSigChild
            // By using a ReaderWriterLock we allow multiple processes to start concurrently.
            s_processStartLock.EnterReadLock();
            try
            {
                if (usesTerminal)
                {
                    ConfigureTerminalForChildProcesses(1);
                }

                int childPid;

                // Invoke the shim fork/execve routine.  It will create pipes for all requested
                // redirects, fork a child process, map the pipe ends onto the appropriate stdin/stdout/stderr
                // descriptors, and execve to execute the requested process.  The shim implementation
                // is used to fork/execve as executing managed code in a forked process is not safe (only
                // the calling thread will transfer, thread IDs aren't stable across the fork, etc.)
                int errno = Interop.Sys.ForkAndExecProcess(
                    resolvedFilename, argv, envp, cwd,
                    startInfo.RedirectStandardInput, startInfo.RedirectStandardOutput, startInfo.RedirectStandardError,
                    setCredentials, userId, groupId, groups,
                    out childPid, out stdinFd, out stdoutFd, out stderrFd);

                if (errno == 0)
                {
                    // Ensure we'll reap this process.
                    // note: SetProcessId will set this if we don't set it first.
                    _waitStateHolder = new ProcessWaitState.Holder(childPid, isNewChild: true, usesTerminal);

                    // Store the child's information into this Process object.
                    Debug.Assert(childPid >= 0);
                    SetProcessId(childPid);
                    SetProcessHandle(new SafeProcessHandle(_processId, GetSafeWaitHandle()));

                    return(true);
                }
                else
                {
                    if (!throwOnNoExec &&
                        new Interop.ErrorInfo(errno).Error == Interop.Error.ENOEXEC)
                    {
                        return(false);
                    }

                    throw CreateExceptionForErrorStartingProcess(new Interop.ErrorInfo(errno).GetErrorMessage(), errno, resolvedFilename, cwd);
                }
            }
            finally
            {
                s_processStartLock.ExitReadLock();

                if (_waitStateHolder == null && usesTerminal)
                {
                    // We failed to launch a child that could use the terminal.
                    s_processStartLock.EnterWriteLock();
                    ConfigureTerminalForChildProcesses(-1);
                    s_processStartLock.ExitWriteLock();
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Starts the process using the supplied start info.
        /// With UseShellExecute option, we'll try the shell tools to launch it(e.g. "open fileName")
        /// </summary>
        /// <param name="startInfo">The start info with which to start the process.</param>
        private bool StartCore(ProcessStartInfo startInfo)
        {
            EnsureSigChildHandler();

            string filename;

            string[] argv;

            if (startInfo.UseShellExecute)
            {
                if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError)
                {
                    throw new InvalidOperationException(SR.CantRedirectStreams);
                }
            }

            int childPid, stdinFd, stdoutFd, stderrFd;

            string[] envp = CreateEnvp(startInfo);
            string   cwd  = !string.IsNullOrWhiteSpace(startInfo.WorkingDirectory) ? startInfo.WorkingDirectory : null;

            if (startInfo.UseShellExecute)
            {
                // use default program to open file/url
                filename = GetPathToOpenFile();
                argv     = ParseArgv(startInfo, filename);
            }
            else
            {
                filename = ResolvePath(startInfo.FileName);
                argv     = ParseArgv(startInfo);
                if (Directory.Exists(filename))
                {
                    throw new Win32Exception(SR.DirectoryNotValidAsInput);
                }
            }

            if (string.IsNullOrEmpty(filename))
            {
                throw new Win32Exception(Interop.Error.ENOENT.Info().RawErrno);
            }

            bool setCredentials = !string.IsNullOrEmpty(startInfo.UserName);
            uint userId         = 0;
            uint groupId        = 0;

            if (setCredentials)
            {
                (userId, groupId) = GetUserAndGroupIds(startInfo);
            }

            // Lock to avoid races with OnSigChild
            // By using a ReaderWriterLock we allow multiple processes to start concurrently.
            s_processStartLock.EnterReadLock();
            try
            {
                // Invoke the shim fork/execve routine.  It will create pipes for all requested
                // redirects, fork a child process, map the pipe ends onto the appropriate stdin/stdout/stderr
                // descriptors, and execve to execute the requested process.  The shim implementation
                // is used to fork/execve as executing managed code in a forked process is not safe (only
                // the calling thread will transfer, thread IDs aren't stable across the fork, etc.)
                Interop.Sys.ForkAndExecProcess(
                    filename, argv, envp, cwd,
                    startInfo.RedirectStandardInput, startInfo.RedirectStandardOutput, startInfo.RedirectStandardError,
                    setCredentials, userId, groupId,
                    out childPid,
                    out stdinFd, out stdoutFd, out stderrFd);

                // Ensure we'll reap this process.
                // note: SetProcessId will set this if we don't set it first.
                _waitStateHolder = new ProcessWaitState.Holder(childPid, isNewChild: true);

                // Store the child's information into this Process object.
                Debug.Assert(childPid >= 0);
                SetProcessId(childPid);
                SetProcessHandle(new SafeProcessHandle(childPid));
            }
            finally
            {
                s_processStartLock.ExitReadLock();
            }

            // Configure the parent's ends of the redirection streams.
            // We use UTF8 encoding without BOM by-default(instead of Console encoding as on Windows)
            // as there is no good way to get this information from the native layer
            // and we do not want to take dependency on Console contract.
            if (startInfo.RedirectStandardInput)
            {
                Debug.Assert(stdinFd >= 0);
                _standardInput = new StreamWriter(OpenStream(stdinFd, FileAccess.Write),
                                                  startInfo.StandardInputEncoding ?? s_utf8NoBom, StreamBufferSize)
                {
                    AutoFlush = true
                };
            }
            if (startInfo.RedirectStandardOutput)
            {
                Debug.Assert(stdoutFd >= 0);
                _standardOutput = new StreamReader(OpenStream(stdoutFd, FileAccess.Read),
                                                   startInfo.StandardOutputEncoding ?? s_utf8NoBom, true, StreamBufferSize);
            }
            if (startInfo.RedirectStandardError)
            {
                Debug.Assert(stderrFd >= 0);
                _standardError = new StreamReader(OpenStream(stderrFd, FileAccess.Read),
                                                  startInfo.StandardErrorEncoding ?? s_utf8NoBom, true, StreamBufferSize);
            }

            return(true);
        }