VirtualBox

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

Last change on this file since 99370 was 99151, checked in by vboxsync, 23 months ago

IPRT/testcase: Always resolve the real paths before passing them to the child process. bugref:8053

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.4 KB
Line 
1/* $Id: tstRTProcCreateEx.cpp 99151 2023-03-23 18:02:50Z 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.virtualbox.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 /* Validate if we really are in the CWD the parent told us. */
110 char szCWD[RTPATH_MAX];
111 rc = RTPathGetCurrent(szCWD, sizeof(szCWD));
112 if (RT_FAILURE(rc))
113 {
114 RTStrmPrintf(g_pStdErr, "childcwd: Unable to retrieve CWD, rc=%Rrc\n", rc);
115 cErrors++;
116 }
117 else
118 {
119 if (RTStrCmp(szCWD, pszCWD))
120 {
121 RTStrmPrintf(g_pStdErr, "childcwd: CWD is '%s', but expected '%s'\n", szCWD, pszCWD);
122 cErrors++;
123 }
124 else
125 {
126 /* Check if we can query information of the current CWD. */
127 char *pszUser = NULL;
128 if ( argc >= 4
129 && argv[3][0] != '\0')
130 {
131 pszUser = argv[3];
132 }
133
134 RTFSOBJINFO objInfo;
135 rc = RTPathQueryInfo(szCWD, &objInfo, RTFSOBJATTRADD_NOTHING);
136 if (pszUser)
137 RTStrmPrintf(g_pStdOut, "childcwd: Accessing CWD '%s' via user '%s' -> %Rrc\n", szCWD, pszUser, rc);
138 else
139 RTStrmPrintf(g_pStdOut, "childcwd: Accesing CWD '%s' -> %Rrc\n", szCWD, rc);
140 if (RT_FAILURE(rc))
141 cErrors++;
142 }
143 }
144
145 RTStrmPrintf(g_pStdOut, "childcwd: Exiting (%d errors)\n", cErrors);
146 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
147}
148
149static void tstRTCreateProcExCwd(const char *pszAsUser, const char *pszPassword)
150{
151 RTTestISub("Current working directory (CWD)");
152
153 const char *apszArgs[5] =
154 {
155 g_szExecName,
156 "--testcase-child-cwd",
157 "<invalid-cwd>",
158 pszAsUser,
159 NULL
160 };
161
162 bool const fMayPanic = RTAssertSetMayPanic(false);
163 bool const fQuiet = RTAssertSetQuiet(true);
164
165 RTPROCESS hProc;
166 uint32_t fFlags = 0;
167 /* Missing RTPROC_FLAGS_CWD. */
168 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
169 NULL, NULL, NULL, pszAsUser, pszPassword,
170 (void *)apszArgs[2] /* pvExtraData (CWD) */, &hProc),
171 VERR_INVALID_PARAMETER);
172
173 /* RTPROC_FLAGS_CWD set, but CWD missing as pvExtradata. */
174 fFlags = RTPROC_FLAGS_CWD;
175 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
176 NULL, NULL, NULL, pszAsUser, pszPassword,
177 NULL, &hProc),
178 VINF_SUCCESS);
179
180 /* CWD is "<invalid-cwd>" from above, should fail. */
181 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
182 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
183
184 char szCWD[RTPATH_MAX];
185 char szResolved[RTPATH_MAX];
186
187 /* Try current CWD, whatever that is. */
188 RTTESTI_CHECK_RC_OK_RETV(RTPathGetCurrent(szCWD, sizeof(szCWD)));
189 RTTESTI_CHECK_RC_OK_RETV(RTPathReal(szCWD, szResolved, sizeof(szResolved)));
190 apszArgs[2] = szResolved;
191 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
192 NULL, NULL, NULL, pszAsUser, pszPassword,
193 (void *)szCWD /* pvExtraData (CWD) */, &hProc),
194 VINF_SUCCESS);
195 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
196 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
197 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
198
199 /* Try temporary directory. */
200 RTTESTI_CHECK_RC_OK_RETV(RTPathTemp(szCWD, sizeof(szCWD)));
201 RTTESTI_CHECK_RC_OK_RETV(RTPathReal(szCWD, szResolved, sizeof(szResolved)));
202 apszArgs[2] = szResolved;
203 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
204 NULL, NULL, NULL, pszAsUser, pszPassword,
205 (void *)szCWD /* pvExtraData (CWD) */, &hProc),
206 VINF_SUCCESS);
207 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
208 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
209 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
210
211 /* Try user home. */
212 RTTESTI_CHECK_RC_OK_RETV(RTPathUserHome(szCWD, sizeof(szCWD)));
213 RTTESTI_CHECK_RC_OK_RETV(RTPathReal(szCWD, szResolved, sizeof(szResolved)));
214 apszArgs[2] = szResolved;
215 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, fFlags,
216 NULL, NULL, NULL, pszAsUser, pszPassword,
217 (void *)szCWD /* pvExtraData (CWD) */, &hProc),
218 VINF_SUCCESS);
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 RTAssertSetMayPanic(fMayPanic);
224 RTAssertSetQuiet(fQuiet);
225}
226
227static int tstRTCreateProcEx6Child(int argc, char **argv)
228{
229 int rc = RTR3InitExeNoArguments(0);
230 if (RT_FAILURE(rc))
231 return RTMsgInitFailure(rc);
232
233 int cErrors = 0;
234 char szValue[_16K];
235
236 /*
237 * Check for the environment variable we've set in the parent process.
238 */
239 if (argc >= 3 && strcmp(argv[2], "inherit") == 0)
240 {
241 if (!RTEnvExistEx(RTENV_DEFAULT, "testcase-child-6"))
242 {
243 RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6' was not inherited from parent\n");
244 cErrors++;
245 }
246 }
247 else if (argc >= 3 && strstr(argv[2], "change-record") != NULL)
248 {
249 rc = RTEnvGetEx(RTENV_DEFAULT, "testcase-child-6", szValue, sizeof(szValue), NULL);
250 if (RT_SUCCESS(rc) && strcmp(szValue, "changed"))
251 {
252 RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6'='%s', expected 'changed'.\n", szValue);
253 cErrors++;
254 }
255 else if (RT_FAILURE(rc))
256 {
257 RTStrmPrintf(g_pStdErr, "child6: RTEnvGetEx(,'testcase-child-6',,) -> %Rrc\n", rc);
258 cErrors++;
259 }
260 }
261 else
262 {
263 if (RTEnvExistEx(RTENV_DEFAULT, "testcase-child-6"))
264 {
265 RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6' was inherited from parent\n");
266 cErrors++;
267 }
268 }
269
270 /*
271 * Check the user name if present we didn't inherit from parent.
272 */
273 if ( argc >= 4
274 && argv[3][0] != '\0'
275 && strstr(argv[2], "noinherit") != NULL)
276 {
277 static struct
278 {
279 const char *pszVarNm;
280 bool fReq;
281 } const s_aVars[] =
282 {
283#ifdef RT_OS_WINDOWS
284 { "USERNAME", true },
285#else
286 { "LOGNAME", true },
287 { "USER", false },
288#endif
289 };
290 for (unsigned i = 0; i < RT_ELEMENTS(s_aVars); i++)
291 {
292 rc = RTEnvGetEx(RTENV_DEFAULT, s_aVars[i].pszVarNm, szValue, sizeof(szValue), NULL);
293 if (RT_SUCCESS(rc))
294 {
295 if (strcmp(szValue, argv[3]))
296 {
297 RTStrmPrintf(g_pStdErr, "child6: env.var. '%s'='%s', expected '%s'\n",
298 s_aVars[i].pszVarNm, szValue, argv[3]);
299 cErrors++;
300 }
301 }
302 else if (rc != VERR_ENV_VAR_NOT_FOUND || s_aVars[i].fReq)
303 {
304 RTStrmPrintf(g_pStdErr, "child6: RTGetEnv('%s') -> %Rrc\n", s_aVars[i].pszVarNm, rc);
305 cErrors++;
306 }
307 }
308 }
309
310#if 1
311 /* For manual testing. */
312 if (strcmp(argv[2],"noinherit") == 0)
313 //if (strcmp(argv[2],"noinherit-change-record") == 0)
314 {
315 RTENV hEnv;
316 rc = RTEnvClone(&hEnv, RTENV_DEFAULT);
317 if (RT_SUCCESS(rc))
318 {
319 uint32_t cVars = RTEnvCountEx(hEnv);
320 for (uint32_t i = 0; i < cVars; i++)
321 {
322 char szVarNm[_1K];
323 rc = RTEnvGetByIndexEx(hEnv, i, szVarNm, sizeof(szVarNm), szValue, sizeof(szValue));
324 if (RT_SUCCESS(rc))
325 RTStrmPrintf(g_pStdErr, "child6: #%u: %s=%s\n", i, szVarNm, szValue);
326 else
327 {
328 RTStrmPrintf(g_pStdErr, "child6: #%u: %Rrc\n", i, rc);
329 cErrors++;
330 }
331 }
332 RTEnvDestroy(hEnv);
333 }
334 else
335 {
336 RTStrmPrintf(g_pStdErr, "child6: RTEnvClone failed: %Rrc\n", rc);
337 cErrors++;
338 }
339 }
340#endif
341
342 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
343}
344
345static void tstRTCreateProcEx6(const char *pszAsUser, const char *pszPassword)
346{
347 RTTestISub("Profile environment");
348
349 const char *apszArgs[5] =
350 {
351 g_szExecName,
352 "--testcase-child-6",
353 "inherit",
354 pszAsUser,
355 NULL
356 };
357
358 RTTESTI_CHECK_RC_RETV(RTEnvSetEx(RTENV_DEFAULT, "testcase-child-6", "true"), VINF_SUCCESS);
359
360 /* Use the process environment first. */
361 RTPROCESS hProc;
362 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/,
363 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
364 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
365 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
366
367 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
368 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
369
370 /* Use the process environment first with a little change. */
371 apszArgs[2] = "change-record";
372 RTENV hEnvChange;
373 RTTESTI_CHECK_RC_RETV(RTEnvCreateChangeRecord(&hEnvChange), VINF_SUCCESS);
374 RTTESTI_CHECK_RC_RETV(RTEnvSetEx(hEnvChange, "testcase-child-6", "changed"), VINF_SUCCESS);
375 int rc;
376 RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, hEnvChange, RTPROC_FLAGS_ENV_CHANGE_RECORD,
377 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
378 if (RT_SUCCESS(rc))
379 {
380 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
381 ProcStatus.iStatus = -1;
382 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
383
384 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
385 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
386 }
387
388
389 /* Use profile environment this time. */
390 apszArgs[2] = "noinherit";
391 RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, RTPROC_FLAGS_PROFILE,
392 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
393 if (RT_SUCCESS(rc))
394 {
395 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
396 ProcStatus.iStatus = -1;
397 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
398
399 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
400 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
401 }
402
403 /* Use profile environment this time. */
404 apszArgs[2] = "noinherit-change-record";
405 RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, hEnvChange,
406 RTPROC_FLAGS_PROFILE | RTPROC_FLAGS_ENV_CHANGE_RECORD,
407 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
408 if (RT_SUCCESS(rc))
409 {
410 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
411 ProcStatus.iStatus = -1;
412 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
413
414 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
415 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
416 }
417
418
419 RTTESTI_CHECK_RC(RTEnvDestroy(hEnvChange), VINF_SUCCESS);
420
421 /*
422 * Restore the environment and check that the PROFILE flag didn't mess with
423 * the process environment. (Note! The bug may be elsewhere as well.)
424 */
425 RTTESTI_CHECK_RC(RTEnvUnsetEx(RTENV_DEFAULT, "testcase-child-6"), VINF_SUCCESS);
426
427 RTENV hEnvCur;
428 RTTESTI_CHECK_RC_RETV(RTEnvClone(&hEnvCur, RTENV_DEFAULT), VINF_SUCCESS);
429 uint32_t cCurrent = RTEnvCountEx(hEnvCur);
430 uint32_t cInitial = RTEnvCountEx(g_hEnvInitial);
431 RTTESTI_CHECK_MSG(cCurrent == cInitial, ("cCurrent=%u cInitial=%u\n", cCurrent, cInitial));
432 uint32_t cVars1;
433 RTENV hEnv1, hEnv2;
434 const char *pszEnv1, *pszEnv2;
435 if (cCurrent >= cInitial)
436 {
437 hEnv1 = hEnvCur;
438 pszEnv1 = "current";
439 cVars1 = cCurrent;
440 hEnv2 = g_hEnvInitial;
441 pszEnv2 = "initial";
442 }
443 else
444 {
445 hEnv2 = hEnvCur;
446 pszEnv2 = "current";
447 hEnv1 = g_hEnvInitial;
448 pszEnv1 = "initial";
449 cVars1 = cInitial;
450 }
451 for (uint32_t i = 0; i < cVars1; i++)
452 {
453 char szValue1[_16K];
454 char szVarNm[_1K];
455 rc = RTEnvGetByIndexEx(hEnv1, i, szVarNm, sizeof(szVarNm), szValue1, sizeof(szValue1));
456 if (RT_SUCCESS(rc))
457 {
458 char szValue2[_16K];
459 rc = RTEnvGetEx(hEnv2, szVarNm, szValue2, sizeof(szValue2), NULL);
460 if (RT_SUCCESS(rc))
461 {
462 if (strcmp(szValue1, szValue2) != 0)
463 {
464 RTTestIFailed("Variable '%s' differs", szVarNm);
465 RTTestIFailureDetails("%s: '%s'\n"
466 "%s: '%s'\n",
467 pszEnv1, szValue1,
468 pszEnv2, szValue2);
469 }
470 }
471 else
472 RTTestIFailed("RTEnvGetEx(%s,%s,,) failed: %Rrc", pszEnv2, szVarNm, rc);
473
474 }
475 else
476 RTTestIFailed("RTEnvGetByIndexEx(%s,%u,,,,) failed: %Rrc", pszEnv1, i, rc);
477 }
478}
479
480
481static int tstRTCreateProcEx5Child(int argc, char **argv)
482{
483 int rc = RTR3InitExe(argc, &argv, 0);
484 if (RT_FAILURE(rc))
485 return RTMsgInitFailure(rc);
486
487 uint32_t cErrors = 0;
488
489 /* Check that the OS thinks we're running as the user we're supposed to. */
490 char *pszUser;
491 rc = RTProcQueryUsernameA(NIL_RTPROCESS, &pszUser);
492 if (RT_SUCCESS(rc))
493 {
494#ifdef RT_OS_WINDOWS
495 if (RTStrICmp(pszUser, argv[2]) != 0)
496#else
497 if (RTStrCmp(pszUser, argv[2]) != 0)
498#endif
499 {
500 RTStrmPrintf(g_pStdErr, "child4: user name is '%s', expected '%s'\n", pszUser, argv[2]);
501 cErrors++;
502 }
503 RTStrFree(pszUser);
504 }
505 else
506 {
507 RTStrmPrintf(g_pStdErr, "child4: RTProcQueryUsernameA failed: %Rrc\n", rc);
508 cErrors++;
509 }
510
511 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
512}
513
514static void tstRTCreateProcEx5(const char *pszUser, const char *pszPassword)
515{
516 RTTestISubF("As user \"%s\" with password \"%s\"", pszUser, pszPassword);
517 RTTESTI_CHECK_RETV(pszUser && *pszUser);
518
519 const char * apszArgs[] =
520 {
521 "test", /* user name */
522 "--testcase-child-5",
523 pszUser,
524 NULL
525 };
526
527 /* Test for invalid logons. */
528 RTPROCESS hProc;
529 int rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL, NULL, NULL,
530 "non-existing-user", "wrong-password", NULL, &hProc);
531 if (rc != VERR_AUTHENTICATION_FAILURE && rc != VERR_PRIVILEGE_NOT_HELD && rc != VERR_PROC_TCB_PRIV_NOT_HELD)
532 RTTestIFailed("rc=%Rrc", rc);
533
534 /* Test for invalid application. */
535 RTTESTI_CHECK_RC(RTProcCreateEx("non-existing-app", apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
536 NULL, NULL, NULL, NULL, NULL, &hProc), VERR_FILE_NOT_FOUND);
537
538 /* Test a (hopefully) valid user/password logon (given by parameters of this function). */
539 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
540 NULL, NULL, pszUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
541 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
542 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
543
544 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
545 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
546}
547
548
549static int tstRTCreateProcEx4Child(int argc, char **argv)
550{
551 int rc = RTR3InitExeNoArguments(0);
552 if (RT_FAILURE(rc))
553 return RTMsgInitFailure(rc);
554
555 int cErrors = 0;
556 for (int i = 0; i < argc; i++)
557 if (strcmp(argv[i], g_apszArgs4[i]))
558 {
559 RTStrmPrintf(g_pStdErr,
560 "child4: argv[%2u]='%s'\n"
561 "child4: expected='%s'\n",
562 i, argv[i], g_apszArgs4[i]);
563 cErrors++;
564 }
565
566 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
567}
568
569static void tstRTCreateProcEx4(const char *pszAsUser, const char *pszPassword)
570{
571 RTTestISub("Argument with spaces and stuff");
572
573 RTPROCESS hProc;
574 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, g_apszArgs4, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
575 NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
576 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
577 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
578
579 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
580 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
581}
582
583
584static int tstRTCreateProcEx3Child(void)
585{
586 int rc = RTR3InitExeNoArguments(0);
587 if (RT_FAILURE(rc))
588 return RTMsgInitFailure(rc);
589
590 RTStrmPrintf(g_pStdOut, "w"); RTStrmFlush(g_pStdOut);
591 RTStrmPrintf(g_pStdErr, "o"); RTStrmFlush(g_pStdErr);
592 RTStrmPrintf(g_pStdOut, "r"); RTStrmFlush(g_pStdOut);
593 RTStrmPrintf(g_pStdErr, "k"); RTStrmFlush(g_pStdErr);
594 RTStrmPrintf(g_pStdOut, "s");
595
596 return RTEXITCODE_SUCCESS;
597}
598
599static void tstRTCreateProcEx3(const char *pszAsUser, const char *pszPassword)
600{
601 RTTestISub("Standard Out+Err");
602
603 RTPIPE hPipeR, hPipeW;
604 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
605 const char * apszArgs[3] =
606 {
607 "non-existing-non-executable-file",
608 "--testcase-child-3",
609 NULL
610 };
611 RTHANDLE Handle;
612 Handle.enmType = RTHANDLETYPE_PIPE;
613 Handle.u.hPipe = hPipeW;
614 RTPROCESS hProc;
615 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
616 &Handle, &Handle, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
617 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
618
619 char szOutput[_4K];
620 size_t offOutput = 0;
621 for (;;)
622 {
623 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
624 RTTESTI_CHECK(cbLeft > 0);
625 if (cbLeft == 0)
626 break;
627
628 size_t cbRead;
629 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
630 if (RT_FAILURE(rc))
631 {
632 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
633 break;
634 }
635 offOutput += cbRead;
636 }
637 szOutput[offOutput] = '\0';
638 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
639
640 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
641 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
642 RTThreadSleep(10);
643
644 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
645 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
646 else if ( offOutput != sizeof("works") - 1
647 || strcmp(szOutput, "works"))
648 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
649}
650
651
652static int tstRTCreateProcEx2Child(void)
653{
654 int rc = RTR3InitExeNoArguments(0);
655 if (RT_FAILURE(rc))
656 return RTMsgInitFailure(rc);
657
658 RTStrmPrintf(g_pStdErr, "howdy");
659 RTStrmPrintf(g_pStdOut, "ignore this output\n");
660
661 return RTEXITCODE_SUCCESS;
662}
663
664static void tstRTCreateProcEx2(const char *pszAsUser, const char *pszPassword)
665{
666 RTTestISub("Standard Err");
667
668 RTPIPE hPipeR, hPipeW;
669 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
670 const char * apszArgs[3] =
671 {
672 "non-existing-non-executable-file",
673 "--testcase-child-2",
674 NULL
675 };
676 RTHANDLE Handle;
677 Handle.enmType = RTHANDLETYPE_PIPE;
678 Handle.u.hPipe = hPipeW;
679 RTPROCESS hProc;
680 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
681 NULL, &Handle, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
682 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
683
684 char szOutput[_4K];
685 size_t offOutput = 0;
686 for (;;)
687 {
688 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
689 RTTESTI_CHECK(cbLeft > 0);
690 if (cbLeft == 0)
691 break;
692
693 size_t cbRead;
694 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
695 if (RT_FAILURE(rc))
696 {
697 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
698 break;
699 }
700 offOutput += cbRead;
701 }
702 szOutput[offOutput] = '\0';
703 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
704
705 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
706 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
707 RTThreadSleep(10);
708
709 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
710 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
711 else if ( offOutput != sizeof("howdy") - 1
712 || strcmp(szOutput, "howdy"))
713 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
714}
715
716
717static int tstRTCreateProcEx1Child(void)
718{
719 int rc = RTR3InitExeNoArguments(0);
720 if (RT_FAILURE(rc))
721 return RTMsgInitFailure(rc);
722
723 RTPrintf("it works");
724 RTStrmPrintf(g_pStdErr, "ignore this output\n");
725
726 return RTEXITCODE_SUCCESS;
727}
728
729
730static void tstRTCreateProcEx1(const char *pszAsUser, const char *pszPassword)
731{
732 RTTestISub("Standard Out");
733
734 RTPIPE hPipeR, hPipeW;
735 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
736 const char * apszArgs[3] =
737 {
738 "non-existing-non-executable-file",
739 "--testcase-child-1",
740 NULL
741 };
742 RTHANDLE Handle;
743 Handle.enmType = RTHANDLETYPE_PIPE;
744 Handle.u.hPipe = hPipeW;
745 RTPROCESS hProc;
746 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
747 &Handle, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
748 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
749
750 char szOutput[_4K];
751 size_t offOutput = 0;
752 for (;;)
753 {
754 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
755 RTTESTI_CHECK(cbLeft > 0);
756 if (cbLeft == 0)
757 break;
758
759 size_t cbRead;
760 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
761 if (RT_FAILURE(rc))
762 {
763 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
764 break;
765 }
766 offOutput += cbRead;
767 }
768 szOutput[offOutput] = '\0';
769 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
770
771 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
772 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
773
774 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
775 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
776 else if ( offOutput != sizeof("it works") - 1
777 || strcmp(szOutput, "it works"))
778 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
779}
780
781
782int main(int argc, char **argv)
783{
784 /*
785 * Deal with child processes first.
786 */
787 if (argc == 2 && !strcmp(argv[1], "--testcase-child-1"))
788 return tstRTCreateProcEx1Child();
789 if (argc == 2 && !strcmp(argv[1], "--testcase-child-2"))
790 return tstRTCreateProcEx2Child();
791 if (argc == 2 && !strcmp(argv[1], "--testcase-child-3"))
792 return tstRTCreateProcEx3Child();
793 if (argc >= 5 && !strcmp(argv[1], "--testcase-child-4"))
794 return tstRTCreateProcEx4Child(argc, argv);
795 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-5"))
796 return tstRTCreateProcEx5Child(argc, argv);
797 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-6"))
798 return tstRTCreateProcEx6Child(argc, argv);
799 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-cwd"))
800 return tstRTCreateProcExCwdChild(argc, argv);
801
802 /*
803 * Main process.
804 */
805 const char *pszAsUser = NULL;
806 const char *pszPassword = NULL;
807 if (argc != 1)
808 {
809 if (argc != 4 || strcmp(argv[1], "--as-user"))
810 return 99;
811 pszAsUser = argv[2];
812 pszPassword = argv[3];
813 }
814
815 RTTEST hTest;
816 int rc = RTTestInitAndCreate("tstRTProcCreateEx", &hTest);
817 if (rc)
818 return rc;
819 RTTestBanner(hTest);
820
821 /*
822 * Init globals.
823 */
824 if (!RTProcGetExecutablePath(g_szExecName, sizeof(g_szExecName)))
825 RTStrCopy(g_szExecName, sizeof(g_szExecName), argv[0]);
826 RTTESTI_CHECK_RC(RTEnvClone(&g_hEnvInitial, RTENV_DEFAULT), VINF_SUCCESS);
827
828 /*
829 * The tests.
830 */
831 tstRTCreateProcEx1(pszAsUser, pszPassword);
832 tstRTCreateProcEx2(pszAsUser, pszPassword);
833 tstRTCreateProcEx3(pszAsUser, pszPassword);
834 tstRTCreateProcEx4(pszAsUser, pszPassword);
835 if (pszAsUser)
836 tstRTCreateProcEx5(pszAsUser, pszPassword);
837 tstRTCreateProcEx6(pszAsUser, pszPassword);
838 tstRTCreateProcExCwd(pszAsUser, pszPassword);
839
840 /** @todo Cover files, ++ */
841
842 RTEnvDestroy(g_hEnvInitial);
843
844 /*
845 * Summary.
846 */
847 return RTTestSummaryAndDestroy(hTest);
848}
849
Note: See TracBrowser for help on using the repository browser.

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