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.

1958 lines
50 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. process.c
  5. Abstract:
  6. Implementation of PSX Process Structure Backbone.
  7. Author:
  8. Mark Lucovsky (markl) 08-Mar-1989
  9. Revision History:
  10. --*/
  11. #include "psxsrv.h"
  12. #include "seposix.h"
  13. #include "sesport.h"
  14. NTSTATUS
  15. PsxInitializeProcessStructure()
  16. /*++
  17. Routine Description:
  18. This function initializes the PSX process structure. This includes
  19. creating an initial process table, open file tables, CLIENT_ID to PID hash
  20. table, and PID allocator.
  21. Arguments:
  22. None.
  23. Return Value:
  24. Status.
  25. --*/
  26. {
  27. LONG i;
  28. PPSX_PROCESS Process;
  29. NTSTATUS Status;
  30. //
  31. // Initialize PsxProcessStructureLock
  32. //
  33. Status = RtlInitializeCriticalSection(&BlockLock);
  34. ASSERT(NT_SUCCESS(Status));
  35. InitializeListHead(&DefaultBlockList);
  36. Status = RtlInitializeCriticalSection(&PsxProcessStructureLock);
  37. ASSERT(NT_SUCCESS(Status));
  38. //
  39. // Initialize the ClientIdHashTable
  40. //
  41. for (i = 0; i < CIDHASHSIZE ; i++) {
  42. InitializeListHead(&ClientIdHashTable[i]);
  43. }
  44. //
  45. // Initialize Process Table
  46. //
  47. FirstProcess = PsxProcessTable;
  48. LastProcess = &PsxProcessTable[32-1];
  49. for (Process = FirstProcess; Process < LastProcess; Process++) {
  50. Process->Flags |= P_FREE;
  51. Process->SequenceNumber = 0;
  52. }
  53. return Status;
  54. }
  55. PPSX_PROCESS
  56. PsxAllocateProcess (
  57. IN PCLIENT_ID ClientId
  58. )
  59. /*++
  60. Routine Description:
  61. This function allocates a slot in the process table for the process
  62. with the specified CLIENT_ID. Once a free process table slot is
  63. allocated, the process is placed in the ClientIdHashTable. The process
  64. slot sequence number is incremented, and a Pid is assigned to the
  65. process. The process' process lock in initialized, and the process
  66. table lock is released. A pointer to the new process is returned.
  67. The process lock of the new process remains held so that the caller
  68. can further initialize the process.
  69. Arguments:
  70. ClientId - Supplies the address of the client id associated with the
  71. process. Only the UniqueProcess portion of the ClientId is used.
  72. Return Value:
  73. Null - No free process table slot could be located.
  74. Non-Null - A pointer to the allocated process. The process' process lock is
  75. held, the process can be located in the ClientIdHashTable, and
  76. the process has a Pid.
  77. --*/
  78. {
  79. PPSX_PROCESS Process;
  80. ULONG index;
  81. NTSTATUS Status;
  82. //
  83. // Lock Process Table
  84. //
  85. AcquireProcessStructureLock();
  86. for (Process = FirstProcess, index = 0; Process < LastProcess;
  87. Process++, index++) {
  88. if (!(Process->Flags & P_FREE)) {
  89. continue;
  90. }
  91. //
  92. // Slot Found. Mark process as allocated and free process table
  93. // lock.
  94. //
  95. Process->Flags &= ~P_FREE;
  96. Process->ClientId = *ClientId;
  97. Process->ClientPort = NULL;
  98. //
  99. // Place Process In CLIENT_ID Hash Table
  100. //
  101. InsertTailList(&ClientIdHashTable[CIDTOHASHINDEX(ClientId)],
  102. &Process->ClientIdHashLinks);
  103. if (++Process->SequenceNumber > 255)
  104. Process->SequenceNumber = 1;
  105. MAKEPID(Process->Pid, Process->SequenceNumber, index);
  106. if (Process->Pid == SPECIALPID) {
  107. KdPrint(("PSXSS: seq %d, index %d\n", Process->SequenceNumber, index));
  108. }
  109. ASSERT(Process->Pid != SPECIALPID);
  110. Status = RtlInitializeCriticalSection(&Process->ProcessLock);
  111. if (!NT_SUCCESS(Status)) {
  112. ReleaseProcessStructureLock();
  113. return NULL;
  114. }
  115. AcquireProcessLock(Process);
  116. //
  117. // Unlock Process Table
  118. //
  119. ReleaseProcessStructureLock();
  120. IF_PSX_DEBUG(EXEC) {
  121. KdPrint(("PsxAllocateProcess: Process = %lx, ClientId %lx.%lx "
  122. "Pid %lx\n", Process, Process->ClientId.UniqueProcess,
  123. Process->ClientId.UniqueThread, Process->Pid));
  124. }
  125. return Process;
  126. }
  127. //
  128. // Unlock Process Table
  129. //
  130. ReleaseProcessStructureLock();
  131. return (PPSX_PROCESS)NULL;
  132. }
  133. PPSX_PROCESS
  134. PsxLocateProcessByClientId (
  135. IN PCLIENT_ID ClientId
  136. )
  137. /*++
  138. Routine Description:
  139. This function attempts to locate the process with the specified CLIENT_ID.
  140. It depends on the way PsxAllocateProcess allocates a process table
  141. slot, assigns it a CLIENT_ID, and places it in the ClientIdHashTable while
  142. holding the PsxProcessStructureLock. Only the UniqueProcess portion of the
  143. specified CLIENT_ID is used.
  144. Arguments:
  145. ClientId - Supplies the client id associated with the process to be located.
  146. Return Value:
  147. Null - No process whose client id matches the specified ClientId parameter
  148. is located in the ClientIdHashTable.
  149. Non-Null - Returns the address of the process whose CLIENT_ID matches the
  150. specified ClientId.
  151. --*/
  152. {
  153. PPSX_PROCESS Process;
  154. PLIST_ENTRY head, next;
  155. head = &ClientIdHashTable[CIDTOHASHINDEX(ClientId)];
  156. //
  157. // Lock Process Table
  158. //
  159. AcquireProcessStructureLock();
  160. next = head->Flink;
  161. while (next != head) {
  162. Process = CONTAINING_RECORD(next, PSX_PROCESS, ClientIdHashLinks);
  163. if (Process->ClientId.UniqueProcess == ClientId->UniqueProcess &&
  164. Process->ClientId.UniqueThread == ClientId->UniqueThread) {
  165. //
  166. // Unlock Process Table
  167. //
  168. ReleaseProcessStructureLock();
  169. return Process;
  170. }
  171. next = next->Flink;
  172. }
  173. //
  174. // Unlock Process Table
  175. //
  176. ReleaseProcessStructureLock();
  177. return (PPSX_PROCESS)NULL;
  178. }
  179. PPSX_PROCESS
  180. PsxLocateProcessBySession (
  181. IN PPSX_SESSION Session
  182. )
  183. {
  184. PPSX_PROCESS Process;
  185. //
  186. // Lock Process Table
  187. //
  188. AcquireProcessStructureLock();
  189. for (Process = FirstProcess; Process < LastProcess; Process++) {
  190. if (!(Process->Flags & P_FREE)) {
  191. continue;
  192. }
  193. if (Process->PsxSession == Session) {
  194. //
  195. // Unlock Process Table
  196. //
  197. ReleaseProcessStructureLock();
  198. return Process;
  199. }
  200. }
  201. //
  202. // Unlock Process Table
  203. //
  204. ReleaseProcessStructureLock();
  205. return (PPSX_PROCESS)NULL;
  206. }
  207. BOOLEAN
  208. IsGroupOrphaned(
  209. IN pid_t ProcessGroup
  210. )
  211. /*++
  212. Routine Description:
  213. This function is called to determine if the specified ProcessGroup
  214. is orphaned.
  215. An orphaned process group is a group where the parent of every member
  216. is itself a member, or is not a member of the group's session. This
  217. definition is a little flawed since it assumes that processes without
  218. a parent are inherited by a real process in a different session.
  219. Arguments:
  220. ProcessGroup - Supplies the process group to check
  221. Return Value:
  222. TRUE - The process group is orphaned.
  223. FALSE - The process group is not orphaned.
  224. --*/
  225. {
  226. PPSX_PROCESS Parent, FirstMember, NextMember;
  227. PLIST_ENTRY Next;
  228. BOOLEAN Orphaned,MemberFound;
  229. LockNtSessionList();
  230. //
  231. // First locate a member of the group by scanning the process
  232. // table. Once a group member is found, then whip through the
  233. // group list looking to see if any member's parent is not in
  234. // the session of the group, or whose parent is SPECIALPID
  235. //
  236. MemberFound = FALSE;
  237. for (FirstMember = FirstProcess; FirstMember < LastProcess; FirstMember++) {
  238. if (FirstMember->Flags & P_FREE) {
  239. continue;
  240. }
  241. if (FirstMember->ProcessGroupId == ProcessGroup) {
  242. MemberFound = TRUE;
  243. break;
  244. }
  245. }
  246. ASSERT(MemberFound);
  247. Orphaned = FALSE;
  248. //
  249. // Scan the group. For each member, look at the members parent.
  250. //
  251. // If the parent is SPECIALPID, then the group is orphaned,
  252. // else if the parent is not in the same group and is in a
  253. // different session, then the group is oprphaned
  254. //
  255. NextMember = FirstMember;
  256. do {
  257. //
  258. // The parent of a member is not in the same session so the
  259. // group is orphaned.
  260. //
  261. if (NextMember->ParentPid == SPECIALPID) {
  262. Orphaned = TRUE;
  263. break;
  264. } else {
  265. //
  266. // The member has a parent, so see if the parent is in
  267. // a different group and in a different session. If this
  268. // is the case, then the group is orphaned.
  269. //
  270. Parent = PIDTOPROCESS(NextMember->ParentPid);
  271. if (Parent->ProcessGroupId != ProcessGroup &&
  272. Parent->PsxSession != FirstMember->PsxSession) {
  273. Orphaned = TRUE;
  274. break;
  275. }
  276. }
  277. Next = NextMember->GroupLinks.Flink;
  278. NextMember = CONTAINING_RECORD(Next, PSX_PROCESS, GroupLinks);
  279. } while (NextMember != FirstMember);
  280. UnlockNtSessionList();
  281. return Orphaned;
  282. }
  283. BOOLEAN
  284. PsxStopProcess(
  285. IN PPSX_PROCESS p,
  286. IN PPSX_API_MSG m,
  287. IN ULONG Signal,
  288. IN sigset_t *RestoreBlockSigset OPTIONAL
  289. )
  290. /*++
  291. Routine Description:
  292. This function is called by PendingSignalHandledInside in response
  293. to a pending stop signal. It simply blocks the process awaiting a
  294. SIGCONT signal.
  295. Arguments:
  296. p - Supplies the address of the process to stop
  297. m - Supplies the reply message to be generated when the process is
  298. continued
  299. Signal - Supplies the signal number used to stop the process.
  300. If the stop signal is anything other than SIGSTOP, a check is
  301. made to see if the processes group is orphaned before stopping
  302. the process.
  303. RestoreBlockSigset - Contains an optional blocked signal mask to
  304. be restured during the reply.
  305. Locks - Process lock always released before return.
  306. Return Value:
  307. TRUE - The process was stopped by this call.
  308. FALSE - The process was not stopped.
  309. --*/
  310. {
  311. sigset_t RestoreBlockMask;
  312. PPSX_PROCESS Parent;
  313. NTSTATUS Status;
  314. if (ARGUMENT_PRESENT(RestoreBlockSigset)) {
  315. RestoreBlockMask = *RestoreBlockSigset;
  316. } else {
  317. RestoreBlockMask = (sigset_t)0xffffffff;
  318. }
  319. ReleaseProcessLock(p);
  320. AcquireProcessStructureLock();
  321. if (Signal != SIGSTOP) {
  322. if (IsGroupOrphaned(p->ProcessGroupId)) {
  323. ReleaseProcessStructureLock();
  324. return FALSE;
  325. }
  326. }
  327. p->State = Stopped;
  328. p->ExitStatus = (Signal << 8) | 0177;
  329. p->Flags &= ~P_WAITED; // proc may satisfy wait
  330. //
  331. // Possibly generate a SIGCHLD to the parent, and satisfy
  332. // a parent wait
  333. //
  334. if (p->ParentPid != SPECIALPID) {
  335. Parent = PIDTOPROCESS(p->ParentPid);
  336. AcquireProcessLock(Parent);
  337. //
  338. // if the SA_NOCLDSTOP flag is not sent, then SIGCHLD the parent
  339. //
  340. if (!Parent->SignalDataBase.SignalDisposition[SIGCHLD-1].sa_flags
  341. & SA_NOCLDSTOP) {
  342. PsxSignalProcess(Parent,SIGCHLD);
  343. }
  344. ReleaseProcessLock(Parent);
  345. if (Parent->State == Waiting) {
  346. Status = BlockProcess(p, (PVOID)RestoreBlockMask,
  347. PsxStopProcessHandler, m, FALSE, &PsxProcessStructureLock);
  348. if (!NT_SUCCESS(Status)) {
  349. m->Error = PsxStatusToErrno(Status);
  350. return FALSE;
  351. }
  352. UnblockProcess(Parent, WaitSatisfyInterrupt, FALSE, 0);
  353. return TRUE;
  354. }
  355. }
  356. Status = BlockProcess(p, (PVOID)RestoreBlockMask, PsxStopProcessHandler,
  357. m, FALSE, &PsxProcessStructureLock);
  358. if (!NT_SUCCESS(Status)) {
  359. m->Error = PsxStatusToErrno(Status);
  360. return FALSE;
  361. }
  362. return TRUE;
  363. }
  364. VOID
  365. PsxStopProcessHandler(
  366. IN PPSX_PROCESS p,
  367. IN PINTCB IntControlBlock,
  368. IN PSX_INTERRUPTREASON InterruptReason,
  369. IN int Signal
  370. )
  371. /*++
  372. Routine Description:
  373. This procedure is called when a stopped process is continued.
  374. Arguments:
  375. p - Supplies the address of the process being continued.
  376. IntControlBlock - Supplies the address of the interrupt control block.
  377. InterruptReason - Supplies the reason that this process is being
  378. interrupted. Not used in this handler.
  379. Return Value:
  380. None.
  381. --*/
  382. {
  383. PPSX_API_MSG m;
  384. sigset_t RestoreBlockSigset;
  385. UNREFERENCED_PARAMETER(InterruptReason);
  386. RtlLeaveCriticalSection(&BlockLock);
  387. RestoreBlockSigset = (sigset_t)((ULONG_PTR)IntControlBlock->IntContext);
  388. m = IntControlBlock->IntMessage;
  389. RtlFreeHeap(PsxHeap, 0, (PVOID)IntControlBlock);
  390. m->Signal = Signal;
  391. if ((ULONG)RestoreBlockSigset == 0xffffffff) {
  392. ApiReply(p, m ,NULL);
  393. } else {
  394. ApiReply(p, m, &RestoreBlockSigset);
  395. }
  396. RtlFreeHeap(PsxHeap, 0, (PVOID)m);
  397. }
  398. VOID
  399. PsxSignalProcess(
  400. IN PPSX_PROCESS p,
  401. IN ULONG Signal
  402. )
  403. /*++
  404. Routine Description:
  405. This function causes the specified signal to be sent to the specified
  406. process. Thsi works by simply marking the signal as pending, and then
  407. making the process looking at ats pending signals.
  408. This function must be called with the PsxProcessTable locked
  409. Getting the process to look at its pending signals has three basic cases:
  410. 1) The process is not in PSX.
  411. Cause the process to call __NullPosixAPI
  412. 2) The process is inside PSX and is not interruptible
  413. Simply set signal to pending
  414. 3) The process is inside PSX and is interruptible
  415. Dispatch to the process' interrupt control block
  416. Arguments:
  417. p - Supplies the address of the process to signal.
  418. Signal - Supplies the Signal value.
  419. Return Value:
  420. None.
  421. --*/
  422. {
  423. NTSTATUS Status;
  424. sigset_t Pending;
  425. ASSERT(NULL != p);
  426. AcquireProcessLock(p);
  427. //
  428. // This can happen due to exit recursion
  429. //
  430. if (p->State == Exited) {
  431. ReleaseProcessLock(p);
  432. return;
  433. }
  434. //
  435. // if signal is SIGCONT, then clear any pending stop signals
  436. // if signal is a stop signal, then clear any pending SIGCONT
  437. //
  438. switch (Signal) {
  439. case SIGCONT:
  440. p->SignalDataBase.PendingSignalMask &= ~_SIGSTOPSIGNALS;
  441. if (p->State == Stopped) {
  442. SIGADDSET(&p->SignalDataBase.PendingSignalMask,SIGCONT);
  443. p->State = Active;
  444. ReleaseProcessLock(p);
  445. UnblockProcess(p, SignalInterrupt, FALSE, Signal);
  446. return;
  447. }
  448. break;
  449. case SIGSTOP:
  450. case SIGTSTP:
  451. case SIGTTIN:
  452. case SIGTTOU:
  453. //
  454. // XXX.mjb: FIX to deal w/ orphaned group
  455. //
  456. p->SignalDataBase.PendingSignalMask &= ~(1L << (SIGCONT - 1));
  457. break;
  458. default:
  459. break;
  460. }
  461. //
  462. // If signal is being ignored, don't add it to the pending set.
  463. //
  464. if (p->SignalDataBase.SignalDisposition[Signal-1].sa_handler
  465. == (_handler)SIG_IGN) {
  466. ReleaseProcessLock(p);
  467. return;
  468. }
  469. //
  470. // Add signal to pending set. If any pending but not blocked signals
  471. // exist for the process, then maybe make the process take a look at
  472. // its pending signals.
  473. //
  474. SIGADDSET(&p->SignalDataBase.PendingSignalMask, Signal);
  475. Pending = p->SignalDataBase.PendingSignalMask &
  476. ~p->SignalDataBase.BlockedSignalMask;
  477. //
  478. // If the signal is defaulted and the default action is to ignore,
  479. // add it to the pending set but don't interrupt the system call.
  480. // This allows a process to block sigchld and then handle it later
  481. // by changing the action and then unblocking.
  482. //
  483. if (Signal == SIGCHLD &&
  484. p->SignalDataBase.SignalDisposition[Signal-1].sa_handler
  485. == (_handler)SIG_DFL) {
  486. ReleaseProcessLock(p);
  487. return;
  488. }
  489. if (!Pending) {
  490. // Fast path: no pending unblocked signals.
  491. ReleaseProcessLock(p);
  492. return;
  493. }
  494. if (p->InPsx > 0) {
  495. if (Stopped == p->State && SIGKILL != Signal) {
  496. //
  497. // While a process is stopped, any additional signals that
  498. // are sent to the process shall not be delivered until the
  499. // process is continued except SIGKILL, which always terminates
  500. // the receiving process. 1003.1-1990 3.3.1.3 (1b)
  501. //
  502. ReleaseProcessLock(p);
  503. return;
  504. }
  505. // XXX.mjb: I'm tense about this code. The process being
  506. // killed is InPsx, and we're unblocking him. But what if
  507. // a processes is killing himself, or there is more than one
  508. // api request thread and the other process is executing a
  509. // system call, but is not blocked?
  510. ReleaseProcessLock(p);
  511. UnblockProcess(p, SignalInterrupt, FALSE, Signal);
  512. return;
  513. }
  514. if (p->State == Unconnected) {
  515. // leave the signal pending
  516. ReleaseProcessLock(p);
  517. return;
  518. }
  519. ReleaseProcessLock(p);
  520. //
  521. // Drag Process inside so that it looks at its signals. We set
  522. // the NO_FORK bit to ensure that the process calls the NullApi
  523. // before he calls fork. We want to avoid a situation where the
  524. // process stack is modified by RtlRemoteCall while the process
  525. // is blocked in lpc in fork(), and we copy his stack to a child
  526. // process.
  527. //
  528. p->Flags |= P_NO_FORK;
  529. Status = RtlRemoteCall(p->Process, p->Thread, (PVOID)p->NullApiCaller,
  530. 0, NULL, TRUE, FALSE);
  531. if (!NT_SUCCESS(Status)) {
  532. KdPrint(("Dragging proc 0x%x inside for sig %d\n", p->Pid, Signal));
  533. KdPrint(("PSXSS: RtlRemoteCall: 0x%x\n", Status));
  534. }
  535. }
  536. static NTSTATUS
  537. InitProcNoParent(
  538. PPSX_PROCESS NewProcess,
  539. IN PPSX_SESSION Session OPTIONAL,
  540. IN ULONG SessionId OPTIONAL
  541. );
  542. static void
  543. InitProcFromParent(
  544. PPSX_PROCESS NewProcess,
  545. PPSX_PROCESS ForkProcess
  546. );
  547. NTSTATUS
  548. PsxInitializeProcess(
  549. IN PPSX_PROCESS NewProcess,
  550. IN PPSX_PROCESS ForkProcess OPTIONAL,
  551. IN ULONG SessionId OPTIONAL,
  552. IN HANDLE ProcessHandle,
  553. IN HANDLE ThreadHandle,
  554. IN PPSX_SESSION Session OPTIONAL
  555. )
  556. {
  557. NTSTATUS Status;
  558. NewProcess->IntControlBlock = (PINTCB)NULL;
  559. NewProcess->State = Unconnected;
  560. NewProcess->Flags = 0;
  561. NewProcess->Process = ProcessHandle;
  562. NewProcess->Thread = ThreadHandle;
  563. NewProcess->AlarmTimer = NULL;
  564. NewProcess->ProcessIsBeingDebugged = FALSE;
  565. NewProcess->BlockingThread = (HANDLE)NULL;
  566. RtlZeroMemory((PVOID)&NewProcess->ProcessTimes, sizeof(struct tms));
  567. if (ARGUMENT_PRESENT(ForkProcess)) {
  568. InitProcFromParent(NewProcess, ForkProcess);
  569. Status = STATUS_SUCCESS;
  570. } else {
  571. Status = InitProcNoParent(NewProcess, Session, SessionId);
  572. }
  573. ReleaseProcessLock(NewProcess);
  574. return Status;
  575. }
  576. static void
  577. InitProcFromParent(
  578. PPSX_PROCESS NewProcess,
  579. PPSX_PROCESS ForkProcess
  580. )
  581. {
  582. NTSTATUS Status;
  583. //
  584. // Propagate Process Attributes
  585. //
  586. //
  587. // InPsx -- this new process will return directly to user-land,
  588. // without the posix subsystem replying to his message. Therefore,
  589. // we set InPsx to 0 here.
  590. //
  591. NewProcess->InPsx = 0;
  592. NewProcess->ParentPid = ForkProcess->Pid;
  593. NewProcess->ProcessGroupId = ForkProcess->ProcessGroupId;
  594. InsertHeadList(&ForkProcess->GroupLinks,
  595. &NewProcess->GroupLinks);
  596. REFERENCE_PSX_SESSION(ForkProcess->PsxSession);
  597. NewProcess->PsxSession = ForkProcess->PsxSession;
  598. NewProcess->EffectiveUid = ForkProcess->EffectiveUid;
  599. NewProcess->RealUid = ForkProcess->RealUid;
  600. NewProcess->EffectiveGid = ForkProcess->EffectiveGid;
  601. NewProcess->RealGid = ForkProcess->RealGid;
  602. NewProcess->DirectoryPrefix = ForkProcess->DirectoryPrefix;
  603. NewProcess->FileModeCreationMask = ForkProcess->FileModeCreationMask;
  604. if (ForkProcess->ProcessIsBeingDebugged && PsxpDebuggerActive) {
  605. Status = NtSetInformationProcess(NewProcess->Process,
  606. ProcessDebugPort, (PVOID)&PsxpDebugPort,
  607. sizeof(HANDLE));
  608. if (NT_SUCCESS(Status)) {
  609. NewProcess->ProcessIsBeingDebugged = TRUE;
  610. NewProcess->DebugUiClientId = ForkProcess->DebugUiClientId;
  611. }
  612. }
  613. //
  614. // Fork the signal database
  615. //
  616. NewProcess->SignalDataBase = ForkProcess->SignalDataBase;
  617. SIGEMPTYSET(&NewProcess->SignalDataBase.PendingSignalMask);
  618. //
  619. // Fork The Open File Table
  620. //
  621. ForkProcessFileTable(ForkProcess, NewProcess);
  622. ReleaseProcessLock(ForkProcess);
  623. }
  624. static NTSTATUS
  625. InitProcNoParent(
  626. PPSX_PROCESS NewProcess,
  627. IN PPSX_SESSION Session,
  628. IN ULONG SessionId OPTIONAL
  629. )
  630. {
  631. HANDLE TokenHandle = NULL;
  632. TOKEN_PRIMARY_GROUP *pGroup = NULL;
  633. TOKEN_GROUPS *pGroups = NULL;
  634. PTOKEN_USER pTokenUser = NULL;
  635. ULONG LengthNeeded;
  636. PULONG pu;
  637. PSID_AND_ATTRIBUTES pSA;
  638. NTSTATUS Status;
  639. PFILEDESCRIPTOR Fd;
  640. ULONG i;
  641. PSID SecondGroupChoice; // to be used if primary group is
  642. // no good.
  643. BOOLEAN PrimaryGroupOk; // is primary group good?
  644. NewProcess->ParentPid = SPECIALPID;
  645. NewProcess->ProcessGroupId = NewProcess->Pid; // process group
  646. InitializeListHead(&NewProcess->GroupLinks);
  647. //
  648. // This process doesn't get to user-land by returning from an lpc
  649. // api, so we take the opportunity to set InPsx to zero here.
  650. //
  651. NewProcess->InPsx = 0;
  652. Session->SessionLeader = NewProcess->Pid;
  653. NewProcess->PsxSession = Session;
  654. //XXX.mjb: is this really right? Or &= ~P_HAS_EXECED?
  655. NewProcess->Flags |= P_HAS_EXECED;
  656. NewProcess->DirectoryPrefix = NULL;
  657. //
  658. // Signal DataBase
  659. //
  660. SIGEMPTYSET(&NewProcess->SignalDataBase.BlockedSignalMask);
  661. SIGEMPTYSET(&NewProcess->SignalDataBase.PendingSignalMask);
  662. SIGEMPTYSET(&NewProcess->SignalDataBase.SigSuspendMask);
  663. for (i = 0; i < _SIGMAXSIGNO; i++) {
  664. NewProcess->SignalDataBase.SignalDisposition[i].sa_handler =
  665. (_handler)SIG_DFL;
  666. NewProcess->SignalDataBase.SignalDisposition[i].sa_flags = 0;
  667. SIGEMPTYSET(&NewProcess->SignalDataBase.SignalDisposition[i].sa_mask);
  668. }
  669. Fd = NewProcess->ProcessFileTable;
  670. RtlEnterCriticalSection(&SystemOpenFileLock);
  671. {
  672. for (i = 0; i < OPEN_MAX; i++, Fd++) {
  673. Fd->SystemOpenFileDesc = (PSYSTEMOPENFILE)NULL;
  674. Fd->Flags = 0;
  675. }
  676. } RtlLeaveCriticalSection(&SystemOpenFileLock);
  677. //
  678. // Examine the new process's token to figure out what the
  679. // uid should be.
  680. //
  681. Status = NtOpenProcessToken(NewProcess->Process, GENERIC_READ,
  682. &TokenHandle);
  683. ASSERT(NT_SUCCESS(Status));
  684. Status = NtQueryInformationToken(TokenHandle, TokenUser,
  685. NULL, 0, &LengthNeeded);
  686. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  687. pTokenUser = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
  688. if (NULL == pTokenUser) {
  689. Status = STATUS_NO_MEMORY;
  690. goto out;
  691. }
  692. Status = NtQueryInformationToken(TokenHandle, TokenUser,
  693. (PVOID)pTokenUser, LengthNeeded, &LengthNeeded);
  694. if (!NT_SUCCESS(Status)) {
  695. KdPrint(("PSXSS: NtQueryInfoToken: 0x%x\n", Status));
  696. }
  697. ASSERT(NT_SUCCESS(Status));
  698. NewProcess->EffectiveUid = NewProcess->RealUid =
  699. MakePosixId(pTokenUser->User.Sid);
  700. //
  701. // Figure out the primary group. Security allows the user to
  702. // set his primary group to whatever he wants, so we make sure
  703. // that his choice is reasonable. If his PrimaryGroup is in
  704. // the group array, he's fine. If it's not, we make his
  705. // PrimaryGroup the first group from the group array other
  706. // than World. If there are none other than World, that's
  707. // what he gets.
  708. //
  709. Status = NtQueryInformationToken(TokenHandle, TokenPrimaryGroup,
  710. NULL, 0, &LengthNeeded);
  711. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  712. pGroup = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
  713. if (NULL == pGroup) {
  714. NewProcess->EffectiveGid = NewProcess->RealGid = 0;
  715. Status = STATUS_NO_MEMORY;
  716. goto out;
  717. }
  718. Status = NtQueryInformationToken(TokenHandle, TokenPrimaryGroup,
  719. (PVOID)pGroup, LengthNeeded, &LengthNeeded);
  720. ASSERT(NT_SUCCESS(Status));
  721. Status = NtQueryInformationToken(TokenHandle, TokenGroups, NULL,
  722. 0, &LengthNeeded);
  723. ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
  724. pGroups = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
  725. if (NULL == pGroups) {
  726. NewProcess->EffectiveGid = NewProcess->RealGid = 0;
  727. Status = STATUS_NO_MEMORY;
  728. goto out;
  729. }
  730. Status = NtQueryInformationToken(TokenHandle, TokenGroups,
  731. (PVOID)pGroups,
  732. LengthNeeded, &LengthNeeded);
  733. ASSERT(NT_SUCCESS(Status));
  734. SecondGroupChoice = NULL;
  735. PrimaryGroupOk = FALSE;
  736. for (i = 0; i < pGroups->GroupCount; ++i) {
  737. if (RtlEqualSid(pGroups->Groups[i].Sid, pGroup->PrimaryGroup)) {
  738. PrimaryGroupOk = TRUE;
  739. }
  740. //
  741. // Our second group choice is the first group in the list
  742. // that is not the World group.
  743. //
  744. if (NULL == SecondGroupChoice &&
  745. SE_WORLD_POSIX_ID != MakePosixId(pGroups->Groups[i].Sid)) {
  746. SecondGroupChoice = pGroups->Groups[i].Sid;
  747. }
  748. }
  749. if (PrimaryGroupOk) {
  750. NewProcess->EffectiveGid = NewProcess->RealGid =
  751. MakePosixId(pGroup->PrimaryGroup);
  752. } else if (NULL != SecondGroupChoice) {
  753. NewProcess->EffectiveGid = NewProcess->RealGid =
  754. MakePosixId(SecondGroupChoice);
  755. } else {
  756. NewProcess->EffectiveGid = NewProcess->RealGid =
  757. SE_WORLD_POSIX_ID;
  758. }
  759. out:
  760. if (pGroup) RtlFreeHeap(PsxHeap, 0, (PVOID)pGroup);
  761. if (pGroups) RtlFreeHeap(PsxHeap, 0, (PVOID)pGroups);
  762. if (pTokenUser) RtlFreeHeap(PsxHeap, 0, (PVOID)pTokenUser);
  763. if (TokenHandle) NtClose(TokenHandle);
  764. return Status;
  765. }
  766. //
  767. // PsxCreateProcess -- this routine is called only by PsxCreateConSession
  768. // to create the first process for a brand-new session.
  769. //
  770. BOOLEAN
  771. PsxCreateProcess(
  772. PPSX_EXEC_INFO ExecInfo,
  773. OUT PPSX_PROCESS *NewProcess,
  774. IN HANDLE ParentProcess,
  775. IN PPSX_SESSION Session
  776. )
  777. {
  778. NTSTATUS Status;
  779. UNICODE_STRING ImageFileName;
  780. UNICODE_STRING Path;
  781. UNICODE_STRING LibPath;
  782. UNICODE_STRING CWD;
  783. PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  784. RTL_USER_PROCESS_INFORMATION ProcessInformation;
  785. PPSX_PROCESS Process;
  786. Path.Buffer = NULL;
  787. LibPath.Buffer = NULL;
  788. CWD.Buffer = NULL;
  789. Status = RtlAnsiStringToUnicodeString(&Path, &ExecInfo->Path, TRUE);
  790. if (NT_SUCCESS(Status)) {
  791. Status = RtlAnsiStringToUnicodeString(&LibPath, &ExecInfo->LibPath, TRUE);
  792. if (NT_SUCCESS(Status)) {
  793. Status = RtlAnsiStringToUnicodeString(&CWD, &ExecInfo->CWD, TRUE);
  794. }
  795. }
  796. if (NT_SUCCESS(Status)) {
  797. //
  798. // Beware - ExecInfo->ArgV is used to pass uninterpreted binary
  799. // data. It is NOT an ANSI string. So don't try to convert
  800. // to Unicode. Just lie to RtlCreateProcessParameters.
  801. //
  802. Status = RtlCreateProcessParameters(&ProcessParameters, &Path,
  803. &LibPath, &CWD, (PUNICODE_STRING)&ExecInfo->Argv, NULL,
  804. NULL, NULL, NULL, NULL);
  805. }
  806. RtlFreeUnicodeString( &Path );
  807. RtlFreeUnicodeString( &LibPath );
  808. RtlFreeUnicodeString( &CWD );
  809. if (!NT_SUCCESS(Status)) {
  810. return FALSE; // ENOMEM
  811. }
  812. ProcessParameters->CurrentDirectory.Handle = NULL;
  813. ImageFileName = ProcessParameters->ImagePathName;
  814. ImageFileName.Buffer = (PWSTR)
  815. ((PCHAR)ImageFileName.Buffer + (ULONG_PTR)ProcessParameters);
  816. IF_PSX_DEBUG(EXEC) {
  817. KdPrint(("PSXSS: Creating process %wZ\n", &ImageFileName));
  818. }
  819. Status = RtlCreateUserProcess(&ImageFileName, OBJ_CASE_INSENSITIVE,
  820. ProcessParameters, NULL,
  821. NULL, ParentProcess, TRUE, NULL, NULL, &ProcessInformation);
  822. RtlDestroyProcessParameters(ProcessParameters);
  823. if (!NT_SUCCESS(Status)) {
  824. KdPrint(("PSXSS: RtlCreateUserProcess: 0x%x\n", Status));
  825. return FALSE; // ENOEXEC
  826. }
  827. if (ProcessInformation.ImageInformation.SubSystemType !=
  828. IMAGE_SUBSYSTEM_POSIX_CUI) {
  829. NtClose(ProcessInformation.Process);
  830. return FALSE; // ENOEXEC
  831. }
  832. Status = NtSetInformationProcess(ProcessInformation.Process,
  833. ProcessExceptionPort, (PVOID)&PsxApiPort, sizeof(PsxApiPort));
  834. if (!NT_SUCCESS(Status)) {
  835. KdPrint(("PSXSS: NtSetInfoProc: 0x%x\n", Status));
  836. }
  837. ASSERT(NT_SUCCESS(Status));
  838. {
  839. ULONG HardErrorMode = 0; // disable popups
  840. Status = NtSetInformationProcess(
  841. ProcessInformation.Process,
  842. ProcessDefaultHardErrorMode,
  843. (PVOID)&HardErrorMode,
  844. sizeof(HardErrorMode)
  845. );
  846. ASSERT(NT_SUCCESS(Status));
  847. }
  848. Process = PsxAllocateProcess(&ProcessInformation.ClientId);
  849. if (!Process) {
  850. Status = NtTerminateProcess(ProcessInformation.Process,
  851. STATUS_SUCCESS);
  852. ASSERT(NT_SUCCESS(Status));
  853. NtClose(ProcessInformation.Process);
  854. NtClose(ProcessInformation.Thread);
  855. return FALSE; // EAGAIN
  856. }
  857. if (! PsxInitializeDirectories(Process, &ExecInfo->CWD)) {
  858. Status = NtTerminateProcess(ProcessInformation.Process,
  859. STATUS_SUCCESS);
  860. ASSERT(NT_SUCCESS(Status));
  861. NtClose(ProcessInformation.Process);
  862. NtClose(ProcessInformation.Thread);
  863. return FALSE;
  864. }
  865. Status = PsxInitializeProcess(Process, NULL, 0L,
  866. ProcessInformation.Process, ProcessInformation.Thread, Session);
  867. if (!NT_SUCCESS(Status)) {
  868. RtlFreeHeap(PsxHeap, 0, Process->DirectoryPrefix->PsxRoot.Buffer);
  869. RtlFreeHeap(PsxHeap, 0,
  870. Process->DirectoryPrefix->NtCurrentWorkingDirectory.Buffer);
  871. RtlFreeHeap(PsxHeap, 0, Process->DirectoryPrefix);
  872. Process->DirectoryPrefix = NULL;
  873. Status = NtTerminateProcess(ProcessInformation.Process,
  874. STATUS_SUCCESS);
  875. ASSERT(NT_SUCCESS(Status));
  876. NtClose(ProcessInformation.Process);
  877. NtClose(ProcessInformation.Thread);
  878. return FALSE;
  879. }
  880. Process->InitialPebPsxData.Length = sizeof(Process->InitialPebPsxData);
  881. Process->InitialPebPsxData.ClientStartAddress = NULL;
  882. //
  883. // Set the session port. The client constructs the port name from the
  884. // unique id, opens the port, and sets the actual handle.
  885. //
  886. Process->InitialPebPsxData.SessionPortHandle =
  887. (HANDLE)Process->PsxSession->Terminal->UniqueId;
  888. *NewProcess = Process;
  889. return TRUE;
  890. }
  891. PPSX_SESSION
  892. PsxAllocateSession(
  893. IN PPSX_CONTROLLING_TTY Terminal OPTIONAL,
  894. IN pid_t SessionLeader
  895. )
  896. /*++
  897. Routine Description:
  898. This function is called to allocate and initialize a posix
  899. session.
  900. Each session may be associated with a controlling terminal. If
  901. the Terminal parameter is specified, and if the terminal is
  902. associated with a session, then no new session is created, and the
  903. process simply joins the session as a new process group. This
  904. case can only occur in a double handoff... (a foreign app is execed,
  905. and then it execs a POSIX app with a terminal stdin that is the same
  906. as the one it left with.
  907. Arguments:
  908. Terminal - An optional parameter, that if supplied specifies the
  909. controlling terminal to be associated with the session.
  910. SessionLeader - Supplies the process id of the session leader for
  911. this session.
  912. Return Value:
  913. Returns a pointer to the new session.
  914. --*/
  915. {
  916. PPSX_SESSION Session;
  917. if (ARGUMENT_PRESENT(Terminal)) {
  918. //
  919. // Look inside terminal to see if it is associated with a session.
  920. // If not, then create a session attached to the terminal
  921. // (logon to posix). If it is associated with a session, then become
  922. // a new group in the session and dis-regard SessionLeader parameter
  923. //
  924. ;
  925. }
  926. //
  927. // Allocate storage for the session and initialize the session
  928. //
  929. Session = RtlAllocateHeap(PsxHeap, 0,sizeof(PSX_SESSION));
  930. if (NULL == Session) {
  931. return NULL;
  932. }
  933. Session->ReferenceCount = 1;
  934. Session->SessionLeader = SessionLeader;
  935. Session->Terminal = Terminal;
  936. if (ARGUMENT_PRESENT(Terminal)) {
  937. Terminal->ForegroundProcessGroup = SessionLeader;
  938. Terminal->Session = Session;
  939. }
  940. return Session;
  941. }
  942. VOID
  943. PsxDeallocateSession(
  944. IN PPSX_SESSION Session
  945. )
  946. /*++
  947. Routine Description:
  948. This function deallocates a posix session and frees the terminal
  949. so that it can become associated with new sessions.
  950. Arguments:
  951. Session - Supplies the address of the posix session being deallocated
  952. Return Value:
  953. None.
  954. --*/
  955. {
  956. NTSTATUS Status;
  957. if (Session->Terminal) {
  958. Session->Terminal->ForegroundProcessGroup = SPECIALPID;
  959. Session->Terminal->Session = NULL;
  960. RtlDeleteCriticalSection(&Session->Terminal->Lock);
  961. if (NULL != Session->Terminal->IoBuffer) {
  962. Status = NtUnmapViewOfSection(NtCurrentProcess(),
  963. Session->Terminal->IoBuffer);
  964. ASSERT(NT_SUCCESS(Status));
  965. }
  966. RtlFreeHeap(PsxHeap, 0, (PVOID)Session->Terminal);
  967. }
  968. UnlockNtSessionList();
  969. RtlFreeHeap(PsxHeap, 0, (PVOID)Session);
  970. }
  971. VOID
  972. PsxTerminateProcessBySignal(
  973. IN PPSX_PROCESS p,
  974. IN PPSX_API_MSG m,
  975. IN ULONG Signal
  976. )
  977. {
  978. UNREFERENCED_PARAMETER(m);
  979. Exit(p, Signal);
  980. }
  981. VOID
  982. Exit(
  983. IN PPSX_PROCESS p,
  984. IN ULONG ExitStatus
  985. )
  986. /*++
  987. Routine Description:
  988. This function process termination. It is called either
  989. from PsxExit as a result of an applications call to _exit(),
  990. or from within PSX to terminate a process.
  991. Arguments:
  992. p - Supplies the address of the exiting process
  993. ExitStatus - Supplies the exit status for the exiting process
  994. Return Value:
  995. None.
  996. --*/
  997. {
  998. PPSX_PROCESS cp, WaitingParent,Parent;
  999. PPSX_PROCESS FirstMember, NextMember;
  1000. PLIST_ENTRY Next;
  1001. NTSTATUS Status;
  1002. HANDLE AlarmTimer;
  1003. BOOLEAN OrphanedAGroupRelatedChild, AlreadyOrphaned, PreviousTimerState;
  1004. KERNEL_USER_TIMES ProcessTime;
  1005. BOOLEAN WaitForProcess;
  1006. if ((ULONG)-1 == ExitStatus) {
  1007. //
  1008. // This process is dying because of some extraordinary event,
  1009. // and we should make sure that we clean up no matter what.
  1010. // XXX.mjb: ExitStatus could be different and more informative,
  1011. // but I haven't had a chance to test that.
  1012. //
  1013. WaitForProcess = FALSE;
  1014. ExitStatus = 0;
  1015. } else {
  1016. WaitForProcess = TRUE;
  1017. }
  1018. AcquireProcessLock(p);
  1019. if (Exited == p->State) {
  1020. ReleaseProcessLock(p);
  1021. return;
  1022. }
  1023. p->State = Exited;
  1024. p->Flags &= ~P_WAITED; // proc may satisfy wait
  1025. //
  1026. // The goal is that after we've changed the process state, no one else
  1027. // will try to muck with this process. So we should be able to
  1028. // release the process lock now.
  1029. //
  1030. ReleaseProcessLock(p);
  1031. p->ExitStatus = ExitStatus;
  1032. WaitingParent = NULL;
  1033. Parent = NULL;
  1034. OrphanedAGroupRelatedChild = FALSE;
  1035. //
  1036. // If this is a local directory prefix, then deallocate it
  1037. //
  1038. if (!IS_DIRECTORY_PREFIX_REMOTE(p->DirectoryPrefix)) {
  1039. if (p->DirectoryPrefix) {
  1040. if (p->DirectoryPrefix->NtCurrentWorkingDirectory.Buffer) {
  1041. RtlFreeHeap(PsxHeap, 0,
  1042. (PVOID)p->DirectoryPrefix->NtCurrentWorkingDirectory.Buffer);
  1043. }
  1044. if (p->DirectoryPrefix->PsxCurrentWorkingDirectory.Buffer) {
  1045. RtlFreeHeap(PsxHeap, 0,
  1046. (PVOID)p->DirectoryPrefix->PsxCurrentWorkingDirectory.Buffer);
  1047. }
  1048. if (p->DirectoryPrefix->PsxRoot.Buffer) {
  1049. RtlFreeHeap(PsxHeap,
  1050. 0,(PVOID)p->DirectoryPrefix->PsxRoot.Buffer);
  1051. }
  1052. RtlFreeHeap(PsxHeap, 0,(PVOID)p->DirectoryPrefix);
  1053. }
  1054. }
  1055. //
  1056. // Lock the process table so that we can clear process' AlarmTimer
  1057. // interlocked with AlarmApcRoutine. Can not use ProcessLock since
  1058. // it is deallocated during process exit.
  1059. //
  1060. // REVISIT deallocation of process lock...
  1061. //
  1062. AcquireProcessStructureLock();
  1063. //
  1064. // Cancel and close alarm timer if present
  1065. //
  1066. if (p->AlarmTimer) {
  1067. AlarmTimer = p->AlarmTimer;
  1068. p->AlarmTimer = NULL;
  1069. //
  1070. // Unlock process table while doing timer cleanup
  1071. //
  1072. ReleaseProcessStructureLock();
  1073. Status = NtCancelTimer(AlarmTimer, &PreviousTimerState);
  1074. if (!NT_SUCCESS(Status)) {
  1075. KdPrint(("PSXSS: NtCancelTimer: 0x%x\n", Status));
  1076. }
  1077. ASSERT(NT_SUCCESS(Status));
  1078. Status = NtClose(AlarmTimer);
  1079. ASSERT(NT_SUCCESS(Status));
  1080. //
  1081. // Lock the process table so that we can scan process table.
  1082. //
  1083. AcquireProcessStructureLock();
  1084. }
  1085. //
  1086. // Scan process table looking for children, and job control
  1087. // related processes.
  1088. //
  1089. AlreadyOrphaned = IsGroupOrphaned(p->ProcessGroupId);
  1090. for (cp = FirstProcess; cp < LastProcess; cp++) {
  1091. //
  1092. // Only look at non-free slots
  1093. //
  1094. if (cp->Flags & P_FREE) {
  1095. continue;
  1096. }
  1097. if (cp->ParentPid == p->Pid) {
  1098. //
  1099. // Orphan and send SIGHUP to each child process
  1100. //
  1101. cp->ParentPid = SPECIALPID;
  1102. if (cp->State == Exited) {
  1103. //
  1104. // Orphaning an exited process is almost like an
  1105. // implicit wait in the sense that process resources
  1106. // are freed immediately.
  1107. //
  1108. cp->Flags |= P_FREE;
  1109. //
  1110. // Remove Process from CLIENT_ID Hash Table
  1111. //
  1112. RemoveEntryList(&cp->ClientIdHashLinks);
  1113. ASSERT(NULL != cp);
  1114. try {
  1115. RtlDeleteCriticalSection(&cp->ProcessLock);
  1116. } except (EXCEPTION_EXECUTE_HANDLER) {
  1117. KdPrint(("PSXSS: took a fault\n"));
  1118. }
  1119. } else {
  1120. if (cp->ProcessGroupId == p->ProcessGroupId) {
  1121. OrphanedAGroupRelatedChild = TRUE;
  1122. }
  1123. // PsxSignalProcess(cp, SIGHUP);
  1124. }
  1125. }
  1126. }
  1127. if (p->ParentPid != SPECIALPID) {
  1128. //
  1129. // The process has a parent. Process termination could satisfy a
  1130. // wait() or waitpid(). Parent must also be signaled.
  1131. //
  1132. Parent = PIDTOPROCESS(p->ParentPid);
  1133. //
  1134. // See if parent is waiting. Arange for wait completion...
  1135. //
  1136. if (Parent->State == Waiting) {
  1137. WaitingParent = Parent;
  1138. }
  1139. PsxSignalProcess(Parent, SIGCHLD);
  1140. }
  1141. //
  1142. // Check to see if the exiting processes group is already orphaned.
  1143. // If so, then do not do anything. Otherwise, remove him from the
  1144. // group list and then whip through the group. If any stopped processes
  1145. // are found, then SIGCONT, SIGHUP all processes in the group
  1146. //
  1147. LockNtSessionList();
  1148. FirstMember = CONTAINING_RECORD(p->GroupLinks.Flink, PSX_PROCESS,
  1149. GroupLinks);
  1150. RemoveEntryList(&p->GroupLinks);
  1151. InitializeListHead(&p->GroupLinks);
  1152. if (!AlreadyOrphaned && FirstMember != p) {
  1153. //
  1154. // See if exit causes group to be orphaned. This is the
  1155. // case if the exiting process is an orphan, or if the
  1156. // parent is in a different session.
  1157. //
  1158. if ( OrphanedAGroupRelatedChild ||
  1159. (Parent == NULL) ||
  1160. (Parent != NULL && Parent->PsxSession != p->PsxSession) ) {
  1161. //
  1162. // Scan the group. Looking for stopped processes. If a stopped
  1163. // process is found, then for each process in the group,
  1164. // send a SIGCONT followed by a SIGHUP.
  1165. //
  1166. NextMember = FirstMember;
  1167. do {
  1168. if (NextMember->State == Stopped) {
  1169. //
  1170. // A stopped group member was found. Scan the group
  1171. // and SIGCONT, SIGHUP each member
  1172. //
  1173. NextMember = FirstMember;
  1174. do {
  1175. Next = NextMember->GroupLinks.Flink;
  1176. PsxSignalProcess(NextMember, SIGCONT);
  1177. PsxSignalProcess(NextMember, SIGHUP);
  1178. NextMember = CONTAINING_RECORD(Next, PSX_PROCESS,
  1179. GroupLinks);
  1180. } while (NextMember != FirstMember);
  1181. break;
  1182. }
  1183. Next = NextMember->GroupLinks.Flink;
  1184. NextMember = CONTAINING_RECORD(Next, PSX_PROCESS, GroupLinks);
  1185. } while (NextMember != FirstMember);
  1186. }
  1187. }
  1188. UnlockNtSessionList();
  1189. //
  1190. // Unlock process table here; we depend on having just one api
  1191. // thread, so no one can call fork while we're still closing the
  1192. // files and so forth.
  1193. //
  1194. ReleaseProcessStructureLock();
  1195. //
  1196. // Now just close files, deallocate the session, close the thread,
  1197. // terminate the process, and close the process.
  1198. //
  1199. CloseProcessFileTable(p);
  1200. if (!(p->Flags & P_FOREIGN_EXEC)) {
  1201. //
  1202. // When a foreign process has exited, it's responsible
  1203. // for shooting its own threads.
  1204. //
  1205. Status = NtTerminateThread(p->Thread, ExitStatus);
  1206. #ifdef PSX_MORE_ERRORS
  1207. if (!NT_SUCCESS(Status)) {
  1208. // XXX.mjb: this may fail if the thread has already died
  1209. // for some reason, f.e. been shot by pview.
  1210. KdPrint(("PSXSS: NtTerminateThread: 0x%x\n", Status));
  1211. }
  1212. #endif
  1213. }
  1214. p->Flags &= ~P_FOREIGN_EXEC;
  1215. //
  1216. // We like to call NtWaitForSingle object on the thread handle,
  1217. // but we don't do that if the process has
  1218. // died in some unusual way, like the dll init routine failed.
  1219. //
  1220. if (WaitForProcess) {
  1221. Status = NtWaitForSingleObject(p->Thread, TRUE, NULL);
  1222. if (!NT_SUCCESS(Status)) {
  1223. KdPrint(("PSXSS: Exit: NtWait: 0x%x\n", Status));
  1224. }
  1225. }
  1226. Status = NtClose(p->Thread);
  1227. if (!NT_SUCCESS(Status)) {
  1228. KdPrint(("PSXSS: NtClose dead thread: 0x%x\n", Status));
  1229. }
  1230. ASSERT(NT_SUCCESS(Status));
  1231. //
  1232. // We like to wait on the process handle here, sometimes we don't
  1233. // do that, see above.
  1234. //
  1235. if (WaitForProcess) {
  1236. Status = NtWaitForSingleObject(p->Process, TRUE, NULL);
  1237. if (!NT_SUCCESS(Status)) {
  1238. KdPrint(("PSXSS: Exit: NtWait: 0x%x\n", Status));
  1239. }
  1240. }
  1241. //
  1242. // Get the time for this process and add to the accumulated time for
  1243. // the process
  1244. //
  1245. Status = NtQueryInformationProcess(p->Process, ProcessTimes,
  1246. (PVOID)&ProcessTime, sizeof(KERNEL_USER_TIMES), NULL);
  1247. if (!NT_SUCCESS(Status)) {
  1248. KdPrint(("PSXSS: NtQueryInfoProc: 0x%x\n", Status));
  1249. } else {
  1250. ULONG Remainder;
  1251. ULONG PosixTime;
  1252. PosixTime = RtlExtendedLargeIntegerDivide(
  1253. ProcessTime.KernelTime, 10000, &Remainder).LowPart;
  1254. p->ProcessTimes.tms_stime += PosixTime;
  1255. PosixTime = RtlExtendedLargeIntegerDivide(
  1256. ProcessTime.UserTime, 10000, &Remainder).LowPart;
  1257. p->ProcessTimes.tms_utime += PosixTime;
  1258. }
  1259. NtClose(p->Process);
  1260. DEREFERENCE_PSX_SESSION(p->PsxSession, ExitStatus >> 8);
  1261. Status = NtClose(p->ClientPort);
  1262. #ifdef PSX_MORE_ERRORS
  1263. if (!NT_SUCCESS(Status)) {
  1264. KdPrint(("PSXSS: NtClose: 0x%x\n", Status));
  1265. }
  1266. #endif
  1267. //
  1268. // Remove the process from ClientIdHashTable; this must be done
  1269. // now rather than in wait(), because unless we do it now a new
  1270. // process could be created with the same ClientId as this zombie.
  1271. // This process shouldn't be making any more api requests, and
  1272. // that's the only time we look processes up by ClientId (right?).
  1273. //
  1274. RemoveEntryList(&p->ClientIdHashLinks);
  1275. InitializeListHead(&p->ClientIdHashLinks);
  1276. if (p->ParentPid == SPECIALPID) {
  1277. //
  1278. // Parent won't clean up after wait, so do all clean up here
  1279. //
  1280. p->Flags |= P_FREE;
  1281. //
  1282. // REVISIT... This might have to stay around
  1283. //
  1284. RtlDeleteCriticalSection(&p->ProcessLock);
  1285. }
  1286. if (NULL != WaitingParent) {
  1287. UnblockProcess(WaitingParent, WaitSatisfyInterrupt, FALSE, 0);
  1288. }
  1289. }
  1290. PSZ PsxpDefaultRoot = "\\DosDevices\\C:";
  1291. BOOLEAN
  1292. PsxInitializeDirectories(
  1293. IN PPSX_PROCESS Process,
  1294. IN PANSI_STRING pCwd
  1295. )
  1296. {
  1297. PPSX_DIRECTORY_PREFIX DirectoryPrefix;
  1298. PSZ Root;
  1299. char sbWorkingDirectory[512];
  1300. char sbRoot[512];
  1301. ULONG len;
  1302. PSX_GET_SESSION_NAME_A(sbWorkingDirectory, DOSDEVICE_A);
  1303. (void)strcat(sbWorkingDirectory, pCwd->Buffer);
  1304. (void)strcpy(sbRoot, sbWorkingDirectory);
  1305. PSX_GET_STRLEN(PsxpDefaultRoot,len);
  1306. sbRoot[len] = '\0';
  1307. Root = sbRoot;
  1308. //
  1309. // The current working directory should end in a "\". We add one
  1310. // if it isn't there already.
  1311. //
  1312. if ('\\' != sbWorkingDirectory[strlen(sbWorkingDirectory) - 1]) {
  1313. (void)strcat(sbWorkingDirectory, "\\");
  1314. }
  1315. DirectoryPrefix = RtlAllocateHeap(PsxHeap, 0,sizeof(*DirectoryPrefix));
  1316. if (NULL == DirectoryPrefix) {
  1317. return FALSE; // ENOMEM
  1318. }
  1319. DirectoryPrefix->PsxRoot.Buffer = NULL;
  1320. DirectoryPrefix->NtCurrentWorkingDirectory.Buffer =
  1321. RtlAllocateHeap(PsxHeap, 0, strlen(sbWorkingDirectory) + 1);
  1322. if (NULL == DirectoryPrefix->NtCurrentWorkingDirectory.Buffer) {
  1323. RtlFreeHeap(PsxHeap, 0, DirectoryPrefix);
  1324. return FALSE;
  1325. }
  1326. DirectoryPrefix->NtCurrentWorkingDirectory.Length =
  1327. (USHORT)strlen(sbWorkingDirectory);
  1328. DirectoryPrefix->NtCurrentWorkingDirectory.MaximumLength =
  1329. DirectoryPrefix->NtCurrentWorkingDirectory.Length + 1;
  1330. RtlMoveMemory(DirectoryPrefix->NtCurrentWorkingDirectory.Buffer,
  1331. sbWorkingDirectory,
  1332. DirectoryPrefix->NtCurrentWorkingDirectory.MaximumLength);
  1333. DirectoryPrefix->PsxCurrentWorkingDirectory.Length = 0;
  1334. DirectoryPrefix->PsxRoot.Buffer = RtlAllocateHeap(PsxHeap, 0,
  1335. strlen(Root) + 1);
  1336. if (! DirectoryPrefix->PsxRoot.Buffer) {
  1337. RtlFreeHeap(PsxHeap, 0,
  1338. DirectoryPrefix->NtCurrentWorkingDirectory.Buffer);
  1339. RtlFreeHeap(PsxHeap, 0, DirectoryPrefix);
  1340. return FALSE;
  1341. }
  1342. DirectoryPrefix->PsxRoot.Length = (USHORT)strlen(Root);
  1343. DirectoryPrefix->PsxRoot.MaximumLength =
  1344. DirectoryPrefix->PsxRoot.Length + 1;
  1345. RtlMoveMemory(DirectoryPrefix->PsxRoot.Buffer, Root,
  1346. DirectoryPrefix->PsxRoot.MaximumLength);
  1347. Process->DirectoryPrefix = DirectoryPrefix;
  1348. return TRUE;
  1349. }
  1350. //
  1351. // PsxPropagateDirectories --
  1352. //
  1353. // Read the root directory, the current working directory
  1354. // from an existing process.
  1355. //
  1356. BOOLEAN
  1357. PsxPropagateDirectories(
  1358. IN PPSX_PROCESS Process
  1359. )
  1360. {
  1361. NTSTATUS Status;
  1362. PPSX_DIRECTORY_PREFIX Prefix = NULL;
  1363. STRING ClientPrefix;
  1364. PVOID p;
  1365. Prefix = RtlAllocateHeap(PsxHeap, 0, sizeof(*Prefix));
  1366. if (NULL == Prefix) {
  1367. goto ErrorExit;
  1368. }
  1369. Prefix->PsxRoot.Buffer = NULL;
  1370. Prefix->NtCurrentWorkingDirectory.Buffer = NULL;
  1371. Status = NtReadVirtualMemory(Process->Process,
  1372. (PVOID)MAKE_DIRECTORY_PREFIX_VALID(Process->DirectoryPrefix),
  1373. (PVOID)Prefix, sizeof(*Prefix), NULL);
  1374. if (!NT_SUCCESS(Status)) {
  1375. goto ErrorExit;
  1376. }
  1377. //
  1378. // Capture the Root and NtCurrentWorkingDirectory
  1379. //
  1380. // XXX.mjb: TODO sanity check lengths ?
  1381. //
  1382. ClientPrefix = Prefix->PsxRoot;
  1383. p = RtlAllocateHeap(PsxHeap, 0, ClientPrefix.Length);
  1384. if (NULL == p) {
  1385. goto ErrorExit;
  1386. }
  1387. Prefix->PsxRoot.Buffer = p;
  1388. Status = NtReadVirtualMemory(Process->Process, ClientPrefix.Buffer,
  1389. Prefix->PsxRoot.Buffer, ClientPrefix.Length, NULL);
  1390. if (!NT_SUCCESS(Status)) {
  1391. goto ErrorExit;
  1392. }
  1393. Prefix->PsxRoot.Length = ClientPrefix.Length;
  1394. Prefix->PsxRoot.MaximumLength = ClientPrefix.Length;
  1395. ClientPrefix = Prefix->NtCurrentWorkingDirectory;
  1396. p = RtlAllocateHeap(PsxHeap, 0, ClientPrefix.Length);
  1397. if (NULL == p) {
  1398. goto ErrorExit;
  1399. }
  1400. Prefix->NtCurrentWorkingDirectory.Buffer = p;
  1401. Status = NtReadVirtualMemory(Process->Process, ClientPrefix.Buffer,
  1402. Prefix->NtCurrentWorkingDirectory.Buffer,
  1403. ClientPrefix.Length, NULL);
  1404. if (!NT_SUCCESS(Status)) {
  1405. goto ErrorExit;
  1406. }
  1407. Prefix->NtCurrentWorkingDirectory.Length = ClientPrefix.Length;
  1408. Prefix->NtCurrentWorkingDirectory.MaximumLength = ClientPrefix.Length;
  1409. Prefix->PsxCurrentWorkingDirectory.Buffer = NULL;
  1410. Prefix->PsxCurrentWorkingDirectory.Length = 0;
  1411. Prefix->PsxCurrentWorkingDirectory.MaximumLength = 0;
  1412. Process->DirectoryPrefix = Prefix;
  1413. return TRUE;
  1414. ErrorExit:
  1415. if (NULL != Prefix) {
  1416. if (NULL != Prefix->NtCurrentWorkingDirectory.Buffer) {
  1417. RtlFreeHeap(PsxHeap, 0, (PVOID)Prefix->NtCurrentWorkingDirectory.Buffer);
  1418. }
  1419. if (NULL != Prefix->PsxRoot.Buffer) {
  1420. RtlFreeHeap(PsxHeap, 0, (PVOID)Prefix->PsxRoot.Buffer);
  1421. }
  1422. RtlFreeHeap(PsxHeap, 0, (PVOID)Prefix);
  1423. }
  1424. return FALSE;
  1425. }
  1426. //
  1427. // When we allocate space in PsxPropagateDirectories, and then find
  1428. // that we can't use it, we free it with PsxFreeDirectories.
  1429. //
  1430. VOID
  1431. PsxFreeDirectories(
  1432. IN PPSX_PROCESS p
  1433. )
  1434. {
  1435. PPSX_DIRECTORY_PREFIX Prefix;
  1436. Prefix = p->DirectoryPrefix;
  1437. if (NULL != Prefix->NtCurrentWorkingDirectory.Buffer) {
  1438. RtlFreeHeap(PsxHeap, 0, Prefix->NtCurrentWorkingDirectory.Buffer);
  1439. }
  1440. if (NULL != Prefix->PsxRoot.Buffer) {
  1441. RtlFreeHeap(PsxHeap, 0, (PVOID)Prefix->PsxRoot.Buffer);
  1442. }
  1443. if (NULL != Prefix) {
  1444. RtlFreeHeap(PsxHeap, 0, (PVOID)Prefix);
  1445. }
  1446. }
  1447. /*++
  1448. Routine Description:
  1449. Locate a Posix Session by it's Unique Id.
  1450. Arguments:
  1451. UniqueId - the session's unique id.
  1452. Return Value:
  1453. NULL - no such session could be found.
  1454. Non-NULL - the found session.
  1455. --*/
  1456. PPSX_SESSION
  1457. PsxLocateSessionByUniqueId(
  1458. ULONG UniqueId
  1459. )
  1460. {
  1461. PPSX_PROCESS Process;
  1462. //
  1463. // We don't have a list of sessions at the moment, so we
  1464. // linear-scan the process table, checking the session of
  1465. // each process to see if it's the one we want.
  1466. //
  1467. AcquireProcessStructureLock();
  1468. for (Process = FirstProcess; Process < LastProcess; Process++) {
  1469. if (Process->Flags & P_FREE) {
  1470. continue;
  1471. }
  1472. if (NULL == Process->PsxSession->Terminal)
  1473. continue;
  1474. if (Process->PsxSession->Terminal->UniqueId == UniqueId) {
  1475. ReleaseProcessStructureLock();
  1476. return Process->PsxSession;
  1477. }
  1478. }
  1479. ReleaseProcessStructureLock();
  1480. return NULL;
  1481. }