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