Beispiel #1
0
		/// <summary>
		/// Creates a StreamWriter which will be appended to
		/// </summary>
		/// <returns>
		/// a StreamWriter to a file that was opened with the append flag
		/// </returns>
		/// <param name='filename'>
		/// the name of the file
		/// </param>
		public static StreamWriter CreateUnixAppendStreamWriter(string filename)
		{
			OpenFlags flags = OpenFlags.O_WRONLY | OpenFlags.O_LARGEFILE | OpenFlags.O_APPEND;
			int fd = Syscall.open(filename, flags);
			UnixStream fs = new UnixStream(fd);
			return new StreamWriter(fs);
		}
Beispiel #2
0
    static void Main()
    {
        var pty = PseudoTerminal.Open (null,
                           "/bin/bash",
                           new string [] { "/bin/bash" },
                           "/tmp",
                           80, 24, false, false, false);

        var x = Console.ForegroundColor;

        //
        // OK, this is a disgusting hack (2 threads instead of non-blocking
        // io) but it is merely a test driver
        //
        var us = new UnixStream (pty.FileDescriptor, false);
        var sw = new StreamWriter (us);
        new Thread (delegate (object p) {
            byte [] b = new byte [1024];
            int n;

            while ((n = us.Read (b, 0, b.Length)) != 0){
                for (int i = 0; i < n; i++)
                    Console.Write ((char) b [i]);
            }
        }).Start ();

        while (true){
            ConsoleKeyInfo k = Console.ReadKey (true);
            sw.Write (k.KeyChar);
            sw.Flush ();
        }
    }
Beispiel #3
0
        public bool AquireLock(int timeout)
        {
            bool success = false;

            if (Monitor.TryEnter(syncRoot, timeout))
            {
                if (this.stream == null)
                {
                    int fd = Syscall.open(PortFilePath, OpenFlags.O_RDWR | OpenFlags.O_EXCL);

                    if (fd == -1)
                    {
                        var e = new Win32Exception(Marshal.GetLastWin32Error());
                        Debug.WriteLine(string.Format("Error opening {0}: {1}", PortFilePath, e.Message));

                        Monitor.Exit(syncRoot);
                    }
                    else
                    {
                        this.stream = new UnixStream(fd);
                        success = true;
                    }
                }
            }

            return success;
        }
Beispiel #4
0
 public Stream OpenStream(FileMode fileMode)
 {
     if (Utilities.ConfigManager.GetValue("NO_FILEOPTIMIZATION") != null)
     {
         return(new FileStream(fileName, FileMode.Open));
     }
     if (fileMode == FileMode.Open)
     {
         fd = Syscall.open(fileName, OpenFlags.O_RDONLY);
     }
     else if (fileMode == FileMode.CreateNew)
     {
         fd = Syscall.open(fileName, OpenFlags.O_CREAT);
     }
     if ((int)fd < 0)
     {
         Logger.Append(Severity.INFO, "Unable to open file with optimized parameters. Falling back to regular open. (Return code was " + fd + ")");
         return(new FileStream(fileName, FileMode.Open));
     }
     else
     {
         UnixStream us = new Mono.Unix.UnixStream(fd);
         return((Stream)us);
     }
 }
		public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern, long offset, long len)
		{
			if (stream == null)
				throw new ArgumentNullException ("stream");
			int r = Native.Syscall.posix_fadvise (stream.Handle, offset, len,
				(Native.PosixFadviseAdvice) pattern);
			UnixMarshal.ThrowExceptionForLastErrorIf (r);
		}
Beispiel #6
0
        public CameraFile(UnixStream file)
        {
            IntPtr native;

            Error.CheckError (gp_file_new_from_fd (out native, file.Handle));

            this.handle = new HandleRef (this, native);
        }
Beispiel #7
0
        public static void AdviseFileAccessPattern(UnixStream stream, FileAccessPattern pattern, long offset, long len)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            int num = Syscall.posix_fadvise(stream.Handle, offset, len, (PosixFadviseAdvice)pattern);

            UnixMarshal.ThrowExceptionForLastErrorIf(num);
        }
Beispiel #8
0
        public UsbDevice(string address)
        {
            _fd = Syscall.open( address, OpenFlags.O_NONBLOCK | OpenFlags.O_RDWR );

            Pollfd poll = new Pollfd();
            poll.fd = _fd;
            poll.events = PollEvents.POLLIN | PollEvents.POLLRDNORM;
            _poll = new [] { poll };

            _stream = new UnixStream(_fd);
            _lock = new object();
        }
Beispiel #9
0
        private void Init()
        {
            if (name != null)
            {
                OpenPty(name);
                Name = name;
            }
            else
            {
                Name = OpenPty();
            }

            stream = new UnixStream(master, true);
        }
Beispiel #10
0
 public void ReleaseLock()
 {
     try
     {
         if (this.stream != null)
         {
             this.stream.Dispose();
             this.stream = null;
         }
     }
     finally
     {
         Monitor.Exit(syncRoot);
     }
 }
Beispiel #11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RlangPipe"/> class.
        /// </summary>
        public RlangPipe()
        {
#if __MonoCS__
// XXX what if running mono on windows?
            ureadStream = new UnixStream(int.Parse(Environment.GetEnvironmentVariable("R2PIPE_IN")));
            reader = new StreamReader(ureadStream);
           
            uwriteStream = new UnixStream(int.Parse(Environment.GetEnvironmentVariable("R2PIPE_OUT")));
            writer = new StreamWriter(uwriteStream);
#else
            // Using named pipes on windows. I like this.
            inclient = new NamedPipeClientStream("R2PIPE_PATH");
            reader = new StreamReader(inclient);
            writer = new StreamWriter(inclient);
#endif
        }
Beispiel #12
0
	public bool Open ()
	{
		_fd = Syscall.open (_name, OpenFlags.O_RDWR);	// | OpenFlags.O_NONBLOCK | OpenFlags.O_NOCTTY);
		if (_fd != -1)
		{
			ForceSetBaudRate ();
			_ss = new UnixStream (_fd);
			var fndelay = (int)OpenFlags.O_NONBLOCK;
			Syscall.fcntl(_ss.Handle, FcntlCommand.F_SETFL, fndelay);
			if (_readThread != null)
			{
				_readThread.Start();
			}
			Clear();
			return true;
		}
		return false;
	}
Beispiel #13
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RlangPipe"/> class.
        /// </summary>
        public RlangPipe()
        {
#if __MonoCS__
            if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) {

            ureadStream = new UnixStream(int.Parse(Environment.GetEnvironmentVariable("R2PIPE_IN")));
            reader = new StreamReader(ureadStream);
           
            uwriteStream = new UnixStream(int.Parse(Environment.GetEnvironmentVariable("R2PIPE_OUT")));
            writer = new StreamWriter(uwriteStream);

            } else {
#endif
            // Using named pipes on windows. I like this.
            inclient = new NamedPipeClientStream("R2PIPE_PATH");
            reader = new StreamReader(inclient);
            writer = new StreamWriter(inclient);
#if __MonoCS__
            }
#endif
        }
 /// <summary>
 /// Closes this instance.
 /// </summary>
 public override void Close()
 {
     if (this.file == null)
         return;
     InternalLogger.Trace("Closing '{0}'", FileName);
     this.file.Close();
     this.file = null;
 }
Beispiel #15
0
 public void SendTo(UnixStream output)
 {
     SendTo(output, (ulong)output.Length);
 }
		public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern)
		{
			AdviseFileAccessPattern (stream, pattern, 0, 0);
		}
		public UnixPipes (UnixStream reading, UnixStream writing)
		{
			Reading = reading;
			Writing = writing;
		}
		public static void AdviseOnceAccess (UnixStream stream)
		{
			AdviseOnceAccess (stream.Handle);
		}
 public static void AdviseFileAccessPattern(UnixStream stream, FileAccessPattern pattern)
 {
     AdviseFileAccessPattern(stream, pattern, 0, 0);
 }
		public static void AdviseNormalAccess (UnixStream stream)
		{
			AdviseNormalAccess (stream.Handle);
		}
 /// <summary>
 /// Closes this instance.
 /// </summary>
 public override void Close()
 {
     if (this.file == null)
         return;
     InternalLogger.Trace("Closing '{0}'", FileName);
     try
     {
         this.file.Close();
     }
     catch (Exception ex)
     {
         // Swallow exception as the file-stream now is in final state (broken instead of closed)
         InternalLogger.Warn(ex, "Failed to close file '{0}'", FileName);
         System.Threading.Thread.Sleep(1);   // Artificial delay to avoid hammering a bad file location
     }
     finally
     {
         this.file = null;
     }
 }
Beispiel #22
0
 public UnixPipes(UnixStream reading, UnixStream writing)
 {
     Reading = reading;
     Writing = writing;
 }
Beispiel #23
0
 public void SendTo(UnixStream output)
 {
     SendTo (output, (ulong)output.Length);
 }
Beispiel #24
0
	public void Close ()
	{
		if (_ss != null)
		{
			//Console.WriteLine("SerialComm::Close port = " + _name);
			_stopReadThread = true;
			System.Threading.Thread.Sleep(100);
			_ss.Close ();
			_ss = null;
			Syscall.close(_fd);
			_fd = 0;
		}
	}
Beispiel #25
0
 public static void AdviseFileAccessPattern(UnixStream stream, FileAccessPattern pattern)
 {
     FileHandleOperations.AdviseFileAccessPattern(stream, pattern, (long)0, (long)0);
 }
Beispiel #26
0
        private void Init()
        {
            active = false;
            // if there is no /dev/net/tun, run in a "dummy" mode
            if(!File.Exists("/dev/net/tun"))
            {
                this.Log(LogLevel.Warning, "No TUN device found, running in dummy mode.");
                return;
            }

            IntPtr devName;
            if(deviceName != "")
            {
                // non-anonymous mapping
                devName = Marshal.StringToHGlobalAnsi(deviceName);
            }
            else
            {
                devName = Marshal.AllocHGlobal(DeviceNameBufferSize);
                Marshal.WriteByte(devName, 0); // null termination
            }
            try
            {
                tapFileDescriptor = LibC.OpenTAP(devName, persistent);
                if(tapFileDescriptor < 0)
                {
                    var process = new Process();
                    var output = string.Empty;
                    process.StartInfo.FileName = "mono";
                    process.StartInfo.Arguments = string.Format("{0} {1} true", DynamicModuleSpawner.GetTAPHelper(), deviceName);

                    try
                    {
                        SudoTools.EnsureSudoProcess(process, "TAP creator");
                    }
                    catch(Exception ex)
                    {
                        throw new RecoverableException("Process elevation failed: " + ex.Message);
                    }

                    process.EnableRaisingEvents = true;
                    process.StartInfo.CreateNoWindow = false;
                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.RedirectStandardError = true;
                    process.StartInfo.RedirectStandardOutput = true;

                    var started = process.Start();
                    if(started)
                    {
                        output = process.StandardError.ReadToEnd();
                        process.WaitForExit();
                    }
                    if(!started || process.ExitCode != 0)
                    {
                        this.Log(LogLevel.Warning, "Could not create TUN/TAP interface, running in dummy mode.");
                        this.Log(LogLevel.Debug, "Error {0} while opening tun device '{1}': {2}", process.ExitCode, deviceName, output);
                        return;
                    }
                    Init();
                    return;
                }
                stream = new UnixStream(tapFileDescriptor, true);
                InterfaceName = Marshal.PtrToStringAnsi(devName);
                this.Log(LogLevel.Info,
                    "Opened interface {0}.", InterfaceName);
            }
            finally
            {
                Marshal.FreeHGlobal(devName);
            }
            active = true;
        }
Beispiel #27
0
 public void SendTo(UnixStream output, ulong count)
 {
     SendTo(output.Handle, count);
 }
        public UnixMultiProcessFileAppender(string fileName, ICreateFileParameters parameters) : base(fileName, parameters)
        {
            int fd = Syscall.open(fileName, OpenFlags.O_CREAT | OpenFlags.O_WRONLY | OpenFlags.O_APPEND, (FilePermissions)(6 | (6 << 3) | (6 << 6)));
            if (fd == -1)
            {
                if (Stdlib.GetLastError() == Errno.ENOENT && parameters.CreateDirs)
                {
                    string dirName = Path.GetDirectoryName(fileName);
                    if (!Directory.Exists(dirName) && parameters.CreateDirs)
                        Directory.CreateDirectory(dirName);
                    
                    fd = Syscall.open(fileName, OpenFlags.O_CREAT | OpenFlags.O_WRONLY | OpenFlags.O_APPEND, (FilePermissions)(6 | (6 << 3) | (6 << 6)));
                }
            }
            if (fd == -1)
                UnixMarshal.ThrowExceptionForLastError();

            try
            {
                this.file = new UnixStream(fd, true);
            }
            catch
            {
                Syscall.close(fd);
                throw;
            }
        }
Beispiel #29
0
        public ProcessInfo Start(ProcessStartInfo psi)
        {
            if (!(psi.User is UnixUserIdentifier) && psi.User != null)
            {
                throw new InvalidOperationException();
            }

            var user_identifier = (UnixUserIdentifier)(psi.User ?? new UnixUserIdentifier((int)Syscall.getuid(), (int)Syscall.getgid()));
            var arguments = new string[] { Path.GetFileName(psi.Path) }.Concat(psi.Arguments).Concat(new string[] { null }).ToArray();

            // instead of these, we just open /dev/null for now
            // this might change when we get better logging facilities
            //Syscall.pipe(out int stdout_read, out int stdout_write); // used to communicate stdout back to parent
            //Syscall.pipe(out int stderr_read, out int stderr_write); // used to communicate stderr back to parent
            int stdin_read  = Syscall.open("/dev/null", OpenFlags.O_RDWR);
            int stdin_write = Syscall.open("/dev/null", OpenFlags.O_RDWR);

            int stdout_read  = Syscall.open("/dev/null", OpenFlags.O_RDWR);
            int stdout_write = Syscall.open("/dev/null", OpenFlags.O_RDWR);

            int stderr_read  = Syscall.open("/dev/null", OpenFlags.O_RDWR);
            int stderr_write = Syscall.open("/dev/null", OpenFlags.O_RDWR);

            Syscall.pipe(out int control_read, out int control_write); // used to communicate errors during process creation back to parent

            var stdout_w_ptr  = new IntPtr(stdout_write);
            var stderr_w_ptr  = new IntPtr(stderr_write);
            var control_w_ptr = new IntPtr(control_write);

#pragma warning disable CS0618 // Type or member is obsolete
            int fork_ret = Mono.Posix.Syscall.fork();
#pragma warning restore CS0618 // Type or member is obsolete

            if (fork_ret == 0) // child process
            {
                int error = 0;

                Syscall.close(stdout_read);
                Syscall.close(stderr_read);
                Syscall.close(control_read);

                var control_w_stream = new UnixStream(control_write);
                var write_to_control = (Action <string>)(_ => control_w_stream.Write(Encoding.ASCII.GetBytes(_), 0, _.Length));

                write_to_control("starting\n");

                while (Syscall.dup2(stdout_write, 1) == -1)
                {
                    if (Syscall.GetLastError() == Errno.EINTR)
                    {
                        continue;
                    }
                    else
                    {
                        write_to_control($"dup2-stdout:{(int)Syscall.GetLastError()}\n");
                        Syscall.exit(1);
                    }
                }

                while (Syscall.dup2(stderr_write, 2) == -1)
                {
                    if (Syscall.GetLastError() == Errno.EINTR)
                    {
                        continue;
                    }
                    else
                    {
                        write_to_control($"dup2-stderr:{(int)Syscall.GetLastError()}\n");
                        Syscall.exit(1);
                    }
                }

                if ((error = Syscall.setgid(user_identifier.GroupId)) != 0)
                {
                    write_to_control($"setgid:{(int)Syscall.GetLastError()}\n");
                    Syscall.exit(1);
                }

                if ((error = Syscall.setuid(user_identifier.UserId)) != 0)
                {
                    write_to_control($"setuid:{(int)Syscall.GetLastError()}\n");
                    Syscall.exit(1);
                }

                if (psi.WorkingDirectory != "")
                {
                    Syscall.chdir(psi.WorkingDirectory);
                }

                if ((error = Syscall.execv(psi.Path, arguments)) != 0)
                {
                    write_to_control($"execv:{(int)Syscall.GetLastError()}\n");
                    Syscall.exit(1);
                }
            }

            if (fork_ret < 0)
            {
                throw new InvalidOperationException($"fork() returned {fork_ret}, errno: {Syscall.GetLastError()}");
            }

            Syscall.close(stdout_write);
            Syscall.close(stderr_write);
            Syscall.close(control_write);

            var stdout_stream  = new Mono.Unix.UnixStream(stdout_read);
            var stderr_stream  = new Mono.Unix.UnixStream(stderr_read);
            var control_stream = new Mono.Unix.UnixStream(control_read);

            var control_sr = new StreamReader(control_stream);

            var starting_line = control_sr.ReadLine();
            if (starting_line != "starting")
            {
                throw new Exception($"Expected starting message from control pipe, received {starting_line}");
            }

            Processes.Add(fork_ret);
            return(new ProcessInfo(System.Diagnostics.Process.GetProcessById(fork_ret)));
        }
Beispiel #30
0
		private UnixStream OpenSocket(uint? mtu)
		{
			/*
			sockaddr_ll sa = new sockaddr_ll();
			sa.sll_family = AF_CAN;
			sa.sll_protocol = CAN_RAW;
			sa.sll_ifindex = if_nametoindex(Interface);
			*/
			sockaddr_can addr = new sockaddr_can();
			addr.can_family = AF_CAN;

			int fd = -1, ret = -1;

			try
			{
				fd = socket(AF_CAN, SOCK_RAW, CAN_RAW);
				UnixMarshal.ThrowExceptionForLastErrorIf(fd);

				ifreq ifr = new ifreq(Interface);
				/* Doesn't seem to work
				ret = ioctl(fd, SIOCGIFINDEX, ref ifr);
				UnixMarshal.ThrowExceptionForLastErrorIf(ret);
				*/
				addr.can_ifindex = if_nametoindex(Interface);

				if (addr.can_ifindex == 0)
					throw new ArgumentException("The interface \"" + Interface + "\" is not valid.");

				ret = bind(fd, ref addr, Marshal.SizeOf(addr));
				UnixMarshal.ThrowExceptionForLastErrorIf(ret);

/*
				if (orig_mtu == 0)
				{
					ret = ioctl(fd, SIOCGIFMTU, ref ifr);
					UnixMarshal.ThrowExceptionForLastErrorIf(ret);
					orig_mtu = ifr.ifru_mtu;
				}

				if (mtu != null)
				{
					ifr.ifru_mtu = mtu.Value;
					//ret = ioctl(fd, SIOCSIFMTU, ref ifr);
					ret = ioctl(fd, SIOCGIFMTU, ref ifr);
					UnixMarshal.ThrowExceptionForLastErrorIf(ret);
				}

*/
				ret = ioctl(fd, SIOCGIFMTU, ref ifr);
				UnixMarshal.ThrowExceptionForLastErrorIf(ret);
/*
				if (mtu != null && ifr.ifru_mtu != mtu.Value)
					throw new PeachException("MTU change did not take effect.");
*/

				_mtu = ifr.ifru_mtu;
/*

				if (ifr.ifru_mtu > (MaxMTU - EthernetHeaderSize))
					_bufferSize = (int)MaxMTU;
				else
					_bufferSize = (int)(ifr.ifru_mtu + EthernetHeaderSize);
*/
				_bufferSize = CAN_MTU;

				var stream = new UnixStream(fd);

				fd = -1;

				return stream;
			}
			catch (InvalidOperationException ex)
			{
				if (ex.InnerException != null)
				{
					var inner = ex.InnerException as UnixIOException;
					if (inner != null && inner.ErrorCode == Errno.EPERM)
						throw new PeachException("Access denied when opening the raw ethernet publisher.  Ensure the user has the appropriate permissions.", ex);
				}

				throw;
			}
			finally
			{
				if (fd != -1)
					Syscall.close(fd);
			}
		}
 public override void Close()
 {
     if (_file == null)
         return;
     InternalLogger.Trace("Closing '{0}'", FileName);
     _file.Close();
     _file = null;
     FileTouched();
 }
Beispiel #32
0
		protected override void OnOpen()
		{
			System.Diagnostics.Debug.Assert(_socket == null);

			_socket = OpenSocket(null);

			System.Diagnostics.Debug.Assert(_socket != null);
			System.Diagnostics.Debug.Assert(_bufferSize > 0);

			Logger.Debug("Opened interface \"{0}\" with MTU {1}.", Interface, _bufferSize);
		}
Beispiel #33
0
		public void Start ()
		{
			if (args == null)
				throw new ArgumentException ("Arguments cannot be empty");

			IntPtr error;

			if (args [args.Length - 1] != null) {
				// Need to null-terminate the array.
				string[] tmp_args = new string [args.Length + 1];
				Array.Copy (args, tmp_args, args.Length);
				args = tmp_args;
			}

			// If LANG=C needs to be specified, then
			// copy the parents environment variable
			// and appand LANG=C to it.
			// Make sure to null-terminate the env array.
			string[] env = null;
			if (use_lang_c) {
				IDictionary env_dict = Environment.GetEnvironmentVariables ();
				env = new string [env_dict.Count + 2];
				int count = 0;
				foreach (DictionaryEntry entry in env_dict)
					if ((string) entry.Key != "LANG")
						env [count ++] = String.Concat (entry.Key, "=", entry.Value);

				env [count ++] = "LANG=C";
				env [count] = null;
			}

			IntPtr in_ptr = IntPtr.Zero, out_ptr = IntPtr.Zero, err_ptr = IntPtr.Zero;

			try {
				if (RedirectStandardInput)
					in_ptr = Marshal.AllocHGlobal (IntPtr.Size);
				
				if (RedirectStandardOutput)
					out_ptr = Marshal.AllocHGlobal (IntPtr.Size);
				
				if (RedirectStandardError)
					err_ptr = Marshal.AllocHGlobal (IntPtr.Size);

				spawn_async_with_pipes_and_limits (args,
								   env,
								   cpu_limit,
								   mem_limit,
								   out pid,
								   in_ptr,
								   out_ptr,
								   err_ptr,
								   out error);

				if (error != IntPtr.Zero)
					throw new SafeProcessException (new GException (error));

				if (in_ptr != IntPtr.Zero) {
					IntPtr v = Marshal.ReadIntPtr (in_ptr);
					stdin_stream = new UnixStream ((int) v);
				}

				if (out_ptr != IntPtr.Zero) {
					IntPtr v = Marshal.ReadIntPtr (out_ptr);
					stdout_stream = new UnixStream ((int) v);
				}

				if (err_ptr != IntPtr.Zero) {
					IntPtr v = Marshal.ReadIntPtr (err_ptr);
					stderr_stream = new UnixStream ((int) v);
				}

			} finally {
				if (in_ptr != IntPtr.Zero)
					Marshal.FreeHGlobal (in_ptr);

				if (out_ptr != IntPtr.Zero)
					Marshal.FreeHGlobal (out_ptr);

				if (err_ptr != IntPtr.Zero)
					Marshal.FreeHGlobal (err_ptr);
			}
		}
		public static void AdviseSequentialAccess (UnixStream stream)
		{
			AdviseSequentialAccess (stream.Handle);
		}
Beispiel #35
0
 public UnixPipes(UnixStream reading, UnixStream writing)
 {
     this.Reading = reading;
     this.Writing = writing;
 }
		public static void AdviseOnceAccess (UnixStream stream, long offset, long len)
		{
			AdviseOnceAccess (stream.Handle, offset, len);
		}
Beispiel #37
0
		protected override void OnClose()
		{
			//this never happens....
			System.Diagnostics.Debug.Assert(_socket != null);
			if (orig_mtu != 0)
				OpenSocket(orig_mtu);

			_socket.Close();
			_socket = null;
		}
Beispiel #38
0
 public void SendTo(UnixStream output, ulong count)
 {
     SendTo (output.Handle, count);
 }
Beispiel #39
0
        public void TestSpawn()
        {
            Spawn spawn;
            UnixReader reader;
            string[] argv = { "/bin/cat" };
            UnixStream stream;
            StreamWriter writer;
            int stdin, stdout, stderr;

            spawn = new Spawn ();

            spawn.SpawnAsyncWithPipes (null,
                           argv,
                           null,
                           GSpawnFlags.G_SPAWN_DO_NOT_REAP_CHILD,
                           null,
                           out pid,
                           out stdin, out stdout, out stderr);

            pids_matched = false;
            exit_status_is_good = false;
            spawn.ChildWatchAdd (pid, child_watch_cb);

            stream = new UnixStream (stdin, true);
            writer = new StreamWriter (stream);

            writer.Write ("Hello, world!");
            writer.Close (); /* this will close the stdin fd */

            reader = new UnixReader (stdout);
            reader.DataAvailable += data_available_cb;
            reader.Closed += closed_cb;

            string_equal = false;
            closed = false;

            loop = new MainLoop ();
            loop.Run ();

            Assert.IsTrue (string_equal, "Read the correct string");
            Assert.IsTrue (closed, "UnixReader got closed");
            Assert.IsTrue (pids_matched, "PID of child process");
            Assert.IsTrue (exit_status_is_good, "Exit status of child process");
        }