1
0

shntos.c 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. shntos.c
  5. Abstract:
  6. This module implements NT operating system dependent functionality for the
  7. shell.
  8. Author:
  9. Evan Green 13-Jun-2013
  10. Environment:
  11. POSIX
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #define _WIN32_WINNT 0x0501
  17. #include <windows.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include <fcntl.h>
  23. #include <signal.h>
  24. #include "shos.h"
  25. //
  26. // ---------------------------------------------------------------- Definitions
  27. //
  28. //
  29. // Define the pipe buffer size. It's so large to prevent an earlier stage of
  30. // an execution pipeline from blocking during execution.
  31. //
  32. #define SHELL_NT_PIPE_SIZE (1024 * 1024 * 10)
  33. #define SHELL_NT_OUTPUT_CHUNK_SIZE 1024
  34. #define SHELL_NT_INPUT_CHUNK_SIZE 1024
  35. //
  36. // Define the unix null device and the corresponding Windows device.
  37. //
  38. #define SHELL_NT_UNIX_NULL "/dev/null"
  39. #define SHELL_NT_NULL "nul"
  40. //
  41. // Define the minimum path size.
  42. //
  43. #define SHELL_NT_PATH_SIZE_MINIMUM sizeof(SHELL_NT_UNIX_NULL)
  44. //
  45. // ------------------------------------------------------ Data Type Definitions
  46. //
  47. /*++
  48. Structure Description:
  49. This structure defines a shell output collection context.
  50. Members:
  51. Thread - Stores the thread handle of the thread servicing this request.
  52. Handle - Stores the handle to read.
  53. Buffer - Stores a pointer to the buffer containing the read output.
  54. BufferSize - Stores the size of the buffer including a null terminator.
  55. BufferCapacity - Stores the capacity of the buffer.
  56. --*/
  57. typedef struct _SHELL_NT_OUTPUT_COLLECTION {
  58. uintptr_t Thread;
  59. int Handle;
  60. void *Buffer;
  61. unsigned long BufferSize;
  62. unsigned long BufferCapacity;
  63. } SHELL_NT_OUTPUT_COLLECTION, *PSHELL_NT_OUTPUT_COLLECTION;
  64. /*++
  65. Structure Description:
  66. This structure defines the context for a thread that pushes input into a
  67. pipe.
  68. Members:
  69. Handle - Stores the pipe to write.
  70. Buffer - Stores a pointer to the buffer containing the input to write.
  71. BufferSize - Stores the size of the buffer including a null terminator.
  72. --*/
  73. typedef struct _SHELL_NT_INPUT_PUSH_CONTEXT {
  74. int Handle;
  75. void *Buffer;
  76. unsigned long BufferSize;
  77. } SHELL_NT_INPUT_PUSH_CONTEXT, *PSHELL_NT_INPUT_PUSH_CONTEXT;
  78. //
  79. // ----------------------------------------------- Internal Function Prototypes
  80. //
  81. void
  82. ShOutputCollectionThread (
  83. void *Context
  84. );
  85. void
  86. ShPushInputThread (
  87. void *Context
  88. );
  89. void
  90. ShNtSignalHandler (
  91. int SignalNumber
  92. );
  93. void
  94. ShPrintLastError (
  95. void
  96. );
  97. //
  98. // -------------------------------------------------------------------- Globals
  99. //
  100. //
  101. // Define the executable extensions.
  102. //
  103. PSTR ShNtExecutableExtensions[] = {
  104. ".exe",
  105. ".bat",
  106. ".cmd",
  107. ".com"
  108. };
  109. //
  110. // Store a global that's non-zero if this OS supports an executable permission
  111. // bit.
  112. //
  113. int ShExecutableBitSupported = 0;
  114. //
  115. // ------------------------------------------------------------------ Functions
  116. //
  117. int
  118. ShGetHomeDirectory (
  119. char *User,
  120. int UserSize,
  121. char **HomePath,
  122. int *HomePathSize
  123. )
  124. /*++
  125. Routine Description:
  126. This routine gets the given user's home directory.
  127. Arguments:
  128. User - Supplies a pointer to the user string to query.
  129. UserSize - Supplies the size of the user string in bytes.
  130. HomePath - Supplies a pointer where the given user's home directory will be
  131. returned on success.
  132. HomePathSize - Supplies a pointer where the size of the home directory
  133. string will be returned on success.
  134. Return Value:
  135. 1 on success.
  136. 0 on failure.
  137. --*/
  138. {
  139. char *Home;
  140. char *NewHomePath;
  141. int NewHomePathSize;
  142. int Result;
  143. NewHomePath = NULL;
  144. NewHomePathSize = 0;
  145. Result = 0;
  146. //
  147. // On Windows, always return the current user's home directory.
  148. //
  149. Home = getenv("HOMEPATH");
  150. if (Home == NULL) {
  151. goto GetHomeDirectoryEnd;
  152. }
  153. NewHomePathSize = strlen(Home) + 1;
  154. NewHomePath = malloc(NewHomePathSize);
  155. if (NewHomePath == NULL) {
  156. goto GetHomeDirectoryEnd;
  157. }
  158. strcpy(NewHomePath, Home);
  159. Result = 1;
  160. GetHomeDirectoryEnd:
  161. if (Result == 0) {
  162. if (NewHomePath != NULL) {
  163. free(NewHomePath);
  164. NewHomePath = NULL;
  165. }
  166. NewHomePathSize = 0;
  167. }
  168. *HomePath = NewHomePath;
  169. *HomePathSize = NewHomePathSize;
  170. return Result;
  171. }
  172. int
  173. ShCreatePipe (
  174. int Descriptors[2]
  175. )
  176. /*++
  177. Routine Description:
  178. This routine creates an anonymous pipe.
  179. Arguments:
  180. Descriptors - Supplies the array where the pipe's read and write ends will
  181. be returned.
  182. Return Value:
  183. 1 on success.
  184. 0 on failure.
  185. --*/
  186. {
  187. int Result;
  188. Result = _pipe(Descriptors, SHELL_NT_PIPE_SIZE, _O_BINARY);
  189. if (Result == 0) {
  190. return 1;
  191. }
  192. return 0;
  193. }
  194. int
  195. ShPrepareForOutputCollection (
  196. int FileDescriptorToRead,
  197. void **Handle
  198. )
  199. /*++
  200. Routine Description:
  201. This routine is called before a subshell is going to run where the output
  202. will be collected.
  203. Arguments:
  204. FileDescriptorToRead - Supplies the file descriptor that will be read to
  205. collect output.
  206. Handle - Supplies a pointer where an opaque token representing the
  207. collection will be returned.
  208. Return Value:
  209. 1 on success.
  210. 0 on failure.
  211. --*/
  212. {
  213. PSHELL_NT_OUTPUT_COLLECTION Context;
  214. int Result;
  215. //
  216. // Create an output collection context, initialize the file handle, and
  217. // spin up the thread which will read the file descriptor.
  218. //
  219. Result = 0;
  220. Context = malloc(sizeof(SHELL_NT_OUTPUT_COLLECTION));
  221. if (Context == NULL) {
  222. goto PrepareForOutputCollectionEnd;
  223. }
  224. memset(Context, 0, sizeof(SHELL_NT_OUTPUT_COLLECTION));
  225. Context->Handle = FileDescriptorToRead;
  226. Context->Thread = _beginthread(ShOutputCollectionThread, 0, Context);
  227. if (Context->Thread == -1) {
  228. goto PrepareForOutputCollectionEnd;
  229. }
  230. Result = 1;
  231. PrepareForOutputCollectionEnd:
  232. if (Result == 1) {
  233. *Handle = Context;
  234. }
  235. return Result;
  236. }
  237. int
  238. ShCollectOutput (
  239. void *Handle,
  240. char **Output,
  241. unsigned long *OutputSize
  242. )
  243. /*++
  244. Routine Description:
  245. This routine is called after a subshell has executed to collect its output.
  246. Arguments:
  247. Handle - Supplies a pointer to the handle returned by the prepare for
  248. output collection function.
  249. Output - Supplies a pointer where the output will be returned. It is the
  250. caller's responsibility to free this memory.
  251. OutputSize - Supplies a pointer where the size of the output will be
  252. returned on success, with no null terminator.
  253. Return Value:
  254. 1 on success.
  255. 0 on failure.
  256. --*/
  257. {
  258. PSHELL_NT_OUTPUT_COLLECTION Context;
  259. *Output = NULL;
  260. *OutputSize = 0;
  261. Context = (PSHELL_NT_OUTPUT_COLLECTION)Handle;
  262. //
  263. // Wait for the thread to exit.
  264. //
  265. WaitForSingleObject((HANDLE)(Context->Thread), INFINITE);
  266. if (Context->BufferSize == 0) {
  267. if (Context->Buffer != NULL) {
  268. free(Context->Buffer);
  269. Context->Buffer = NULL;
  270. }
  271. Context->BufferSize = 0;
  272. }
  273. *Output = Context->Buffer;
  274. *OutputSize = Context->BufferSize;
  275. free(Context);
  276. return 1;
  277. }
  278. int
  279. ShPushInputText (
  280. char *Text,
  281. unsigned long TextSize,
  282. int Pipe[2]
  283. )
  284. /*++
  285. Routine Description:
  286. This routine forks an executable or thread to push the given input into the
  287. given pipe.
  288. Arguments:
  289. Text - Supplies a pointer to the string containing the text to push into
  290. the input.
  291. TextSize - Supplies the number of bytes to write.
  292. Pipe - Supplies the pipe to write into. This routine is responsible for
  293. closing the write end of the pipe.
  294. Return Value:
  295. Returns the pid that was created (and needs to be waited for) on success.
  296. 0 on success if no pid needs to be waited on.
  297. -1 on failure.
  298. --*/
  299. {
  300. PSHELL_NT_INPUT_PUSH_CONTEXT Context;
  301. int Result;
  302. uintptr_t Thread;
  303. Result = -1;
  304. Context = malloc(sizeof(SHELL_NT_INPUT_PUSH_CONTEXT));
  305. if (Context == NULL) {
  306. goto PushInputTextEnd;
  307. }
  308. memset(Context, 0, sizeof(SHELL_NT_INPUT_PUSH_CONTEXT));
  309. Context->Handle = -1;
  310. //
  311. // Copy the document.
  312. //
  313. Context->Buffer = malloc(TextSize);
  314. if (Context->Buffer == NULL) {
  315. goto PushInputTextEnd;
  316. }
  317. memcpy(Context->Buffer, Text, TextSize);
  318. Context->BufferSize = TextSize;
  319. Context->Handle = Pipe[1];
  320. if (Context->Handle == -1) {
  321. goto PushInputTextEnd;
  322. }
  323. if (ShSetDescriptorFlags(Context->Handle, 0) != 0) {
  324. goto PushInputTextEnd;
  325. }
  326. Thread = _beginthread(ShPushInputThread, 0, Context);
  327. if (Thread == -1) {
  328. goto PushInputTextEnd;
  329. }
  330. Result = 0;
  331. PushInputTextEnd:
  332. if (Result != 0) {
  333. if (Context != NULL) {
  334. if (Context->Buffer != NULL) {
  335. free(Context->Buffer);
  336. }
  337. if (Context->Handle != -1) {
  338. close(Context->Handle);
  339. }
  340. free(Context);
  341. }
  342. }
  343. return Result;
  344. }
  345. int
  346. ShFixUpPath (
  347. char **Path,
  348. unsigned long *PathSize
  349. )
  350. /*++
  351. Routine Description:
  352. This routine performs any operating system dependent modifications to a
  353. path or path list.
  354. Arguments:
  355. Path - Supplies a pointer where a pointer to the path variable value will
  356. be on input. This value may get replaced by a different buffer.
  357. PathSize - Supplies a pointer to the size of the path variable value on
  358. input. This value will be updated if the path size changes.
  359. Return Value:
  360. 1 on success.
  361. 0 on failure.
  362. --*/
  363. {
  364. unsigned long long BufferSize;
  365. char Character;
  366. char *Input;
  367. unsigned long long InputIndex;
  368. unsigned long long InputSize;
  369. char *Output;
  370. unsigned long long OutputIndex;
  371. //
  372. // Just double the buffer as a worst-case scenario.
  373. //
  374. Input = *Path;
  375. InputSize = *PathSize;
  376. BufferSize = InputSize * 2;
  377. if (BufferSize < SHELL_NT_PATH_SIZE_MINIMUM) {
  378. BufferSize = SHELL_NT_PATH_SIZE_MINIMUM;
  379. }
  380. Output = malloc(BufferSize);
  381. if (Output == NULL) {
  382. return 0;
  383. }
  384. OutputIndex = 0;
  385. for (InputIndex = 0; InputIndex < InputSize; InputIndex += 1) {
  386. Character = Input[InputIndex];
  387. //
  388. // Convert backslashes to forward slashes. Windows under MinGW gets it
  389. // and it makes everything else in the shell understand path
  390. // separators.
  391. //
  392. if (Character == '\\') {
  393. Character = '/';
  394. }
  395. Output[OutputIndex] = Character;
  396. OutputIndex += 1;
  397. if (Character == '\0') {
  398. break;
  399. }
  400. }
  401. free(*Path);
  402. //
  403. // Watch out for the special null device.
  404. //
  405. if (strcmp(Output, SHELL_NT_UNIX_NULL) == 0) {
  406. strcpy(Output, SHELL_NT_NULL);
  407. OutputIndex = strlen(Output) + 1;
  408. }
  409. *Path = Output;
  410. *PathSize = OutputIndex;
  411. return 1;
  412. }
  413. char *
  414. ShGetEnvironmentVariable (
  415. char *Name
  416. )
  417. /*++
  418. Routine Description:
  419. This routine gets the current value of an environment variable.
  420. Arguments:
  421. Name - Supplies a pointer to the null terminated string representing the
  422. name of the variable to get.
  423. Return Value:
  424. Returns a pointer to an allocated buffer containing the value of the
  425. variable on success. The caller must call free to reclaim this buffer when
  426. finished.
  427. NULL on failure or if the variable is not set.
  428. --*/
  429. {
  430. if (getenv(Name) == NULL) {
  431. return NULL;
  432. }
  433. return strdup(getenv(Name));
  434. }
  435. int
  436. ShSetEnvironmentVariable (
  437. char *Name,
  438. char *Value
  439. )
  440. /*++
  441. Routine Description:
  442. This routine sets the value of an environment variable.
  443. Arguments:
  444. Name - Supplies a pointer to the null terminated string representing the
  445. name of the variable to set.
  446. Value - Supplies a pointer to the null terminated string containing the
  447. value to set for the given environment variable.
  448. Return Value:
  449. 1 on success.
  450. 0 on failure.
  451. --*/
  452. {
  453. size_t Length;
  454. char *String;
  455. if (Value == NULL) {
  456. Value = "";
  457. }
  458. Length = strlen(Name) + strlen(Value) + 2;
  459. String = malloc(Length);
  460. if (String == NULL) {
  461. return 0;
  462. }
  463. snprintf(String, Length, "%s=%s", Name, Value);
  464. if (putenv(String) == 0) {
  465. return 1;
  466. }
  467. free(String);
  468. return 0;
  469. }
  470. int
  471. ShUnsetEnvironmentVariable (
  472. char *Name
  473. )
  474. /*++
  475. Routine Description:
  476. This routine unsets the value of an environment variable, deleting it
  477. from the environment.
  478. Arguments:
  479. Name - Supplies a pointer to the null terminated string representing the
  480. name of the variable to unset.
  481. Return Value:
  482. 1 on success.
  483. 0 on failure.
  484. --*/
  485. {
  486. size_t Length;
  487. int Result;
  488. char *String;
  489. Length = strlen(Name) + 2;
  490. String = malloc(Length);
  491. if (String == NULL) {
  492. return 0;
  493. }
  494. snprintf(String, Length, "%s=", Name);
  495. Result = putenv(String);
  496. free(String);
  497. if (Result == 0) {
  498. return 1;
  499. }
  500. return 0;
  501. }
  502. int
  503. ShGetExecutionTimes (
  504. PSHELL_PROCESS_TIMES Times
  505. )
  506. /*++
  507. Routine Description:
  508. This routine returns the execution time information from the kernel.
  509. Arguments:
  510. Times - Supplies a pointer where the execution time information will be
  511. returned.
  512. Return Value:
  513. 1 on success.
  514. 0 on failure.
  515. --*/
  516. {
  517. FILETIME CreationTime;
  518. FILETIME ExitTime;
  519. FILETIME KernelTime;
  520. unsigned long long Microseconds;
  521. BOOL Result;
  522. FILETIME UserTime;
  523. memset(Times, 0, sizeof(SHELL_PROCESS_TIMES));
  524. Result = GetProcessTimes(GetCurrentProcess(),
  525. &CreationTime,
  526. &ExitTime,
  527. &KernelTime,
  528. &UserTime);
  529. if (Result == FALSE) {
  530. return 0;
  531. }
  532. Microseconds = (((unsigned long long)UserTime.dwHighDateTime << 32) |
  533. UserTime.dwLowDateTime) / 10;
  534. Times->ShellUserMinutes = Microseconds / 60000000;
  535. Times->ShellUserMicroseconds = Microseconds % 60000000;
  536. Microseconds = (((unsigned long long)KernelTime.dwHighDateTime << 32) |
  537. KernelTime.dwLowDateTime) / 10;
  538. Times->ShellSystemMinutes = Microseconds / 60000000;
  539. Times->ShellSystemMicroseconds = Microseconds % 60000000;
  540. return 1;
  541. }
  542. int
  543. ShSetSignalDisposition (
  544. SHELL_SIGNAL Signal,
  545. SHELL_SIGNAL_DISPOSITION Disposition
  546. )
  547. /*++
  548. Routine Description:
  549. This routine sets the disposition with the OS for the given signal.
  550. Arguments:
  551. Signal - Supplies the signal to change.
  552. Disposition - Supplies the disposition of the signal.
  553. Return Value:
  554. 1 on success.
  555. 0 on failure.
  556. --*/
  557. {
  558. int OsSignalNumber;
  559. switch (Signal) {
  560. case ShellSignalInterrupt:
  561. OsSignalNumber = SIGINT;
  562. break;
  563. case ShellSignalIllegalInstruction:
  564. OsSignalNumber = SIGILL;
  565. break;
  566. case ShellSignalFloatingPointException:
  567. OsSignalNumber = SIGFPE;
  568. break;
  569. case ShellSignalSegmentationFault:
  570. OsSignalNumber = SIGSEGV;
  571. break;
  572. case ShellSignalTerminate:
  573. OsSignalNumber = SIGTERM;
  574. break;
  575. case ShellSignalAbort:
  576. OsSignalNumber = SIGABRT;
  577. break;
  578. default:
  579. return 1;
  580. }
  581. switch (Disposition) {
  582. case ShellSignalDispositionDefault:
  583. signal(OsSignalNumber, SIG_DFL);
  584. break;
  585. case ShellSignalDispositionIgnore:
  586. signal(OsSignalNumber, SIG_IGN);
  587. break;
  588. case ShellSignalDispositionTrap:
  589. signal(OsSignalNumber, ShNtSignalHandler);
  590. break;
  591. default:
  592. return 0;
  593. }
  594. return 1;
  595. }
  596. void
  597. ShRestoreOriginalSignalDispositions (
  598. void
  599. )
  600. /*++
  601. Routine Description:
  602. This routine restores all the signal dispositions back to their original
  603. state.
  604. Arguments:
  605. None.
  606. Return Value:
  607. None.
  608. --*/
  609. {
  610. signal(SIGINT, SIG_DFL);
  611. signal(SIGILL, SIG_DFL);
  612. signal(SIGFPE, SIG_DFL);
  613. signal(SIGSEGV, SIG_DFL);
  614. signal(SIGTERM, SIG_DFL);
  615. signal(SIGABRT, SIG_DFL);
  616. return;
  617. }
  618. void
  619. ShGetExecutableExtensions (
  620. char ***ExtensionList,
  621. unsigned int *ElementCount
  622. )
  623. /*++
  624. Routine Description:
  625. This routine gets the list of extensions to try when looking for an
  626. executable.
  627. Arguments:
  628. ExtensionList - Supplies a pointer that will receive an array of strings
  629. containing the executable extensions. Yes, this is a triple character
  630. pointer (ie a pointer that returns a list). The caller does not own
  631. this memory and must not modify or free it.
  632. ElementCount - Supplies a pointer where the number of elements in the
  633. extension list will be returned.
  634. Return Value:
  635. None.
  636. --*/
  637. {
  638. *ElementCount = sizeof(ShNtExecutableExtensions) /
  639. sizeof(ShNtExecutableExtensions[0]);
  640. *ExtensionList = ShNtExecutableExtensions;
  641. return;
  642. }
  643. int
  644. ShSetDescriptorFlags (
  645. int FileDescriptor,
  646. int Inheritable
  647. )
  648. /*++
  649. Routine Description:
  650. This routine sets the file flags for the given descriptor.
  651. Arguments:
  652. FileDescriptor - Supplies the open file descriptor.
  653. Inheritable - Supplies a boolean indicating if this descriptor should be
  654. passed on to spawned processes.
  655. Return Value:
  656. Zero on success.
  657. Non-zero on failure.
  658. --*/
  659. {
  660. DWORD Flags;
  661. HANDLE Handle;
  662. BOOL Result;
  663. Flags = 0;
  664. if (Inheritable != 0) {
  665. Flags |= HANDLE_FLAG_INHERIT;
  666. }
  667. Handle = (HANDLE)_get_osfhandle(FileDescriptor);
  668. Result = SetHandleInformation(Handle, HANDLE_FLAG_INHERIT, Flags);
  669. if ((Result == 0) &&
  670. ((Inheritable != 0) && (GetLastError() != ERROR_INVALID_PARAMETER))) {
  671. ShPrintLastError();
  672. return 0;
  673. }
  674. return 0;
  675. }
  676. int
  677. ShOsDup (
  678. int FileDescriptor
  679. )
  680. /*++
  681. Routine Description:
  682. This routine duplicates the given file descriptor above the application
  683. reserved area.
  684. Arguments:
  685. FileDescriptor - Supplies the open file descriptor.
  686. Return Value:
  687. Returns the duplicate file descriptor on success.
  688. -1 on failure.
  689. --*/
  690. {
  691. int ExtraDescriptors[SHELL_MINIMUM_FILE_DESCRIPTOR];
  692. int ExtraIndex;
  693. int FreeIndex;
  694. int Result;
  695. //
  696. // Call dup in a loop until a file descriptor above the user range is
  697. // found.
  698. //
  699. ExtraIndex = 0;
  700. Result = dup(FileDescriptor);
  701. while (Result < SHELL_MINIMUM_FILE_DESCRIPTOR) {
  702. ExtraDescriptors[ExtraIndex] = Result;
  703. ExtraIndex += 1;
  704. Result = dup(Result);
  705. if (Result < 0) {
  706. break;
  707. }
  708. }
  709. //
  710. // Release the extra descriptors.
  711. //
  712. for (FreeIndex = 0; FreeIndex < ExtraIndex; FreeIndex += 1) {
  713. close(ExtraDescriptors[FreeIndex]);
  714. }
  715. return Result;
  716. }
  717. void
  718. ShOsConvertExitStatus (
  719. int *Status
  720. )
  721. /*++
  722. Routine Description:
  723. This routine converts an OS exit status code into a shell exit status code.
  724. Arguments:
  725. Status - Supplies a pointer that on input contains the OS-specific exit
  726. status code. On output, returns the shell exit status code.
  727. Return Value:
  728. None.
  729. --*/
  730. {
  731. return;
  732. }
  733. //
  734. // --------------------------------------------------------- Internal Functions
  735. //
  736. void
  737. ShOutputCollectionThread (
  738. void *Context
  739. )
  740. /*++
  741. Routine Description:
  742. This routine implements the output collection thread on Windows.
  743. Arguments:
  744. Context - Supplies a pointer to the thread context, in this case it's a
  745. pointer to the NT output collection structure.
  746. Return Value:
  747. 1 on success.
  748. 0 on failure.
  749. --*/
  750. {
  751. ssize_t BytesRead;
  752. PSHELL_NT_OUTPUT_COLLECTION OutputContext;
  753. OutputContext = (PSHELL_NT_OUTPUT_COLLECTION)Context;
  754. //
  755. // Loop reading from the file descriptor, reallocating the buffer as
  756. // needed.
  757. //
  758. while (TRUE) {
  759. if (OutputContext->BufferSize + SHELL_NT_OUTPUT_CHUNK_SIZE >
  760. OutputContext->BufferCapacity) {
  761. if (OutputContext->BufferCapacity == 0) {
  762. OutputContext->BufferCapacity = SHELL_NT_OUTPUT_CHUNK_SIZE;
  763. }
  764. while (OutputContext->BufferSize + SHELL_NT_OUTPUT_CHUNK_SIZE >
  765. OutputContext->BufferCapacity) {
  766. OutputContext->BufferCapacity *= 2;
  767. }
  768. OutputContext->Buffer = realloc(OutputContext->Buffer,
  769. OutputContext->BufferCapacity);
  770. if (OutputContext->Buffer == NULL) {
  771. OutputContext->BufferCapacity = 0;
  772. OutputContext->BufferSize = 0;
  773. break;
  774. }
  775. }
  776. BytesRead = read(OutputContext->Handle,
  777. OutputContext->Buffer + OutputContext->BufferSize,
  778. SHELL_NT_OUTPUT_CHUNK_SIZE);
  779. if (BytesRead <= 0) {
  780. break;
  781. }
  782. OutputContext->BufferSize += BytesRead;
  783. }
  784. return;
  785. }
  786. void
  787. ShPushInputThread (
  788. void *Context
  789. )
  790. /*++
  791. Routine Description:
  792. This routine implements the input push thread on windows.
  793. Arguments:
  794. Context - Supplies a pointer to the thread context, in this case it's a
  795. pointer to the NT input push context.
  796. Return Value:
  797. 1 on success.
  798. 0 on failure.
  799. --*/
  800. {
  801. unsigned long BytesToWrite;
  802. ssize_t BytesWritten;
  803. PSHELL_NT_INPUT_PUSH_CONTEXT InputContext;
  804. unsigned long TotalBytesWritten;
  805. InputContext = (PSHELL_NT_INPUT_PUSH_CONTEXT)Context;
  806. //
  807. // Loop writing to the file descriptor.
  808. //
  809. TotalBytesWritten = 0;
  810. while (TotalBytesWritten != InputContext->BufferSize) {
  811. BytesToWrite = SHELL_NT_INPUT_CHUNK_SIZE;
  812. if (InputContext->BufferSize - TotalBytesWritten < BytesToWrite) {
  813. BytesToWrite = InputContext->BufferSize - TotalBytesWritten;
  814. }
  815. BytesWritten = write(InputContext->Handle,
  816. InputContext->Buffer + TotalBytesWritten,
  817. BytesToWrite);
  818. if (BytesWritten <= 0) {
  819. break;
  820. }
  821. TotalBytesWritten += BytesWritten;
  822. }
  823. //
  824. // Release the resources.
  825. //
  826. if (InputContext->Buffer != NULL) {
  827. free(InputContext->Buffer);
  828. }
  829. close(InputContext->Handle);
  830. free(InputContext);
  831. return;
  832. }
  833. void
  834. ShNtSignalHandler (
  835. int SignalNumber
  836. )
  837. /*++
  838. Routine Description:
  839. This routine is called when a signal comes in. It marks the signal as
  840. pending and makes an effort to get out as quickly as possible. The signal
  841. execution environment is fairly hostile, so there's not much that could be
  842. done anyway.
  843. Arguments:
  844. SignalNumber - Supplies the signal number of the signal that came in.
  845. Return Value:
  846. None.
  847. --*/
  848. {
  849. //
  850. // Re-apply the signal for trapping.
  851. //
  852. signal(SignalNumber, ShNtSignalHandler);
  853. ShSignalHandler(SignalNumber);
  854. return;
  855. }
  856. void
  857. ShPrintLastError (
  858. void
  859. )
  860. /*++
  861. Routine Description:
  862. This routine prints the result of GetLastError.
  863. Arguments:
  864. None.
  865. Return Value:
  866. None.
  867. --*/
  868. {
  869. DWORD Flags;
  870. PCHAR MessageBuffer;
  871. Flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
  872. FORMAT_MESSAGE_FROM_SYSTEM |
  873. FORMAT_MESSAGE_IGNORE_INSERTS;
  874. FormatMessage(Flags,
  875. NULL,
  876. GetLastError(),
  877. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  878. (LPTSTR)&MessageBuffer,
  879. 0,
  880. NULL);
  881. fprintf(stderr, "Last Error: %s\n", MessageBuffer);
  882. LocalFree(MessageBuffer);
  883. return;
  884. }