VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp@ 4837

Last change on this file since 4837 was 1, checked in by vboxsync, 54 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is Mozilla Communicator client code, released
16 * March 31, 1998.
17 *
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998-1999
21 * the Initial Developer. All Rights Reserved.
22 *
23 * Contributor(s):
24 * Don Bragg <dbragg@netscape.com>
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
40/*****************************************************************************
41 *
42 * nsProcess is used to execute new processes and specify if you want to
43 * wait (blocking) or continue (non-blocking).
44 *
45 *****************************************************************************
46 */
47
48#include "nsCOMPtr.h"
49#include "nsMemory.h"
50#include "nsProcess.h"
51#include "prtypes.h"
52#include "prio.h"
53#include "prenv.h"
54#include "nsCRT.h"
55
56#include <stdlib.h>
57
58#if defined( XP_WIN )
59#include "prmem.h"
60#include "nsString.h"
61#include "nsLiteralString.h"
62#include "nsReadableUtils.h"
63#include <windows.h>
64#endif
65
66//-------------------------------------------------------------------//
67// nsIProcess implementation
68//-------------------------------------------------------------------//
69NS_IMPL_ISUPPORTS1(nsProcess, nsIProcess)
70
71//Constructor
72nsProcess::nsProcess():mExitValue(-1),
73 mProcess(nsnull)
74{
75}
76
77NS_IMETHODIMP
78nsProcess::Init(nsIFile* executable)
79{
80 PRBool isFile;
81
82 //First make sure the file exists
83 nsresult rv = executable->IsFile(&isFile);
84 if (NS_FAILED(rv)) return rv;
85 if (!isFile)
86 return NS_ERROR_FAILURE;
87
88 //Store the nsIFile in mExecutable
89 mExecutable = executable;
90 //Get the path because it is needed by the NSPR process creation
91#ifdef XP_WIN
92 rv = mExecutable->GetNativeTarget(mTargetPath);
93 if (NS_FAILED(rv) || mTargetPath.IsEmpty() )
94#endif
95 rv = mExecutable->GetNativePath(mTargetPath);
96
97 return rv;
98}
99
100
101#if defined( XP_WIN )
102static int assembleCmdLine(char *const *argv, char **cmdLine)
103{
104 char *const *arg;
105 char *p, *q;
106 int cmdLineSize;
107 int numBackslashes;
108 int i;
109 int argNeedQuotes;
110
111 /*
112 * Find out how large the command line buffer should be.
113 */
114 cmdLineSize = 0;
115 for (arg = argv; *arg; arg++) {
116 /*
117 * \ and " need to be escaped by a \. In the worst case,
118 * every character is a \ or ", so the string of length
119 * may double. If we quote an argument, that needs two ".
120 * Finally, we need a space between arguments, and
121 * a null byte at the end of command line.
122 */
123 cmdLineSize += 2 * strlen(*arg) /* \ and " need to be escaped */
124 + 2 /* we quote every argument */
125 + 1; /* space in between, or final null */
126 }
127 p = *cmdLine = (char *) PR_MALLOC(cmdLineSize);
128 if (p == NULL) {
129 return -1;
130 }
131
132 for (arg = argv; *arg; arg++) {
133 /* Add a space to separates the arguments */
134 if (arg != argv) {
135 *p++ = ' ';
136 }
137 q = *arg;
138 numBackslashes = 0;
139 argNeedQuotes = 0;
140
141 /* If the argument contains white space, it needs to be quoted. */
142 if (strpbrk(*arg, " \f\n\r\t\v")) {
143 argNeedQuotes = 1;
144 }
145
146 if (argNeedQuotes) {
147 *p++ = '"';
148 }
149 while (*q) {
150 if (*q == '\\') {
151 numBackslashes++;
152 q++;
153 } else if (*q == '"') {
154 if (numBackslashes) {
155 /*
156 * Double the backslashes since they are followed
157 * by a quote
158 */
159 for (i = 0; i < 2 * numBackslashes; i++) {
160 *p++ = '\\';
161 }
162 numBackslashes = 0;
163 }
164 /* To escape the quote */
165 *p++ = '\\';
166 *p++ = *q++;
167 } else {
168 if (numBackslashes) {
169 /*
170 * Backslashes are not followed by a quote, so
171 * don't need to double the backslashes.
172 */
173 for (i = 0; i < numBackslashes; i++) {
174 *p++ = '\\';
175 }
176 numBackslashes = 0;
177 }
178 *p++ = *q++;
179 }
180 }
181
182 /* Now we are at the end of this argument */
183 if (numBackslashes) {
184 /*
185 * Double the backslashes if we have a quote string
186 * delimiter at the end.
187 */
188 if (argNeedQuotes) {
189 numBackslashes *= 2;
190 }
191 for (i = 0; i < numBackslashes; i++) {
192 *p++ = '\\';
193 }
194 }
195 if (argNeedQuotes) {
196 *p++ = '"';
197 }
198 }
199
200 *p = '\0';
201 return 0;
202}
203#endif
204
205// XXXldb |args| has the wrong const-ness
206NS_IMETHODIMP
207nsProcess::Run(PRBool blocking, const char **args, PRUint32 count, PRUint32 *pid)
208{
209 nsresult rv = NS_OK;
210
211 // make sure that when we allocate we have 1 greater than the
212 // count since we need to null terminate the list for the argv to
213 // pass into PR_CreateProcess
214 char **my_argv = NULL;
215 my_argv = (char **)malloc(sizeof(char *) * (count + 2) );
216 if (!my_argv) {
217 return NS_ERROR_OUT_OF_MEMORY;
218 }
219
220 // copy the args
221 PRUint32 i;
222 for (i=0; i < count; i++) {
223 my_argv[i+1] = NS_CONST_CAST(char*, args[i]);
224 }
225 // we need to set argv[0] to the program name.
226 my_argv[0] = mTargetPath.BeginWriting();
227 // null terminate the array
228 my_argv[count+1] = NULL;
229
230 #if defined(XP_WIN)
231 STARTUPINFO startupInfo;
232 PROCESS_INFORMATION procInfo;
233 BOOL retVal;
234 char *cmdLine;
235
236 if (assembleCmdLine(my_argv, &cmdLine) == -1) {
237 nsMemory::Free(my_argv);
238 return NS_ERROR_FILE_EXECUTION_FAILED;
239 }
240
241 ZeroMemory(&startupInfo, sizeof(startupInfo));
242 startupInfo.cb = sizeof(startupInfo);
243
244 retVal = CreateProcess(NULL,
245 // NS_CONST_CAST(char*, mTargetPath.get()),
246 cmdLine,
247 NULL, /* security attributes for the new
248 * process */
249 NULL, /* security attributes for the primary
250 * thread in the new process */
251 FALSE, /* inherit handles */
252 0, /* creation flags */
253 NULL, /* env */
254 NULL, /* current drive and directory */
255 &startupInfo,
256 &procInfo
257 );
258 PR_FREEIF( cmdLine );
259 if (blocking) {
260
261 // if success, wait for process termination. the early returns and such
262 // are a bit ugly but preserving the logic of the nspr code I copied to
263 // minimize our risk abit.
264
265 if ( retVal == TRUE ) {
266 DWORD dwRetVal;
267 unsigned long exitCode;
268
269 dwRetVal = WaitForSingleObject(procInfo.hProcess, INFINITE);
270 if (dwRetVal == WAIT_FAILED) {
271 nsMemory::Free(my_argv);
272 return PR_FAILURE;
273 }
274 if (GetExitCodeProcess(procInfo.hProcess, &exitCode) == FALSE) {
275 mExitValue = exitCode;
276 nsMemory::Free(my_argv);
277 return PR_FAILURE;
278 }
279 mExitValue = exitCode;
280 CloseHandle(procInfo.hProcess);
281 }
282 else
283 rv = PR_FAILURE;
284 }
285 else {
286
287 // map return value into success code
288
289 if ( retVal == TRUE )
290 rv = PR_SUCCESS;
291 else
292 rv = PR_FAILURE;
293 }
294
295#else
296 if ( blocking ) {
297 mProcess = PR_CreateProcess(mTargetPath.get(), my_argv, NULL, NULL);
298 if (mProcess)
299 rv = PR_WaitProcess(mProcess, &mExitValue);
300 }
301 else {
302 rv = PR_CreateProcessDetached(mTargetPath.get(), my_argv, NULL, NULL);
303 }
304#endif
305
306 // free up our argv
307 nsMemory::Free(my_argv);
308
309 if (rv != PR_SUCCESS)
310 return NS_ERROR_FILE_EXECUTION_FAILED;
311 return NS_OK;
312}
313
314NS_IMETHODIMP nsProcess::InitWithPid(PRUint32 pid)
315{
316 return NS_ERROR_NOT_IMPLEMENTED;
317}
318
319NS_IMETHODIMP
320nsProcess::GetLocation(nsIFile** aLocation)
321{
322 return NS_ERROR_NOT_IMPLEMENTED;
323}
324
325NS_IMETHODIMP
326nsProcess::GetPid(PRUint32 *aPid)
327{
328 return NS_ERROR_NOT_IMPLEMENTED;
329}
330
331NS_IMETHODIMP
332nsProcess::GetProcessName(char** aProcessName)
333{
334 return NS_ERROR_NOT_IMPLEMENTED;
335}
336
337NS_IMETHODIMP
338nsProcess::GetProcessSignature(PRUint32 *aProcessSignature)
339{
340 return NS_ERROR_NOT_IMPLEMENTED;
341}
342
343NS_IMETHODIMP
344nsProcess::Kill()
345{
346 nsresult rv = NS_OK;
347 if (mProcess)
348 rv = PR_KillProcess(mProcess);
349
350 return rv;
351}
352
353NS_IMETHODIMP
354nsProcess::GetExitValue(PRInt32 *aExitValue)
355{
356 *aExitValue = mExitValue;
357
358 return NS_OK;
359}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use