VirtualBox

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

Last change on this file since 83743 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.5 KB
Line 
1/* $Id: tstRTProcCreateEx.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTProcCreateEx.
4 */
5
6/*
7 * Copyright (C) 2010-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/process.h>
32
33#include <iprt/assert.h>
34#include <iprt/env.h>
35#include <iprt/err.h>
36#include <iprt/initterm.h>
37#include <iprt/mem.h>
38#include <iprt/message.h>
39#include <iprt/param.h>
40#include <iprt/pipe.h>
41#include <iprt/string.h>
42#include <iprt/stream.h>
43#include <iprt/test.h>
44#include <iprt/thread.h>
45
46#ifdef RT_OS_WINDOWS
47# define SECURITY_WIN32
48# include <iprt/win/windows.h>
49# include <Security.h>
50#endif
51
52
53/*********************************************************************************************************************************
54* Global Variables *
55*********************************************************************************************************************************/
56static RTENV g_hEnvInitial = NIL_RTENV;
57static char g_szExecName[RTPATH_MAX];
58
59
60static const char * const g_apszArgs4[] =
61{
62 /* 0 */ "non existing non executable file",
63 /* 1 */ "--testcase-child-4",
64 /* 2 */ "a b",
65 /* 3 */ " cdef",
66 /* 4 */ "ghijkl ",
67 /* 5 */ "\"",
68 /* 6 */ "\\",
69 /* 7 */ "\\\"",
70 /* 8 */ "\\\"\\",
71 /* 9 */ "\\\\\"\\",
72 /*10 */ "%TEMP%",
73 /*11 */ "%TEMP%\filename",
74 /*12 */ "%TEMP%postfix",
75 /*13 */ "Prefix%TEMP%postfix",
76 /*14 */ "%",
77 /*15 */ "%%",
78 /*16 */ "%%%",
79 /*17 */ "%X",
80 /*18 */ "%%X",
81 NULL
82};
83
84
85static int tstRTCreateProcEx6Child(int argc, char **argv)
86{
87 int rc = RTR3InitExeNoArguments(0);
88 if (RT_FAILURE(rc))
89 return RTMsgInitFailure(rc);
90
91 int cErrors = 0;
92 char szValue[_16K];
93
94 /*
95 * Check for the environment variable we've set in the parent process.
96 */
97 if (argc >= 3 && strcmp(argv[2], "inherit") == 0)
98 {
99 if (!RTEnvExistEx(RTENV_DEFAULT, "testcase-child-6"))
100 {
101 RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6' was not inherited from parent\n");
102 cErrors++;
103 }
104 }
105 else if (argc >= 3 && strstr(argv[2], "change-record") != NULL)
106 {
107 rc = RTEnvGetEx(RTENV_DEFAULT, "testcase-child-6", szValue, sizeof(szValue), NULL);
108 if (RT_SUCCESS(rc) && strcmp(szValue, "changed"))
109 {
110 RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6'='%s', expected 'changed'.\n", szValue);
111 cErrors++;
112 }
113 else if (RT_FAILURE(rc))
114 {
115 RTStrmPrintf(g_pStdErr, "child6: RTEnvGetEx(,'testcase-child-6',,) -> %Rrc\n", rc);
116 cErrors++;
117 }
118 }
119 else
120 {
121 if (RTEnvExistEx(RTENV_DEFAULT, "testcase-child-6"))
122 {
123 RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6' was inherited from parent\n");
124 cErrors++;
125 }
126 }
127
128 /*
129 * Check the user name if present we didn't inherit from parent.
130 */
131 if ( argc >= 4
132 && argv[3][0] != '\0'
133 && strstr(argv[2], "noinherit") != NULL)
134 {
135 static struct
136 {
137 const char *pszVarNm;
138 bool fReq;
139 } const s_aVars[] =
140 {
141#ifdef RT_OS_WINDOWS
142 { "USERNAME", true },
143#else
144 { "LOGNAME", true },
145 { "USER", false },
146#endif
147 };
148 for (unsigned i = 0; i < RT_ELEMENTS(s_aVars); i++)
149 {
150 rc = RTEnvGetEx(RTENV_DEFAULT, s_aVars[i].pszVarNm, szValue, sizeof(szValue), NULL);
151 if (RT_SUCCESS(rc))
152 {
153 if (strcmp(szValue, argv[3]))
154 {
155 RTStrmPrintf(g_pStdErr, "child6: env.var. '%s'='%s', expected '%s'\n",
156 s_aVars[i].pszVarNm, szValue, argv[3]);
157 cErrors++;
158 }
159 }
160 else if (rc != VERR_ENV_VAR_NOT_FOUND || s_aVars[i].fReq)
161 {
162 RTStrmPrintf(g_pStdErr, "child6: RTGetEnv('%s') -> %Rrc\n", s_aVars[i].pszVarNm, rc);
163 cErrors++;
164 }
165 }
166 }
167
168#if 1
169 /* For manual testing. */
170 if (strcmp(argv[2],"noinherit") == 0)
171 //if (strcmp(argv[2],"noinherit-change-record") == 0)
172 {
173 RTENV hEnv;
174 rc = RTEnvClone(&hEnv, RTENV_DEFAULT);
175 if (RT_SUCCESS(rc))
176 {
177 uint32_t cVars = RTEnvCountEx(hEnv);
178 for (uint32_t i = 0; i < cVars; i++)
179 {
180 char szVarNm[_1K];
181 rc = RTEnvGetByIndexEx(hEnv, i, szVarNm, sizeof(szVarNm), szValue, sizeof(szValue));
182 if (RT_SUCCESS(rc))
183 RTStrmPrintf(g_pStdErr, "child6: #%u: %s=%s\n", i, szVarNm, szValue);
184 else
185 {
186 RTStrmPrintf(g_pStdErr, "child6: #%u: %Rrc\n", i, rc);
187 cErrors++;
188 }
189 }
190 RTEnvDestroy(hEnv);
191 }
192 else
193 {
194 RTStrmPrintf(g_pStdErr, "child6: RTEnvClone failed: %Rrc\n", rc);
195 cErrors++;
196 }
197 }
198#endif
199
200 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
201}
202
203static void tstRTCreateProcEx6(const char *pszAsUser, const char *pszPassword)
204{
205 RTTestISub("Profile environment");
206
207 const char *apszArgs[5] =
208 {
209 g_szExecName,
210 "--testcase-child-6",
211 "inherit",
212 pszAsUser,
213 NULL
214 };
215
216 RTTESTI_CHECK_RC_RETV(RTEnvSetEx(RTENV_DEFAULT, "testcase-child-6", "true"), VINF_SUCCESS);
217
218 /* Use the process environment first. */
219 RTPROCESS hProc;
220 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/,
221 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
222 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
223 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
224
225 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
226 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
227
228 /* Use the process environment first with a little change. */
229 apszArgs[2] = "change-record";
230 RTENV hEnvChange;
231 RTTESTI_CHECK_RC_RETV(RTEnvCreateChangeRecord(&hEnvChange), VINF_SUCCESS);
232 RTTESTI_CHECK_RC_RETV(RTEnvSetEx(hEnvChange, "testcase-child-6", "changed"), VINF_SUCCESS);
233 int rc;
234 RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, hEnvChange, RTPROC_FLAGS_ENV_CHANGE_RECORD,
235 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
236 if (RT_SUCCESS(rc))
237 {
238 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
239 ProcStatus.iStatus = -1;
240 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
241
242 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
243 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
244 }
245
246
247 /* Use profile environment this time. */
248 apszArgs[2] = "noinherit";
249 RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, RTPROC_FLAGS_PROFILE,
250 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
251 if (RT_SUCCESS(rc))
252 {
253 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
254 ProcStatus.iStatus = -1;
255 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
256
257 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
258 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
259 }
260
261 /* Use profile environment this time. */
262 apszArgs[2] = "noinherit-change-record";
263 RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, hEnvChange,
264 RTPROC_FLAGS_PROFILE | RTPROC_FLAGS_ENV_CHANGE_RECORD,
265 NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
266 if (RT_SUCCESS(rc))
267 {
268 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
269 ProcStatus.iStatus = -1;
270 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
271
272 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
273 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
274 }
275
276
277 RTTESTI_CHECK_RC(RTEnvDestroy(hEnvChange), VINF_SUCCESS);
278
279 /*
280 * Restore the environment and check that the PROFILE flag didn't mess with
281 * the process environment. (Note! The bug may be elsewhere as well.)
282 */
283 RTTESTI_CHECK_RC(RTEnvUnsetEx(RTENV_DEFAULT, "testcase-child-6"), VINF_SUCCESS);
284
285 RTENV hEnvCur;
286 RTTESTI_CHECK_RC_RETV(RTEnvClone(&hEnvCur, RTENV_DEFAULT), VINF_SUCCESS);
287 uint32_t cCurrent = RTEnvCountEx(hEnvCur);
288 uint32_t cInitial = RTEnvCountEx(g_hEnvInitial);
289 RTTESTI_CHECK_MSG(cCurrent == cInitial, ("cCurrent=%u cInitial=%u\n", cCurrent, cInitial));
290 uint32_t cVars1;
291 RTENV hEnv1, hEnv2;
292 const char *pszEnv1, *pszEnv2;
293 if (cCurrent >= cInitial)
294 {
295 hEnv1 = hEnvCur;
296 pszEnv1 = "current";
297 cVars1 = cCurrent;
298 hEnv2 = g_hEnvInitial;
299 pszEnv2 = "initial";
300 }
301 else
302 {
303 hEnv2 = hEnvCur;
304 pszEnv2 = "current";
305 hEnv1 = g_hEnvInitial;
306 pszEnv1 = "initial";
307 cVars1 = cInitial;
308 }
309 for (uint32_t i = 0; i < cVars1; i++)
310 {
311 char szValue1[_16K];
312 char szVarNm[_1K];
313 rc = RTEnvGetByIndexEx(hEnv1, i, szVarNm, sizeof(szVarNm), szValue1, sizeof(szValue1));
314 if (RT_SUCCESS(rc))
315 {
316 char szValue2[_16K];
317 rc = RTEnvGetEx(hEnv2, szVarNm, szValue2, sizeof(szValue2), NULL);
318 if (RT_SUCCESS(rc))
319 {
320 if (strcmp(szValue1, szValue2) != 0)
321 {
322 RTTestIFailed("Variable '%s' differs", szVarNm);
323 RTTestIFailureDetails("%s: '%s'\n"
324 "%s: '%s'\n",
325 pszEnv1, szValue1,
326 pszEnv2, szValue2);
327 }
328 }
329 else
330 RTTestIFailed("RTEnvGetEx(%s,%s,,) failed: %Rrc", pszEnv2, szVarNm, rc);
331
332 }
333 else
334 RTTestIFailed("RTEnvGetByIndexEx(%s,%u,,,,) failed: %Rrc", pszEnv1, i, rc);
335 }
336}
337
338
339static int tstRTCreateProcEx5Child(int argc, char **argv)
340{
341 int rc = RTR3InitExe(argc, &argv, 0);
342 if (RT_FAILURE(rc))
343 return RTMsgInitFailure(rc);
344
345 uint32_t cErrors = 0;
346
347 /* Check that the OS thinks we're running as the user we're supposed to. */
348 char *pszUser;
349 rc = RTProcQueryUsernameA(NIL_RTPROCESS, &pszUser);
350 if (RT_SUCCESS(rc))
351 {
352#ifdef RT_OS_WINDOWS
353 if (RTStrICmp(pszUser, argv[2]) != 0)
354#else
355 if (RTStrCmp(pszUser, argv[2]) != 0)
356#endif
357 {
358 RTStrmPrintf(g_pStdErr, "child4: user name is '%s', expected '%s'\n", pszUser, argv[2]);
359 cErrors++;
360 }
361 RTStrFree(pszUser);
362 }
363 else
364 {
365 RTStrmPrintf(g_pStdErr, "child4: RTProcQueryUsernameA failed: %Rrc\n", rc);
366 cErrors++;
367 }
368
369 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
370}
371
372static void tstRTCreateProcEx5(const char *pszUser, const char *pszPassword)
373{
374 RTTestISubF("As user \"%s\" with password \"%s\"", pszUser, pszPassword);
375 RTTESTI_CHECK_RETV(pszUser && *pszUser);
376
377 const char * apszArgs[] =
378 {
379 "test", /* user name */
380 "--testcase-child-5",
381 pszUser,
382 NULL
383 };
384
385 /* Test for invalid logons. */
386 RTPROCESS hProc;
387 int rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL, NULL, NULL,
388 "non-existing-user", "wrong-password", NULL, &hProc);
389 if (rc != VERR_AUTHENTICATION_FAILURE && rc != VERR_PRIVILEGE_NOT_HELD && rc != VERR_PROC_TCB_PRIV_NOT_HELD)
390 RTTestIFailed("rc=%Rrc", rc);
391
392 /* Test for invalid application. */
393 RTTESTI_CHECK_RC(RTProcCreateEx("non-existing-app", apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
394 NULL, NULL, NULL, NULL, NULL, &hProc), VERR_FILE_NOT_FOUND);
395
396 /* Test a (hopefully) valid user/password logon (given by parameters of this function). */
397 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
398 NULL, NULL, pszUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
399 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
400 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
401
402 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
403 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
404}
405
406
407static int tstRTCreateProcEx4Child(int argc, char **argv)
408{
409 int rc = RTR3InitExeNoArguments(0);
410 if (RT_FAILURE(rc))
411 return RTMsgInitFailure(rc);
412
413 int cErrors = 0;
414 for (int i = 0; i < argc; i++)
415 if (strcmp(argv[i], g_apszArgs4[i]))
416 {
417 RTStrmPrintf(g_pStdErr,
418 "child4: argv[%2u]='%s'\n"
419 "child4: expected='%s'\n",
420 i, argv[i], g_apszArgs4[i]);
421 cErrors++;
422 }
423
424 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
425}
426
427static void tstRTCreateProcEx4(const char *pszAsUser, const char *pszPassword)
428{
429 RTTestISub("Argument with spaces and stuff");
430
431 RTPROCESS hProc;
432 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, g_apszArgs4, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
433 NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
434 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
435 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
436
437 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
438 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
439}
440
441
442static int tstRTCreateProcEx3Child(void)
443{
444 int rc = RTR3InitExeNoArguments(0);
445 if (RT_FAILURE(rc))
446 return RTMsgInitFailure(rc);
447
448 RTStrmPrintf(g_pStdOut, "w"); RTStrmFlush(g_pStdOut);
449 RTStrmPrintf(g_pStdErr, "o"); RTStrmFlush(g_pStdErr);
450 RTStrmPrintf(g_pStdOut, "r"); RTStrmFlush(g_pStdOut);
451 RTStrmPrintf(g_pStdErr, "k"); RTStrmFlush(g_pStdErr);
452 RTStrmPrintf(g_pStdOut, "s");
453
454 return RTEXITCODE_SUCCESS;
455}
456
457static void tstRTCreateProcEx3(const char *pszAsUser, const char *pszPassword)
458{
459 RTTestISub("Standard Out+Err");
460
461 RTPIPE hPipeR, hPipeW;
462 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
463 const char * apszArgs[3] =
464 {
465 "non-existing-non-executable-file",
466 "--testcase-child-3",
467 NULL
468 };
469 RTHANDLE Handle;
470 Handle.enmType = RTHANDLETYPE_PIPE;
471 Handle.u.hPipe = hPipeW;
472 RTPROCESS hProc;
473 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
474 &Handle, &Handle, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
475 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
476
477 char szOutput[_4K];
478 size_t offOutput = 0;
479 for (;;)
480 {
481 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
482 RTTESTI_CHECK(cbLeft > 0);
483 if (cbLeft == 0)
484 break;
485
486 size_t cbRead;
487 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
488 if (RT_FAILURE(rc))
489 {
490 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
491 break;
492 }
493 offOutput += cbRead;
494 }
495 szOutput[offOutput] = '\0';
496 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
497
498 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
499 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
500 RTThreadSleep(10);
501
502 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
503 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
504 else if ( offOutput != sizeof("works") - 1
505 || strcmp(szOutput, "works"))
506 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
507}
508
509
510static int tstRTCreateProcEx2Child(void)
511{
512 int rc = RTR3InitExeNoArguments(0);
513 if (RT_FAILURE(rc))
514 return RTMsgInitFailure(rc);
515
516 RTStrmPrintf(g_pStdErr, "howdy");
517 RTStrmPrintf(g_pStdOut, "ignore this output\n");
518
519 return RTEXITCODE_SUCCESS;
520}
521
522static void tstRTCreateProcEx2(const char *pszAsUser, const char *pszPassword)
523{
524 RTTestISub("Standard Err");
525
526 RTPIPE hPipeR, hPipeW;
527 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
528 const char * apszArgs[3] =
529 {
530 "non-existing-non-executable-file",
531 "--testcase-child-2",
532 NULL
533 };
534 RTHANDLE Handle;
535 Handle.enmType = RTHANDLETYPE_PIPE;
536 Handle.u.hPipe = hPipeW;
537 RTPROCESS hProc;
538 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
539 NULL, &Handle, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
540 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
541
542 char szOutput[_4K];
543 size_t offOutput = 0;
544 for (;;)
545 {
546 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
547 RTTESTI_CHECK(cbLeft > 0);
548 if (cbLeft == 0)
549 break;
550
551 size_t cbRead;
552 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
553 if (RT_FAILURE(rc))
554 {
555 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
556 break;
557 }
558 offOutput += cbRead;
559 }
560 szOutput[offOutput] = '\0';
561 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
562
563 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
564 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
565 RTThreadSleep(10);
566
567 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
568 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
569 else if ( offOutput != sizeof("howdy") - 1
570 || strcmp(szOutput, "howdy"))
571 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
572}
573
574
575static int tstRTCreateProcEx1Child(void)
576{
577 int rc = RTR3InitExeNoArguments(0);
578 if (RT_FAILURE(rc))
579 return RTMsgInitFailure(rc);
580
581 RTPrintf("it works");
582 RTStrmPrintf(g_pStdErr, "ignore this output\n");
583
584 return RTEXITCODE_SUCCESS;
585}
586
587
588static void tstRTCreateProcEx1(const char *pszAsUser, const char *pszPassword)
589{
590 RTTestISub("Standard Out");
591
592 RTPIPE hPipeR, hPipeW;
593 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
594 const char * apszArgs[3] =
595 {
596 "non-existing-non-executable-file",
597 "--testcase-child-1",
598 NULL
599 };
600 RTHANDLE Handle;
601 Handle.enmType = RTHANDLETYPE_PIPE;
602 Handle.u.hPipe = hPipeW;
603 RTPROCESS hProc;
604 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
605 &Handle, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
606 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
607
608 char szOutput[_4K];
609 size_t offOutput = 0;
610 for (;;)
611 {
612 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
613 RTTESTI_CHECK(cbLeft > 0);
614 if (cbLeft == 0)
615 break;
616
617 size_t cbRead;
618 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
619 if (RT_FAILURE(rc))
620 {
621 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
622 break;
623 }
624 offOutput += cbRead;
625 }
626 szOutput[offOutput] = '\0';
627 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
628
629 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
630 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
631
632 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
633 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
634 else if ( offOutput != sizeof("it works") - 1
635 || strcmp(szOutput, "it works"))
636 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
637}
638
639
640int main(int argc, char **argv)
641{
642 /*
643 * Deal with child processes first.
644 */
645 if (argc == 2 && !strcmp(argv[1], "--testcase-child-1"))
646 return tstRTCreateProcEx1Child();
647 if (argc == 2 && !strcmp(argv[1], "--testcase-child-2"))
648 return tstRTCreateProcEx2Child();
649 if (argc == 2 && !strcmp(argv[1], "--testcase-child-3"))
650 return tstRTCreateProcEx3Child();
651 if (argc >= 5 && !strcmp(argv[1], "--testcase-child-4"))
652 return tstRTCreateProcEx4Child(argc, argv);
653 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-5"))
654 return tstRTCreateProcEx5Child(argc, argv);
655 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-6"))
656 return tstRTCreateProcEx6Child(argc, argv);
657
658 /*
659 * Main process.
660 */
661 const char *pszAsUser = NULL;
662 const char *pszPassword = NULL;
663 if (argc != 1)
664 {
665 if (argc != 4 || strcmp(argv[1], "--as-user"))
666 return 99;
667 pszAsUser = argv[2];
668 pszPassword = argv[3];
669 }
670
671 RTTEST hTest;
672 int rc = RTTestInitAndCreate("tstRTProcCreateEx", &hTest);
673 if (rc)
674 return rc;
675 RTTestBanner(hTest);
676
677 /*
678 * Init globals.
679 */
680 if (!RTProcGetExecutablePath(g_szExecName, sizeof(g_szExecName)))
681 RTStrCopy(g_szExecName, sizeof(g_szExecName), argv[0]);
682 RTTESTI_CHECK_RC(RTEnvClone(&g_hEnvInitial, RTENV_DEFAULT), VINF_SUCCESS);
683
684 /*
685 * The tests.
686 */
687 tstRTCreateProcEx1(pszAsUser, pszPassword);
688 tstRTCreateProcEx2(pszAsUser, pszPassword);
689 tstRTCreateProcEx3(pszAsUser, pszPassword);
690 tstRTCreateProcEx4(pszAsUser, pszPassword);
691 if (pszAsUser)
692 tstRTCreateProcEx5(pszAsUser, pszPassword);
693 tstRTCreateProcEx6(pszAsUser, pszPassword);
694
695 /** @todo Cover files, ++ */
696
697 RTEnvDestroy(g_hEnvInitial);
698
699 /*
700 * Summary.
701 */
702 return RTTestSummaryAndDestroy(hTest);
703}
704
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