1 module arsd.exec;
2 
3 static import stdlib = core.stdc.stdlib;
4 static import cstdio = core.stdc.stdio;
5 
6 import std.stdio;
7 import std..string;
8 version(D_Version2)
9 static import linux = core.sys.posix.unistd;
10 else
11 static import linux = std.c.linux.linux;
12 
13 extern(C) int execve(const(char)*, const(char)**, const(char)**);
14 
15 
16 /**
17 	executes an external program, with stdin and stdout of that program optionally going to/from strings
18 
19 	args - an array of command line arguments to pass (may be empty or null to pass nothing)
20 	input - a string that contains the data pass to standard input of the program (null is no override)
21 	output - a pointer to a string that will receive standard output from the program (null is no override)
22 	environment - a string of additional environment variables to send (null is none) [NOT YET IMPLEMENTED]
23 
24 	returns return value of program ran
25 
26 	throws exceptions on error
27 */
28 int exec(string program, string[] args = null, string input = null, string* output = null, string* error = null, string[] environment = null){
29 	int[2] newStdin;
30 	int[2] newStdout;
31 	int[2] newStderr;
32 	if(input !is null)
33 		if(linux.pipe(newStdin) != 0)
34 			throw new Exception("pipe stdin");
35 	if(output !is null)
36 		if(linux.pipe(newStdout) != 0)
37 			throw new Exception("pipe stdout");
38 	if(error !is null)
39 		if(linux.pipe(newStderr) != 0)
40 			throw new Exception("pipe stderr");
41 
42 	int pid = linux.fork();
43 	if(pid == 0){ // child
44 		if(input !is null){
45 			linux.close(newStdin[1]);
46 			linux.close(0);
47 			linux.dup(newStdin[0]);
48 		}
49 		if(output !is null){
50 			linux.close(1);
51 			linux.dup(newStdout[1]);
52 		}
53 		if(error !is null){
54 			linux.close(2);
55 			linux.dup(newStderr[1]);
56 		}
57 
58 		const(char)*[] argv;
59 		argv.length = 2 + args.length;
60 		int a = 1;
61 		argv[0] = toStringz(program);
62 
63 		if(args !is null)
64 			foreach(arg; args){
65 				argv[a] = toStringz(arg);
66 				a++;
67 			}
68 		argv[a] = null;
69 
70 
71 		const(char)*[] envp;
72 		envp.length = 1 + environment.length;
73 		a = 0;
74 
75 		if(environment !is null)
76 			foreach(arg; environment){
77 				envp[a] = toStringz(arg);
78 				a++;
79 			}
80 		envp[a] = null;
81 
82 		if(execve(toStringz(program), argv.ptr, envp.ptr) == -1)
83 			throw new Exception("Execute");
84 	} else { // parent
85 
86 		if(input !is null)
87 			linux.close(newStdin[0]);
88 		if(output !is null)
89 			linux.close(newStdout[1]);
90 		if(error !is null)
91 			linux.close(newStderr[1]);
92 
93 		typeof(linux.write(1, null, 0)) s;
94 		if(input !is null){
95 			do{
96 				s = linux.write(newStdin[1], input.ptr, input.length);
97 				if(s < input.length)
98 					input = input[s..$];
99 				else
100 					s = 0;
101 			} while (s > 0);
102 			linux.close(newStdin[1]);
103 		}
104 
105 		if(output !is null){
106 			ubyte[1024] buffer;
107 			do {
108 				s = linux.read(newStdout[0], buffer.ptr, 1024);
109 				(*output) ~= buffer[0..s];
110 			} while (s > 0);
111 
112 			linux.close(newStdout[0]);
113 		}
114 
115 		if(error !is null){
116 			ubyte[1024] buffer;
117 			do {
118 				s = linux.read(newStderr[0], buffer.ptr, 1024);
119 				(*error) ~= buffer[0..s];
120 			} while (s > 0);
121 
122 			linux.close(newStderr[0]);
123 		}
124 
125 
126 		int i;
127 		linux.wait(&i);
128 
129 		return i;
130 	}
131 
132 	return 0; // never reached
133 }
134 
135 
136 void callInBackground(void delegate() functionToCall) {
137 	int pid = linux.fork();
138 	if(pid == 0){ // child
139 		linux.umask(0);
140 		auto sid = linux.setsid();
141 		if(sid < 0) {
142 			stdlib.exit(1);
143 		}
144 		if(linux.chdir("/") < 0) {
145 			stdlib.exit(1);
146 		}
147 
148 		freopen("/dev/null", "r", cstdio.stdin);
149 		freopen("/dev/null", "w", cstdio.stdout);
150 		freopen("/dev/null", "w", cstdio.stderr);
151 
152 		try
153 			functionToCall();
154 		catch(Throwable e) {
155 			stderr.writeln(e.toString());
156 	//	/*
157 			try {
158 				import arsd.email;
159 				email("me@arsdnet.net", "background exception", e.toString(), "root@fanclipper.com");
160 			} catch(Throwable e) {}
161 	//	*/
162 			stdlib.exit(1);
163 		}
164 		stdlib.exit(0);
165 	}
166 }
167 
168 
Suggestion Box / Bug Report