Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

477 lines
11 KiB

  1. /*++
  2. Copyright (c) 1998 Intel Corporation
  3. Module Name:
  4. init.c
  5. Abstract:
  6. Shell
  7. Revision History
  8. --*/
  9. #include "nshell.h"
  10. /*
  11. * Globals
  12. */
  13. CHAR16 *ShellEnvPathName[] = {
  14. L"shellenv.efi",
  15. L"efi\\shellenv.efi",
  16. L"efi\\tools\\shellenv.efi",
  17. NULL
  18. } ;
  19. /*
  20. * Prototypes
  21. */
  22. EFI_STATUS
  23. InitializeShell (
  24. IN EFI_HANDLE ImageHandle,
  25. IN EFI_SYSTEM_TABLE *SystemTable
  26. );
  27. EFI_STATUS
  28. ShellLoadEnvDriver (
  29. IN EFI_HANDLE ImageHandle
  30. );
  31. EFI_STATUS
  32. NShellPrompt (
  33. IN EFI_HANDLE ImageHandle
  34. );
  35. BOOLEAN
  36. ParseLoadOptions(
  37. EFI_HANDLE ImageHandle,
  38. OUT CHAR16 **CommandLine,
  39. OUT CHAR16 **CurrentDir
  40. );
  41. /*
  42. *
  43. */
  44. EFI_DRIVER_ENTRY_POINT(InitializeShell)
  45. EFI_STATUS
  46. InitializeShell (
  47. IN EFI_HANDLE ImageHandle,
  48. IN EFI_SYSTEM_TABLE *SystemTable
  49. )
  50. /*++
  51. Routine Description:
  52. Arguments:
  53. ImageHandle - The handle for this driver
  54. SystemTable - The system table
  55. Returns:
  56. --*/
  57. {
  58. EFI_STATUS Status;
  59. EFI_HANDLE Handle;
  60. UINTN BufferSize;
  61. VOID *Junk;
  62. BOOLEAN IsRootInstance;
  63. CHAR16 *CommandLine;
  64. CHAR16 *CurrentDir;
  65. /*
  66. * The shell may be started as either:
  67. * 1. the first time with no shell environment loaded yet
  68. * 2. not the first time, but with a shell environment loaded
  69. * 3. as a child of a parent shell image
  70. */
  71. IsRootInstance = FALSE;
  72. InitializeLib (ImageHandle, SystemTable);
  73. /*
  74. * If the shell environment is not loaded, load it now
  75. */
  76. BufferSize = sizeof(Handle);
  77. Status = BS->LocateHandle(ByProtocol, &ShellEnvProtocol, NULL, &BufferSize, &Handle);
  78. if (EFI_ERROR(Status)) {
  79. Status = ShellLoadEnvDriver (ImageHandle);
  80. if (EFI_ERROR(Status)) {
  81. Print(L"Shell environment driver not loaded\n");
  82. BS->Exit (ImageHandle, Status, 0, NULL);
  83. }
  84. }
  85. /*
  86. * Check to see if we're a child of a previous shell
  87. */
  88. Status = BS->HandleProtocol (ImageHandle, &ShellInterfaceProtocol, (VOID*)&Junk);
  89. if (EFI_ERROR(Status)) {
  90. /*
  91. * Special case were the shell is being started directly (e.g., not
  92. * as a child of another shell)
  93. */
  94. BufferSize = sizeof(Handle);
  95. Status = BS->LocateHandle(ByProtocol, &ShellEnvProtocol, NULL, &BufferSize, &Handle);
  96. ASSERT (!EFI_ERROR(Status));
  97. Status = BS->HandleProtocol(Handle, &ShellEnvProtocol, (VOID*)&SE);
  98. ASSERT (!EFI_ERROR(Status));
  99. /*
  100. * Allocate a new shell interface structure, and assign it to our
  101. * image handle
  102. */
  103. SI = SE->NewShell(ImageHandle);
  104. Status = LibInstallProtocolInterfaces (&ImageHandle, &ShellInterfaceProtocol, SI, NULL);
  105. ASSERT (!EFI_ERROR(Status));
  106. IsRootInstance = TRUE;
  107. }
  108. /*
  109. * Now we can initialize like a normal shell app
  110. */
  111. InitializeShellApplication (ImageHandle, SystemTable);
  112. /*
  113. * If there are load options, assume they contain a command line and
  114. * possible current working directory
  115. */
  116. if (ParseLoadOptions (ImageHandle, &CommandLine, &CurrentDir)) {
  117. /*
  118. * Skip the 1st argument which should be us.
  119. */
  120. while (*CommandLine != L' ' && *CommandLine != 0) {
  121. CommandLine++;
  122. }
  123. /*
  124. * Get to the beginning of the next argument.
  125. */
  126. while (*CommandLine == L' ') {
  127. CommandLine++;
  128. }
  129. /*
  130. * If there was a current working directory, set it.
  131. */
  132. if (CurrentDir) {
  133. CHAR16 CmdLine[256], *Tmp;
  134. /*
  135. * Set a mapping
  136. */
  137. StrCpy (CmdLine, CurrentDir);
  138. for (Tmp = CmdLine; *Tmp && *Tmp != L':'; Tmp++)
  139. ;
  140. if ( *Tmp ) {
  141. *(++Tmp) = 0;
  142. ShellExecute (ImageHandle, CmdLine, TRUE);
  143. }
  144. /*
  145. * Now change to that directory
  146. */
  147. StrCpy (CmdLine, L"cd ");
  148. if ((StrLen (CmdLine) + StrLen (CurrentDir) + sizeof(CHAR16)) <
  149. (sizeof(CmdLine) / sizeof(CHAR16))) {
  150. StrCat (CmdLine, CurrentDir);
  151. ShellExecute (ImageHandle, CmdLine, TRUE);
  152. }
  153. }
  154. /*
  155. * Have the shell execute the remaining command line. If there is
  156. * nothing remaining, run the shell main loop below.
  157. */
  158. if ( *CommandLine != 0 )
  159. return (ShellExecute (ImageHandle, CommandLine, TRUE));
  160. }
  161. /*
  162. * If this is the root instance, execute the command to load the default values
  163. */
  164. if (IsRootInstance) {
  165. Print (L"%EEFI Shell version %01d.%02d [%d.%d]\n%N",
  166. (ST->Hdr.Revision >> 16),
  167. (ST->Hdr.Revision & 0xffff),
  168. (ST->FirmwareRevision >> 16),
  169. (ST->FirmwareRevision & 0xffff));
  170. ShellExecute (ImageHandle, L"_load_defaults", TRUE);
  171. /* dump device mappings, -r to sync with current hardware */
  172. ShellExecute (ImageHandle, L"map -r", TRUE);
  173. /* run startup script (if any) */
  174. /*
  175. * BugBug: I turned on echo so you can tell the startup.nsh is running
  176. *
  177. * ShellExecute (ImageHandle, L"echo -off", FALSE); */
  178. ShellExecute (ImageHandle, L"startup.nsh", FALSE);
  179. /* ShellExecute (ImageHandle, L"echo -on", FALSE); */
  180. }
  181. /*
  182. * EFI Shell main loop
  183. */
  184. Status = EFI_SUCCESS;
  185. while (Status != -1) {
  186. Status = NShellPrompt (ImageHandle);
  187. }
  188. /*
  189. * Done - cleanup the shell
  190. */
  191. Status = EFI_SUCCESS;
  192. Print (L"Shell exit - %r\n", Status);
  193. /*
  194. * If this was a root instance, we allocate a dumby shell interface for ourselves
  195. * free it now
  196. */
  197. if (IsRootInstance) {
  198. BS->UninstallProtocolInterface (ImageHandle, &ShellInterfaceProtocol, SI);
  199. FreePool (SI);
  200. }
  201. return Status;
  202. }
  203. EFI_STATUS
  204. ShellLoadEnvDriverByPath (
  205. IN EFI_HANDLE ParentImageHandle,
  206. IN EFI_HANDLE DeviceHandle
  207. )
  208. {
  209. EFI_STATUS Status;
  210. EFI_DEVICE_PATH *FilePath;
  211. EFI_HANDLE NewImageHandle;
  212. UINTN Index;
  213. BOOLEAN SearchNext;
  214. /*
  215. * If there's no device to search forget it
  216. */
  217. if (!DeviceHandle) {
  218. return EFI_NOT_FOUND;
  219. }
  220. /*
  221. * Try loading shellenv from each path
  222. */
  223. SearchNext = TRUE;
  224. for (Index=0; ShellEnvPathName[Index] && SearchNext; Index++) {
  225. /*
  226. * Load it
  227. */
  228. FilePath = FileDevicePath (DeviceHandle, ShellEnvPathName[Index]);
  229. ASSERT (FilePath);
  230. Status = BS->LoadImage(FALSE, ParentImageHandle, FilePath, NULL, 0, &NewImageHandle);
  231. FreePool (FilePath);
  232. /*
  233. * Only search the next path if it was not found on this path
  234. */
  235. SearchNext = FALSE;
  236. if (Status == EFI_LOAD_ERROR || Status == EFI_NOT_FOUND) {
  237. SearchNext = TRUE;
  238. }
  239. /*
  240. * If there was no error, start the image
  241. */
  242. if (!EFI_ERROR(Status)) {
  243. Status = BS->StartImage(NewImageHandle, NULL, 0);
  244. }
  245. }
  246. return Status;
  247. }
  248. EFI_STATUS
  249. ShellLoadEnvDriver (
  250. IN EFI_HANDLE ImageHandle
  251. )
  252. {
  253. EFI_STATUS Status;
  254. EFI_LOADED_IMAGE *Image;
  255. UINTN Index, NoHandles;
  256. EFI_HANDLE *Handles;
  257. /*
  258. * Get the file path for the current image
  259. */
  260. Status = BS->HandleProtocol (ImageHandle, &LoadedImageProtocol, (VOID*)&Image);
  261. ASSERT (!EFI_ERROR(Status));
  262. /*
  263. * Attempt to load shellenv
  264. */
  265. Status = ShellLoadEnvDriverByPath (Image->ParentHandle, Image->DeviceHandle);
  266. if (EFI_ERROR(Status)) {
  267. /*
  268. * shellenv was not found. Search all filesystems for it
  269. */
  270. Status = LibLocateHandle (ByProtocol, &FileSystemProtocol, NULL, &NoHandles, &Handles);
  271. for (Index=0; Index < NoHandles; Index++) {
  272. Status = ShellLoadEnvDriverByPath (Image->ParentHandle, Handles[Index]);
  273. if (!EFI_ERROR(Status)) {
  274. break;
  275. }
  276. }
  277. if (Handles) {
  278. FreePool (Handles);
  279. }
  280. }
  281. /*
  282. * Done
  283. */
  284. return Status;
  285. }
  286. EFI_STATUS
  287. NShellPrompt (
  288. IN EFI_HANDLE ImageHandle
  289. )
  290. {
  291. CHAR16 CmdLine[256];
  292. CHAR16 *CurDir;
  293. UINTN BufferSize;
  294. EFI_STATUS Status;
  295. /*
  296. * Prompt for input
  297. */
  298. CurDir = ShellCurDir(NULL);
  299. if (CurDir) {
  300. Print (L"%E%s> ", CurDir);
  301. FreePool (CurDir);
  302. } else {
  303. Print (L"%EShell> ");
  304. }
  305. /*
  306. * Read a line from the console
  307. */
  308. BufferSize = sizeof(CmdLine)-1;
  309. Status = SI->StdIn->Read (SI->StdIn, &BufferSize, CmdLine);
  310. /*
  311. * Null terminate the string and parse it
  312. */
  313. if (!EFI_ERROR(Status)) {
  314. CmdLine[BufferSize/sizeof(CHAR16)] = 0;
  315. Status = ShellExecute (ImageHandle, CmdLine, TRUE);
  316. }
  317. /*
  318. * Done with this command
  319. */
  320. return Status;
  321. }
  322. BOOLEAN
  323. ParseLoadOptions(
  324. EFI_HANDLE ImageHandle,
  325. OUT CHAR16 **CommandLine,
  326. OUT CHAR16 **CurrentDir
  327. )
  328. {
  329. EFI_LOADED_IMAGE *Image;
  330. EFI_STATUS Status;
  331. /*
  332. * Set defaults.
  333. */
  334. *CommandLine = NULL;
  335. *CurrentDir = NULL;
  336. Status = BS->HandleProtocol (ImageHandle, &LoadedImageProtocol, (VOID*)&Image);
  337. if (!EFI_ERROR(Status)) {
  338. CHAR16 *CmdLine = Image->LoadOptions;
  339. UINT32 CmdSize = Image->LoadOptionsSize & ~1; /* make sure it is power of 2 */
  340. if (CmdLine && CmdSize) {
  341. /*
  342. * Set command line pointer for caller
  343. */
  344. *CommandLine = CmdLine;
  345. /*
  346. * See if current working directory was passed.
  347. */
  348. while ((*CmdLine != 0) && CmdSize) {
  349. CmdLine++;
  350. CmdSize -= sizeof(CHAR16);
  351. }
  352. /*
  353. * If a current working directory was passed, set it.
  354. */
  355. if (CmdSize > sizeof(CHAR16)) {
  356. *CurrentDir = ++CmdLine;
  357. }
  358. return TRUE;
  359. }
  360. }
  361. return FALSE;
  362. }