Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1972 lines
50 KiB

  1. /*--
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. srvtask.c
  5. Abstract:
  6. Implementation of PSX Process Structure APIs.
  7. Author:
  8. Mark Lucovsky (markl) 08-Mar-1989
  9. Revision History:
  10. --*/
  11. #include "psxsrv.h"
  12. #include "sesport.h"
  13. #ifdef _MIPS_
  14. #include "psxmips.h"
  15. #endif
  16. #ifdef _ALPHA_
  17. #include "psxalpha.h"
  18. #endif
  19. #ifdef _X86_
  20. #include "psxi386.h"
  21. #endif
  22. #ifdef _PPC_
  23. #include "psxppc.h"
  24. #endif
  25. #ifdef _IA64_
  26. #include "psxia64.h"
  27. #endif
  28. #include <time.h>
  29. extern VOID
  30. PsxFreeDirectories(
  31. IN PPSX_PROCESS
  32. );
  33. VOID
  34. ConvertPathToWin(char *path);
  35. BOOLEAN
  36. PsxFork(
  37. IN PPSX_PROCESS p,
  38. IN PPSX_API_MSG m
  39. )
  40. /*++
  41. Routine Description:
  42. This function implements posix fork() API
  43. Arguments:
  44. p - Supplies the address of the calling process
  45. m - Supplies the address of the related message
  46. Return Value:
  47. TRUE - Always succeeds and generates a reply
  48. --*/
  49. {
  50. PPSX_PROCESS ForkProcess, NewProcess;
  51. HANDLE NewProcessHandle, NewThreadHandle;
  52. THREAD_BASIC_INFORMATION ThreadBasicInfo;
  53. PVOID ExcptList;
  54. CONTEXT Context;
  55. ULONG Psp;
  56. NTSTATUS st;
  57. INITIAL_TEB InitialTeb;
  58. CLIENT_ID ClientId;
  59. PPSX_FORK_MSG args;
  60. HANDLE h;
  61. args = &m->u.Fork;
  62. if (p->Flags & P_NO_FORK) {
  63. //
  64. // This process may not fork; it's context has been
  65. // rearranged to make it call the PdxNullApiCaller.
  66. //
  67. m->Error = EINTR;
  68. m->Signal = SIGCONT;
  69. return TRUE;
  70. }
  71. //
  72. // Impersonate the client to insure that the new process will belong
  73. // to him instead of to us.
  74. //
  75. st = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  76. if (!NT_SUCCESS(st)) {
  77. m->Error = EAGAIN;
  78. return TRUE;
  79. }
  80. //
  81. // Create a new process to be the child. The ExceptionPort is
  82. // initialized to PsxApiPort.
  83. //
  84. st = NtCreateProcess(&NewProcessHandle, PROCESS_ALL_ACCESS, NULL,
  85. p->Process, TRUE, NULL, NULL, PsxApiPort);
  86. if (!NT_SUCCESS(st)) {
  87. EndImpersonation();
  88. m->Error = EAGAIN;
  89. return TRUE;
  90. }
  91. {
  92. ULONG HardErrorMode = 0; // disable popups
  93. st = NtSetInformationProcess(
  94. NewProcessHandle,
  95. ProcessDefaultHardErrorMode,
  96. (PVOID)&HardErrorMode,
  97. sizeof(HardErrorMode)
  98. );
  99. ASSERT(NT_SUCCESS(st));
  100. }
  101. Context.ContextFlags = CONTEXT_FULL;
  102. st = NtGetContextThread(p->Thread, &Context);
  103. if (!NT_SUCCESS(st)) {
  104. NtTerminateProcess(NewProcessHandle, STATUS_SUCCESS);
  105. NtWaitForSingleObject(NewProcessHandle, FALSE, NULL);
  106. NtClose(NewProcessHandle);
  107. EndImpersonation();
  108. m->Error = EINVAL;
  109. return TRUE;
  110. }
  111. InitialTeb.OldInitialTeb.OldStackBase = NULL;
  112. InitialTeb.OldInitialTeb.OldStackLimit = NULL;
  113. #ifdef _IA64_
  114. InitialTeb.OldInitialTeb.OldBStoreLimit = NULL;
  115. InitialTeb.BStoreLimit = args->BStoreLimit;
  116. #endif
  117. InitialTeb.StackBase = args->StackBase;
  118. InitialTeb.StackLimit = args->StackLimit;
  119. InitialTeb.StackAllocationBase = args->StackAllocationBase;
  120. SetPsxForkReturn(Context);
  121. st = NtCreateThread(&NewThreadHandle, THREAD_ALL_ACCESS, NULL,
  122. NewProcessHandle, &ClientId, &Context, &InitialTeb, TRUE);
  123. EndImpersonation();
  124. if (!NT_SUCCESS(st)) {
  125. st = NtTerminateProcess(NewProcessHandle, STATUS_SUCCESS);
  126. ASSERT(NT_SUCCESS(st));
  127. NtWaitForSingleObject(NewProcessHandle, FALSE, NULL);
  128. NtClose(NewProcessHandle);
  129. m->Error = EAGAIN;
  130. return TRUE;
  131. }
  132. //
  133. // Allocate a process structure.
  134. //
  135. NewProcess = PsxAllocateProcess(&ClientId);
  136. if (NULL == NewProcess) {
  137. st = NtTerminateProcess(NewProcessHandle, STATUS_SUCCESS);
  138. ASSERT(NT_SUCCESS(st));
  139. st = NtResumeThread(NewThreadHandle,&Psp);
  140. ASSERT(NT_SUCCESS(st));
  141. NtWaitForSingleObject(NewProcessHandle, FALSE, NULL);
  142. NtClose(NewProcessHandle);
  143. NtClose(NewThreadHandle);
  144. m->Error = EAGAIN;
  145. return TRUE;
  146. }
  147. //
  148. // Copy the ExceptionList pointer from the parent process TEB
  149. // to the child process TEB.
  150. //
  151. st = NtQueryInformationThread(p->Thread, ThreadBasicInformation,
  152. (PVOID)&ThreadBasicInfo, sizeof(ThreadBasicInfo), NULL);
  153. ASSERT(NT_SUCCESS(st));
  154. // XXX.mjb: The actual address we want to read is
  155. // TebBaseAddress->NtTib.ExceptionList, but I happen to know
  156. // that these are equivalent.
  157. //
  158. st = NtReadVirtualMemory(p->Process,
  159. (PVOID)ThreadBasicInfo.TebBaseAddress,
  160. (PVOID)&ExcptList, sizeof(ExcptList), NULL);
  161. ASSERT(NT_SUCCESS(st));
  162. st = NtQueryInformationThread(NewThreadHandle, ThreadBasicInformation,
  163. (PVOID)&ThreadBasicInfo, sizeof(ThreadBasicInfo), NULL);
  164. ASSERT(NT_SUCCESS(st));
  165. st = NtWriteVirtualMemory(NewProcessHandle,
  166. (PVOID)ThreadBasicInfo.TebBaseAddress,
  167. (PVOID)&ExcptList, sizeof(ExcptList), NULL);
  168. ASSERT(NT_SUCCESS(st));
  169. ForkProcess = p;
  170. //
  171. // The new process is allocated locked, but we need to lock the
  172. // parent (ForkProcess).
  173. //
  174. AcquireProcessLock(ForkProcess);
  175. st = PsxInitializeProcess(NewProcess, ForkProcess, 0L, NewProcessHandle,
  176. NewThreadHandle, NULL);
  177. if (!NT_SUCCESS(st)) {
  178. st = NtTerminateProcess(NewProcessHandle, STATUS_SUCCESS);
  179. ASSERT(NT_SUCCESS(st));
  180. st = NtResumeThread(NewThreadHandle,&Psp);
  181. ASSERT(NT_SUCCESS(st));
  182. st = NtWaitForSingleObject(NewProcessHandle, FALSE, NULL);
  183. NtClose(NewProcessHandle);
  184. NtClose(NewThreadHandle);
  185. m->Error = EAGAIN;
  186. return TRUE;
  187. }
  188. NewProcess->InitialPebPsxData.Length =
  189. sizeof(ForkProcess->InitialPebPsxData);
  190. NewProcess->InitialPebPsxData.ClientStartAddress = NULL;
  191. if (NULL != ForkProcess->PsxSession->Terminal) {
  192. NewProcess->InitialPebPsxData.SessionPortHandle =
  193. (HANDLE)ForkProcess->PsxSession->Terminal->UniqueId;
  194. } else {
  195. //
  196. // What if there are no open file descriptors?
  197. //
  198. if (NULL != ForkProcess->ProcessFileTable[0].SystemOpenFileDesc)
  199. NewProcess->InitialPebPsxData.SessionPortHandle =
  200. (HANDLE)ForkProcess->ProcessFileTable[0].SystemOpenFileDesc->Terminal->UniqueId;
  201. }
  202. m->ReturnValue = NewProcess->Pid;
  203. st = NtResumeThread(NewThreadHandle, &Psp);
  204. ASSERT(NT_SUCCESS(st));
  205. return TRUE;
  206. }
  207. BOOLEAN
  208. PsxExec(
  209. IN PPSX_PROCESS p,
  210. IN PPSX_API_MSG m
  211. )
  212. /*++
  213. Routine Description:
  214. This function implements posix execve() API
  215. Arguments:
  216. p - Supplies the address of the calling process
  217. m - Supplies the address of the related message
  218. Return Value:
  219. TRUE - Always succeeds and generates a reply
  220. --*/
  221. {
  222. RTL_USER_PROCESS_INFORMATION ProcInfo;
  223. PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  224. PPSX_EXEC_MSG args;
  225. WCHAR ImageFileString[1024];
  226. ANSI_STRING CommandLine;
  227. ANSI_STRING CWD;
  228. NTSTATUS Status;
  229. ULONG whocares;
  230. ULONG i;
  231. KERNEL_USER_TIMES ProcessTime;
  232. ULONG PosixTime, Remainder;
  233. UNICODE_STRING uCWD, uImageFileName;
  234. PUNICODE_STRING u;
  235. PVOID SaveDirectoryPrefix;
  236. HANDLE h;
  237. USHORT len;
  238. args = &m->u.Exec;
  239. //
  240. // If pathname is too big, then return error. This should
  241. // really allow for names that are longer because of PSX
  242. // prefixes
  243. //
  244. if (args->Path.Length > PATH_MAX) {
  245. m->Error = ENAMETOOLONG;
  246. return TRUE;
  247. }
  248. AcquireProcessLock(p);
  249. if (Exited == p->State) {
  250. ReleaseProcessLock(p);
  251. return FALSE;
  252. }
  253. //
  254. // Capture the pathname
  255. //
  256. Status = NtReadVirtualMemory(p->Process, args->Path.Buffer,
  257. &ImageFileString[0], args->Path.Length, NULL);
  258. if (!NT_SUCCESS(Status)) {
  259. ReleaseProcessLock(p);
  260. m->Error = ENOMEM;
  261. return TRUE;
  262. }
  263. uImageFileName.Buffer = &ImageFileString[0];
  264. uImageFileName.Length = args->Path.Length;
  265. uImageFileName.MaximumLength = args->Path.Length;
  266. //
  267. // Propagate Current Working Directory
  268. //
  269. SaveDirectoryPrefix = (PVOID)p->DirectoryPrefix;
  270. if (!PsxPropagateDirectories(p)) {
  271. ReleaseProcessLock(p);
  272. p->DirectoryPrefix = SaveDirectoryPrefix;
  273. m->Error = ENOMEM;
  274. return TRUE;
  275. }
  276. //
  277. // Format the process parameters
  278. //
  279. CommandLine.Buffer = args->Args;
  280. CommandLine.Length = ARG_MAX;
  281. CommandLine.MaximumLength = ARG_MAX;
  282. PSX_GET_STRLEN(DOSDEVICE_A,len);
  283. CWD.Buffer = p->DirectoryPrefix->NtCurrentWorkingDirectory.Buffer + len;
  284. CWD.MaximumLength = p->DirectoryPrefix->NtCurrentWorkingDirectory.Length - len;
  285. CWD.Length = CWD.MaximumLength;
  286. Status = RtlAnsiStringToUnicodeString(&uCWD, &CWD, TRUE);
  287. if (!NT_SUCCESS(Status)) {
  288. PsxFreeDirectories(p);
  289. p->DirectoryPrefix = SaveDirectoryPrefix;
  290. ReleaseProcessLock(p);
  291. m->Error = ENOMEM;
  292. return TRUE;
  293. }
  294. //
  295. // Somewhere along the line someone changes the old process's
  296. // DllPath to Unicode. If we pass a NULL DllPath here, we find
  297. // that Ansi is expected, and we can't find the Dll. So here we
  298. // take the Unicode DllPath, convert to Ansi, and pass it
  299. // explicitly.
  300. //
  301. u = (PUNICODE_STRING)&NtCurrentPeb()->ProcessParameters->DllPath;
  302. Status = RtlCreateProcessParameters(&ProcessParameters, &uImageFileName,
  303. u, &uCWD, (PUNICODE_STRING)&CommandLine, NULL, NULL, NULL, NULL, NULL);
  304. #ifndef EXEC_FOREIGN
  305. RtlFreeUnicodeString(&uCWD);
  306. #endif
  307. if (!NT_SUCCESS(Status)) {
  308. #ifdef EXEC_FOREIGN
  309. RtlFreeUnicodeString(&uCWD);
  310. #endif
  311. PsxFreeDirectories(p);
  312. p->DirectoryPrefix = SaveDirectoryPrefix;
  313. ReleaseProcessLock(p);
  314. m->Error = ENOMEM;
  315. return TRUE;
  316. }
  317. //
  318. // Create the process and thread. We impersonate the client so that
  319. // they end up being owned by him, instead of owned by us.
  320. //
  321. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  322. if (NT_SUCCESS(Status)) {
  323. Status = RtlCreateUserProcess(&uImageFileName, 0, ProcessParameters,
  324. NULL, NULL, p->Process, FALSE, NULL, NULL, &ProcInfo);
  325. EndImpersonation();
  326. }
  327. if (!NT_SUCCESS(Status)) {
  328. #ifdef EXEC_FOREIGN
  329. RtlFreeUnicodeString(&uCWD);
  330. #endif
  331. PsxFreeDirectories(p);
  332. p->DirectoryPrefix = SaveDirectoryPrefix;
  333. ReleaseProcessLock(p);
  334. if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
  335. m->Error = PsxStatusToErrnoPath(&uImageFileName);
  336. return TRUE;
  337. }
  338. m->Error = PsxStatusToErrno(Status);
  339. return TRUE;
  340. }
  341. RtlDestroyProcessParameters(ProcessParameters);
  342. //
  343. // Set the exception port for the new process so we'll find out
  344. // if he takes a fault.
  345. //
  346. Status = NtSetInformationProcess(ProcInfo.Process,
  347. ProcessExceptionPort, (PVOID)&PsxApiPort, sizeof(PsxApiPort));
  348. if (!NT_SUCCESS(Status)) {
  349. KdPrint(("PSXSS: NtSetInfoProcess: 0x%x\n", Status));
  350. }
  351. ASSERT(NT_SUCCESS(Status));
  352. {
  353. ULONG HardErrorMode = 0; // disable popups
  354. Status = NtSetInformationProcess(
  355. ProcInfo.Process,
  356. ProcessDefaultHardErrorMode,
  357. (PVOID)&HardErrorMode,
  358. sizeof(HardErrorMode)
  359. );
  360. ASSERT(NT_SUCCESS(Status));
  361. }
  362. //
  363. // check to make sure it is a POSIX app
  364. //
  365. if (ProcInfo.ImageInformation.SubSystemType !=
  366. IMAGE_SUBSYSTEM_POSIX_CUI) {
  367. //
  368. // The image is not a Posix program. Tear down the
  369. // process we just created in the usual way, and then
  370. // call the windows subsystem to do the same thing
  371. // over.
  372. //
  373. PsxFreeDirectories(p);
  374. p->DirectoryPrefix = SaveDirectoryPrefix;
  375. #ifndef EXEC_FOREIGN
  376. ReleaseProcessLock(p);
  377. #endif
  378. Status = NtTerminateProcess(ProcInfo.Process, STATUS_SUCCESS);
  379. if (!NT_SUCCESS(Status)) {
  380. KdPrint(("PSXSS: NtTerminateProcess: 0x%x\n", Status));
  381. }
  382. Status = NtWaitForSingleObject(ProcInfo.Process, FALSE, NULL);
  383. if (!NT_SUCCESS(Status)) {
  384. KdPrint(("PSXSS: NtWaitForSingleObject: 0x%x\n", Status));
  385. }
  386. #ifdef EXEC_FOREIGN
  387. Status = ExecForeignImage(p, m, &uImageFileName, &uCWD);
  388. ReleaseProcessLock(p);
  389. RtlFreeUnicodeString(&uCWD);
  390. if (!NT_SUCCESS(Status)) {
  391. m->Error = ENOEXEC;
  392. return TRUE;
  393. }
  394. return FALSE;
  395. #else
  396. m->Error = ENOEXEC;
  397. return TRUE;
  398. #endif
  399. }
  400. #ifdef EXEC_FOREIGN
  401. RtlFreeUnicodeString(&uCWD);
  402. #endif
  403. //
  404. // Close open files that have their close-on-exec bit set.
  405. //
  406. for (i = 0; i < OPEN_MAX; ++i) {
  407. if (NULL != p->ProcessFileTable[i].SystemOpenFileDesc &&
  408. p->ProcessFileTable[i].Flags & PSX_FD_CLOSE_ON_EXEC) {
  409. (void)DeallocateFd(p, i);
  410. }
  411. }
  412. AcquireProcessStructureLock();
  413. //
  414. // Get the time for this process and add to the accumulated time for
  415. // the process
  416. //
  417. Status = NtQueryInformationProcess(p->Process, ProcessTimes,
  418. (PVOID)&ProcessTime, sizeof(KERNEL_USER_TIMES), NULL);
  419. ASSERT(NT_SUCCESS(Status));
  420. PosixTime = RtlExtendedLargeIntegerDivide(ProcessTime.KernelTime,
  421. 10000, &Remainder).LowPart;
  422. p->ProcessTimes.tms_stime += PosixTime;
  423. PosixTime = RtlExtendedLargeIntegerDivide(ProcessTime.UserTime,
  424. 10000, &Remainder).LowPart;
  425. p->ProcessTimes.tms_utime += PosixTime;
  426. //
  427. // Terminate the current process, and munge in the
  428. // new process
  429. //
  430. RemoveEntryList(&p->ClientIdHashLinks);
  431. p->ClientIdHashLinks.Flink = p->ClientIdHashLinks.Blink = NULL;
  432. Status = NtTerminateProcess(p->Process, STATUS_SUCCESS);
  433. ASSERT(NT_SUCCESS(Status));
  434. Status = NtWaitForSingleObject(p->Process, FALSE, NULL);
  435. ASSERT(NT_SUCCESS(Status));
  436. Status = NtClose(p->ClientPort);
  437. ASSERT(NT_SUCCESS(Status));
  438. Status = NtClose(p->Process);
  439. ASSERT(NT_SUCCESS(Status));
  440. Status = NtClose(p->Thread);
  441. ASSERT(NT_SUCCESS(Status));
  442. p->Process = ProcInfo.Process;
  443. p->Thread = ProcInfo.Thread;
  444. p->ClientId = ProcInfo.ClientId;
  445. p->ClientPort = NULL;
  446. InsertTailList(&ClientIdHashTable[CIDTOHASHINDEX(&p->ClientId)],
  447. &p->ClientIdHashLinks);
  448. p->Flags |= P_HAS_EXECED;
  449. ReleaseProcessStructureLock();
  450. //
  451. // Restore signals being caught to SIG_DFL
  452. // --- Posix does not specify what to do w/ associated flags or mask
  453. //
  454. for (i = 0; i < _SIGMAXSIGNO; i++) {
  455. if (p->SignalDataBase.SignalDisposition[i].sa_handler !=
  456. SIG_IGN) {
  457. p->SignalDataBase.SignalDisposition[i].sa_handler =
  458. SIG_DFL;
  459. }
  460. }
  461. //
  462. // Since we don't reply to the old process (he's gone now), we need
  463. // to start the new process's InPsx count at zero.
  464. //
  465. p->InPsx = 0;
  466. ReleaseProcessLock(p);
  467. ExecProcessFileTable(p);
  468. if (p->ProcessIsBeingDebugged && PsxpDebuggerActive) {
  469. Status = NtSetInformationProcess(p->Process, ProcessDebugPort,
  470. (PVOID)&PsxpDebugPort, sizeof(HANDLE));
  471. if (!NT_SUCCESS(Status)) {
  472. p->ProcessIsBeingDebugged = FALSE;
  473. }
  474. }
  475. Status = NtResumeThread(p->Thread,&whocares);
  476. if (!NT_SUCCESS(Status)) {
  477. KdPrint(("PSXSS: NtResumeThread: 0x%x\n", Status));
  478. }
  479. ASSERT(NT_SUCCESS(Status) && whocares == 1);
  480. return FALSE;
  481. }
  482. BOOLEAN
  483. PsxGetIds(
  484. IN PPSX_PROCESS p,
  485. IN PPSX_API_MSG m
  486. )
  487. /*++
  488. Routine Description:
  489. This function provides all the support needed to implement
  490. getpid(), getppid(), getuid(), geteuid(), getgid(), and getegid().
  491. Arguments:
  492. p - Supplies the address of the calling process
  493. m - Supplies the address of the related message
  494. Return Value:
  495. TRUE - Always succeeds and generates a reply
  496. --*/
  497. {
  498. PPSX_GETIDS_MSG args;
  499. args = &m->u.GetIds;
  500. args->Pid = p->Pid;
  501. args->ParentPid = p->ParentPid;
  502. args->GroupId = p->ProcessGroupId;
  503. args->RealUid = p->RealUid;
  504. args->EffectiveUid = p->EffectiveUid;
  505. args->RealGid = p->RealGid;
  506. args->EffectiveGid = p->EffectiveGid;
  507. return TRUE;
  508. }
  509. BOOLEAN
  510. PsxExit(
  511. IN PPSX_PROCESS p,
  512. IN PPSX_API_MSG m
  513. )
  514. /*++
  515. Routine Description:
  516. This function implements the _exit() API.
  517. Arguments:
  518. p - Supplies the address of the calling process
  519. m - Supplies the address of the related message
  520. Return Value:
  521. TRUE - Always succeeds and generates a reply
  522. --*/
  523. {
  524. PPSX_EXIT_MSG args;
  525. args = &m->u.Exit;
  526. Exit(p, (args->ExitStatus & 0xff) << 8);
  527. return FALSE;
  528. }
  529. VOID
  530. WaitPidHandler(
  531. IN PPSX_PROCESS p,
  532. IN PINTCB IntControlBlock,
  533. IN PSX_INTERRUPTREASON InterruptReason,
  534. IN int Signal
  535. )
  536. /*++
  537. Routine Description:
  538. This function is called whenever a process that is in a waitpid wait
  539. is sent a signal, or has a child stop/terminate that could possibly
  540. satisfy a wait.
  541. This function is responsible for unlocking the process.
  542. Arguments:
  543. p - Supplies the address of the process being interrupted.
  544. IntControlBlock - Supplies the address of the interrupt control block.
  545. InterruptReason - Supplies the reason that this process is being
  546. interrupted. Not used in this handler.
  547. Return Value:
  548. None.
  549. --*/
  550. {
  551. PPSX_API_MSG m;
  552. PPSX_WAITPID_MSG args;
  553. PPSX_PROCESS cp;
  554. BOOLEAN WaitSatisfied;
  555. pid_t TargetProcess;
  556. pid_t TargetGroup;
  557. enum _WaitType { AnyProcess, SpecificProcess, SpecificGroup };
  558. enum _WaitType WaitType;
  559. RtlLeaveCriticalSection(&BlockLock);
  560. m = IntControlBlock->IntMessage;
  561. args = &m->u.WaitPid;
  562. AcquireProcessStructureLock();
  563. p->State = Active;
  564. if (InterruptReason == SignalInterrupt) {
  565. ReleaseProcessStructureLock();
  566. RtlFreeHeap(PsxHeap, 0, (PVOID)IntControlBlock);
  567. m->Error = EINTR;
  568. m->Signal = Signal;
  569. ApiReply(p,m,NULL);
  570. RtlFreeHeap(PsxHeap, 0, (PVOID)m);
  571. return;
  572. }
  573. WaitSatisfied = FALSE;
  574. TargetProcess = SPECIALPID;
  575. TargetGroup = SPECIALPID;
  576. WaitType = AnyProcess;
  577. if (args->Pid <= 0 && args->Pid != (pid_t)-1) {
  578. WaitType = SpecificGroup;
  579. //
  580. // Process group id is specified.
  581. //
  582. if (args->Pid == 0) {
  583. TargetGroup = p->ProcessGroupId;
  584. } else {
  585. TargetGroup = -1 * args->Pid;
  586. }
  587. } else {
  588. if (args->Pid != (pid_t)-1) {
  589. TargetProcess = args->Pid;
  590. WaitType = SpecificProcess;
  591. }
  592. }
  593. //
  594. // Scan process table
  595. //
  596. for (cp = FirstProcess; cp < LastProcess; cp++) {
  597. if (cp->Flags & P_FREE) {
  598. continue;
  599. }
  600. //
  601. // Just look at processes that could possibly satisfy a wait.
  602. // - Processes that have exited
  603. // - Stopped processes that have not previously satisfied a
  604. // wait (if WUNTRACED was set)
  605. //
  606. if (cp->State == Exited ||
  607. (cp->State == Stopped && (args->Options & WUNTRACED) &&
  608. !(cp->Flags & P_WAITED))) {
  609. if (cp->ParentPid != p->Pid) {
  610. continue;
  611. }
  612. switch (WaitType) {
  613. case AnyProcess:
  614. m->ReturnValue = cp->Pid;
  615. args->StatLocValue = cp->ExitStatus;
  616. break;
  617. case SpecificProcess:
  618. if ( cp->Pid == TargetProcess ) {
  619. m->ReturnValue = cp->Pid;
  620. args->StatLocValue = cp->ExitStatus;
  621. }
  622. break;
  623. case SpecificGroup:
  624. if ( cp->ProcessGroupId == TargetGroup){
  625. m->ReturnValue = cp->Pid;
  626. args->StatLocValue = cp->ExitStatus;
  627. }
  628. break;
  629. }
  630. if ( m->ReturnValue ) {
  631. //
  632. // wait was satisfied
  633. //
  634. if ( cp->State == Exited ) {
  635. p->ProcessTimes.tms_cstime += (cp->ProcessTimes.tms_stime
  636. + cp->ProcessTimes.tms_cstime);
  637. p->ProcessTimes.tms_cutime += (cp->ProcessTimes.tms_utime
  638. + cp->ProcessTimes.tms_cutime);
  639. //
  640. // Deallocate the process
  641. //
  642. cp->Flags |= P_FREE;
  643. RtlDeleteCriticalSection(&cp->ProcessLock);
  644. } else {
  645. //
  646. // set bit so this stopped process won't satisfy another
  647. // wait until it stops again or exits.
  648. //
  649. cp->Flags |= P_WAITED;
  650. args->StatLocValue = cp->ExitStatus | (1L << 30);
  651. }
  652. WaitSatisfied = TRUE;
  653. break;
  654. }
  655. }
  656. }
  657. if ( WaitSatisfied ) {
  658. ReleaseProcessStructureLock();
  659. RtlFreeHeap(PsxHeap, 0, (PVOID)IntControlBlock);
  660. ApiReply(p,m,NULL);
  661. RtlFreeHeap(PsxHeap, 0, (PVOID)m);
  662. return;
  663. }
  664. //
  665. // Rewait
  666. //
  667. p->State = Waiting;
  668. (void)BlockProcess(p,
  669. NULL,
  670. WaitPidHandler,
  671. m,
  672. NULL,
  673. &PsxProcessStructureLock);
  674. }
  675. BOOLEAN
  676. PsxWaitPid(
  677. IN PPSX_PROCESS p,
  678. IN PPSX_API_MSG m
  679. )
  680. /*++
  681. Routine Description:
  682. This function implements the wait() and waitpid() APIs.
  683. Arguments:
  684. p - Supplies the address of the calling process
  685. m - Supplies the address of the related message
  686. Return Value:
  687. TRUE - Always succeeds and generates a reply
  688. --*/
  689. {
  690. NTSTATUS Status;
  691. PPSX_WAITPID_MSG args;
  692. PPSX_PROCESS cp;
  693. pid_t TargetProcess;
  694. pid_t TargetGroup;
  695. BOOLEAN EmitEchild;
  696. enum _WaitType { AnyProcess, SpecificProcess, SpecificGroup };
  697. enum _WaitType WaitType;
  698. args = &m->u.WaitPid;
  699. //
  700. // Test for invalid options
  701. //
  702. if (args->Options & ~(WNOHANG|WUNTRACED)) {
  703. m->Error = EINVAL;
  704. return TRUE;
  705. }
  706. TargetProcess = SPECIALPID;
  707. TargetGroup = SPECIALPID;
  708. WaitType = AnyProcess;
  709. if (args->Pid <= 0 && args->Pid != (pid_t)-1) {
  710. WaitType = SpecificGroup;
  711. if (args->Pid == 0) {
  712. TargetGroup = p->ProcessGroupId;
  713. } else {
  714. TargetGroup = -1 * args->Pid;
  715. }
  716. } else {
  717. if (args->Pid != (pid_t)-1) {
  718. TargetProcess = args->Pid;
  719. WaitType = SpecificProcess;
  720. }
  721. }
  722. AcquireProcessStructureLock();
  723. EmitEchild = TRUE;
  724. //
  725. // Scan process table
  726. //
  727. for (cp = FirstProcess; cp < LastProcess; cp++) {
  728. if (cp->Flags & P_FREE) {
  729. continue;
  730. }
  731. //
  732. // Until we know whether or not there is a process that
  733. // could possibly satisfy a wait, we have to keep looking
  734. // at all processes.
  735. //
  736. if (EmitEchild) {
  737. if (WaitType == SpecificGroup) {
  738. if (cp->ParentPid == p->Pid &&
  739. cp->ProcessGroupId == TargetGroup) {
  740. EmitEchild = FALSE;
  741. }
  742. } else {
  743. if (cp->ParentPid == p->Pid) {
  744. if (WaitType == SpecificProcess) {
  745. if (cp->Pid == TargetProcess) {
  746. EmitEchild = FALSE;
  747. }
  748. } else {
  749. EmitEchild = FALSE;
  750. }
  751. }
  752. }
  753. }
  754. //
  755. // Just look at processes that could possibly satisfy a wait.
  756. // - Processes that have exited
  757. // - Stopped processes that have not previously satisfied
  758. // a wait (if WUNTRACED was set)
  759. //
  760. if (cp->State == Exited ||
  761. (cp->State == Stopped && (args->Options & WUNTRACED) &&
  762. !(cp->Flags & P_WAITED))) {
  763. if (cp->ParentPid != p->Pid) {
  764. continue;
  765. }
  766. switch (WaitType) {
  767. case AnyProcess:
  768. m->ReturnValue = cp->Pid;
  769. args->StatLocValue = cp->ExitStatus;
  770. break;
  771. case SpecificProcess:
  772. if (cp->Pid == TargetProcess) {
  773. m->ReturnValue = cp->Pid;
  774. args->StatLocValue = cp->ExitStatus;
  775. }
  776. break;
  777. case SpecificGroup:
  778. if (cp->ProcessGroupId == TargetGroup) {
  779. m->ReturnValue = cp->Pid;
  780. args->StatLocValue = cp->ExitStatus;
  781. }
  782. break;
  783. }
  784. if (m->ReturnValue) {
  785. //
  786. // wait was satisfied
  787. //
  788. if ( cp->State == Exited ) {
  789. p->ProcessTimes.tms_cstime += (cp->ProcessTimes.tms_stime
  790. + cp->ProcessTimes.tms_cstime);
  791. p->ProcessTimes.tms_cutime += (cp->ProcessTimes.tms_utime
  792. + cp->ProcessTimes.tms_cutime);
  793. //
  794. // Deallocate the process
  795. //
  796. cp->Flags |= P_FREE;
  797. RtlDeleteCriticalSection(&cp->ProcessLock);
  798. } else {
  799. //
  800. // Set a bit to keep this stopped process from satisfying
  801. // another wait.
  802. //
  803. cp->Flags |= P_WAITED;
  804. args->StatLocValue = cp->ExitStatus | (1L << 30);
  805. }
  806. ReleaseProcessStructureLock();
  807. return TRUE;
  808. }
  809. }
  810. }
  811. if (EmitEchild) {
  812. m->Error = ECHILD;
  813. ReleaseProcessStructureLock();
  814. return TRUE;
  815. }
  816. if (args->Options & WNOHANG) {
  817. m->ReturnValue = 0;
  818. args->StatLocValue = 0;
  819. ReleaseProcessStructureLock();
  820. return TRUE;
  821. }
  822. //
  823. // Make the process sleep until the wait can be satisfied.
  824. //
  825. p->State = Waiting;
  826. Status = BlockProcess(p, NULL, WaitPidHandler, m, NULL,
  827. &PsxProcessStructureLock);
  828. if (!NT_SUCCESS(Status)) {
  829. m->Error = PsxStatusToErrno(Status);
  830. return TRUE;
  831. }
  832. //
  833. // The process has successfully been blocked. Don't reply to the api
  834. // request message.
  835. //
  836. return FALSE;
  837. }
  838. BOOLEAN
  839. PsxSetSid(
  840. IN PPSX_PROCESS p,
  841. IN PPSX_API_MSG m
  842. )
  843. /*++
  844. Routine Description:
  845. This function implements the setsid() API.
  846. Arguments:
  847. p - Supplies the address of the calling process
  848. m - Supplies the address of the related message
  849. Return Value:
  850. TRUE - Always succeeds and generates a reply
  851. --*/
  852. {
  853. PPSX_SESSION OldSession;
  854. //
  855. // 1003.1-90 (4.3.2.4): EPERM when the calling process
  856. // is already a process group leader.
  857. //
  858. if (p->Pid == p->ProcessGroupId) {
  859. m->Error = EPERM;
  860. return TRUE;
  861. }
  862. //
  863. // Create a new session with no controlling tty and make
  864. // the calling process the session leader.
  865. //
  866. AcquireProcessStructureLock();
  867. LockNtSessionList();
  868. RemoveEntryList(&p->GroupLinks);
  869. InitializeListHead(&p->GroupLinks);
  870. //
  871. // Make the process the leader of his process group.
  872. //
  873. p->ProcessGroupId = p->Pid;
  874. OldSession = p->PsxSession;
  875. p->PsxSession = PsxAllocateSession(NULL, p->Pid);
  876. UnlockNtSessionList();
  877. ReleaseProcessStructureLock();
  878. DEREFERENCE_PSX_SESSION(OldSession, 0);
  879. m->ReturnValue = (pid_t)p->ProcessGroupId;
  880. return TRUE;
  881. }
  882. BOOLEAN
  883. PsxSetPGroupId(
  884. IN PPSX_PROCESS p,
  885. IN PPSX_API_MSG m
  886. )
  887. /*++
  888. Routine Description:
  889. This function implements the setpgid() API.
  890. Arguments:
  891. p - Supplies the address of the calling process
  892. m - Supplies the address of the related message
  893. Return Value:
  894. TRUE - Always succeeds and generates a reply
  895. --*/
  896. {
  897. PPSX_SETPGROUPID_MSG args;
  898. pid_t TargetPid, TargetGroup;
  899. PPSX_PROCESS cp, Target;
  900. BOOLEAN EmitEsrch;
  901. args = &m->u.SetPGroupId;
  902. if (args->Pid < 0 || args->Pgid < 0) {
  903. m->Error = EINVAL;
  904. return TRUE;
  905. }
  906. TargetPid = (args->Pid ? args->Pid : p->Pid);
  907. TargetGroup = (args->Pgid ? args->Pgid : TargetPid);
  908. AcquireProcessStructureLock();
  909. LockNtSessionList();
  910. if ( p->Pid == TargetPid ) {
  911. Target = p;
  912. } else {
  913. //
  914. // Scan process table
  915. //
  916. EmitEsrch = TRUE;
  917. for (cp = FirstProcess ;cp < LastProcess ;cp++ ) {
  918. if ( cp->Flags & P_FREE ) {
  919. continue;
  920. }
  921. if ( cp->ParentPid == p->Pid && cp->Pid == TargetPid ) {
  922. EmitEsrch = FALSE;
  923. Target = cp;
  924. break;
  925. }
  926. }
  927. if ( EmitEsrch ) {
  928. m->Error = ESRCH;
  929. goto done;
  930. }
  931. }
  932. //
  933. // If target is a child who has executed an exec, then report error
  934. //
  935. if (Target->ParentPid == p->Pid && (Target->Flags & P_HAS_EXECED)) {
  936. m->Error = EACCES;
  937. goto done;
  938. }
  939. //
  940. // If target is a session leader, then report error
  941. //
  942. if ( Target->PsxSession->SessionLeader == TargetPid ) {
  943. m->Error = EPERM;
  944. goto done;
  945. }
  946. //
  947. // If target is not in the same session as the calling process, then
  948. // report error
  949. //
  950. if ( Target->PsxSession != p->PsxSession ) {
  951. m->Error = EPERM;
  952. goto done;
  953. }
  954. if ( TargetPid != TargetGroup ) {
  955. //
  956. // Scan process table looking for a pgrp id the same
  957. // as TargetGroup and is in the same session is the calling process
  958. //
  959. EmitEsrch = TRUE;
  960. for (cp = FirstProcess ;cp < LastProcess ;cp++ ) {
  961. if ( cp->Flags & P_FREE ) {
  962. continue;
  963. }
  964. if ( cp->ProcessGroupId == TargetGroup &&
  965. p->PsxSession == cp->PsxSession ) {
  966. EmitEsrch = FALSE;
  967. break;
  968. }
  969. }
  970. if ( EmitEsrch ) {
  971. m->Error = EPERM;
  972. goto done;
  973. }
  974. } else {
  975. cp = Target;
  976. }
  977. //
  978. // Everything is ok, so set the Target's pgrp id to the specified id
  979. //
  980. RemoveEntryList(&Target->GroupLinks);
  981. if (cp != Target) {
  982. InsertHeadList(&cp->GroupLinks, &Target->GroupLinks);
  983. } else {
  984. InitializeListHead(&Target->GroupLinks);
  985. }
  986. Target->ProcessGroupId = TargetGroup;
  987. done:
  988. UnlockNtSessionList();
  989. ReleaseProcessStructureLock();
  990. return TRUE;
  991. }
  992. BOOLEAN
  993. PsxGetProcessTimes(
  994. IN PPSX_PROCESS p,
  995. IN PPSX_API_MSG m
  996. )
  997. /*++
  998. Routine Description:
  999. This function implements the times() API.
  1000. Arguments:
  1001. p - Supplies the address of the calling process
  1002. m - Supplies the address of the related message
  1003. Return Value:
  1004. TRUE - Always succeeds and generates a reply
  1005. --*/
  1006. {
  1007. PPSX_GETPROCESSTIMES_MSG args;
  1008. NTSTATUS Status;
  1009. KERNEL_USER_TIMES ProcessTime;
  1010. ULONG PosixTime, Remainder;
  1011. ULONG LengthNeeded;
  1012. args = &m->u.GetProcessTimes;
  1013. {
  1014. LARGE_INTEGER DelayInterval;
  1015. DelayInterval.HighPart = 0;
  1016. DelayInterval.LowPart = 100;
  1017. NtDelayExecution(TRUE, &DelayInterval);
  1018. }
  1019. //
  1020. // Get the time for this process and add to the accumulated time for
  1021. // the process
  1022. //
  1023. Status = NtQueryInformationProcess(p->Process, ProcessTimes,
  1024. (PVOID)&ProcessTime, sizeof(ProcessTime), &LengthNeeded);
  1025. ASSERT(NT_SUCCESS(Status));
  1026. PosixTime = RtlExtendedLargeIntegerDivide(ProcessTime.UserTime,
  1027. 10000, &Remainder).LowPart;
  1028. args->ProcessTimes.tms_utime = p->ProcessTimes.tms_utime + PosixTime;
  1029. PosixTime = RtlExtendedLargeIntegerDivide(ProcessTime.KernelTime,
  1030. 10000, &Remainder).LowPart;
  1031. args->ProcessTimes.tms_stime = p->ProcessTimes.tms_stime + PosixTime;
  1032. args->ProcessTimes.tms_cutime = p->ProcessTimes.tms_cutime;
  1033. args->ProcessTimes.tms_cstime = p->ProcessTimes.tms_cstime;
  1034. return TRUE;
  1035. }
  1036. BOOLEAN
  1037. PsxGetGroups(
  1038. IN PPSX_PROCESS p,
  1039. IN PPSX_API_MSG m
  1040. )
  1041. /*++
  1042. Routine Description:
  1043. This function implements the getgroups() API.
  1044. Arguments:
  1045. p - Supplies the address of the calling process
  1046. m - Supplies the address of the related message
  1047. Return Value:
  1048. TRUE - Always succeeds and generates a reply
  1049. XXX.mjb:
  1050. NT essentially puts no limit on the number of supplementary groups
  1051. a user may belong to. This is bad for Posix, since we want a limit,
  1052. and we want it small enough that people don't mess themselves up by
  1053. allocating an array[NGROUPS_MAX] of gid_t.
  1054. --*/
  1055. {
  1056. PPSX_GETGROUPS_MSG args;
  1057. NTSTATUS Status;
  1058. HANDLE TokenHandle;
  1059. TOKEN_GROUPS *pGroups;
  1060. ULONG outlen, i, j;
  1061. gid_t *GroupList;
  1062. args = &m->u.GetGroups;
  1063. //
  1064. // Check args->GroupList for group array address validity.
  1065. //
  1066. //
  1067. // Examine the new process's token to figure out what the
  1068. // uid's should be.
  1069. //
  1070. Status = NtOpenProcessToken(p->Process, GENERIC_READ,
  1071. &TokenHandle);
  1072. ASSERT(NT_SUCCESS(Status));
  1073. //
  1074. // Get the supplemental groups.
  1075. //
  1076. Status = NtQueryInformationToken(TokenHandle, TokenGroups, NULL,
  1077. 0, &outlen);
  1078. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  1079. pGroups = RtlAllocateHeap(PsxHeap, 0, outlen);
  1080. if (NULL == pGroups) {
  1081. //
  1082. // We don't have enough memory to hold the list of the process's
  1083. // groups. What is there to do except return an error?
  1084. //
  1085. NtClose(TokenHandle);
  1086. m->Error = ENOMEM;
  1087. return TRUE;
  1088. }
  1089. Status = NtQueryInformationToken(TokenHandle, TokenGroups, (PVOID)pGroups,
  1090. outlen, &outlen);
  1091. if (!NT_SUCCESS(Status)) {
  1092. KdPrint(("PSXSS: NtQueryInformationToken failed: 0x%x\n",
  1093. Status));
  1094. RtlFreeHeap(PsxHeap, 0, (PVOID)pGroups);
  1095. NtClose(TokenHandle);
  1096. m->Error = EACCES;
  1097. return TRUE;
  1098. }
  1099. //
  1100. // If the user has passed in a listsize of 0, then we only return
  1101. // the number of supplementary groups, without writing anything in
  1102. // the group array.
  1103. //
  1104. if (0 == args->NGroups) {
  1105. m->ReturnValue = pGroups->GroupCount;
  1106. m->Error = 0;
  1107. NtClose(TokenHandle);
  1108. RtlFreeHeap(PsxHeap, 0, (PVOID)pGroups);
  1109. return TRUE;
  1110. }
  1111. if ((ULONG)args->NGroups < pGroups->GroupCount) {
  1112. if (args->NGroups < NGROUPS_MAX) {
  1113. m->Error = EINVAL;
  1114. return TRUE;
  1115. }
  1116. //
  1117. // XXX.mjb: We're having a problem here. The caller has
  1118. // allocated space for the maximum number of groups that the
  1119. // user can have, according to the _NGROUPS_MAX limit, but
  1120. // the user actually has more groups than that. This can
  1121. // happen because NT's limit is indeterminate.
  1122. //
  1123. // ignore the groups that we cannot return.
  1124. pGroups->GroupCount = args->NGroups;
  1125. }
  1126. //
  1127. // Make an array of gid_t's and copy it to the user address space.
  1128. //
  1129. GroupList = RtlAllocateHeap(PsxHeap, 0, pGroups->GroupCount *
  1130. sizeof(gid_t));
  1131. if (NULL == GroupList) {
  1132. RtlFreeHeap(PsxHeap, 0, (PVOID)pGroups);
  1133. NtClose(TokenHandle);
  1134. m->Error = ENOMEM;
  1135. return TRUE;
  1136. }
  1137. for (i = 0, j = 0; i < pGroups->GroupCount; ++i) {
  1138. PSID Sid = pGroups->Groups[i].Sid;
  1139. GroupList[j] = MakePosixId(Sid);
  1140. if (0 != GroupList[j]) {
  1141. ++j;
  1142. }
  1143. }
  1144. //
  1145. // Copy GroupList to client's address space, at the place
  1146. // specified.
  1147. //
  1148. Status = NtWriteVirtualMemory(p->Process, args->GroupList,
  1149. GroupList, j * sizeof(gid_t), NULL);
  1150. RtlFreeHeap(PsxHeap, 0, (PVOID)GroupList);
  1151. if (!NT_SUCCESS(Status)) {
  1152. m->Error = PsxStatusToErrno(Status);
  1153. RtlFreeHeap(PsxHeap, 0, (PVOID)pGroups);
  1154. NtClose(TokenHandle);
  1155. return TRUE;
  1156. }
  1157. m->ReturnValue = j;
  1158. RtlFreeHeap(PsxHeap, 0, (PVOID)pGroups);
  1159. NtClose(TokenHandle);
  1160. return TRUE;
  1161. }
  1162. BOOLEAN
  1163. PsxGetLogin(
  1164. IN PPSX_PROCESS p,
  1165. IN PPSX_API_MSG m
  1166. )
  1167. /*++
  1168. Routine Description:
  1169. This function implements the getlogin() API.
  1170. Arguments:
  1171. p - Supplies the address of the calling process
  1172. m - Supplies the address of the related message
  1173. Return Value:
  1174. TRUE - Always succeeds and generates a reply
  1175. XXX.mjb: this routine is never called; getlogin() is implemented as
  1176. "getpwuid(getuid())->pw_name", kind of. See client-side getlogin().
  1177. --*/
  1178. {
  1179. PPSX_GETLOGIN_MSG args;
  1180. NTSTATUS Status;
  1181. args = &m->u.GetLogin;
  1182. args->LoginName; // w.r.t. our address space
  1183. m->Error = ENOSYS;
  1184. return TRUE;
  1185. }
  1186. BOOLEAN
  1187. PsxSysconf(
  1188. IN PPSX_PROCESS p,
  1189. IN PPSX_API_MSG m
  1190. )
  1191. /*++
  1192. Routine Description:
  1193. This function implements the sysconf() api.
  1194. Arguments:
  1195. p - Supplies the address of the calling process.
  1196. m - Supplies the address of the related message.
  1197. Return Value:
  1198. TRUE - Always succeeds and generates a reply.
  1199. --*/
  1200. {
  1201. PPSX_SYSCONF_MSG args;
  1202. NTSTATUS Status;
  1203. long value;
  1204. PPSX_PROCESS Process;
  1205. args = &m->u.Sysconf;
  1206. switch (args->Name) {
  1207. case _SC_ARG_MAX:
  1208. value = ARG_MAX;
  1209. break;
  1210. case _SC_CHILD_MAX:
  1211. //
  1212. // This is the reason sysconf is implemented in the
  1213. // server. We don't bother to grab any locks, since the
  1214. // result is out of date by the time it gets back to the
  1215. // user anyway.
  1216. //
  1217. value = 1;
  1218. for (Process = FirstProcess; Process < LastProcess; ++Process) {
  1219. if (Process->Flags & P_FREE) {
  1220. ++value;
  1221. }
  1222. }
  1223. break;
  1224. case _SC_CLK_TCK:
  1225. value = CLK_TCK;
  1226. break;
  1227. case _SC_NGROUPS_MAX:
  1228. value = NGROUPS_MAX;
  1229. break;
  1230. case _SC_OPEN_MAX:
  1231. value = OPEN_MAX;
  1232. break;
  1233. case _SC_JOB_CONTROL:
  1234. #ifdef _POSIX_JOB_CONTROL
  1235. value = 1;
  1236. break;
  1237. #else
  1238. value = 0;
  1239. break;
  1240. #endif
  1241. case _SC_SAVED_IDS:
  1242. #ifdef _POSIX_SAVED_IDS
  1243. value = 1;
  1244. #else
  1245. value = 0;
  1246. #endif
  1247. break;
  1248. case _SC_VERSION:
  1249. value = _POSIX_VERSION;
  1250. break;
  1251. case _SC_STREAM_MAX:
  1252. value = STREAM_MAX;
  1253. break;
  1254. case _SC_TZNAME_MAX:
  1255. value = TZNAME_MAX;
  1256. break;
  1257. default:
  1258. value = -1;
  1259. m->Error = EINVAL;
  1260. }
  1261. m->ReturnValue = value;
  1262. return TRUE;
  1263. }
  1264. #ifdef EXEC_FOREIGN
  1265. #define UNICODE
  1266. #include <windows.h>
  1267. DWORD ForeignProcessWait(PVOID);
  1268. NTSTATUS
  1269. ExecForeignImage(
  1270. PPSX_PROCESS p,
  1271. PPSX_API_MSG m,
  1272. PUNICODE_STRING Image,
  1273. PUNICODE_STRING CurDir
  1274. )
  1275. {
  1276. PPSX_EXEC_MSG args;
  1277. NTSTATUS Status;
  1278. LPWSTR CommandLine;
  1279. LPVOID Environment;
  1280. STARTUPINFO StartInfo;
  1281. PROCESS_INFORMATION ProcInfo;
  1282. BOOL Success = FALSE;
  1283. char **ppch;
  1284. PWCHAR pwc;
  1285. ULONG flags;
  1286. ULONG ThreadId;
  1287. HANDLE ForeignProc;
  1288. ULONG len;
  1289. args = &m->u.Exec;
  1290. //
  1291. // Convert argv array to command line format.
  1292. //
  1293. CommandLine = RtlAllocateHeap(PsxHeap, 0, ARG_MAX);
  1294. if (NULL == CommandLine) {
  1295. return STATUS_NO_MEMORY;
  1296. }
  1297. CommandLine[0] = 0;
  1298. ppch = (PVOID)args->Args;
  1299. for (ppch = (PVOID)args->Args; NULL != *ppch; ++ppch) {
  1300. ANSI_STRING A;
  1301. UNICODE_STRING U;
  1302. // this breaks on args with spaces in them
  1303. A.Buffer = *ppch + (ULONG)args->Args;
  1304. A.Length = A.MaximumLength = strlen(A.Buffer);
  1305. U.Buffer = &CommandLine[wcslen(CommandLine)];
  1306. U.Length = 0;
  1307. U.MaximumLength = ARG_MAX;
  1308. Status = RtlAnsiStringToUnicodeString(&U, &A, FALSE);
  1309. ASSERT(NT_SUCCESS(Status));
  1310. wcscat((PVOID)CommandLine, L" ");
  1311. }
  1312. Status = RtlCreateEnvironment(FALSE, &Environment);
  1313. if (!NT_SUCCESS(Status)) {
  1314. RtlFreeHeap(PsxHeap, 0, CommandLine);
  1315. return Status;
  1316. }
  1317. for (++ppch; NULL != *ppch; ++ppch) {
  1318. ANSI_STRING aName, aValue;
  1319. UNICODE_STRING nU, vU;
  1320. char *pch;
  1321. pch = strchr(*ppch + (ULONG)args->Args, '=');
  1322. ASSERT(NULL != pch);
  1323. *pch = '\0';
  1324. aName.Buffer = *ppch + (ULONG)args->Args;
  1325. aName.Length = strlen(aName.Buffer);
  1326. aName.MaximumLength = aName.Length;
  1327. aValue.Buffer = pch + 1;
  1328. aValue.Length = strlen(aValue.Buffer);
  1329. aValue.MaximumLength = aName.Length;
  1330. if (0 == stricmp("PATH", aName.Buffer)) {
  1331. ConvertPathToWin(aValue.Buffer);
  1332. aValue.Length = strlen(aValue.Buffer);
  1333. }
  1334. *pch = '=';
  1335. Status = RtlAnsiStringToUnicodeString(&nU, &aName, TRUE);
  1336. if (!NT_SUCCESS(Status)) {
  1337. RtlFreeHeap(PsxHeap, 0, CommandLine);
  1338. RtlDestroyEnvironment(Environment);
  1339. return Status;
  1340. }
  1341. Status = RtlAnsiStringToUnicodeString(&vU, &aValue, TRUE);
  1342. if (!NT_SUCCESS(Status)) {
  1343. RtlFreeHeap(PsxHeap, 0, nU.Buffer);
  1344. RtlFreeHeap(PsxHeap, 0, CommandLine);
  1345. RtlDestroyEnvironment(Environment);
  1346. return Status;
  1347. }
  1348. Status = RtlSetEnvironmentVariable_U(&Environment, &nU, &vU);
  1349. RtlFreeHeap(PsxHeap, 0, nU.Buffer);
  1350. RtlFreeHeap(PsxHeap, 0, vU.Buffer);
  1351. if (!NT_SUCCESS(Status)) {
  1352. KdPrint(("PSXSS: RtlSetEnvVar: 0x%x\n", Status));
  1353. RtlFreeHeap(PsxHeap, 0, CommandLine);
  1354. RtlDestroyEnvironment(Environment);
  1355. return Status;
  1356. }
  1357. }
  1358. // Make Image into correct format: "X:\path", return to original
  1359. // after we're done.
  1360. pwc = Image->Buffer;
  1361. PSX_GET_SIZEOF(DOSDEVICE_W,len);
  1362. Image->Buffer += (len - 2)/2;
  1363. Image->Length -= (len - 2);
  1364. flags = CREATE_SUSPENDED|CREATE_NEW_CONSOLE|
  1365. CREATE_NEW_PROCESS_GROUP|CREATE_UNICODE_ENVIRONMENT;
  1366. // set up StartInfo
  1367. StartInfo.cb = sizeof(STARTUPINFO);
  1368. StartInfo.lpReserved = 0;
  1369. StartInfo.lpDesktop = NULL;
  1370. StartInfo.lpTitle = NULL;
  1371. StartInfo.dwX = StartInfo.dwY = 0;
  1372. StartInfo.dwXSize = StartInfo.dwYSize = 400;
  1373. StartInfo.dwFlags = 0;
  1374. StartInfo.wShowWindow = SW_SHOWDEFAULT;
  1375. StartInfo.cbReserved2 = 0;
  1376. StartInfo.lpReserved2 = NULL;
  1377. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  1378. if (NT_SUCCESS(Status)) {
  1379. Success = CreateProcess(
  1380. Image->Buffer, // address of module name
  1381. CommandLine, // command line
  1382. NULL, // process security attr
  1383. NULL, // thread security attr
  1384. FALSE, // inherit handles
  1385. flags, // creation flags
  1386. Environment, // address of new environ
  1387. CurDir->Buffer, // current working dir
  1388. &StartInfo, // startup info
  1389. &ProcInfo // process information
  1390. );
  1391. EndImpersonation();
  1392. }
  1393. // restore image name
  1394. Image->Buffer = pwc;
  1395. (void)RtlDestroyEnvironment(Environment);
  1396. // ASSERT(NT_SUCCESS(Status));
  1397. RtlFreeHeap(PsxHeap, 0, CommandLine);
  1398. if (!Success) {
  1399. KdPrint(("PSXSS: CreateProcess: %d\n", GetLastError()));
  1400. return STATUS_UNSUCCESSFUL;
  1401. }
  1402. p->Thread = ProcInfo.hThread;
  1403. p->Process = ProcInfo.hProcess;
  1404. // set bit in the process to indicate it's a foreign
  1405. // image type
  1406. p->Flags |= P_FOREIGN_EXEC;
  1407. // create additional thread in psxss to wait for new
  1408. // process to exit.
  1409. p->BlockingThread = NULL;
  1410. Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
  1411. if (NT_SUCCESS(Status)) {
  1412. p->BlockingThread = CreateThread(
  1413. NULL,
  1414. 0,
  1415. ForeignProcessWait,
  1416. (PVOID)p,
  1417. CREATE_SUSPENDED,
  1418. &ThreadId
  1419. );
  1420. EndImpersonation();
  1421. if (NULL == p->BlockingThread) {
  1422. //XXX.mjb: clean process
  1423. Status = STATUS_UNSUCCESSFUL;
  1424. }
  1425. }
  1426. if (!NT_SUCCESS(Status)) {
  1427. return Status;
  1428. }
  1429. Success = ResumeThread(p->BlockingThread);
  1430. ASSERT(Success);
  1431. Success = ResumeThread(p->Thread);
  1432. ASSERT(Success);
  1433. return STATUS_SUCCESS;
  1434. }
  1435. DWORD
  1436. ForeignProcessWait(PVOID arg)
  1437. {
  1438. PPSX_PROCESS p = arg;
  1439. ULONG ExitStatus;
  1440. WaitForSingleObject(p->Process, (DWORD)-1);
  1441. Exit(p, ExitStatus);
  1442. p->BlockingThread = NULL;
  1443. ExitThread(0);
  1444. //NOTREACHED
  1445. ASSERT(0);
  1446. return 0;
  1447. }
  1448. //
  1449. // Change a posix-type path variable to win32 path. The given
  1450. // buffer is modified in place.
  1451. //
  1452. VOID
  1453. ConvertPathToWin(char *path)
  1454. {
  1455. char *pch;
  1456. pch = path;
  1457. while (*path) {
  1458. // change ':' to ';'
  1459. if (':' == *path) {
  1460. *pch = ';';
  1461. ++path;
  1462. ++pch;
  1463. continue;
  1464. }
  1465. // change "//X" to "X:"
  1466. if ('/' == *path && '/' == path[1]) {
  1467. path += 2;
  1468. *pch = *path;
  1469. ++pch;
  1470. *pch = ':';
  1471. ++path;
  1472. ++pch;
  1473. continue;
  1474. }
  1475. // change slash to backslash
  1476. if ('/' == *path) {
  1477. *pch = '\\';
  1478. ++path;
  1479. ++pch;
  1480. continue;
  1481. }
  1482. *pch = *path;
  1483. ++pch;
  1484. ++path;
  1485. }
  1486. *pch = '\0';
  1487. }
  1488. #endif /* EXEC_FOREIGN */