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       AsciiStrToUnicodeStrS (Argv[2], UnicodeFileName,
120         ARRAY_SIZE (UnicodeFileName));
121       if (UnicodeFileName[0] == '*') {
122         // Handle *Name substring matching
123         MatchSubString = &UnicodeFileName[1];
124       }
125 
126       // Handle file type matchs
127       if (Argc > 3) {
128         // match a specific file type, always last argument
129         Length = AsciiStrLen (Argv[3]);
130         for (Index = 1, BestMatchCount = 0; Index < sizeof (gFvFileType)/sizeof (CHAR8 *); Index++) {
131           if (AsciiStriCmp (gFvFileType[Index], Argv[3]) == 0) {
132             // exact match
133             SearchType = Index;
134             break;
135           }
136 
137           if (AsciiStrniCmp (Argv[3], gFvFileType[Index], Length) == 0) {
138             // partial match, so keep looking to make sure there is only one partial match
139             BestMatchCount++;
140             SearchType = Index;
141           }
142         }
143 
144         if (BestMatchCount > 1) {
145           SearchType = EFI_FV_FILETYPE_ALL;
146         }
147       }
148     }
149 
150     TotalSize = 0;
151     Fv = File->Fv;
152     Key = 0;
153     CurrentRow = 0;
154     do {
155       Type = SearchType;
156       GetNextFileStatus = Fv->GetNextFile (
157                                 Fv,
158                                 &Key,
159                                 &Type,
160                                 &NameGuid,
161                                 &Attributes,
162                                 &Size
163                                 );
164       if (!EFI_ERROR (GetNextFileStatus)) {
165         TotalSize += Size;
166         // Calculate size of entire file
167         Section = NULL;
168         Size = 0;
169         Status = Fv->ReadFile (
170                       Fv,
171                       &NameGuid,
172                       Section,
173                       &Size,
174                       &Type,
175                       &Attributes,
176                       &AuthenticationStatus
177                       );
178         if (!((Status == EFI_BUFFER_TOO_SMALL) || !EFI_ERROR (Status))) {
179           // EFI_SUCCESS or EFI_BUFFER_TOO_SMALL mean size is valid
180           Size = 0;
181         }
182 
183         TypeStr = (Type <= EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) ? gFvFileType[Type] : "UNKNOWN";
184 
185         // read the UI seciton to do a name match.
186         Section = NULL;
187         Status = Fv->ReadSection (
188                         Fv,
189                         &NameGuid,
190                         EFI_SECTION_USER_INTERFACE,
191                         0,
192                         &Section,
193                         &SectionSize,
194                         &AuthenticationStatus
195                         );
196         if (!EFI_ERROR (Status)) {
197           if (StrStr (Section, MatchSubString) != NULL) {
198             AsciiPrint ("%,9d %7a %g %s\n", Size, TypeStr, &NameGuid, Section);
199             if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
200               break;
201             }
202           }
203           FreePool (Section);
204         } else {
205           if (*MatchSubString == '\0') {
206             AsciiPrint ("%,9d %7a %g\n", Size, TypeStr, &NameGuid);
207             if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
208               break;
209             }
210           }
211         }
212       }
213     } while (!EFI_ERROR (GetNextFileStatus));
214 
215     if (SearchType == EFI_FV_FILETYPE_ALL) {
216       AsciiPrint ("%,20d bytes in files %,d bytes free\n", TotalSize, File->FvSize - File->FvHeaderSize - TotalSize);
217     }
218 
219 
220   } else if ((File->Type == EfiOpenFileSystem) || (File->Type == EfiOpenBlockIo)) {
221     // Simple File System DIR
222 
223     if (File->FsFileInfo ==  NULL) {
224       return EFI_SUCCESS;
225     }
226 
227     if (!(File->FsFileInfo->Attribute & EFI_FILE_DIRECTORY)) {
228       return EFI_SUCCESS;
229     }
230 
231     // Handle *Name substring matching
232     MatchSubString = NULL;
233     UnicodeFileName[0] = '\0';
234     if (Argc > 2) {
235       AsciiStrToUnicodeStrS (Argv[2], UnicodeFileName, MAX_CMD_LINE);
236       if (UnicodeFileName[0] == '*') {
237         MatchSubString = &UnicodeFileName[1];
238       }
239     }
240 
241     File->FsFileHandle->SetPosition (File->FsFileHandle, 0);
242     for (CurrentRow = 0;;) {
243       // First read gets the size
244       DirInfo = NULL;
245       ReadSize = 0;
246       Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo);
247       if (Status == EFI_BUFFER_TOO_SMALL) {
248         // Allocate the buffer for the real read
249         DirInfo = AllocatePool (ReadSize);
250         if (DirInfo == NULL) {
251           goto Done;
252         }
253 
254         // Read the data
255         Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo);
256         if ((EFI_ERROR (Status)) || (ReadSize == 0)) {
257           break;
258         }
259       } else {
260         break;
261       }
262 
263       if (MatchSubString != NULL) {
264         if (StrStr (&DirInfo->FileName[0], MatchSubString) == NULL) {
265           // does not match *name argument, so skip
266           continue;
267         }
268       } else if (UnicodeFileName[0] != '\0') {
269         // is not an exact match for name argument, so skip
270         if (StrCmp (&DirInfo->FileName[0], UnicodeFileName) != 0) {
271           continue;
272         }
273       }
274 
275       if (DirInfo->Attribute & EFI_FILE_DIRECTORY) {
276         AsciiPrint ("         <DIR> %s\n", &DirInfo->FileName[0]);
277       } else {
278         AsciiPrint ("%,14ld %s\n", DirInfo->FileSize, &DirInfo->FileName[0]);
279       }
280 
281       if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) {
282         break;
283       }
284 
285       FreePool (DirInfo);
286     }
287 
288 Done:
289     if (DirInfo != NULL) {
290       FreePool (DirInfo);
291     }
292   }
293 
294   EfiClose (File);
295 
296   return EFI_SUCCESS;
297 }
298 
299 /**
300   Change the Current Working Directory
301 
302   Argv[0] - "cd"
303   Argv[1] - Device Name:path. Path is optional
304 
305   @param  Argc   Number of command arguments in Argv
306   @param  Argv   Array of strings that represent the parsed command line.
307                  Argv[0] is the command name
308 
309   @return EFI_SUCCESS
310 
311 **/
312 EFI_STATUS
313 EFIAPI
EblCdCmd(IN UINTN Argc,IN CHAR8 ** Argv)314 EblCdCmd (
315   IN UINTN  Argc,
316   IN CHAR8  **Argv
317   )
318 {
319   if (Argc <= 1) {
320     return EFI_SUCCESS;
321   }
322 
323   return EfiSetCwd (Argv[1]);
324 }
325 
326 
327 
328 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDirTemplate[] =
329 {
330   {
331     "dir",
332     " dirdev [*match]; directory listing of dirdev. opt match a substring",
333     NULL,
334     EblDirCmd
335   },
336   {
337     "cd",
338     " device - set the current working directory",
339     NULL,
340     EblCdCmd
341   }
342 };
343 
344 
345 /**
346   Initialize the commands in this in this file
347 **/
348 VOID
EblInitializeDirCmd(VOID)349 EblInitializeDirCmd (
350   VOID
351   )
352 {
353   if (FeaturePcdGet (PcdEmbeddedDirCmd)) {
354     EblAddCommands (mCmdDirTemplate, sizeof (mCmdDirTemplate)/sizeof (EBL_COMMAND_TABLE));
355   }
356 }
357 
358