[grub] add GRUB 2.0 versioning and enable external core.img download

* Closes #419
* Also updated Bled to latest
This commit is contained in:
Pete Batard 2014-12-30 19:46:13 +00:00
parent 7599715ae6
commit e90eaa4abc
11 changed files with 158 additions and 18 deletions

5
res/grub/grub_version.h Normal file
View file

@ -0,0 +1,5 @@
/*
* This file contains the version string of the Grub4Dos 2.x binary embedded in Rufus.
* Should be the same as the grub4dos_version file in the source Grub4Dos was compiled from.
*/
#define GRUB4DOS_VERSION "0.4.5c"

View file

@ -0,0 +1,5 @@
/*
* This file contains the version string of the GRUB 2.x binary embedded in Rufus.
* Should be the same as GRUB's PACKAGE_VERSION in config.h.
*/
#define GRUB2_PACKAGE_VERSION "2.02~beta2"

View file

@ -305,6 +305,15 @@ t MSG_114 "This image uses Syslinux %s%s but this application only includes the
"Note: The files will be downloaded in the current application directory and will be reused "
"automatically if present.\n"
t MSG_115 "Download required"
t MSG_116 "This image uses Grub %s but the application only includes the installation files for "
"Grub %s.\n\nAs different versions of Grub may not be compatible with one another, and it is "
"not possible to include them all, Rufus will attempt to locate a version of the Grub "
"installation file ('core.img') that matches the one from your image:\n"
"- Select 'Yes' to connect to the Internet and attempt to download it\n"
"- Select 'No' to use the embedded version regardless\n"
"- Select 'Cancel' to abort the operation\n\n"
"Note: The file will be downloaded in the current application directory and will be reused "
"automatically if present. If no match can be found, then the embedded version will be used.\n"
# Tootips
# Partition Scheme and Target Type
t MSG_150 "Usually the safest choice. If you have an UEFI computer and want to install "

View file

@ -23,6 +23,7 @@ uint64_t bb_total_rb;
printf_t bled_printf = NULL;
progress_t bled_progress = NULL;
static bool bled_initialized = 0;
jmp_buf bb_error_jmp;
static long long int unpack_none(transformer_state_t *xstate)
{
@ -72,6 +73,8 @@ int64_t bled_uncompress(const char* src, const char* dst, int type)
goto err;
}
if (setjmp(bb_error_jmp))
goto err;
ret = unpacker[type](&xstate);
_close(xstate.src_fd);
_close(xstate.dst_fd);
@ -116,6 +119,8 @@ int64_t bled_uncompress_with_handles(HANDLE hSrc, HANDLE hDst, int type)
return -1;
}
if (setjmp(bb_error_jmp))
return -1;
return unpacker[type](&xstate);
}

View file

@ -110,6 +110,7 @@ typedef unsigned int uid_t;
extern smallint bb_got_signal;
extern uint32_t *global_crc32_table;
extern jmp_buf bb_error_jmp;
uint32_t* crc32_filltable(uint32_t *crc_table, int endian);
uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len, uint32_t *crc32table_le);
@ -135,10 +136,11 @@ typedef struct _llist_t {
extern void (*bled_printf) (const char* format, ...);
extern void (*bled_progress) (const uint64_t processed_bytes);
#define xfunc_die() longjmp(bb_error_jmp, 1)
#define bb_printf(...) do { if (bled_printf != NULL) bled_printf(__VA_ARGS__); \
else { printf(__VA_ARGS__); putchar('\n'); } } while(0)
#define bb_error_msg bb_printf
#define bb_error_msg_and_die(...) do {bb_printf(__VA_ARGS__); return;} while(0)
#define bb_error_msg_and_die(...) do {bb_printf(__VA_ARGS__); xfunc_die();} while(0)
#define bb_error_msg_and_err(...) do {bb_printf(__VA_ARGS__); goto err;} while(0)
#define bb_perror_msg bb_error_msg
#define bb_perror_msg_and_die bb_error_msg_and_die
@ -185,7 +187,6 @@ static inline ssize_t full_read(int fd, void *buf, size_t count) {
#define xzalloc(x) calloc(x, 1)
#define malloc_or_warn malloc
#define xopen3 open
#define xfunc_die() do { bb_printf("not implemented"); return -1; } while(0)
#define mkdir(x, y) _mkdirU(x)
#if defined(_MSC_VER)

View file

@ -58,6 +58,8 @@ extern const int nb_steps[FS_MAX];
extern uint32_t dur_mins, dur_secs;
static int fs_index = 0;
BOOL force_large_fat32 = FALSE, enable_ntfs_compression = FALSE;
uint8_t *grub2_buf = NULL;
long grub2_len;
static BOOL WritePBR(HANDLE hLogicalDrive);
/*
@ -952,7 +954,7 @@ static BOOL WriteSBR(HANDLE hPhysicalDrive)
{
// TODO: Do we need anything special for 4K sectors?
DWORD size, max_size, mbr_size = 0x200;
int dt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType));
int r, dt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType));
unsigned char* buf = NULL;
FILE fake_fd = { 0 };
@ -969,6 +971,7 @@ static BOOL WriteSBR(HANDLE hPhysicalDrive)
switch (dt) {
case DT_GRUB4DOS:
uprintf("Writing Grub4Dos SBR...");
buf = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_GR_GRUB_GRLDR_MBR), _RT_RCDATA, "grldr.mbr", &size, FALSE);
if ((buf == NULL) || (size <= mbr_size)) {
uprintf("grldr.mbr is either not present or too small");
@ -978,10 +981,17 @@ static BOOL WriteSBR(HANDLE hPhysicalDrive)
size -= mbr_size;
break;
case DT_GRUB2:
buf = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_GR_GRUB2_CORE_IMG), _RT_RCDATA, "core.img", &size, FALSE);
if (buf == NULL) {
uprintf("Could not access core.img");
return FALSE;
if (grub2_buf != NULL) {
uprintf("Writing Grub 2.0 SBR (from download)...");
buf = grub2_buf;
size = (DWORD)grub2_len;
} else {
uprintf("Writing Grub 2.0 SBR (from embedded)...");
buf = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_GR_GRUB2_CORE_IMG), _RT_RCDATA, "core.img", &size, FALSE);
if (buf == NULL) {
uprintf("Could not access core.img");
return FALSE;
}
}
break;
default:
@ -989,12 +999,13 @@ static BOOL WriteSBR(HANDLE hPhysicalDrive)
return TRUE;
}
uprintf("Writing SBR (Secondary Boot record)");
if (size > max_size) {
uprintf(" SBR size is too large - You may need to uncheck 'Add fixes for old BIOSes'.");
return FALSE;
}
return (write_data(&fake_fd, mbr_size, buf, (uint64_t)size) != 0);
r = write_data(&fake_fd, mbr_size, buf, (uint64_t)size);
safe_free(grub2_buf);
return (r != 0);
}
/*

View file

@ -552,6 +552,27 @@ out:
return r;
}
void GetGrubVersion(char* buf, size_t buf_size)
{
char *p, unauthorized[] = {'<', '>', ':', '|', '*', '?', '\\', '/'};
size_t i;
const char grub_version_str[] = "GRUB version %s";
for (i=0; i<buf_size; i++) {
if (memcmp(&buf[i], grub_version_str, sizeof(grub_version_str)) == 0) {
safe_strcpy(iso_report.grub2_version, sizeof(iso_report.grub2_version), &buf[i + sizeof(grub_version_str)]);
break;
}
}
// Sanitize the string
for (p = &iso_report.grub2_version[0]; *p; p++) {
for (i=0; i<sizeof(unauthorized); i++) {
if (*p == unauthorized[i])
*p = '_';
}
}
}
BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan)
{
size_t i, size;
@ -743,6 +764,25 @@ out:
_unlink(tmp_sif);
safe_free(tmp);
}
if (iso_report.has_grub2) {
// In case we have a GRUB2 based iso, we extract boot/grub/i386-pc/normal.mod to parse its version
strcpy(iso_report.grub2_version, "unknown");
if ((GetTempPathU(sizeof(path), path) != 0) && (GetTempFileNameU(path, APPLICATION_NAME, 0, path) != 0)) {
size = (size_t)ExtractISOFile(src_iso, "boot/grub/i386-pc/normal.mod", path, FILE_ATTRIBUTE_NORMAL);
buf = (char*)calloc(size, 1);
fd = fopen(path, "rb");
if ((size == 0) || (buf == NULL) || (fd == NULL)) {
uprintf("Could not read Grub version from 'boot/grub/i386-pc/normal.mod'");
} else {
fread(buf, 1, size, fd);
fclose(fd);
GetGrubVersion(buf, size);
}
free(buf);
_unlink(path);
}
uprintf("Detected Grub version: %s", iso_report.grub2_version);
}
StrArrayDestroy(&config_path);
StrArrayDestroy(&isolinux_path);
} else if (HAS_SYSLINUX(iso_report)) {

View file

@ -427,7 +427,7 @@ static __inline DWORD GetTempFileNameU(char* lpPathName, char* lpPrefixString, U
wconvert(lpPathName);
wconvert(lpPrefixString);
walloc(lpTempFileName, MAX_PATH);
ret =GetTempFileNameW(wlpPathName, wlpPrefixString, uUnique, wlpTempFileName);
ret = GetTempFileNameW(wlpPathName, wlpPrefixString, uUnique, wlpTempFileName);
err = GetLastError();
if ((ret != 0) && ((ret = wchar_to_utf8_no_alloc(wlpTempFileName, lpTempFileName, MAX_PATH)) == 0)) {
err = GetLastError();

View file

@ -42,6 +42,8 @@
#include "registry.h"
#include "localization.h"
#include "bled/bled.h"
#include "../res/grub/grub_version.h"
#include "../res/grub2/grub2_version.h"
/* Redefinitions for WDK and MinGW */
// TODO: these would be better in a 'missing.h' file
@ -99,6 +101,8 @@ static BOOL iso_provided = FALSE;
static BOOL user_notified = FALSE;
static BOOL relaunch = FALSE;
extern BOOL force_large_fat32, enable_iso, enable_joliet, enable_rockridge, enable_ntfs_compression;
extern uint8_t* grub2_buf;
extern long grub2_len;
extern const char* old_c32_name[NB_OLD_C32];
static int selection_default;
static loc_cmd* selected_locale = NULL;
@ -129,6 +133,8 @@ int dialog_showing = 0;
uint16_t rufus_version[4], embedded_sl_version[2];
char embedded_sl_version_str[2][12] = { "?.??", "?.??" };
char embedded_sl_version_ext[2][32];
char embedded_grub_version[] = GRUB4DOS_VERSION;
char embedded_grub2_version[] = GRUB2_PACKAGE_VERSION;
RUFUS_UPDATE update = { {0,0,0,0}, {0,0}, NULL, NULL};
StrArray DriveID, DriveLabel;
extern char szStatusMessage[256];
@ -1122,12 +1128,15 @@ static BOOL BootCheck(void)
FILE *fd;
DWORD len;
BOOL in_files_dir = FALSE;
const char* grub = "grub";
const char* core_img = "core.img";
const char* ldlinux = "ldlinux";
const char* syslinux = "syslinux";
const char* ldlinux_ext[3] = { "sys", "bss", "c32" };
char tmp[MAX_PATH], tmp2[MAX_PATH];
syslinux_ldlinux_len[0] = 0; syslinux_ldlinux_len[1] = 0;
safe_free(grub2_buf);
dt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType));
if ((dt == DT_ISO) || (dt == DT_IMG)) {
if (image_path == NULL) {
@ -1185,6 +1194,59 @@ static BOOL BootCheck(void)
return FALSE;
}
if ((iso_report.has_grub2) && (safe_strcmp(iso_report.grub2_version, embedded_grub2_version) != 0)) {
// We may have to download a different Grub2 version if we can find one
IGNORE_RETVAL(_chdirU(app_dir));
IGNORE_RETVAL(_mkdir(FILES_DIR));
IGNORE_RETVAL(_chdir(FILES_DIR));
static_sprintf(tmp, "%s-%s/%s", grub, iso_report.grub2_version, core_img);
fd = fopen(tmp, "rb");
if (fd != NULL) {
// If a file already exists in the current directory, use that one
uprintf("Will reuse '%s' from './" FILES_DIR "/%s-%s/' for Grub 2.x installation\n",
core_img, grub, iso_report.grub2_version);
fseek(fd, 0, SEEK_END);
grub2_len = ftell(fd);
fseek(fd, 0, SEEK_SET);
if (grub2_len > 0)
grub2_buf = malloc(grub2_len);
// grub2_buf was set to NULL at the beginning of this call
if ((grub2_buf == NULL) || (fread(grub2_buf, 1, (size_t)grub2_len, fd) != (size_t)grub2_len)) {
uprintf("Failed to read existing '%s' data - will use embedded version", core_img);
safe_free(grub2_buf);
}
fclose(fd);
} else {
r = MessageBoxU(hMainDialog, lmprintf(MSG_116, iso_report.grub2_version, embedded_grub2_version),
lmprintf(MSG_115), MB_YESNOCANCEL|MB_ICONWARNING|MB_IS_RTL);
if (r == IDCANCEL)
return FALSE;
else if (r == IDYES) {
static_sprintf(tmp, "%s-%s", grub, iso_report.grub2_version);
IGNORE_RETVAL(_mkdir(tmp));
static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, grub, iso_report.grub2_version, core_img);
SetWindowTextU(hISOProgressDlg, lmprintf(MSG_085, tmp));
SetWindowTextU(hISOFileName, tmp);
PromptOnError = FALSE;
grub2_len = (long)DownloadFile(tmp, &tmp[sizeof(FILES_URL)], hISOProgressDlg);
PromptOnError = TRUE;
if (grub2_len <= 0)
uprintf("%s was not found - will use embedded version\n", tmp);
else {
fd = fopen(&tmp[sizeof(FILES_URL)], "rb");
grub2_buf = malloc(grub2_len);
if ((fd == NULL) || (grub2_buf == NULL) || (fread(grub2_buf, 1, (size_t)grub2_len, fd) != (size_t)grub2_len)) {
uprintf("Failed to read '%s' data - will use embedded version", core_img);
safe_free(grub2_buf);
}
if (fd != NULL)
fclose(fd);
}
}
}
}
if (HAS_SYSLINUX(iso_report)) {
if (SL_MAJOR(iso_report.sl_version) < 5) {
IGNORE_RETVAL(_chdirU(app_dir));
@ -1434,6 +1496,7 @@ void InitDialog(HWND hDlg)
}
uprintf("Syslinux versions: %s%s, %s%s", embedded_sl_version_str[0], embedded_sl_version_ext[0],
embedded_sl_version_str[1], embedded_sl_version_ext[1]);
uprintf("Grub versions: %s, %s", embedded_grub_version, embedded_grub2_version);
uprintf("Windows version: %s\n", WindowsVersionStr);
uprintf("Locale ID: 0x%04X\n", GetUserDefaultUILanguage());

View file

@ -263,6 +263,7 @@ typedef struct {
uint16_t sl_version; // Syslinux/Isolinux version
char sl_version_str[12];
char sl_version_ext[32];
char grub2_version[32];
} RUFUS_ISO_REPORT;
/* Isolate the Syslinux version numbers */

View file

@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 242, 329
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Rufus 1.5.0.563"
CAPTION "Rufus 1.5.0.564"
FONT 8, "Segoe UI", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,127,291,50,14
@ -164,7 +164,7 @@ END
IDD_DIALOG_XP DIALOGEX 12, 12, 242, 329
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Rufus 1.5.0.563"
CAPTION "Rufus 1.5.0.564"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,127,291,50,14
@ -297,7 +297,7 @@ END
IDD_DIALOG_RTL DIALOGEX 12, 12, 242, 329
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
CAPTION "Rufus 1.5.0.563"
CAPTION "Rufus 1.5.0.564"
FONT 8, "Segoe UI", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,127,291,50,14
@ -437,7 +437,7 @@ END
IDD_DIALOG_RTL_XP DIALOGEX 12, 12, 242, 329
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
CAPTION "Rufus 1.5.0.563"
CAPTION "Rufus 1.5.0.564"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,127,291,50,14
@ -703,8 +703,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,5,0,563
PRODUCTVERSION 1,5,0,563
FILEVERSION 1,5,0,564
PRODUCTVERSION 1,5,0,564
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -721,13 +721,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "1.5.0.563"
VALUE "FileVersion", "1.5.0.564"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "1.5.0.563"
VALUE "ProductVersion", "1.5.0.564"
END
END
BLOCK "VarFileInfo"