VirtualBox

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

Last change on this file since 100838 was 99486, checked in by vboxsync, 20 months ago

IPRT/testcase: Fixed a leak in tstRTProcCreateEx found by ASAN.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.4 KB
Line 
1/* $Id: tstRTProcCreateEx.cpp 99486 2023-04-20 12:51:40Z 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 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 RTEnvDestroy(hEnvCur);
504}
505
506
507static int tstRTCreateProcEx5Child(int argc, char **argv)
508{
509 int rc = RTR3InitExe(argc, &argv, 0);
510 if (RT_FAILURE(rc))
511 return RTMsgInitFailure(rc);
512
513 uint32_t cErrors = 0;
514
515 /* Check that the OS thinks we're running as the user we're supposed to. */
516 char *pszUser;
517 rc = RTProcQueryUsernameA(NIL_RTPROCESS, &pszUser);
518 if (RT_SUCCESS(rc))
519 {
520#ifdef RT_OS_WINDOWS
521 if (RTStrICmp(pszUser, argv[2]) != 0)
522#else
523 if (RTStrCmp(pszUser, argv[2]) != 0)
524#endif
525 {
526 RTStrmPrintf(g_pStdErr, "child4: user name is '%s', expected '%s'\n", pszUser, argv[2]);
527 cErrors++;
528 }
529 RTStrFree(pszUser);
530 }
531 else
532 {
533 RTStrmPrintf(g_pStdErr, "child4: RTProcQueryUsernameA failed: %Rrc\n", rc);
534 cErrors++;
535 }
536
537 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
538}
539
540static void tstRTCreateProcEx5(const char *pszUser, const char *pszPassword)
541{
542 RTTestISubF("As user \"%s\" with password \"%s\"", pszUser, pszPassword);
543 RTTESTI_CHECK_RETV(pszUser && *pszUser);
544
545 const char * apszArgs[] =
546 {
547 "test", /* user name */
548 "--testcase-child-5",
549 pszUser,
550 NULL
551 };
552
553 /* Test for invalid logons. */
554 RTPROCESS hProc;
555 int rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL, NULL, NULL,
556 "non-existing-user", "wrong-password", NULL, &hProc);
557 if (rc != VERR_AUTHENTICATION_FAILURE && rc != VERR_PRIVILEGE_NOT_HELD && rc != VERR_PROC_TCB_PRIV_NOT_HELD)
558 RTTestIFailed("rc=%Rrc", rc);
559
560 /* Test for invalid application. */
561 RTTESTI_CHECK_RC(RTProcCreateEx("non-existing-app", apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
562 NULL, NULL, NULL, NULL, NULL, &hProc), VERR_FILE_NOT_FOUND);
563
564 /* Test a (hopefully) valid user/password logon (given by parameters of this function). */
565 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
566 NULL, NULL, pszUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
567 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
568 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
569
570 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
571 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
572}
573
574
575static int tstRTCreateProcEx4Child(int argc, char **argv)
576{
577 int rc = RTR3InitExeNoArguments(0);
578 if (RT_FAILURE(rc))
579 return RTMsgInitFailure(rc);
580
581 int cErrors = 0;
582 for (int i = 0; i < argc; i++)
583 if (strcmp(argv[i], g_apszArgs4[i]))
584 {
585 RTStrmPrintf(g_pStdErr,
586 "child4: argv[%2u]='%s'\n"
587 "child4: expected='%s'\n",
588 i, argv[i], g_apszArgs4[i]);
589 cErrors++;
590 }
591
592 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
593}
594
595static void tstRTCreateProcEx4(const char *pszAsUser, const char *pszPassword)
596{
597 RTTestISub("Argument with spaces and stuff");
598
599 RTPROCESS hProc;
600 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, g_apszArgs4, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
601 NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
602 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
603 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
604
605 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
606 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
607}
608
609
610static int tstRTCreateProcEx3Child(void)
611{
612 int rc = RTR3InitExeNoArguments(0);
613 if (RT_FAILURE(rc))
614 return RTMsgInitFailure(rc);
615
616 RTStrmPrintf(g_pStdOut, "w"); RTStrmFlush(g_pStdOut);
617 RTStrmPrintf(g_pStdErr, "o"); RTStrmFlush(g_pStdErr);
618 RTStrmPrintf(g_pStdOut, "r"); RTStrmFlush(g_pStdOut);
619 RTStrmPrintf(g_pStdErr, "k"); RTStrmFlush(g_pStdErr);
620 RTStrmPrintf(g_pStdOut, "s");
621
622 return RTEXITCODE_SUCCESS;
623}
624
625static void tstRTCreateProcEx3(const char *pszAsUser, const char *pszPassword)
626{
627 RTTestISub("Standard Out+Err");
628
629 RTPIPE hPipeR, hPipeW;
630 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
631 const char * apszArgs[3] =
632 {
633 "non-existing-non-executable-file",
634 "--testcase-child-3",
635 NULL
636 };
637 RTHANDLE Handle;
638 Handle.enmType = RTHANDLETYPE_PIPE;
639 Handle.u.hPipe = hPipeW;
640 RTPROCESS hProc;
641 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
642 &Handle, &Handle, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
643 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
644
645 char szOutput[_4K];
646 size_t offOutput = 0;
647 for (;;)
648 {
649 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
650 RTTESTI_CHECK(cbLeft > 0);
651 if (cbLeft == 0)
652 break;
653
654 size_t cbRead;
655 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
656 if (RT_FAILURE(rc))
657 {
658 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
659 break;
660 }
661 offOutput += cbRead;
662 }
663 szOutput[offOutput] = '\0';
664 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
665
666 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
667 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
668 RTThreadSleep(10);
669
670 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
671 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
672 else if ( offOutput != sizeof("works") - 1
673 || strcmp(szOutput, "works"))
674 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
675}
676
677
678static int tstRTCreateProcEx2Child(void)
679{
680 int rc = RTR3InitExeNoArguments(0);
681 if (RT_FAILURE(rc))
682 return RTMsgInitFailure(rc);
683
684 RTStrmPrintf(g_pStdErr, "howdy");
685 RTStrmPrintf(g_pStdOut, "ignore this output\n");
686
687 return RTEXITCODE_SUCCESS;
688}
689
690static void tstRTCreateProcEx2(const char *pszAsUser, const char *pszPassword)
691{
692 RTTestISub("Standard Err");
693
694 RTPIPE hPipeR, hPipeW;
695 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
696 const char * apszArgs[3] =
697 {
698 "non-existing-non-executable-file",
699 "--testcase-child-2",
700 NULL
701 };
702 RTHANDLE Handle;
703 Handle.enmType = RTHANDLETYPE_PIPE;
704 Handle.u.hPipe = hPipeW;
705 RTPROCESS hProc;
706 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
707 NULL, &Handle, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
708 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
709
710 char szOutput[_4K];
711 size_t offOutput = 0;
712 for (;;)
713 {
714 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
715 RTTESTI_CHECK(cbLeft > 0);
716 if (cbLeft == 0)
717 break;
718
719 size_t cbRead;
720 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
721 if (RT_FAILURE(rc))
722 {
723 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
724 break;
725 }
726 offOutput += cbRead;
727 }
728 szOutput[offOutput] = '\0';
729 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
730
731 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
732 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
733 RTThreadSleep(10);
734
735 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
736 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
737 else if ( offOutput != sizeof("howdy") - 1
738 || strcmp(szOutput, "howdy"))
739 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
740}
741
742
743static int tstRTCreateProcEx1Child(void)
744{
745 int rc = RTR3InitExeNoArguments(0);
746 if (RT_FAILURE(rc))
747 return RTMsgInitFailure(rc);
748
749 RTPrintf("it works");
750 RTStrmPrintf(g_pStdErr, "ignore this output\n");
751
752 return RTEXITCODE_SUCCESS;
753}
754
755
756static void tstRTCreateProcEx1(const char *pszAsUser, const char *pszPassword)
757{
758 RTTestISub("Standard Out");
759
760 RTPIPE hPipeR, hPipeW;
761 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
762 const char * apszArgs[3] =
763 {
764 "non-existing-non-executable-file",
765 "--testcase-child-1",
766 NULL
767 };
768 RTHANDLE Handle;
769 Handle.enmType = RTHANDLETYPE_PIPE;
770 Handle.u.hPipe = hPipeW;
771 RTPROCESS hProc;
772 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
773 &Handle, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
774 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
775
776 char szOutput[_4K];
777 size_t offOutput = 0;
778 for (;;)
779 {
780 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
781 RTTESTI_CHECK(cbLeft > 0);
782 if (cbLeft == 0)
783 break;
784
785 size_t cbRead;
786 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
787 if (RT_FAILURE(rc))
788 {
789 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
790 break;
791 }
792 offOutput += cbRead;
793 }
794 szOutput[offOutput] = '\0';
795 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
796
797 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
798 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
799
800 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
801 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
802 else if ( offOutput != sizeof("it works") - 1
803 || strcmp(szOutput, "it works"))
804 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
805}
806
807
808int main(int argc, char **argv)
809{
810 /*
811 * Deal with child processes first.
812 */
813 if (argc == 2 && !strcmp(argv[1], "--testcase-child-1"))
814 return tstRTCreateProcEx1Child();
815 if (argc == 2 && !strcmp(argv[1], "--testcase-child-2"))
816 return tstRTCreateProcEx2Child();
817 if (argc == 2 && !strcmp(argv[1], "--testcase-child-3"))
818 return tstRTCreateProcEx3Child();
819 if (argc >= 5 && !strcmp(argv[1], "--testcase-child-4"))
820 return tstRTCreateProcEx4Child(argc, argv);
821 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-5"))
822 return tstRTCreateProcEx5Child(argc, argv);
823 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-6"))
824 return tstRTCreateProcEx6Child(argc, argv);
825 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-cwd"))
826 return tstRTCreateProcExCwdChild(argc, argv);
827
828 /*
829 * Main process.
830 */
831 const char *pszAsUser = NULL;
832 const char *pszPassword = NULL;
833 if (argc != 1)
834 {
835 if (argc != 4 || strcmp(argv[1], "--as-user"))
836 return 99;
837 pszAsUser = argv[2];
838 pszPassword = argv[3];
839 }
840
841 RTTEST hTest;
842 int rc = RTTestInitAndCreate("tstRTProcCreateEx", &hTest);
843 if (rc)
844 return rc;
845 RTTestBanner(hTest);
846
847 /*
848 * Init globals.
849 */
850 if (!RTProcGetExecutablePath(g_szExecName, sizeof(g_szExecName)))
851 RTStrCopy(g_szExecName, sizeof(g_szExecName), argv[0]);
852 RTTESTI_CHECK_RC(RTEnvClone(&g_hEnvInitial, RTENV_DEFAULT), VINF_SUCCESS);
853
854 /*
855 * The tests.
856 */
857 tstRTCreateProcEx1(pszAsUser, pszPassword);
858 tstRTCreateProcEx2(pszAsUser, pszPassword);
859 tstRTCreateProcEx3(pszAsUser, pszPassword);
860 tstRTCreateProcEx4(pszAsUser, pszPassword);
861 if (pszAsUser)
862 tstRTCreateProcEx5(pszAsUser, pszPassword);
863 tstRTCreateProcEx6(pszAsUser, pszPassword);
864 tstRTCreateProcExCwd(pszAsUser, pszPassword);
865
866 /** @todo Cover files, ++ */
867
868 RTEnvDestroy(g_hEnvInitial);
869
870 /*
871 * Summary.
872 */
873 return RTTestSummaryAndDestroy(hTest);
874}
875
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