exec.c 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. exec.c
  5. Abstract:
  6. This module handles execution of commands for the shell.
  7. Author:
  8. Evan Green 6-Jun-2013
  9. Environment:
  10. POSIX
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "sh.h"
  16. #include "shparse.h"
  17. #include "../swiss.h"
  18. #include <assert.h>
  19. #include <errno.h>
  20. #include <fcntl.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <unistd.h>
  24. #include "../swlib.h"
  25. //
  26. // --------------------------------------------------------------------- Macros
  27. //
  28. //
  29. // Define the file creation mask for new files created by I/O redirection.
  30. //
  31. #define SHELL_FILE_CREATION_MASK 0664
  32. //
  33. // ---------------------------------------------------------------- Definitions
  34. //
  35. //
  36. // ------------------------------------------------------ Data Type Definitions
  37. //
  38. //
  39. // ----------------------------------------------- Internal Function Prototypes
  40. //
  41. BOOL
  42. ShExecuteNode (
  43. PSHELL Shell,
  44. PSHELL_NODE Node
  45. );
  46. BOOL
  47. ShExecuteAsynchronousNode (
  48. PSHELL Shell,
  49. PSHELL_NODE Node
  50. );
  51. BOOL
  52. ShExecuteList (
  53. PSHELL Shell,
  54. PSHELL_EXECUTION_NODE ExecutionNode
  55. );
  56. BOOL
  57. ShExecuteAndOr (
  58. PSHELL Shell,
  59. PSHELL_EXECUTION_NODE ExecutionNode
  60. );
  61. BOOL
  62. ShExecutePipeline (
  63. PSHELL Shell,
  64. PSHELL_EXECUTION_NODE ExecutionNode
  65. );
  66. BOOL
  67. ShExecuteSimpleCommand (
  68. PSHELL Shell,
  69. PSHELL_EXECUTION_NODE ExecutionNode
  70. );
  71. BOOL
  72. ShExecuteFunctionDefinition (
  73. PSHELL Shell,
  74. PSHELL_EXECUTION_NODE ExecutionNode
  75. );
  76. BOOL
  77. ShExecuteFunctionInvocation (
  78. PSHELL Shell,
  79. PSHELL_EXECUTION_NODE ExecutingNode,
  80. PSHELL_NODE Function,
  81. PSTR *Arguments,
  82. ULONG ArgumentCount
  83. );
  84. BOOL
  85. ShExecuteIf (
  86. PSHELL Shell,
  87. PSHELL_EXECUTION_NODE ExecutionNode
  88. );
  89. BOOL
  90. ShExecuteFor (
  91. PSHELL Shell,
  92. PSHELL_EXECUTION_NODE ExecutionNode
  93. );
  94. BOOL
  95. ShExecuteCase (
  96. PSHELL Shell,
  97. PSHELL_EXECUTION_NODE ExecutionNode
  98. );
  99. BOOL
  100. ShExecuteWhileOrUntil (
  101. PSHELL Shell,
  102. PSHELL_EXECUTION_NODE ExecutionNode
  103. );
  104. BOOL
  105. ShExecuteSubshellGroup (
  106. PSHELL Shell,
  107. PSHELL_EXECUTION_NODE ExecutionNode
  108. );
  109. VOID
  110. ShExitOnError (
  111. PSHELL Shell
  112. );
  113. BOOL
  114. ShApplyRedirections (
  115. PSHELL Shell,
  116. PSHELL_EXECUTION_NODE ExecutionNode
  117. );
  118. //
  119. // -------------------------------------------------------------------- Globals
  120. //
  121. //
  122. // Set this variable if swiss command should be recognized even before
  123. // searching the path.
  124. //
  125. BOOL ShUseSwissBuiltins = TRUE;
  126. //
  127. // Define the quoted at arguments string.
  128. //
  129. CHAR ShQuotedAtArgumentsString[] =
  130. {SHELL_CONTROL_QUOTE, '$', '@', SHELL_CONTROL_QUOTE, '\0'};
  131. //
  132. // ------------------------------------------------------------------ Functions
  133. //
  134. BOOL
  135. ShExecute (
  136. PSHELL Shell,
  137. PINT ReturnValue
  138. )
  139. /*++
  140. Routine Description:
  141. This routine executes commands from the input of the shell.
  142. Arguments:
  143. Shell - Supplies a pointer to the shell whose input should be read and
  144. executed.
  145. ReturnValue - Supplies a pointer where the return value of the shell will
  146. be returned.
  147. Return Value:
  148. TRUE on success.
  149. FALSE on failure.
  150. --*/
  151. {
  152. PSHELL_NODE Command;
  153. BOOL Result;
  154. Result = FALSE;
  155. ShPrintPrompt(Shell, 1);
  156. while (Shell->Exited == FALSE) {
  157. ShCheckForSignals(Shell);
  158. Result = ShParse(Shell, &Command);
  159. if (Result == FALSE) {
  160. if ((Shell->Options & SHELL_OPTION_INTERACTIVE) != 0) {
  161. ShPrintPrompt(Shell, 1);
  162. Shell->Lexer.LexerPrimed = FALSE;
  163. continue;
  164. }
  165. break;
  166. }
  167. if (Command == NULL) {
  168. break;
  169. }
  170. if ((Shell->Options & SHELL_OPTION_NO_EXECUTE) == 0) {
  171. Result = ShExecuteNode(Shell, Command);
  172. }
  173. ShReleaseNode(Command);
  174. if (Result == FALSE) {
  175. if ((Shell->Options & SHELL_OPTION_INTERACTIVE) == 0) {
  176. break;
  177. }
  178. }
  179. }
  180. *ReturnValue = Shell->LastReturnValue;
  181. return Result;
  182. }
  183. VOID
  184. ShRestoreRedirections (
  185. PSHELL Shell,
  186. PLIST_ENTRY ActiveRedirectList
  187. )
  188. /*++
  189. Routine Description:
  190. This routine restores all active redirections back to their previous state.
  191. Arguments:
  192. Shell - Supplies a pointer to the shell.
  193. ActiveRedirectList - Supplies a pointer to the active redirect list.
  194. Return Value:
  195. None.
  196. --*/
  197. {
  198. PSHELL_ACTIVE_REDIRECT ActiveRedirect;
  199. INT ReplacedDescriptor;
  200. while (LIST_EMPTY(ActiveRedirectList) == FALSE) {
  201. //
  202. // Loop backwards so that if the same descriptor is redirected multiple
  203. // times then its value gets popped back to the original.
  204. //
  205. ActiveRedirect = LIST_VALUE(ActiveRedirectList->Previous,
  206. SHELL_ACTIVE_REDIRECT,
  207. ListEntry);
  208. LIST_REMOVE(&(ActiveRedirect->ListEntry));
  209. if (ActiveRedirect->OriginalDescriptor != -1) {
  210. ReplacedDescriptor = ShDup2(Shell,
  211. ActiveRedirect->OriginalDescriptor,
  212. ActiveRedirect->FileNumber);
  213. if (ReplacedDescriptor < 0) {
  214. PRINT_ERROR("Failed to restore file number %d.\n",
  215. ActiveRedirect->FileNumber);
  216. }
  217. ShClose(Shell, ActiveRedirect->OriginalDescriptor);
  218. //
  219. // If there was no original descriptor there, close whatever there is
  220. // now to restore it to former non-glory.
  221. //
  222. } else {
  223. ShClose(Shell, ActiveRedirect->FileNumber);
  224. }
  225. if (ActiveRedirect->ChildProcessId > 0) {
  226. SwWaitPid(ActiveRedirect->ChildProcessId, 0, NULL);
  227. }
  228. free(ActiveRedirect);
  229. }
  230. return;
  231. }
  232. VOID
  233. ShSetTerminalMode (
  234. PSHELL Shell,
  235. BOOL Raw
  236. )
  237. /*++
  238. Routine Description:
  239. This routine potentially sets the terminal input mode one way or another.
  240. If the interactive flag is not set, this does nothing.
  241. Arguments:
  242. Shell - Supplies a pointer to the shell. If the interactive flag is not set
  243. in this shell, then nothing happens.
  244. Raw - Supplies a boolean indicating whether to set it in raw mode (TRUE)
  245. or it's previous original mode (FALSE).
  246. Return Value:
  247. None.
  248. --*/
  249. {
  250. if ((Shell->Options & SHELL_OPTION_INTERACTIVE) == 0) {
  251. return;
  252. }
  253. if (Raw != FALSE) {
  254. SwSetRawInputMode(&ShBackspaceCharacter, &ShKillLineCharacter);
  255. } else {
  256. SwRestoreInputMode();
  257. }
  258. return;
  259. }
  260. INT
  261. ShRunCommand (
  262. PSHELL Shell,
  263. PSTR Command,
  264. PSTR *Arguments,
  265. INT ArgumentCount,
  266. INT Asynchronous,
  267. PINT ReturnValue
  268. )
  269. /*++
  270. Routine Description:
  271. This routine is called to run a basic command for the shell.
  272. Arguments:
  273. Shell - Supplies a pointer to the shell.
  274. Command - Supplies a pointer to the command name to run.
  275. Arguments - Supplies a pointer to an array of command argument strings.
  276. This includes the first argument, the command name.
  277. ArgumentCount - Supplies the number of arguments on the command line.
  278. Asynchronous - Supplies 0 if the shell should wait until the command is
  279. finished, or 1 if the function should return immediately with a
  280. return value of 0.
  281. ReturnValue - Supplies a pointer where the return value from the executed
  282. program will be returned.
  283. Return Value:
  284. 0 if the executable was successfully launched.
  285. Non-zero if there was trouble launching the executable.
  286. --*/
  287. {
  288. pid_t Child;
  289. PSTR FullCommandPath;
  290. ULONG FullCommandPathSize;
  291. BOOL Result;
  292. INT Status;
  293. PSWISS_COMMAND_ENTRY SwissCommand;
  294. id_t UserId;
  295. FullCommandPath = NULL;
  296. *ReturnValue = -1;
  297. Child = -1;
  298. //
  299. // If enabled, try the builtin commands.
  300. //
  301. if (ShUseSwissBuiltins != FALSE) {
  302. SwissCommand = SwissFindCommand(Arguments[0]);
  303. //
  304. // If the command is setuid and the environment is currently not setuid,
  305. // pretend like the command wasn't found.
  306. //
  307. if ((SwissCommand != NULL) &&
  308. ((SwissCommand->Flags & SWISS_APP_SETUID_OK) != 0)) {
  309. UserId = SwGetEffectiveUserId();
  310. if ((UserId != 0) && (UserId == SwGetRealUserId())) {
  311. SwissCommand = NULL;
  312. }
  313. }
  314. if (SwissCommand != NULL) {
  315. if (SwForkSupported != 0) {
  316. Child = SwFork();
  317. if (Child < 0) {
  318. PRINT_ERROR("sh: Failed to fork: %s\n", strerror(errno));
  319. Status = -1;
  320. goto RunCommandEnd;
  321. } else if (Child == 0) {
  322. ShRestoreOriginalSignalDispositions();
  323. SwissRunCommand(SwissCommand,
  324. Arguments,
  325. ArgumentCount,
  326. FALSE,
  327. TRUE,
  328. ReturnValue);
  329. exit(*ReturnValue);
  330. //
  331. // In the parent, jump down to wait for the child.
  332. //
  333. } else {
  334. Status = 0;
  335. goto RunCommandEnd;
  336. }
  337. //
  338. // If fork is not supported (Windows), just execute the command in
  339. // a separate process.
  340. //
  341. } else {
  342. fflush(NULL);
  343. Result = SwissRunCommand(SwissCommand,
  344. Arguments,
  345. ArgumentCount,
  346. TRUE,
  347. !Asynchronous,
  348. ReturnValue);
  349. if (Result != FALSE) {
  350. Status = 0;
  351. ShOsConvertExitStatus(ReturnValue);
  352. goto RunCommandEnd;
  353. }
  354. }
  355. }
  356. }
  357. *ReturnValue = 0;
  358. Result = ShLocateCommand(Shell,
  359. Arguments[0],
  360. strlen(Arguments[0]) + 1,
  361. TRUE,
  362. &FullCommandPath,
  363. &FullCommandPathSize,
  364. ReturnValue);
  365. if (Result == FALSE) {
  366. Status = -1;
  367. goto RunCommandEnd;
  368. }
  369. if (*ReturnValue != 0) {
  370. if (*ReturnValue == SHELL_ERROR_OPEN) {
  371. PRINT_ERROR("sh: %s: Command not found.\n", Arguments[0]);
  372. } else if (*ReturnValue == SHELL_ERROR_EXECUTE) {
  373. PRINT_ERROR("sh: %s: Permission denied.\n", Arguments[0]);
  374. }
  375. Status = 0;
  376. goto RunCommandEnd;
  377. }
  378. if (SwForkSupported != 0) {
  379. Child = SwFork();
  380. if (Child < 0) {
  381. PRINT_ERROR("sh: Failed to fork: %s\n", strerror(errno));
  382. Status = -1;
  383. goto RunCommandEnd;
  384. } else if (Child == 0) {
  385. ShRestoreOriginalSignalDispositions();
  386. SwExec(FullCommandPath, Arguments, ArgumentCount);
  387. exit(errno);
  388. //
  389. // In the parent, jump down to wait for the child.
  390. //
  391. } else {
  392. Status = 0;
  393. goto RunCommandEnd;
  394. }
  395. } else {
  396. fflush(NULL);
  397. Status = SwRunCommand(FullCommandPath,
  398. Arguments,
  399. ArgumentCount,
  400. Asynchronous,
  401. ReturnValue);
  402. ShOsConvertExitStatus(ReturnValue);
  403. }
  404. RunCommandEnd:
  405. //
  406. // Wait for the child if there is one.
  407. //
  408. if (Child > 0) {
  409. if (Asynchronous != 0) {
  410. *ReturnValue = 0;
  411. } else {
  412. Status = SwWaitPid(Child, 0, ReturnValue);
  413. if (Status != Child) {
  414. PRINT_ERROR("sh: Failed to wait for child %d\n", Child);
  415. Status = -1;
  416. } else {
  417. ShOsConvertExitStatus(ReturnValue);
  418. }
  419. }
  420. }
  421. if (*ReturnValue > SHELL_EXIT_SIGNALED) {
  422. if ((Shell->Options & SHELL_OPTION_INTERACTIVE) != 0) {
  423. printf("%s terminated by signal %d: %s\n",
  424. Arguments[0],
  425. *ReturnValue - SHELL_EXIT_SIGNALED,
  426. strsignal(*ReturnValue - SHELL_EXIT_SIGNALED));
  427. }
  428. //
  429. // If the command exited normally, save any terminal changes it may have
  430. // made.
  431. //
  432. } else {
  433. SwSaveTerminalMode();
  434. }
  435. if ((FullCommandPath != NULL) && (FullCommandPath != Arguments[0])) {
  436. free(FullCommandPath);
  437. }
  438. return Status;
  439. }
  440. //
  441. // --------------------------------------------------------- Internal Functions
  442. //
  443. BOOL
  444. ShExecuteNode (
  445. PSHELL Shell,
  446. PSHELL_NODE Node
  447. )
  448. /*++
  449. Routine Description:
  450. This routine executes a generic shell node.
  451. Arguments:
  452. Shell - Supplies a pointer to the shell containing the node.
  453. Node - Supplies a pointer to the node to execute.
  454. Return Value:
  455. TRUE on success.
  456. FALSE on failure.
  457. --*/
  458. {
  459. PSHELL_EXECUTION_NODE ExecutionNode;
  460. ULONG OriginalLineNumber;
  461. BOOL Result;
  462. if ((Node->RunInBackground != FALSE) && (SwForkSupported != 0)) {
  463. return ShExecuteAsynchronousNode(Shell, Node);
  464. }
  465. //
  466. // Create an execution node and push it on the stack.
  467. //
  468. ExecutionNode = malloc(sizeof(SHELL_EXECUTION_NODE));
  469. if (ExecutionNode == NULL) {
  470. return FALSE;
  471. }
  472. INITIALIZE_LIST_HEAD(&(ExecutionNode->VariableList));
  473. INITIALIZE_LIST_HEAD(&(ExecutionNode->ArgumentList));
  474. INITIALIZE_LIST_HEAD(&(ExecutionNode->ActiveRedirectList));
  475. ExecutionNode->Node = Node;
  476. ExecutionNode->Flags = 0;
  477. ExecutionNode->ReturnValue = 0;
  478. INSERT_AFTER(&(ExecutionNode->ListEntry), &(Shell->ExecutionStack));
  479. OriginalLineNumber = Shell->ExecutingLineNumber;
  480. Shell->ExecutingLineNumber = Node->LineNumber;
  481. Result = ShApplyRedirections(Shell, ExecutionNode);
  482. if (Result == FALSE) {
  483. goto ExecuteNodeEnd;
  484. }
  485. Result = FALSE;
  486. switch (Node->Type) {
  487. case ShellNodeList:
  488. case ShellNodeTerm:
  489. case ShellNodeBraceGroup:
  490. Result = ShExecuteList(Shell, ExecutionNode);
  491. break;
  492. case ShellNodeAndOr:
  493. Result = ShExecuteAndOr(Shell, ExecutionNode);
  494. break;
  495. case ShellNodePipeline:
  496. Result = ShExecutePipeline(Shell, ExecutionNode);
  497. break;
  498. case ShellNodeSimpleCommand:
  499. Result = ShExecuteSimpleCommand(Shell, ExecutionNode);
  500. break;
  501. case ShellNodeFunction:
  502. Result = ShExecuteFunctionDefinition(Shell, ExecutionNode);
  503. break;
  504. case ShellNodeIf:
  505. Result = ShExecuteIf(Shell, ExecutionNode);
  506. break;
  507. case ShellNodeFor:
  508. Result = ShExecuteFor(Shell, ExecutionNode);
  509. break;
  510. case ShellNodeCase:
  511. Result = ShExecuteCase(Shell, ExecutionNode);
  512. break;
  513. case ShellNodeWhile:
  514. case ShellNodeUntil:
  515. Result = ShExecuteWhileOrUntil(Shell, ExecutionNode);
  516. break;
  517. case ShellNodeSubshell:
  518. Result = ShExecuteSubshellGroup(Shell, ExecutionNode);
  519. break;
  520. default:
  521. assert(FALSE);
  522. Result = FALSE;
  523. }
  524. ExecuteNodeEnd:
  525. //
  526. // Remove the node from the stack if not already done.
  527. //
  528. if (ExecutionNode->ListEntry.Next != NULL) {
  529. LIST_REMOVE(&(ExecutionNode->ListEntry));
  530. }
  531. ShDestroyArgumentList(&(ExecutionNode->ArgumentList));
  532. ShDestroyVariableList(&(ExecutionNode->VariableList));
  533. ShRestoreRedirections(Shell, &(ExecutionNode->ActiveRedirectList));
  534. free(ExecutionNode);
  535. Shell->ExecutingLineNumber = OriginalLineNumber;
  536. Shell->LastReturnValue = Shell->ReturnValue;
  537. return Result;
  538. }
  539. BOOL
  540. ShExecuteAsynchronousNode (
  541. PSHELL Shell,
  542. PSHELL_NODE Node
  543. )
  544. /*++
  545. Routine Description:
  546. This routine executes a shell node asynchronously.
  547. Arguments:
  548. Shell - Supplies a pointer to the shell containing the node.
  549. Node - Supplies a pointer to the node to execute.
  550. Return Value:
  551. TRUE on success.
  552. FALSE on failure.
  553. --*/
  554. {
  555. pid_t Process;
  556. BOOL Result;
  557. assert((Node->RunInBackground != FALSE) && (SwForkSupported != 0));
  558. //
  559. // Attempt to fork the current process, which is easiest and most in line
  560. // with what the shell would like to do.
  561. //
  562. Process = SwFork();
  563. //
  564. // If this is the child, set the node to be synchronous, run the node, and
  565. // exit straight away. Altering the node here doesn't change the memory of
  566. // the parent process remember. See how easy that was?
  567. //
  568. if (Process == 0) {
  569. if (Shell->PostForkCloseDescriptor != -1) {
  570. close(Shell->PostForkCloseDescriptor);
  571. Shell->PostForkCloseDescriptor = -1;
  572. }
  573. Node->RunInBackground = FALSE;
  574. ShExecuteNode(Shell, Node);
  575. exit(Shell->LastReturnValue);
  576. //
  577. // If this is the parent process, then work is finished here. Even easier!
  578. //
  579. } else if (Process != -1) {
  580. Result = TRUE;
  581. goto ExecuteAsynchronousNodeEnd;
  582. //
  583. // Fork failed.
  584. //
  585. } else {
  586. Result = FALSE;
  587. goto ExecuteAsynchronousNodeEnd;
  588. }
  589. Result = TRUE;
  590. ExecuteAsynchronousNodeEnd:
  591. if (Result == FALSE) {
  592. Shell->ReturnValue = 1;
  593. } else {
  594. Shell->ReturnValue = 0;
  595. }
  596. return Result;
  597. }
  598. BOOL
  599. ShExecuteList (
  600. PSHELL Shell,
  601. PSHELL_EXECUTION_NODE ExecutionNode
  602. )
  603. /*++
  604. Routine Description:
  605. This routine executes a list node.
  606. Arguments:
  607. Shell - Supplies a pointer to the shell containing the node.
  608. ExecutionNode - Supplies a pointer to the node to execute.
  609. Return Value:
  610. TRUE on success.
  611. FALSE on failure.
  612. --*/
  613. {
  614. PSHELL_NODE Child;
  615. PLIST_ENTRY CurrentEntry;
  616. PSHELL_NODE Node;
  617. BOOL Result;
  618. Node = ExecutionNode->Node;
  619. assert((Node->Type == ShellNodeList) || (Node->Type == ShellNodeTerm) ||
  620. (Node->Type == ShellNodeBraceGroup));
  621. CurrentEntry = Node->Children.Next;
  622. while (CurrentEntry != &(Node->Children)) {
  623. Child = LIST_VALUE(CurrentEntry, SHELL_NODE, SiblingListEntry);
  624. CurrentEntry = CurrentEntry->Next;
  625. Result = ShExecuteNode(Shell, Child);
  626. if (Result == FALSE) {
  627. return FALSE;
  628. }
  629. if (Shell->Exited != FALSE) {
  630. break;
  631. }
  632. //
  633. // Break out if the execution node was removed from the stack.
  634. //
  635. if (ExecutionNode->ListEntry.Next == NULL) {
  636. break;
  637. }
  638. }
  639. return TRUE;
  640. }
  641. BOOL
  642. ShExecuteAndOr (
  643. PSHELL Shell,
  644. PSHELL_EXECUTION_NODE ExecutionNode
  645. )
  646. /*++
  647. Routine Description:
  648. This routine executes a logical And-Or (&&/||) node.
  649. Arguments:
  650. Shell - Supplies a pointer to the shell containing the node.
  651. ExecutionNode - Supplies a pointer to the node to execute.
  652. Return Value:
  653. TRUE on success.
  654. FALSE on failure.
  655. --*/
  656. {
  657. PSHELL_NODE Child;
  658. PLIST_ENTRY CurrentEntry;
  659. BOOL Execute;
  660. PSHELL_NODE Node;
  661. PSHELL_NODE Previous;
  662. BOOL Result;
  663. Node = ExecutionNode->Node;
  664. assert(Node->Type == ShellNodeAndOr);
  665. Previous = NULL;
  666. CurrentEntry = Node->Children.Next;
  667. while (CurrentEntry != &(Node->Children)) {
  668. Child = LIST_VALUE(CurrentEntry, SHELL_NODE, SiblingListEntry);
  669. CurrentEntry = CurrentEntry->Next;
  670. //
  671. // The first node always executes. If the previous node was an AND,
  672. // then don't execute this node if the previous node failed. If the
  673. // previous node was an OR, then don't execute this node if the
  674. // previous node succeeded.
  675. //
  676. Execute = TRUE;
  677. if (Previous != NULL) {
  678. if (Previous->AndOr == TOKEN_DOUBLE_AND) {
  679. if (Shell->LastReturnValue != 0) {
  680. Execute = FALSE;
  681. }
  682. } else if (Previous->AndOr == TOKEN_DOUBLE_OR) {
  683. if (Shell->LastReturnValue == 0) {
  684. Execute = FALSE;
  685. }
  686. }
  687. }
  688. if (Execute != FALSE) {
  689. Result = ShExecuteNode(Shell, Child);
  690. if (Result == FALSE) {
  691. return FALSE;
  692. }
  693. }
  694. if (Shell->Exited != FALSE) {
  695. break;
  696. }
  697. //
  698. // Break out if the execution node was removed from the stack.
  699. //
  700. if (ExecutionNode->ListEntry.Next == NULL) {
  701. break;
  702. }
  703. Previous = Child;
  704. }
  705. return TRUE;
  706. }
  707. BOOL
  708. ShExecutePipeline (
  709. PSHELL Shell,
  710. PSHELL_EXECUTION_NODE ExecutionNode
  711. )
  712. /*++
  713. Routine Description:
  714. This routine executes a pipeline.
  715. Arguments:
  716. Shell - Supplies a pointer to the shell containing the node.
  717. ExecutionNode - Supplies a pointer to the node to execute.
  718. Return Value:
  719. TRUE on success.
  720. FALSE on failure.
  721. --*/
  722. {
  723. PSHELL_NODE Child;
  724. PLIST_ENTRY CurrentEntry;
  725. INT NextPipe[2];
  726. PSHELL_NODE Node;
  727. INT OriginalStandardIn;
  728. INT OriginalStandardOut;
  729. INT PreviousPipeRead;
  730. BOOL Result;
  731. NextPipe[0] = -1;
  732. NextPipe[1] = -1;
  733. Node = ExecutionNode->Node;
  734. OriginalStandardIn = -1;
  735. OriginalStandardOut = -1;
  736. PreviousPipeRead = -1;
  737. Result = TRUE;
  738. assert(Node->Type == ShellNodePipeline);
  739. CurrentEntry = Node->Children.Next;
  740. while (CurrentEntry != &(Node->Children)) {
  741. Child = LIST_VALUE(CurrentEntry, SHELL_NODE, SiblingListEntry);
  742. CurrentEntry = CurrentEntry->Next;
  743. //
  744. // If this is not the last node, create a new pipe and wire standard out
  745. // up to that pipe. If it is the last node, leave standard out wired up
  746. // the way it is.
  747. //
  748. if (Child->SiblingListEntry.Next != &(Node->Children)) {
  749. Result = ShCreatePipe(NextPipe);
  750. if (Result == FALSE) {
  751. return FALSE;
  752. }
  753. OriginalStandardOut = ShDup(Shell, STDOUT_FILENO, FALSE);
  754. ShDup2(Shell, NextPipe[1], STDOUT_FILENO);
  755. ShClose(Shell, NextPipe[1]);
  756. NextPipe[1] = -1;
  757. }
  758. //
  759. // If this is not the first node, wire up standard input to the
  760. // previous pipe's read end.
  761. //
  762. if (Child->SiblingListEntry.Previous != &(Node->Children)) {
  763. OriginalStandardIn = ShDup(Shell, STDIN_FILENO, FALSE);
  764. assert(PreviousPipeRead != -1);
  765. ShDup2(Shell, PreviousPipeRead, STDIN_FILENO);
  766. ShClose(Shell, PreviousPipeRead);
  767. PreviousPipeRead = -1;
  768. }
  769. //
  770. // Save the previous pipe's read entry. Make it a non-inheritable
  771. // handle so that when the next process closes standard in, that's the
  772. // last open handle.
  773. //
  774. if (NextPipe[0] != -1) {
  775. PreviousPipeRead = ShDup(Shell, NextPipe[0], FALSE);
  776. ShClose(Shell, NextPipe[0]);
  777. NextPipe[0] = -1;
  778. Shell->PostForkCloseDescriptor = PreviousPipeRead;
  779. }
  780. Result = ShExecuteNode(Shell, Child);
  781. //
  782. // Restore standard in and standard out if they were changed.
  783. //
  784. if (OriginalStandardIn != -1) {
  785. ShDup2(Shell, OriginalStandardIn, STDIN_FILENO);
  786. ShClose(Shell, OriginalStandardIn);
  787. OriginalStandardIn = -1;
  788. }
  789. if (OriginalStandardOut != -1) {
  790. ShDup2(Shell, OriginalStandardOut, STDOUT_FILENO);
  791. ShClose(Shell, OriginalStandardOut);
  792. OriginalStandardOut = -1;
  793. }
  794. if (PreviousPipeRead != -1) {
  795. assert((Shell->PostForkCloseDescriptor == PreviousPipeRead) ||
  796. (Shell->PostForkCloseDescriptor == -1));
  797. Shell->PostForkCloseDescriptor = -1;
  798. }
  799. //
  800. // If executing the command failed, stop now.
  801. //
  802. if (Result == FALSE) {
  803. goto ExecutePipelineEnd;
  804. }
  805. if (Shell->Exited != FALSE) {
  806. break;
  807. }
  808. //
  809. // Break out if the execution node was removed from the stack.
  810. //
  811. if (ExecutionNode->ListEntry.Next == NULL) {
  812. break;
  813. }
  814. }
  815. assert(Shell->ReturnValue == Shell->LastReturnValue);
  816. if ((Shell->Exited == FALSE) && (Node->U.Pipeline.Bang != FALSE)) {
  817. Shell->ReturnValue = !Shell->LastReturnValue;
  818. }
  819. ExecutePipelineEnd:
  820. if (OriginalStandardIn != -1) {
  821. ShDup2(Shell, OriginalStandardIn, STDIN_FILENO);
  822. ShClose(Shell, OriginalStandardIn);
  823. OriginalStandardIn = -1;
  824. }
  825. if (OriginalStandardOut != -1) {
  826. ShDup2(Shell, OriginalStandardOut, STDOUT_FILENO);
  827. ShClose(Shell, OriginalStandardOut);
  828. OriginalStandardOut = -1;
  829. }
  830. if (NextPipe[0] != -1) {
  831. ShClose(Shell, NextPipe[0]);
  832. }
  833. if (NextPipe[1] != -1) {
  834. ShClose(Shell, NextPipe[1]);
  835. }
  836. //
  837. // Check for signals to reap any child processes that were created.
  838. //
  839. ShCheckForSignals(Shell);
  840. return Result;
  841. }
  842. BOOL
  843. ShExecuteSimpleCommand (
  844. PSHELL Shell,
  845. PSHELL_EXECUTION_NODE ExecutionNode
  846. )
  847. /*++
  848. Routine Description:
  849. This routine executes a simple command. The function makes it sound easier
  850. than it is.
  851. Arguments:
  852. Shell - Supplies a pointer to the shell containing the node.
  853. ExecutionNode - Supplies a pointer to the node to execute.
  854. Return Value:
  855. TRUE on success.
  856. FALSE on failure.
  857. --*/
  858. {
  859. ULONG ArgumentCount;
  860. ULONG ArgumentIndex;
  861. PSTR *Arguments;
  862. BOOL Asynchronous;
  863. PSHELL_BUILTIN_COMMAND BuiltinCommand;
  864. PSTR ExpandedArguments;
  865. UINTN ExpandedArgumentsSize;
  866. PSHELL_FUNCTION Function;
  867. PSHELL_EXECUTION_NODE LatestExecutionNode;
  868. PSHELL_NODE Node;
  869. BOOL Result;
  870. INT ReturnValue;
  871. PSHELL_NODE_SIMPLE_COMMAND SimpleCommand;
  872. ArgumentCount = 0;
  873. Arguments = NULL;
  874. ExpandedArguments = NULL;
  875. Node = ExecutionNode->Node;
  876. assert(Node->Type == ShellNodeSimpleCommand);
  877. SimpleCommand = &(Node->U.SimpleCommand);
  878. if ((Shell->Options & SHELL_OPTION_TRACE_COMMAND) != 0) {
  879. ShPrintPrompt(Shell, 4);
  880. }
  881. Shell->ReturnValue = 0;
  882. Result = ShExecuteVariableAssignments(Shell, ExecutionNode);
  883. if (Result == FALSE) {
  884. goto ExecuteSimpleCommandEnd;
  885. }
  886. if (SimpleCommand->Arguments != NULL) {
  887. //
  888. // Perform expansions, field splitting, and quote removal.
  889. //
  890. Result = ShPerformExpansions(Shell,
  891. SimpleCommand->Arguments,
  892. SimpleCommand->ArgumentsSize,
  893. 0,
  894. &ExpandedArguments,
  895. &ExpandedArgumentsSize,
  896. &Arguments,
  897. &ArgumentCount);
  898. if (Result == FALSE) {
  899. goto ExecuteSimpleCommandEnd;
  900. }
  901. }
  902. //
  903. // If tracing is enabled, print the tracing prompt and then the command
  904. //
  905. if ((Shell->Options & SHELL_OPTION_TRACE_COMMAND) != 0) {
  906. for (ArgumentIndex = 0;
  907. ArgumentIndex < ArgumentCount;
  908. ArgumentIndex += 1) {
  909. ShPrintTrace(Shell, "%s ", Arguments[ArgumentIndex]);
  910. }
  911. ShPrintTrace(Shell, "\n");
  912. }
  913. if (SimpleCommand->Arguments == NULL) {
  914. Result = TRUE;
  915. goto ExecuteSimpleCommandEnd;
  916. }
  917. //
  918. // If the command is empty, don't do much.
  919. //
  920. if ((ArgumentCount == 0) || (strlen(Arguments[0]) == 0)) {
  921. Result = TRUE;
  922. goto ExecuteSimpleCommandEnd;
  923. }
  924. Asynchronous = FALSE;
  925. if (Node->RunInBackground != FALSE) {
  926. Asynchronous = TRUE;
  927. }
  928. //
  929. // Check to see if this is a builtin command, and run it if it is.
  930. //
  931. BuiltinCommand = ShIsBuiltinCommand(Arguments[0]);
  932. if (BuiltinCommand != NULL) {
  933. ReturnValue = ShRunBuiltinCommand(Shell,
  934. BuiltinCommand,
  935. ArgumentCount,
  936. Arguments);
  937. //
  938. // Put the return value on the most recent execution node.
  939. //
  940. if (!LIST_EMPTY(&(Shell->ExecutionStack))) {
  941. LatestExecutionNode = LIST_VALUE(Shell->ExecutionStack.Next,
  942. SHELL_EXECUTION_NODE,
  943. ListEntry);
  944. LatestExecutionNode->ReturnValue = ReturnValue;
  945. }
  946. } else {
  947. //
  948. // Look to see if this is a function, and run that function if so.
  949. //
  950. Function = ShGetFunction(Shell, Arguments[0], strlen(Arguments[0]) + 1);
  951. if (Function != NULL) {
  952. Result = ShExecuteFunctionInvocation(Shell,
  953. ExecutionNode,
  954. Function->Node,
  955. Arguments + 1,
  956. ArgumentCount - 1);
  957. goto ExecuteSimpleCommandEnd;
  958. }
  959. Result = TRUE;
  960. ShRunCommand(Shell,
  961. Arguments[0],
  962. Arguments,
  963. ArgumentCount,
  964. Asynchronous,
  965. &ReturnValue);
  966. }
  967. Shell->ReturnValue = ReturnValue;
  968. Result = TRUE;
  969. ExecuteSimpleCommandEnd:
  970. //
  971. // If the simple command failed and exit on errors is set, potentially
  972. // exit.
  973. //
  974. if ((Shell->Options & SHELL_OPTION_EXIT_ON_FAILURE) != 0) {
  975. ShExitOnError(Shell);
  976. }
  977. if (Arguments != NULL) {
  978. free(Arguments);
  979. }
  980. if (ExpandedArguments != NULL) {
  981. free(ExpandedArguments);
  982. }
  983. return Result;
  984. }
  985. BOOL
  986. ShExecuteFunctionDefinition (
  987. PSHELL Shell,
  988. PSHELL_EXECUTION_NODE ExecutionNode
  989. )
  990. /*++
  991. Routine Description:
  992. This routine executes a function definition node. The definitions don't
  993. actually run the function, so this is a no-op.
  994. Arguments:
  995. Shell - Supplies a pointer to the shell containing the node.
  996. ExecutionNode - Supplies a pointer to the node to execute.
  997. Return Value:
  998. TRUE on success.
  999. FALSE on failure.
  1000. --*/
  1001. {
  1002. BOOL Result;
  1003. //
  1004. // Make the function declaration active in the shell.
  1005. //
  1006. Result = ShDeclareFunction(Shell, ExecutionNode->Node);
  1007. if (Result == FALSE) {
  1008. return FALSE;
  1009. }
  1010. //
  1011. // Function definitions are successful if they were parsed correctly, which
  1012. // it was.
  1013. //
  1014. Shell->ReturnValue = 0;
  1015. return TRUE;
  1016. }
  1017. BOOL
  1018. ShExecuteFunctionInvocation (
  1019. PSHELL Shell,
  1020. PSHELL_EXECUTION_NODE ExecutingNode,
  1021. PSHELL_NODE Function,
  1022. PSTR *Arguments,
  1023. ULONG ArgumentCount
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. This routine executes a function.
  1028. Arguments:
  1029. Shell - Supplies a pointer to the shell containing the node.
  1030. ExecutingNode - Supplies a pointer to the execution node this function is
  1031. run as. This will temporarily get pointed to the function node.
  1032. Function - Supplies a pointer to the function to execute.
  1033. Arguments - Supplies a pointer to the array of strings containing the
  1034. arguments.
  1035. ArgumentCount - Supplies the number of arguments in the array.
  1036. Return Value:
  1037. TRUE on success.
  1038. FALSE on failure.
  1039. --*/
  1040. {
  1041. PSHELL_NODE Body;
  1042. PSHELL_NODE OriginalNode;
  1043. BOOL Result;
  1044. assert(ExecutingNode->Node->Type == ShellNodeSimpleCommand);
  1045. assert((ExecutingNode->Flags & SHELL_EXECUTION_BODY) == 0);
  1046. OriginalNode = ExecutingNode->Node;
  1047. ExecutingNode->Node = Function;
  1048. ExecutingNode->Flags |= SHELL_EXECUTION_BODY;
  1049. assert(LIST_EMPTY(&(ExecutingNode->ArgumentList)) != FALSE);
  1050. //
  1051. // Create an argument list out of the incoming arguments.
  1052. //
  1053. Result = ShCreateArgumentList(Arguments,
  1054. ArgumentCount,
  1055. &(ExecutingNode->ArgumentList));
  1056. if (Result == FALSE) {
  1057. goto ExecuteFunctionInvocationEnd;
  1058. }
  1059. //
  1060. // There should only be one thing in the children list, the compound
  1061. // body statement.
  1062. //
  1063. assert((LIST_EMPTY(&(Function->Children)) == FALSE) &&
  1064. (Function->Children.Next->Next == &(Function->Children)));
  1065. Body = LIST_VALUE(Function->Children.Next, SHELL_NODE, SiblingListEntry);
  1066. Result = ShExecuteNode(Shell, Body);
  1067. if (Result == FALSE) {
  1068. goto ExecuteFunctionInvocationEnd;
  1069. }
  1070. ExecuteFunctionInvocationEnd:
  1071. ExecutingNode->Flags &= ~SHELL_EXECUTION_BODY;
  1072. //
  1073. // If the options were made local, restore them now.
  1074. //
  1075. if ((ExecutingNode->Flags & SHELL_EXECUTION_RESTORE_OPTIONS) != 0) {
  1076. Shell->Options = ExecutingNode->SavedOptions;
  1077. }
  1078. ExecutingNode->Node = OriginalNode;
  1079. //
  1080. // Destroy the current argument list, as it's the ones set up for the
  1081. // function.
  1082. //
  1083. ShDestroyArgumentList(&(ExecutingNode->ArgumentList));
  1084. return Result;
  1085. }
  1086. BOOL
  1087. ShExecuteIf (
  1088. PSHELL Shell,
  1089. PSHELL_EXECUTION_NODE ExecutionNode
  1090. )
  1091. /*++
  1092. Routine Description:
  1093. This routine executes an if statement.
  1094. Arguments:
  1095. Shell - Supplies a pointer to the shell containing the node.
  1096. ExecutionNode - Supplies a pointer to the node to execute.
  1097. Return Value:
  1098. TRUE on success.
  1099. FALSE on failure.
  1100. --*/
  1101. {
  1102. PSHELL_NODE Condition;
  1103. INT ConditionReturn;
  1104. PSHELL_NODE FalseStatement;
  1105. PSHELL_NODE Node;
  1106. BOOL Result;
  1107. PSHELL_NODE TrueStatement;
  1108. Node = ExecutionNode->Node;
  1109. assert(Node->Type == ShellNodeIf);
  1110. //
  1111. // Get the condition, true, and maybe the false conditions.
  1112. //
  1113. assert(Node->Children.Next != &(Node->Children));
  1114. Condition = LIST_VALUE(Node->Children.Next, SHELL_NODE, SiblingListEntry);
  1115. assert(Condition->SiblingListEntry.Next != &(Node->Children));
  1116. TrueStatement = LIST_VALUE(Condition->SiblingListEntry.Next,
  1117. SHELL_NODE,
  1118. SiblingListEntry);
  1119. FalseStatement = NULL;
  1120. if (TrueStatement->SiblingListEntry.Next != &(Node->Children)) {
  1121. FalseStatement = LIST_VALUE(TrueStatement->SiblingListEntry.Next,
  1122. SHELL_NODE,
  1123. SiblingListEntry);
  1124. }
  1125. Result = ShExecuteNode(Shell, Condition);
  1126. if (Result == FALSE) {
  1127. return FALSE;
  1128. }
  1129. if (Shell->Exited != FALSE) {
  1130. return TRUE;
  1131. }
  1132. ConditionReturn = Shell->LastReturnValue;
  1133. Shell->ReturnValue = 0;
  1134. //
  1135. // Break out if no longer on the execution stack.
  1136. //
  1137. if (ExecutionNode->ListEntry.Next == NULL) {
  1138. return TRUE;
  1139. }
  1140. //
  1141. // Go to the true statement if the return value was zero.
  1142. //
  1143. ExecutionNode->Flags |= SHELL_EXECUTION_BODY;
  1144. if (ConditionReturn == 0) {
  1145. Result = ShExecuteNode(Shell, TrueStatement);
  1146. } else if (FalseStatement != NULL) {
  1147. Result = ShExecuteNode(Shell, FalseStatement);
  1148. }
  1149. ExecutionNode->Flags &= ~SHELL_EXECUTION_BODY;
  1150. return Result;
  1151. }
  1152. BOOL
  1153. ShExecuteFor (
  1154. PSHELL Shell,
  1155. PSHELL_EXECUTION_NODE ExecutionNode
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. This routine executes a for loop.
  1160. Arguments:
  1161. Shell - Supplies a pointer to the shell containing the node.
  1162. ExecutionNode - Supplies a pointer to the node to execute.
  1163. Return Value:
  1164. TRUE on success.
  1165. FALSE on failure.
  1166. --*/
  1167. {
  1168. PSHELL_NODE DoGroup;
  1169. PSHELL_NODE_FOR ForStatement;
  1170. PSHELL_NODE Node;
  1171. BOOL Result;
  1172. PSTR SplitBuffer;
  1173. ULONG WordCount;
  1174. ULONG WordIndex;
  1175. PSTR WordListString;
  1176. UINTN WordListStringSize;
  1177. PSTR *Words;
  1178. Node = ExecutionNode->Node;
  1179. SplitBuffer = NULL;
  1180. WordListString = NULL;
  1181. Words = NULL;
  1182. assert(Node->Type == ShellNodeFor);
  1183. assert(LIST_EMPTY(&(Node->Children)) == FALSE);
  1184. ForStatement = &(Node->U.For);
  1185. DoGroup = LIST_VALUE(Node->Children.Next, SHELL_NODE, SiblingListEntry);
  1186. assert(DoGroup->SiblingListEntry.Next == &(Node->Children));
  1187. //
  1188. // Expand the word list. If there is no word list, use the parameters.
  1189. //
  1190. if (ForStatement->WordListBuffer == NULL) {
  1191. Result = ShPerformExpansions(Shell,
  1192. ShQuotedAtArgumentsString,
  1193. sizeof(ShQuotedAtArgumentsString),
  1194. 0,
  1195. &WordListString,
  1196. &WordListStringSize,
  1197. &Words,
  1198. &WordCount);
  1199. } else {
  1200. Result = ShPerformExpansions(Shell,
  1201. ForStatement->WordListBuffer,
  1202. ForStatement->WordListBufferSize,
  1203. 0,
  1204. &WordListString,
  1205. &WordListStringSize,
  1206. &Words,
  1207. &WordCount);
  1208. }
  1209. if (Result == FALSE) {
  1210. goto ExecuteForEnd;
  1211. }
  1212. //
  1213. // If there are no words anymore, simply end.
  1214. //
  1215. if (WordCount == 0) {
  1216. Shell->ReturnValue = 0;
  1217. Result = TRUE;
  1218. goto ExecuteForEnd;
  1219. }
  1220. //
  1221. // Loop through every word, assign the variable, and execute the do group.
  1222. //
  1223. for (WordIndex = 0; WordIndex < WordCount; WordIndex += 1) {
  1224. Result = ShSetVariable(Shell,
  1225. ForStatement->Name,
  1226. ForStatement->NameSize,
  1227. Words[WordIndex],
  1228. strlen(Words[WordIndex]) + 1);
  1229. if (Result == FALSE) {
  1230. goto ExecuteForEnd;
  1231. }
  1232. Result = ShExecuteNode(Shell, DoGroup);
  1233. if (Result == FALSE) {
  1234. goto ExecuteForEnd;
  1235. }
  1236. if (Shell->Exited != FALSE) {
  1237. break;
  1238. }
  1239. //
  1240. // Stop if this execution node is no longer on the stack.
  1241. //
  1242. if (ExecutionNode->ListEntry.Next == NULL) {
  1243. break;
  1244. }
  1245. }
  1246. ExecuteForEnd:
  1247. if (WordListString != NULL) {
  1248. free(WordListString);
  1249. }
  1250. if (SplitBuffer != NULL) {
  1251. free(SplitBuffer);
  1252. }
  1253. if (Words != NULL) {
  1254. free(Words);
  1255. }
  1256. return Result;
  1257. }
  1258. BOOL
  1259. ShExecuteCase (
  1260. PSHELL Shell,
  1261. PSHELL_EXECUTION_NODE ExecutionNode
  1262. )
  1263. /*++
  1264. Routine Description:
  1265. This routine executes a list node.
  1266. Arguments:
  1267. Shell - Supplies a pointer to the shell containing the node.
  1268. ExecutionNode - Supplies a pointer to the node to execute.
  1269. Return Value:
  1270. TRUE on success.
  1271. FALSE on failure.
  1272. --*/
  1273. {
  1274. PLIST_ENTRY CurrentPatternEntry;
  1275. PLIST_ENTRY CurrentSetEntry;
  1276. PSTR ExpandedPattern;
  1277. UINTN ExpandedPatternSize;
  1278. PSTR Input;
  1279. UINTN InputSize;
  1280. BOOL Match;
  1281. PSHELL_NODE Node;
  1282. ULONG Options;
  1283. PSHELL_CASE_PATTERN_ENTRY PatternEntry;
  1284. BOOL Result;
  1285. PSHELL_CASE_PATTERN_SET Set;
  1286. Input = NULL;
  1287. Match = FALSE;
  1288. Node = ExecutionNode->Node;
  1289. assert(Node->Type == ShellNodeCase);
  1290. //
  1291. // Get and expand the input.
  1292. //
  1293. Result = ShPerformExpansions(Shell,
  1294. Node->U.Case.Name,
  1295. Node->U.Case.NameSize,
  1296. SHELL_EXPANSION_OPTION_NO_FIELD_SPLIT,
  1297. &Input,
  1298. &InputSize,
  1299. NULL,
  1300. NULL);
  1301. if (Result == FALSE) {
  1302. goto ExecuteCaseEnd;
  1303. }
  1304. if (LIST_EMPTY(&(Node->U.Case.PatternList)) != FALSE) {
  1305. Result = TRUE;
  1306. goto ExecuteCaseEnd;
  1307. }
  1308. Options = SHELL_EXPANSION_OPTION_NO_FIELD_SPLIT |
  1309. SHELL_EXPANSION_OPTION_NO_QUOTE_REMOVAL;
  1310. //
  1311. // Loop through every case and see if any of the sets of patterns match.
  1312. //
  1313. CurrentSetEntry = Node->U.Case.PatternList.Next;
  1314. while (CurrentSetEntry != &(Node->U.Case.PatternList)) {
  1315. Set = LIST_VALUE(CurrentSetEntry, SHELL_CASE_PATTERN_SET, ListEntry);
  1316. CurrentSetEntry = CurrentSetEntry->Next;
  1317. //
  1318. // Loop through every pattern in the set.
  1319. //
  1320. CurrentPatternEntry = Set->PatternEntryList.Next;
  1321. while (CurrentPatternEntry != &(Set->PatternEntryList)) {
  1322. PatternEntry = LIST_VALUE(CurrentPatternEntry,
  1323. SHELL_CASE_PATTERN_ENTRY,
  1324. ListEntry);
  1325. CurrentPatternEntry = CurrentPatternEntry->Next;
  1326. Result = ShPerformExpansions(Shell,
  1327. PatternEntry->Pattern,
  1328. PatternEntry->PatternSize,
  1329. Options,
  1330. &ExpandedPattern,
  1331. &ExpandedPatternSize,
  1332. NULL,
  1333. NULL);
  1334. if (Result == FALSE) {
  1335. goto ExecuteCaseEnd;
  1336. }
  1337. ShStringDequote(ExpandedPattern,
  1338. ExpandedPatternSize,
  1339. SHELL_DEQUOTE_FOR_PATTERN_MATCHING,
  1340. &ExpandedPatternSize);
  1341. Match = SwDoesPatternMatch(Input,
  1342. InputSize,
  1343. ExpandedPattern,
  1344. ExpandedPatternSize);
  1345. free(ExpandedPattern);
  1346. //
  1347. // If the input matches the case, run the action associated with
  1348. // it and end the case.
  1349. //
  1350. if (Match != FALSE) {
  1351. Result = TRUE;
  1352. if (Set->Action != NULL) {
  1353. Result = ShExecuteNode(Shell, Set->Action);
  1354. }
  1355. goto ExecuteCaseEnd;
  1356. }
  1357. }
  1358. }
  1359. ExecuteCaseEnd:
  1360. if (Input != NULL) {
  1361. free(Input);
  1362. }
  1363. //
  1364. // If no case was executed, the return value is zero.
  1365. //
  1366. if (Match == FALSE) {
  1367. Shell->ReturnValue = 0;
  1368. }
  1369. return Result;
  1370. }
  1371. BOOL
  1372. ShExecuteWhileOrUntil (
  1373. PSHELL Shell,
  1374. PSHELL_EXECUTION_NODE ExecutionNode
  1375. )
  1376. /*++
  1377. Routine Description:
  1378. This routine executes a while statement or an until statement.
  1379. Arguments:
  1380. Shell - Supplies a pointer to the shell containing the node.
  1381. ExecutionNode - Supplies a pointer to the node to execute.
  1382. Return Value:
  1383. TRUE on success.
  1384. FALSE on failure.
  1385. --*/
  1386. {
  1387. BOOL BeenAround;
  1388. PSHELL_NODE Condition;
  1389. INT ConditionResult;
  1390. PSHELL_NODE DoGroup;
  1391. BOOL ExecuteDoGroup;
  1392. PSHELL_NODE Node;
  1393. BOOL Result;
  1394. Node = ExecutionNode->Node;
  1395. assert((Node->Type == ShellNodeWhile) || (Node->Type == ShellNodeUntil));
  1396. //
  1397. // Get the condition, true, and maybe the false conditions.
  1398. //
  1399. assert(Node->Children.Next != &(Node->Children));
  1400. Condition = LIST_VALUE(Node->Children.Next, SHELL_NODE, SiblingListEntry);
  1401. assert(Condition->SiblingListEntry.Next != &(Node->Children));
  1402. DoGroup = LIST_VALUE(Condition->SiblingListEntry.Next,
  1403. SHELL_NODE,
  1404. SiblingListEntry);
  1405. //
  1406. // Execute the do-group as long as the condition is zero for while loops
  1407. // or non-zero for until loops.
  1408. //
  1409. BeenAround = FALSE;
  1410. while (TRUE) {
  1411. Result = ShExecuteNode(Shell, Condition);
  1412. if (Result == FALSE) {
  1413. return FALSE;
  1414. }
  1415. if (Shell->Exited != FALSE) {
  1416. break;
  1417. }
  1418. ConditionResult = Shell->LastReturnValue;
  1419. Shell->ReturnValue = 0;
  1420. //
  1421. // Break out if no longer on the execution stack.
  1422. //
  1423. if (ExecutionNode->ListEntry.Next == NULL) {
  1424. return TRUE;
  1425. }
  1426. //
  1427. // Figure out whether or not to execute the do group.
  1428. //
  1429. ExecuteDoGroup = FALSE;
  1430. if (Node->Type == ShellNodeWhile) {
  1431. if (ConditionResult == 0) {
  1432. ExecuteDoGroup = TRUE;
  1433. }
  1434. } else {
  1435. if (ConditionResult != 0) {
  1436. ExecuteDoGroup = TRUE;
  1437. }
  1438. }
  1439. //
  1440. // If the do-group isn't going to be executed and never has before,
  1441. // the return value is zero. Otherwise the return value is left as the
  1442. // last command in the do-group.
  1443. //
  1444. if (ExecuteDoGroup == FALSE) {
  1445. if (BeenAround == FALSE) {
  1446. Shell->ReturnValue = 0;
  1447. }
  1448. break;
  1449. }
  1450. //
  1451. // Run the do-group.
  1452. //
  1453. ExecutionNode->Flags |= SHELL_EXECUTION_BODY;
  1454. Result = ShExecuteNode(Shell, DoGroup);
  1455. ExecutionNode->Flags &= ~SHELL_EXECUTION_BODY;
  1456. if (Result == FALSE) {
  1457. return FALSE;
  1458. }
  1459. //
  1460. // Break out if no longer on the execution stack, otherwise loop
  1461. // around and run the condition again.
  1462. //
  1463. if (ExecutionNode->ListEntry.Next == NULL) {
  1464. return TRUE;
  1465. }
  1466. }
  1467. return Result;
  1468. }
  1469. BOOL
  1470. ShExecuteSubshellGroup (
  1471. PSHELL Shell,
  1472. PSHELL_EXECUTION_NODE ExecutionNode
  1473. )
  1474. /*++
  1475. Routine Description:
  1476. This routine executes a subshell compound statement, which is a compound
  1477. list inside of parentheses.
  1478. Arguments:
  1479. Shell - Supplies a pointer to the shell containing the node.
  1480. ExecutionNode - Supplies a pointer to the node to execute.
  1481. Return Value:
  1482. TRUE on success.
  1483. FALSE on failure.
  1484. --*/
  1485. {
  1486. PSHELL_NODE Child;
  1487. pid_t ChildProcess;
  1488. PLIST_ENTRY CurrentEntry;
  1489. PSHELL_NODE Node;
  1490. PSTR OriginalDirectory;
  1491. BOOL Result;
  1492. INT Status;
  1493. PSHELL Subshell;
  1494. pid_t WaitResult;
  1495. Node = ExecutionNode->Node;
  1496. OriginalDirectory = NULL;
  1497. assert(Node->Type == ShellNodeSubshell);
  1498. Subshell = ShCreateSubshell(Shell, NULL, 0, FALSE);
  1499. if (Subshell == NULL) {
  1500. return FALSE;
  1501. }
  1502. ChildProcess = -1;
  1503. if (SwForkSupported != FALSE) {
  1504. ChildProcess = SwFork();
  1505. } else {
  1506. //
  1507. // Save the current directory.
  1508. //
  1509. OriginalDirectory = getcwd(NULL, 0);
  1510. }
  1511. //
  1512. // Execute all the children on the subshell (either if this is the child
  1513. // process or fork never happened.
  1514. //
  1515. if (ChildProcess <= 0) {
  1516. CurrentEntry = Node->Children.Next;
  1517. while (CurrentEntry != &(Node->Children)) {
  1518. Child = LIST_VALUE(CurrentEntry, SHELL_NODE, SiblingListEntry);
  1519. CurrentEntry = CurrentEntry->Next;
  1520. Result = ShExecuteNode(Subshell, Child);
  1521. if (Result == FALSE) {
  1522. goto ExecuteSubshellGroupEnd;
  1523. }
  1524. if (Shell->Exited != FALSE) {
  1525. break;
  1526. }
  1527. //
  1528. // Break out if the execution node was removed from the stack.
  1529. //
  1530. if (ExecutionNode->ListEntry.Next == NULL) {
  1531. break;
  1532. }
  1533. }
  1534. }
  1535. //
  1536. // If this is the child process, exit now.
  1537. //
  1538. if (ChildProcess == 0) {
  1539. exit(Subshell->LastReturnValue);
  1540. //
  1541. // If this is the parent process, wait for the child.
  1542. //
  1543. } else if (ChildProcess > 0) {
  1544. WaitResult = SwWaitPid(ChildProcess, 0, &(Subshell->LastReturnValue));
  1545. if (WaitResult == -1) {
  1546. Subshell->LastReturnValue = SHELL_ERROR_OPEN;
  1547. SwPrintError(errno,
  1548. NULL,
  1549. "Failed to wait for pid %d",
  1550. ChildProcess);
  1551. Result = FALSE;
  1552. goto ExecuteSubshellGroupEnd;
  1553. }
  1554. ShOsConvertExitStatus(&(Subshell->LastReturnValue));
  1555. }
  1556. Shell->ReturnValue = Subshell->LastReturnValue;
  1557. Result = TRUE;
  1558. ExecuteSubshellGroupEnd:
  1559. if (Subshell != NULL) {
  1560. ShDestroyShell(Subshell);
  1561. }
  1562. //
  1563. // Restore the current directory.
  1564. //
  1565. if (OriginalDirectory != NULL) {
  1566. Status = chdir(OriginalDirectory);
  1567. if (Status != 0) {
  1568. Result = FALSE;
  1569. }
  1570. free(OriginalDirectory);
  1571. }
  1572. return Result;
  1573. }
  1574. VOID
  1575. ShExitOnError (
  1576. PSHELL Shell
  1577. )
  1578. /*++
  1579. Routine Description:
  1580. This routine exits the shell if the most recent simple command failed,
  1581. unless the simple command is part of a compound list inside a while, until,
  1582. or if, is part of an And-Or list, or is a pipeline with a bang.
  1583. Arguments:
  1584. Shell - Supplies a pointer to the shell containing the node.
  1585. Return Value:
  1586. None.
  1587. --*/
  1588. {
  1589. PLIST_ENTRY CurrentEntry;
  1590. PSHELL_EXECUTION_NODE ExecutionNode;
  1591. SHELL_NODE_TYPE Type;
  1592. if ((Shell->Exited != FALSE) || (Shell->ReturnValue == 0)) {
  1593. return;
  1594. }
  1595. CurrentEntry = Shell->ExecutionStack.Next;
  1596. while (CurrentEntry != &(Shell->ExecutionStack)) {
  1597. ExecutionNode = LIST_VALUE(CurrentEntry,
  1598. SHELL_EXECUTION_NODE,
  1599. ListEntry);
  1600. CurrentEntry = CurrentEntry->Next;
  1601. //
  1602. // If an if/while/until is found with the body executing, an And-Or
  1603. // is found, or a pipeline is found with a bang then don't exit, just
  1604. // return.
  1605. //
  1606. Type = ExecutionNode->Node->Type;
  1607. if (((Type == ShellNodeIf) || (Type == ShellNodeWhile) ||
  1608. (Type == ShellNodeUntil) || (Type == ShellNodeAndOr)) &&
  1609. ((ExecutionNode->Flags & SHELL_EXECUTION_BODY) == 0)) {
  1610. return;
  1611. }
  1612. if ((Type == ShellNodePipeline) &&
  1613. (ExecutionNode->Node->U.Pipeline.Bang != FALSE)) {
  1614. return;
  1615. }
  1616. }
  1617. //
  1618. // None of the conditions were met, so exit this shell.
  1619. //
  1620. Shell->Exited = TRUE;
  1621. return;
  1622. }
  1623. BOOL
  1624. ShApplyRedirections (
  1625. PSHELL Shell,
  1626. PSHELL_EXECUTION_NODE ExecutionNode
  1627. )
  1628. /*++
  1629. Routine Description:
  1630. This routine applies any redirections to the current command.
  1631. Arguments:
  1632. Shell - Supplies a pointer to the shell.
  1633. ExecutionNode - Supplies a pointer to the execution node to apply
  1634. redirections of.
  1635. Return Value:
  1636. TRUE on success.
  1637. --*/
  1638. {
  1639. PSHELL_ACTIVE_REDIRECT ActiveRedirect;
  1640. PSTR AfterScan;
  1641. PLIST_ENTRY CurrentEntry;
  1642. PSTR DocumentText;
  1643. UINTN DocumentTextSize;
  1644. PSTR ExpandedFileName;
  1645. UINTN ExpandedFileNameSize;
  1646. PSTR ExpandedString;
  1647. UINTN ExpandedStringSize;
  1648. PSHELL_HERE_DOCUMENT HereDocument;
  1649. INT NewDescriptor;
  1650. INT NewDescriptorAnywhere;
  1651. INT OpenFlags;
  1652. ULONG Options;
  1653. INT OriginalDescriptor;
  1654. unsigned long PathSize;
  1655. INT Pipe[2];
  1656. PSHELL_IO_REDIRECT Redirect;
  1657. BOOL Result;
  1658. INT SourceFileNumber;
  1659. SHELL_IO_REDIRECTION_TYPE Type;
  1660. INT WriteCopy;
  1661. ActiveRedirect = NULL;
  1662. ExpandedFileName = NULL;
  1663. ExpandedFileNameSize = 0;
  1664. ExpandedString = NULL;
  1665. Pipe[0] = -1;
  1666. Pipe[1] = -1;
  1667. //
  1668. // Loop through all the redirections.
  1669. //
  1670. CurrentEntry = ExecutionNode->Node->RedirectList.Next;
  1671. while (CurrentEntry != &(ExecutionNode->Node->RedirectList)) {
  1672. Redirect = LIST_VALUE(CurrentEntry, SHELL_IO_REDIRECT, ListEntry);
  1673. CurrentEntry = CurrentEntry->Next;
  1674. Type = Redirect->Type;
  1675. //
  1676. // Allocate an active redirect entry.
  1677. //
  1678. ActiveRedirect = malloc(sizeof(SHELL_ACTIVE_REDIRECT));
  1679. if (ActiveRedirect == NULL) {
  1680. Result = FALSE;
  1681. goto ApplyRedirectionsEnd;
  1682. }
  1683. ActiveRedirect->ChildProcessId = -1;
  1684. //
  1685. // Expand the file name.
  1686. //
  1687. if (Redirect->FileName != NULL) {
  1688. Options = SHELL_EXPANSION_OPTION_NO_FIELD_SPLIT;
  1689. Result = ShPerformExpansions(Shell,
  1690. Redirect->FileName,
  1691. Redirect->FileNameSize,
  1692. Options,
  1693. &ExpandedFileName,
  1694. &ExpandedFileNameSize,
  1695. NULL,
  1696. NULL);
  1697. if (Result == FALSE) {
  1698. goto ApplyRedirectionsEnd;
  1699. }
  1700. //
  1701. // Let the OS layer play with the path if it wants.
  1702. //
  1703. PathSize = ExpandedFileNameSize;
  1704. Result = ShFixUpPath(&ExpandedFileName, &PathSize);
  1705. if (Result == FALSE) {
  1706. goto ApplyRedirectionsEnd;
  1707. }
  1708. }
  1709. //
  1710. // Perform normal file redirections.
  1711. //
  1712. if ((Type == ShellRedirectRead) ||
  1713. (Type == ShellRedirectWrite) ||
  1714. (Type == ShellRedirectAppend) ||
  1715. (Type == ShellRedirectReadWrite) ||
  1716. (Type == ShellRedirectClobber)) {
  1717. OpenFlags = O_CREAT | O_BINARY;
  1718. if ((Shell->Options & SHELL_OPTION_NO_CLOBBER) != 0) {
  1719. OpenFlags |= O_EXCL;
  1720. }
  1721. if (Type == ShellRedirectRead) {
  1722. OpenFlags |= O_RDONLY;
  1723. OpenFlags &= ~(O_CREAT | O_EXCL);
  1724. } else if (Type == ShellRedirectWrite) {
  1725. OpenFlags |= O_WRONLY | O_TRUNC;
  1726. } else if (Type == ShellRedirectAppend) {
  1727. OpenFlags |= O_WRONLY | O_APPEND;
  1728. } else if (Type == ShellRedirectReadWrite) {
  1729. OpenFlags |= O_RDWR;
  1730. } else if (Type == ShellRedirectClobber) {
  1731. OpenFlags |= O_WRONLY | O_TRUNC;
  1732. OpenFlags &= ~O_EXCL;
  1733. }
  1734. //
  1735. // Open up the file.
  1736. //
  1737. NewDescriptorAnywhere = open(ExpandedFileName,
  1738. OpenFlags,
  1739. SHELL_FILE_CREATION_MASK);
  1740. if (NewDescriptorAnywhere < 0) {
  1741. PRINT_ERROR("sh: Unable to open redirection file %s: %s.\n",
  1742. ExpandedFileName,
  1743. strerror(errno));
  1744. Result = FALSE;
  1745. goto ApplyRedirectionsEnd;
  1746. }
  1747. //
  1748. // Copy the original descriptor somewhere, then close the
  1749. // descriptor and copy the newly opened file into it.
  1750. //
  1751. OriginalDescriptor = ShDup(Shell, Redirect->FileNumber, FALSE);
  1752. if (NewDescriptorAnywhere != Redirect->FileNumber) {
  1753. NewDescriptor = ShDup2(Shell,
  1754. NewDescriptorAnywhere,
  1755. Redirect->FileNumber);
  1756. if (NewDescriptor < 0) {
  1757. Result = FALSE;
  1758. goto ApplyRedirectionsEnd;
  1759. }
  1760. ShClose(Shell, NewDescriptorAnywhere);
  1761. }
  1762. //
  1763. // Perform redirections from other file descriptors.
  1764. //
  1765. } else if ((Type == ShellRedirectReadFromDescriptor) ||
  1766. (Type == ShellRedirectWriteToDescriptor)) {
  1767. //
  1768. // If the source file number evaluates to -, then the file number is
  1769. // closed.
  1770. //
  1771. if (strcmp(ExpandedFileName, "-") == 0) {
  1772. OriginalDescriptor = ShDup(Shell, Redirect->FileNumber, FALSE);
  1773. ShClose(Shell, Redirect->FileNumber);
  1774. } else {
  1775. SourceFileNumber = strtol(ExpandedFileName, &AfterScan, 10);
  1776. if ((SourceFileNumber < 0) || (AfterScan == ExpandedFileName)) {
  1777. PRINT_ERROR("sh: Bad file descriptor number '%s'.",
  1778. ExpandedFileName);
  1779. Result = FALSE;
  1780. goto ApplyRedirectionsEnd;
  1781. }
  1782. //
  1783. // Copy the original descriptor, then close the destination and
  1784. // copy the source in there.
  1785. //
  1786. OriginalDescriptor = ShDup(Shell, Redirect->FileNumber, FALSE);
  1787. if (Redirect->FileNumber != SourceFileNumber) {
  1788. NewDescriptor = ShDup2(Shell,
  1789. SourceFileNumber,
  1790. Redirect->FileNumber);
  1791. if (NewDescriptor < 0) {
  1792. PRINT_ERROR("sh: Unable to duplicate file %d.\n",
  1793. SourceFileNumber);
  1794. Result = FALSE;
  1795. goto ApplyRedirectionsEnd;
  1796. }
  1797. }
  1798. }
  1799. //
  1800. // Perform a redirection from a here document.
  1801. //
  1802. } else if ((Type == ShellRedirectHereDocument) ||
  1803. (Type == ShellRedirectStrippedHereDocument)) {
  1804. HereDocument = Redirect->HereDocument;
  1805. DocumentText = HereDocument->Document;
  1806. DocumentTextSize = HereDocument->DocumentSize;
  1807. //
  1808. // Perform expansions on the here document.
  1809. //
  1810. if (Redirect->HereDocument->EndWordWasQuoted == FALSE) {
  1811. Options = SHELL_EXPANSION_OPTION_NO_TILDE_EXPANSION |
  1812. SHELL_EXPANSION_OPTION_NO_FIELD_SPLIT;
  1813. Result = ShPerformExpansions(Shell,
  1814. DocumentText,
  1815. DocumentTextSize,
  1816. Options,
  1817. &ExpandedString,
  1818. &ExpandedStringSize,
  1819. NULL,
  1820. NULL);
  1821. if (Result == FALSE) {
  1822. goto ApplyRedirectionsEnd;
  1823. }
  1824. DocumentText = ExpandedString;
  1825. DocumentTextSize = ExpandedStringSize;
  1826. }
  1827. //
  1828. // Create a pipe for the here document and wire up the file
  1829. // descriptor to the read end of the pipe.
  1830. //
  1831. Result = ShCreatePipe(Pipe);
  1832. if (Result == FALSE) {
  1833. goto ApplyRedirectionsEnd;
  1834. }
  1835. OriginalDescriptor = ShDup(Shell, Redirect->FileNumber, FALSE);
  1836. if (OriginalDescriptor == -1) {
  1837. Result = FALSE;
  1838. goto ApplyRedirectionsEnd;
  1839. }
  1840. //
  1841. // Copy the write descriptor out of range of the shell standard
  1842. // descriptors, since on Windows the write side is just a thread,
  1843. // so it stays open.
  1844. //
  1845. if (SwForkSupported == 0) {
  1846. WriteCopy = ShDup(Shell, Pipe[1], 0);
  1847. ShClose(Shell, Pipe[1]);
  1848. Pipe[1] = WriteCopy;
  1849. }
  1850. //
  1851. // Launch the subprocess or thread to feed the document text into
  1852. // the descriptor.
  1853. //
  1854. assert(DocumentTextSize != 0);
  1855. DocumentTextSize -= 1;
  1856. Result = ShPushInputText(DocumentText, DocumentTextSize, Pipe);
  1857. if (Result < 0) {
  1858. goto ApplyRedirectionsEnd;
  1859. }
  1860. Pipe[1] = -1;
  1861. ShDup2(Shell, Pipe[0], Redirect->FileNumber);
  1862. ShClose(Shell, Pipe[0]);
  1863. Pipe[0] = -1;
  1864. if (Result > 0) {
  1865. ActiveRedirect->ChildProcessId = Result;
  1866. }
  1867. } else {
  1868. assert(FALSE);
  1869. Result = FALSE;
  1870. goto ApplyRedirectionsEnd;
  1871. }
  1872. if (Redirect->FileNumber == STDOUT_FILENO) {
  1873. fflush(stdout);
  1874. } else if (Redirect->FileNumber == STDERR_FILENO) {
  1875. fflush(stderr);
  1876. }
  1877. //
  1878. // Initialize the active redirect so that the original descriptor can
  1879. // be restored.
  1880. //
  1881. ActiveRedirect->FileNumber = Redirect->FileNumber;
  1882. ActiveRedirect->OriginalDescriptor = OriginalDescriptor;
  1883. INSERT_BEFORE(&(ActiveRedirect->ListEntry),
  1884. &(ExecutionNode->ActiveRedirectList));
  1885. ActiveRedirect = NULL;
  1886. //
  1887. // Free the expanded file name.
  1888. //
  1889. if (ExpandedFileName != NULL) {
  1890. free(ExpandedFileName);
  1891. ExpandedFileName = NULL;
  1892. }
  1893. }
  1894. Result = TRUE;
  1895. ApplyRedirectionsEnd:
  1896. if (Pipe[0] != -1) {
  1897. ShClose(Shell, Pipe[0]);
  1898. }
  1899. if (Pipe[1] != -1) {
  1900. ShClose(Shell, Pipe[1]);
  1901. }
  1902. if (ExpandedString != NULL) {
  1903. free(ExpandedString);
  1904. }
  1905. if (ExpandedFileName != NULL) {
  1906. free(ExpandedFileName);
  1907. }
  1908. if (Result == FALSE) {
  1909. if (ActiveRedirect != NULL) {
  1910. free(ActiveRedirect);
  1911. }
  1912. }
  1913. return Result;
  1914. }