VirtualBox

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

Last change on this file since 57869 was 57869, checked in by vboxsync, 10 years ago

process-creation-posix.cpp: Hacked up support for RTPROC_FLAGS_PROFILE and RTPROC_FLAGS_ENV_CHANGE_RECORD. Works on my linux.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.2 KB
Line 
1/* $Id: tstRTProcCreateEx.cpp 57869 2015-09-23 13:53:53Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTProcCreateEx.
4 */
5
6/*
7 * Copyright (C) 2010-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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 <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-change-record") == 0)
171 {
172 RTENV hEnv;
173 rc = RTEnvClone(&hEnv, RTENV_DEFAULT);
174 if (RT_SUCCESS(rc))
175 {
176 uint32_t cVars = RTEnvCountEx(hEnv);
177 for (uint32_t i = 0; i < cVars; i++)
178 {
179 char szVarNm[_1K];
180 rc = RTEnvGetByIndexEx(hEnv, i, szVarNm, sizeof(szVarNm), szValue, sizeof(szValue));
181 if (RT_SUCCESS(rc))
182 RTStrmPrintf(g_pStdErr, "child6: #%u: %s=%s\n", i, szVarNm, szValue);
183 else
184 {
185 RTStrmPrintf(g_pStdErr, "child6: #%u: %Rrc\n", rc);
186 cErrors++;
187 }
188 }
189 RTEnvDestroy(hEnv);
190 }
191 else
192 {
193 RTStrmPrintf(g_pStdErr, "child6: RTEnvClone failed: %Rrc\n", rc);
194 cErrors++;
195 }
196 }
197#endif
198
199 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
200}
201
202static void tstRTCreateProcEx6(const char *pszAsUser, const char *pszPassword)
203{
204 RTTestISub("Profile environment");
205
206 const char *apszArgs[5] =
207 {
208 g_szExecName,
209 "--testcase-child-6",
210 "inherit",
211 pszAsUser,
212 NULL
213 };
214
215 RTTESTI_CHECK_RC_RETV(RTEnvSetEx(RTENV_DEFAULT, "testcase-child-6", "true"), VINF_SUCCESS);
216
217 /* Use the process environment first. */
218 RTPROCESS hProc;
219 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/,
220 NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
221 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
222 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
223
224 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
225 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
226
227 /* Use the process environment first with a little change. */
228 apszArgs[2] = "change-record";
229 RTENV hEnvChange;
230 RTTESTI_CHECK_RC_RETV(RTEnvCreateChangeRecord(&hEnvChange), VINF_SUCCESS);
231 RTTESTI_CHECK_RC_RETV(RTEnvSetEx(hEnvChange, "testcase-child-6", "changed"), VINF_SUCCESS);
232 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, hEnvChange, RTPROC_FLAGS_ENV_CHANGE_RECORD,
233 NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
234 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
235 ProcStatus.iStatus = -1;
236 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
237
238 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
239 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
240
241
242 /* Use profile environment this time. */
243 apszArgs[2] = "noinherit";
244 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, RTPROC_FLAGS_PROFILE,
245 NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
246 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
247 ProcStatus.iStatus = -1;
248 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
249
250 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
251 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
252
253 /* Use profile environment this time. */
254 apszArgs[2] = "noinherit-change-record";
255 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, hEnvChange,
256 RTPROC_FLAGS_PROFILE | RTPROC_FLAGS_ENV_CHANGE_RECORD,
257 NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
258 ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
259 ProcStatus.iStatus = -1;
260 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
261
262 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
263 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
264
265
266 RTTESTI_CHECK_RC(RTEnvDestroy(hEnvChange), VINF_SUCCESS);
267
268 /*
269 * Restore the environment and check that the PROFILE flag didn't mess with
270 * the process environment. (Note! The bug may be elsewhere as well.)
271 */
272 RTTESTI_CHECK_RC(RTEnvUnsetEx(RTENV_DEFAULT, "testcase-child-6"), VINF_SUCCESS);
273
274 RTENV hEnvCur;
275 RTTESTI_CHECK_RC_RETV(RTEnvClone(&hEnvCur, RTENV_DEFAULT), VINF_SUCCESS);
276 uint32_t cCurrent = RTEnvCountEx(hEnvCur);
277 uint32_t cInitial = RTEnvCountEx(g_hEnvInitial);
278 RTTESTI_CHECK_MSG(cInitial == cInitial, ("cCurrent=%u cInitial=%u\n", cCurrent, cInitial));
279 uint32_t cVars1;
280 RTENV hEnv1, hEnv2;
281 const char *pszEnv1, *pszEnv2;
282 if (cCurrent >= cInitial)
283 {
284 hEnv1 = hEnvCur;
285 pszEnv1 = "current";
286 cVars1 = cCurrent;
287 hEnv2 = g_hEnvInitial;
288 pszEnv2 = "initial";
289 }
290 else
291 {
292 hEnv2 = hEnvCur;
293 pszEnv2 = "current";
294 hEnv1 = g_hEnvInitial;
295 pszEnv1 = "initial";
296 cVars1 = cInitial;
297 }
298 for (uint32_t i = 0; i < cVars1; i++)
299 {
300 char szValue1[_16K];
301 char szVarNm[_1K];
302 int rc = RTEnvGetByIndexEx(hEnv1, i, szVarNm, sizeof(szVarNm), szValue1, sizeof(szValue1));
303 if (RT_SUCCESS(rc))
304 {
305 char szValue2[_16K];
306 rc = RTEnvGetEx(hEnv2, szVarNm, szValue2, sizeof(szValue2), NULL);
307 if (RT_SUCCESS(rc))
308 {
309 if (strcmp(szValue1, szValue2) != 0)
310 {
311 RTTestIFailed("Variable '%s' differs", szVarNm);
312 RTTestIFailureDetails("%s: '%s'\n"
313 "%s: '%s'\n",
314 pszEnv1, szValue1,
315 pszEnv2, szValue2);
316 }
317 }
318 else
319 RTTestIFailed("RTEnvGetEx(%s,%s,,) failed: %Rrc", pszEnv2, szVarNm, rc);
320
321 }
322 else
323 RTTestIFailed("RTEnvGetByIndexEx(%s,%u,,,,) failed: %Rrc", pszEnv1, i, rc);
324 }
325}
326
327
328static int tstRTCreateProcEx5Child(int argc, char **argv)
329{
330 int rc = RTR3InitExeNoArguments(0);
331 if (RT_FAILURE(rc))
332 return RTMsgInitFailure(rc);
333
334#ifdef RT_OS_WINDOWS
335 char szUser[_1K];
336 DWORD cbLen = sizeof(szUser);
337 /** @todo Does not yet handle ERROR_MORE_DATA for user names longer than 32767. */
338 if (!GetUserName(szUser, &cbLen))
339 {
340 RTPrintf("GetUserName failed with last error=%ld\n", GetLastError());
341 return RTEXITCODE_FAILURE;
342 }
343# if 0 /* Does not work on NT4 (yet). */
344 DWORD cbSid = 0;
345 DWORD cbDomain = 0;
346 SID_NAME_USE sidUse;
347 /* First try to figure out how much space for SID + domain name we need. */
348 BOOL bRet = LookupAccountName(NULL /* current system*/,
349 szUser,
350 NULL,
351 &cbSid,
352 NULL,
353 &cbDomain,
354 &sidUse);
355 if (!bRet)
356 {
357 DWORD dwErr = GetLastError();
358 if (dwErr != ERROR_INSUFFICIENT_BUFFER)
359 {
360 RTPrintf("LookupAccountName(1) failed with last error=%ld\n", dwErr);
361 return RTEXITCODE_FAILURE;
362 }
363 }
364
365 /* Now try getting the real SID + domain name. */
366 SID *pSid = (SID *)RTMemAlloc(cbSid);
367 AssertPtr(pSid);
368 char *pszDomain = (char *)RTMemAlloc(cbDomain); /* Size in TCHAR! */
369 AssertPtr(pszDomain);
370
371 if (!LookupAccountName(NULL /* Current system */,
372 szUser,
373 pSid,
374 &cbSid,
375 pszDomain,
376 &cbDomain,
377 &sidUse))
378 {
379 RTPrintf("LookupAccountName(2) failed with last error=%ld\n", GetLastError());
380 return RTEXITCODE_FAILURE;
381 }
382 RTMemFree(pSid);
383 RTMemFree(pszDomain);
384# endif
385#else
386 /** @todo Lookup UID/effective UID, maybe GID? */
387#endif
388 return RTEXITCODE_SUCCESS;
389}
390
391static void tstRTCreateProcEx5(const char *pszUser, const char *pszPassword)
392{
393 RTTestISubF("As user \"%s\" with password \"%s\"", pszUser, pszPassword);
394
395 const char * apszArgs[3] =
396 {
397 "test", /* user name */
398 "--testcase-child-5",
399 NULL
400 };
401
402 RTPROCESS hProc;
403
404 /* Test for invalid logons. */
405 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
406 NULL, NULL, "non-existing-user", "wrong-password", &hProc), VERR_AUTHENTICATION_FAILURE);
407 /* Test for invalid application. */
408 RTTESTI_CHECK_RC_RETV(RTProcCreateEx("non-existing-app", apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
409 NULL, NULL, NULL, NULL, &hProc), VERR_FILE_NOT_FOUND);
410 /* Test a (hopefully) valid user/password logon (given by parameters of this function). */
411 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
412 NULL, NULL, pszUser, pszPassword, &hProc), VINF_SUCCESS);
413 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
414 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
415
416 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
417 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
418}
419
420
421static int tstRTCreateProcEx4Child(int argc, char **argv)
422{
423 int rc = RTR3InitExeNoArguments(0);
424 if (RT_FAILURE(rc))
425 return RTMsgInitFailure(rc);
426
427 int cErrors = 0;
428 for (int i = 0; i < argc; i++)
429 if (strcmp(argv[i], g_apszArgs4[i]))
430 {
431 RTStrmPrintf(g_pStdErr,
432 "child4: argv[%2u]='%s'\n"
433 "child4: expected='%s'\n",
434 i, argv[i], g_apszArgs4[i]);
435 cErrors++;
436 }
437
438 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
439}
440
441static void tstRTCreateProcEx4(const char *pszAsUser, const char *pszPassword)
442{
443 RTTestISub("Argument with spaces and stuff");
444
445 RTPROCESS hProc;
446 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, g_apszArgs4, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
447 NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
448 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
449 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
450
451 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
452 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
453}
454
455
456static int tstRTCreateProcEx3Child(void)
457{
458 int rc = RTR3InitExeNoArguments(0);
459 if (RT_FAILURE(rc))
460 return RTMsgInitFailure(rc);
461
462 RTStrmPrintf(g_pStdOut, "w"); RTStrmFlush(g_pStdOut);
463 RTStrmPrintf(g_pStdErr, "o"); RTStrmFlush(g_pStdErr);
464 RTStrmPrintf(g_pStdOut, "r"); RTStrmFlush(g_pStdOut);
465 RTStrmPrintf(g_pStdErr, "k"); RTStrmFlush(g_pStdErr);
466 RTStrmPrintf(g_pStdOut, "s");
467
468 return RTEXITCODE_SUCCESS;
469}
470
471static void tstRTCreateProcEx3(const char *pszAsUser, const char *pszPassword)
472{
473 RTTestISub("Standard Out+Err");
474
475 RTPIPE hPipeR, hPipeW;
476 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
477 const char * apszArgs[3] =
478 {
479 "non-existing-non-executable-file",
480 "--testcase-child-3",
481 NULL
482 };
483 RTHANDLE Handle;
484 Handle.enmType = RTHANDLETYPE_PIPE;
485 Handle.u.hPipe = hPipeW;
486 RTPROCESS hProc;
487 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
488 &Handle, &Handle, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
489 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
490
491 char szOutput[_4K];
492 size_t offOutput = 0;
493 for (;;)
494 {
495 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
496 RTTESTI_CHECK(cbLeft > 0);
497 if (cbLeft == 0)
498 break;
499
500 size_t cbRead;
501 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
502 if (RT_FAILURE(rc))
503 {
504 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
505 break;
506 }
507 offOutput += cbRead;
508 }
509 szOutput[offOutput] = '\0';
510 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
511
512 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
513 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
514 RTThreadSleep(10);
515
516 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
517 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
518 else if ( offOutput != sizeof("works") - 1
519 || strcmp(szOutput, "works"))
520 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
521}
522
523
524static int tstRTCreateProcEx2Child(void)
525{
526 int rc = RTR3InitExeNoArguments(0);
527 if (RT_FAILURE(rc))
528 return RTMsgInitFailure(rc);
529
530 RTStrmPrintf(g_pStdErr, "howdy");
531 RTStrmPrintf(g_pStdOut, "ignore this output\n");
532
533 return RTEXITCODE_SUCCESS;
534}
535
536static void tstRTCreateProcEx2(const char *pszAsUser, const char *pszPassword)
537{
538 RTTestISub("Standard Err");
539
540 RTPIPE hPipeR, hPipeW;
541 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
542 const char * apszArgs[3] =
543 {
544 "non-existing-non-executable-file",
545 "--testcase-child-2",
546 NULL
547 };
548 RTHANDLE Handle;
549 Handle.enmType = RTHANDLETYPE_PIPE;
550 Handle.u.hPipe = hPipeW;
551 RTPROCESS hProc;
552 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
553 NULL, &Handle, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
554 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
555
556 char szOutput[_4K];
557 size_t offOutput = 0;
558 for (;;)
559 {
560 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
561 RTTESTI_CHECK(cbLeft > 0);
562 if (cbLeft == 0)
563 break;
564
565 size_t cbRead;
566 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
567 if (RT_FAILURE(rc))
568 {
569 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
570 break;
571 }
572 offOutput += cbRead;
573 }
574 szOutput[offOutput] = '\0';
575 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
576
577 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
578 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
579 RTThreadSleep(10);
580
581 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
582 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
583 else if ( offOutput != sizeof("howdy") - 1
584 || strcmp(szOutput, "howdy"))
585 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
586}
587
588
589static int tstRTCreateProcEx1Child(void)
590{
591 int rc = RTR3InitExeNoArguments(0);
592 if (RT_FAILURE(rc))
593 return RTMsgInitFailure(rc);
594
595 RTPrintf("it works");
596 RTStrmPrintf(g_pStdErr, "ignore this output\n");
597
598 return RTEXITCODE_SUCCESS;
599}
600
601
602static void tstRTCreateProcEx1(const char *pszAsUser, const char *pszPassword)
603{
604 RTTestISub("Standard Out");
605
606 RTPIPE hPipeR, hPipeW;
607 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
608 const char * apszArgs[3] =
609 {
610 "non-existing-non-executable-file",
611 "--testcase-child-1",
612 NULL
613 };
614 RTHANDLE Handle;
615 Handle.enmType = RTHANDLETYPE_PIPE;
616 Handle.u.hPipe = hPipeW;
617 RTPROCESS hProc;
618 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
619 &Handle, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
620 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
621
622 char szOutput[_4K];
623 size_t offOutput = 0;
624 for (;;)
625 {
626 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
627 RTTESTI_CHECK(cbLeft > 0);
628 if (cbLeft == 0)
629 break;
630
631 size_t cbRead;
632 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
633 if (RT_FAILURE(rc))
634 {
635 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
636 break;
637 }
638 offOutput += cbRead;
639 }
640 szOutput[offOutput] = '\0';
641 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
642
643 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
644 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
645
646 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
647 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
648 else if ( offOutput != sizeof("it works") - 1
649 || strcmp(szOutput, "it works"))
650 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
651}
652
653
654int main(int argc, char **argv)
655{
656 /*
657 * Deal with child processes first.
658 */
659 if (argc == 2 && !strcmp(argv[1], "--testcase-child-1"))
660 return tstRTCreateProcEx1Child();
661 if (argc == 2 && !strcmp(argv[1], "--testcase-child-2"))
662 return tstRTCreateProcEx2Child();
663 if (argc == 2 && !strcmp(argv[1], "--testcase-child-3"))
664 return tstRTCreateProcEx3Child();
665 if (argc >= 5 && !strcmp(argv[1], "--testcase-child-4"))
666 return tstRTCreateProcEx4Child(argc, argv);
667 if (argc == 2 && !strcmp(argv[1], "--testcase-child-5"))
668 return tstRTCreateProcEx5Child(argc, argv);
669 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-6"))
670 return tstRTCreateProcEx6Child(argc, argv);
671
672
673 /*
674 * Main process.
675 */
676 const char *pszAsUser = NULL;
677 const char *pszPassword = NULL;
678 if (argc != 1)
679 {
680 if (argc != 4 || strcmp(argv[1], "--as-user"))
681 return 99;
682 pszAsUser = argv[2];
683 pszPassword = argv[3];
684 }
685
686 RTTEST hTest;
687 int rc = RTTestInitAndCreate("tstRTProcCreateEx", &hTest);
688 if (rc)
689 return rc;
690 RTTestBanner(hTest);
691
692 /*
693 * Init globals.
694 */
695 if (!RTProcGetExecutablePath(g_szExecName, sizeof(g_szExecName)))
696 RTStrCopy(g_szExecName, sizeof(g_szExecName), argv[0]);
697 RTTESTI_CHECK_RC(RTEnvClone(&g_hEnvInitial, RTENV_DEFAULT), VINF_SUCCESS);
698
699 /*
700 * The tests.
701 */
702 tstRTCreateProcEx1(pszAsUser, pszPassword);
703 tstRTCreateProcEx2(pszAsUser, pszPassword);
704 tstRTCreateProcEx3(pszAsUser, pszPassword);
705 tstRTCreateProcEx4(pszAsUser, pszPassword);
706 if (pszAsUser)
707 tstRTCreateProcEx5(pszAsUser, pszPassword);
708 tstRTCreateProcEx6(pszAsUser, pszPassword);
709
710 /** @todo Cover files, ++ */
711
712 RTEnvDestroy(g_hEnvInitial);
713
714 /*
715 * Summary.
716 */
717 return RTTestSummaryAndDestroy(hTest);
718}
719
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