VirtualBox

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

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

RTProc/win,RTErr: Avoid doing LogonUserW when we don't need to get the profile environment as this may require the TCB privilege. On W2K CreateProcessWithLogonW doesn't plant standard handles in the child process, so try our best to do it ourselves. (This may be applicable to later windows versions too, but behavior must've been change in W10 or earlier.) Introduced specific error codes for the missing process rights to prevent wasting time.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.5 KB
Line 
1/* $Id: tstRTProcCreateEx.cpp 57906 2015-09-25 20:43:36Z 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") == 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", 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, &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, &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, &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, &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(cInitial == 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 int 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 = RTR3InitExeNoArguments(0);
342 if (RT_FAILURE(rc))
343 return RTMsgInitFailure(rc);
344
345#ifdef RT_OS_WINDOWS
346 char szUser[_1K];
347 DWORD cbLen = sizeof(szUser);
348 /** @todo Does not yet handle ERROR_MORE_DATA for user names longer than 32767. */
349 if (!GetUserName(szUser, &cbLen))
350 {
351 RTPrintf("GetUserName failed with last error=%ld\n", GetLastError());
352 return RTEXITCODE_FAILURE;
353 }
354# if 0 /* Does not work on NT4 (yet). */
355 DWORD cbSid = 0;
356 DWORD cbDomain = 0;
357 SID_NAME_USE sidUse;
358 /* First try to figure out how much space for SID + domain name we need. */
359 BOOL bRet = LookupAccountName(NULL /* current system*/,
360 szUser,
361 NULL,
362 &cbSid,
363 NULL,
364 &cbDomain,
365 &sidUse);
366 if (!bRet)
367 {
368 DWORD dwErr = GetLastError();
369 if (dwErr != ERROR_INSUFFICIENT_BUFFER)
370 {
371 RTPrintf("LookupAccountName(1) failed with last error=%ld\n", dwErr);
372 return RTEXITCODE_FAILURE;
373 }
374 }
375
376 /* Now try getting the real SID + domain name. */
377 SID *pSid = (SID *)RTMemAlloc(cbSid);
378 AssertPtr(pSid);
379 char *pszDomain = (char *)RTMemAlloc(cbDomain); /* Size in TCHAR! */
380 AssertPtr(pszDomain);
381
382 if (!LookupAccountName(NULL /* Current system */,
383 szUser,
384 pSid,
385 &cbSid,
386 pszDomain,
387 &cbDomain,
388 &sidUse))
389 {
390 RTPrintf("LookupAccountName(2) failed with last error=%ld\n", GetLastError());
391 return RTEXITCODE_FAILURE;
392 }
393 RTMemFree(pSid);
394 RTMemFree(pszDomain);
395# endif
396#else
397 /** @todo Lookup UID/effective UID, maybe GID? */
398#endif
399 return RTEXITCODE_SUCCESS;
400}
401
402static void tstRTCreateProcEx5(const char *pszUser, const char *pszPassword)
403{
404 RTTestISubF("As user \"%s\" with password \"%s\"", pszUser, pszPassword);
405
406 const char * apszArgs[3] =
407 {
408 "test", /* user name */
409 "--testcase-child-5",
410 NULL
411 };
412
413 RTPROCESS hProc;
414
415 /* Test for invalid logons. */
416 int rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL, NULL, NULL,
417 "non-existing-user", "wrong-password", &hProc);
418 if (rc != VERR_AUTHENTICATION_FAILURE && rc != VERR_PRIVILEGE_NOT_HELD && rc != VERR_PROC_TCB_PRIV_NOT_HELD)
419 RTTestIFailed("rc=%Rrc");
420
421 /* Test for invalid application. */
422 RTTESTI_CHECK_RC(RTProcCreateEx("non-existing-app", apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
423 NULL, NULL, NULL, NULL, &hProc), VERR_FILE_NOT_FOUND);
424 /* Test a (hopefully) valid user/password logon (given by parameters of this function). */
425 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
426 NULL, NULL, pszUser, pszPassword, &hProc), VINF_SUCCESS);
427 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
428 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
429
430 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
431 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
432}
433
434
435static int tstRTCreateProcEx4Child(int argc, char **argv)
436{
437 int rc = RTR3InitExeNoArguments(0);
438 if (RT_FAILURE(rc))
439 return RTMsgInitFailure(rc);
440
441 int cErrors = 0;
442 for (int i = 0; i < argc; i++)
443 if (strcmp(argv[i], g_apszArgs4[i]))
444 {
445 RTStrmPrintf(g_pStdErr,
446 "child4: argv[%2u]='%s'\n"
447 "child4: expected='%s'\n",
448 i, argv[i], g_apszArgs4[i]);
449 cErrors++;
450 }
451
452 return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
453}
454
455static void tstRTCreateProcEx4(const char *pszAsUser, const char *pszPassword)
456{
457 RTTestISub("Argument with spaces and stuff");
458
459 RTPROCESS hProc;
460 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, g_apszArgs4, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
461 NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
462 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
463 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
464
465 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
466 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
467}
468
469
470static int tstRTCreateProcEx3Child(void)
471{
472 int rc = RTR3InitExeNoArguments(0);
473 if (RT_FAILURE(rc))
474 return RTMsgInitFailure(rc);
475
476 RTStrmPrintf(g_pStdOut, "w"); RTStrmFlush(g_pStdOut);
477 RTStrmPrintf(g_pStdErr, "o"); RTStrmFlush(g_pStdErr);
478 RTStrmPrintf(g_pStdOut, "r"); RTStrmFlush(g_pStdOut);
479 RTStrmPrintf(g_pStdErr, "k"); RTStrmFlush(g_pStdErr);
480 RTStrmPrintf(g_pStdOut, "s");
481
482 return RTEXITCODE_SUCCESS;
483}
484
485static void tstRTCreateProcEx3(const char *pszAsUser, const char *pszPassword)
486{
487 RTTestISub("Standard Out+Err");
488
489 RTPIPE hPipeR, hPipeW;
490 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
491 const char * apszArgs[3] =
492 {
493 "non-existing-non-executable-file",
494 "--testcase-child-3",
495 NULL
496 };
497 RTHANDLE Handle;
498 Handle.enmType = RTHANDLETYPE_PIPE;
499 Handle.u.hPipe = hPipeW;
500 RTPROCESS hProc;
501 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
502 &Handle, &Handle, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
503 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
504
505 char szOutput[_4K];
506 size_t offOutput = 0;
507 for (;;)
508 {
509 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
510 RTTESTI_CHECK(cbLeft > 0);
511 if (cbLeft == 0)
512 break;
513
514 size_t cbRead;
515 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
516 if (RT_FAILURE(rc))
517 {
518 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
519 break;
520 }
521 offOutput += cbRead;
522 }
523 szOutput[offOutput] = '\0';
524 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
525
526 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
527 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
528 RTThreadSleep(10);
529
530 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
531 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
532 else if ( offOutput != sizeof("works") - 1
533 || strcmp(szOutput, "works"))
534 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
535}
536
537
538static int tstRTCreateProcEx2Child(void)
539{
540 int rc = RTR3InitExeNoArguments(0);
541 if (RT_FAILURE(rc))
542 return RTMsgInitFailure(rc);
543
544 RTStrmPrintf(g_pStdErr, "howdy");
545 RTStrmPrintf(g_pStdOut, "ignore this output\n");
546
547 return RTEXITCODE_SUCCESS;
548}
549
550static void tstRTCreateProcEx2(const char *pszAsUser, const char *pszPassword)
551{
552 RTTestISub("Standard Err");
553
554 RTPIPE hPipeR, hPipeW;
555 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
556 const char * apszArgs[3] =
557 {
558 "non-existing-non-executable-file",
559 "--testcase-child-2",
560 NULL
561 };
562 RTHANDLE Handle;
563 Handle.enmType = RTHANDLETYPE_PIPE;
564 Handle.u.hPipe = hPipeW;
565 RTPROCESS hProc;
566 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
567 NULL, &Handle, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
568 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
569
570 char szOutput[_4K];
571 size_t offOutput = 0;
572 for (;;)
573 {
574 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
575 RTTESTI_CHECK(cbLeft > 0);
576 if (cbLeft == 0)
577 break;
578
579 size_t cbRead;
580 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
581 if (RT_FAILURE(rc))
582 {
583 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
584 break;
585 }
586 offOutput += cbRead;
587 }
588 szOutput[offOutput] = '\0';
589 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
590
591 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
592 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
593 RTThreadSleep(10);
594
595 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
596 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
597 else if ( offOutput != sizeof("howdy") - 1
598 || strcmp(szOutput, "howdy"))
599 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
600}
601
602
603static int tstRTCreateProcEx1Child(void)
604{
605 int rc = RTR3InitExeNoArguments(0);
606 if (RT_FAILURE(rc))
607 return RTMsgInitFailure(rc);
608
609 RTPrintf("it works");
610 RTStrmPrintf(g_pStdErr, "ignore this output\n");
611
612 return RTEXITCODE_SUCCESS;
613}
614
615
616static void tstRTCreateProcEx1(const char *pszAsUser, const char *pszPassword)
617{
618 RTTestISub("Standard Out");
619
620 RTPIPE hPipeR, hPipeW;
621 RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS);
622 const char * apszArgs[3] =
623 {
624 "non-existing-non-executable-file",
625 "--testcase-child-1",
626 NULL
627 };
628 RTHANDLE Handle;
629 Handle.enmType = RTHANDLETYPE_PIPE;
630 Handle.u.hPipe = hPipeW;
631 RTPROCESS hProc;
632 RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
633 &Handle, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
634 RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
635
636 char szOutput[_4K];
637 size_t offOutput = 0;
638 for (;;)
639 {
640 size_t cbLeft = sizeof(szOutput) - 1 - offOutput;
641 RTTESTI_CHECK(cbLeft > 0);
642 if (cbLeft == 0)
643 break;
644
645 size_t cbRead;
646 int rc = RTPipeReadBlocking(hPipeR, &szOutput[offOutput], cbLeft, &cbRead);
647 if (RT_FAILURE(rc))
648 {
649 RTTESTI_CHECK_RC(rc, VERR_BROKEN_PIPE);
650 break;
651 }
652 offOutput += cbRead;
653 }
654 szOutput[offOutput] = '\0';
655 RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS);
656
657 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
658 RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
659
660 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
661 RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
662 else if ( offOutput != sizeof("it works") - 1
663 || strcmp(szOutput, "it works"))
664 RTTestIFailed("wrong output: \"%s\" (len=%u)", szOutput, offOutput);
665}
666
667
668int main(int argc, char **argv)
669{
670 /*
671 * Deal with child processes first.
672 */
673 if (argc == 2 && !strcmp(argv[1], "--testcase-child-1"))
674 return tstRTCreateProcEx1Child();
675 if (argc == 2 && !strcmp(argv[1], "--testcase-child-2"))
676 return tstRTCreateProcEx2Child();
677 if (argc == 2 && !strcmp(argv[1], "--testcase-child-3"))
678 return tstRTCreateProcEx3Child();
679 if (argc >= 5 && !strcmp(argv[1], "--testcase-child-4"))
680 return tstRTCreateProcEx4Child(argc, argv);
681 if (argc == 2 && !strcmp(argv[1], "--testcase-child-5"))
682 return tstRTCreateProcEx5Child(argc, argv);
683 if (argc >= 2 && !strcmp(argv[1], "--testcase-child-6"))
684 return tstRTCreateProcEx6Child(argc, argv);
685
686
687 /*
688 * Main process.
689 */
690 const char *pszAsUser = NULL;
691 const char *pszPassword = NULL;
692 if (argc != 1)
693 {
694 if (argc != 4 || strcmp(argv[1], "--as-user"))
695 return 99;
696 pszAsUser = argv[2];
697 pszPassword = argv[3];
698 }
699
700 RTTEST hTest;
701 int rc = RTTestInitAndCreate("tstRTProcCreateEx", &hTest);
702 if (rc)
703 return rc;
704 RTTestBanner(hTest);
705
706 /*
707 * Init globals.
708 */
709 if (!RTProcGetExecutablePath(g_szExecName, sizeof(g_szExecName)))
710 RTStrCopy(g_szExecName, sizeof(g_szExecName), argv[0]);
711 RTTESTI_CHECK_RC(RTEnvClone(&g_hEnvInitial, RTENV_DEFAULT), VINF_SUCCESS);
712
713 /*
714 * The tests.
715 */
716 tstRTCreateProcEx1(pszAsUser, pszPassword);
717 tstRTCreateProcEx2(pszAsUser, pszPassword);
718 tstRTCreateProcEx3(pszAsUser, pszPassword);
719 tstRTCreateProcEx4(pszAsUser, pszPassword);
720 if (pszAsUser)
721 tstRTCreateProcEx5(pszAsUser, pszPassword);
722 tstRTCreateProcEx6(pszAsUser, pszPassword);
723
724 /** @todo Cover files, ++ */
725
726 RTEnvDestroy(g_hEnvInitial);
727
728 /*
729 * Summary.
730 */
731 return RTTestSummaryAndDestroy(hTest);
732}
733
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