+0.2.7 (?/??/2012):
+------------------
+
+- Fixed bug that caused rEFInd to show up in its own menu sometimes.
+
+- Added new refind.conf token: also_scan_dirs. When scanning volumes for
+ EFI boot loaders, rEFInd always scans the root directory and every
+ subdirectory of the /EFI directory, but it doesn't recurse into these
+ directories. The also_scan_dirs token adds more directories to the scan
+ list. It defaults to "elilo,boot", but you can set it to any directory or
+ directories you like.
+
0.2.6 (4/14/2012):
------------------
<td><tt>internal</tt>, <tt>external</tt>, <tt>optical</tt>, <tt>hdbios</tt>, <tt>biosexternal</tt>, <tt>cd</tt>, and <tt>manual</tt></td>
<td>Tells rEFInd what methods to use to locate boot loaders. The <tt>internal</tt>, <tt>external</tt>, and <tt>optical</tt> parameters tell rEFInd to scan for EFI boot loaders on internal, external, and optical (CD, DVD, and Blu-ray) devices, respectively. The <tt>hdbios</tt>, <tt>biosexternal</tt>, and <tt>cd</tt> parameters are similar, but scan for BIOS boot loaders. (Note that the BIOS options are likely to be useless on UEFI PCs.) The <tt>manual</tt> parameter tells rEFInd to scan the configuration file for manual settings. You can specify multiple parameters to have the program scan for multiple boot loader types. When you do so, the order determines the order in which the boot loaders appear in the menu. The default is <tt>internal, external, optical</tt>.</td>
</tr>
+<tr>
+ <td><tt>also_scan_dirs</tt></td>
+ <td>directory path(s)</td>
+ <td>Adds the specified directory or directories to the directory list that rEFInd scans for EFI boot loaders when <tt>scanfor</tt> includes the <tt>internal</tt>, <tt>external</tt>, or <tt>optical</tt> options. Directories are specified relative to the filesystem's root directory. If this option is used, it's applied to <i>all</i> the filesystems that rEFInd scans. If a specified directory doesn't exist, rEFInd ignores it (no error results).</td>
+</tr>
<tr>
<td><tt>default_selection</tt></td>
<td>A substring of a boot loader's title</td>
# systems)
# reboot - a tag to reboot the computer
# Default is shell,about,shutdown,reboot
+#
#showtools shell, about, reboot
# Which types of boot loaders to search, and in what order to display them:
# cd - BIOS optical-disc boot loaders
# manual - use stanzas later in this configuration file
# Default is internal,external,optical
-scanfor internal,external,optical
+#
+#scanfor internal,external,optical
+
+# When scanning volumes for EFI boot loaders, rEFInd always looks for
+# Mac OS X's and Microsoft Windows' boot loaders in their normal locations,
+# and scans the root directory and every subdirectory of the /EFI directory
+# for additional boot loaders, but it doesn't recurse into these directories.
+# The also_scan_dirs token adds more directories to the scan list.
+# Directories are specified relative to the volume's root directory. This
+# option applies to ALL the volumes that rEFInd scans. If a specified
+# directory doesn't exist, it's ignored (no error condition results).
+# The default is to scan no additional directories.
+#
+#also_scan_dirs boot,EFI/linux/kernels
# Set the maximum number of tags that can be displayed on the screen at
# any time. If more loaders are discovered than this value, rEFInd shows
else
GlobalConfig.ScanFor[i] = ' ';
}
- } else if (StriCmp(TokenList[0], L"showtools") == 0) {
+
+ } else if (StriCmp(TokenList[0], L"also_scan_dirs") == 0) {
+ if (GlobalConfig.AlsoScan != NULL) {
+ FreePool(GlobalConfig.AlsoScan);
+ GlobalConfig.AlsoScan = NULL;
+ } // if
+ for (i = 1; i < TokenCount; i++)
+ MergeStrings(&GlobalConfig.AlsoScan, TokenList[i], L',');
+
+ } else if (StriCmp(TokenList[0], L"showtools") == 0) {
SetMem(GlobalConfig.ShowTools, NUM_TOOLS * sizeof(UINTN), 0);
for (i = 1; (i < TokenCount) && (i < NUM_TOOLS); i++) {
FlagName = TokenList[i];
CHAR16 *SelectionSmallFileName;
CHAR16 *SelectionBigFileName;
CHAR16 *DefaultSelection;
+ CHAR16 *AlsoScan;
UINTN ShowTools[NUM_TOOLS];
CHAR8 ScanFor[NUM_SCAN_OPTIONS]; // codes of types of loaders for which to scan
} REFIT_CONFIG;
// Converts forward slashes to backslashes and removes duplicate slashes.
// Necessary because some (buggy?) EFI implementations produce "\/" strings
-// in pathnames.
-static VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) {
+// in pathnames and because some user inputs can produce duplicate directory
+// separators
+VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) {
CHAR16 *NewName;
UINTN i, j = 0;
BOOLEAN LastWasSlash = FALSE;
if (Second != NULL)
Length2 = StrLen(Second);
NewString = AllocatePool(sizeof(CHAR16) * (Length1 + Length2 + 2));
- NewString[0] = L'\0';
if (NewString != NULL) {
+ NewString[0] = L'\0';
if (*First != NULL) {
StrCat(NewString, *First);
if (AddChar) {
NewString[Length1 + 1] = 0;
} // if (AddChar)
} // if (*First != NULL)
- if (First != NULL)
+ if (Second != NULL)
StrCat(NewString, Second);
FreePool(*First);
*First = NewString;
// Find the #Index element (numbered from 0) in a comma-delimited string
// of elements.
-// Returns the found element, or NULL if Index is out of range of InString
+// Returns the found element, or NULL if Index is out of range or InString
// is NULL.
CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index) {
UINTN StartPos = 0, CurPos = 0;
else
CurPos++;
} // while
+ if (Index == 0)
+ FoundString = StrDuplicate(&InString[StartPos]);
+ if (FoundString != NULL)
+ FoundString[CurPos - StartPos] = 0;
} // if
- if (Index == 0)
- FoundString = StrDuplicate(&InString[StartPos]);
- if (FoundString != NULL)
- FoundString[CurPos - StartPos] = 0;
return (FoundString);
} // CHAR16 *FindCommaDelimited()
VOID UninitRefitLib(VOID);
EFI_STATUS ReinitRefitLib(VOID);
+VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName);
VOID CreateList(OUT VOID ***ListPtr, OUT UINTN *ElementCount, IN UINTN InitialElementCount);
VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement);
VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount /*, IN Callback*/);
static REFIT_MENU_SCREEN MainMenu = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot" };
static REFIT_MENU_SCREEN AboutMenu = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL };
-REFIT_CONFIG GlobalConfig = { FALSE, 20, 0, 0, NULL, NULL, NULL, NULL,
+REFIT_CONFIG GlobalConfig = { FALSE, 20, 0, 0, NULL, NULL, NULL, NULL, NULL,
{TAG_SHELL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, 0, 0, 0, 0, 0 }};
//
{
if (AboutMenu.EntryCount == 0) {
AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
- AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.6");
+ AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.6.1");
AddMenuInfoLine(&AboutMenu, L"");
AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith");
LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) {
LOADER_ENTRY *Entry;
+ CleanUpPathNameSlashes(LoaderPath);
Entry = InitializeLoaderEntry(NULL);
if (Entry != NULL) {
Entry->Title = StrDuplicate(LoaderTitle);
EFI_STATUS Status;
REFIT_DIR_ITER DirIter;
EFI_FILE_INFO *DirEntry;
- CHAR16 FileName[256];
+ CHAR16 FileName[256], *SelfPath;
+ UINTN i = 0;
+
+ // Skip past leading slashes, which are sometimes (but not always) included
+ // in SelfDirPath, to get a path that's known to never include this feature.
+ while ((SelfDirPath != NULL) && (SelfDirPath[i] == L'\\')) {
+ i++;
+ }
+ SelfPath = &SelfDirPath[i]; // NOTE: *DO NOT* call FreePool() on SelfPath!!!
- // Note: SelfDirPath includes a leading backslash ('\'), but Path
- // doesn't, so we rejigger the string to compensate....
- if (!SelfDirPath || !Path || ((StriCmp(Path, &SelfDirPath[1]) == 0) && Volume != SelfVolume) ||
- (StriCmp(Path, &SelfDirPath[1]) != 0)) {
+ if (!SelfPath || !Path || ((StriCmp(Path, SelfPath) == 0) && Volume != SelfVolume) ||
+ (StriCmp(Path, SelfPath) != 0)) {
// look through contents of the directory
DirIterOpen(Volume->RootDir, Path, &DirIter);
while (DirIterNext(&DirIter, 2, L"*.efi", &DirEntry)) {
EFI_STATUS Status;
REFIT_DIR_ITER EfiDirIter;
EFI_FILE_INFO *EfiDirEntry;
- CHAR16 FileName[256];
+ CHAR16 FileName[256], *Directory;
+ UINTN i, Length;
if ((Volume->RootDir != NULL) && (Volume->VolName != NULL)) {
// check for Mac OS X boot loader
// scan the root directory for EFI executables
ScanLoaderDir(Volume, NULL);
- // scan the elilo directory (as used on gimli's first Live CD)
- ScanLoaderDir(Volume, L"elilo");
- // scan the boot directory
- ScanLoaderDir(Volume, L"boot");
// scan subdirectories of the EFI directory (as per the standard)
DirIterOpen(Volume->RootDir, L"EFI", &EfiDirIter);
Status = DirIterClose(&EfiDirIter);
if (Status != EFI_NOT_FOUND)
CheckError(Status, L"while scanning the EFI directory");
+
+ // Scan user-specified (or additional default) directories....
+ i = 0;
+ while ((Directory = FindCommaDelimited(GlobalConfig.AlsoScan, i++)) != NULL) {
+ Length = StrLen(Directory);
+ // Some EFI implementations won't read a directory if the path ends in
+ // a backslash, so eliminate this character, if it's present....
+ while ((Length > 0) && (Directory[Length - 1] == L'\\')) {
+ Directory[--Length] = 0;
+ } // while
+ if (Length > 0)
+ ScanLoaderDir(Volume, Directory);
+ FreePool(Directory);
+ } // while
} // if
} // static VOID ScanEfiFiles()