1
0

builtin.c 67 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. builtin.c
  5. Abstract:
  6. This module implements support for the builtin shell utilities.
  7. Author:
  8. Evan Green 20-Aug-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 <ctype.h>
  20. #include <errno.h>
  21. #include <fcntl.h>
  22. #include <getopt.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <unistd.h>
  26. #include "../swlib.h"
  27. //
  28. // --------------------------------------------------------------------- Macros
  29. //
  30. //
  31. // This macro returns non-zero if the given node type is a for, while, or until
  32. // loop.
  33. //
  34. #define SHELL_LOOP_NODE(_NodeType) \
  35. (((_NodeType) == ShellNodeFor) || ((_NodeType) == ShellNodeWhile) || \
  36. ((_NodeType) == ShellNodeUntil))
  37. //
  38. // ---------------------------------------------------------------- Definitions
  39. //
  40. #define SHELL_READ_INITIAL_STRING_SIZE 32
  41. #define SHELL_MAX_OPTION_INDEX_LENGTH 12
  42. #define RUBOUT_CHARACTER 0x7F
  43. //
  44. // Define the default builtin path used by the command builtin.
  45. //
  46. #define SHELL_COMMAND_BUILTIN_PATH "/bin:/usr/bin:/usr/local/bin"
  47. //
  48. // ------------------------------------------------------ Data Type Definitions
  49. //
  50. //
  51. // ----------------------------------------------- Internal Function Prototypes
  52. //
  53. INT
  54. ShBuiltinBreak (
  55. PSHELL Shell,
  56. INT ArgumentCount,
  57. PSTR *Arguments
  58. );
  59. INT
  60. ShBuiltinContinue (
  61. PSHELL Shell,
  62. INT ArgumentCount,
  63. PSTR *Arguments
  64. );
  65. INT
  66. ShBuiltinReturn (
  67. PSHELL Shell,
  68. INT ArgumentCount,
  69. PSTR *Arguments
  70. );
  71. INT
  72. ShBuiltinExit (
  73. PSHELL Shell,
  74. INT ArgumentCount,
  75. PSTR *Arguments
  76. );
  77. INT
  78. ShBuiltinBreakOrContinue (
  79. PSHELL Shell,
  80. INT ArgumentCount,
  81. PSTR *Arguments,
  82. BOOL Break
  83. );
  84. INT
  85. ShBuiltinReturnOrExit (
  86. PSHELL Shell,
  87. INT ArgumentCount,
  88. PSTR *Arguments,
  89. BOOL Exit
  90. );
  91. INT
  92. ShBuiltinNop (
  93. PSHELL Shell,
  94. INT ArgumentCount,
  95. PSTR *Arguments
  96. );
  97. INT
  98. ShBuiltinFalse (
  99. PSHELL Shell,
  100. INT ArgumentCount,
  101. PSTR *Arguments
  102. );
  103. INT
  104. ShBuiltinDot (
  105. PSHELL Shell,
  106. INT ArgumentCount,
  107. PSTR *Arguments
  108. );
  109. INT
  110. ShBuiltinExec (
  111. PSHELL Shell,
  112. INT ArgumentCount,
  113. PSTR *Arguments
  114. );
  115. INT
  116. ShBuiltinRead (
  117. PSHELL Shell,
  118. INT ArgumentCount,
  119. PSTR *Arguments
  120. );
  121. INT
  122. ShBuiltinShift (
  123. PSHELL Shell,
  124. INT ArgumentCount,
  125. PSTR *Arguments
  126. );
  127. INT
  128. ShBuiltinTimes (
  129. PSHELL Shell,
  130. INT ArgumentCount,
  131. PSTR *Arguments
  132. );
  133. INT
  134. ShBuiltinUmask (
  135. PSHELL Shell,
  136. INT ArgumentCount,
  137. PSTR *Arguments
  138. );
  139. INT
  140. ShBuiltinGetopts (
  141. PSHELL Shell,
  142. INT ArgumentCount,
  143. PSTR *Arguments
  144. );
  145. INT
  146. ShBuiltinCommand (
  147. PSHELL Shell,
  148. INT ArgumentCount,
  149. PSTR *Arguments
  150. );
  151. INT
  152. ShBuiltinType (
  153. PSHELL Shell,
  154. INT ArgumentCount,
  155. PSTR *Arguments
  156. );
  157. INT
  158. ShBuiltinTypeOrCommand (
  159. PSHELL Shell,
  160. INT ArgumentCount,
  161. PSTR *Arguments,
  162. BOOL IsType
  163. );
  164. INT
  165. ShClassifyCommand (
  166. PSHELL Shell,
  167. PSTR Command,
  168. BOOL Verbose
  169. );
  170. INT
  171. ShGetNextOption (
  172. PSHELL Shell,
  173. ULONG ArgumentCount,
  174. PSTR *Arguments,
  175. PINT ArgumentIndex,
  176. PSTR Options,
  177. PCHAR Option,
  178. PSTR *OptionArgument,
  179. PBOOL EndOfOptions
  180. );
  181. //
  182. // -------------------------------------------------------------------- Globals
  183. //
  184. //
  185. // Stores the expected index for the next call to the built-in option
  186. // processing.
  187. //
  188. INT ShOptionsIndex;
  189. //
  190. // Stores the string index of the next option character to process.
  191. //
  192. ULONG ShNextOptionCharacter;
  193. //
  194. // Stores whether or not a "--" end of arguments marker has been seen by the
  195. // built-in get options command.
  196. //
  197. BOOL ShSeenDoubleDash;
  198. //
  199. // Define the shell reserved keywords.
  200. //
  201. PSTR ShReservedWords[] = {
  202. "if",
  203. "then",
  204. "else",
  205. "elif",
  206. "fi",
  207. "do",
  208. "done",
  209. "case",
  210. "esac",
  211. "while",
  212. "until",
  213. "for",
  214. "{",
  215. "}",
  216. "!",
  217. "in",
  218. NULL
  219. };
  220. //
  221. // ------------------------------------------------------------------ Functions
  222. //
  223. PSHELL_BUILTIN_COMMAND
  224. ShIsBuiltinCommand (
  225. PSTR Command
  226. )
  227. /*++
  228. Routine Description:
  229. This routine determines if the given command name is a built in command,
  230. and returns a pointer to the command function if it is.
  231. Arguments:
  232. Command - Supplies the null terminated string of the command.
  233. Return Value:
  234. Returns a pointer to the command entry point function if the given string
  235. is a built-in command.
  236. NULL if the command is not a built-in command.
  237. --*/
  238. {
  239. PSHELL_BUILTIN_COMMAND EntryPoint;
  240. EntryPoint = NULL;
  241. switch (*Command) {
  242. case ':':
  243. if (*(Command + 1) == '\0') {
  244. EntryPoint = ShBuiltinNop;
  245. }
  246. break;
  247. case 'a':
  248. if (strcmp(Command + 1, "lias") == 0) {
  249. EntryPoint = ShBuiltinAlias;
  250. }
  251. break;
  252. case 'b':
  253. if (strcmp(Command + 1, "reak") == 0) {
  254. EntryPoint = ShBuiltinBreak;
  255. }
  256. break;
  257. case 'c':
  258. if (strcmp(Command + 1, "d") == 0) {
  259. EntryPoint = ShBuiltinCd;
  260. } else if (strcmp(Command + 1, "ommand") == 0) {
  261. EntryPoint = ShBuiltinCommand;
  262. } else if (strcmp(Command + 1, "ontinue") == 0) {
  263. EntryPoint = ShBuiltinContinue;
  264. }
  265. break;
  266. case '.':
  267. if (*(Command + 1) == '\0') {
  268. EntryPoint = ShBuiltinDot;
  269. }
  270. break;
  271. case 'e':
  272. if (strcmp(Command + 1, "val") == 0) {
  273. EntryPoint = ShBuiltinEval;
  274. } else if (strcmp(Command + 1, "xec") == 0) {
  275. EntryPoint = ShBuiltinExec;
  276. } else if (strcmp(Command + 1, "xit") == 0) {
  277. EntryPoint = ShBuiltinExit;
  278. } else if (strcmp(Command + 1, "xport") == 0) {
  279. EntryPoint = ShBuiltinExport;
  280. }
  281. break;
  282. case 'f':
  283. if (strcmp(Command + 1, "alse") == 0) {
  284. EntryPoint = ShBuiltinFalse;
  285. }
  286. break;
  287. case 'g':
  288. if (strcmp(Command + 1, "etopts") == 0) {
  289. EntryPoint = ShBuiltinGetopts;
  290. }
  291. break;
  292. case 'l':
  293. if (strcmp(Command + 1, "ocal") == 0) {
  294. EntryPoint = ShBuiltinLocal;
  295. }
  296. break;
  297. case 'p':
  298. if (strcmp(Command + 1, "wd") == 0) {
  299. EntryPoint = ShBuiltinPwd;
  300. }
  301. break;
  302. case 'r':
  303. if (strcmp(Command + 1, "ead") == 0) {
  304. EntryPoint = ShBuiltinRead;
  305. } else if (strcmp(Command + 1, "eadonly") == 0) {
  306. EntryPoint = ShBuiltinReadOnly;
  307. } else if (strcmp(Command + 1, "eturn") == 0) {
  308. EntryPoint = ShBuiltinReturn;
  309. }
  310. break;
  311. case 's':
  312. if (strcmp(Command + 1, "et") == 0) {
  313. EntryPoint = ShBuiltinSet;
  314. } else if (strcmp(Command + 1, "hift") == 0) {
  315. EntryPoint = ShBuiltinShift;
  316. }
  317. break;
  318. case 't':
  319. if (strcmp(Command + 1, "imes") == 0) {
  320. EntryPoint = ShBuiltinTimes;
  321. } else if (strcmp(Command + 1, "rap") == 0) {
  322. EntryPoint = ShBuiltinTrap;
  323. } else if (strcmp(Command + 1, "rue") == 0) {
  324. EntryPoint = ShBuiltinNop;
  325. } else if (strcmp(Command + 1, "ype") == 0) {
  326. EntryPoint = ShBuiltinType;
  327. }
  328. break;
  329. case 'u':
  330. if (strcmp(Command + 1, "mask") == 0) {
  331. EntryPoint = ShBuiltinUmask;
  332. } else if (strcmp(Command + 1, "nalias") == 0) {
  333. EntryPoint = ShBuiltinUnalias;
  334. } else if (strcmp(Command + 1, "nset") == 0) {
  335. EntryPoint = ShBuiltinUnset;
  336. }
  337. break;
  338. default:
  339. break;
  340. }
  341. return EntryPoint;
  342. }
  343. INT
  344. ShRunBuiltinCommand (
  345. PSHELL Shell,
  346. PSHELL_BUILTIN_COMMAND Command,
  347. INT ArgumentCount,
  348. PSTR *Arguments
  349. )
  350. /*++
  351. Routine Description:
  352. This routine runs a shell builtin command.
  353. Arguments:
  354. Shell - Supplies a pointer to the shell.
  355. Command - Supplies a pointer to the command function to run.
  356. ArgumentCount - Supplies the number of arguments on the command line.
  357. Arguments - Supplies the array of pointers to strings representing each
  358. argument. Arguments can be -v to unset a variable (the default), or -f
  359. to unset a function. This is followed by the variable or function name.
  360. Return Value:
  361. 0 on success.
  362. 1 on failure.
  363. --*/
  364. {
  365. INT Result;
  366. //
  367. // Run the command.
  368. //
  369. Result = Command(Shell, ArgumentCount, Arguments);
  370. fflush(NULL);
  371. return Result;
  372. }
  373. INT
  374. ShBuiltinEval (
  375. PSHELL Shell,
  376. INT ArgumentCount,
  377. PSTR *Arguments
  378. )
  379. /*++
  380. Routine Description:
  381. This routine implements the eval command, which collects all the parameters
  382. together separated by spaces and reexecutes them in the shell.
  383. Arguments:
  384. Shell - Supplies a pointer to the shell.
  385. ArgumentCount - Supplies the number of arguments on the command line.
  386. Arguments - Supplies the array of pointers to strings representing each
  387. argument. Arguments can be -v to unset a variable (the default), or -f
  388. to unset a function. This is followed by the variable or function name.
  389. Return Value:
  390. Returns the return value of the command it executes.
  391. --*/
  392. {
  393. INT ArgumentIndex;
  394. UINTN ArgumentSize;
  395. PSTR Input;
  396. UINTN InputIndex;
  397. UINTN InputSize;
  398. ULONG OldOptions;
  399. SHELL_LEXER_STATE OriginalLexer;
  400. BOOL Result;
  401. INT ReturnValue;
  402. Input = NULL;
  403. if (ArgumentCount < 2) {
  404. return 0;
  405. }
  406. //
  407. // Loop through once to figure out how big the input buffer needs to be.
  408. //
  409. InputSize = 0;
  410. for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
  411. ArgumentSize = strlen(Arguments[ArgumentIndex]);
  412. if (ArgumentSize == 0) {
  413. continue;
  414. }
  415. InputSize += ArgumentSize + 1;
  416. }
  417. if (InputSize == 0) {
  418. return 0;
  419. }
  420. //
  421. // Create the buffer consisting of all the strings separated by spaces.
  422. //
  423. Input = malloc(InputSize);
  424. if (Input == NULL) {
  425. ReturnValue = ENOMEM;
  426. goto BuiltinEvalEnd;
  427. }
  428. InputIndex = 0;
  429. for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
  430. ArgumentSize = strlen(Arguments[ArgumentIndex]);
  431. if (ArgumentSize == 0) {
  432. continue;
  433. }
  434. memcpy(Input + InputIndex, Arguments[ArgumentIndex], ArgumentSize);
  435. InputIndex += ArgumentSize;
  436. if (ArgumentIndex == ArgumentCount - 1) {
  437. Input[InputIndex] = '\0';
  438. } else {
  439. Input[InputIndex] = ' ';
  440. }
  441. InputIndex += 1;
  442. }
  443. assert(InputIndex == InputSize);
  444. //
  445. // Save the original lexer and re-initialize the lexer for this new file.
  446. //
  447. memcpy(&OriginalLexer, &(Shell->Lexer), sizeof(SHELL_LEXER_STATE));
  448. Result = ShInitializeLexer(&(Shell->Lexer), NULL, Input, InputSize);
  449. if (Result == FALSE) {
  450. memcpy(&(Shell->Lexer), &OriginalLexer, sizeof(SHELL_LEXER_STATE));
  451. goto BuiltinEvalEnd;
  452. }
  453. OldOptions = Shell->Options;
  454. Shell->Options &= ~SHELL_OPTION_PRINT_PROMPTS;
  455. Shell->Options |= SHELL_OPTION_INPUT_BUFFER_ONLY;
  456. //
  457. // Run the commands.
  458. //
  459. Result = ShExecute(Shell, &ReturnValue);
  460. //
  461. // Turn the print prompts flag back on if it was set before.
  462. //
  463. Shell->Options &= ~SHELL_OPTION_INPUT_BUFFER_ONLY;
  464. Shell->Options |= OldOptions &
  465. (SHELL_OPTION_PRINT_PROMPTS |
  466. SHELL_OPTION_INPUT_BUFFER_ONLY);
  467. //
  468. // Restore the original lexer.
  469. //
  470. ShDestroyLexer(&(Shell->Lexer));
  471. memcpy(&(Shell->Lexer), &OriginalLexer, sizeof(SHELL_LEXER_STATE));
  472. if ((Result == FALSE) && (ReturnValue == 0)) {
  473. ReturnValue = 1;
  474. }
  475. BuiltinEvalEnd:
  476. if (Input != NULL) {
  477. free(Input);
  478. }
  479. return ReturnValue;
  480. }
  481. //
  482. // --------------------------------------------------------- Internal Functions
  483. //
  484. INT
  485. ShBuiltinBreak (
  486. PSHELL Shell,
  487. INT ArgumentCount,
  488. PSTR *Arguments
  489. )
  490. /*++
  491. Routine Description:
  492. This routine implements the builtin break statement.
  493. Arguments:
  494. Shell - Supplies a pointer to the shell being run in.
  495. ArgumentCount - Supplies the number of arguments on the command line.
  496. Arguments - Supplies the array of pointers to strings representing each
  497. argument.
  498. Return Value:
  499. Returns the integer return value from the built-in command, which will be
  500. placed in the node on top of the execution stack. This may not be the node
  501. that executed this command, as this command may have popped things off the
  502. execution stack (such as a return, break, or continue will do).
  503. --*/
  504. {
  505. return ShBuiltinBreakOrContinue(Shell, ArgumentCount, Arguments, TRUE);
  506. }
  507. INT
  508. ShBuiltinContinue (
  509. PSHELL Shell,
  510. INT ArgumentCount,
  511. PSTR *Arguments
  512. )
  513. /*++
  514. Routine Description:
  515. This routine implements the builtin break statement.
  516. Arguments:
  517. Shell - Supplies a pointer to the shell being run in.
  518. ArgumentCount - Supplies the number of arguments on the command line.
  519. Arguments - Supplies the array of pointers to strings representing each
  520. argument.
  521. Return Value:
  522. Returns the integer return value from the built-in command, which will be
  523. placed in the node on top of the execution stack. This may not be the node
  524. that executed this command, as this command may have popped things off the
  525. execution stack (such as a return, break, or continue will do).
  526. --*/
  527. {
  528. return ShBuiltinBreakOrContinue(Shell, ArgumentCount, Arguments, FALSE);
  529. }
  530. INT
  531. ShBuiltinReturn (
  532. PSHELL Shell,
  533. INT ArgumentCount,
  534. PSTR *Arguments
  535. )
  536. /*++
  537. Routine Description:
  538. This routine implements the builtin return statement.
  539. Arguments:
  540. Shell - Supplies a pointer to the shell being run in.
  541. ArgumentCount - Supplies the number of arguments on the command line.
  542. Arguments - Supplies the array of pointers to strings representing each
  543. argument.
  544. Return Value:
  545. Returns the integer return value from the built-in command, which will be
  546. placed in the node on top of the execution stack. This may not be the node
  547. that executed this command, as this command may have popped things off the
  548. execution stack (such as a return, break, or continue will do).
  549. --*/
  550. {
  551. return ShBuiltinReturnOrExit(Shell, ArgumentCount, Arguments, FALSE);
  552. }
  553. INT
  554. ShBuiltinExit (
  555. PSHELL Shell,
  556. INT ArgumentCount,
  557. PSTR *Arguments
  558. )
  559. /*++
  560. Routine Description:
  561. This routine implements the builtin exit statement.
  562. Arguments:
  563. Shell - Supplies a pointer to the shell being run in.
  564. ArgumentCount - Supplies the number of arguments on the command line.
  565. Arguments - Supplies the array of pointers to strings representing each
  566. argument.
  567. Return Value:
  568. Returns the integer return value from the built-in command, which will be
  569. placed in the node on top of the execution stack. This may not be the node
  570. that executed this command, as this command may have popped things off the
  571. execution stack (such as a return, break, or continue will do).
  572. --*/
  573. {
  574. return ShBuiltinReturnOrExit(Shell, ArgumentCount, Arguments, TRUE);
  575. }
  576. INT
  577. ShBuiltinBreakOrContinue (
  578. PSHELL Shell,
  579. INT ArgumentCount,
  580. PSTR *Arguments,
  581. BOOL Break
  582. )
  583. /*++
  584. Routine Description:
  585. This routine implements the guts of the built in break and continue
  586. statements.
  587. Arguments:
  588. Shell - Supplies a pointer to the shell being run in.
  589. ArgumentCount - Supplies the number of arguments on the command line.
  590. Arguments - Supplies the array of pointers to strings representing each
  591. argument.
  592. Break - Supplies a boolean indicating if this is a break command (TRUE) or
  593. a continue command (FALSE).
  594. Return Value:
  595. Returns the integer return value from the built-in command, which will be
  596. placed in the node on top of the execution stack. This may not be the node
  597. that executed this command, as this command may have popped things off the
  598. execution stack (such as a return, break, or continue will do).
  599. --*/
  600. {
  601. PSTR AfterScan;
  602. PLIST_ENTRY CurrentEntry;
  603. PSHELL_EXECUTION_NODE DestinationLoop;
  604. ULONG LoopCount;
  605. PSHELL_EXECUTION_NODE Node;
  606. //
  607. // Get the argument to how many loops to exit if there is one.
  608. //
  609. LoopCount = 1;
  610. if (ArgumentCount > 2) {
  611. return 1;
  612. } else if (ArgumentCount == 2) {
  613. LoopCount = strtoul(Arguments[1], &AfterScan, 10);
  614. if ((LoopCount < 1) || (*AfterScan != '\0')) {
  615. PRINT_ERROR("sh: break: Invalid count\n");
  616. return 1;
  617. }
  618. }
  619. assert(LoopCount >= 1);
  620. if (LIST_EMPTY(&(Shell->ExecutionStack)) != FALSE) {
  621. return 0;
  622. }
  623. //
  624. // Get the node corresponding to loop N, or if loop N is greater than the
  625. // number of loops, then just get the outermost loop.
  626. //
  627. DestinationLoop = NULL;
  628. CurrentEntry = Shell->ExecutionStack.Next;
  629. while (CurrentEntry != &(Shell->ExecutionStack)) {
  630. Node = LIST_VALUE(CurrentEntry, SHELL_EXECUTION_NODE, ListEntry);
  631. CurrentEntry = CurrentEntry->Next;
  632. if (SHELL_LOOP_NODE(Node->Node->Type)) {
  633. DestinationLoop = Node;
  634. LoopCount -= 1;
  635. if (LoopCount == 0) {
  636. break;
  637. }
  638. }
  639. }
  640. //
  641. // If there were no loops on the whole stack, then just return happily.
  642. //
  643. if (DestinationLoop == NULL) {
  644. return 0;
  645. }
  646. //
  647. // Remove nodes up until the destination loop.
  648. //
  649. CurrentEntry = Shell->ExecutionStack.Next;
  650. CurrentEntry = Shell->ExecutionStack.Next;
  651. while (CurrentEntry != &(Shell->ExecutionStack)) {
  652. Node = LIST_VALUE(CurrentEntry, SHELL_EXECUTION_NODE, ListEntry);
  653. CurrentEntry = CurrentEntry->Next;
  654. //
  655. // If this is the destination node, it's removed for breaks, but not
  656. // for continues.
  657. //
  658. if (Node == DestinationLoop) {
  659. if (Break == FALSE) {
  660. break;
  661. }
  662. }
  663. //
  664. // Don't worry about freeing the node, as all the functions on this
  665. // execution stack are also on the real stack. They'll notice they
  666. // were removed and return immediately.
  667. //
  668. LIST_REMOVE(&(Node->ListEntry));
  669. Node->ListEntry.Next = NULL;
  670. //
  671. // Stop if this is the destination node.
  672. //
  673. if (Node == DestinationLoop) {
  674. break;
  675. }
  676. }
  677. return 0;
  678. }
  679. INT
  680. ShBuiltinReturnOrExit (
  681. PSHELL Shell,
  682. INT ArgumentCount,
  683. PSTR *Arguments,
  684. BOOL Exit
  685. )
  686. /*++
  687. Routine Description:
  688. This routine implements the return and exit functions.
  689. Arguments:
  690. Shell - Supplies a pointer to the shell being run in.
  691. ArgumentCount - Supplies the number of arguments on the command line.
  692. Arguments - Supplies the array of pointers to strings representing each
  693. argument.
  694. Exit - Supplies a boolean indicating if this is an exit command (TRUE) or
  695. a return command (FALSE).
  696. Return Value:
  697. Returns the integer return value from the built-in command, which will be
  698. placed in the node on top of the execution stack. This may not be the node
  699. that executed this command, as this command may have popped things off the
  700. execution stack (such as a return, break, or continue will do).
  701. --*/
  702. {
  703. PSTR AfterScan;
  704. PLIST_ENTRY CurrentEntry;
  705. PSHELL_EXECUTION_NODE Node;
  706. LONG ReturnValue;
  707. //
  708. // Get the return value argument if there is one.
  709. //
  710. ReturnValue = Shell->LastReturnValue;
  711. if (ArgumentCount >= 2) {
  712. ReturnValue = strtoul(Arguments[1], &AfterScan, 10);
  713. if (*AfterScan != '\0') {
  714. PRINT_ERROR("sh: return: invalid argument '%s'\n", Arguments[1]);
  715. ReturnValue = Shell->LastReturnValue;
  716. }
  717. }
  718. if (LIST_EMPTY(&(Shell->ExecutionStack)) != FALSE) {
  719. return ReturnValue;
  720. }
  721. //
  722. // Remove nodes up until either the first function for return statements or
  723. // until there are none for exit statements.
  724. //
  725. CurrentEntry = Shell->ExecutionStack.Next;
  726. CurrentEntry = Shell->ExecutionStack.Next;
  727. while (CurrentEntry != &(Shell->ExecutionStack)) {
  728. Node = LIST_VALUE(CurrentEntry, SHELL_EXECUTION_NODE, ListEntry);
  729. CurrentEntry = CurrentEntry->Next;
  730. LIST_REMOVE(&(Node->ListEntry));
  731. Node->ListEntry.Next = NULL;
  732. //
  733. // If this was an executing function and it's a return statement, then
  734. // stop here.
  735. //
  736. if ((Exit == FALSE) && (Node->Node->Type == ShellNodeFunction) &&
  737. ((Node->Flags & SHELL_EXECUTION_BODY) != 0)) {
  738. break;
  739. }
  740. }
  741. if (Exit != FALSE) {
  742. Shell->Exited = TRUE;
  743. }
  744. return ReturnValue;
  745. }
  746. INT
  747. ShBuiltinNop (
  748. PSHELL Shell,
  749. INT ArgumentCount,
  750. PSTR *Arguments
  751. )
  752. /*++
  753. Routine Description:
  754. This routine implements the no-op colon (:) command. It also doubles as the
  755. true command.
  756. Arguments:
  757. Shell - Supplies a pointer to the shell being run in.
  758. ArgumentCount - Supplies the number of arguments on the command line.
  759. Arguments - Supplies the array of pointers to strings representing each
  760. argument.
  761. Return Value:
  762. 0 always.
  763. --*/
  764. {
  765. return 0;
  766. }
  767. INT
  768. ShBuiltinFalse (
  769. PSHELL Shell,
  770. INT ArgumentCount,
  771. PSTR *Arguments
  772. )
  773. /*++
  774. Routine Description:
  775. This routine implements the builtin false command, which just fails
  776. everything.
  777. Arguments:
  778. Shell - Supplies a pointer to the shell being run in.
  779. ArgumentCount - Supplies the number of arguments on the command line.
  780. Arguments - Supplies the array of pointers to strings representing each
  781. argument.
  782. Return Value:
  783. 1 always.
  784. --*/
  785. {
  786. return 1;
  787. }
  788. INT
  789. ShBuiltinDot (
  790. PSHELL Shell,
  791. INT ArgumentCount,
  792. PSTR *Arguments
  793. )
  794. /*++
  795. Routine Description:
  796. This routine implements the dot command, which executes commands from the
  797. given file in the current environment.
  798. Arguments:
  799. Shell - Supplies a pointer to the shell being run in.
  800. ArgumentCount - Supplies the number of arguments on the command line.
  801. Arguments - Supplies the array of pointers to strings representing each
  802. argument. Arguments can be -v to unset a variable (the default), or -f
  803. to unset a function. This is followed by the variable or function name.
  804. Return Value:
  805. 0 always.
  806. --*/
  807. {
  808. PSTR FullCommandPath;
  809. ULONG FullCommandPathSize;
  810. FILE *NewFile;
  811. INT NewFileDescriptor;
  812. INT NewFileDescriptorHigh;
  813. SHELL_LEXER_STATE OriginalLexer;
  814. ULONG OriginalOptions;
  815. BOOL Result;
  816. INT ReturnValue;
  817. NewFile = NULL;
  818. NewFileDescriptor = -1;
  819. NewFileDescriptorHigh = -1;
  820. if (ArgumentCount < 2) {
  821. return 0;
  822. }
  823. //
  824. // Find the command.
  825. //
  826. ReturnValue = 0;
  827. Result = ShLocateCommand(Shell,
  828. Arguments[1],
  829. strlen(Arguments[1]) + 1,
  830. FALSE,
  831. &FullCommandPath,
  832. &FullCommandPathSize,
  833. &ReturnValue);
  834. if (Result == FALSE) {
  835. goto BuiltinDotEnd;
  836. }
  837. if (ReturnValue != 0) {
  838. if (ReturnValue == SHELL_ERROR_OPEN) {
  839. PRINT_ERROR("sh: %s: Command not found.\n", Arguments[1]);
  840. } else if (ReturnValue == SHELL_ERROR_EXECUTE) {
  841. PRINT_ERROR("sh: %s: Permission denied.\n", Arguments[1]);
  842. }
  843. goto BuiltinDotEnd;
  844. }
  845. //
  846. // Open up the new file to be read for commands. Make sure it's out of the
  847. // user file descriptor range.
  848. //
  849. NewFileDescriptor = open(FullCommandPath, O_RDONLY | O_BINARY);
  850. if (NewFileDescriptor < 0) {
  851. SwPrintError(errno, FullCommandPath, "Unable to open");
  852. ReturnValue = SHELL_ERROR_OPEN;
  853. goto BuiltinDotEnd;
  854. }
  855. if (NewFileDescriptor >= SHELL_MINIMUM_FILE_DESCRIPTOR) {
  856. NewFileDescriptorHigh = NewFileDescriptor;
  857. NewFileDescriptor = -1;
  858. } else {
  859. NewFileDescriptorHigh = ShDup(Shell, NewFileDescriptor, FALSE);
  860. if (NewFileDescriptorHigh < 0) {
  861. SwPrintError(errno, FullCommandPath, "Unable to dup");
  862. ReturnValue = SHELL_ERROR_OPEN;
  863. goto BuiltinDotEnd;
  864. }
  865. assert(NewFileDescriptorHigh >= SHELL_MINIMUM_FILE_DESCRIPTOR);
  866. close(NewFileDescriptor);
  867. NewFileDescriptor = -1;
  868. }
  869. NewFile = fdopen(NewFileDescriptorHigh, "rb");
  870. if (NewFile == NULL) {
  871. SwPrintError(errno, FullCommandPath, "Unable to Open");
  872. ReturnValue = SHELL_ERROR_OPEN;
  873. goto BuiltinDotEnd;
  874. }
  875. NewFileDescriptorHigh = -1;
  876. //
  877. // Save the original lexer and re-initialize the lexer for this new file.
  878. //
  879. memcpy(&OriginalLexer, &(Shell->Lexer), sizeof(SHELL_LEXER_STATE));
  880. Result = ShInitializeLexer(&(Shell->Lexer), NewFile, NULL, 0);
  881. if (Result == FALSE) {
  882. memcpy(&(Shell->Lexer), &OriginalLexer, sizeof(SHELL_LEXER_STATE));
  883. goto BuiltinDotEnd;
  884. }
  885. OriginalOptions = Shell->Options &
  886. (SHELL_OPTION_PRINT_PROMPTS |
  887. SHELL_OPTION_INTERACTIVE |
  888. SHELL_OPTION_RAW_INPUT |
  889. SHELL_OPTION_INPUT_BUFFER_ONLY);
  890. Shell->Options &= ~OriginalOptions;
  891. Shell->LastReturnValue = 0;
  892. //
  893. // Run the commands.
  894. //
  895. Result = ShExecute(Shell, &ReturnValue);
  896. Shell->Options |= OriginalOptions;
  897. //
  898. // Restore the original lexer.
  899. //
  900. ShDestroyLexer(&(Shell->Lexer));
  901. memcpy(&(Shell->Lexer), &OriginalLexer, sizeof(SHELL_LEXER_STATE));
  902. if ((Result == FALSE) && (ReturnValue == 0)) {
  903. ReturnValue = 1;
  904. }
  905. BuiltinDotEnd:
  906. if ((FullCommandPath != NULL) && (FullCommandPath != Arguments[1])) {
  907. free(FullCommandPath);
  908. }
  909. if (NewFileDescriptor >= 0) {
  910. close(NewFileDescriptor);
  911. }
  912. if (NewFileDescriptorHigh >= 0) {
  913. close(NewFileDescriptorHigh);
  914. }
  915. return ReturnValue;
  916. }
  917. INT
  918. ShBuiltinExec (
  919. PSHELL Shell,
  920. INT ArgumentCount,
  921. PSTR *Arguments
  922. )
  923. /*++
  924. Routine Description:
  925. This routine implements the exec command, which makes the current shell
  926. into the given program.
  927. Arguments:
  928. Shell - Supplies a pointer to the shell.
  929. ArgumentCount - Supplies the number of arguments on the command line.
  930. Arguments - Supplies the array of pointers to strings representing each
  931. argument. Arguments can be -v to unset a variable (the default), or -f
  932. to unset a function. This is followed by the variable or function name.
  933. Return Value:
  934. 0 if the command ran successfully. In this case the shell's exited flag
  935. will be set.
  936. Returns an error code if the app failed to launch.
  937. --*/
  938. {
  939. PSHELL_ACTIVE_REDIRECT ActiveRedirect;
  940. PSHELL_BUILTIN_COMMAND BuiltinCommand;
  941. PSHELL_EXECUTION_NODE ExecutionNode;
  942. PSTR FullCommandPath;
  943. ULONG FullCommandPathSize;
  944. INT Result;
  945. INT ReturnValue;
  946. FullCommandPath = NULL;
  947. //
  948. // If there are no arguments, pull off any active redirection entries so
  949. // they are not undone when the command finishes.
  950. //
  951. if (ArgumentCount <= 1) {
  952. ExecutionNode = LIST_VALUE(Shell->ExecutionStack.Next,
  953. SHELL_EXECUTION_NODE,
  954. ListEntry);
  955. assert(ExecutionNode->Node->Type == ShellNodeSimpleCommand);
  956. while (LIST_EMPTY(&(ExecutionNode->ActiveRedirectList)) == FALSE) {
  957. ActiveRedirect = LIST_VALUE(ExecutionNode->ActiveRedirectList.Next,
  958. SHELL_ACTIVE_REDIRECT,
  959. ListEntry);
  960. LIST_REMOVE(&(ActiveRedirect->ListEntry));
  961. INSERT_BEFORE(&(ActiveRedirect->ListEntry),
  962. &(Shell->ActiveRedirectList));
  963. }
  964. return 0;
  965. }
  966. Arguments += 1;
  967. ArgumentCount -= 1;
  968. //
  969. // Check to see if this is a builtin command, and run it if it is.
  970. //
  971. BuiltinCommand = ShIsBuiltinCommand(Arguments[0]);
  972. if (BuiltinCommand != NULL) {
  973. ReturnValue = ShRunBuiltinCommand(Shell,
  974. BuiltinCommand,
  975. ArgumentCount,
  976. Arguments);
  977. Shell->Exited = TRUE;
  978. Shell->SkipExitSignal = TRUE;
  979. goto BuiltinExecEnd;
  980. } else {
  981. //
  982. // If fork is supported, then actually try to exec the item.
  983. //
  984. ReturnValue = 0;
  985. if (SwForkSupported != FALSE) {
  986. Result = ShLocateCommand(Shell,
  987. Arguments[0],
  988. strlen(Arguments[0]) + 1,
  989. TRUE,
  990. &FullCommandPath,
  991. &FullCommandPathSize,
  992. &ReturnValue);
  993. if (Result == FALSE) {
  994. if (ReturnValue == 0) {
  995. ReturnValue = 1;
  996. }
  997. goto BuiltinExecEnd;
  998. }
  999. if (ReturnValue != 0) {
  1000. if (ReturnValue == SHELL_ERROR_OPEN) {
  1001. PRINT_ERROR("sh: %s: Command not found.\n", Arguments[0]);
  1002. } else if (ReturnValue == SHELL_ERROR_EXECUTE) {
  1003. PRINT_ERROR("sh: %s: Permission denied.\n", Arguments[0]);
  1004. }
  1005. Shell->ReturnValue = ReturnValue;
  1006. goto BuiltinExecEnd;
  1007. }
  1008. fflush(NULL);
  1009. //
  1010. // Execute the destination image. If this fails, exit immediately
  1011. // anyway.
  1012. //
  1013. ShRestoreOriginalSignalDispositions();
  1014. ReturnValue = SwExec(FullCommandPath, Arguments, ArgumentCount);
  1015. ShSetAllSignalDispositions(Shell);
  1016. SwPrintError(ReturnValue, FullCommandPath, "Failed to exec");
  1017. Shell->ReturnValue = ReturnValue;
  1018. //
  1019. // If fork is not supported, then subshells never forked, and this
  1020. // process needs to unwind back up to that. Run the command, then
  1021. // go back up to the previous subshell.
  1022. //
  1023. } else {
  1024. Result = ShRunCommand(Shell,
  1025. Arguments[0],
  1026. Arguments,
  1027. ArgumentCount,
  1028. FALSE,
  1029. &ReturnValue);
  1030. if (Result == 0) {
  1031. ShOsConvertExitStatus(&ReturnValue);
  1032. Shell->ReturnValue = ReturnValue;
  1033. Shell->Exited = TRUE;
  1034. Shell->SkipExitSignal = TRUE;
  1035. goto BuiltinExecEnd;
  1036. } else {
  1037. SwPrintError(Result, Arguments[0], "Failed to exec");
  1038. ReturnValue = 1;
  1039. }
  1040. }
  1041. }
  1042. BuiltinExecEnd:
  1043. if ((FullCommandPath != NULL) && (FullCommandPath != Arguments[0])) {
  1044. free(FullCommandPath);
  1045. }
  1046. return ReturnValue;
  1047. }
  1048. INT
  1049. ShBuiltinRead (
  1050. PSHELL Shell,
  1051. INT ArgumentCount,
  1052. PSTR *Arguments
  1053. )
  1054. /*++
  1055. Routine Description:
  1056. This routine implements the read command, which reads a line from standard
  1057. in, splits it, and assigns variable names given on the command line to the
  1058. given fields.
  1059. Arguments:
  1060. Shell - Supplies a pointer to the shell.
  1061. ArgumentCount - Supplies the number of arguments on the command line.
  1062. Arguments - Supplies the array of pointers to strings representing each
  1063. argument. Arguments can be -v to unset a variable (the default), or -f
  1064. to unset a function. This is followed by the variable or function name.
  1065. Return Value:
  1066. 0 if the command ran successfully. In this case the shell's exited flag
  1067. will be set.
  1068. Returns an error code if the app failed to launch.
  1069. --*/
  1070. {
  1071. PSTR Argument;
  1072. INT ArgumentIndex;
  1073. UINTN ArgumentSize;
  1074. UCHAR Character;
  1075. BOOL EndOfFileDetected;
  1076. SHELL_EXPANSION_RANGE Expansion;
  1077. LIST_ENTRY ExpansionList;
  1078. PSTR Field;
  1079. ULONG FieldCount;
  1080. PSTR *Fields;
  1081. ULONG FieldSize;
  1082. BOOL IgnoreBackslash;
  1083. PSTR Line;
  1084. UINTN LineCapacity;
  1085. UINTN LineSize;
  1086. PSTR NewBuffer;
  1087. BOOL Result;
  1088. INT Status;
  1089. BOOL WasBackslash;
  1090. assert(ArgumentCount != 0);
  1091. EndOfFileDetected = FALSE;
  1092. Fields = NULL;
  1093. //
  1094. // Skip over the "read" argument.
  1095. //
  1096. Arguments += 1;
  1097. ArgumentCount -= 1;
  1098. IgnoreBackslash = FALSE;
  1099. if ((ArgumentCount != 0) && (strcmp(Arguments[0], "-r") == 0)) {
  1100. IgnoreBackslash = TRUE;
  1101. Arguments += 1;
  1102. ArgumentCount -= 1;
  1103. }
  1104. //
  1105. // Read a line of input.
  1106. //
  1107. LineCapacity = SHELL_READ_INITIAL_STRING_SIZE;
  1108. Line = malloc(LineCapacity);
  1109. if (Line == NULL) {
  1110. Status = ENOMEM;
  1111. goto BuiltinReadEnd;
  1112. }
  1113. LineSize = 0;
  1114. WasBackslash = FALSE;
  1115. while (TRUE) {
  1116. do {
  1117. Status = read(STDIN_FILENO, &Character, 1);
  1118. } while ((Status < 0) && (errno == EINTR));
  1119. if (Status < 0) {
  1120. Status = errno;
  1121. ShPrintTrace(Shell, "sh: Failed read: %s.\n", strerror(Status));
  1122. goto BuiltinReadEnd;
  1123. }
  1124. if (Status == 0) {
  1125. EndOfFileDetected = TRUE;
  1126. break;
  1127. }
  1128. if (Character == '\n') {
  1129. //
  1130. // A backslash followed by a newline is a line continuation.
  1131. // Remove the backslash from the input line.
  1132. //
  1133. if (WasBackslash != FALSE) {
  1134. continue;
  1135. } else {
  1136. //
  1137. // Remove any carriage returns that may have strayed along.
  1138. //
  1139. if ((LineSize != 0) && (Line[LineSize - 1] == '\r')) {
  1140. LineSize -= 1;
  1141. }
  1142. break;
  1143. }
  1144. //
  1145. // A backslash followed by any character preserves the literal meaning
  1146. // of that character. Remove the backslash from the input line.
  1147. //
  1148. } else if (WasBackslash != FALSE) {
  1149. LineSize -= 1;
  1150. }
  1151. //
  1152. // Allocate more space for the line if needed. Always have enough
  1153. // space for the terminator as well.
  1154. //
  1155. if (LineSize + 2 >= LineCapacity) {
  1156. LineCapacity *= 2;
  1157. NewBuffer = realloc(Line, LineCapacity);
  1158. if (NewBuffer == NULL) {
  1159. Status = ENOMEM;
  1160. goto BuiltinReadEnd;
  1161. }
  1162. Line = NewBuffer;
  1163. }
  1164. Line[LineSize] = Character;
  1165. LineSize += 1;
  1166. //
  1167. // Keep track of whether or not the previous character was a backslash,
  1168. // but only if backslashes are not being ignored.
  1169. //
  1170. if ((Character == '\\') && (IgnoreBackslash == FALSE)) {
  1171. WasBackslash = !WasBackslash;
  1172. } else {
  1173. WasBackslash = FALSE;
  1174. }
  1175. }
  1176. //
  1177. // Terminate the line.
  1178. //
  1179. Line[LineSize] = '\0';
  1180. LineSize += 1;
  1181. //
  1182. // Split the line into fields.
  1183. //
  1184. INITIALIZE_LIST_HEAD(&ExpansionList);
  1185. Expansion.Type = ShellExpansionFieldSplit;
  1186. Expansion.Index = 0;
  1187. Expansion.Length = LineSize;
  1188. INSERT_BEFORE(&(Expansion.ListEntry), &ExpansionList);
  1189. Result = ShFieldSplit(Shell,
  1190. &Line,
  1191. &LineSize,
  1192. &ExpansionList,
  1193. ArgumentCount,
  1194. &Fields,
  1195. &FieldCount);
  1196. if (Result == FALSE) {
  1197. Status = 1;
  1198. goto BuiltinReadEnd;
  1199. }
  1200. //
  1201. // Assign every argument to the field.
  1202. //
  1203. for (ArgumentIndex = 0; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
  1204. Argument = Arguments[ArgumentIndex];
  1205. ArgumentSize = strlen(Argument) + 1;
  1206. if (ShIsName(Argument, ArgumentSize) == FALSE) {
  1207. PRINT_ERROR("read: Invalid variable name '%s'.\n", Argument);
  1208. Status = EINVAL;
  1209. goto BuiltinReadEnd;
  1210. }
  1211. if (ArgumentIndex < FieldCount) {
  1212. Field = Fields[ArgumentIndex];
  1213. } else {
  1214. Field = "";
  1215. }
  1216. FieldSize = strlen(Field) + 1;
  1217. Result = ShSetVariable(Shell,
  1218. Argument,
  1219. ArgumentSize,
  1220. Field,
  1221. FieldSize);
  1222. if (Result == FALSE) {
  1223. PRINT_ERROR("read: Unable to set variable '%s'.\n", Argument);
  1224. Status = 1;
  1225. goto BuiltinReadEnd;
  1226. }
  1227. }
  1228. Status = 0;
  1229. if (EndOfFileDetected != FALSE) {
  1230. Status = 1;
  1231. }
  1232. BuiltinReadEnd:
  1233. if (Fields != NULL) {
  1234. free(Fields);
  1235. }
  1236. if (Line != NULL) {
  1237. free(Line);
  1238. }
  1239. return Status;
  1240. }
  1241. INT
  1242. ShBuiltinShift (
  1243. PSHELL Shell,
  1244. INT ArgumentCount,
  1245. PSTR *Arguments
  1246. )
  1247. /*++
  1248. Routine Description:
  1249. This routine implements the shift command, which chomps away at the
  1250. positional arguments.
  1251. Arguments:
  1252. Shell - Supplies a pointer to the shell.
  1253. ArgumentCount - Supplies the number of arguments on the command line. The
  1254. only valid values are 1 and 2 (only one optional argument expected).
  1255. Arguments - Supplies the array of pointers to strings representing each
  1256. argument. Arguments can be -v to unset a variable (the default), or -f
  1257. to unset a function. This is followed by the variable or function name.
  1258. Return Value:
  1259. 1 on failure.
  1260. 0 on success.
  1261. --*/
  1262. {
  1263. PSTR AfterScan;
  1264. PSHELL_ARGUMENT Argument;
  1265. PLIST_ENTRY ArgumentList;
  1266. PLIST_ENTRY CurrentEntry;
  1267. ULONG ShellArgumentCount;
  1268. ULONG ShiftCount;
  1269. ULONG ShiftIndex;
  1270. ShellArgumentCount = 0;
  1271. ArgumentList = ShGetCurrentArgumentList(Shell);
  1272. //
  1273. // Loop through once to count arguments.
  1274. //
  1275. CurrentEntry = ArgumentList->Next;
  1276. while (CurrentEntry != ArgumentList) {
  1277. Argument = LIST_VALUE(CurrentEntry, SHELL_ARGUMENT, ListEntry);
  1278. CurrentEntry = CurrentEntry->Next;
  1279. ShellArgumentCount += 1;
  1280. }
  1281. //
  1282. // Convert the optional argument to a shift count.
  1283. //
  1284. ShiftCount = 1;
  1285. if (ArgumentCount > 1) {
  1286. ShiftCount = strtol(Arguments[1], &AfterScan, 10);
  1287. if ((AfterScan == Arguments[1]) || (*AfterScan != '\0')) {
  1288. PRINT_ERROR("shift: Illegal number %s.\n", Arguments[1]);
  1289. return 1;
  1290. }
  1291. }
  1292. //
  1293. // Don't overextend.
  1294. //
  1295. if (ShiftCount > ShellArgumentCount) {
  1296. PRINT_ERROR("shift: Can't shift by %d, only %d arguments.\n",
  1297. ShiftCount,
  1298. ShellArgumentCount);
  1299. return 1;
  1300. }
  1301. //
  1302. // Pull arguments off the list.
  1303. //
  1304. for (ShiftIndex = 0; ShiftIndex < ShiftCount; ShiftIndex += 1) {
  1305. assert(LIST_EMPTY(ArgumentList) == FALSE);
  1306. Argument = LIST_VALUE(ArgumentList->Next, SHELL_ARGUMENT, ListEntry);
  1307. LIST_REMOVE(&(Argument->ListEntry));
  1308. if (Argument->Name != NULL) {
  1309. free(Argument->Name);
  1310. }
  1311. free(Argument);
  1312. }
  1313. return 0;
  1314. }
  1315. INT
  1316. ShBuiltinTimes (
  1317. PSHELL Shell,
  1318. INT ArgumentCount,
  1319. PSTR *Arguments
  1320. )
  1321. /*++
  1322. Routine Description:
  1323. This routine implements the times command, which prints execution
  1324. statistics about the shell and its children.
  1325. Arguments:
  1326. Shell - Supplies a pointer to the shell.
  1327. ArgumentCount - Supplies the number of arguments on the command line.
  1328. Arguments - Supplies the array of pointers to strings representing each
  1329. argument. Arguments can be -v to unset a variable (the default), or -f
  1330. to unset a function. This is followed by the variable or function name.
  1331. Return Value:
  1332. 0 on success.
  1333. 1 on failure.
  1334. --*/
  1335. {
  1336. BOOL Result;
  1337. SHELL_PROCESS_TIMES Times;
  1338. Result = ShGetExecutionTimes(&Times);
  1339. if (Result == FALSE) {
  1340. return 1;
  1341. }
  1342. //
  1343. // Floats are for losers.
  1344. //
  1345. printf("%I64dm%d.%06ds %I64dm%d.%06ds\n%I64dm%d.%06ds %I64dm%d.%06ds\n",
  1346. Times.ShellUserMinutes,
  1347. Times.ShellUserMicroseconds / 1000000,
  1348. Times.ShellUserMicroseconds % 1000000,
  1349. Times.ShellSystemMinutes,
  1350. Times.ShellSystemMicroseconds / 1000000,
  1351. Times.ShellSystemMicroseconds % 1000000,
  1352. Times.ChildrenUserMinutes,
  1353. Times.ChildrenUserMicroseconds / 1000000,
  1354. Times.ChildrenUserMicroseconds % 1000000,
  1355. Times.ChildrenSystemMinutes,
  1356. Times.ChildrenSystemMicroseconds / 1000000,
  1357. Times.ChildrenSystemMicroseconds % 1000000);
  1358. return 0;
  1359. }
  1360. INT
  1361. ShBuiltinUmask (
  1362. PSHELL Shell,
  1363. INT ArgumentCount,
  1364. PSTR *Arguments
  1365. )
  1366. /*++
  1367. Routine Description:
  1368. This routine implements the uname builtin command, which changes the
  1369. umask of the process the current shell is running in.
  1370. Arguments:
  1371. Shell - Supplies a pointer to the shell.
  1372. ArgumentCount - Supplies the number of arguments on the command line.
  1373. Arguments - Supplies the array of pointers to strings representing each
  1374. argument. Arguments can be -v to unset a variable (the default), or -f
  1375. to unset a function. This is followed by the variable or function name.
  1376. Return Value:
  1377. 0 on success.
  1378. 1 on failure.
  1379. --*/
  1380. {
  1381. PSTR Argument;
  1382. INT ArgumentIndex;
  1383. mode_t Mask;
  1384. PSTR ModeString;
  1385. mode_t OriginalMask;
  1386. BOOL Result;
  1387. BOOL Symbolic;
  1388. Symbolic = FALSE;
  1389. if (ArgumentCount > 3) {
  1390. fprintf(stderr, "usage: umask [-S] [mask]\n");
  1391. return 1;
  1392. }
  1393. ModeString = NULL;
  1394. for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
  1395. Argument = Arguments[ArgumentIndex];
  1396. if (strcmp(Argument, "-S") == 0) {
  1397. Symbolic = TRUE;
  1398. } else {
  1399. ModeString = Argument;
  1400. }
  1401. }
  1402. OriginalMask = umask(0);
  1403. umask(OriginalMask);
  1404. //
  1405. // If a mode string was supplied, create the and set the new mask.
  1406. //
  1407. if (ModeString != NULL) {
  1408. Mask = OriginalMask;
  1409. Result = SwParseFilePermissionsString(ModeString, FALSE, &Mask);
  1410. if (Result == FALSE) {
  1411. fprintf(stderr,
  1412. "umask: Could not parse mode string '%s'.\n",
  1413. ModeString);
  1414. return 1;
  1415. }
  1416. umask(Mask);
  1417. //
  1418. // If there's no mode string, print the current mask out.
  1419. //
  1420. } else {
  1421. if (Symbolic != FALSE) {
  1422. //
  1423. // Go through the motions to print out something pretty.
  1424. //
  1425. Mask = OriginalMask;
  1426. printf("u=");
  1427. if ((Mask & S_IRUSR) == 0) {
  1428. fputc('r', stdout);
  1429. }
  1430. if ((Mask & S_IWUSR) == 0) {
  1431. fputc('w', stdout);
  1432. }
  1433. if ((Mask & S_IXUSR) == 0) {
  1434. fputc('x', stdout);
  1435. }
  1436. printf(",g=");
  1437. if ((Mask & S_IRGRP) == 0) {
  1438. fputc('r', stdout);
  1439. }
  1440. if ((Mask & S_IWGRP) == 0) {
  1441. fputc('w', stdout);
  1442. }
  1443. if ((Mask & S_IXGRP) == 0) {
  1444. fputc('x', stdout);
  1445. }
  1446. printf(",o=");
  1447. if ((Mask & S_IROTH) == 0) {
  1448. fputc('r', stdout);
  1449. }
  1450. if ((Mask & S_IWOTH) == 0) {
  1451. fputc('w', stdout);
  1452. }
  1453. if ((Mask & S_IXOTH) == 0) {
  1454. fputc('x', stdout);
  1455. }
  1456. printf("\n");
  1457. //
  1458. // Just print out the octal value.
  1459. //
  1460. } else {
  1461. printf("%04o\n", OriginalMask);
  1462. }
  1463. }
  1464. return 0;
  1465. }
  1466. INT
  1467. ShBuiltinGetopts (
  1468. PSHELL Shell,
  1469. INT ArgumentCount,
  1470. PSTR *Arguments
  1471. )
  1472. /*++
  1473. Routine Description:
  1474. This routine implements the getopts builtin command, which parses
  1475. positional parameters or the supplied arguments for command.
  1476. Arguments:
  1477. Shell - Supplies a pointer to the shell.
  1478. ArgumentCount - Supplies the number of arguments on the command line.
  1479. Arguments - Supplies the array of pointers to strings representing each
  1480. argument.
  1481. Return Value:
  1482. 0 on success.
  1483. Returns greater than zero if an error occurred.
  1484. --*/
  1485. {
  1486. PSTR AfterScan;
  1487. PSTR Argument;
  1488. ULONG ArgumentIndex;
  1489. INT BytesConverted;
  1490. BOOL EndOfOptions;
  1491. PSTR ExpandedArguments;
  1492. UINTN ExpandedArgumentsSize;
  1493. CHAR NewOptionIndex[SHELL_MAX_OPTION_INDEX_LENGTH];
  1494. CHAR NewOptionValueBuffer[2];
  1495. PSTR NewOptionVariable;
  1496. PSTR OptionArgument;
  1497. CHAR OptionCharacter;
  1498. PSTR OptionIndexString;
  1499. ULONG OptionsArgumentCount;
  1500. PSTR *OptionsArguments;
  1501. INT OptionsIndex;
  1502. PSTR OptionsString;
  1503. BOOL Result;
  1504. INT ReturnValue;
  1505. INT Status;
  1506. BOOL UsingPositionalParameters;
  1507. ReturnValue = 0;
  1508. //
  1509. // There are no options to the getopts utility, but eat up arguments
  1510. // looking for bad options.
  1511. //
  1512. for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
  1513. Argument = Arguments[ArgumentIndex];
  1514. //
  1515. // Break out if a non-argument is seen.
  1516. //
  1517. if (*Argument != '-') {
  1518. break;
  1519. }
  1520. //
  1521. // Break out and advance the argument index if the "--" is seen.
  1522. //
  1523. Argument += 1;
  1524. if (strcmp(Argument, "-") == 0) {
  1525. ArgumentIndex += 1;
  1526. break;
  1527. }
  1528. //
  1529. // Anything else is an error.
  1530. //
  1531. fprintf(stderr, "getopts: invalid option '-%c'.\n", *Argument);
  1532. fprintf(stderr, "usage: getopts optstring name [arg...]\n");
  1533. return 2;
  1534. }
  1535. //
  1536. // Argument index holds the position of the option string. If there aren't
  1537. // at least two parameters remaining, then exit.
  1538. //
  1539. if ((ArgumentCount - ArgumentIndex) < 2) {
  1540. fprintf(stderr, "usage: getopts optstring name [arg...]\n");
  1541. return 2;
  1542. }
  1543. OptionsString = Arguments[ArgumentIndex];
  1544. NewOptionVariable = Arguments[ArgumentIndex + 1];
  1545. ArgumentIndex += 2;
  1546. //
  1547. // Try to get the option index. If it's not there or invalid, then reset to
  1548. // 1.
  1549. //
  1550. OptionsIndex = 1;
  1551. Result = ShGetVariable(Shell,
  1552. SHELL_OPTION_INDEX,
  1553. sizeof(SHELL_OPTION_INDEX),
  1554. &OptionIndexString,
  1555. NULL);
  1556. if (Result != FALSE) {
  1557. OptionsIndex = (int)strtol(OptionIndexString, &AfterScan, 10);
  1558. if ((OptionIndexString == AfterScan) || (*AfterScan != '\0')) {
  1559. OptionsIndex = 1;
  1560. }
  1561. }
  1562. //
  1563. // If the options index is less than 1, then reset it.
  1564. //
  1565. if (OptionsIndex < 1) {
  1566. ShOptionsIndex = OptionsIndex;
  1567. OptionsIndex = 1;
  1568. }
  1569. //
  1570. // Reset if the caller tried to manipluate the option index.
  1571. //
  1572. if (ShOptionsIndex != OptionsIndex) {
  1573. ShOptionsIndex = OptionsIndex;
  1574. ShNextOptionCharacter = 0;
  1575. ShSeenDoubleDash = FALSE;
  1576. }
  1577. //
  1578. // If arguments are present, those are preferred to the positional
  1579. // parameters.
  1580. //
  1581. UsingPositionalParameters = FALSE;
  1582. if (ArgumentIndex != ArgumentCount) {
  1583. OptionsArgumentCount = ArgumentCount - ArgumentIndex;
  1584. OptionsArguments = &(Arguments[ArgumentIndex]);
  1585. } else {
  1586. Result = ShPerformExpansions(Shell,
  1587. "$@",
  1588. sizeof("$@"),
  1589. 0,
  1590. &ExpandedArguments,
  1591. &ExpandedArgumentsSize,
  1592. &OptionsArguments,
  1593. &OptionsArgumentCount);
  1594. if (Result == FALSE) {
  1595. ReturnValue += 1;
  1596. goto BuiltinGetoptsEnd;
  1597. }
  1598. UsingPositionalParameters = TRUE;
  1599. }
  1600. //
  1601. // The options index is off by one because the arguments array does not
  1602. // have the command as the first entry.
  1603. //
  1604. OptionsIndex -= 1;
  1605. //
  1606. // Get the next option using the built-in parser rather than the C library
  1607. // getopts() routine. Things are handled slightly differently with regards
  1608. // to the option string.
  1609. //
  1610. Status = ShGetNextOption(Shell,
  1611. OptionsArgumentCount,
  1612. OptionsArguments,
  1613. &OptionsIndex,
  1614. OptionsString,
  1615. &OptionCharacter,
  1616. &OptionArgument,
  1617. &EndOfOptions);
  1618. if (Status == 0) {
  1619. ReturnValue += 1;
  1620. goto BuiltinGetoptsEnd;
  1621. }
  1622. //
  1623. // Shift the options index back as it is stored considering the command as
  1624. // 0.
  1625. //
  1626. OptionsIndex += 1;
  1627. ShOptionsIndex = OptionsIndex;
  1628. //
  1629. // Update the environment variables.
  1630. //
  1631. BytesConverted = snprintf(NewOptionIndex,
  1632. SHELL_MAX_OPTION_INDEX_LENGTH,
  1633. "%d",
  1634. OptionsIndex);
  1635. if (BytesConverted < 0) {
  1636. ReturnValue += 1;
  1637. goto BuiltinGetoptsEnd;
  1638. }
  1639. Result = ShSetVariable(Shell,
  1640. SHELL_OPTION_INDEX,
  1641. sizeof(SHELL_OPTION_INDEX),
  1642. NewOptionIndex,
  1643. BytesConverted + 1);
  1644. if (Result == FALSE) {
  1645. ReturnValue += 1;
  1646. goto BuiltinGetoptsEnd;
  1647. }
  1648. NewOptionValueBuffer[0] = OptionCharacter;
  1649. NewOptionValueBuffer[1] = '\0';
  1650. BytesConverted = 1;
  1651. Result = ShSetVariable(Shell,
  1652. NewOptionVariable,
  1653. strlen(NewOptionVariable) + 1,
  1654. NewOptionValueBuffer,
  1655. BytesConverted + 1);
  1656. if (Result == FALSE) {
  1657. ReturnValue += 1;
  1658. goto BuiltinGetoptsEnd;
  1659. }
  1660. if (OptionArgument != NULL) {
  1661. Result = ShSetVariable(Shell,
  1662. SHELL_OPTION_ARGUMENT,
  1663. sizeof(SHELL_OPTION_ARGUMENT),
  1664. OptionArgument,
  1665. strlen(OptionArgument) + 1);
  1666. if (Result == FALSE) {
  1667. ReturnValue += 1;
  1668. goto BuiltinGetoptsEnd;
  1669. }
  1670. } else {
  1671. ShUnsetVariableOrFunction(Shell,
  1672. SHELL_OPTION_ARGUMENT,
  1673. sizeof(SHELL_OPTION_ARGUMENT),
  1674. ShellUnsetDefault);
  1675. }
  1676. //
  1677. // If the end of options was reached, return a non-zero value.
  1678. //
  1679. if (EndOfOptions != FALSE) {
  1680. ReturnValue += 1;
  1681. }
  1682. BuiltinGetoptsEnd:
  1683. if (OptionArgument != NULL) {
  1684. free(OptionArgument);
  1685. }
  1686. if (UsingPositionalParameters != FALSE) {
  1687. if (ExpandedArguments != NULL) {
  1688. free(ExpandedArguments);
  1689. }
  1690. if (OptionsArguments != NULL) {
  1691. free(OptionsArguments);
  1692. }
  1693. }
  1694. return ReturnValue;
  1695. }
  1696. INT
  1697. ShBuiltinCommand (
  1698. PSHELL Shell,
  1699. INT ArgumentCount,
  1700. PSTR *Arguments
  1701. )
  1702. /*++
  1703. Routine Description:
  1704. This routine implements the command builtin command, which runs the given
  1705. command without invoking shell functions.
  1706. Arguments:
  1707. Shell - Supplies a pointer to the shell.
  1708. ArgumentCount - Supplies the number of arguments on the command line.
  1709. Arguments - Supplies the array of pointers to strings representing each
  1710. argument. Arguments can be -v to unset a variable (the default), or -f
  1711. to unset a function. This is followed by the variable or function name.
  1712. Return Value:
  1713. 0 on success.
  1714. 1 on failure.
  1715. --*/
  1716. {
  1717. INT Result;
  1718. Result = ShBuiltinTypeOrCommand(Shell, ArgumentCount, Arguments, FALSE);
  1719. return Result;
  1720. }
  1721. INT
  1722. ShBuiltinType (
  1723. PSHELL Shell,
  1724. INT ArgumentCount,
  1725. PSTR *Arguments
  1726. )
  1727. /*++
  1728. Routine Description:
  1729. This routine implements the 'type' builtin command, which describes the
  1730. given commands.
  1731. Arguments:
  1732. Shell - Supplies a pointer to the shell.
  1733. ArgumentCount - Supplies the number of arguments on the command line.
  1734. Arguments - Supplies the array of pointers to strings representing each
  1735. argument. Arguments can be -v to unset a variable (the default), or -f
  1736. to unset a function. This is followed by the variable or function name.
  1737. Return Value:
  1738. 0 on success.
  1739. 1 on failure.
  1740. --*/
  1741. {
  1742. INT Result;
  1743. Result = ShBuiltinTypeOrCommand(Shell, ArgumentCount, Arguments, TRUE);
  1744. return Result;
  1745. }
  1746. INT
  1747. ShBuiltinTypeOrCommand (
  1748. PSHELL Shell,
  1749. INT ArgumentCount,
  1750. PSTR *Arguments,
  1751. BOOL IsType
  1752. )
  1753. /*++
  1754. Routine Description:
  1755. This routine implements the command or type builtins, which run or describe
  1756. a command.
  1757. Arguments:
  1758. Shell - Supplies a pointer to the shell.
  1759. ArgumentCount - Supplies the number of arguments on the command line.
  1760. Arguments - Supplies the array of pointers to strings representing each
  1761. argument. Arguments can be -v to unset a variable (the default), or -f
  1762. to unset a function. This is followed by the variable or function name.
  1763. IsType - Supplies a boolean indicating whether this is the type builtin
  1764. function (TRUE) or the command builtin function (FALSE).
  1765. Return Value:
  1766. 0 on success.
  1767. 1 on failure.
  1768. --*/
  1769. {
  1770. PSTR Argument;
  1771. INT ArgumentIndex;
  1772. PSHELL_BUILTIN_COMMAND BuiltinCommand;
  1773. BOOL DefaultPath;
  1774. PSTR OriginalPath;
  1775. UINTN OriginalPathSize;
  1776. BOOL PrintPath;
  1777. INT ReturnValue;
  1778. INT TotalReturnValue;
  1779. BOOL Verbose;
  1780. DefaultPath = FALSE;
  1781. OriginalPath = NULL;
  1782. PrintPath = FALSE;
  1783. Verbose = FALSE;
  1784. TotalReturnValue = 0;
  1785. //
  1786. // Type acts just like command -v.
  1787. //
  1788. if (IsType != FALSE) {
  1789. Verbose = TRUE;
  1790. ArgumentIndex = 1;
  1791. //
  1792. // Handle the arguments for the command command.
  1793. //
  1794. } else {
  1795. for (ArgumentIndex = 1;
  1796. ArgumentIndex < ArgumentCount;
  1797. ArgumentIndex += 1) {
  1798. Argument = Arguments[ArgumentIndex];
  1799. if (*Argument != '-') {
  1800. break;
  1801. }
  1802. Argument += 1;
  1803. if (*Argument == '-') {
  1804. break;
  1805. }
  1806. while (*Argument != '\0') {
  1807. switch (*Argument) {
  1808. case 'p':
  1809. DefaultPath = TRUE;
  1810. break;
  1811. case 'v':
  1812. PrintPath = TRUE;
  1813. break;
  1814. case 'V':
  1815. Verbose = TRUE;
  1816. break;
  1817. default:
  1818. fprintf(stderr, "command: Invalid option %c.\n", *Argument);
  1819. break;
  1820. }
  1821. Argument += 1;
  1822. }
  1823. }
  1824. if (PrintPath != FALSE) {
  1825. Verbose = FALSE;
  1826. }
  1827. }
  1828. Arguments += ArgumentIndex;
  1829. ArgumentCount -= ArgumentIndex;
  1830. //
  1831. // If the command is empty, don't do much.
  1832. //
  1833. if ((ArgumentCount == 0) || (strlen(Arguments[0]) == 0)) {
  1834. return 0;
  1835. }
  1836. if (DefaultPath != FALSE) {
  1837. ShGetVariable(Shell,
  1838. SHELL_PATH,
  1839. sizeof(SHELL_PATH),
  1840. &OriginalPath,
  1841. &OriginalPathSize);
  1842. OriginalPath = SwStringDuplicate(OriginalPath, OriginalPathSize);
  1843. ShSetVariableWithProperties(Shell,
  1844. SHELL_PATH,
  1845. sizeof(SHELL_PATH),
  1846. SHELL_COMMAND_BUILTIN_PATH,
  1847. sizeof(SHELL_COMMAND_BUILTIN_PATH),
  1848. TRUE,
  1849. FALSE,
  1850. TRUE);
  1851. }
  1852. if ((Verbose != FALSE) || (PrintPath != FALSE)) {
  1853. //
  1854. // Loop over all the arguments, though if this is not the 'type'
  1855. // builtin this will break after the first iteration.
  1856. //
  1857. while (ArgumentCount != 0) {
  1858. ReturnValue = ShClassifyCommand(Shell, Arguments[0], Verbose);
  1859. if (ReturnValue != 0) {
  1860. TotalReturnValue = ReturnValue;
  1861. }
  1862. if (IsType == FALSE) {
  1863. break;
  1864. }
  1865. Arguments += 1;
  1866. ArgumentCount -= 1;
  1867. }
  1868. //
  1869. // Really run the command.
  1870. //
  1871. } else {
  1872. BuiltinCommand = ShIsBuiltinCommand(Arguments[0]);
  1873. if (BuiltinCommand != NULL) {
  1874. ReturnValue = ShRunBuiltinCommand(Shell,
  1875. BuiltinCommand,
  1876. ArgumentCount,
  1877. Arguments);
  1878. } else {
  1879. ShRunCommand(Shell,
  1880. Arguments[0],
  1881. Arguments,
  1882. ArgumentCount,
  1883. FALSE,
  1884. &ReturnValue);
  1885. }
  1886. }
  1887. if ((TotalReturnValue == 0) && (ReturnValue != 0)) {
  1888. TotalReturnValue = ReturnValue;
  1889. }
  1890. if (OriginalPath != NULL) {
  1891. ShSetVariable(Shell,
  1892. SHELL_PATH,
  1893. sizeof(SHELL_PATH),
  1894. OriginalPath,
  1895. OriginalPathSize);
  1896. }
  1897. return TotalReturnValue;
  1898. }
  1899. INT
  1900. ShClassifyCommand (
  1901. PSHELL Shell,
  1902. PSTR Command,
  1903. BOOL Verbose
  1904. )
  1905. /*++
  1906. Routine Description:
  1907. This routine classifies and prints the classification for the given command.
  1908. Arguments:
  1909. Shell - Supplies a pointer to the shell.
  1910. Command - Supplies a pointer to the command to classify.
  1911. Verbose - Supplies a boolean indicating whether to print the verbose
  1912. description or just the command path (or name).
  1913. Return Value:
  1914. 0 on success.
  1915. 127 if the command could not be found.
  1916. --*/
  1917. {
  1918. PSHELL_ALIAS Alias;
  1919. PSHELL_BUILTIN_COMMAND BuiltinCommand;
  1920. PSTR FullCommandPath;
  1921. ULONG FullCommandPathSize;
  1922. PSHELL_FUNCTION Function;
  1923. PSTR ReservedWord;
  1924. UINTN ReservedWordIndex;
  1925. BOOL Result;
  1926. INT ReturnValue;
  1927. //
  1928. // First look to see if it is a reserved word.
  1929. //
  1930. ReservedWordIndex = 0;
  1931. while (ShReservedWords[ReservedWordIndex] != NULL) {
  1932. ReservedWord = ShReservedWords[ReservedWordIndex];
  1933. if (strcmp(Command, ReservedWord) == 0) {
  1934. if (Verbose != FALSE) {
  1935. printf("%s is a shell keyword\n", Command);
  1936. } else {
  1937. printf("%s\n", Command);
  1938. }
  1939. return 0;
  1940. }
  1941. ReservedWordIndex += 1;
  1942. }
  1943. BuiltinCommand = ShIsBuiltinCommand(Command);
  1944. if (BuiltinCommand != NULL) {
  1945. ReturnValue = 0;
  1946. if (Verbose != FALSE) {
  1947. printf("%s is a shell builtin\n", Command);
  1948. } else {
  1949. printf("%s\n", Command);
  1950. }
  1951. return 0;
  1952. }
  1953. //
  1954. // Then look to see if it is an alias.
  1955. //
  1956. Alias = ShLookupAlias(Shell, Command, strlen(Command) + 1);
  1957. if (Alias != NULL) {
  1958. if (Verbose != FALSE) {
  1959. printf("%s is an alias for %s\n", Command, Alias->Value);
  1960. } else {
  1961. printf("alias %s='%s'\n", Command, Alias->Value);
  1962. }
  1963. return 0;
  1964. }
  1965. //
  1966. // Look to see if this is a function.
  1967. //
  1968. Function = ShGetFunction(Shell, Command, strlen(Command) + 1);
  1969. if (Function != NULL) {
  1970. if (Verbose != FALSE) {
  1971. printf("%s is a shell function\n", Command);
  1972. } else {
  1973. printf("%s\n", Command);
  1974. }
  1975. return 0;
  1976. }
  1977. //
  1978. // Attempt to locate the command in the path.
  1979. //
  1980. ReturnValue = 0;
  1981. FullCommandPath = NULL;
  1982. Result = ShLocateCommand(Shell,
  1983. Command,
  1984. strlen(Command) + 1,
  1985. TRUE,
  1986. &FullCommandPath,
  1987. &FullCommandPathSize,
  1988. &ReturnValue);
  1989. if (Result == FALSE) {
  1990. ReturnValue = SHELL_ERROR_OPEN;
  1991. }
  1992. if (ReturnValue != 0) {
  1993. if (Verbose != FALSE) {
  1994. ShPrintTrace(Shell, "sh: %s: Command not found.\n", Command);
  1995. }
  1996. } else {
  1997. if (Verbose != FALSE) {
  1998. printf("%s is %s\n", Command, FullCommandPath);
  1999. } else {
  2000. printf("%s\n", FullCommandPath);
  2001. }
  2002. }
  2003. if ((FullCommandPath != NULL) && (FullCommandPath != Command)) {
  2004. free(FullCommandPath);
  2005. }
  2006. return ReturnValue;
  2007. }
  2008. INT
  2009. ShGetNextOption (
  2010. PSHELL Shell,
  2011. ULONG ArgumentCount,
  2012. PSTR *Arguments,
  2013. PINT ArgumentIndex,
  2014. PSTR Options,
  2015. PCHAR Option,
  2016. PSTR *OptionArgument,
  2017. PBOOL EndOfOptions
  2018. )
  2019. /*++
  2020. Routine Description:
  2021. This routine gets the next option from the list of arguments. Starting at
  2022. the given argument index, it determines if that argument string begins with
  2023. an option.
  2024. Arguments:
  2025. Shell - Supplies a pointer to the shell.
  2026. ArgumentCount - Supplies the number of arguments in the arguments array.
  2027. Arguments - Supplies the arguments to parse. The first array item is the
  2028. first argument (e.g. positional parameter 1). On return it will contain
  2029. the index of the next argument to parse.
  2030. ArgumentIndex - Supplies the index into the argument array that should be
  2031. analyzed for an option.
  2032. Options - Supplies the options string.
  2033. Option - Supplies a pointer that receives the parsed option.
  2034. OptionArgument - Supplies a pointer that receives the option's argument
  2035. string. The caller is responsible for releasing this memory.
  2036. EndOfOptions - Supplies a pointer that receives a boolean indicating
  2037. whether or not the end of options has been reached.
  2038. Return Value:
  2039. 1 on success.
  2040. 0 on failure.
  2041. --*/
  2042. {
  2043. PSTR Argument;
  2044. CHAR CharacterString[2];
  2045. PSTR OptionError;
  2046. BOOL Result;
  2047. BOOL StartsWithColon;
  2048. *OptionArgument = NULL;
  2049. *EndOfOptions = FALSE;
  2050. //
  2051. // If the argument index is beyond the bounds of the array, then return as
  2052. // if the end of the options was reached.
  2053. //
  2054. if (*ArgumentIndex >= ArgumentCount) {
  2055. *ArgumentIndex = ArgumentCount;
  2056. *Option = '?';
  2057. ShNextOptionCharacter = 0;
  2058. *EndOfOptions = TRUE;
  2059. return 1;
  2060. }
  2061. //
  2062. // If the next option character value is 0, then this argument has not been
  2063. // processed.
  2064. //
  2065. Argument = Arguments[*ArgumentIndex];
  2066. if (ShNextOptionCharacter == 0) {
  2067. //
  2068. // If the argument does not start with a dash, then this is the end of
  2069. // the arguments.
  2070. //
  2071. if (*Argument != '-') {
  2072. *Option = '?';
  2073. *EndOfOptions = TRUE;
  2074. return 1;
  2075. }
  2076. Argument += 1;
  2077. //
  2078. // If this is the "--" argument, then it's also the end of the line.
  2079. //
  2080. if ((*Argument == '-') && (*(Argument + 1) == '\0')) {
  2081. *Option = '?';
  2082. //
  2083. // If the "--" has not yet been seen, then the index needs to jump
  2084. // to the next argument.
  2085. //
  2086. if (ShSeenDoubleDash == FALSE) {
  2087. *ArgumentIndex += 1;
  2088. ShSeenDoubleDash = TRUE;
  2089. }
  2090. *EndOfOptions = TRUE;
  2091. return 1;
  2092. }
  2093. //
  2094. // Ok. There might be some options in this argument, start looking at
  2095. // the second character.
  2096. //
  2097. ShNextOptionCharacter = 1;
  2098. } else {
  2099. Argument += ShNextOptionCharacter;
  2100. }
  2101. assert(*Argument != '\0');
  2102. StartsWithColon = FALSE;
  2103. if (*Options == ':') {
  2104. StartsWithColon = TRUE;
  2105. Options += 1;
  2106. }
  2107. //
  2108. // Loop over every acceptible option.
  2109. //
  2110. while (*Options != '\0') {
  2111. //
  2112. // Keep looking if they are not equal.
  2113. //
  2114. if ((!isalnum(*Options)) || (*Argument != *Options)) {
  2115. Options += 1;
  2116. continue;
  2117. }
  2118. //
  2119. // They're equal, look to see if the next character is a colon.
  2120. //
  2121. *Option = *Options;
  2122. Options += 1;
  2123. ShNextOptionCharacter += 1;
  2124. Argument += 1;
  2125. //
  2126. // If no argument is required, then work here is done.
  2127. //
  2128. if (*Options != ':') {
  2129. //
  2130. // If the next character of the argument is the terminator, then
  2131. // up the index and reset the option character.
  2132. //
  2133. if (*Argument == '\0') {
  2134. ShNextOptionCharacter = 0;
  2135. *ArgumentIndex += 1;
  2136. }
  2137. return 1;
  2138. }
  2139. Options += 1;
  2140. //
  2141. // An argument is required. Optional arguments are not supported for
  2142. // the built-in shell option parsing. If the next character of the
  2143. // argument is not null, then the argument is the remainder.
  2144. //
  2145. ShNextOptionCharacter = 0;
  2146. if (*Argument != '\0') {
  2147. *OptionArgument = strdup(Argument);
  2148. if (*OptionArgument == NULL) {
  2149. return 0;
  2150. }
  2151. *ArgumentIndex += 1;
  2152. return 1;
  2153. }
  2154. //
  2155. // It must be the next argument. If there is no next argument, that's a
  2156. // problem.
  2157. //
  2158. if (*ArgumentIndex >= (ArgumentCount - 1)) {
  2159. *ArgumentIndex += 1;
  2160. if (StartsWithColon != FALSE) {
  2161. CharacterString[0] = *Option;
  2162. CharacterString[1] = '\0';
  2163. *OptionArgument = strdup(CharacterString);
  2164. if (*OptionArgument == NULL) {
  2165. return 0;
  2166. }
  2167. *Option = ':';
  2168. } else {
  2169. assert(*OptionArgument == NULL);
  2170. Result = ShGetVariable(Shell,
  2171. SHELL_OPTION_ERROR,
  2172. sizeof(SHELL_OPTION_ERROR),
  2173. &OptionError,
  2174. NULL);
  2175. if ((Result == FALSE) || (strcmp(OptionError, "0") != 0)) {
  2176. fprintf(stderr,
  2177. "%s: option -%c requires an argument.\n",
  2178. Shell->CommandName,
  2179. *Option);
  2180. }
  2181. *Option = '?';
  2182. }
  2183. return 1;
  2184. }
  2185. *ArgumentIndex += 1;
  2186. *OptionArgument = strdup(Arguments[*ArgumentIndex]);
  2187. if (*OptionArgument == NULL) {
  2188. return 0;
  2189. }
  2190. *ArgumentIndex += 1;
  2191. return 1;
  2192. }
  2193. //
  2194. // The argument doesn't match any of the acceptable options.
  2195. //
  2196. if (StartsWithColon != FALSE) {
  2197. CharacterString[0] = *Option;
  2198. CharacterString[1] = '\0';
  2199. *OptionArgument = strdup(CharacterString);
  2200. if (*OptionArgument == NULL) {
  2201. return 0;
  2202. }
  2203. } else {
  2204. assert(*OptionArgument == NULL);
  2205. Result = ShGetVariable(Shell,
  2206. SHELL_OPTION_ERROR,
  2207. sizeof(SHELL_OPTION_ERROR),
  2208. &OptionError,
  2209. NULL);
  2210. if ((Result == FALSE) || (strcmp(OptionError, "0") != 0)) {
  2211. fprintf(stderr,
  2212. "%s: Invalid option -%c.\n",
  2213. Shell->CommandName,
  2214. *Argument);
  2215. }
  2216. }
  2217. //
  2218. // Skip to the next option. It could be in the next argument or next
  2219. // character.
  2220. //
  2221. Argument += 1;
  2222. if (*Argument == '\0') {
  2223. ShNextOptionCharacter = 0;
  2224. *ArgumentIndex += 1;
  2225. } else {
  2226. ShNextOptionCharacter += 1;
  2227. }
  2228. *Option = '?';
  2229. return 1;
  2230. }