VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp@ 99483

最後變更 在這個檔案從99483是 99483,由 vboxsync 提交於 2 年 前

IPRT/RTProcCreateEx: More fixes for the initial patch supplied; also tweaked the testcases a little. bugref:8053

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 30.4 KB
 
1/* $Id: tstRTProcCreateEx.cpp 99483 2023-04-20 10:16:10Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTProcCreateEx.
4 */
5
6/*
7 * Copyright (C) 2010-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/process.h>
42
43#include <iprt/assert.h>
44#include <iprt/env.h>
45#include <iprt/err.h>
46#include <iprt/initterm.h>
47#include <iprt/mem.h>
48#include <iprt/message.h>
49#include <iprt/param.h>
50#include <iprt/path.h> /* For CWD testing. */
51#include <iprt/pipe.h>
52#include <iprt/string.h>
53#include <iprt/stream.h>
54#include <iprt/test.h>
55#include <iprt/thread.h>
56
57#ifdef RT_OS_WINDOWS
58# define SECURITY_WIN32
59# include <iprt/win/windows.h>
60# include <Security.h>
61#endif
62
63
64/*********************************************************************************************************************************
65* Global Variables *
66*********************************************************************************************************************************/
67static RTENV g_hEnvInitial = NIL_RTENV;
68static char g_szExecName[RTPATH_MAX];
69
70
71static const char * const g_apszArgs4[] =
72{
73 /* 0 */ "non existing non executable file",
74 /* 1 */ "--testcase-child-4",
75 /* 2 */ "a b",
76 /* 3 */ " cdef",
77 /* 4 */ "ghijkl ",
78 /* 5 */ "\"",
79 /* 6 */ "\\",
80 /* 7 */ "\\\"",
81 /* 8 */ "\\\"\\",
82 /* 9 */ "\\\\\"\\",
83 /*10 */ "%TEMP%",
84 /*11 */ "%TEMP%\filename",
85 /*12 */ "%TEMP%postfix",
86 /*13 */ "Prefix%TEMP%postfix",
87 /*14 */ "%",
88 /*15 */ "%%",
89 /*16 */ "%%%",
90 /*17 */ "%X",
91 /*18 */ "%%X",
92 NULL
93};
94
95
96static int tstRTCreateProcExCwdChild(int argc, char **argv)
97{
98 int rc = RTR3InitExeNoArguments(0);
99 if (RT_FAILURE(rc))
100 return RTMsgInitFailure(rc);
101
102 int cErrors = 0;
103
104 if (argc < 3)
105 return RTEXITCODE_FAILURE;
106
107 const char *pszCWD = argv[2];
108
109 RTStrmPrintf(g_pStdOut, "childcwd: Called with CWD '%s'\n", pszCWD);
110
111 if (!RTStrICmp(pszCWD, "<cwd-not-specified>")) /* Bail out early if no CWD has been explicitly specified. */
112 return RTEXITCODE_SUCCESS;
113
114 /* Validate if we really are in the CWD the parent told us. */
115 char szCWD[RTPATH_MAX];
116 rc = RTPathGetCurrent(szCWD, sizeof(szCWD));
117 if (RT_FAILURE(rc))
118 {
119 RTStrmPrintf(g_pStdErr, "childcwd: Unable to retrieve CWD, rc=%Rrc\n", rc);
120 cErrors++;
121 }
122 else
123 {
124 if (RTStrCmp(szCWD, pszCWD))
125 {
126 RTStrmPrintf(g_pStdErr, "childcwd: CWD is '%s', but expected '%s'\n", szCWD, pszCWD);
127 cErrors++;
128 }
129 else
130 {
131 /* Check if we can query information of the current CWD. */
132 char *pszUser = NULL;
133 if ( argc >= 4
134 && argv[3][0] != '\0')
135 {
136 pszUser = argv[3];
137 }
138
139 RTFSOBJINFO objInfo;
140 rc = RTPathQueryInfo(szCWD, &objInfo, RTFSOBJATTRADD_NOTHING);
141 if (pszUser)
142 RTStrmPrintf(g_pStdOut, "childcwd: Accessing CWD '%s' via user '%s' -> %Rrc\n", szCWD, pszUser, rc);
143 else
144 RTStrmPrintf(g_pStdOut, "childcwd: Accesing CWD '%s' -> %Rrc\n", szCWD, rc);
145 if (RT_FAILURE(rc))
146 cErrors++;
147 }
148 }
149
150 RTStrmPrintf(g_pStdOut, "childcwd: Exiting (%d errors)\n", cErrors);
151 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
152}
153
154static void tstRTCreateProcExCwd(const char *pszAsUser, const char *pszPassword)
155{
156 RTTestISub("Current working directory (CWD)");
157
158 const char *apszArgs[5] =
159 {
160 g_szExecName,
161 "--testcase-child-cwd",
162 "<cwd-not-specified>",
163 pszAsUser,
164 NULL
165 };
166
167 bool const fMayPanic = RTAssertSetMayPanic(false);
168 bool const fQuiet = RTAssertSetQuiet(true);
169
170 RTPROCESS hProc;
171 uint32_t fFlags = 0;
172 /* Missing RTPROC_FLAGS_CWD. */
173 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
174 NULL, NULL, NULL, pszAsUser, pszPassword,
175 (void *)apszArgs[2] /* pvExtraData (CWD) */, &hProc),
176 VERR_INVALID_PARAMETER);
177
178 /* Invalid flag combinations. Windows flags ignored elsewhere. */
179#ifdef RT_OS_WINDOWS
180 int rc = VERR_INVALID_PARAMETER;
181#else
182 int rc = VERR_INVALID_POINTER; /* Due to missing pvExtraData. */
183#endif
184 fFlags = RTPROC_FLAGS_CWD | RTPROC_FLAGS_DESIRED_SESSION_ID | RTPROC_FLAGS_SERVICE;
185 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
186 NULL, NULL, NULL, pszAsUser, pszPassword,
187 NULL, &hProc), rc);
188
189 /* Windows-only flags. Ignored elsewhere. */
190#ifdef RT_OS_WINDOWS
191 rc = VERR_INVALID_POINTER;
192#else
193 rc = VINF_SUCCESS;
194#endif
195 fFlags = RTPROC_FLAGS_DESIRED_SESSION_ID | RTPROC_FLAGS_SERVICE;
196 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
197 NULL, NULL, NULL, pszAsUser, pszPassword,
198 NULL, &hProc), rc);
199
200 /* RTPROC_FLAGS_CWD set, but CWD missing as pvExtradata. */
201 fFlags = RTPROC_FLAGS_CWD;
202 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
203 NULL, NULL, NULL, pszAsUser, pszPassword,
204 NULL, &hProc),
205 VERR_INVALID_POINTER);
206
207 char szCWD[RTPATH_MAX];
208 char szResolved[RTPATH_MAX];
209
210 /* Try current CWD, whatever that is. */
211 RTTESTI_CHECK_RC_OK_RETV(RTPathGetCurrent(szCWD, sizeof(szCWD)));
212 RTTESTI_CHECK_RC_OK_RETV(RTPathReal(szCWD, szResolved, sizeof(szResolved)));
213 apszArgs[2] = szResolved;
214 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
215 NULL, NULL, NULL, pszAsUser, pszPassword,
216 (void *)szCWD /* pvExtraData (CWD) */, &hProc),
217 VINF_SUCCESS);
218 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
219 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
220 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
221 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
222
223 /* Try temporary directory. */
224 RTTESTI_CHECK_RC_OK_RETV(RTPathTemp(szCWD, sizeof(szCWD)));
225 RTTESTI_CHECK_RC_OK_RETV(RTPathReal(szCWD, szResolved, sizeof(szResolved)));
226 apszArgs[2] = szResolved;
227 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
228 NULL, NULL, NULL, pszAsUser, pszPassword,
229 (void *)szCWD /* pvExtraData (CWD) */, &hProc),
230 VINF_SUCCESS);
231 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
232 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
233 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
234
235 /* Try user home. */
236 RTTESTI_CHECK_RC_OK_RETV(RTPathUserHome(szCWD, sizeof(szCWD)));
237 RTTESTI_CHECK_RC_OK_RETV(RTPathReal(szCWD, szResolved, sizeof(szResolved)));
238 apszArgs[2] = szResolved;
239 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
240 NULL, NULL, NULL, pszAsUser, pszPassword,
241 (void *)szCWD /* pvExtraData (CWD) */, &hProc),
242 VINF_SUCCESS);
243 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
244 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
245 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
246
247 RTAssertSetMayPanic(fMayPanic);
248 RTAssertSetQuiet(fQuiet);
249}
250
251static int tstRTCreateProcEx6Child(int argc, char **argv)
252{
253 int rc = RTR3InitExeNoArguments(0);
254 if (RT_FAILURE(rc))
255 return RTMsgInitFailure(rc);
256
257 int cErrors = 0;
258 char szValue[_16K];
259
260 /*
261 * Check for the environment variable we've set in the parent process.
262 */
263 if (argc >= 3 && strcmp(argv[2], "inherit") == 0)
264 {
265 if (!RTEnvExistEx(RTENV_DEFAULT, "testcase-child-6"))
266 {
267 RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6' was not inherited from parent\n");
268 cErrors++;
269 }
270 }
271 else if (argc >= 3 && strstr(argv[2], "change-record") != NULL)
272 {
273 rc = RTEnvGetEx(RTENV_DEFAULT, "testcase-child-6", szValue, sizeof(szValue), NULL);
274 if (RT_SUCCESS(rc) && strcmp(szValue, "changed"))
275 {
276 RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6'='%s', expected 'changed'.\n", szValue);
277 cErrors++;
278 }
279 else if (RT_FAILURE(rc))
280 {
281 RTStrmPrintf(g_pStdErr, "child6: RTEnvGetEx(,'testcase-child-6',,) -> %Rrc\n", rc);
282 cErrors++;
283 }
284 }
285 else
286 {
287 if (RTEnvExistEx(RTENV_DEFAULT, "testcase-child-6"))
288 {
289 RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6' was inherited from parent\n");
290 cErrors++;
291 }
292 }
293
294 /*
295 * Check the user name if present we didn't inherit from parent.
296 */
297 if ( argc >= 4
298 && argv[3][0] != '\0'
299 && strstr(argv[2], "noinherit") != NULL)
300 {
301 static struct
302 {
303 const char *pszVarNm;
304 bool fReq;
305 } const s_aVars[] =
306 {
307#ifdef RT_OS_WINDOWS
308 { "USERNAME", true },
309#else
310 { "LOGNAME", true },
311 { "USER", false },
312#endif
313 };
314 for (unsigned i = 0; i < RT_ELEMENTS(s_aVars); i++)
315 {
316 rc = RTEnvGetEx(RTENV_DEFAULT, s_aVars[i].pszVarNm, szValue, sizeof(szValue), NULL);
317 if (RT_SUCCESS(rc))
318 {
319 if (strcmp(szValue, argv[3]))
320 {
321 RTStrmPrintf(g_pStdErr, "child6: env.var. '%s'='%s', expected '%s'\n",
322 s_aVars[i].pszVarNm, szValue, argv[3]);
323 cErrors++;
324 }
325 }
326 else if (rc != VERR_ENV_VAR_NOT_FOUND || s_aVars[i].fReq)
327 {
328 RTStrmPrintf(g_pStdErr, "child6: RTGetEnv('%s') -> %Rrc\n", s_aVars[i].pszVarNm, rc);
329 cErrors++;
330 }
331 }
332 }
333
334#if 1
335 /* For manual testing. */
336 if (strcmp(argv[2],"noinherit") == 0)
337 //if (strcmp(argv[2],"noinherit-change-record") == 0)
338 {
339 RTENV hEnv;
340 rc = RTEnvClone(&hEnv, RTENV_DEFAULT);
341 if (RT_SUCCESS(rc))
342 {
343 uint32_t cVars = RTEnvCountEx(hEnv);
344 for (uint32_t i = 0; i < cVars; i++)
345 {
346 char szVarNm[_1K];
347 rc = RTEnvGetByIndexEx(hEnv, i, szVarNm, sizeof(szVarNm), szValue, sizeof(szValue));
348 if (RT_SUCCESS(rc))
349 RTStrmPrintf(g_pStdErr, "child6: #%u: %s=%s\n", i, szVarNm, szValue);
350 else
351 {
352 RTStrmPrintf(g_pStdErr, "child6: #%u: %Rrc\n", i, rc);
353 cErrors++;
354 }
355 }
356 RTEnvDestroy(hEnv);
357 }
358 else
359 {
360 RTStrmPrintf(g_pStdErr, "child6: RTEnvClone failed: %Rrc\n", rc);
361 cErrors++;
362 }
363 }
364#endif
365
366 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
367}
368
369static void tstRTCreateProcEx6(const char *pszAsUser, const char *pszPassword)
370{
371 RTTestISub("Profile environment");
372
373 const char *apszArgs[5] =
374 {
375 g_szExecName,
376 "--testcase-child-6",
377 "inherit",
378 pszAsUser,
379 NULL
380 };
381
382 RTTESTI_CHECK_RC_RETV(RTEnvSetEx(RTENV_DEFAULT, "testcase-child-6", "true"), VINF_SUCCESS);
383
384 /* Use the process environment first. */
385 RTPROCESS hProc;
386 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/,
387 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
388 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
389 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
390
391 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
392 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
393
394 /* Use the process environment first with a little change. */
395 apszArgs[2] = "change-record";
396 RTENV hEnvChange;
397 RTTESTI_CHECK_RC_RETV(RTEnvCreateChangeRecord(&hEnvChange), VINF_SUCCESS);
398 RTTESTI_CHECK_RC_RETV(RTEnvSetEx(hEnvChange, "testcase-child-6", "changed"), VINF_SUCCESS);
399 int rc;
400 RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, hEnvChange, RTPROC_FLAGS_ENV_CHANGE_RECORD,
401 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
402 if (RT_SUCCESS(rc))
403 {
404 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
405 ProcStatus.iStatus = -1;
406 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
407
408 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
409 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
410 }
411
412
413 /* Use profile environment this time. */
414 apszArgs[2] = "noinherit";
415 RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, RTPROC_FLAGS_PROFILE,
416 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
417 if (RT_SUCCESS(rc))
418 {
419 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
420 ProcStatus.iStatus = -1;
421 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
422
423 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
424 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
425 }
426
427 /* Use profile environment this time. */
428 apszArgs[2] = "noinherit-change-record";
429 RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, hEnvChange,
430 RTPROC_FLAGS_PROFILE | RTPROC_FLAGS_ENV_CHANGE_RECORD,
431 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
432 if (RT_SUCCESS(rc))
433 {
434 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
435 ProcStatus.iStatus = -1;
436 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
437
438 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
439 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
440 }
441
442
443 RTTESTI_CHECK_RC(RTEnvDestroy(hEnvChange), VINF_SUCCESS);
444
445 /*
446 * Restore the environment and check that the PROFILE flag didn't mess with
447 * the process environment. (Note! The bug may be elsewhere as well.)
448 */
449 RTTESTI_CHECK_RC(RTEnvUnsetEx(RTENV_DEFAULT, "testcase-child-6"), VINF_SUCCESS);
450
451 RTENV hEnvCur;
452 RTTESTI_CHECK_RC_RETV(RTEnvClone(&hEnvCur, RTENV_DEFAULT), VINF_SUCCESS);
453 uint32_t cCurrent = RTEnvCountEx(hEnvCur);
454 uint32_t cInitial = RTEnvCountEx(g_hEnvInitial);
455 RTTESTI_CHECK_MSG(cCurrent == cInitial, ("cCurrent=%u cInitial=%u\n", cCurrent, cInitial));
456 uint32_t cVars1;
457 RTENV hEnv1, hEnv2;
458 const char *pszEnv1, *pszEnv2;
459 if (cCurrent >= cInitial)
460 {
461 hEnv1 = hEnvCur;
462 pszEnv1 = "current";
463 cVars1 = cCurrent;
464 hEnv2 = g_hEnvInitial;
465 pszEnv2 = "initial";
466 }
467 else
468 {
469 hEnv2 = hEnvCur;
470 pszEnv2 = "current";
471 hEnv1 = g_hEnvInitial;
472 pszEnv1 = "initial";
473 cVars1 = cInitial;
474 }
475 for (uint32_t i = 0; i < cVars1; i++)
476 {
477 char szValue1[_16K];
478 char szVarNm[_1K];
479 rc = RTEnvGetByIndexEx(hEnv1, i, szVarNm, sizeof(szVarNm), szValue1, sizeof(szValue1));
480 if (RT_SUCCESS(rc))
481 {
482 char szValue2[_16K];
483 rc = RTEnvGetEx(hEnv2, szVarNm, szValue2, sizeof(szValue2), NULL);
484 if (RT_SUCCESS(rc))
485 {
486 if (strcmp(szValue1, szValue2) != 0)
487 {
488 RTTestIFailed("Variable '%s' differs", szVarNm);
489 RTTestIFailureDetails("%s: '%s'\n"
490 "%s: '%s'\n",
491 pszEnv1, szValue1,
492 pszEnv2, szValue2);
493 }
494 }
495 else
496 RTTestIFailed("RTEnvGetEx(%s,%s,,) failed: %Rrc", pszEnv2, szVarNm, rc);
497
498 }
499 else
500 RTTestIFailed("RTEnvGetByIndexEx(%s,%u,,,,) failed: %Rrc", pszEnv1, i, rc);
501 }
502}
503
504
505static int tstRTCreateProcEx5Child(int argc, char **argv)
506{
507 int rc = RTR3InitExe(argc, &argv, 0);
508 if (RT_FAILURE(rc))
509 return RTMsgInitFailure(rc);
510
511 uint32_t cErrors = 0;
512
513 /* Check that the OS thinks we're running as the user we're supposed to. */
514 char *pszUser;
515 rc = RTProcQueryUsernameA(NIL_RTPROCESS, &pszUser);
516 if (RT_SUCCESS(rc))
517 {
518#ifdef RT_OS_WINDOWS
519 if (RTStrICmp(pszUser, argv[2]) != 0)
520#else
521 if (RTStrCmp(pszUser, argv[2]) != 0)
522#endif
523 {
524 RTStrmPrintf(g_pStdErr, "child4: user name is '%s', expected '%s'\n", pszUser, argv[2]);
525 cErrors++;
526 }
527 RTStrFree(pszUser);
528 }
529 else
530 {
531 RTStrmPrintf(g_pStdErr, "child4: RTProcQueryUsernameA failed: %Rrc\n", rc);
532 cErrors++;
533 }
534
535 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
536}
537
538static void tstRTCreateProcEx5(const char *pszUser, const char *pszPassword)
539{
540 RTTestISubF("As user \"%s\" with password \"%s\"", pszUser, pszPassword);
541 RTTESTI_CHECK_RETV(pszUser && *pszUser);
542
543 const char * apszArgs[] =
544 {
545 "test", /* user name */
546 "--testcase-child-5",
547 pszUser,
548 NULL
549 };
550
551 /* Test for invalid logons. */
552 RTPROCESS hProc;
553 int rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL, NULL, NULL,
554 "non-existing-user", "wrong-password", NULL, &hProc);
555 if (rc != VERR_AUTHENTICATION_FAILURE && rc != VERR_PRIVILEGE_NOT_HELD && rc != VERR_PROC_TCB_PRIV_NOT_HELD)
556 RTTestIFailed("rc=%Rrc", rc);
557
558 /* Test for invalid application. */
559 RTTESTI_CHECK_RC(RTProcCreateEx("non-existing-app", apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
560 NULL, NULL, NULL, NULL, NULL, &hProc), VERR_FILE_NOT_FOUND);
561
562 /* Test a (hopefully) valid user/password logon (given by parameters of this function). */
563 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
564 NULL, NULL, pszUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
565 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
566 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
567
568 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
569 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
570}
571
572
573static int tstRTCreateProcEx4Child(int argc, char **argv)
574{
575 int rc = RTR3InitExeNoArguments(0);
576 if (RT_FAILURE(rc))
577 return RTMsgInitFailure(rc);
578
579 int cErrors = 0;
580 for (int i = 0; i < argc; i++)
581 if (strcmp(argv[i], g_apszArgs4[i]))
582 {
583 RTStrmPrintf(g_pStdErr,
584 "child4: argv[%2u]='%s'\n"
585 "child4: expected='%s'\n",
586 i, argv[i], g_apszArgs4[i]);
587 cErrors++;
588 }
589
590 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
591}
592
593static void tstRTCreateProcEx4(const char *pszAsUser, const char *pszPassword)
594{
595 RTTestISub("Argument with spaces and stuff");
596
597 RTPROCESS hProc;
598 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, g_apszArgs4, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
599 NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
600 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
601 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
602
603 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
604 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
605}
606
607
608static int tstRTCreateProcEx3Child(void)
609{
610 int rc = RTR3InitExeNoArguments(0);
611 if (RT_FAILURE(rc))
612 return RTMsgInitFailure(rc);
613
614 RTStrmPrintf(g_pStdOut, "w"); RTStrmFlush(g_pStdOut);
615 RTStrmPrintf(g_pStdErr, "o"); RTStrmFlush(g_pStdErr);
616 RTStrmPrintf(g_pStdOut, "r"); RTStrmFlush(g_pStdOut);
617 RTStrmPrintf(g_pStdErr, "k"); RTStrmFlush(g_pStdErr);
618 RTStrmPrintf(g_pStdOut, "s");
619
620 return RTEXITCODE_SUCCESS;
621}
622
623static void tstRTCreateProcEx3(const char *pszAsUser, const char *pszPassword)
624{
625 RTTestISub("Standard Out+Err");
626
627 RTPIPE hPipeR, hPipeW;
628 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
629 const char * apszArgs[3] =
630 {
631 "non-existing-non-executable-file",
632 "--testcase-child-3",
633 NULL
634 };
635 RTHANDLE Handle;
636 Handle.enmType = RTHANDLETYPE_PIPE;
637 Handle.u.hPipe = hPipeW;
638 RTPROCESS hProc;
639 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
640 &Handle, &Handle, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
641 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
642
643 char szOutput[_4K];
644 size_t offOutput = 0;
645 for (;;)
646 {
647 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
648 RTTESTI_CHECK(cbLeft > 0);
649 if (cbLeft == 0)
650 break;
651
652 size_t cbRead;
653 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
654 if (RT_FAILURE(rc))
655 {
656 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
657 break;
658 }
659 offOutput += cbRead;
660 }
661 szOutput[offOutput] = '\0';
662 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
663
664 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
665 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
666 RTThreadSleep(10);
667
668 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
669 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
670 else if ( offOutput != sizeof("works") - 1
671 || strcmp(szOutput, "works"))
672 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
673}
674
675
676static int tstRTCreateProcEx2Child(void)
677{
678 int rc = RTR3InitExeNoArguments(0);
679 if (RT_FAILURE(rc))
680 return RTMsgInitFailure(rc);
681
682 RTStrmPrintf(g_pStdErr, "howdy");
683 RTStrmPrintf(g_pStdOut, "ignore this output\n");
684
685 return RTEXITCODE_SUCCESS;
686}
687
688static void tstRTCreateProcEx2(const char *pszAsUser, const char *pszPassword)
689{
690 RTTestISub("Standard Err");
691
692 RTPIPE hPipeR, hPipeW;
693 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
694 const char * apszArgs[3] =
695 {
696 "non-existing-non-executable-file",
697 "--testcase-child-2",
698 NULL
699 };
700 RTHANDLE Handle;
701 Handle.enmType = RTHANDLETYPE_PIPE;
702 Handle.u.hPipe = hPipeW;
703 RTPROCESS hProc;
704 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
705 NULL, &Handle, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
706 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
707
708 char szOutput[_4K];
709 size_t offOutput = 0;
710 for (;;)
711 {
712 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
713 RTTESTI_CHECK(cbLeft > 0);
714 if (cbLeft == 0)
715 break;
716
717 size_t cbRead;
718 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
719 if (RT_FAILURE(rc))
720 {
721 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
722 break;
723 }
724 offOutput += cbRead;
725 }
726 szOutput[offOutput] = '\0';
727 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
728
729 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
730 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
731 RTThreadSleep(10);
732
733 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
734 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
735 else if ( offOutput != sizeof("howdy") - 1
736 || strcmp(szOutput, "howdy"))
737 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
738}
739
740
741static int tstRTCreateProcEx1Child(void)
742{
743 int rc = RTR3InitExeNoArguments(0);
744 if (RT_FAILURE(rc))
745 return RTMsgInitFailure(rc);
746
747 RTPrintf("it works");
748 RTStrmPrintf(g_pStdErr, "ignore this output\n");
749
750 return RTEXITCODE_SUCCESS;
751}
752
753
754static void tstRTCreateProcEx1(const char *pszAsUser, const char *pszPassword)
755{
756 RTTestISub("Standard Out");
757
758 RTPIPE hPipeR, hPipeW;
759 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
760 const char * apszArgs[3] =
761 {
762 "non-existing-non-executable-file",
763 "--testcase-child-1",
764 NULL
765 };
766 RTHANDLE Handle;
767 Handle.enmType = RTHANDLETYPE_PIPE;
768 Handle.u.hPipe = hPipeW;
769 RTPROCESS hProc;
770 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
771 &Handle, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
772 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
773
774 char szOutput[_4K];
775 size_t offOutput = 0;
776 for (;;)
777 {
778 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
779 RTTESTI_CHECK(cbLeft > 0);
780 if (cbLeft == 0)
781 break;
782
783 size_t cbRead;
784 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
785 if (RT_FAILURE(rc))
786 {
787 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
788 break;
789 }
790 offOutput += cbRead;
791 }
792 szOutput[offOutput] = '\0';
793 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
794
795 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
796 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
797
798 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
799 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
800 else if ( offOutput != sizeof("it works") - 1
801 || strcmp(szOutput, "it works"))
802 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
803}
804
805
806int main(int argc, char **argv)
807{
808 /*
809 * Deal with child processes first.
810 */
811 if (argc == 2 && !strcmp(argv[1], "--testcase-child-1"))
812 return tstRTCreateProcEx1Child();
813 if (argc == 2 && !strcmp(argv[1], "--testcase-child-2"))
814 return tstRTCreateProcEx2Child();
815 if (argc == 2 && !strcmp(argv[1], "--testcase-child-3"))
816 return tstRTCreateProcEx3Child();
817 if (argc >= 5 && !strcmp(argv[1], "--testcase-child-4"))
818 return tstRTCreateProcEx4Child(argc, argv);
819 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-5"))
820 return tstRTCreateProcEx5Child(argc, argv);
821 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-6"))
822 return tstRTCreateProcEx6Child(argc, argv);
823 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-cwd"))
824 return tstRTCreateProcExCwdChild(argc, argv);
825
826 /*
827 * Main process.
828 */
829 const char *pszAsUser = NULL;
830 const char *pszPassword = NULL;
831 if (argc != 1)
832 {
833 if (argc != 4 || strcmp(argv[1], "--as-user"))
834 return 99;
835 pszAsUser = argv[2];
836 pszPassword = argv[3];
837 }
838
839 RTTEST hTest;
840 int rc = RTTestInitAndCreate("tstRTProcCreateEx", &hTest);
841 if (rc)
842 return rc;
843 RTTestBanner(hTest);
844
845 /*
846 * Init globals.
847 */
848 if (!RTProcGetExecutablePath(g_szExecName, sizeof(g_szExecName)))
849 RTStrCopy(g_szExecName, sizeof(g_szExecName), argv[0]);
850 RTTESTI_CHECK_RC(RTEnvClone(&g_hEnvInitial, RTENV_DEFAULT), VINF_SUCCESS);
851
852 /*
853 * The tests.
854 */
855 tstRTCreateProcEx1(pszAsUser, pszPassword);
856 tstRTCreateProcEx2(pszAsUser, pszPassword);
857 tstRTCreateProcEx3(pszAsUser, pszPassword);
858 tstRTCreateProcEx4(pszAsUser, pszPassword);
859 if (pszAsUser)
860 tstRTCreateProcEx5(pszAsUser, pszPassword);
861 tstRTCreateProcEx6(pszAsUser, pszPassword);
862 tstRTCreateProcExCwd(pszAsUser, pszPassword);
863
864 /** @todo Cover files, ++ */
865
866 RTEnvDestroy(g_hEnvInitial);
867
868 /*
869 * Summary.
870 */
871 return RTTestSummaryAndDestroy(hTest);
872}
873
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette