From 6ef8bde9b1d4e01507fe8a3ee6441b3266625145 Mon Sep 17 00:00:00 2001 From: srs5694 Date: Sun, 15 Dec 2013 00:10:46 -0500 Subject: [PATCH] Time support in default_selection; enables different default based on time of day. --- BUILDING.txt | 27 ++++++------ NEWS.txt | 12 +++++ docs/refind/configfile.html | 4 +- refind/config.c | 88 ++++++++++++++++++++++++++++++++++++- refind/config.h | 1 + refind/main.c | 2 +- 6 files changed, 117 insertions(+), 17 deletions(-) diff --git a/BUILDING.txt b/BUILDING.txt index 917a66a..b35ed4e 100644 --- a/BUILDING.txt +++ b/BUILDING.txt @@ -28,19 +28,20 @@ To compile rEFInd, you'll need the following: install this from a package called "gnu-efi"; however, rEFInd relies on features that were added in (I think) 3.0l to provide driver-loading capabilities. The versions I've used and that work are 3.0p, 3.0q, - 3.0r, and 3.0s, with the caveat that 3.0s works when I installed it via - a Gentoo package, but not when I installed it by compiling the source - code locally. Through mid-to-late 2012, most Linux distributions - delivered rather elderly versions of GNU-EFI, but many are catching up - by late 2012. You should check your GNU-EFI version number; you may - need to download the latest source code, compile it, and install it - locally. Between rEFInd version 0.2.7 and 0.6.1, the Makefiles assumed - a locally-compiled GNU-EFI package, but older and more recent versions - assume GNU-EFI installation in typical locations for - distribution-provided packages. The legacy BIOS boot support on - UEFI-based PCs doesn't work when rEFInd is compiled under GNU-EFI, so - as of rEFInd 0.4.6, GNU-EFI is no longer the primary build environment, - although it's easier to set up on a Linux system. + 3.0r, 3.0s, and 3.0u, with a caveat: The new time-sensitive + default_selection feature causes rEFInd to hang when using 3.0s and + earlier. 3.0u works fine for this (tested with compilation on three + computers). I don't know if 3.0t would work. Through mid-to-late 2012, + most Linux distributions delivered rather elderly versions of GNU-EFI, + but many are catching up by late 2012. You should check your GNU-EFI + version number; you may need to download the latest source code, + compile it, and install it locally. Between rEFInd version 0.2.7 and + 0.6.1, the Makefiles assumed a locally-compiled GNU-EFI package, but + older and more recent versions assume GNU-EFI installation in typical + locations for distribution-provided packages. The legacy BIOS boot + support on UEFI-based PCs doesn't work when rEFInd is compiled under + GNU-EFI, so as of rEFInd 0.4.6, GNU-EFI is no longer the primary build + environment, although it's easier to set up on a Linux system. Of the two toolkits, I prefer to use TianoCore because it produces binaries that can boot BIOS/legacy-mode OSes and because the TianoCore-produced diff --git a/NEWS.txt b/NEWS.txt index bcfefd4..163936c 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,6 +1,18 @@ 0.7.6 (12/??/2013): ------------------- +- Added support for time-sensitive "default_selection" setting. This token + may now have either one or three options. If one, it's interpreted as it + has been in the past, as setting a default that's independent of times. + If you follow this default by two times, however, those are interpreted + as the start and end times (in 24-hour format) for a default setting. For + instance, "default_selection foo 8:00 17:00" causes foo to be the default + from 8:00 (AM) to 17:00 (aka 5:00 PM). You can include multiple + "default_selection" lines to set different defaults for a variety of + times. If they're in conflict, the last one takes precedence. Note that + times are hardware clock's native value, which may be local time or UTC, + depending on your computer. + - Added support for a blank-screen startup: Set "screensaver -1" and the screen saver will be initialized when rEFInd starts. If you set a low "timeout" value, the result will be a boot straight to the default OS diff --git a/docs/refind/configfile.html b/docs/refind/configfile.html index 4bae3e5..9f78ba9 100644 --- a/docs/refind/configfile.html +++ b/docs/refind/configfile.html @@ -318,8 +318,8 @@ timeout 20 default_selection - a substring of a boot loader's title; or a numeric position - Sets the default boot OS based on the loader's title, which appears in the main menu beneath the icons when you select the loader. You can enter any substring of the title as the default_selection, so long as it's two or more characters in length. It's best to use a unique substring, since rEFInd stops searching when it finds the first match. Because rEFInd sorts entries within a directory in descending order by file modification time, if you specify a directory (or volume name, for loaders in a partition's root directory) as the default_selection, the most recent loader in that directory will be the default. One-character entries are matched against the first character of the title, except for digits, which refer to the numeric order of the boot loader entries. + a substring of a boot loader's title, or a numeric position; optionally followed by two times in HH:MM format + Sets the default boot OS based on the loader's title, which appears in the main menu beneath the icons when you select the loader. You can enter any substring of the title as the default_selection, so long as it's two or more characters in length. It's best to use a unique substring, since rEFInd stops searching when it finds the first match. Because rEFInd sorts entries within a directory in descending order by file modification time, if you specify a directory (or volume name, for loaders in a partition's root directory) as the default_selection, the most recent loader in that directory will be the default. One-character entries are matched against the first character of the title, except for digits, which refer to the numeric order of the boot loader entries. You may optionally follow the match string by two times, in 24-hour format, in which case the entry applies only between those two times. For instance, default_selection Safety 1:30 2:30 boots the entry called Safety by default between the hours of 1:30 and 2:30. These times are specified in whatever format the motherboard clock uses (local time or UTC). If the first value is larger than the second, as in 23:00 1:00, it is interpreted as crossing midnight—11:00 PM to 1:00 AM in this example. The last default_selection setting takes precedence over preceding ones if the time value matches. Thus, you can set a main default_selection without a time specification and then set one or more others to override the main setting at specific times. include diff --git a/refind/config.c b/refind/config.c index c310e30..f86edc8 100644 --- a/refind/config.c +++ b/refind/config.c @@ -60,6 +60,9 @@ #define ENCODING_UTF8 (1) #define ENCODING_UTF16_LE (2) +#define GetTime ST->RuntimeServices->GetTime +#define LAST_MINUTE 1439 /* Last minute of a day */ + static REFIT_MENU_ENTRY MenuEntryReturn = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL }; // @@ -337,6 +340,85 @@ static VOID HandleStrings(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 } } // static VOID HandleStrings() +// Convert TimeString (in "HH:MM" format) to a pure-minute format. Values should be +// in the range from 0 (for 00:00, or midnight) to 1439 (for 23:59; aka LAST_MINUTE). +// Any value outside that range denotes an error in the specification. +// static UINTN HandleTime(IN CHAR16 *TimeString) { +// BOOLEAN Found = FALSE; +// UINTN ColonPosition = 0, Hour = 0, Minute = 0, TimeLength; +// +// Print(L"Entering HandleTime('%s')\n", TimeString); +// TimeLength = StrLen(TimeString); +// for (ColonPosition = 0; (ColonPosition < TimeLength) && !Found; ColonPosition++) { +// Print(L"ColonPosition = %d\n", ColonPosition); +// if (TimeString[ColonPosition] == ':') +// Found = TRUE; +// } // for +// +// if ((ColonPosition == 0) || (ColonPosition > StrLen(TimeString))) +// return (LAST_MINUTE + 1); +// +// Hour = Atoi(TimeString); +// Minute = Atoi(&TimeString[ColonPosition + 1]); +// Print(L"Hour = %d, Minute = %d\n", Hour, Minute); +// return (Hour * 60 + Minute); +// } // BOOLEAN HandleTime() + +static UINTN HandleTime(IN CHAR16 *TimeString) { + UINTN Hour = 0, Minute = 0, TimeLength, i = 0; + BOOLEAN FoundColon = FALSE; + + TimeLength = StrLen(TimeString); + while (i < TimeLength) { + if (TimeString[i] == L':') { + FoundColon = TRUE; + Hour = Minute; + Minute = 0; + } // if + if ((TimeString[i] >= L'0') && (TimeString[i] <= '9')) { + Minute *= 10; + Minute += (TimeString[i] - L'0'); + } // if + i++; + } // while + return (FoundColon ? Hour * 60 + Minute : LAST_MINUTE + 1); +} // BOOLEAN HandleTime() + +// Sets the default boot loader IF the current time is within the bounds +// defined by the third and fourth tokens in the TokenList. +static VOID SetDefaultByTime(IN CHAR16 **TokenList, OUT CHAR16 **Default) { + EFI_STATUS Status; + EFI_TIME CurrentTime; + UINTN StartTime = LAST_MINUTE + 1, EndTime = LAST_MINUTE + 1, Now; + BOOLEAN SetIt = FALSE; + + StartTime = HandleTime(TokenList[2]); + EndTime = HandleTime(TokenList[3]); + + if ((StartTime <= LAST_MINUTE) && (EndTime <= LAST_MINUTE)) { + Status = refit_call2_wrapper(GetTime, &CurrentTime, NULL); + Now = CurrentTime.Hour * 60 + CurrentTime.Minute; + + if (Now > LAST_MINUTE) { // Shouldn't happen; just being paranoid + Print(L"Warning: Impossible system time: %d:%d\n", CurrentTime.Hour, CurrentTime.Minute); + return; + } // if impossible time + + if (StartTime < EndTime) { // Time range does NOT cross midnight + if ((Now >= StartTime) && (Now <= EndTime)) + SetIt = TRUE; + } else { // Time range DOES cross midnight + if ((Now >= StartTime) && (Now <= EndTime)) + SetIt = TRUE; + } // if/else time range crosses midnight + + if (SetIt) { + MyFreePool(*Default); + *Default = StrDuplicate(TokenList[1]); + } // if (SetIt) + } // if ((StartTime <= LAST_MINUTE) && (EndTime <= LAST_MINUTE)) +} // VOID SetDefaultByTime() + // read config file VOID ReadConfig(CHAR16 *FileName) { @@ -487,7 +569,11 @@ VOID ReadConfig(CHAR16 *FileName) HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionBigFileName)); } else if (StriCmp(TokenList[0], L"default_selection") == 0) { - HandleString(TokenList, TokenCount, &(GlobalConfig.DefaultSelection)); + if (TokenCount == 4) { + SetDefaultByTime(TokenList, &(GlobalConfig.DefaultSelection)); + } else { + HandleString(TokenList, TokenCount, &(GlobalConfig.DefaultSelection)); + } } else if (StriCmp(TokenList[0], L"textonly") == 0) { if ((TokenCount >= 2) && (StriCmp(TokenList[1], L"0") == 0)) { diff --git a/refind/config.h b/refind/config.h index aad46a6..3c92fdb 100644 --- a/refind/config.h +++ b/refind/config.h @@ -53,6 +53,7 @@ #endif #include "global.h" + // // config module // diff --git a/refind/main.c b/refind/main.c index 14296b9..83c44e7 100644 --- a/refind/main.c +++ b/refind/main.c @@ -153,7 +153,7 @@ static VOID AboutrEFInd(VOID) { if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.5"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.5.2"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2013 Roderick W. Smith"); -- 2.39.2