71 - Grubutils - menuset, wenv, bios, grub4dos utilities and batch files

Hits

The GrubUtils utilities can be downloaded from Chenalls site here (this includes wenv, chkpci and other utilities). See the bottom of this page for a recent version (includes 2014 version of chkpci).

There are some interesting utilities that can be called or executed from grub4dos. The documentation is difficult to find and is usually in Chinese. Here are some notes which may be helpful.

When running an external grub4dos batch file or utility executable, you need to copy the file to your boot drive and make sure that the path is specified correctly in the menu.lst file, e.g.

will run the file menuset which must exist on the root of the boot drive. menuset is contained in the grubutils package.

Note: The default command path for grub4dos is the current path (set by the root command) and the /boot/grub folder - it is recommended to place all your utilities in /boot/grub on your boot drive so that grub4dos can find them without needing to set the root or define a full path.

will run the file menuset which must exist in the /boot/grub folder or in the current root folder (as shown by the ls command).

The alternative is to path each command - e.g. use /bin/wenv instead of just wenv and place the wenv file at /bin.

Note: grub4dos 0.4.6a 2018 now supports the built-in setmenu command. I recommend you use this instead of menuset or menusetting executables...

Grub4dos Batch files

Max no lines = 2048 in a batch file, Max. no. labels in a batch file =128, file must start with !BAT on first line.

Grub4dos can execute a batch file (usually given a .g4b file extension, but sometime it has a .bat extension or no extension - whereas a grub4dos executable file has a .g4e extension or no extension). The grub4dos batch file must begin with !BAT. The syntax to use in the batch file is similar to that in a menu.lst file but not quite the same. For instance when using two variables together, you must use three % signs in a batch file because any two consecutive % signs will be treated as a single % sign in a batch file:

test.bat file contents:

!BAT

set a=Fred is a

set b=GENIOUS!

echo %a%%%b%

echo Fred got 100%% in his test!

/menuset 0 0 0 0 0 0 10 50 5 29 35

menuset 0 0 0 0 0 0 10 50 5 29 35

Unsupported embed

in a grub4dos commandline shell, type /test.bat

Fred is a GENIOUS!

Fred got 100% in his test!

Note that in a batch file we cannot use %a%%b% - we must add an extra % symbol and use %a%%%b%, but in a menu.lst file, echo %a%%b% will work and you don't need the extra % sign!

If want to add a SPACE before a value using set then use double-quotes:

set "C= fred"

or use double-quotes if it is possible that a variable's value (A in this case) might contain leading spaces (in batch file %%=% so we must use three % signs - %A%%%B%):

set "C=%A%%%B%"

tip: If you place all utility and batch files in the /boot/grub folder then grub4dos will find them without needing to specify a path.

tip: If you use debug 3 then you can single step a batch file (on later versions of grub4dos use debug <batchfile> <args> )

Also, if you call a grub4dos utility a lot in a batch file (for instance, in a loop or subroutine), then load it into memory first using the command insmod - e.g.

insmod /utils/wenv

wenv calc bs=%bs%-%bc2b%

will load wenv into memory so that whenever it is called later (with no path specified) it will run from memory instead of being loaded from the disk each time. Thus using insmod at the start of your batch file to load any utilities into memory will greatly improve the speed of execution! Insmod can also be called from within a menu.lst file and this will increase the speed of execution of grub4dos menus if you call a grub4dos utility within the menu.lst file, as well as any batch files you call afterwards. Use delmod <filename) to unload a file or :

::echo Checking if this batch file is loaded into memory - if not load it for faster execution

delmod -l %~nx0 || insmod %0

#Note: can only use filenames up to 11 characters (including the dot - i.e. up to 8.2 not 8.3) with insmod.

You can also call internal Function calls in a batch file using call Fn.x where x is a number and can be followed by one or more parameters - e.g.:

call Fn.0 0 "Hello" - will print Hello to the console

Here is a batch file to get lines from a text file, one at a time (redirecting bold blue lines will give a perfect copy of the file):

!BAT

insmod %0 > nul

set n=0

set l=0

:LOOP

cat --locate=\x0d\x0a --number=1 --skip=%n% /menu.lst > nul

if "%?%"=="0x0" goto :EOF

set /a l=%?% - %n% > nul

::echo -e \nFound CR at start %n% length %l%

if %l%>=1 cat --skip=%n% --length=%l% /menu.lst

echo

set /a n=%n% + %l% + 2 > nul

goto :LOOP

Tip: to get more lines on the console screen, type graphicsmode 179 first.

Here is a batch file to search for and list BIOS strings. Save the file to your grub4dos bootable disk as ShowBiosStrings.bat, boot to a grub4dos command prompt and then type:

ShowBiosStrings 0x680+0x180 CPU

and see what you get (tip: add insmod %0 to load the whole batch file into memory and speed it up a lot)!

This requires \grub\wenv. If a string is found the GOTSTR=1 is returned.

!BAT

if "%1"=="FF" goto :FF

if "%1"=="" goto :EOF

:: Requires wenv in grub folder

:: Usage: ShowBiosStrings.bat [memorystart+memoryrange] [string]

:: where memorystart and memoryrange is in units of 512 bytes

:: e.g. ShowBiosStrings.bat 0x680+0x80 CPU

:: ShowBiosStrings.bat 0x700+0x80 "cpu\ is\ present"

:: ShowBiosStrings.bat 0x780+0x80 cpu\ is\ present

:: 0x680 = D000:0 in memory and is often use for storing DMI BIOS strings

:: 0x700 = E000:0 in memory and is used for DMI string as well a BIOS code and workspace

:: 0x780 = F000:0 in memory and is usually the BIOS code but may also contain fixed strings

:: 0x680+0x180 will search all BIOS area from D000:0 to end of BIOS area (FFFF:F)

:: 0x680+0x80 will search the 64K segment from D000:0 only

:: 0x700+0x100 will search 128K from E000:0

:: This grub4dos batch file displays all BIOS strings matching the specified string

:: Case Insensitive - if one or more matches found GOTSTR=1

:: so we don't get invalid argument if no matches

errorcheck on

debug 1

set GOTSTR=

set SLOC=%1

:: get location of strings from D000:0 to F000:FFFF in BIOS and DMI area

cat --locatei=%2 (md)%SLOC% | set a=

:: limit to 400 chars to reduce length of the for /f line below 512 chars!

set a=%a:~0,400%

if "%a%"=="" goto :EOF

:: parse the list and get first 17 locations into %i to %z - call this batch file again (%0) with FF as the first parameter so that it jumps to :FF

/grub/WENV for /f "delims= " %i in ( "%a%" ) do exec %0 FF %i %j %k %l %m %n %o %p %q %r %s %t %u %v %w %x %y

set a=

set A=

set z=

set SLOC=

goto :EOF

:: ============ SUBROUTINE =====

:FF

:: %2 %3 etc will have the first 17 locations

::echo @F 2=%2 3=%3 4=%4 5=%5 6=%6 7=%7 8=%8 9=%9

:: we may have an odd " in the string, turn off errorchecking otherwise it may abort

errorcheck off

set z=

if "%2"=="" goto :EOF

set z=%2

set z=%z:~0,5%

if %z:~-2,1%"=="" set z=%z:~,-2%

set /A A=0x%z%+0 > nul

if "%A%"=="0x0" goto :EOF

if "%A%"=="" goto :EOF

:: we can turn it on again now!

errorcheck on

:: now put the string at location %A% into memory

::cat --length=50 --skip=%A% (md)%SLOC%

cat --length=50 --skip=%A% (md)%SLOC% > (md)0x3000+1

:: remove line feeds, carriage returns, etc.

cat --locate=\x0a --replace=\x20 (md)0x3000+1 > nul

cat --locate=\x0d --replace=\x20 (md)0x3000+1 > nul

:: ensure end of string is marked

echo -e -n \x0 >> (md)0x3000+1

:: now display the modified string on the display

echo -n @(md)%SLOC% OFFSET=%A% ==>

cat (md)0x3000+1

:: throw a line

echo

:: set success - found a match!

set GOTSTR=1

:: shift %3 to %2 and loop until no more left

shift

goto :FF

Special 'command line' variables

%0 is the calling batch file name

%1 to %9 are parameters 1-9 (use shift if you have more than 9 parameters)

%* represents all parameters

call :fred mary joe

...

goto :eof

:fred

echo %2 is joe

goto :eof

IMPORTANT GOTCHA!

In batch files, %0-%9 and %* will be recognised as a command line variable, therefore the following do not work as expected in a batch file:

set /a A=%B%*2 - %* means all parameters - use set /a A=%B% *2

echo %D%1 - %1 means the first parameter - use %D%%1

Another Batch file example - use checkdate.g4b to check an Expiry Date

A simple example of an expiry date test (thanks to Wonko on reboot.pro) is:

if 20131226>=%@date:~0,4%%@date:~5,2%%@date:~8,2% pause --wait=3 THIS SOFTWARE HAS EXPIRED - XMAS 2013 IS OVER && halt

Suppose we release a bootable CD or USB drive which has software on it that should be regularly updated. We want to warn the user when it is about to expire or if it has expired. We can use a grub4dos batch file to do this and call it from a menu.lst file like this:

# Usage: /checkdate.g4b <Release Year> <Release Month> <Release DayOfMonth> <ExpiresInDays> [<SILENT>]

# Example below: Released on 2102-12-03 Expires in 30 days

/checkdate.g4b 2012 12 3 30

# Example1 without text displayed: /checkdate.g4b 2012 12 3 30 SILENT

# Example2 without text displayed: /checkdate.g4b 2012 12 3 30 > nul

pause

if NOT "%CHECKDATE%"=="OK" reboot

This will show the following text when the grub4dos menu runs...

CheckDate: Release Date 2012-12-31 (Today is 2012-12-31)

CheckDate: This version is good for 30 days from release

CheckDate: This version expires in 29 day(s)

OR

CheckDate: Release Date 2012-12-3 (Today is 2012-12-31)

CheckDate: This version is good for 30 days from release

CheckDate: WARNING: This is older than 30 days!

The checkdate.g4b file can be found at the bottom of this page or click here. If you add the word SILENT to the call parameters then the user will have no idea why it no longer displays a nice menu and just keeps rebooting!

Instead of 'reboot' you could just make the user wait 30 seconds using 'call Fn.73 30'.

Note: If you are burning this to a CD or DVD, use an 8.3 filename like chkdate.g4b as checkdate.g4b is too long a name!

If you wish to 'encrypt' your menu.lst file so that it is not just a plain text file, use 7Zip to compress the menu.lst file to GZip format (menu.lst.gz) and then rename the file to menu.lst.

grub4dos will still run the compressed menu.lst file just fine but if anyone tries to read the file using a text editor they will find it hard to understand!

Set the System Date

Using the grub4dos Function 53 we can set the Real Time Clock date. The Date.g4b grub4dos batch file can be run to set the date - this might be useful for expiry date sensitive DOS utilities that check the date of the system.

run the batchfile from your menu.lst like this

# set date of system to Jan 30th 2001

/Date.g4b 2001-01-30

# OR ...

# Prompt user to set a date

/Date.g4b

Note that this will permanently change the date of the system Real Time Clock until you set back the correct time.

grub4dos variables and setlocal/endlocal

Currently there is a maximum limit of 60 variables and each can be up to 512 bytes each.

The batch file VarsLeft.g4b will tell you how many variables remain out of the 60 allowed. It is quite easy to run out if you are not careful!

If you reset them (e.g. set A= will remove the variable A from the environment) then you will free up a 'slot for another variable'.

You can use setlocal to make a copy of the current environment (e.g. variables, root path, current filespec, etc.).

When the endlocal command is run these values are restored and any variables set during the setlocal portion are lost (a copy of the current environment is made when you use setlocal and that copy is restored when you use endlocal).

e.g.

set l=1

set m=

root (hd0,0)

setlocal

root (hd1,0)

set l=2

set m=1

echo %l% is 2

endlocal

echo %l% is 1

echo %m% is empty

echo root command shows (hd0,0) is the root

root

If you want to use setlocal, but pass back a variable, you can do it by placing an && set x=y statement on the end of the same line as endlocal - like this:

set m=3

setlocal

set /a m=%m%+1

set n=4

endlocal && set m=%m% && set n=%n%

echo %m% is 4 and %n% is 4

setlocal will inherit the current variables.

If you have 30 or so variables already set, then when you use setlocal, you will already have 30 variables set - this uses up the variable space (max. 60 variables can be defined). You can clear the local variables using set * : e.g.

setlocal

set *

# now no variables set

### do stuff here

set A=1

endlocal && set fred=%A%

#now original variables restored + fred=1

There is an undocumented way of getting more than 60 variables in 2013+ versions of grub4dos - see here for details.

Global variables

grub4dos currently supports up to two user-definable global variables.

?_abcx and ?_yyyy where abcx and yyyy can be any user defined name - the first two that are set by the user become global, any more are ignored.

setlocal

set ?_test=test

set ?_x=x

set ?_x=

set ?_y=y

endlocal

echo %?_test% %?_x% %?_y%

will produce the result:

test y

Note: set does not list these global variables, nor does set ?_ - you can only see their values if you reference them by name.

Note that set * will also delete the global variables

setlocal @

You can also use the special parameter @ with setlocal, this will preserve all variables after an endlocal is executed

e.g.

!BAT

set doris=

set fred=9

setlocal @

set steve=3

set doris=%fred%

echo ----- level 1

set

endlocal

echo ----- level 0

set

Produces the output:

----- level 1

fred=9

doris=1

steve=3

----- level 0

fred=9

doris=9

steve=3

Another example when mixing setlocal @ with setlocal

!BAT

set a=0

setlocal @

set a=1

setlocal

set a=2

setlocal

set a=3

When the batch exits, the variable a=1

Batch files that search sub-folders

FFFName.g4b - FindFullFileName - finds the first file matching a full filename, searches all disk - e.g. /grub/FFName.g4b / explorer.exe

FFName.g4b - FindFileName - finds the first file matching a filename (without extension), searches all disk - e.g. /grub/FFName.g4b / explorer

FFExt.g4b - FindFileExtension - finds the first file matching a file extension - returns variables - e.g. /grub/FFExt.g4b /_ISO .iso

DirFile.g4b - lists all files in a single directory (does not list directories) (e.g. /grub/DirFil.g4b /_ISO DIR (to just list dir names omit DIR))

LstDir.g4b - Lists directory names in a directory (e.g. /grub/LstDir.g4b /_ISO DIR (to just list dir names omit DIR))

LstFExt.g4b - Lists all files in a single folder that match a file extension

The names must be kept to 11 characters - otherwise insmod refuses to load it (says filename too long!). Make sure there are no spaces at the end of the line after the filename or this will be counted too!

Please download FindFile.zip to obtain these batch files.

The batch file LFExt.g4b lists all files in a single speciified folder (and not below - this has been suppressed in the batch file) that match a specified extension, e.g. /LFExt.g4b /_ISO/Linux .iso will list all ISO files e.g.:

aaaaa.iso

bbbbb.iso

ccccc.iso

wenv

Wenv (available on Beta downloads page) is a grub4dos utility (a program - see grubutils section below) that you can run under the grub4dos environment. It is just like an executable that you would run under DOS (e.g. find.exe) but it runs under grub4dos. It allows you to use environment variables in your menu.lst files or to run a script file which can execute grub4dos commands. Note: The Wenv download zip file in the Beta Downloads section of this site also includes an English translation of the Chinese text help file for wenv which I have added for you to study.

For instance....

title Install Windows 7 64-bit Enterprise Edition\nRun the Windows install DVD to install a copy of Windows to your hard disk

/Imdisk/wenv set iso=/iso/en_windows_7_enterprise_with_sp1_x64_dvd_620201.iso

find --set-root/ImDisk/myiso.cmd

dd if=()/ImDisk/au.xml of=()/AutoUnattend.xml

dd if=()/ImDisk/cr.txt of=()/ImDisk/myiso.cmd

/ImDisk/wenv call write ()/ImDIsk/myiso.cmd SET MYISO=${iso}\r\n

/ImDisk/wenv call map ${iso} (0xff)

map (hd0) (hd1)

map (hd1) (hd0)

map --hook

chainloader (0xff)

Note that line 2 sets the grub4dos environment variable 'iso' to the path of the ISO file by running the wenv executable with parameters.

In line 6 and line 7 we can use this variable value by substituting it with ${iso}.

Note that wenv needs to have a full path as grub4dos needs to find the wenv file which is in the /ImDisk folder in this example.

Also note that to use environment variables and wenv with grub4dos commands, we need to 'call' the grub4dos command, this why lines 6 and 7 start with '/ImDisk/wenv call'

If you copy the grub4dos executable file wenv (latest version available on grubutils download page) to the USB drive /ImDisk folder, you can make the menu.lst easier to edit and add more ISO files.

WENV list of commands currently supported:

SET to set/change/add/delete/display variables - for a substring use :~start,length - e.g. set a = %xyz:~10,2%%%xyz:~13,2%

(note you need to add another % when two %% signs are used together!)

GET display variable/variables and get length of the variable in ?_GET internal variable

FOR similar to the windows shell FOR cmd instruction

CALC simple calculator (priority from left to right, does not support brackets)

ECHO Display a message or variable to the screen

READ a file and run the commands inside - similar to a .cmd batch file (must use WENV supported commands) also supports parameters.

CHECK check if an equation is true or false, if it returns true a command can be executed

RESET clear/reset a variable

CALL call the grub4dos shell to execute a grub4dos command

Note: SET, GET, FOR, RESET, CALC and ECHO are largely redundant now as similar functions are built into the latest grub4dos versions from chenall (included in RMPrepUSB).

For instance, if you type /wenv set in the grub4dos command console window, then wenv will display all current grub4dos environment variables.

Here is another example of how you can use wenv (note: this time wenv is located in the root of the drive and not in the ImDisk folder):

title Specify an iso file to run

# list all files in the /boot/imgs folder so the user can see them

ls /boot/imgs/

echo

# Ask user which iso they want (name is converted to uppercase as $U is specified)

/WENV set ask=$U,$input,Enter iso name with no extension (e.g. dban) :

/WENV get ask || echo No iso file specified! && configfile (bd)/menu.lst

clear

/WENV echo Loading /boot/imgs/${ask}.iso - please wait ...

# run the grub4dos map command and specify the iso file we want to load

/WENV call map --mem (bd)/boot/imgs/${ask}.iso (0xff)

map --hook

chainloader (0xff)

# Examples using the RUN.bat file (included with the download)

title Auto-make menu for /BOOT/IMGS/ folder

# call the RUN batch file and create a configfile in the ramdrive for all image files

/RUN.bat .Automenu

# Load the new configfile

configfile (md)0x3000+0x10

title Boot dos

# call the RUN batch file with the file we want to load in the /BOOT/IMGS folder specified

/RUN.bat DOS622.IMA

# Add the boot command so the user can use the cursor keys to select this menu entry

boot

For an example of how to make a script file which can run under grub4dos (which must begin with the text !BAT), see the file RUN.BAT example included with the wenv.zip download.

For an example of a grub4dos batch file that uses wenv to display the MBR partition table of a drive - see jaclaz's/Wonko the Sane's mbrview.g4b batch file on reboot.pro here.

Example output of mbrview.g4b batch file from jaclaz.

hotkey

Another grub4dos utility you can run is the 'hotkey' utility which allows the user to use hotkeys (e.g. F1, F2, etc.) to select a menu item and run it (use the latest chenall build of grub4dos) - see Tutorial #57 for details.

grubutils

'grubutils' is just a name for a collection of individual executable utilities that can run within the grub4dos environment.

Grub4dos can call these utilities or execute them from a grub4dos batch file or from within a grub4dos menu.lst.

Some of these will list usage syntax if you use -h switch. C sources are here

chkpci - lists PCI devices, use -cc:06 (scan class codes that match PCI class 06) [FILE] PCI database file

diskid (hd0,1) will report Ghost style disk id 1:2

echo - echo's chars, variables, etc. = echo -h will display a colour chart of background/foreground

fatmini - similar to fat but small size, only supports mkfile, copy and del functions

fontfile - specify a fontfile to load

g4d_off - quit grub4dos!

inifile - see below

mbrcheck (hd1)+1 - checks for a valid mbr (checks a single active ptn table entry, magic bytes, non-overlapping ptns,

menuset - changes menu size and position - useful if using a high resolution background

snake - snake game - use cursor keys to eat the small square

unifont - load a unifont file

unitest - test a fontfile for validity

vbmp - vbmp /small.bmp - displays a small monochrome bmp file (must be mono bmp) see here

vfont - loads a font file??

wenv - work with environment variables - many functions now in grub4dos anyway - see grub4dos tutorial for details

wenv-readme.txt - readme file for wenv usage

chkpci

Latest 2011 version with -u command here.

chkpci [-h] [-o] [-u] [-cc:CC] [-sc:SC] [-srs] [FILE]

-h help

-u unique - displays lines in INI file matching h/w IDs

-cc:CC scan Class Codes with CC only

-sc:SC scan SubClass Codes

-srs for SATA/SCSI/RAID - displays mass storage PCI device only - similar to -cc:-1 -sc:06

FILE PCI device database file

usage:

chkpci -u /driverpack.ini

outputs:

"PCI\VEN_8086&DEV_2829&CC_0106"="iastor3" ; D/M/I3 "iastor.sys" "<description>"

fat

fat can perform file operations on a fat volume.

fat can be downloaded from here.

Note: for obvious reasons, this does not work on NTFS volumes!

fat mkfile size=xx filename - create a new file of a certain size (size=* will get size from memory address 0x8290

fat [/o] copy file1,<length> file2 - copy contents of file1 to file2 - fat copy /o (md)0x300+2,20 (%2)/txtsetup.oem - copy 20 bytes to txtsetup.oem (/o = overwrite if file already exists)

fat ren oldname newname - rename a file or directory

fat dir - list directory contents - e.g. fat dir /iso/app/ or fat dir /a-d /grubut~1/ (lists files but not directories, note shortfilenames 8.3 must be used! d,s,r,h valid attributes)

fat info (disk) - e.g, fat info (hd1,0) - displays info such as FAT start, sectors per cluster, sectors per FAT, free clusters, total clusters, drive free space and size

fat del file or directory (dir must be empty)

fat mkdir newdir

fat mkfs [/A:UNIT-SIZE] DRIVE - creates fat volume on drive, UNIT_SIZE = cluster size in bytes

For fat mkfs to work, the size of the device must be approx greater than 66,000 bytes (depending on if mounted using --mem or not). For example, the following two menu entries fail after echo 0 with FAT Error (1) message...

title test not --mem

find --set-root /fat

insmod /fat

map (md)0x800+0x5000 (fd1)

map --hook

fat mkfs (fd1)

# 65024 fail, 65025 ok,

fat mkfile size=65024 (fd1)/test.img

map (fd1)/test.img (fd2)

map --hook

echo 0

fat mkfs (fd2)

echo 1

fat mkfile size=100 (fd2)/testfd2.img

ls (fd2)/

pause

commandline

title test --mem

find --set-root /fat

insmod /fat

map (md)0x800+0x5000 (fd1)

map --hook

fat mkfs (fd1)

# 61440 fail, 61441 ok,

fat mkfile size=61440 (fd1)/test.img

map --mem (fd1)/test.img (fd2)

map --hook

echo 0

fat mkfs (fd2)

echo 1

fat mkfile size=100 (fd2)/testfd2.img

ls (fd2)/

pause

commandline

You can only copy the contents of a file to an existing file, so you must create the target file first (must be same size or bigger).

Example

Here is a batch file called copyff.bat and a menu.lst which uses the fat utility. It creates a large virtual floppy disk in memory and copies the entire contents from a mapped ISO file into it. It can cope with several 100's of files per folder but will not work on very large folders such as the XP CD's /I386 folder in an XP ISO (unfortunately!).

To make a memory-mapped 2.88MB Floppy disk 0

# make a disk (8) in memory at 1.3MB address

map --mem (md)0xA00+5760 (8)

#hook the interrupt so BIOS can see it

map --hook

#good practice to clear memory area start in case confuses g4d if looks like a compressed file header

echo -e \0\\0\0\0\0\0\0\0\0\0\0 > (8)+1

#make a FAT16 filesystem 63spt 255trackspercyl

fat mkfs (8)

#change to FAT12 BPB

write --offset=0xc (8) \2\2\1\0\2\xf0\0\x80\x16\xf0\x09\0\x24\0\2

#map as floppy 0

map --mem (8)+1 (0)

map --rehook

#remove device (8)

map --unmap=8

map --rehook

Alternate - not using fat mkfs

:: make 2.88MB floppy as device (8) - Note: 'fat mkfs (8)' makes a FAT16 disk with 63 hds and 255 spt which may not be recognised as a floppy by Windows

map --mem (md)0xA00+5760 (8)

map --hook

:: initialize memory area

echo -e \0\0\0\0\0\0\0\0\0\0\0\0 > (8)+40

write (8)+1 \xeb\xfe

write --offset=0xc (8) \2\2\1\0\2\xf0\0\x80\x16\xf0\x09\0\x24\0\2

#write Extended Boot Record signature = 29h, Serial Number=4 bytes, Volume label 11 bytes, System Identifier (FAT12, FAT16, or FAT32) 8 bytes

write --offset=0x26 (8)+1 \x29WXYZmyrmprepusbFAT12\x20\x20\x20

write --offset=0x1fe (8)+2 \x55\xAA\xf0\xff\xff

#map as floppy 0

map --mem (8)+1 (0)

map --rehook

#remove device (8)

map --unmap=8

map --rehook

menuset

Note: grub4dos 0.4.6a 2018 now supports the built-in setmenu command. I recommend you use this instead of menuset or menusetting executables...

menuset sets the border characters that grub4dos uses to surround a menu and position of menu box and help text.

arguments:

upper left corner border char, upper right corner bordr char, lower left corner char, lower right corner char, horizontal char, vertical char, menubox left pos, menubox width, first line no., height of menu, row position for help text

ul ur ll lr hor ver ml mw 1st hgt hlprow

menuset 218 191 192 217 196 179 2 76 2 21 22

menuset 0 0 0 0 - I sets the horizontal top/bottom char to - and vertical sides to I

menuset 0 0 0 0 0 0 8 60 10 makes a small 9 entry high menu at x,y 8,10

menuset 0 0 0 0 0 0 8 60 10 6 as above but only 6 rows in the menu

menuset 0 0 0 0 0 0 8 60 10 6 1 as above but puts the help text at the top of the menu

menuset resets all back to normal menu chars and position

Example: menuset 0 0 0 0 - I 8 60 10 6 1

Unsupported embed

Example

# turn off debug text

debug -1

# Auto number menu entries

write --bytes=2 0x8274 0x2001

color black/cyan yellow/cyan

graphicsmode -1 1024 100:1000 24:32 && splashimage /nicepair1024.bmp.gz

color normal=0x66 highlight=0x75 helptext=0x1D heading=0x0A standard=0x0F border=0x00

# ul ur ll lr hor ver menul menuw 1st hgt helprow

/menuset 0 0 0 0 0 0 10 50 5 29 35

# blank out grub4dos version number at the top and write a menu heading in line 3 (NOTE: green text below is all one line>>>>>>)

write (md)0x220+1 !BAT\necho -n -P:0000 $[0133] \necho -n -P:0300 $[0133]

--- MY MENU ---\0

# run the script

initscript (md)0x220+1

# don't print the menu item number at top of menu when I move the cursor by adding debug 0

debug 0

# Use title abc\n or title abc\nmy help text goes here so that you don't get the default help text

sets menu left position to 10, menu width to 50, the first menu item at row 5, 29 items per menu and help text starts at row 35.

1024x768 background with smaller menu

In this example the grub4dos version text is not blanked out

and there is no menu heading.

menusetting

If you require the menu to be past column 78 then menuset will not work correctly. In this case use the menusetting grub4dos batch file utility as follows:

#/menusetting u will restore max menu grub4dos default

# wordspacing linespacing borderwidth tophelp numberofitemsinmenu topstart menuwidth rightstartposofmenu

set wdspace=0

set lnspace=0

set topstart=10

set rstart=45

set noitems=10

set menuw=60

set bdwidth=5

set tophelp=23

/menusetting u

/menusetting %wdspace% %lnspace% %bdwidth% %tophelp% %noitems% %topstart% %menuw% %rstart%

Note that there is a problem with help text with grub4dos - the help text will only appear up to text column 79 - if you have a menu box after column 79 then no help text will appear at all. The default grub4dos help text will always start a column 0, but any menu help text in your titles can only occupy from the left-hand side of your menu box up to column 79. Note: Try the latest 2014 version of grub4dos and grubutils tools - this may now be fixed.

Example using the settings shown above - note how the help text is cut off at column 79!

setmenu (inbuilt command)

grub4dos 0.4.6a (2017+) supports the new setmenu command. I recommend that you use this instead of the menusetting or menuset batch file.

bios

This utility allows you to make any BIOS call you like. You can setup the registers and which interrupt you want to use, it then makes the BIOS call and prints out the CPU register contents after the call returns, like this:

EAX=00008600 EBX=00000000 ECX=00000000 EDX=00000000 ESI=00000000

EDI=00000000 EBP=00000000 ESP=00006284 EIP=00000000 eFLAG=00000A83

DS=0000 ES=0000 FS=0000 GS=0000 SS=0000 CS=0000 OV UP EI NG NZ NA PO CY

The flag registers are displayed so you can test for the Carry Flag (NC or CY) or Zero flag (NZ or ZR).

This allows you to make any BIOS call (for instance write characters to a certain position on the screen, read a disk sector, etc.).

e.g.

# beep the speaker (if one is fitted) - send a Ctrl-G to the display

/bios int=0x10 eax=0xe07 ebx=0x0 > nul

You can then check these registers by redirecting the output to memory and using cat - e.g. a single line in a grub4dos menu ...

# if plop is not installed, then run it to reboot from USB in USB 2.0 mode

/plpbt/bios int=0x13 eax=0x504c6f50 ebp=0x43484b44 > (md)0x300+1 && cat --locate="EAX=79657320" (md)0x300+1 || pause --wait=3 loading Plop! && kernel /plpbt/plpbt.bin hiddenusb && boot

Do not experiment with int13h calls unless you are careful and know what you are doing as they can be dangerous (e.g. could trash your hard disk!).

Here is an example to calculate available memory size and use the value in your menus:

#suppress timer countdown and other text

debug -1

if "%RUN%"=="" /bios int=0x15 eax=0x0000e801 > (md)0x300+1

if "%RUN%"=="" cat --skip=24 --length=4 (md)0x300+1 | set n=

if "%RUN%"=="" set /a MEMSIZE=0x%n%/16+16

#reload menu once MEMSIZE is set

if "%RUN%"=="" set RUN=0 && configfile /menu.lst

pause --wait=2 Memory Size=%MEMSIZE%MB

<your normal menu entries here>

iftitle [if %MEMSIZE%>=700 && if exist /myiso.iso] run myiso (needs more than 700MB)

etc.

To use this in an iftitle [if %MEMSIZE%>=600] to run iso that requires more than 600MB - see reboot.pro here. You must load the menu.lst twice - the first time it runs it calculates MEMSIZE, the next time it runs, the iftitle statements will be able to use the MEMSIZE variable and only display the appropriate menus.

Note: The menu line below will also fetch the memory size from an internal grub4dos storage location and put the value into a variable in units of MBs without needing to call the bios utility:

set /a MEMSIZE=*0x8298 & 0xffffffff>> 10+1

Get last physical disk sector (and thus disk size)

# set size of buffer available

write 0x6000 0x42 > nul

# get size of disk from INT 13h AH=48 into memory at DS:SI+10h - edx=80h is hard disk 0, 81h would be hard disk 1

# set parameter in buffer area to 0 in case bios call fails

write 0x60010 0

# make bios call using grub4dos bios utility

/bios int=0x13 eax=0x4800 edx=0x80 ds=0x6000 esi=0x0 > nul

# get returned value for total sectors on disk

read 0x60010 > nul

set /A END=%@retval%-1 > nul

if %END%<=0 echo Drive too big! && exit

or for larger disks - get capacity in MB or GB

!BAT

# DISK can be 0-9, A-F only

# Returns: CAP = Capacity of disk displayed in GB

set DISK=0

# Get disk capacity

# set size of buffer available

write 0x6000 0x42 > nul

write 0x60010 0 > nul

# get size of disk from INT 13h AH=48 into memory at DS:DI+10h - edx=80h is hard disk 0, 81h would be hard disk 1

/%grub%/bios int=0x13 eax=0x4800 edx=0x8%DISK% ds=0x6000 edi=0x0 > nul

read 0x60010 > nul

set /A A=%@retval% & 0xffffffff > nul

set /a CAP=%A%>>21&0xffffffff > nul

# Get most significant dword

read 0x60014 > nul

set /A B=%@retval% & 0x1ffff > nul

set /a CAP=%B% * 0x800 + %CAP% > nul

echo DISK %DISK% = %CAP%GiB (LS_DWORD=%A% MS_DWORD=%B%, TOTAL SECTORS=%B%%%A:~2,999%)

set A=

set B=

Get disk bus and type from BIOS

Here is a batch file that gets the disk bus and disk type using the same AH=48h BIOS call, for the first 3 drives

!BAT

# Get Drive Bus and Drive Type from BIOS

set DRIVE=0

call :gettype

set DRIVE=1

call :gettype

set DRIVE=2

call :gettype

exit

:gettype

# set buffer size

write 0x60000 0x42 > nul

write 0x60010 0 > nul

/bios int=0x13 eax=0x4800 edx=0x8%DRIVE% ds=0x6000 edi=0x0 > nul

read 0x60010 > nul

#24h 4 BYTEs ASCIZ name of host bus ("ISA" or "PCI")

#28h 8 BYTEs ASCIZ name of interface type

#"ATA"

#"ATAPI"

#"SCSI"

#"USB"

#"1394" IEEE 1394 (FireWire)

#"FIBRE" Fibre Channel

set BUS= && set DTYPE=

cat --locate=PCI --skip=0x24 --length=4 (md)0x300+1 > nul && set BUS=PCI

cat --locate=ISA --skip=0x24 --length=4 (md)0x300+1 > nul && set BUS=ISA

cat --locate=USB --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=USB

cat --locate="ATA " --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=ATA

cat --locate=ATAPI --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=ATAPI

cat --locate=USB --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=USB

cat --locate=SCSI --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=SCSI

cat --locate=1394 --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=IEEE_1394

cat --locate=FIBRE --skip=0x28 --length=8 (md)0x300+1 > nul && set DTYPE=FIBRE_CHANNEL

echo Drive %DRIVE% = %BUS% %DTYPE%

goto :eof

Note that this does not work if Plop! or the grub4dos USB driver has been loaded first.

Test for SHIFT key using bios utility

Here is an example of how you can test to see if the SHIFT key is pressed when the user hits Enter to select a menu item.

Using these two lines, you can modify the menu commands - for instance, if SHIFT+ENTER is pressed when a menu item is selected, safemode parameters could be used to boot linux rather than normal parameters.

title Run Linux\nPress SHIFT+ENTER for safe mode

/bios int=0x16 eax=0x00000200 > (md)0x300+1

cat --skip=12 --length=2 (md)0x300+1 | set /a n=0x > nul

if exist n calc %n%&3 && echo SHIFT PRESSED!

#if exist n calc %n%&4 && echo CTRL PRESSED!

#LShift=01, RShift=02,CTRL=04,ALT=08,SCROLL=10,NUM=20,CAPS=40,INS=80

set sf=

if %n%>=1 set sf=acpi=off irqpoll noapic noapm nodma nomce nolapic nosmp

kernel /casper/vmlinuz file=/cdrom/preseed/ubuntu.seed boot=casper %sf% splash

initrd /casper/initrd.img

inifile

Displays or modifies a section of an ini file e.g.

inifile /dir/dir/oemsetup.inf [AAA] - displays contents of section [AAA]

inifile /dir/dir/oemsetup.inf [AAA] bbbbb=cccccc - adds new entry under section [AAA]

More Examples

insmod FAT load fat as a module into memory for faster operation - future uses of fat will execute the fat code from memory instead of loading it from disk each time.

insmod INIFILE load inifile as a module into memory

map --floppies=2 set BIOS to recognise 2 floppies

map --mem (md)0xA00+5760 (8) map memory as device 8

map --hook hook the mapping so it is active

fat mkfs (8) > nul make a fat filesystem

write --offset=0x18 (8) \x24\0\2 write to the 18th/19th/20th bytes the values 24h 00h and 02h respectively

fat mkfile size=4096 (8)/chkpci.pci make a 4096 byte file on the filesystem and name it chkpci.pci

/CHKPCI -u /DRIVERPACK.INI > (8)/chkpci.pci run chkpci and send the matching description of a pci device to the file chkpci.pci

Example of chenalll's grub4dos batch file which autocreates the correct txtsetup.oem for whatever mass storage driver can be found - taken from chenall's DPMS project.

!BAT

setlocal

debug off

checkrange 20110918:-1 read 0x8278 || echo Please use grub4dos-0.4.5b-2011-09-18 or above! && exit 1

root %~dp0

if exist %~dp0DRIVERPACK.INI && goto :DPMS_START

:dpms.iso

if /i "%~nx1"=="dpms.iso" && shift 1 && root %~dp1

map /DPMS.ISO (0xdf) || map --mem /DPMS.ISO (0xdf)

map --hook

root (0xdf)

if exist (0xdf)/DRIVERPACK.INI && goto :DPMS_START

map --unmap=0xdf

map --rehook

exit 1

:DPMS_START

set *

if /i "%1"=="pe" set WINPE=1 && shift 1 ! if /i "%2"=="pe" set WINPE=1

clear

call Fn.5 0 2

echo $[0107] ###### $[0102]Auto SCSI/RAID/SATA Driver for NT5.X/PE by chenall 2011-09-27 $[0107]#######

echo -n -e \n$[0000] $[1106] Working......\r

insmod FAT

insmod INIFILE

map --floppies=2

map --mem (md)0xA00+5760 (8)

map --hook

fat mkfs (8) > nul

write --offset=0x18 (8) \x24\0\2

fat mkfile size=4096 (8)/chkpci.pci

CHKPCI -u /DRIVERPACK.INI > (8)/chkpci.pci

echo [Disks] > (md)0x300+2

echo d1="DPMS Installation Disk by chenall(disk0)",\disk0,\ >> (md)0x300+2

set pci.max=0

set skip=0

call :·ÖÎö

if exist (0xd1)+1 && map --unmap=0xd1 && map --rehook

if %pci.max%==0 && goto :NoDriver

echo

echo $[0107] ######## $[0102]drivers from DPMS(driverpack.net) $[0107]######## $[0102]chenall.net $[0107]#############

echo

echo [chenall.net] >> (md)0x300+2

cat --locate=\0 --replace=#*chenall.net*** (md)0x300+1

echo -e -n \r\n[Defaults]\r\nscsi=$$ >> (md)0x300+2

call Fn.11 0x60000 "$$"

set scsi=%@retval%

call :fd_%1 %1

map --unmap=8

map --rehook

call Fn.73 3

goto :eof

:fd_0

:fd_1

set def=1

if %pci.max%==1 || call :Ñ¡ÔñĬÈÏ

call :ÉèÖÃĬÈÏ %def% %1

exit

:fd_

:fd_2

call :ÉèÖÃĬÈÏ 1 1

if %pci.max%==1 && goto :BLANK_FD0

call :ÉèÖÃĬÈÏ 2 0

exit

:Ñ¡ÔñĬÈÏ

echo -e -n \t\tPlease select a default driver (1-%pci.max%):\r

pause --wait=9

if %@retval%==1 && set def=1 ! set /a def=%@retval%-48

checkrange 1:%pci.max% calc %def% || goto %0

echo -e \t%def%

exit

:·ÖÎö

cat --locate=\n --skip=%skip% --number=1 (8)/chkpci.pci > nul || exit

set /a len=%?%-%skip%

cat --skip=%skip% --length=%len% (8)/chkpci.pci | call :chkpci=

set /a skip=%skip%+1+%len%

goto :·ÖÎö

:NoDriver

echo $[0104] No driver found

:Err_quit

map --unmap=8,0xdf

map --rehook

pause --wait=2

exit 1

:check_inf

shift

if "%~0"=="" exit

if /i "%~x0"==".inf" || goto :check_inf

cat --locate=%id% --number=1 /%0 > nul || goto :check_inf

inifile /%0 [SourceDisksFiles] | call :copyfiles= || inifile /%0 [SourceDisksFiles.x86] | call :copyfiles=

inifile /%0 [Version] CatalogFile | call :copyfiles %0=

exit

:copyfiles

if "%~1"=="" exit

shift

if "%~x0"=="" && goto :copyfiles

set /u filename=/%0

call :%~x0 %0 && if not exist (8)/%0 && fat copy %filename% (8)

goto :copyfiles

:.inf

echo inf=d1,%1 >> (md)0x300+2

exit

:.cat

echo catalog=d1,%1 >> (md)0x300+2

exit

:.dll

echo dll=d1,%1 >> (md)0x300+2

exit

:chkpci

setlocal

if not "%3"==";" && exit

set /u root=%~4

root %@root%/%root%

set /u sysfile=/%~5

if not exist (8)/%sysfile% && fat copy %sysfile% (8)

echo [scsi] >> (md)0x300+2

echo %~2=%6 >> (md)0x300+2

echo [HardwareIds.scsi.%~2] >> (md)0x300+2

echo -n %~1 > (md)0x200+2

set /a p_hwid=0x40000

call :addids %~n5

echo [Files.scsi.%~2] >> (md)0x300+2

echo driver=d1,%~5,%~2 >> (md)0x300+2

if exist WINPE && goto :chkpci_winpe

set /u filename=%~n5.inf

if exist /%filename% && call :check_inf %filename% ! ls | call :check_inf=

:chkpci_winpe

endlocal && set /a pci.max=%pci.max%+1

echo $[0105] PCI.%pci.max% $[0107]%1=$[0106]%2 $[0107]%3 $[0105]%4 $[0107]%5 %6

set pci.%pci.max%=%~2

exit

:addids

::call func strok

call Fn.13 %p_hwid% ","

call Fn.0 0 "id="%s","%1"" %p_hwid% | echo >> (md)0x300+2

call Fn.0 0 %p_hwid% | set id=

set id=%id:~4,16%

:addins_next

call Fn.13 0 "," || exit

call Fn.0 0 "id="%s","%1"" %@retval% | echo >> (md)0x300+2

goto :addins_next

:BLANK_FD0

echo > (md)0x200+2

write --offset=0xb (md)0x200+3 \x00\x02\x01\x01\x00\x01\x70\x00\x10\x00\xfd\x01\x00\x08\x00\x01

write 0x401FE 0xAA55

write 0x40200 0xfffffe

map --mem (md)0x200+2 (fd0)

exit

:ÉèÖÃĬÈÏ

if not exist pci.%1 && exit

map --mem (8)+1 (%2)

map --hook

echo $[0105] (fd%2) $[0107]defaults=$[0106]%pci.%1%

call Fn.0 %scsi% "%pci.%1%\r\n"

calc %scsi%+%@retval%-0x60000

fat copy /o (md)0x300+2,%@retval% (%2)/txtsetup.oem

fat mkfile (%2)/disk%2

write --offset=0x33 (%2)/txtsetup.oem %2

write --offset=0x3c (%2)/txtsetup.oem %2

exit

QGHO.BAT batch file example

For an example batch script file that dynamically creates a grub4dos menu for Ghost, see QGHO.zip in the attached zip file below.

This batch file is taken from chenalls MODBOOT project here (download the ISO)

Demo Download: File Name: modboot.iso File Size: 12.05 MB (12,636,160 bytes) Modified: May 3, 2011, 16:18:50 the MD5: E5AE83BF5D517506DED80BA4D2FB12D7 the SHA1: B5879F7C78F772ECFE985EAF1C6302BAD2E96309 Address 1: http://u .115.com/file/f0f3bc7143

Here is the QGHO.bat file contents:

!BAT

goto %1

:menu

set title=Quick Ghost v0.6

exit

:boot

set QGHO_BAT=%~nx0

insmod %0

write (md)0x220+1 !BAT\necho -P:0130 $[0106]MODBOOT MENU\necho -P:0102 $[0105]Today is %@DATE%\necho -P:-0656 $[010A]By chenall $[0103]2011-01-14\necho -P:-0602 $[0101]This menu is automatically generated by MODBOOT\0

set boot=%~nx0 MAIN_MENU %2

set copyfile=/LEVEL1/GHOST115.ZIP /BIN/SMARTDRV.EXE

exit

::ÒÔÉÏÊǹ©MODBOOTÄ£¿éµ÷Óõġ£¾ßÌå¿ÉÒԲο¼MODBOOTµÄʹÓÃ˵Ã÷

:MAIN_MENU

root %base_dir%

::ĬÈϵÄÅäÖÃÎļþ

set QGHO_CFG=QGHO.SET

::ÅжÏÅäÖÃÎļþµÄ±ê־룬Èç¹û·Ç£¡Ôò²»ÏÔʾ²Ëµ¥£¬Ö±½Ó¸ù¾ÝÅäÖÃÎļþ½øÐб¸·Ý¡¢»Ö¸´

cat --length=1 /QGHO/QGHO.SET | set CFG_FLAG=

if not %CFG_FLAG%==! && goto :QGHO

if not "%2"=="" && goto :QGHO

::Ö÷²Ëµ¥Ê¹ÓõÄÄÚ´æ

set menu=(md)0x200+8

::ÄÚ´æÇå0

echo -n > (md)0x200+9

::QGHOÅäÖÃÎļþÊýÁ¿£¨×î´óÊÇ9£©

set CFG_MAX=0

::ÒÑÑ¡ÔñµÄQGHOÅäÖÃÎļþ£¨Ä¬ÈÏÊÇQGHO.SET)

set CFG_SEL=1000000000

::QGHOÖ÷²Ëµ¥×¢ÊÍÄÚÈÝ

set QGHO_HLP=\n\t\tQuick Ghost Ver: 0.6\t\t2011-01-15\n\n\t\tby chenall QQ:366840202\t\thttp://chenall.net

set default=0

echo -e default %default^%\ndebug %debug^%\ninitscript (md)0x220+1 > %menu%

::×Ô¶¯Éú³ÉÅäÖÃÎļþÑ¡Ôñ²Ëµ¥

echo -e title ============QGHO Config File Select=================\nclear >> %menu%

::Ê×Ñ¡Éú³ÉÒ»¸öĬÈϵÄÅäÖÃÎļþ²Ëµ¥

call :check_cfg QGHO.SET

WENV dir /QGHO/qgho?.set | call :check_cfg=

echo -e title ============QGHO Config File Select=================\nclear >> %menu%

set /a default=%CFG_MAX%+2

::Èç¹ûÖ»ÓÐÒ»¸öÅäÖÃÎļþ£¬²»ÏÔʾÅäÖÃÎļþÑ¡Ôñ²Ëµ¥

if %CFG_MAX%==1 && echo -e default 0\ndebug %debug^%\ninitscript (md)0x220+1 > %menu%

::Éú³ÉQGHOÖ÷²Ëµ¥ÏîÄ¿

echo title Default: auto check\n%QGHO_HLP% >> %menu%

echo command %QGHO_BAT% QGHO=auto >> %menu%

echo title Backup\n%QGHO_HLP% >> %menu%

echo command %QGHO_BAT% QGHO=pdump >> %menu%

echo title Restore\n%QGHO_HLP% >> %menu%

echo command %QGHO_BAT% QGHO=pload >> %menu%

echo title Custom Restore\n%QGHO_HLP% >> %menu%

echo command %QGHO_BAT% CUSTOM >> %menu%

::¼ÓÔØÖ÷²Ëµ¥

configfile (md)0x200+8

exit

:check_cfg

if #%1#==## exit

::Ìø¹ýÁÙʱÅäÖÃÎļþqgho#.set

if /i "%~n1"=="qgho#" && goto :check_next_cfg

::¼ÓÔØÅäÖÃÎļþµÄMENUÉèÖÃÄÚÈÝ

/QGHO/%1 menu

echo title [%CFG_SEL:^~%CFG_MAX%,1%^]%title% >> %menu%

echo command %QGHO_BAT% SET_CFG=%1 %CFG_MAX% >> %menu%

set /a CFG_MAX=%CFG_MAX%+1

::ÅäÖÃÎļþÊýÁ¿²»ÄÜ´óÓÚ9

checkrange 0:9 calc %CFG_MAX% || exit

::Ñ­»·¶ÁÈ¡ÏÂÒ»¸öÅäÖÃÎļþ

:check_next_cfg

shift

goto :check_cfg

exit

:SET_CFG

::ÖØÖÃÅäÖÃÎļþÑ¡Ôñ״̬

write (md)0x208+1 000000000\0

::ÉèÖÃÑ¡ÔñµÄÅäÖÃÎļþ״̬Ϊ1

write --offset=%3 (md)0x208+1 1

::ÉèÖñäÁ¿

set QGHO_CFG=%2

cat (md)0x208+1,%CFG_MAX% | set CFG_SEL=

exit

:QGHO

root %base_dir%

set mode=pdump

::ĬÈϱ¸·ÝÎļþ·¾¶

set dst_path=/sys_c.gho

if %CFG_FLAG%==! goto :check

write /QGHO/QGHO.SET !

if %CFG_FLAG%==0 goto :check

set QGHO_CFG=QGHO%CFG_FLAG%.SET

goto :check

:check

::´ÓÖ¸¶¨ÅäÖÃÎļþÖжÁÈ¡ÅäÖÃ

/QGHO/%QGHO_CFG% QGHO_CFG

::×¢ÒâÏÂÃæµÄÓï¾äÊDZØÐëµÄ£¬»Ö¸´rootµÄÉ趨¡£

root (bd)

::Èç¹ûÓÐÉèÖñäÁ¿dst_chk¾ÍÖ´Ðмì²â²Ù×÷.²¢°ÑÕÒµ½µÄ·ÖÇøÉèÖÃΪdst_id

if not %dst_chk%#==# find --set-root --devices=h %dst_chk% && diskid && wenv set dst_id=*0x4ff00$

if not %src_chk%#==# find --set-root --devices=h %src_chk% && diskid && wenv set src_id=*0x4ff00$

::ÉèÖÃĬÈϲÎÊý£¬Ä¬Èϱ¸·ÝµÚÒ»¸öÓ²Å̼¤»îµÄ·ÖÇøµ½µÚÒ»Ó²ÅÌ×îºó·ÖÇø.

if %src_id%#==# find --set-root --devices=h makeactive --status && diskid && wenv set src_id=*0x4ff00$

::ûÓÐÖ¸¶¨dst_id,ʹÓÃ×îºóÒ»¸ö·ÖÇø(src_idËùÔÚ´ÅÅÌ×îºó·ÖÇø)

diskid gid=%src_id%

if %dst_id%#==# root endpart && diskid && wenv set dst_id=*0x4ff00$

::ÒÔÏÂÁ½¾äÓÃÓÚ¶¨Î»Ä¿±ê·ÖÇø.

::diskid ÃüÁîgid=XX:YY

diskid gid=%dst_id%

if not %CFG_FLAG%#==!# && goto :QGHO_BOOT

set mode=%2

::ĬÈϱ¸·Ýģʽ

:QGHO_BOOT

if /i "%mode%"=="AUTO" && set mode=pdump && cat --length=0 %dst_path% && set mode=pload

::À´Ô´·ÖÇøºÍÄ¿±ê·ÖÇø²»¿ÉÒÔÏàͬ

if %src_id%==%dst_id% && exit

::¼ì²âÊÇ·ñÓдøÃÜÂë

diskid gid=%dst_id%

if %mode%==pload && ghostpwd %dst_path% | set pwd=

::±¾À´ÊÇ%dst_id%%dst_path%

::ÓÉÓÚÅú´¦Àí½Å±¾Ö´ÐÐʱ»áÌæ»»%%Ϊ%£¬ËùÒÔÒª¶àдһ¸ö%¡£

set dst=%dst_id%%%dst_path%

WENV set dst=${dst!/=\}

echo %@TIME% Saving configuration....

write --offset=0x14 (fd9)/config.sys M4,0

echo -n > (md)0x3000+1

if not #%pwd%==# && echo -pwd=%pwd% >> (md)0x3000+1

fat copy /o (md)0x3000+1 (fd9)/qgho.ini

echo set src=%src_id% > (fd9)/SETENV.BAT

echo set dst=%dst% >> (fd9)/SETENV.BAT

echo set mode=%mode% >> (fd9)/SETENV.BAT

echo set cmd=%cmd% >> (fd9)/SETENV.BAT

echo set ramdrv=a: >> (fd9)/SETENV.BAT

echo QGHO:%mode% CFG_FILE:%QGHO_CFG%

echo %src_id% <==> %dst%

pause --wait=5 Press 'ESC' to quit, any other keys to continue... || exit 3

map (fd9) (fd0)

map --unmap=9

map --hook

chainloader (fd0)/io.sys

boot

:CUSTOM

::×Ô¶¨Òå»Ö¸´

set mode=pload

debug off

::ÁгöËùÓÐÓ²ÅÌ·ÖÇøµÚÒ»¸öÊǼ¤»îµÄ·ÖÇø

find --set-root --devices=h makeactive --status

find --devices=h root > (md)0x209+6

debug %debug%

root endpart

goto :gho_file

:custom_step1

set dst_path=%2

set menu=(md)0x210+8

echo -e default 1\ndebug %debug^%\ninitscript (md)0x220+1\ntitle =============Select Target Partition for restore=============\nclear > %menu%

WENV for /f "tokens=1" %i in ( (md)0x209+6 ) do call call part_menu custom_step2 %i "%j"

echo -e title \nclear\ntitle ==================Return=========================================\nconfigfile (md)0x218+8 >> %menu%

configfile %menu%

exit

:custom_step2

root %2 && diskid && WENV set src_id=*0x4ff00$

goto :QGHO_BOOT

:part_menu

echo title *** %2 %~3 *** >> %menu%

echo command %QGHO_BAT% %1=%2 >> %menu%

exit

:CUSTOM_DST

root %2

:gho_file

diskid && WENV set dst_id=*0x4ff00$

set menu=(md)0x218+8

echo -e -n default 2\ndebug off\ninitscript (md)0x220+1\ntitle current partition: > %menu%

root >> %menu%

echo -e \nclear\ntitle =============Select GHO file to restore============================\nclear >> %menu%

echo %@TIME% Searching gho file...

ls | call :find_gho || echo -n

echo -e \nclear\ntitle ====Search Gho file in other partition============================\nclear >> %menu%

WENV for /f "tokens=1" %i in ( (md)0x209+6 ) do call call part_menu CUSTOM_DST %i "%j"

echo -e title\nclear\ntitle==================Return======================================\nconfigfile (md)0x200+8 >> %menu%

configfile %menu%

exit

:find_gho

if "%1"=="" && exit

set tmp=%~n1

shift

if "%tmp:~-2,1%"=="~" goto :find_gho

set cur_dir=

::Èç¹ûÊÇGHOÎļþÖ±½ÓÉú³É²Ëµ¥,·ñÔò³¢ÊÔ¶ÁÈ¡×ÓĿ¼

if /i "%~x0"==".gho" && call :gho_menu %0 ! call :find_gho_sub %0

goto :find_gho

:find_gho_sub

if /i not "%~x1"=="" && exit

set cur_dir=/%1

wenv dir /%1/*.gho | call :gho_menu= || echo -n

exit

:gho_menu

if "%1"=="" && exit

set tmp=%~n1

shift

if "%tmp:~-2,1%"=="~" goto :gho_menu

echo title *** %cur_dir%/%0 *** >> %menu%

echo command %QGHO_BAT% custom_step1=%cur_dir%/%0 >> %menu%

goto :gho_menu

:error

pause %1 %2 %3 %4 %5 %6 %7 %8 %9

calc *0x8314=*0x8314|0xff