VirtualBox

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

Last change on this file since 99145 was 99145, checked in by vboxsync, 2 years ago

IPRT/process: Bugfixes for testcases for RTPROC_FLAGS_CWD. bugref:8053

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

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