1 // glib/Spawn.cs : Spawn g_spawn API wrapper 2 // 3 // Author: Mike Kestner <mkestner@novell.com> 4 // 5 // Copyright (c) 2007 Novell, Inc. 6 // 7 // This program is free software; you can redistribute it and/or 8 // modify it under the terms of version 2 of the Lesser GNU General 9 // Public License as published by the Free Software Foundation. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 // Lesser General Public License for more details. 15 // 16 // You should have received a copy of the GNU Lesser General Public 17 // License along with this program; if not, write to the 18 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 // Boston, MA 02111-1307, USA. 20 21 22 namespace GLib { 23 24 using System; 25 using System.Runtime.InteropServices; 26 27 public enum SpawnError { 28 Fork, 29 Read, 30 Chdir, 31 Acces, 32 Perm, 33 TooBig, 34 NoExec, 35 NameTooLong, 36 NoEnt, 37 NoMem, 38 NotDir, 39 Loop, 40 TxtBusy, 41 IO, 42 NFile, 43 MFile, 44 Inval, 45 IsDir, 46 LibBad, 47 Failed, 48 } 49 50 [Flags] 51 public enum SpawnFlags { 52 LeaveDescriptorsOpen = 1 << 0, 53 DoNotReapChild = 1 << 1, 54 SearchPath = 1 << 2, 55 StdoutToDevNull = 1 << 3, 56 StderrToDevNull = 1 << 4, 57 ChildInheritsStdin = 1 << 5, 58 FileAndArgvZero = 1 << 6, 59 } 60 SpawnChildSetupFunc()61 public delegate void SpawnChildSetupFunc (); 62 63 [UnmanagedFunctionPointer (CallingConvention.Cdecl)] SpawnChildSetupFuncNative(IntPtr gch)64 internal delegate void SpawnChildSetupFuncNative (IntPtr gch); 65 66 internal class SpawnChildSetupWrapper { 67 68 SpawnChildSetupFunc handler; 69 SpawnChildSetupWrapper(SpawnChildSetupFunc handler)70 public SpawnChildSetupWrapper (SpawnChildSetupFunc handler) 71 { 72 if (handler == null) 73 return; 74 75 this.handler = handler; 76 Data = (IntPtr) GCHandle.Alloc (this); 77 NativeCallback = new SpawnChildSetupFuncNative (InvokeHandler); 78 } 79 80 public IntPtr Data; 81 public SpawnChildSetupFuncNative NativeCallback; 82 InvokeHandler(IntPtr data)83 static void InvokeHandler (IntPtr data) 84 { 85 if (data == IntPtr.Zero) 86 return; 87 GCHandle gch = (GCHandle) data; 88 (gch.Target as SpawnChildSetupWrapper).handler (); 89 gch.Free (); 90 } 91 } 92 93 public class Process { 94 95 public const int IgnorePipe = Int32.MaxValue; 96 public const int RequestPipe = 0; 97 98 long pid; 99 Process(int pid)100 private Process (int pid) 101 { 102 this.pid = pid; 103 } 104 105 [DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)] g_spawn_close_pid(int pid)106 static extern void g_spawn_close_pid (int pid); 107 Close()108 public void Close () 109 { 110 g_spawn_close_pid ((int) pid); 111 } 112 113 [DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)] g_spawn_async(IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out int pid, out IntPtr error)114 static extern bool g_spawn_async (IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out int pid, out IntPtr error); 115 116 [DllImport (Global.GLibNativeDll)] g_spawn_async_utf8(IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out int pid, out IntPtr error)117 static extern bool g_spawn_async_utf8 (IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out int pid, out IntPtr error); 118 SpawnAsync(string working_directory, string[] argv, string[] envp, SpawnFlags flags, SpawnChildSetupFunc child_setup, out Process child_process)119 public static bool SpawnAsync (string working_directory, string[] argv, string[] envp, SpawnFlags flags, SpawnChildSetupFunc child_setup, out Process child_process) 120 { 121 int pid; 122 IntPtr error; 123 IntPtr native_dir = Marshaller.StringToPtrGStrdup (working_directory); 124 IntPtr[] native_argv = Marshaller.StringArrayToNullTermPointer (argv); 125 IntPtr[] native_envp = Marshaller.StringArrayToNullTermPointer (envp); 126 SpawnChildSetupWrapper wrapper = new SpawnChildSetupWrapper (child_setup); 127 bool result; 128 129 if (Global.IsWindowsPlatform) 130 result = g_spawn_async_utf8 (native_dir, native_argv, native_envp, (int) flags, wrapper.NativeCallback, wrapper.Data, out pid, out error); 131 else 132 result = g_spawn_async (native_dir, native_argv, native_envp, (int) flags, wrapper.NativeCallback, wrapper.Data, out pid, out error); 133 134 child_process = new Process (pid); 135 Marshaller.Free (native_dir); 136 Marshaller.Free (native_argv); 137 Marshaller.Free (native_envp); 138 if (error != IntPtr.Zero) throw new GLib.GException (error); 139 return result; 140 } 141 142 [DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)] g_spawn_async_with_pipes(IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out int pid, IntPtr stdin, IntPtr stdout, IntPtr stderr, out IntPtr error)143 static extern bool g_spawn_async_with_pipes (IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out int pid, IntPtr stdin, IntPtr stdout, IntPtr stderr, out IntPtr error); 144 145 [DllImport (Global.GLibNativeDll)] g_spawn_async_with_pipes_utf8(IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out int pid, IntPtr stdin, IntPtr stdout, IntPtr stderr, out IntPtr error)146 static extern bool g_spawn_async_with_pipes_utf8 (IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out int pid, IntPtr stdin, IntPtr stdout, IntPtr stderr, out IntPtr error); 147 SpawnAsyncWithPipes(string working_directory, string[] argv, string[] envp, SpawnFlags flags, SpawnChildSetupFunc child_setup, out Process child_process, ref int stdin, ref int stdout, ref int stderr)148 public static bool SpawnAsyncWithPipes (string working_directory, string[] argv, string[] envp, SpawnFlags flags, SpawnChildSetupFunc child_setup, out Process child_process, ref int stdin, ref int stdout, ref int stderr) 149 { 150 int pid; 151 IntPtr error; 152 IntPtr native_dir = Marshaller.StringToPtrGStrdup (working_directory); 153 IntPtr[] native_argv = Marshaller.StringArrayToNullTermPointer (argv); 154 IntPtr[] native_envp = Marshaller.StringArrayToNullTermPointer (envp); 155 SpawnChildSetupWrapper wrapper = new SpawnChildSetupWrapper (child_setup); 156 IntPtr in_ptr = stdin == IgnorePipe ? IntPtr.Zero : Marshal.AllocHGlobal (4); 157 IntPtr out_ptr = stdout == IgnorePipe ? IntPtr.Zero : Marshal.AllocHGlobal (4); 158 IntPtr err_ptr = stderr == IgnorePipe ? IntPtr.Zero : Marshal.AllocHGlobal (4); 159 bool result; 160 161 if (Global.IsWindowsPlatform) 162 result = g_spawn_async_with_pipes_utf8 (native_dir, native_argv, native_envp, (int) flags, wrapper.NativeCallback, wrapper.Data, out pid, in_ptr, out_ptr, err_ptr, out error); 163 else 164 result = g_spawn_async_with_pipes (native_dir, native_argv, native_envp, (int) flags, wrapper.NativeCallback, wrapper.Data, out pid, in_ptr, out_ptr, err_ptr, out error); 165 166 child_process = new Process (pid); 167 if (in_ptr != IntPtr.Zero) { 168 stdin = Marshal.ReadInt32 (in_ptr); 169 Marshal.FreeHGlobal (in_ptr); 170 } 171 if (out_ptr != IntPtr.Zero) { 172 stdout = Marshal.ReadInt32 (out_ptr); 173 Marshal.FreeHGlobal (out_ptr); 174 } 175 if (err_ptr != IntPtr.Zero) { 176 stderr = Marshal.ReadInt32 (err_ptr); 177 Marshal.FreeHGlobal (err_ptr); 178 } 179 Marshaller.Free (native_dir); 180 Marshaller.Free (native_argv); 181 Marshaller.Free (native_envp); 182 if (error != IntPtr.Zero) throw new GLib.GException (error); 183 return result; 184 } 185 186 [DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)] g_spawn_sync(IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out IntPtr stdout, out IntPtr stderr, out int exit_status, out IntPtr error)187 static extern bool g_spawn_sync (IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out IntPtr stdout, out IntPtr stderr, out int exit_status, out IntPtr error); 188 189 [DllImport (Global.GLibNativeDll)] g_spawn_sync_utf8(IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out IntPtr stdout, out IntPtr stderr, out int exit_status, out IntPtr error)190 static extern bool g_spawn_sync_utf8 (IntPtr dir, IntPtr[] argv, IntPtr[] envp, int flags, SpawnChildSetupFuncNative func, IntPtr data, out IntPtr stdout, out IntPtr stderr, out int exit_status, out IntPtr error); 191 SpawnSync(string working_directory, string[] argv, string[] envp, SpawnFlags flags, SpawnChildSetupFunc child_setup, out string stdout, out string stderr, out int exit_status)192 public static bool SpawnSync (string working_directory, string[] argv, string[] envp, SpawnFlags flags, SpawnChildSetupFunc child_setup, out string stdout, out string stderr, out int exit_status) 193 { 194 IntPtr native_stdout, native_stderr, error; 195 IntPtr native_dir = Marshaller.StringToPtrGStrdup (working_directory); 196 IntPtr[] native_argv = Marshaller.StringArrayToNullTermPointer (argv); 197 IntPtr[] native_envp = Marshaller.StringArrayToNullTermPointer (envp); 198 SpawnChildSetupWrapper wrapper = new SpawnChildSetupWrapper (child_setup); 199 bool result; 200 201 if (Global.IsWindowsPlatform) 202 result = g_spawn_sync (native_dir, native_argv, native_envp, (int) flags, wrapper.NativeCallback, wrapper.Data, out native_stdout, out native_stderr, out exit_status, out error); 203 else 204 result = g_spawn_sync (native_dir, native_argv, native_envp, (int) flags, wrapper.NativeCallback, wrapper.Data, out native_stdout, out native_stderr, out exit_status, out error); 205 206 Marshaller.Free (native_dir); 207 Marshaller.Free (native_argv); 208 Marshaller.Free (native_envp); 209 stdout = Marshaller.PtrToStringGFree (native_stdout); 210 stderr = Marshaller.PtrToStringGFree (native_stderr); 211 if (error != IntPtr.Zero) throw new GLib.GException (error); 212 return result; 213 } 214 215 [DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)] g_spawn_command_line_async(IntPtr cmdline, out IntPtr error)216 static extern bool g_spawn_command_line_async (IntPtr cmdline, out IntPtr error); 217 218 [DllImport (Global.GLibNativeDll)] g_spawn_command_line_async_utf8(IntPtr cmdline, out IntPtr error)219 static extern bool g_spawn_command_line_async_utf8 (IntPtr cmdline, out IntPtr error); 220 SpawnCommandLineAsync(string command_line)221 public static bool SpawnCommandLineAsync (string command_line) 222 { 223 IntPtr error; 224 IntPtr native_cmd = Marshaller.StringToPtrGStrdup (command_line); 225 bool result; 226 227 if (Global.IsWindowsPlatform) 228 result = g_spawn_command_line_async_utf8 (native_cmd, out error); 229 else 230 result = g_spawn_command_line_async (native_cmd, out error); 231 232 Marshaller.Free (native_cmd); 233 if (error != IntPtr.Zero) throw new GLib.GException (error); 234 return result; 235 } 236 237 [DllImport (Global.GLibNativeDll, CallingConvention = CallingConvention.Cdecl)] g_spawn_command_line_sync(IntPtr cmdline, out IntPtr stdout, out IntPtr stderr, out int exit_status, out IntPtr error)238 static extern bool g_spawn_command_line_sync (IntPtr cmdline, out IntPtr stdout, out IntPtr stderr, out int exit_status, out IntPtr error); 239 240 [DllImport (Global.GLibNativeDll)] g_spawn_command_line_sync_utf8(IntPtr cmdline, out IntPtr stdout, out IntPtr stderr, out int exit_status, out IntPtr error)241 static extern bool g_spawn_command_line_sync_utf8 (IntPtr cmdline, out IntPtr stdout, out IntPtr stderr, out int exit_status, out IntPtr error); 242 SpawnCommandLineSync(string command_line, out string stdout, out string stderr, out int exit_status)243 public static bool SpawnCommandLineSync (string command_line, out string stdout, out string stderr, out int exit_status) 244 { 245 IntPtr error, native_stdout, native_stderr; 246 IntPtr native_cmd = Marshaller.StringToPtrGStrdup (command_line); 247 bool result; 248 249 if (Global.IsWindowsPlatform) 250 result = g_spawn_command_line_sync_utf8 (native_cmd, out native_stdout, out native_stderr, out exit_status, out error); 251 else 252 result = g_spawn_command_line_sync (native_cmd, out native_stdout, out native_stderr, out exit_status, out error); 253 254 Marshaller.Free (native_cmd); 255 stdout = Marshaller.PtrToStringGFree (native_stdout); 256 stderr = Marshaller.PtrToStringGFree (native_stderr); 257 if (error != IntPtr.Zero) throw new GLib.GException (error); 258 return result; 259 } 260 } 261 } 262