/*++ Copyright (c) 1998 Intel Corporation Module Name: map.c Abstract: Shell environment short device name mapping information management Revision History --*/ #include "shelle.h" /* * */ extern LIST_ENTRY SEnvMap; STATIC CHAR16 *SEnvCurDevice; /* * */ VOID SEnvInitMap ( VOID ) { /* * The mapping data is read in from the variable init. */ /* * Init the default map device */ SEnvCurDevice = StrDuplicate(L"none"); } CHAR16 * SEnvGetDefaultMapping ( IN EFI_HANDLE ImageHandle ) { EFI_LOADED_IMAGE *LoadedImage; EFI_STATUS Status; LIST_ENTRY *Head; LIST_ENTRY *Link; VARIABLE_ID *Var; EFI_HANDLE Handle; EFI_DEVICE_PATH *DevicePath; Status = BS->HandleProtocol (ImageHandle, &LoadedImageProtocol, (VOID*)&LoadedImage); if (EFI_ERROR(Status) || LoadedImage==NULL) { return NULL; } Head = &SEnvMap; for (Link=Head->Flink; Link != Head; Link=Link->Flink) { Var = CR(Link, VARIABLE_ID, Link, VARIABLE_SIGNATURE); DevicePath = (EFI_DEVICE_PATH *)Var->u.Str; Status = BS->LocateDevicePath(&DevicePathProtocol,&DevicePath,&Handle); if (!EFI_ERROR(Status) && Handle!=NULL) { if (LoadedImage->DeviceHandle == Handle) { return(Var->Name); } } } return NULL; } VOID SEnvDumpMapping( IN UINTN SLen, IN BOOLEAN Verbose, IN VARIABLE_ID *Var ) { CHAR16 *p; EFI_DEVICE_PATH *DPath; EFI_STATUS Status; EFI_HANDLE DeviceHandle; p = DevicePathToStr ((EFI_DEVICE_PATH *) Var->u.Str); Print(L" %h-.*s : %s\n", SLen, Var->Name, p); if (Verbose) { /* lookup handle for this mapping */ DPath = (EFI_DEVICE_PATH *) Var->u.Value; Status = BS->LocateDevicePath (&DevicePathProtocol, &DPath, &DeviceHandle); if (EFI_ERROR(Status)) { Print(L"%*s= Handle for this mapping not found\n", SLen+3); } else { Print(L"%*s= Handle", SLen + 3, L""); SEnvDHProt (FALSE, 0, DeviceHandle); } /* print current directory for this mapping */ Print(L"%*s> %s\n\n", SLen+3, L"", Var->CurDir ? Var->CurDir : L"\\"); } FreePool (p); } EFI_STATUS SEnvCmdMap ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) /* Code for internal "map" command */ { LIST_ENTRY *Link, *Head; VARIABLE_ID *Var; VARIABLE_ID *Found; CHAR16 *Name; CHAR16 *Value; UINTN SLen, Len; UINTN Size, DataSize; BOOLEAN Delete, Verbose, Remap; EFI_STATUS Status; UINTN Index; CHAR16 *p; EFI_HANDLE Handle; EFI_DEVICE_PATH *DevicePath; BOOLEAN PageBreaks; UINTN TempColumn; UINTN ScreenCount; UINTN ScreenSize; CHAR16 ReturnStr[1]; InitializeShellApplication (ImageHandle, SystemTable); Head = &SEnvMap; Name = NULL; Value = NULL; Delete = FALSE; Verbose = FALSE; Remap = FALSE; Status = EFI_SUCCESS; Found = NULL; /* * Crack arguments */ PageBreaks = FALSE; for (Index = 1; Index < SI->Argc; Index += 1) { p = SI->Argv[Index]; if (*p == '-') { switch (p[1]) { case 'd': case 'D': Delete = TRUE; break; case 'v': case 'V': Verbose = TRUE; break; case 'r': case 'R': Remap = TRUE; break; case 'b' : case 'B' : PageBreaks = TRUE; ST->ConOut->QueryMode (ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize); ScreenCount = 0; break; default: Print (L"Map: Unkown flag %s\n", p); return EFI_INVALID_PARAMETER; } continue; } if (!Name) { Name = p; continue; } if (!Value) { Value = p; continue; } Print (L"Map: too many arguments\n"); return EFI_INVALID_PARAMETER; } if (Delete && Value) { Print (L"Map: too many arguments\n"); } /* * Process */ if (Remap && !Value && !Delete) { AcquireLock (&SEnvLock); for (Link=Head->Flink; Link != Head;) { Var = CR(Link, VARIABLE_ID, Link, VARIABLE_SIGNATURE); Status = RT->SetVariable (Var->Name, &SEnvMapId, 0, 0, NULL); Link = Link->Flink; RemoveEntryList (&Var->Link); FreePool (Var); } ReleaseLock (&SEnvLock); Status = SEnvReloadDefaults (ImageHandle,SystemTable); Remap = FALSE; } if (Value || Verbose) { SEnvLoadHandleTable (); if (Verbose) { SEnvLoadHandleProtocolInfo (&DevicePathProtocol); } } AcquireLock (&SEnvLock); SLen = 0; for (Link=Head->Flink; Link != Head; Link=Link->Flink) { Var = CR(Link, VARIABLE_ID, Link, VARIABLE_SIGNATURE); Len = StrLen(Var->Name); if (Len > SLen) { SLen = Len; } } if (!Name) { Print (L"%EDevice mapping table%N\n"); for (Link=Head->Flink; Link != Head; Link=Link->Flink) { Var = CR(Link, VARIABLE_ID, Link, VARIABLE_SIGNATURE); SEnvDumpMapping(SLen, Verbose, Var); if (PageBreaks) { ScreenCount++; if (ScreenCount > ScreenSize - 4) { ScreenCount = 0; Print (L"\nPress Return to contiue :"); Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16)); Print (L"\n\n"); } } } } else { /* * Find the specified value */ for (Link=Head->Flink; Link != Head; Link=Link->Flink) { Var = CR(Link, VARIABLE_ID, Link, VARIABLE_SIGNATURE); if (StriCmp(Var->Name, Name) == 0) { Found = Var; break; } } if (Found && Delete) { /* * Remove it from the store */ Status = RT->SetVariable (Found->Name, &SEnvMapId, 0, 0, NULL); } else if (Value) { /* * Find the handle in question */ Handle = SEnvHandleFromStr(Value); if (!Handle) { Print(L"map: Handle not found\n"); Status = EFI_NOT_FOUND; goto Done; } /* * Get the handle's device path */ DevicePath = DevicePathFromHandle(Handle); if (!DevicePath) { Print(L"map: handle does not have a device path\n"); Status = EFI_INVALID_PARAMETER; goto Done; } DataSize = DevicePathSize(DevicePath); /* * Add it to the store */ Status = RT->SetVariable ( Found ? Found->Name : Name, &SEnvMapId, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, DataSize, DevicePath ); if (!EFI_ERROR(Status)) { /* * Make a new in memory copy */ Size = sizeof(VARIABLE_ID) + StrSize(Name) + DataSize; Var = AllocateZeroPool (Size); Var->Signature = VARIABLE_SIGNATURE; Var->u.Value = ((UINT8 *) Var) + sizeof(VARIABLE_ID); Var->Name = (CHAR16*) (Var->u.Value + DataSize); Var->ValueSize = DataSize; CopyMem (Var->u.Value, DevicePath, DataSize); StrCpy (Var->Name, Found ? Found->Name : Name); InsertTailList (Head, &Var->Link); } } else { if (Found) { SEnvDumpMapping(SLen, Verbose, Var); } else { Print(L"map: '%es' not found\n", Name); } Found = NULL; } /* * Remove the old in memory copy if there was one */ if (Found) { RemoveEntryList (&Found->Link); FreePool (Found); } } Done: ReleaseLock (&SEnvLock); SEnvFreeHandleTable (); return Status; } VARIABLE_ID * SEnvMapDeviceFromName ( IN OUT CHAR16 **pPath ) /* Check the Path for a device name, and updates the path to point after * the device name. If no device name is found, the current default is used. */ { CHAR16 *Path, *p; CHAR16 *MappedName, c; VARIABLE_ID *Var; LIST_ENTRY *Link; ASSERT_LOCKED (&SEnvLock); Var = NULL; Path = *pPath; /* * Check for a device name terminator */ for(p = Path; *p && *p != ':' && *p != '\\'; p++) ; /* * Use either the passed in name or the current device name setting */ MappedName = *p == ':' ? Path : SEnvCurDevice; /* * Null terminate the string in Path just in case that is the one we * are using */ c = *p; *p = 0; /* * Find the mapping for the device */ for (Link=SEnvMap.Flink; Link != &SEnvMap; Link=Link->Flink) { Var = CR(Link, VARIABLE_ID, Link, VARIABLE_SIGNATURE); if (StriCmp(Var->Name, MappedName) == 0) { break; } } /* * Restore the path */ *p = c; /* * If the mapped device was not found, return NULL */ if (Link == &SEnvMap) { DEBUG((D_PARSE, "SEnvNameToPath: Mapping for '%es' not found\n", Path)); return NULL; } /* * If we found it as part of the path, skip the path over it */ if (MappedName == Path) { *pPath = p + 1; } /* * Return the target mapping */ return Var; } EFI_DEVICE_PATH * SEnvIFileNameToPath ( IN CHAR16 *Path ) /* Builds a device path from the filename string. Note that the * device name must already be stripped off of the file name string */ { CHAR16 *LPath, *ps; BOOLEAN UseLPath; EFI_DEVICE_PATH *DPath, *Node, *NewPath; CHAR16 Buffer[MAX_ARG_LENGTH]; UINTN Index; ASSERT_LOCKED (&SEnvLock); DPath = NULL; /* * If no path, return the root */ if (!*Path) { DPath = FileDevicePath(NULL, L"\\"); } /* * Build a file path for the name component(s) */ while (*Path) { Index = 0; LPath = NULL; UseLPath = FALSE; ps = Path; while (*ps) { /* if buffer has run out, just handle to LPath */ if (Index > MAX_ARG_LENGTH-2 || *ps == '#') { UseLPath = TRUE; break; } if (*ps == '^') { if (ps[1]) { ps += 1; Buffer[Index++] = *ps; } ps += 1; continue; } if (*ps == '\\') { LPath = ps; } Buffer[Index++] = *ps; ps += 1; } if (UseLPath) { Index = LPath ? LPath - Path : 0; ps = Path + Index; } /* * If we have part of a path name, append it to the device path */ if (Index) { Buffer[Index] = 0; Node = FileDevicePath(NULL, Buffer); NewPath = AppendDevicePath (DPath, Node); FreePool (Node); if (DPath) { FreePool (DPath); } DPath = NewPath; } if (*ps == 0) { break; } Path = ps + 1; } return DPath; } EFI_DEVICE_PATH * SEnvFileNameToPath ( IN CHAR16 *Path ) { EFI_DEVICE_PATH *FilePath; AcquireLock (&SEnvLock); FilePath = SEnvIFileNameToPath (Path); ReleaseLock (&SEnvLock); return FilePath; } EFI_DEVICE_PATH * SEnvINameToPath ( IN CHAR16 *Path ) /* Convert a filesystem stlye name to an file path */ { EFI_DEVICE_PATH *DPath, *FPath, *RPath, *FilePath; VARIABLE_ID *Var; BOOLEAN FreeDPath; DPath = NULL; RPath = NULL; FPath = NULL; FilePath = NULL; FreeDPath = FALSE; ASSERT_LOCKED (&SEnvLock); /* * Get the device for the name, and advance past the device name */ Var = SEnvMapDeviceFromName (&Path); if (!Var) { DEBUG((D_PARSE, "SEnvNameToPath: mapped device not found\n")); goto Done; } /* * Start the file path with this mapping */ DPath = (EFI_DEVICE_PATH *) Var->u.Value; /* * If the path is realitve, append the current dir of the device to the dpath */ if (*Path != '\\') { RPath = SEnvIFileNameToPath (Var->CurDir ? Var->CurDir : L"\\"); DPath = AppendDevicePath (DPath, RPath); FreeDPath = TRUE; } /* * Build a file path for the rest of the name string */ FPath = SEnvIFileNameToPath (Path); /* * Append the 2 paths */ FilePath = AppendDevicePath(DPath, FPath); /* * Done */ Done: if (DPath && FreeDPath) { FreePool (DPath); } if (RPath) { FreePool (RPath); } if (FPath) { FreePool (FPath); } return FilePath; } EFI_DEVICE_PATH * SEnvNameToPath ( IN CHAR16 *Path ) { EFI_DEVICE_PATH *DPath; AcquireLock (&SEnvLock); DPath = SEnvINameToPath (Path); ReleaseLock (&SEnvLock); return DPath; } EFI_STATUS SEnvCmdCd ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_DEVICE_PATH *FilePath; EFI_STATUS Status; EFI_FILE_HANDLE OpenDir; CHAR16 *Dir; CHAR16 *CurDir; VARIABLE_ID *Var; EFI_FILE_INFO *FileInfo; InitializeShellApplication (ImageHandle, SystemTable); FilePath = NULL; /* * If no arguments, print the current directory */ if (SI->Argc == 1) { Dir = SEnvGetCurDir(NULL); if (Dir) { Print (L"%s\n", Dir); FreePool (Dir); } else { Print (L"no current directory\n"); } return EFI_SUCCESS; } AcquireLock (&SEnvLock); /* * If more then 1 argument, syntax */ if (SI->Argc > 2) { Print (L"cd: too many arguments\n"); Status =EFI_INVALID_PARAMETER; goto Done; } /* * Find the target device */ Dir = SI->Argv[1]; Var = SEnvMapDeviceFromName (&Dir); if (!Var) { Print(L"cd: mapped device not found\n"); Status = EFI_NOT_FOUND; goto Done; } /* * If there's no path specified, print the current path for the device */ if (*Dir == 0) { Print (L"%s\n", Var->CurDir ? Var->CurDir : L"\\"); Status = EFI_SUCCESS; goto Done; } /* * Build a file path for the argument */ FilePath = SEnvINameToPath (SI->Argv[1]); if (!FilePath) { Status = EFI_NOT_FOUND; goto Done; } /* * Open the target directory */ OpenDir = ShellOpenFilePath(FilePath, EFI_FILE_MODE_READ); if (!OpenDir) { Print (L"cd: target directory not found\n"); Status = EFI_NOT_FOUND; goto Done; } /* * Get information on the file path that was opened. */ FileInfo = LibFileInfo(OpenDir); if (FileInfo == NULL) { Status = EFI_NOT_FOUND; goto Done; } /* * Verify that the file opened is a directory. */ if (!(FileInfo->Attribute & EFI_FILE_DIRECTORY)) { Print (L"cd: target is not a directory\n"); FreePool (FileInfo); OpenDir->Close (OpenDir); Status = EFI_NOT_FOUND; goto Done; } FreePool (FileInfo); CurDir = SEnvFileHandleToFileName(OpenDir); OpenDir->Close (OpenDir); /* * If we have a new path, update the device */ if (CurDir) { if (Var->CurDir) { FreePool(Var->CurDir); } Var->CurDir = CurDir; } else { Print (L"cd: could not cd to '%hs%'\n", FilePath); } Status = EFI_SUCCESS; Done: ReleaseLock (&SEnvLock); if (FilePath) { FreePool (FilePath); } return Status; } CHAR16 * SEnvGetCurDir ( IN CHAR16 *DeviceName OPTIONAL ) /* N.B. results are allocated in pool */ { CHAR16 *Dir; LIST_ENTRY *Link; VARIABLE_ID *Var; Dir = NULL; if (!DeviceName) { DeviceName = SEnvCurDevice; } AcquireLock (&SEnvLock); for (Link=SEnvMap.Flink; Link != &SEnvMap; Link=Link->Flink) { Var = CR(Link, VARIABLE_ID, Link, VARIABLE_SIGNATURE); if (StriCmp(Var->Name, DeviceName) == 0) { Dir = PoolPrint(L"%s:%s", Var->Name, Var->CurDir ? Var->CurDir : L"\\"); break; } } ReleaseLock (&SEnvLock); return Dir; } EFI_STATUS SEnvSetCurrentDevice ( IN CHAR16 *Name ) { VARIABLE_ID *Var; LIST_ENTRY *Link; EFI_STATUS Status; UINTN Len; CHAR16 *NewName, c; Len = StrLen(Name); if (Len < 1) { return EFI_INVALID_PARAMETER; } /* * If the name ends with a ":" strip it off */ Len -= 1; c = Name[Len]; if (c == ':') { Name[Len] = 0; } Status = EFI_NO_MAPPING; AcquireLock (&SEnvLock); for (Link=SEnvMap.Flink; Link != &SEnvMap; Link=Link->Flink) { Var = CR(Link, VARIABLE_ID, Link, VARIABLE_SIGNATURE); if (StriCmp(Var->Name, Name) == 0) { NewName = StrDuplicate(Name); if (NewName) { FreePool (SEnvCurDevice); SEnvCurDevice = NewName; } Status = EFI_SUCCESS; break; } } ReleaseLock (&SEnvLock); /* * Restore the name */ Name[Len] = c; return Status; }