1 /** @file
2 Dir for EBL (Embedded Boot Loader)
3
4 Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
6 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
7
8
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17 Module Name: CmdTemplate.c
18
19 Search/Replace Dir with the name of your new command
20
21 **/
22
23 #include "Ebl.h"
24
25
26 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *gFvFileType[] = {
27 "All",
28 "Bin",
29 "section",
30 "SEC",
31 "PeiCore",
32 "DxeCore",
33 "PEIM",
34 "Driver",
35 "Combo",
36 "App",
37 "NULL",
38 "FV"
39 };
40
41
42 /**
43 Perform a dir on a device. The device must support Simple File System Protocol
44 or the FV protocol.
45
46 Argv[0] - "dir"
47 Argv[1] - Device Name:path. Path is optional
48 Argv[2] - Optional filename to match on. A leading * means match substring
49 Argv[3] - Optional FV file type
50
51 dir fs1:\efi ; perform a dir on fs1: device in the efi directory
52 dir fs1:\efi *.efi; perform a dir on fs1: device in the efi directory but
53 only print out files that contain the string *.efi
54 dir fv1:\ ; perform a dir on fv1: device in the efi directory
55 NOTE: fv devices do not contain subdirs
56 dir fv1:\ * PEIM ; will match all files of type PEIM
57
58 @param Argc Number of command arguments in Argv
59 @param Argv Array of strings that represent the parsed command line.
60 Argv[0] is the command name
61
62 @return EFI_SUCCESS
63
64 **/
65 EFI_STATUS
66 EFIAPI
EblDirCmd(IN UINTN Argc,IN CHAR8 ** Argv)67 EblDirCmd (
68 IN UINTN Argc,
69 IN CHAR8 **Argv
70 )
71 {
72 EFI_STATUS Status;
73 EFI_OPEN_FILE *File;
74 EFI_FILE_INFO *DirInfo;
75 UINTN ReadSize;
76 UINTN CurrentRow;
77 CHAR16 *MatchSubString;
78 EFI_STATUS GetNextFileStatus;
79 UINTN Key;
80 EFI_FV_FILETYPE SearchType;
81 EFI_FV_FILETYPE Type;
82 EFI_FV_FILE_ATTRIBUTES Attributes;
83 UINTN Size;
84 EFI_GUID NameGuid;
85 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
86 UINT32 AuthenticationStatus;
87 VOID *Section;
88 UINTN SectionSize;
89 EFI_FV_FILETYPE Index;
90 UINTN Length;
91 UINTN BestMatchCount;
92 CHAR16 UnicodeFileName[MAX_CMD_LINE];
93 CHAR8 *Path;
94 CHAR8 *TypeStr;
95 UINTN TotalSize;
96
97
98 if (Argc <= 1) {
99 Path = EfiGetCwd ();
100 if (Path == NULL) {
101 return EFI_SUCCESS;
102 }
103 } else {
104 Path = Argv[1];
105 }
106
107 File = EfiOpen (Path, EFI_FILE_MODE_READ, 0);
108 if (File == NULL) {
109 return EFI_SUCCESS;
110 }
111
112 if (File->Type == EfiOpenFirmwareVolume) {
113 // FV Dir
114
115 SearchType = EFI_FV_FILETYPE_ALL;
116 UnicodeFileName[0] = '\0';
117 MatchSubString = &UnicodeFileName[0];
118 if (Argc > 2) {
119 AsciiStrToUnicodeStr (Argv[2], UnicodeFileName);
120 if (UnicodeFileName[0] == '*') {
121 // Handle *Name substring matching
122 MatchSubString = &UnicodeFileName[1];
123 }
124
125 // Handle file type matchs
126 if (Argc > 3) {
127 // match a specific file type, always last argument
128 Length = AsciiStrLen (Argv[3]);
129 for (Index = 1, BestMatchCount = 0; Index < sizeof (gFvFileType)/sizeof (CHAR8 *); Index++) {
130 if (AsciiStriCmp (gFvFileType[Index], Argv[3]) == 0) {
131 // exact match
132 SearchType = Index;
133 break;
134 }
135
136 if (AsciiStrniCmp (Argv[3], gFvFileType[Index], Length) == 0) {
137 // partial match, so keep looking to make sure there is only one partial match
138 BestMatchCount++;
139 SearchType = Index;
140 }
141 }
142
143 if (BestMatchCount > 1) {
144 SearchType = EFI_FV_FILETYPE_ALL;
145 }
146 }
147 }
148
149 TotalSize = 0;
150 Fv = File->Fv;
151 Key = 0;
152 CurrentRow = 0;
153 do {
154 Type = SearchType;
155 GetNextFileStatus = Fv->GetNextFile (
156 Fv,
157 &Key,
158 &Type,
159 &NameGuid,
160 &Attributes,
161 &Size
162 );
163 if (!EFI_ERROR (GetNextFileStatus)) {
164 TotalSize += Size;
165 // Calculate size of entire file
166 Section = NULL;
167 Size = 0;
168 Status = Fv->ReadFile (
169 Fv,
170 &NameGuid,
171 Section,
172 &Size,
173 &Type,
174 &Attributes,
175 &AuthenticationStatus
176 );
177 if (!((Status == EFI_BUFFER_TOO_SMALL) || !EFI_ERROR (Status))) {
178 // EFI_SUCCESS or EFI_BUFFER_TOO_SMALL mean size is valid
179 Size = 0;
180 }
181
182 TypeStr = (Type <= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) ? gFvFileType[Type] : "UNKNOWN";
183
184 // read the UI seciton to do a name match.
185 Section = NULL;
186 Status = Fv->ReadSection (
187 Fv,
188 &NameGuid,
189 EFI_SECTION_USER_INTERFACE,
190 0,
191 &Section,
192 &SectionSize,
193 &AuthenticationStatus
194 );
195 if (!EFI_ERROR (Status)) {
196 if (StrStr (Section, MatchSubString) != NULL) {
197 AsciiPrint ("%,9d %7a %g %s\n", Size, TypeStr, &NameGuid, Section);
198 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
199 break;
200 }
201 }
202 FreePool (Section);
203 } else {
204 if (*MatchSubString == '\0') {
205 AsciiPrint ("%,9d %7a %g\n", Size, TypeStr, &NameGuid);
206 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
207 break;
208 }
209 }
210 }
211 }
212 } while (!EFI_ERROR (GetNextFileStatus));
213
214 if (SearchType == EFI_FV_FILETYPE_ALL) {
215 AsciiPrint ("%,20d bytes in files %,d bytes free\n", TotalSize, File->FvSize - File->FvHeaderSize - TotalSize);
216 }
217
218
219 } else if ((File->Type == EfiOpenFileSystem) || (File->Type == EfiOpenBlockIo)) {
220 // Simple File System DIR
221
222 if (File->FsFileInfo == NULL) {
223 return EFI_SUCCESS;
224 }
225
226 if (!(File->FsFileInfo->Attribute & EFI_FILE_DIRECTORY)) {
227 return EFI_SUCCESS;
228 }
229
230 // Handle *Name substring matching
231 MatchSubString = NULL;
232 UnicodeFileName[0] = '\0';
233 if (Argc > 2) {
234 AsciiStrToUnicodeStr (Argv[2], UnicodeFileName);
235 if (UnicodeFileName[0] == '*') {
236 MatchSubString = &UnicodeFileName[1];
237 }
238 }
239
240 File->FsFileHandle->SetPosition (File->FsFileHandle, 0);
241 for (CurrentRow = 0;;) {
242 // First read gets the size
243 DirInfo = NULL;
244 ReadSize = 0;
245 Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo);
246 if (Status == EFI_BUFFER_TOO_SMALL) {
247 // Allocate the buffer for the real read
248 DirInfo = AllocatePool (ReadSize);
249 if (DirInfo == NULL) {
250 goto Done;
251 }
252
253 // Read the data
254 Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo);
255 if ((EFI_ERROR (Status)) || (ReadSize == 0)) {
256 break;
257 }
258 } else {
259 break;
260 }
261
262 if (MatchSubString != NULL) {
263 if (StrStr (&DirInfo->FileName[0], MatchSubString) == NULL) {
264 // does not match *name argument, so skip
265 continue;
266 }
267 } else if (UnicodeFileName[0] != '\0') {
268 // is not an exact match for name argument, so skip
269 if (StrCmp (&DirInfo->FileName[0], UnicodeFileName) != 0) {
270 continue;
271 }
272 }
273
274 if (DirInfo->Attribute & EFI_FILE_DIRECTORY) {
275 AsciiPrint (" <DIR> %s\n", &DirInfo->FileName[0]);
276 } else {
277 AsciiPrint ("%,14ld %s\n", DirInfo->FileSize, &DirInfo->FileName[0]);
278 }
279
280 if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
281 break;
282 }
283
284 FreePool (DirInfo);
285 }
286
287 Done:
288 if (DirInfo != NULL) {
289 FreePool (DirInfo);
290 }
291 }
292
293 EfiClose (File);
294
295 return EFI_SUCCESS;
296 }
297
298 /**
299 Change the Current Working Directory
300
301 Argv[0] - "cd"
302 Argv[1] - Device Name:path. Path is optional
303
304 @param Argc Number of command arguments in Argv
305 @param Argv Array of strings that represent the parsed command line.
306 Argv[0] is the command name
307
308 @return EFI_SUCCESS
309
310 **/
311 EFI_STATUS
312 EFIAPI
EblCdCmd(IN UINTN Argc,IN CHAR8 ** Argv)313 EblCdCmd (
314 IN UINTN Argc,
315 IN CHAR8 **Argv
316 )
317 {
318 if (Argc <= 1) {
319 return EFI_SUCCESS;
320 }
321
322 return EfiSetCwd (Argv[1]);
323 }
324
325
326
327 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDirTemplate[] =
328 {
329 {
330 "dir",
331 " dirdev [*match]; directory listing of dirdev. opt match a substring",
332 NULL,
333 EblDirCmd
334 },
335 {
336 "cd",
337 " device - set the current working directory",
338 NULL,
339 EblCdCmd
340 }
341 };
342
343
344 /**
345 Initialize the commands in this in this file
346 **/
347 VOID
EblInitializeDirCmd(VOID)348 EblInitializeDirCmd (
349 VOID
350 )
351 {
352 if (FeaturePcdGet (PcdEmbeddedDirCmd)) {
353 EblAddCommands (mCmdDirTemplate, sizeof (mCmdDirTemplate)/sizeof (EBL_COMMAND_TABLE));
354 }
355 }
356
357