40
40
*/
41
41
package com .oracle .graal .python .builtins .modules ;
42
42
43
+ import java .io .File ;
43
44
import java .io .IOException ;
44
45
import java .lang .ProcessBuilder .Redirect ;
45
46
import java .nio .ByteBuffer ;
48
49
import java .nio .channels .WritableByteChannel ;
49
50
import java .util .ArrayList ;
50
51
import java .util .List ;
52
+ import java .util .Map ;
51
53
52
54
import com .oracle .graal .python .builtins .Builtin ;
53
55
import com .oracle .graal .python .builtins .CoreFunctions ;
54
56
import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
55
57
import com .oracle .graal .python .builtins .PythonBuiltins ;
56
58
import com .oracle .graal .python .builtins .objects .PNone ;
59
+ import com .oracle .graal .python .builtins .objects .bytes .BytesNodes ;
60
+ import com .oracle .graal .python .builtins .objects .bytes .PBytes ;
57
61
import com .oracle .graal .python .builtins .objects .list .PList ;
58
62
import com .oracle .graal .python .builtins .objects .module .PythonModule ;
59
63
import com .oracle .graal .python .builtins .objects .str .PString ;
60
- import com .oracle .graal .python .builtins .objects .tuple .PTuple ;
64
+ import com .oracle .graal .python .nodes .expression .CastToBooleanNode ;
65
+ import com .oracle .graal .python .nodes .expression .CastToListNode ;
61
66
import com .oracle .graal .python .nodes .function .PythonBuiltinBaseNode ;
62
67
import com .oracle .graal .python .nodes .function .PythonBuiltinNode ;
68
+ import com .oracle .graal .python .nodes .util .CastToIndexNode ;
69
+ import com .oracle .graal .python .nodes .util .CastToStringNode ;
63
70
import com .oracle .graal .python .runtime .PosixResources ;
64
71
import com .oracle .graal .python .runtime .PythonContext ;
65
72
import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
66
73
import com .oracle .truffle .api .TruffleOptions ;
74
+ import com .oracle .truffle .api .dsl .Cached ;
67
75
import com .oracle .truffle .api .dsl .GenerateNodeFactory ;
68
76
import com .oracle .truffle .api .dsl .NodeFactory ;
69
77
import com .oracle .truffle .api .dsl .Specialization ;
@@ -80,14 +88,15 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
80
88
"errpipe_read" , "errpipe_write" , "restore_signals" , "call_setsid" , "preexec_fn" })
81
89
@ GenerateNodeFactory
82
90
abstract static class ForkExecNode extends PythonBuiltinNode {
83
- @ SuppressWarnings ( "unused" )
84
- @ TruffleBoundary
91
+ @ Child BytesNodes . ToBytesNode toBytes = BytesNodes . ToBytesNode . create ();
92
+
85
93
@ Specialization
86
- synchronized int forkExec (PList args , PTuple executable_list , boolean close_fds ,
87
- PTuple fdsToKeep , PNone cwd , PNone env ,
94
+ @ TruffleBoundary
95
+ synchronized int forkExec (PList args , @ SuppressWarnings ("unused" ) PList execList , @ SuppressWarnings ("unused" ) boolean closeFds ,
96
+ @ SuppressWarnings ("unused" ) PList fdsToKeep , String cwd , PList env ,
88
97
int p2cread , int p2cwrite , int c2pread , int c2pwrite ,
89
- int errread , int errwrite , int errpipe_read , int errpipe_write ,
90
- boolean restore_signals , boolean call_setsid , PNone preexec_fn ) {
98
+ int errread , int errwrite , @ SuppressWarnings ( "unused" ) int errpipe_read , int errpipe_write ,
99
+ @ SuppressWarnings ( "unused" ) boolean restore_signals , @ SuppressWarnings ( "unused" ) boolean call_setsid , @ SuppressWarnings ( "unused" ) PNone preexec_fn ) {
91
100
PythonContext context = getContext ();
92
101
PosixResources resources = context .getResources ();
93
102
if (!context .isExecutableAccessAllowed ()) {
@@ -119,10 +128,6 @@ synchronized int forkExec(PList args, PTuple executable_list, boolean close_fds,
119
128
}
120
129
}
121
130
122
- Channel stdin = null ;
123
- Channel stdout = null ;
124
- Channel stderr = null ;
125
-
126
131
ProcessBuilder pb = new ProcessBuilder (argStrings );
127
132
if (p2cread != -1 && p2cwrite != -1 ) {
128
133
pb .redirectInput (Redirect .PIPE );
@@ -142,6 +147,26 @@ synchronized int forkExec(PList args, PTuple executable_list, boolean close_fds,
142
147
pb .redirectError (Redirect .INHERIT );
143
148
}
144
149
150
+ try {
151
+ if (getContext ().getEnv ().getTruffleFile (cwd ).exists ()) {
152
+ pb .directory (new File (cwd ));
153
+ } else {
154
+ throw raise (PythonBuiltinClassType .OSError , "working directory %s is not accessible" , cwd );
155
+ }
156
+ } catch (SecurityException e ) {
157
+ throw raise (PythonBuiltinClassType .OSError , e .getMessage ());
158
+ }
159
+
160
+ Map <String , String > environment = pb .environment ();
161
+ for (Object keyValue : env .getSequenceStorage ().getInternalArray ()) {
162
+ if (keyValue instanceof PBytes ) {
163
+ String [] string = new String (toBytes .execute (keyValue )).split ("=" , 2 );
164
+ if (string .length == 2 ) {
165
+ environment .put (string [0 ], string [1 ]);
166
+ }
167
+ }
168
+ }
169
+
145
170
try {
146
171
Process process = pb .start ();
147
172
if (p2cwrite != -1 ) {
@@ -177,5 +202,49 @@ synchronized int forkExec(PList args, PTuple executable_list, boolean close_fds,
177
202
return -1 ;
178
203
}
179
204
}
205
+
206
+ @ Specialization (replaces = "forkExec" )
207
+ int forkExecDefault (Object args , Object executable_list , Object close_fds ,
208
+ Object fdsToKeep , Object cwd , Object env ,
209
+ Object p2cread , Object p2cwrite , Object c2pread , Object c2pwrite ,
210
+ Object errread , Object errwrite , Object errpipe_read , Object errpipe_write ,
211
+ Object restore_signals , Object call_setsid , PNone preexec_fn ,
212
+ @ Cached ("create()" ) CastToListNode castArgs ,
213
+ @ Cached ("create()" ) CastToListNode castExecList ,
214
+ @ Cached ("createIfTrueNode()" ) CastToBooleanNode castCloseFds ,
215
+ @ Cached ("create()" ) CastToListNode castFdsToKeep ,
216
+ @ Cached ("create()" ) CastToStringNode castCwd ,
217
+ @ Cached ("create()" ) CastToListNode castEnv ,
218
+ @ Cached ("create()" ) CastToIndexNode castP2cread ,
219
+ @ Cached ("create()" ) CastToIndexNode castP2cwrite ,
220
+ @ Cached ("create()" ) CastToIndexNode castC2pread ,
221
+ @ Cached ("create()" ) CastToIndexNode castC2pwrite ,
222
+ @ Cached ("create()" ) CastToIndexNode castErrread ,
223
+ @ Cached ("create()" ) CastToIndexNode castErrwrite ,
224
+ @ Cached ("create()" ) CastToIndexNode castErrpipeRead ,
225
+ @ Cached ("create()" ) CastToIndexNode castErrpipeWrite ,
226
+ @ Cached ("createIfTrueNode()" ) CastToBooleanNode castRestoreSignals ,
227
+ @ Cached ("createIfTrueNode()" ) CastToBooleanNode castSetsid ) {
228
+
229
+ String actualCwd ;
230
+ if (cwd instanceof PNone ) {
231
+ actualCwd = getContext ().getEnv ().getCurrentWorkingDirectory ().getPath ();
232
+ } else {
233
+ actualCwd = castCwd .execute (cwd );
234
+ }
235
+
236
+ PList actualEnv ;
237
+ if (env instanceof PNone ) {
238
+ actualEnv = factory ().createList ();
239
+ } else {
240
+ actualEnv = castEnv .executeWith (env );
241
+ }
242
+
243
+ return forkExec (castArgs .executeWith (args ), castExecList .executeWith (executable_list ), castCloseFds .executeWith (close_fds ),
244
+ castFdsToKeep .executeWith (fdsToKeep ), actualCwd , actualEnv ,
245
+ castP2cread .execute (p2cread ), castP2cwrite .execute (p2cwrite ), castC2pread .execute (c2pread ), castC2pwrite .execute (c2pwrite ),
246
+ castErrread .execute (errread ), castErrwrite .execute (errwrite ), castErrpipeRead .execute (errpipe_read ), castErrpipeWrite .execute (errpipe_write ),
247
+ castRestoreSignals .executeWith (restore_signals ), castSetsid .executeWith (call_setsid ), preexec_fn );
248
+ }
180
249
}
181
250
}
0 commit comments