merge mainline into install
This commit is contained in:
commit
6ed71f4831
135 changed files with 7695 additions and 1076 deletions
|
@ -18,7 +18,6 @@ config.log
|
|||
config.status
|
||||
config.sub
|
||||
configure
|
||||
conf/*.mk
|
||||
*.d
|
||||
DISTLIST
|
||||
docs/*.info
|
||||
|
@ -69,6 +68,7 @@ Makefile
|
|||
mod-*.c
|
||||
missing
|
||||
*.pf2
|
||||
*.pp
|
||||
po/*.mo
|
||||
po/grub.pot
|
||||
stamp-h
|
||||
|
@ -91,7 +91,10 @@ texinfo.tex
|
|||
grub-core/lib/libgcrypt-grub
|
||||
**/.deps-util
|
||||
**/.deps-core
|
||||
**/.dirstamp
|
||||
Makefile.util.am
|
||||
grub-core/Makefile.core.am
|
||||
grub-core/Makefile.gcry.am
|
||||
grub-core/Makefile.gcry.def
|
||||
grub-core/*.module
|
||||
grub-core/*.pp
|
||||
|
|
491
ChangeLog
491
ChangeLog
|
@ -1,3 +1,466 @@
|
|||
2010-09-08 Colin Watson <cjwatson@ubuntu.com>
|
||||
|
||||
* grub-core/kern/efi/init.c (grub_efi_set_prefix): If the prefix
|
||||
starts with "(,", fill the drive containing the loaded image in
|
||||
between those two characters, but expect that a full partition
|
||||
specification including partition map names will follow.
|
||||
|
||||
2010-09-08 Robert Millan <rmh@gnu.org>
|
||||
|
||||
* configure.ac: Remove `--enable-grub-fstest' option.
|
||||
* Makefile.util.def (grub-fstest): Remove COND_GRUB_FSTEST condition.
|
||||
|
||||
* util/grub-mkconfig_lib.in (is_path_readable_by_grub): Use
|
||||
`grub-fstest' instead of `grub-probe' for readability verification.
|
||||
* util/grub-probe.c (probe): Remove readability verification kludge.
|
||||
|
||||
2010-09-08 Robert Millan <rmh@gnu.org>
|
||||
|
||||
* util/grub-mkconfig.in: Pass `--device ${GRUB_DEVICE}' when
|
||||
initializing `GRUB_FS'.
|
||||
|
||||
2010-09-08 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
Not command (!) support to GRUB script.
|
||||
|
||||
* tests/grub_script_not.in: New test.
|
||||
* Makefile.util.def: Rules for new test.
|
||||
|
||||
* grub-core/script/execute.c (grub_script_execute_cmdline): Handle
|
||||
! command as a special case.
|
||||
* grub-core/script/yylex.l (GRUB_PARSER_TOKEN_NOT): Removed.
|
||||
|
||||
2010-09-07 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
* grub-core/commands/wildcard.c (wildcard_expand): Fix wrong
|
||||
grub_free.
|
||||
|
||||
2010-09-07 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
* docs/grub.texi (Shell-like scripting): Fix @dots to @dots{}.
|
||||
|
||||
2010-09-07 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
* docs/grub.texi (Shell-like scripting): Documentation for break,
|
||||
continue, shift and return commands.
|
||||
|
||||
2010-09-06 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Rename CD-ROM to cd on BIOS.
|
||||
|
||||
* grub-core/disk/i386/pc/biosdisk.c (grub_biosdisk_get_drive): Recognise
|
||||
"cd".
|
||||
(grub_biosdisk_call_hook): Call with "cd" instead of arbitrary hdX.
|
||||
|
||||
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* grub-core/kern/emu/main.c (main): Reinit LVM and RAID.
|
||||
* util/grub-probe.c (main): Likewise.
|
||||
* util/i386/pc/grub-setup.c (main): Likewise.
|
||||
* util/sparc64/ieee1275/grub-setup.c (main): Likewise.
|
||||
Reported and debugged by: alexxy
|
||||
|
||||
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* grub-core/disk/lvm.c (grub_lvm_scan_device) [GRUB_UTIL]: Output more
|
||||
diagnostic info.
|
||||
|
||||
2010-09-05 Jo Shields <directhex@apebox.org>
|
||||
|
||||
* util/grub.d/30_os-prober.in: Add missing classes.
|
||||
|
||||
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* docs/grub.texi (Theme file format): Document new position format.
|
||||
|
||||
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* docs/grub.texi (Theme file format): Replace Box_slice_names.png with
|
||||
a table. Use @code instead of @verbatim.
|
||||
|
||||
2010-09-05 Colin D Bennett <colin@gibibit.com>
|
||||
|
||||
Gfxmenu documentation.
|
||||
|
||||
* docs/grub.texi (Theme file format): New chapter.
|
||||
|
||||
2010-09-05 Szymon Janc <szymon@janc.net.pl>
|
||||
|
||||
* grub-core/Makefile.core.def (xzio): New module.
|
||||
* grub-core/io/xzio.c: New file.
|
||||
* grub-core/lib/xzembed/xz.h: New file (from xembed).
|
||||
* grub-core/lib/xzembed/xz_config.h: Likewise.
|
||||
* grub-core/lib/xzembed/xz_dec_bcj.c: Likewise.
|
||||
* grub-core/lib/xzembed/xz_dec_lzma2.c: Likewise.
|
||||
* grub-core/lib/xzembed/xz_dec_stream.c: Likewise.
|
||||
* grub-core/lib/xzembed/xz_lzma2.h: Likewise.
|
||||
* grub-core/lib/xzembed/xz_private.h: Likewise.
|
||||
* grub-core/lib/xzembed/xz_stream.h: Likewise.
|
||||
* include/grub/file.h (grub_file_filter_id): New compression filter
|
||||
GRUB_FILE_FILTER_XZIO.
|
||||
|
||||
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* include/grub/file.h (GRUB_FILE_SIZE_UNKNOWN): New definition.
|
||||
* grub-core/disk/loopback.c (grub_loopback_open): Handle unknown file
|
||||
size.
|
||||
|
||||
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* include/grub/err.h (grub_err_t): Replace GRUB_ERR_BAD_GZIP_DATA with
|
||||
GRUB_ERR_BAD_COMPRESSED_DATA. All users updated.
|
||||
|
||||
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Uncompressed checksum support.
|
||||
|
||||
* grub-core/commands/hashsum.c (options): Add option --uncompress.
|
||||
(check_list): New parameter uncompress.
|
||||
(grub_cmd_hashsum): Handle --uncompress.
|
||||
|
||||
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Reintroduce testload.
|
||||
|
||||
* grub-core/commands/minicmd.c (grub_rescue_cmd_testload) [0]: Moved
|
||||
from here ...
|
||||
* grub-core/commands/testload.c (grub_cmd_testload): ... here.
|
||||
(GRUB_MOD_INIT): New function.
|
||||
(GRUB_MOD_FINI): Likewise.
|
||||
* grub-core/Makefile.core.def (testload): New module.
|
||||
|
||||
2010-09-05 Szymon Janc <szymon@janc.net.pl>
|
||||
|
||||
* grub-core/lib/posix_wrap/sys/types.h (bool): Transform into an enum.
|
||||
(uint8_t): New type.
|
||||
(uint16_t): Likewise.
|
||||
(uint32_t): Likewise.
|
||||
(uint64_t): Likewise.
|
||||
|
||||
2010-09-05 Szymon Janc <szymon@janc.net.pl>
|
||||
|
||||
* include/grub/crypto.h (GRUB_MD_CRC32): New definition.
|
||||
|
||||
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* grub-core/io/gzio.c (grub_gzio_open): Removed "transparent" parameter.
|
||||
Made static.
|
||||
(grub_gzfile_open): Removed. All users updated.
|
||||
(GRUB_MOD_INIT): New function.
|
||||
(GRUB_MOD_FINI): Likewise.
|
||||
* grub-core/kern/file.c (grub_file_filters_all): New variable.
|
||||
(grub_file_filters_enabled): Likewise.
|
||||
(grub_file_open): Handle filters.
|
||||
* grub-core/loader/i386/bsd.c (GRUB_MOD_INIT): Load gzio.
|
||||
* grub-core/normal/main.c (GRUB_MOD_INIT): Likewise.
|
||||
* include/grub/file.h (grub_file_filter_id_t): New type.
|
||||
(grub_file_filter_t): Likewise.
|
||||
(grub_file_filters_all): New extern variable.
|
||||
(grub_file_filters_enabled): Likewise.
|
||||
(grub_file_filter_register): New inline function.
|
||||
(grub_file_filter_unregister): Likewise.
|
||||
(grub_file_filter_disable): Likewise.
|
||||
(grub_file_filter_disable_compression): Likewise.
|
||||
* include/grub/gzio.h: Removed.
|
||||
|
||||
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
Filename expansion support for wildcards in GRUB script.
|
||||
|
||||
* tests/grub_script_expansion.in: New test.
|
||||
* Makefile.util.def: Rule for new test.
|
||||
|
||||
* grub-core/commands/wildcard.c: New file, implements filename
|
||||
expansion support for GRUB script.
|
||||
* grub-core/Makefile.core.def: Rule update for regexp.mod.
|
||||
* grub-core/script/argv.c: Cosmetic changes.
|
||||
* grub-core/script/execute.c (grub_script_arglist_to_argv):
|
||||
Refactored to perform wildcard expansion on arguments.
|
||||
* include/grub/script_sh.h (grub_script_wildcard_translator): New
|
||||
struct.
|
||||
|
||||
* tests/util/grub-shell.in: Fix quoting for read input.
|
||||
|
||||
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
Support for updating environment variables with matched substrings
|
||||
of regexp.
|
||||
|
||||
* tests/grub_cmd_regexp.in: New test.
|
||||
* Makefile.util.def: Rule for new test.
|
||||
|
||||
* grub-core/commands/regexp.c: New option -s to update environment
|
||||
variables with regexp matches.
|
||||
|
||||
2010-09-04 Szymon Janc <szymon@janc.net.pl>
|
||||
|
||||
* include/grub/file.h (grub_file): New member not_easly_seekable.
|
||||
(grub_file_seekable): New inline function.
|
||||
* grub-core/io/gzio.c (test_header): Don't test end magic if file isn't
|
||||
easily seekable.
|
||||
(grub_gzio_open): Set not_easly_seekable.
|
||||
* grub-core/fs/i386/pc/pxe.c (grub_pxefs_open): Set not_easily_seekable.
|
||||
* grub-core/io/bufio.c (grub_bufio_open): Propagate not_easily_seekable.
|
||||
|
||||
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
Support for options to appear multiple times on cmdline.
|
||||
|
||||
* include/grub/lib/arg.h (grub_arg_list_alloc): New prototype.
|
||||
* grub-core/commands/extcmd.c: Support for repeatable option.
|
||||
* grub-core/lib/arg.c (grub_arg_list_alloc): New function for
|
||||
repeatable option support.
|
||||
|
||||
Refactor menuentry into a regular command.
|
||||
|
||||
* grub-core/commands/menuentry.c: New file, menuentry command
|
||||
implementation.
|
||||
* grub-core/Makefile.core.def: Rule update for normal.mod.
|
||||
* grub-core/normal/main.c: Moved menuentry creation to
|
||||
grub-core/commands/menuentry.c.
|
||||
* grub-core/normal/menu.c (grub_menu_execute_entry): Removed.
|
||||
(grub_menu_execute_entry_real): Removed.
|
||||
* grub-core/script/execute.c (grub_script_execute_sourcecode): New
|
||||
function.
|
||||
(grub_script_execute_menuentry): Removed.
|
||||
* grub-core/script/parser.y (menuentry): Removed.
|
||||
* grub-core/script/script.c (grub_script_create_cmdmenu): Removed.
|
||||
* grub-core/script/yylex.l (menuentry): Removed.
|
||||
* include/grub/menu.h (grub_menu_init): New prototype.
|
||||
(grub_menu_fini): New prototype.
|
||||
* include/grub/normal.h (grub_normal_add_menu_entry): Removed.
|
||||
* include/grub/script_sh.h (grub_script_cmd_menuentry): Removed.
|
||||
(grub_script_execute_sourcecode): New prototype.
|
||||
|
||||
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
"return" command for GRUB script functions.
|
||||
|
||||
* tests/grub_script_return.in: New test.
|
||||
* Makefile.util.def: Rules for new test.
|
||||
|
||||
* grub-core/script/execute.c (grub_script_return): New function.
|
||||
* grub-core/script/main.c: Register/unregister return commaond.
|
||||
* include/grub/script_sh.h (grub_script_return): New prototype.
|
||||
|
||||
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
"setparams" command to update positional parameters.
|
||||
|
||||
* tests/grub_script_setparams.in: New test.
|
||||
* Makefile.util.def: Rules for new test.
|
||||
|
||||
* grub-core/script/argv.c (grub_script_argv_make): New function.
|
||||
* grub-core/script/execute.c (replace_scope): New function.
|
||||
(grub_script_setparams): New function.
|
||||
* grub-core/script/lexer.c: Remove unused variables.
|
||||
* grub-core/script/main.c: Register/unregister setparams command.
|
||||
* include/grub/script_sh.h (grub_script_argv_make): New prototype.
|
||||
(grub_script_setparams): New prototype.
|
||||
|
||||
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
* grub-core/normal/completion.c (grub_normal_do_completion): Fix
|
||||
grub_free order.
|
||||
|
||||
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
Support for passing block of commands as an argument to extcmds.
|
||||
|
||||
* Makefile.util.def: Rules for new test.
|
||||
* tests/grub_script_blockarg.in: New test.
|
||||
* grub-core/tests/test_blockarg.c: New file, block argument
|
||||
command used in the test.
|
||||
|
||||
* include/grub/extcmd.h (grub_extcmd_context): New struct.
|
||||
(grub_register_extcmd_prio): New function prototype.
|
||||
(grub_extcmd_dispatcher): New function prototype.
|
||||
* include/grub/command.h (GRUB_COMMAND_FLAG_BLOCKS): New command
|
||||
type.
|
||||
* include/grub/script_sh.h (struct grub_script): New members
|
||||
`children', `next_siblings' and `refcnt' for block arguments and
|
||||
reference counting.
|
||||
(GRUB_SCRIPT_ARG_TYPE_BLOCK): New argument type.
|
||||
(grub_script_arg): New member `script' for block argument.
|
||||
(grub_script_argv): New member `script' for block argument.
|
||||
(grub_parser_param): New member `scripts' for block argument.
|
||||
(grub_script_mem_free): New extern function prototype.
|
||||
(grub_script_ref): New function prototype.
|
||||
(grub_script_unref): New function prototype.
|
||||
|
||||
* grub-core/normal/dyncmd.c (grub_dyncmd_dispatcher): Moved to
|
||||
extcmd form to support block arguments.
|
||||
* grub-core/script/argv.c: Block arguments support.
|
||||
* grub-core/script/execute.c: Likewise.
|
||||
* grub-core/script/lexer.c: Likewise.
|
||||
* grub-core/script/main.c: Likewise.
|
||||
* grub-core/script/script.c: Likewise.
|
||||
* grub-core/script/parser.y: Likewise. New `block' and `block0'
|
||||
non-terminals.
|
||||
|
||||
* grub-core/commands/acpi.c: Update extcmd implementations with
|
||||
grub_extcmd_context_t.
|
||||
* grub-core/commands/cat.c: Likewise.
|
||||
* grub-core/commands/echo.c: Likewise.
|
||||
* grub-core/commands/extcmd.c: Likewise.
|
||||
* grub-core/commands/hashsum.c: Likewise.
|
||||
* grub-core/commands/hdparm.c: Likewise.
|
||||
* grub-core/commands/help.c: Likewise.
|
||||
* grub-core/commands/hexdump.c: Likewise.
|
||||
* grub-core/commands/i386/cpuid.c: Likewise.
|
||||
* grub-core/commands/i386/pc/drivemap.c: Likewise.
|
||||
* grub-core/commands/i386/pc/halt.c: Likewise.
|
||||
* grub-core/commands/i386/pc/sendkey.c: Likewise.
|
||||
* grub-core/commands/iorw.c: Likewise.
|
||||
* grub-core/commands/keystatus.c: Likewise.
|
||||
* grub-core/commands/loadenv.c: Likewise.
|
||||
* grub-core/commands/ls.c: Likewise.
|
||||
* grub-core/commands/lspci.c: Likewise.
|
||||
* grub-core/commands/memrw.c: Likewise.
|
||||
* grub-core/commands/probe.c: Likewise.
|
||||
* grub-core/commands/search_wrap.c: Likewise.
|
||||
* grub-core/commands/setpci.c: Likewise.
|
||||
* grub-core/commands/sleep.c: Likewise.
|
||||
* grub-core/disk/loopback.c: Likewise.
|
||||
* grub-core/hello/hello.c: Likewise.
|
||||
* grub-core/loader/i386/bsd.c: Likewise.
|
||||
* grub-core/loader/xnu.c: Likewise.
|
||||
* grub-core/term/gfxterm.c: Likewise.
|
||||
* grub-core/term/serial.c: Likewise.
|
||||
* grub-core/tests/lib/functional_test.c: Likewise.
|
||||
|
||||
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
Multi-line quoted strings support.
|
||||
|
||||
* grub-core/script/lexer.c (append_newline): Removed.
|
||||
(grub_script_lexer_yywrap): Refactored.
|
||||
(grub_script_lexer_init): Refactored.
|
||||
* grub-core/script/yylex.l (yywrap): New function.
|
||||
(grub_lexer_resplit): New function.
|
||||
(grub_lexer_unput): New function.
|
||||
* include/grub/script_sh.h (grub_lexer_param): New members, unput
|
||||
and resplit.
|
||||
* tests/grub_script_echo1.in: Added few more testcases.
|
||||
|
||||
2010-09-04 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* grub-core/kern/misc.c: Don't add abort alias in utils.
|
||||
Reported by: echoline.
|
||||
|
||||
2010-09-03 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
Add missing files into "make dist" tarball for other platforms.
|
||||
|
||||
* gentpl.py (script): Use dist_noinst_DATA instead of EXTRA_DIST.
|
||||
* conf/Makefile.common (dist_noinst_DATA): New variable.
|
||||
* conf/Makefile.extra-dist: Added missing make dist files.
|
||||
* grub-core/Makefile.core.def: Likewise.
|
||||
|
||||
2010-09-03 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Compress grub_prefix.
|
||||
|
||||
* grub-core/boot/i386/pc/lnxboot.S: Use
|
||||
GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE.
|
||||
* grub-core/kern/i386/pc/startup.S: Move grub_prefix to compressed part.
|
||||
* include/grub/offsets.h: Rename GRUB_MACHINE_DATA_END to
|
||||
GRUB_MACHINE_PREFIX_END. All users updated.
|
||||
(GRUB_KERNEL_I386_PC_PREFIX): Set to GRUB_KERNEL_I386_PC_RAW_SIZE.
|
||||
(GRUB_KERNEL_I386_PC_PREFIX_END): Set to GRUB_KERNEL_I386_PC_PREFIX
|
||||
+ 0x40.
|
||||
(GRUB_KERNEL_I386_PC_RAW_SIZE): Decrease.
|
||||
* util/grub-mkimage.c (image_target_desc): Change data_end to
|
||||
prefix_end. All users updated.
|
||||
|
||||
2010-09-03 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* grub-core/loader/i386/bsd.c (grub_freebsd_boot): Set %ebp to sane
|
||||
value.
|
||||
(grub_openbsd_boot): Likewise.
|
||||
(grub_netbsd_boot): Likewise.
|
||||
* grub-core/loader/i386/xnu.c (grub_xnu_boot_resume): Likewise.
|
||||
(grub_xnu_boot): Likewise.
|
||||
|
||||
2010-09-02 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* configure.ac: Clean LIBS variable after tests.
|
||||
|
||||
2010-09-02 Colin Watson <cjwatson@ubuntu.com>
|
||||
|
||||
* INSTALL: Document that libdevmapper needs to be 1.02.34 or later.
|
||||
|
||||
2010-09-02 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* configure.ac: Check for dm_log_with_errno_init in libdevmapper and
|
||||
echo if libdevmapper will be used.
|
||||
|
||||
2010-09-02 Ian Turner <Ian.Turner@deshaw.com>
|
||||
|
||||
* grub-core/fs/i386/pc/pxe.c (grub_pxefs_read): Keep the blocksize
|
||||
constant for the same file.
|
||||
|
||||
2010-09-02 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* grub-core/kern/i386/multiboot_mmap.c: Remove leftover include.
|
||||
|
||||
2010-09-02 Colin Watson <cjwatson@ubuntu.com>
|
||||
|
||||
* .bzrignore: Add *.pp, **/.dirstamp, grub-core/*.module, and
|
||||
grub-core/*.pp.
|
||||
|
||||
2010-09-02 Colin Watson <cjwatson@ubuntu.com>
|
||||
|
||||
Zero %ebp and %edi when entering Linux's 32-bit entry point, as
|
||||
required by the boot protocol.
|
||||
|
||||
* include/grub/i386/relocator.h (struct grub_relocator32_state): Add
|
||||
ebp and edi members.
|
||||
* grub-core/lib/i386/relocator.c (grub_relocator_boot): Handle
|
||||
state.ebp and state.edi.
|
||||
* grub-core/lib/i386/relocator32.S (grub_relocator32_start): Set
|
||||
%ebp and %edi according to grub_relocator32_ebp and
|
||||
grub_relocator32_edi respectively.
|
||||
* grub-core/loader/i386/linux.c (grub_linux_boot): Zero state.ebp
|
||||
and state.edi.
|
||||
|
||||
2010-09-02 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Add i386-pc-pxe image target.
|
||||
|
||||
* util/grub-mkimage.c (image_target_desc): New enum value
|
||||
IMAGE_I386_PC_PXE.
|
||||
(image_targets): New target i386-pc-pxe.
|
||||
(generate_image): Handle i386-pc-pxe image.
|
||||
|
||||
2010-09-02 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Fix grub_pxe_scan.
|
||||
|
||||
* grub-core/fs/i386/pc/pxe.c (grub_pxe_pxenv): Put correct type bangpxe.
|
||||
(grub_pxe_scan): Fix types and pxe_rm_entry computation.
|
||||
All users updated.
|
||||
* include/grub/i386/pc/pxe.h (grub_pxe_bangpxe): New struct.
|
||||
(grub_pxe_pxenv): Correct type.
|
||||
|
||||
2010-09-01 Colin Watson <cjwatson@ubuntu.com>
|
||||
|
||||
* NEWS: Document most of the important changes since 1.98.
|
||||
|
||||
2010-09-01 Colin Watson <cjwatson@ubuntu.com>
|
||||
|
||||
* util/grub-mkrescue.in (usage): Tidy up usage output (and hence
|
||||
generated manual page) a little.
|
||||
|
||||
2010-09-01 Colin Watson <cjwatson@ubuntu.com>
|
||||
|
||||
* docs/grub.texi: Add myself as an author.
|
||||
|
||||
2010-09-01 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* Makefile.util.def (libgrub.a): Add missing sunpc.
|
||||
Reported by: Seth Goldberg.
|
||||
|
||||
2010-08-30 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Interrupt wrapping and code simplifications.
|
||||
|
@ -162,10 +625,10 @@
|
|||
Moved from here...
|
||||
* grub-core/video/i386/pc/vbe.c (grub_vbe_bios_get_mode):
|
||||
... here. Transformed into C.
|
||||
* grub-core/kern/i386/pc/startup.S (grub_vbe_bios_getset_dac_palette_width):
|
||||
Moved from here...
|
||||
* grub-core/video/i386/pc/vbe.c (grub_vbe_bios_getset_dac_palette_width):
|
||||
... here. Transformed into C.
|
||||
* grub-core/kern/i386/pc/startup.S
|
||||
(grub_vbe_bios_getset_dac_palette_width):Moved from here...
|
||||
* grub-core/video/i386/pc/vbe.c
|
||||
(grub_vbe_bios_getset_dac_palette_width):... here. Transformed into C.
|
||||
* grub-core/kern/i386/pc/startup.S (grub_vbe_bios_set_memory_window):
|
||||
Moved from here...
|
||||
* grub-core/video/i386/pc/vbe.c (grub_vbe_bios_set_memory_window):
|
||||
|
@ -230,8 +693,26 @@
|
|||
(grub_reboot): Likewise.
|
||||
* grub-core/kern/i386/coreboot/init.c (grub_stop_floppy): Moved from here...
|
||||
* include/grub/i386/floppy.h (grub_stop_floppy): ...here. Inlined.
|
||||
* grub-core/kern/i386/pc/startup.S (grub_hard_stop): Removed.
|
||||
|
||||
* grub-core/kern/i386/pc/startup.S (grub_hard_stop)
|
||||
2010-08-30 Robert Millan <rmh@gnu.org>
|
||||
|
||||
* NEWS: Document addition of ZFS support in `grub-install' and
|
||||
`grub-mkconfig'.
|
||||
|
||||
2010-08-30 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
* conf/Makefile.common (CPPFLAGS_DEFAULT): Remove leading / from
|
||||
dprintf output.
|
||||
|
||||
2010-08-30 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Remove leftover embedding of font objects.
|
||||
|
||||
* include/grub/kernel.h (OBJ_TYPE_FONT): Removed.
|
||||
* util/grub-install.in (font): Removed.
|
||||
* util/grub-mkimage.c (generate_image): Remove font support. All users
|
||||
updated.
|
||||
|
||||
2010-08-30 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
|
|
2
INSTALL
2
INSTALL
|
@ -21,7 +21,7 @@ configuring the GRUB.
|
|||
|
||||
On GNU/Linux, you also need:
|
||||
|
||||
* libdevmapper (recommended)
|
||||
* libdevmapper 1.02.34 or later (recommended)
|
||||
|
||||
To build grub-emu, you need:
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ library = {
|
|||
common = grub-core/partmap/gpt.c;
|
||||
common = grub-core/partmap/msdos.c;
|
||||
common = grub-core/partmap/sun.c;
|
||||
common = grub-core/partmap/sunpc.c;
|
||||
common = grub-core/script/function.c;
|
||||
common = grub-core/script/lexer.c;
|
||||
common = grub-core/script/main.c;
|
||||
|
@ -182,7 +183,6 @@ program = {
|
|||
|
||||
ldadd = libgrub.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER)';
|
||||
condition = COND_GRUB_FSTEST;
|
||||
};
|
||||
|
||||
program = {
|
||||
|
@ -490,6 +490,42 @@ script = {
|
|||
common = tests/grub_script_shift.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase;
|
||||
name = grub_script_blockarg;
|
||||
common = tests/grub_script_blockarg.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase;
|
||||
name = grub_script_setparams;
|
||||
common = tests/grub_script_setparams.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase;
|
||||
name = grub_script_return;
|
||||
common = tests/grub_script_return.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase;
|
||||
name = grub_cmd_regexp;
|
||||
common = tests/grub_cmd_regexp.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase;
|
||||
name = grub_script_expansion;
|
||||
common = tests/grub_script_expansion.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase;
|
||||
name = grub_script_not;
|
||||
common = tests/grub_script_not.in;
|
||||
};
|
||||
|
||||
program = {
|
||||
testcase;
|
||||
name = example_unit_test;
|
||||
|
|
95
NEWS
95
NEWS
|
@ -1,3 +1,98 @@
|
|||
New in 1.99:
|
||||
|
||||
* New relocator. Allows for more kernel support and more
|
||||
straightforward loader writing.
|
||||
|
||||
* Handle USB pendrives exposed as floppies.
|
||||
|
||||
* New Automake-based build system.
|
||||
|
||||
* Add `sendkey' command (i386-pc only).
|
||||
|
||||
* ZFS support in `grub-install' and `grub-mkconfig'. Note: complete
|
||||
functionality requires external ZFS implementation (available from
|
||||
grub-extras).
|
||||
|
||||
* Support 1.x versions of mdadm metadata.
|
||||
|
||||
* Fix corruption when reading Reiserfs directory entries.
|
||||
|
||||
* Bidirectional text and diacritics support.
|
||||
|
||||
* Skip LVM snapshots.
|
||||
|
||||
* MIPS Yeeloong firmware port.
|
||||
|
||||
* Change grub-mkdevicemap to emit /dev/disk/by-id/ names where possible
|
||||
on GNU/Linux.
|
||||
|
||||
* Add `grub-mkconfig' support for Xen with Linux.
|
||||
|
||||
* Add `grub-mkconfig' support for initrd images on Fedora 13.
|
||||
|
||||
* Support >3GiB and <16MiB RAM in i386-qemu.
|
||||
|
||||
* Add support for Cirrus 5446 and Bochs video cards.
|
||||
|
||||
* Load more appropriate video drivers automatically in `grub-mkconfig'.
|
||||
|
||||
* USB improvements, including hotplugging/hotunplugging, hub support,
|
||||
and USB serial support.
|
||||
|
||||
* AMD Geode CS5536 support.
|
||||
|
||||
* Extensive updates to the Texinfo documentation.
|
||||
|
||||
* Add `grub-probe' support for the btrfs filesystem, permitting / to
|
||||
reside on btrfs as long as /boot is on a filesystem natively supported
|
||||
by GRUB.
|
||||
|
||||
* Handle symbolic links under /dev/mapper on GNU/Linux.
|
||||
|
||||
* Handle installation across multiple partition table types.
|
||||
|
||||
* Add `cmostest' command (i386/x86_64 only).
|
||||
|
||||
* Add support for DM-RAID disk devices on GNU/Linux.
|
||||
|
||||
* Remove `grub-mkisofs'. `grub-mkrescue' now uses GNU xorriso to build
|
||||
CD images.
|
||||
|
||||
* `grub-mkrescue' support for EFI, coreboot, and QEMU platforms.
|
||||
|
||||
* Unify `grub-mkimage' source code across platforms.
|
||||
|
||||
* Fix VGA (as opposed to VBE) video driver, formerly a terminal driver.
|
||||
|
||||
* Add menu hotkey support.
|
||||
|
||||
* Add support for the nilfs2 filesystem.
|
||||
|
||||
* `grub-probe' and `grub-mkconfig' support for NetBSD.
|
||||
|
||||
* Support setting a background image in `grub-mkconfig'.
|
||||
|
||||
* Support multiple terminals in `grub-mkconfig'.
|
||||
|
||||
* Regexp support.
|
||||
|
||||
* MIPS multiboot2 support.
|
||||
|
||||
* Multiboot2 tag support.
|
||||
|
||||
* sunpc partition table support.
|
||||
|
||||
* Add a number of new language features to GRUB script: `for', `while',
|
||||
`until', `elif', function parameters, `break', `continue', and
|
||||
`shift'.
|
||||
|
||||
* Support nested partition tables. GRUB now prefers to name partitions
|
||||
in the form `(hd0,msdos1,bsd1)' rather than `(hd0,1,a)'.
|
||||
|
||||
* Speed up consecutive hostdisk operations on the same device.
|
||||
|
||||
* Compile parts of `grub-emu' as modules.
|
||||
|
||||
New in 1.98 - 2010-03-06:
|
||||
|
||||
* Multiboot on EFI support.
|
||||
|
|
|
@ -31,7 +31,7 @@ endif
|
|||
|
||||
# Other options
|
||||
|
||||
CPPFLAGS_DEFAULT = -DGRUB_FILE=\"$(subst $(srcdir),,$<)\"
|
||||
CPPFLAGS_DEFAULT = -DGRUB_FILE=\"$(subst $(srcdir)/,,$<)\"
|
||||
CPPFLAGS_DEFAULT += -I$(builddir)
|
||||
CPPFLAGS_DEFAULT += -I$(srcdir)
|
||||
CPPFLAGS_DEFAULT += -I$(top_builddir)
|
||||
|
@ -115,6 +115,7 @@ pkglib_SCRIPTS =
|
|||
noinst_PROGRAMS =
|
||||
grubconf_SCRIPTS =
|
||||
noinst_LIBRARIES =
|
||||
dist_noinst_DATA =
|
||||
|
||||
TESTS =
|
||||
EXTRA_DIST =
|
||||
|
|
|
@ -5,6 +5,11 @@ EXTRA_DIST += gentpl.py
|
|||
EXTRA_DIST += Makefile.tpl
|
||||
EXTRA_DIST += Makefile.util.def
|
||||
|
||||
EXTRA_DIST += unicode
|
||||
|
||||
EXTRA_DIST += util/import_gcry.py
|
||||
EXTRA_DIST += util/import_unicode.py
|
||||
|
||||
EXTRA_DIST += docs/man
|
||||
EXTRA_DIST += docs/grub.cfg
|
||||
|
||||
|
@ -26,8 +31,8 @@ EXTRA_DIST += grub-core/genterminallist.sh
|
|||
EXTRA_DIST += grub-core/genparttoollist.sh
|
||||
EXTRA_DIST += grub-core/genemuinitheader.sh
|
||||
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt/cipher
|
||||
EXTRA_DIST += $(shell find $(top_srcdir)/include -name '*.h')
|
||||
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/gnulib -name '*.h')
|
||||
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/efiemu -name '*.h')
|
||||
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib/posix_wrap -name '*.h')
|
||||
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib/libgcrypt_wrap -name '*.h')
|
||||
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib -name '*.h')
|
||||
|
|
45
configure.ac
45
configure.ac
|
@ -762,19 +762,6 @@ AC_SUBST([enable_grub_emu_usb])
|
|||
AC_SUBST([enable_grub_emu_pci])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([grub-fstest],
|
||||
[AS_HELP_STRING([--enable-grub-fstest],
|
||||
[build and install the `grub-fstest' debugging utility (default=guessed)])])
|
||||
if test x"$enable_grub_fstest" = xno ; then
|
||||
grub_fstest_excuse="explicitly disabled"
|
||||
fi
|
||||
if test x"$grub_fstest_excuse" = x ; then
|
||||
enable_grub_fstest=yes
|
||||
else
|
||||
enable_grub_fstest=no
|
||||
fi
|
||||
AC_SUBST([enable_grub_fstest])
|
||||
|
||||
AC_ARG_ENABLE([grub-mkfont],
|
||||
[AS_HELP_STRING([--enable-grub-mkfont],
|
||||
[build and install the `grub-mkfont' utility (default=guessed)])])
|
||||
|
@ -822,12 +809,23 @@ fi
|
|||
|
||||
if test x"$device_mapper_excuse" = x ; then
|
||||
# Check for device-mapper library.
|
||||
AC_CHECK_LIB([devmapper], [dm_task_create],
|
||||
[LIBDEVMAPPER="-ldevmapper"
|
||||
AC_DEFINE([HAVE_DEVICE_MAPPER], [1],
|
||||
[Define to 1 if you have the devmapper library.])],
|
||||
AC_CHECK_LIB([devmapper], [dm_task_create], [],
|
||||
[device_mapper_excuse="need devmapper library"])
|
||||
fi
|
||||
|
||||
if test x"$device_mapper_excuse" = x ; then
|
||||
# Check for device-mapper library.
|
||||
AC_CHECK_LIB([devmapper], [dm_log_with_errno_init],
|
||||
[],
|
||||
[device_mapper_excuse="need devmapper library"])
|
||||
fi
|
||||
|
||||
if test x"$device_mapper_excuse" = x ; then
|
||||
LIBDEVMAPPER="-ldevmapper";
|
||||
AC_DEFINE([HAVE_DEVICE_MAPPER], [1],
|
||||
[Define to 1 if you have the devmapper library.])
|
||||
fi
|
||||
|
||||
AC_SUBST([LIBDEVMAPPER])
|
||||
|
||||
AC_CHECK_LIB([zfs], [libzfs_init],
|
||||
|
@ -842,6 +840,8 @@ AC_CHECK_LIB([nvpair], [nvlist_print],
|
|||
[Define to 1 if you have the NVPAIR library.])],)
|
||||
AC_SUBST([LIBNVPAIR])
|
||||
|
||||
LIBS=""
|
||||
|
||||
pkglibrootdir='$(libdir)'/`echo $PACKAGE | sed "$program_transform_name"`
|
||||
AC_SUBST(pkglibrootdir)
|
||||
|
||||
|
@ -892,7 +892,6 @@ AM_CONDITIONAL([COND_GRUB_EMU_SDL], [test x$enable_grub_emu_sdl = xyes])
|
|||
AM_CONDITIONAL([COND_GRUB_EMU_PCI], [test x$enable_grub_emu_pci = xyes])
|
||||
AM_CONDITIONAL([COND_GRUB_MKFONT], [test x$enable_grub_mkfont = xyes])
|
||||
AM_CONDITIONAL([COND_HAVE_FONT_SOURCE], [test x$FONT_SOURCE != x])
|
||||
AM_CONDITIONAL([COND_GRUB_FSTEST], [test x$enable_grub_fstest = xyes])
|
||||
AM_CONDITIONAL([COND_GRUB_PE2ELF], [test x$TARGET_OBJ2ELF != x])
|
||||
AM_CONDITIONAL([COND_APPLE_CC], [test x$TARGET_APPLE_CC = x1])
|
||||
AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes])
|
||||
|
@ -942,6 +941,11 @@ else
|
|||
echo PCI support for grub-emu: No "($grub_emu_pci_excuse)"
|
||||
fi
|
||||
fi
|
||||
if test x"$device_mapper_excuse" = x ; then
|
||||
echo With devmapper support: Yes
|
||||
else
|
||||
echo With devmapper support: No "($device_mapper_excuse)"
|
||||
fi
|
||||
if [ x"$enable_mm_debug" = xyes ]; then
|
||||
echo With memory debugging: Yes
|
||||
else
|
||||
|
@ -952,11 +956,6 @@ echo efiemu runtime: Yes
|
|||
else
|
||||
echo efiemu runtime: No "($efiemu_excuse)"
|
||||
fi
|
||||
if [ x"$grub_fstest_excuse" = x ]; then
|
||||
echo grub-fstest: Yes
|
||||
else
|
||||
echo grub-fstest: No "($grub_fstest_excuse)"
|
||||
fi
|
||||
if [ x"$grub_mkfont_excuse" = x ]; then
|
||||
echo grub-mkfont: Yes
|
||||
else
|
||||
|
|
427
docs/grub.texi
427
docs/grub.texi
|
@ -46,6 +46,8 @@ Invariant Sections.
|
|||
@subtitle The GRand Unified Bootloader, version @value{VERSION}, @value{UPDATED}.
|
||||
@author Gordon Matzigkeit
|
||||
@author Yoshinori K. Okuji
|
||||
@author Colin Watson
|
||||
@author Colin D. Bennett
|
||||
@c The following two commands start the copyright page.
|
||||
@page
|
||||
@vskip 0pt plus 1filll
|
||||
|
@ -77,6 +79,7 @@ This edition documents version @value{VERSION}.
|
|||
* Installation:: Installing GRUB on your drive
|
||||
* Booting:: How to boot different operating systems
|
||||
* Configuration:: Writing your own configuration file
|
||||
* Theme file format:: Format of GRUB theme files
|
||||
* Network:: Downloading OS images from a network
|
||||
* Serial terminal:: Using GRUB via a serial line
|
||||
* Vendor power-on keys:: Changing GRUB behaviour on vendor power-on keys
|
||||
|
@ -964,7 +967,6 @@ need to write the whole thing by hand.
|
|||
* Simple configuration:: Recommended for most users
|
||||
* Shell-like scripting:: For power users and developers
|
||||
* Embedded configuration:: Embedding a configuration file into GRUB
|
||||
* Themes:: Graphical menu themes
|
||||
@end menu
|
||||
|
||||
|
||||
|
@ -1126,7 +1128,6 @@ The image will be scaled if necessary to fit the screen.
|
|||
|
||||
@item GRUB_THEME
|
||||
Set a theme for use with the @samp{gfxterm} graphical terminal.
|
||||
@xref{Themes}.
|
||||
|
||||
@item GRUB_GFXPAYLOAD_LINUX
|
||||
Set to @samp{text} to force the Linux kernel to boot in normal text mode,
|
||||
|
@ -1226,8 +1227,10 @@ The @samp{$} character retains its special meaning within double quotes.
|
|||
The backslash retains its special meaning only when followed by one of the
|
||||
following characters: @samp{$}, @samp{"}, @samp{\}, or newline. A
|
||||
backslash-newline pair is treated as a line continuation (that is, it is
|
||||
removed from the input stream and effectively ignored). A double quote may
|
||||
be quoted within double quotes by preceding it with a backslash.
|
||||
removed from the input stream and effectively ignored@footnote{Currently a
|
||||
backslash-newline pair within a variable name is not handled properly, so
|
||||
use this feature with some care.}). A double quote may be quoted within
|
||||
double quotes by preceding it with a backslash.
|
||||
|
||||
@heading Variable expansion
|
||||
|
||||
|
@ -1239,11 +1242,15 @@ which could be interpreted as part of the name.
|
|||
Normal variable names begin with an alphabetic character, followed by zero
|
||||
or more alphanumeric characters.
|
||||
|
||||
Positional variable names consist of one or more digits. These are reserved
|
||||
for future expansion.
|
||||
Positional variable names consist of one or more digits. They represent
|
||||
parameters passed to function calls, with @samp{$1} representing the first
|
||||
parameter, and so on.
|
||||
|
||||
The special variable name @samp{?} expands to the exit status of the most
|
||||
recently executed command.
|
||||
recently executed command. When positional variable names are active, other
|
||||
special variable names @samp{@@}, @samp{*} and @samp{#} are defined and they
|
||||
expand to all positional parameters with necessary quoting, positional
|
||||
parameters without any quoting, and positional parameter count respectively.
|
||||
|
||||
@heading Comments
|
||||
|
||||
|
@ -1304,6 +1311,45 @@ the body.
|
|||
@xref{menuentry}.
|
||||
@end table
|
||||
|
||||
@heading Built-in Commands
|
||||
|
||||
Some built-in commands are also provided by GRUB script to help script
|
||||
writers perform actions that are otherwise not possible. For example, these
|
||||
include commands to jump out of a loop without fully completing it, etc.
|
||||
|
||||
@table @asis
|
||||
@item break [@code{n}]
|
||||
Exit from within a @code{for}, @code{while}, or @code{until} loop. If
|
||||
@code{n} is specified, break @code{n} levels. @code{n} must be greater than
|
||||
or equal to 1. If @code{n} is greater than the number of enclosing loops,
|
||||
all enclosing loops are exited. The return value is 0 unless @code{n} is
|
||||
not greater than or equal to 1.
|
||||
|
||||
@item continue [@code{n}]
|
||||
Resume the next iteration of the enclosing @code{for}, @code{while} or
|
||||
@code{until} loop. If @code{n} is specified, resume at the @code{n}th
|
||||
enclosing loop. @code{n} must be greater than or equal to 1. If @code{n}
|
||||
is greater than the number of enclosing loops, the last enclosing loop (the
|
||||
@dfn{top-level} loop) is resumed. The return value is 0 unless @code{n} is
|
||||
not greater than or equal to 1.
|
||||
|
||||
@item return [@code{n}]
|
||||
Causes a function to exit with the return value specified by @code{n}. If
|
||||
@code{n} is omitted, the return status is that of the last command executed
|
||||
in the function body. If used outside a function the return status is
|
||||
false.
|
||||
|
||||
@item shift [@code{n}]
|
||||
The positional parameters from @code{n}+1 @dots{} are renamed to
|
||||
@code{$1}@dots{}. Parameters represented by the numbers @code{$#} down to
|
||||
@code{$#}-@code{n}+1 are unset. @code{n} must be a non-negative number less
|
||||
than or equal to @code{$#}. If @code{n} is 0, no parameters are changed.
|
||||
If @code{n} is not given, it is assumed to be 1. If @code{n} is greater
|
||||
than @code{$#}, the positional parameters are not changed. The return
|
||||
status is greater than zero if @code{n} is greater than @code{$#} or less
|
||||
than zero; otherwise 0.
|
||||
|
||||
@end table
|
||||
|
||||
@node Embedded configuration
|
||||
@section Embedding a configuration file into GRUB
|
||||
|
@ -1372,9 +1418,372 @@ fi
|
|||
The embedded configuration file may not contain menu entries directly, but
|
||||
may only read them from elsewhere using @command{configfile}.
|
||||
|
||||
@node Theme file format
|
||||
@chapter Theme file format
|
||||
@section Introduction
|
||||
The GRUB graphical menu supports themes that can customize the layout and
|
||||
appearance of the GRUB boot menu. The theme is configured through a plain
|
||||
text file that specifies the layout of the various GUI components (including
|
||||
the boot menu, timeout progress bar, and text messages) as well as the
|
||||
appearance using colors, fonts, and images. Example is available in docs/example_theme.txt
|
||||
|
||||
@section Theme Elements
|
||||
@subsection Colors
|
||||
|
||||
Colors can be specified in several ways:
|
||||
|
||||
@itemize
|
||||
@item HTML-style ``#RRGGBB'' or ``#RGB'' format, where *R*, *G*, and *B* are hexadecimal digits (e.g., ``#8899FF'')
|
||||
@item as comma-separated decimal RGB values (e.g., ``128, 128, 255'')
|
||||
@item with ``SVG 1.0 color names'' (e.g., ``cornflowerblue'') which must be specified in lowercase.
|
||||
@end itemize
|
||||
@subsection Fonts
|
||||
The fonts GRUB uses ``PFF2 font format'' bitmap fonts. Fonts are specified
|
||||
with full font names. Currently there is no
|
||||
provision for a preference list of fonts, or deriving one font from another.
|
||||
Fonts are loaded with the ``loadfont'' command in GRUB. To see the list of
|
||||
loaded fonts, execute the ``lsfonts'' command. If there are too many fonts to
|
||||
fit on screen, do ``set pager=1'' before executing ``lsfonts''.
|
||||
|
||||
|
||||
@subsection Progress Bar
|
||||
|
||||
@float Figure, Pixmap-styled progress bar
|
||||
@c @image{Theme_progress_bar,,,,.png}
|
||||
@end float
|
||||
|
||||
@float Figure, Plain progress bar, drawn with solid color.
|
||||
@c @image{Theme_progress_bar_filled,,,,.png}
|
||||
@end float
|
||||
|
||||
Progress bars are used to display the remaining time before GRUB boots the
|
||||
default menu entry. To create a progress bar that will display the remaining
|
||||
time before automatic boot, simply create a ``progress_bar'' component with
|
||||
the id ``__timeout__''. This indicates to GRUB that the progress bar should
|
||||
be updated as time passes, and it should be made invisible if the countdown to
|
||||
automatic boot is interrupted by the user.
|
||||
|
||||
Progress bars may optionally have text displayed on them. This is controlled
|
||||
through the ``show_text'' property, which can be set to either ``true'' or
|
||||
``false'' to control whether text is displayed. When GRUB is counting down to
|
||||
automatic boot, the text informs the user of the number of seconds remaining.
|
||||
|
||||
|
||||
@subsection Circular Progress Indicator
|
||||
|
||||
@c @image{Theme_circular_progress,,,,.png}
|
||||
|
||||
The circular progress indicator functions similarly to the progress bar. When
|
||||
given an id of ``__timeout__'', GRUB updates the circular progress indicator's
|
||||
value to indicate the time remaining. For the circular progress indicator,
|
||||
there are two images used to render it: the *center* image, and the *tick*
|
||||
image. The center image is rendered in the center of the component, while the
|
||||
tick image is used to render each mark along the circumference of the
|
||||
indicator.
|
||||
|
||||
|
||||
@subsection Labels
|
||||
|
||||
Text labels can be placed on the boot screen. The font, color, and horizontal
|
||||
alignment can be specified for labels. If a label is given the id
|
||||
``__timeout__'', then the ``text'' property for that label is also updated
|
||||
with a message informing the user of the number of seconds remaining until
|
||||
automatic boot. This is useful in case you want the text displayed somewhere
|
||||
else instead of directly on the progress bar.
|
||||
|
||||
|
||||
@subsection Boot Menu
|
||||
|
||||
@c @image{Theme_boot_menu,,,,.png}
|
||||
|
||||
The boot menu where GRUB displays the menu entries from the ``grub.cfg'' file.
|
||||
It is a list of items, where each item has a title and an optional icon. The
|
||||
icon is selected based on the *classes* specified for the menu entry. If
|
||||
there is a PNG file named ``myclass.png'' in the ``grub/themes/icons''
|
||||
directory, it will be displayed for items which have the class *myclass*. The
|
||||
boot menu can be customized in several ways, such as the font and color used
|
||||
for the menu entry title, and by specifying styled boxes for the menu itself
|
||||
and for the selected item highlight.
|
||||
|
||||
|
||||
@subsection Styled Boxes
|
||||
|
||||
One of the most important features for customizing the layout is the use of
|
||||
*styled boxes*. A styled box is composed of 9 rectangular (and potentially
|
||||
empty) regions, which are used to seamlessly draw the styled box on screen:
|
||||
|
||||
@multitable @columnfractions 0.3 0.3 0.3
|
||||
@item Northwest (nw) @tab North (n) @tab Northeast (ne)
|
||||
@item West (w) @tab Center (c) @tab East (e)
|
||||
@item Southwest (sw) @tab South (s) @tab Southeast (se)
|
||||
@end multitable
|
||||
|
||||
To support any size of box on screen, the center slice and the slices for the
|
||||
top, bottom, and sides are all scaled to the correct size for the component on
|
||||
screen, using the following rules:
|
||||
|
||||
@enumerate
|
||||
@item The edge slices (north, south, east, and west) are scaled in the direction of the edge they are adjacent to. For instance, the west slice is scaled vertically.
|
||||
@item The corner slices (northwest, northeast, southeast, and southwest) are not scaled.
|
||||
@item The center slice is scaled to fill the remaining space in the middle.
|
||||
@end enumerate
|
||||
|
||||
As an example of how an image might be sliced up, consider the styled box
|
||||
used for a terminal view.
|
||||
|
||||
@float Figure, An example of the slices (in red) used for a terminal window. This drawing was created and sliced in Inkscape_, as the next section explains.
|
||||
@c @image{Box_slice_example_terminal,,,,.png}
|
||||
@end float
|
||||
|
||||
@subsection Creating Styled Box Images
|
||||
|
||||
The Inkscape_ scalable vector graphics editor is a very useful tool for
|
||||
creating styled box images. One process that works well for slicing a drawing
|
||||
into the necessary image slices is:
|
||||
|
||||
@enumerate
|
||||
@item Create or open the drawing you'd like use.
|
||||
@item Create a new layer on the top of the layer stack. Make it visible. Select this layer as the current layer.
|
||||
@item Draw 9 rectangles on your drawing where you'd like the slices to be. Clear the fill option, and set the stroke to 1 pixel wide solid stroke. The corners of the slices must meet precisely; if it is off by a single pixel, it will probably be evident when the styled box is rendered in the GRUB menu. You should probably go to File | Document Properties | Grids and enable a grid or create a guide (click on one of the rulers next to the drawing and drag over the drawing; release the mouse button to place the guide) to help place the rectangles precisely.
|
||||
@item Right click on the center slice rectangle and choose Object Properties. Change the "Id" to ``slice_c`` and click Set. Repeat this for the remaining 8 rectangles, giving them Id values of ``slice_n``, ``slice_ne``, ``slice_e``, and so on according to the location.
|
||||
@item Save the drawing.
|
||||
@item Select all the slice rectangles. With the slice layer selected, you can simply press Ctrl+A to select all rectangles. The status bar should indicate that 9 rectangles are selected.
|
||||
@item Click the layer hide icon for the slice layer in the layer palette. The rectangles will remain selected, even though they are hidden.
|
||||
@item Choose File | Export Bitmap and check the *Batch export 9 selected objects* box. Make sure that *Hide all except selected* is unchecked. click *Export*. This will create PNG files in the same directory as the drawing, named after the slices. These can now be used for a styled box in a GRUB theme.
|
||||
@end enumerate
|
||||
|
||||
@section Theme File Manual
|
||||
|
||||
The theme file is a plain text file. Lines that begin with ``#`` are ignored
|
||||
and considered comments. (Note: This may not be the case if the previous line
|
||||
ended where a value was expected.)
|
||||
|
||||
The theme file contains two types of statements:
|
||||
@enumerate
|
||||
@item Global properties.
|
||||
@item Component construction.
|
||||
@end enumerate
|
||||
|
||||
@subsection Global Properties
|
||||
|
||||
@subsection Format
|
||||
|
||||
Global properties are specified with the simple format:
|
||||
@itemize
|
||||
@item name1: value1
|
||||
@item name2: "value which may contain spaces"
|
||||
@item name3: #88F
|
||||
@end itemize
|
||||
|
||||
In this example, name3 is assigned a color value.
|
||||
|
||||
|
||||
@subsection Global Property List
|
||||
|
||||
@multitable @columnfractions 0.3 0.6
|
||||
@item title-text @tab Specifies the text to display at the top center of the screen as a title.
|
||||
@item title-font @tab Defines the font used for the title message at the top of the screen.
|
||||
@item title-color @tab Defines the color of the title message.
|
||||
@item message-font @tab Defines the font used for messages, such as when GRUB is unable to automatically boot an entry.
|
||||
@item message-color @tab Defines the color of the message text.
|
||||
@item message-bg-color @tab Defines the background color of the message text area.
|
||||
@item desktop-image @tab Specifies the image to use as the background. It will be scaled to fit the screen size.
|
||||
@item desktop-color @tab Specifies the color for the background if *desktop-image* is not specified.
|
||||
@item terminal-box @tab Specifies the file name pattern for the styled box slices used for the command line terminal window. For example, ``terminal-box: terminal_*.png'' will use the images ``terminal_c.png`` as the center area, ``terminal_n.png`` as the north (top) edge, ``terminal_nw.png`` as the northwest (upper left) corner, and so on. If the image for any slice is not found, it will simply be left empty.
|
||||
@end multitable
|
||||
|
||||
|
||||
@subsection Component Construction
|
||||
|
||||
Greater customizability comes is provided by components. A tree of components
|
||||
forms the user interface. *Containers* are components that can contain other
|
||||
components, and there is always a single root component which is an instance
|
||||
of a *canvas* container.
|
||||
|
||||
Components are created in the theme file by prefixing the type of component
|
||||
with a '+' sign:
|
||||
|
||||
@code{ + label @{ text="GRUB" font="aqui 11" color="#8FF" @} }
|
||||
|
||||
properties of a component are specified as "name = value" (whitespace
|
||||
surrounding tokens is optional and is ignored) where *value* may be:
|
||||
@itemize
|
||||
@item a single word (e.g., ``align = center``, ``color = #FF8080``),
|
||||
@item a quoted string (e.g., ``text = "Hello, World!"``), or
|
||||
@item a tuple (e.g., ``preferred_size = (120, 80)``).
|
||||
@end itemize
|
||||
|
||||
@subsection Component List
|
||||
|
||||
The following is a list of the components and the properties they support.
|
||||
|
||||
@itemize
|
||||
@item label
|
||||
A label displays a line of text.
|
||||
|
||||
Properties:
|
||||
@multitable @columnfractions 0.2 0.7
|
||||
@item text @tab The text to display.
|
||||
@item font @tab The font to use for text display.
|
||||
@item color @tab The color of the text.
|
||||
@item align @tab The horizontal alignment of the text within the component. Options are ``left``, ``center``, and ``right``.
|
||||
@end multitable
|
||||
|
||||
@item image
|
||||
A component that displays an image. The image is scaled to fit the
|
||||
component, although the preferred size defaults to the image's original
|
||||
size unless the ``preferred_size`` property is explicitly set.
|
||||
|
||||
Properties:
|
||||
|
||||
@multitable @columnfractions 0.2 0.7
|
||||
@item file @tab The full path to the image file to load.
|
||||
@end multitable
|
||||
|
||||
@item progress_bar
|
||||
Displays a horizontally oriented progress bar. It can be rendered using
|
||||
simple solid filled rectangles, or using a pair of pixmap styled boxes.
|
||||
|
||||
Properties:
|
||||
|
||||
@multitable @columnfractions 0.2 0.7
|
||||
@item fg_color @tab The foreground color for plain solid color rendering.
|
||||
@item bg_color @tab The background color for plain solid color rendering.
|
||||
@item border_color @tab The border color for plain solid color rendering.
|
||||
@item text_color @tab The text color.
|
||||
@item show_text @tab Boolean value indicating whether or not text should be displayed on the progress bar. If set to *false*, then no text will be displayed on the bar. If set to any other value, text will be displayed on the bar.
|
||||
@item bar_style @tab The styled box specification for the frame of the progress bar. Example: ``progress_frame_*.png``
|
||||
@item highlight_style @tab The styled box specification for the highlighted region of the progress bar. This box will be used to paint just the highlighted region of the bar, and will be increased in size as the bar nears completion. Example: ``progress_hl_*.png``.
|
||||
@item text @tab The text to display on the progress bar. If the progress bar's ID is set to ``__timeout__``, then GRUB will updated this property with an informative message as the timeout approaches.
|
||||
@item value @tab The progress bar current value. Normally not set manually.
|
||||
@item start @tab The progress bar start value. Normally not set manually.
|
||||
@item end @tab The progress bar end value. Normally not set manually.
|
||||
@end multitable
|
||||
|
||||
@item circular_progress
|
||||
Displays a circular progress indicator. The appearance of this component
|
||||
is determined by two images: the *center* image and the *tick* image. The
|
||||
center image is generally larger and will be drawn in the center of the
|
||||
component. Around the circumference of a circle within the component, the
|
||||
tick image will be drawn a certain number of times, depending on the
|
||||
properties of the component.
|
||||
|
||||
Properties:
|
||||
|
||||
@multitable @columnfractions 0.3 0.6
|
||||
@item center_bitmap
|
||||
@tab The file name of the image to draw in the center of the component.
|
||||
@item tick_bitmap
|
||||
@tab The file name of the image to draw for the tick marks.
|
||||
@item num_ticks
|
||||
@tab The number of ticks that make up a full circle.
|
||||
@item ticks_disappear
|
||||
@tab Boolean value indicating whether tick marks should progressively appear,
|
||||
or progressively disappear as *value* approaches *end*. Specify
|
||||
``true`` or ``false``.
|
||||
@item value
|
||||
@tab The progress indicator current value. Normally not set manually.
|
||||
@item start
|
||||
@tab The progress indicator start value. Normally not set manually.
|
||||
@item end
|
||||
@tab The progress indicator end value. Normally not set manually.
|
||||
@end multitable
|
||||
@item boot_menu
|
||||
Displays the GRUB boot menu. It allows selecting items and executing them.
|
||||
|
||||
Properties:
|
||||
|
||||
@multitable @columnfractions 0.4 0.5
|
||||
@item item_font
|
||||
@tab The font to use for the menu item titles.
|
||||
@item selected_item_font
|
||||
@tab The font to use for the selected menu item, or ``inherit`` (the default)
|
||||
to use ``item_font`` for the selected menu item as well.
|
||||
@item item_color
|
||||
@tab The color to use for the menu item titles.
|
||||
@item selected_item_color
|
||||
@tab The color to use for the selected menu item, or ``inherit`` (the default)
|
||||
to use ``item_color`` for the selected menu item as well.
|
||||
@item icon_width
|
||||
@tab The width of menu item icons. Icons are scaled to the specified size.
|
||||
@item icon_height
|
||||
@tab The height of menu item icons.
|
||||
@item item_height
|
||||
@tab The height of each menu item in pixels.
|
||||
@item item_padding
|
||||
@tab The amount of space in pixels to leave on each side of the menu item
|
||||
contents.
|
||||
@item item_icon_space
|
||||
@tab The space between an item's icon and the title text, in pixels.
|
||||
@item item_spacing
|
||||
@tab The amount of space to leave between menu items, in pixels.
|
||||
@item menu_pixmap_style
|
||||
@tab The image file pattern for the menu frame styled box.
|
||||
Example: ``menu_*.png`` (this will use images such as ``menu_c.png``,
|
||||
``menu_w.png``, `menu_nw.png``, etc.)
|
||||
@item selected_item_pixmap_style
|
||||
@tab The image file pattern for the selected item highlight styled box.
|
||||
@item scrollbar
|
||||
@tab Boolean value indicating whether the scroll bar should be drawn if the
|
||||
frame and thumb styled boxes are configured.
|
||||
@item scrollbar_frame
|
||||
@tab The image file pattern for the entire scroll bar.
|
||||
Example: ``scrollbar_*.png``
|
||||
@item scrollbar_thumb
|
||||
@tab The image file pattern for the scroll bar thumb (the part of the scroll
|
||||
bar that moves as scrolling occurs).
|
||||
Example: ``scrollbar_thumb_*.png``
|
||||
@item max_items_shown
|
||||
@tab The maximum number of items to show on the menu. If there are more than
|
||||
*max_items_shown* items in the menu, the list will scroll to make all
|
||||
items accessible.
|
||||
@end multitable
|
||||
|
||||
@item canvas
|
||||
Canvas is a container that allows manual placement of components within it.
|
||||
It does not alter the positions of its child components. It assigns all
|
||||
child components their preferred sizes.
|
||||
|
||||
@item hbox
|
||||
The *hbox* container lays out its children from left to right, giving each
|
||||
one its preferred width. The height of each child is set to the maximum of
|
||||
the preferred heights of all children.
|
||||
|
||||
@item vbox
|
||||
The *vbox* container lays out its children from top to bottom, giving each
|
||||
one its preferred height. The width of each child is set to the maximum of
|
||||
the preferred widths of all children.
|
||||
@end itemize
|
||||
|
||||
|
||||
@subsection Common properties
|
||||
|
||||
The following properties are supported by all components:
|
||||
@table @samp
|
||||
@item left
|
||||
The distance from the left border of container to left border of the object in either of three formats:
|
||||
@multitable @columnfractions 0.2 0.7
|
||||
@item x @tab Value in pixels
|
||||
@item p% @tab Percentage
|
||||
@item p%+x @tab mixture of both
|
||||
@end multitable
|
||||
@item top
|
||||
The distance from the left border of container to left border of the object in same format.
|
||||
@item width
|
||||
The width of object in same format.
|
||||
@item height
|
||||
The height of object in same format.
|
||||
@item id
|
||||
The identifier for the component. This can be any arbitrary string.
|
||||
The ID can be used by scripts to refer to various components in the GUI
|
||||
component tree. Currently, there is one special ID value that GRUB
|
||||
recognizes:
|
||||
|
||||
@multitable @columnfractions 0.2 0.7
|
||||
@item ``__timeout__`` @tab Any component with this ID will have its *text*, *start*, *end*, *value*, and *visible* properties set by GRUB when it is counting down to an automatic boot of the default menu entry.
|
||||
@end multitable
|
||||
@end table
|
||||
|
||||
@node Themes
|
||||
@section Graphical menu themes
|
||||
|
||||
|
||||
@node Network
|
||||
|
|
|
@ -478,7 +478,7 @@ chmod a+x [+ name +]
|
|||
""")
|
||||
|
||||
r += gvar_add("CLEANFILES", "[+ name +]")
|
||||
r += gvar_add("EXTRA_DIST", platform_sources(platform))
|
||||
r += gvar_add("dist_noinst_DATA", platform_sources(platform))
|
||||
return r
|
||||
|
||||
def module_rules():
|
||||
|
|
|
@ -137,6 +137,7 @@ kernel = {
|
|||
mips_yeeloong = term/at_keyboard.c;
|
||||
mips_yeeloong = term/serial.c;
|
||||
mips_yeeloong = video/sm712.c;
|
||||
extra_dist = video/sm712_init.c;
|
||||
|
||||
powerpc_ieee1275 = kern/ieee1275/init.c;
|
||||
powerpc_ieee1275 = kern/powerpc/cache.S;
|
||||
|
@ -394,6 +395,7 @@ module = {
|
|||
module = {
|
||||
name = regexp;
|
||||
common = commands/regexp.c;
|
||||
common = commands/wildcard.c;
|
||||
ldadd = libgnulib.a;
|
||||
cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
|
||||
cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
|
||||
|
@ -1009,6 +1011,9 @@ module = {
|
|||
powerpc = lib/powerpc/relocator_asm.S;
|
||||
powerpc = lib/powerpc/relocator.c;
|
||||
|
||||
extra_dist = lib/i386/relocator_common.S;
|
||||
extra_dist = kern/powerpc/cache_flush.S;
|
||||
|
||||
enable = mips;
|
||||
enable = powerpc;
|
||||
enable = x86;
|
||||
|
@ -1160,6 +1165,8 @@ module = {
|
|||
common = script/lexer.c;
|
||||
common = script/argv.c;
|
||||
|
||||
common = commands/menuentry.c;
|
||||
|
||||
common = unidata.c;
|
||||
common_nodist = grub_script.tab.c;
|
||||
common_nodist = grub_script.yy.c;
|
||||
|
@ -1376,3 +1383,22 @@ module = {
|
|||
name = datehook;
|
||||
common = hook/datehook.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = test_blockarg;
|
||||
common = tests/test_blockarg.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = xzio;
|
||||
common = io/xzio.c;
|
||||
common = lib/xzembed/xz_dec_bcj.c;
|
||||
common = lib/xzembed/xz_dec_lzma2.c;
|
||||
common = lib/xzembed/xz_dec_stream.c;
|
||||
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed';
|
||||
};
|
||||
|
||||
module = {
|
||||
name = testload;
|
||||
common = commands/testload.c;
|
||||
};
|
||||
|
|
|
@ -185,7 +185,7 @@ real_code_2:
|
|||
call LOCAL(move_memory)
|
||||
|
||||
/* Check for multiboot signature. */
|
||||
cmpl $MULTIBOOT_HEADER_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_DATA_END)
|
||||
cmpl $MULTIBOOT_HEADER_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE)
|
||||
jz 1f
|
||||
|
||||
movl (ramdisk_image - start), %esi
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <grub/disk.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/acpi.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/machine/memory.h>
|
||||
|
@ -458,10 +457,9 @@ free_tables (void)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_acpi (struct grub_extcmd *cmd,
|
||||
int argc, char **args)
|
||||
grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
struct grub_acpi_rsdp_v10 *rsdp;
|
||||
struct efiemu_acpi_table *cur, *t;
|
||||
grub_err_t err;
|
||||
|
@ -629,7 +627,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd,
|
|||
grub_size_t size;
|
||||
char *buf;
|
||||
|
||||
file = grub_gzfile_open (args[i], 1);
|
||||
file = grub_file_open (args[i]);
|
||||
if (! file)
|
||||
{
|
||||
free_tables ();
|
||||
|
|
|
@ -82,6 +82,7 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (argc < 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (args[0]);
|
||||
if (! file)
|
||||
return grub_errno;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <grub/disk.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
|
@ -33,9 +32,9 @@ static const struct grub_arg_option options[] =
|
|||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_cat (grub_extcmd_t cmd, int argc, char **args)
|
||||
grub_cmd_cat (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
int dos = 0;
|
||||
grub_file_t file;
|
||||
char buf[GRUB_DISK_SECTOR_SIZE];
|
||||
|
@ -48,7 +47,7 @@ grub_cmd_cat (grub_extcmd_t cmd, int argc, char **args)
|
|||
if (argc != 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
|
||||
|
||||
file = grub_gzfile_open (args[0], 1);
|
||||
file = grub_file_open (args[0]);
|
||||
if (! file)
|
||||
return grub_errno;
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <grub/misc.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
|
@ -44,8 +43,8 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)),
|
|||
grub_printf ("Compare file `%s' with `%s':\n", args[0],
|
||||
args[1]);
|
||||
|
||||
file1 = grub_gzfile_open (args[0], 1);
|
||||
file2 = grub_gzfile_open (args[1], 1);
|
||||
file1 = grub_file_open (args[0]);
|
||||
file2 = grub_file_open (args[1]);
|
||||
if (! file1 || ! file2)
|
||||
goto cleanup;
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ grub_cmd_crc (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (argc != 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (args[0]);
|
||||
if (! file)
|
||||
return 0;
|
||||
|
|
|
@ -30,9 +30,9 @@ static const struct grub_arg_option options[] =
|
|||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_echo (grub_extcmd_t cmd, int argc, char **args)
|
||||
grub_cmd_echo (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
int newline = 1;
|
||||
int i;
|
||||
|
||||
|
|
|
@ -21,46 +21,55 @@
|
|||
#include <grub/list.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/script_sh.h>
|
||||
|
||||
static grub_err_t
|
||||
grub_extcmd_dispatcher (struct grub_command *cmd,
|
||||
int argc, char **args)
|
||||
grub_err_t
|
||||
grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args,
|
||||
struct grub_script *script)
|
||||
{
|
||||
int new_argc;
|
||||
char **new_args;
|
||||
struct grub_arg_option *parser;
|
||||
struct grub_arg_list *state;
|
||||
int maxargs = 0;
|
||||
struct grub_extcmd_context context;
|
||||
grub_err_t ret;
|
||||
grub_extcmd_t ext;
|
||||
grub_extcmd_t ext = cmd->data;
|
||||
|
||||
ext = cmd->data;
|
||||
parser = (struct grub_arg_option *) ext->options;
|
||||
while (parser && (parser++)->doc)
|
||||
maxargs++;
|
||||
context.state = 0;
|
||||
context.extcmd = ext;
|
||||
context.script = script;
|
||||
|
||||
/* Set up the option state. */
|
||||
state = grub_zalloc (sizeof (struct grub_arg_list) * maxargs);
|
||||
if (! ext->options)
|
||||
{
|
||||
ret = (ext->func) (&context, argc, args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
state = grub_arg_list_alloc (ext, argc, args);
|
||||
if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc))
|
||||
{
|
||||
ext->state = state;
|
||||
ret = (ext->func) (ext, new_argc, new_args);
|
||||
context.state = state;
|
||||
ret = (ext->func) (&context, new_argc, new_args);
|
||||
grub_free (new_args);
|
||||
grub_free (state);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
ret = grub_errno;
|
||||
|
||||
grub_free (state);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
return ret;
|
||||
static grub_err_t
|
||||
grub_extcmd_dispatch (struct grub_command *cmd, int argc, char **args)
|
||||
{
|
||||
return grub_extcmd_dispatcher (cmd, argc, args, 0);
|
||||
}
|
||||
|
||||
grub_extcmd_t
|
||||
grub_register_extcmd (const char *name, grub_extcmd_func_t func,
|
||||
grub_register_extcmd_prio (const char *name, grub_extcmd_func_t func,
|
||||
unsigned flags, const char *summary,
|
||||
const char *description,
|
||||
const struct grub_arg_option *parser)
|
||||
const struct grub_arg_option *parser,
|
||||
int prio)
|
||||
{
|
||||
grub_extcmd_t ext;
|
||||
grub_command_t cmd;
|
||||
|
@ -69,8 +78,8 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func,
|
|||
if (! ext)
|
||||
return 0;
|
||||
|
||||
cmd = grub_register_command_prio (name, grub_extcmd_dispatcher,
|
||||
summary, description, 1);
|
||||
cmd = grub_register_command_prio (name, grub_extcmd_dispatch,
|
||||
summary, description, prio);
|
||||
if (! cmd)
|
||||
{
|
||||
grub_free (ext);
|
||||
|
@ -88,6 +97,16 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func,
|
|||
return ext;
|
||||
}
|
||||
|
||||
grub_extcmd_t
|
||||
grub_register_extcmd (const char *name, grub_extcmd_func_t func,
|
||||
unsigned flags, const char *summary,
|
||||
const char *description,
|
||||
const struct grub_arg_option *parser)
|
||||
{
|
||||
return grub_register_extcmd_prio (name, func, flags,
|
||||
summary, description, parser, 1);
|
||||
}
|
||||
|
||||
void
|
||||
grub_unregister_extcmd (grub_extcmd_t ext)
|
||||
{
|
||||
|
|
|
@ -32,6 +32,7 @@ static const struct grub_arg_option options[] = {
|
|||
{"prefix", 'p', 0, N_("Base directory for hash list."), N_("DIRECTORY"),
|
||||
ARG_TYPE_STRING},
|
||||
{"keep-going", 'k', 0, N_("Don't stop after first error."), 0, 0},
|
||||
{"uncompress", 'u', 0, N_("Uncompress file before checksumming."), 0, 0},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
@ -80,7 +81,7 @@ hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result)
|
|||
|
||||
static grub_err_t
|
||||
check_list (const gcry_md_spec_t *hash, const char *hashfilename,
|
||||
const char *prefix, int keep)
|
||||
const char *prefix, int keep, int uncompress)
|
||||
{
|
||||
grub_file_t hashlist, file;
|
||||
char *buf = NULL;
|
||||
|
@ -115,11 +116,17 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename,
|
|||
filename = grub_xasprintf ("%s/%s", prefix, p);
|
||||
if (!filename)
|
||||
return grub_errno;
|
||||
if (!uncompress)
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (filename);
|
||||
grub_free (filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!uncompress)
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (p);
|
||||
}
|
||||
if (!file)
|
||||
{
|
||||
grub_file_close (hashlist);
|
||||
|
@ -165,19 +172,20 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename,
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_hashsum (struct grub_extcmd *cmd,
|
||||
grub_cmd_hashsum (struct grub_extcmd_context *ctxt,
|
||||
int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
const char *hashname = NULL;
|
||||
const char *prefix = NULL;
|
||||
const gcry_md_spec_t *hash;
|
||||
unsigned i;
|
||||
int keep = state[3].set;
|
||||
int uncompress = state[4].set;
|
||||
unsigned unread = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (aliases); i++)
|
||||
if (grub_strcmp (cmd->cmd->name, aliases[i].name) == 0)
|
||||
if (grub_strcmp (ctxt->extcmd->cmd->name, aliases[i].name) == 0)
|
||||
hashname = aliases[i].hashname;
|
||||
if (state[0].set)
|
||||
hashname = state[0].arg;
|
||||
|
@ -197,7 +205,7 @@ grub_cmd_hashsum (struct grub_extcmd *cmd,
|
|||
if (argc != 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"--check is incompatible with file list");
|
||||
return check_list (hash, state[1].arg, prefix, keep);
|
||||
return check_list (hash, state[1].arg, prefix, keep, uncompress);
|
||||
}
|
||||
|
||||
for (i = 0; i < (unsigned) argc; i++)
|
||||
|
@ -206,6 +214,8 @@ grub_cmd_hashsum (struct grub_extcmd *cmd,
|
|||
grub_file_t file;
|
||||
grub_err_t err;
|
||||
unsigned j;
|
||||
if (!uncompress)
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (args[i]);
|
||||
if (!file)
|
||||
{
|
||||
|
|
|
@ -270,9 +270,9 @@ static int get_int_arg (const struct grub_arg_list *state)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_hdparm (grub_extcmd_t cmd, int argc, char **args) // state????
|
||||
grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
|
||||
/* Check command line. */
|
||||
if (argc != 1)
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <grub/charset.h>
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc,
|
||||
grub_cmd_help (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc,
|
||||
char **args)
|
||||
{
|
||||
int cnt = 0;
|
||||
|
@ -112,7 +112,8 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc,
|
|||
if (cnt++ > 0)
|
||||
grub_printf ("\n\n");
|
||||
|
||||
if (cmd->flags & GRUB_COMMAND_FLAG_EXTCMD)
|
||||
if ((cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) &&
|
||||
! (cmd->flags & GRUB_COMMAND_FLAG_DYNCMD))
|
||||
grub_arg_show_help ((grub_extcmd_t) cmd->data);
|
||||
else
|
||||
grub_printf ("%s %s %s\n%s\n", _("Usage:"), cmd->name, _(cmd->summary),
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <grub/file.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/lib/hexdump.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
|
@ -34,9 +33,9 @@ static const struct grub_arg_option options[] = {
|
|||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args)
|
||||
grub_cmd_hexdump (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
char buf[GRUB_DISK_SECTOR_SIZE * 4];
|
||||
grub_ssize_t size, length;
|
||||
grub_disk_addr_t skip;
|
||||
|
@ -89,7 +88,7 @@ grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args)
|
|||
{
|
||||
grub_file_t file;
|
||||
|
||||
file = grub_gzfile_open (args[0], 1);
|
||||
file = grub_file_open (args[0]);
|
||||
if (! file)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ static const struct grub_arg_option options[] =
|
|||
unsigned char grub_cpuid_has_longmode = 0;
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_cpuid (grub_extcmd_t cmd __attribute__ ((unused)),
|
||||
grub_cmd_cpuid (grub_extcmd_context_t ctxt __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
|
|
|
@ -196,13 +196,13 @@ list_mappings (void)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args)
|
||||
grub_cmd_drivemap (struct grub_extcmd_context *ctxt, int argc, char **args)
|
||||
{
|
||||
if (cmd->state[OPTIDX_LIST].set)
|
||||
if (ctxt->state[OPTIDX_LIST].set)
|
||||
{
|
||||
return list_mappings ();
|
||||
}
|
||||
else if (cmd->state[OPTIDX_RESET].set)
|
||||
else if (ctxt->state[OPTIDX_RESET].set)
|
||||
{
|
||||
/* Reset: just delete all mappings, freeing their memory. */
|
||||
drivemap_node_t *curnode = map_head;
|
||||
|
@ -216,7 +216,7 @@ grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args)
|
|||
map_head = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
else if (!cmd->state[OPTIDX_SWAP].set && argc == 0)
|
||||
else if (!ctxt->state[OPTIDX_SWAP].set && argc == 0)
|
||||
{
|
||||
/* No arguments */
|
||||
return list_mappings ();
|
||||
|
@ -248,11 +248,11 @@ grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args)
|
|||
}
|
||||
/* Set the mapping for the disk (overwrites any existing mapping). */
|
||||
grub_dprintf ("drivemap", "%s %s (%02x) = %s (%02x)\n",
|
||||
cmd->state[OPTIDX_SWAP].set ? "Swapping" : "Mapping",
|
||||
ctxt->state[OPTIDX_SWAP].set ? "Swapping" : "Mapping",
|
||||
args[1], mapto, args[0], mapfrom);
|
||||
err = drivemap_set (mapto, mapfrom);
|
||||
/* If -s, perform the reverse mapping too (only if the first was OK). */
|
||||
if (cmd->state[OPTIDX_SWAP].set && err == GRUB_ERR_NONE)
|
||||
if (ctxt->state[OPTIDX_SWAP].set && err == GRUB_ERR_NONE)
|
||||
err = drivemap_set (mapfrom, mapto);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -93,12 +93,12 @@ grub_halt (int no_apm)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_halt (grub_extcmd_t cmd,
|
||||
grub_cmd_halt (grub_extcmd_context_t ctxt,
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
int no_apm = 0;
|
||||
if (state[0].set)
|
||||
no_apm = 1;
|
||||
|
|
|
@ -284,9 +284,9 @@ grub_sendkey_preboot (int noret __attribute__ ((unused)))
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_sendkey (grub_extcmd_t cmd, int argc, char **args)
|
||||
grub_cmd_sendkey (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
|
||||
auto int find_key_code (char *key);
|
||||
auto int find_ascii_code (char *key);
|
||||
|
|
|
@ -36,7 +36,7 @@ static const struct grub_arg_option options[] =
|
|||
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
|
||||
grub_cmd_read (grub_extcmd_context_t ctxt, int argc, char **argv)
|
||||
{
|
||||
grub_target_addr_t addr;
|
||||
grub_uint32_t value = 0;
|
||||
|
@ -46,7 +46,7 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
|
|||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments");
|
||||
|
||||
addr = grub_strtoul (argv[0], 0, 0);
|
||||
switch (cmd->cmd->name[sizeof ("in") - 1])
|
||||
switch (ctxt->extcmd->cmd->name[sizeof ("in") - 1])
|
||||
{
|
||||
case 'l':
|
||||
value = grub_inl (addr);
|
||||
|
@ -61,10 +61,10 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
|
|||
break;
|
||||
}
|
||||
|
||||
if (cmd->state[0].set)
|
||||
if (ctxt->state[0].set)
|
||||
{
|
||||
grub_snprintf (buf, sizeof (buf), "%x", value);
|
||||
grub_env_set (cmd->state[0].arg, buf);
|
||||
grub_env_set (ctxt->state[0].arg, buf);
|
||||
}
|
||||
else
|
||||
grub_printf ("0x%x\n", value);
|
||||
|
|
|
@ -34,11 +34,11 @@ static const struct grub_arg_option options[] =
|
|||
#define grub_cur_term_input grub_term_get_current_input ()
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_keystatus (grub_extcmd_t cmd,
|
||||
grub_cmd_keystatus (grub_extcmd_context_t ctxt,
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
int expect_mods = 0;
|
||||
int mods;
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ open_envblk_file (char *filename)
|
|||
grub_strcpy (filename, prefix);
|
||||
filename[len] = '/';
|
||||
grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG);
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (filename);
|
||||
grub_free (filename);
|
||||
return file;
|
||||
|
@ -67,6 +68,7 @@ open_envblk_file (char *filename)
|
|||
}
|
||||
}
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
return grub_file_open (filename);
|
||||
}
|
||||
|
||||
|
@ -111,11 +113,11 @@ read_envblk_file (grub_file_t file)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_load_env (grub_extcmd_t cmd,
|
||||
grub_cmd_load_env (grub_extcmd_context_t ctxt,
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
grub_file_t file;
|
||||
grub_envblk_t envblk;
|
||||
|
||||
|
@ -143,11 +145,11 @@ grub_cmd_load_env (grub_extcmd_t cmd,
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_list_env (grub_extcmd_t cmd,
|
||||
grub_cmd_list_env (grub_extcmd_context_t ctxt,
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
grub_file_t file;
|
||||
grub_envblk_t envblk;
|
||||
|
||||
|
@ -280,9 +282,9 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_save_env (grub_extcmd_t cmd, int argc, char **args)
|
||||
grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
grub_file_t file;
|
||||
grub_envblk_t envblk;
|
||||
struct blocklist *head = 0;
|
||||
|
|
|
@ -105,6 +105,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
|
|||
|
||||
/* XXX: For ext2fs symlinks are detected as files while they
|
||||
should be reported as directories. */
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (pathname);
|
||||
if (! file)
|
||||
{
|
||||
|
@ -211,6 +212,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
|
|||
struct grub_dirhook_info info;
|
||||
grub_errno = 0;
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (dirname);
|
||||
if (! file)
|
||||
goto fail;
|
||||
|
@ -248,9 +250,9 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_ls (grub_extcmd_t cmd, int argc, char **args)
|
||||
grub_cmd_ls (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
|
||||
if (argc == 0)
|
||||
grub_ls_list_devices (state[0].set);
|
||||
|
|
|
@ -211,11 +211,11 @@ grub_lspci_iter (grub_pci_device_t dev, grub_pci_id_t pciid)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_lspci (grub_extcmd_t cmd,
|
||||
grub_cmd_lspci (grub_extcmd_context_t ctxt,
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
iospace = cmd->state[0].set;
|
||||
iospace = ctxt->state[0].set;
|
||||
grub_pci_iterate (grub_lspci_iter);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ static const struct grub_arg_option options[] =
|
|||
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
|
||||
grub_cmd_read (grub_extcmd_context_t ctxt, int argc, char **argv)
|
||||
{
|
||||
grub_target_addr_t addr;
|
||||
grub_uint32_t value = 0;
|
||||
|
@ -45,7 +45,7 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
|
|||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid number of arguments");
|
||||
|
||||
addr = grub_strtoul (argv[0], 0, 0);
|
||||
switch (cmd->cmd->name[sizeof ("read_") - 1])
|
||||
switch (ctxt->extcmd->cmd->name[sizeof ("read_") - 1])
|
||||
{
|
||||
case 'd':
|
||||
value = *((volatile grub_uint32_t *) addr);
|
||||
|
@ -60,10 +60,10 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
|
|||
break;
|
||||
}
|
||||
|
||||
if (cmd->state[0].set)
|
||||
if (ctxt->state[0].set)
|
||||
{
|
||||
grub_snprintf (buf, sizeof (buf), "%x", value);
|
||||
grub_env_set (cmd->state[0].arg, buf);
|
||||
grub_env_set (ctxt->state[0].arg, buf);
|
||||
}
|
||||
else
|
||||
grub_printf ("0x%x\n", value);
|
||||
|
|
285
grub-core/commands/menuentry.c
Normal file
285
grub-core/commands/menuentry.c
Normal file
|
@ -0,0 +1,285 @@
|
|||
/* menuentry.c - menuentry command */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/normal.h>
|
||||
|
||||
static const struct grub_arg_option options[] =
|
||||
{
|
||||
{"class", 1, GRUB_ARG_OPTION_REPEATABLE,
|
||||
N_("Menu entry type."), "STRING", ARG_TYPE_STRING},
|
||||
{"users", 2, 0,
|
||||
N_("Users allowed to boot this entry."), "USERNAME", ARG_TYPE_STRING},
|
||||
{"hotkey", 3, 0,
|
||||
N_("Keyboard key for this entry."), "KEY", ARG_TYPE_STRING},
|
||||
{"source", 4, 0,
|
||||
N_("Menu entry definition as a string."), "STRING", ARG_TYPE_STRING},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
int key;
|
||||
} hotkey_aliases[] =
|
||||
{
|
||||
{"backspace", '\b'},
|
||||
{"tab", '\t'},
|
||||
{"delete", GRUB_TERM_DC}
|
||||
};
|
||||
|
||||
/* Add a menu entry to the current menu context (as given by the environment
|
||||
variable data slot `menu'). As the configuration file is read, the script
|
||||
parser calls this when a menu entry is to be created. */
|
||||
static grub_err_t
|
||||
append_menu_entry (int argc, const char **args, char **classes,
|
||||
const char *users, const char *hotkey,
|
||||
const char *prefix, const char *sourcecode)
|
||||
{
|
||||
unsigned i;
|
||||
int menu_hotkey = 0;
|
||||
char **menu_args = NULL;
|
||||
char *menu_users = NULL;
|
||||
char *menu_title = NULL;
|
||||
char *menu_sourcecode = NULL;
|
||||
struct grub_menu_entry_class *menu_classes = NULL;
|
||||
|
||||
grub_menu_t menu;
|
||||
grub_menu_entry_t *last;
|
||||
|
||||
menu = grub_env_get_menu ();
|
||||
if (! menu)
|
||||
return grub_error (GRUB_ERR_MENU, "no menu context");
|
||||
|
||||
last = &menu->entry_list;
|
||||
|
||||
menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode);
|
||||
if (! menu_sourcecode)
|
||||
return grub_errno;
|
||||
|
||||
if (classes)
|
||||
{
|
||||
for (i = 0; classes[i]; i++); /* count # of menuentry classes */
|
||||
menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class) * i);
|
||||
if (! menu_classes)
|
||||
goto fail;
|
||||
|
||||
for (i = 0; classes[i]; i++)
|
||||
{
|
||||
menu_classes[i].name = grub_strdup (classes[i]);
|
||||
if (! menu_classes[i].name)
|
||||
goto fail;
|
||||
menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (users)
|
||||
{
|
||||
menu_users = grub_strdup (users);
|
||||
if (! menu_users)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hotkey)
|
||||
{
|
||||
for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++)
|
||||
if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0)
|
||||
{
|
||||
menu_hotkey = hotkey_aliases[i].key;
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE (hotkey_aliases))
|
||||
menu_hotkey = hotkey[0];
|
||||
}
|
||||
|
||||
if (! argc)
|
||||
{
|
||||
grub_error (GRUB_ERR_MENU, "menuentry is missing title");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
menu_title = grub_strdup (args[0]);
|
||||
if (! menu_title)
|
||||
goto fail;
|
||||
|
||||
/* Save argc, args to pass as parameters to block arg later. */
|
||||
menu_args = grub_malloc (sizeof (char*) * (argc + 1));
|
||||
if (! menu_args)
|
||||
goto fail;
|
||||
|
||||
for (i = 0; args[i]; i++)
|
||||
{
|
||||
menu_args[i] = grub_strdup (args[i]);
|
||||
if (! menu_args[i])
|
||||
goto fail;
|
||||
}
|
||||
menu_args[argc] = NULL;
|
||||
|
||||
/* Add the menu entry at the end of the list. */
|
||||
while (*last)
|
||||
last = &(*last)->next;
|
||||
|
||||
*last = grub_zalloc (sizeof (**last));
|
||||
if (! *last)
|
||||
goto fail;
|
||||
|
||||
(*last)->title = menu_title;
|
||||
(*last)->hotkey = menu_hotkey;
|
||||
(*last)->classes = menu_classes;
|
||||
if (menu_users)
|
||||
(*last)->restricted = 1;
|
||||
(*last)->users = menu_users;
|
||||
(*last)->argc = argc;
|
||||
(*last)->args = menu_args;
|
||||
(*last)->sourcecode = menu_sourcecode;
|
||||
|
||||
menu->size++;
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
fail:
|
||||
|
||||
grub_free (menu_sourcecode);
|
||||
for (i = 0; menu_classes && menu_classes[i].name; i++)
|
||||
grub_free (menu_classes[i].name);
|
||||
grub_free (menu_classes);
|
||||
|
||||
for (i = 0; menu_args && menu_args[i]; i++)
|
||||
grub_free (menu_args[i]);
|
||||
grub_free (menu_args);
|
||||
|
||||
grub_free (menu_users);
|
||||
grub_free (menu_title);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static char *
|
||||
setparams_prefix (int argc, char **args)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
char *p;
|
||||
char *result;
|
||||
grub_size_t len = 10;
|
||||
static const char *escape_characters = "\"\\";
|
||||
|
||||
auto char *strescpy (char *, const char *, const char *);
|
||||
char * strescpy (char *d, const char *s, const char *escapes)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
if (grub_strchr (escapes, *s))
|
||||
*d++ = '\\';
|
||||
*d++ = *s++;
|
||||
}
|
||||
*d = '\0';
|
||||
return d;
|
||||
}
|
||||
|
||||
/* Count resulting string length */
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
len += 3; /* 3 = 1 space + 2 quotes */
|
||||
p = args[i];
|
||||
while (*p)
|
||||
len += grub_strchr (escape_characters, *p++) ? 2 : 1;
|
||||
}
|
||||
|
||||
result = grub_malloc (len + 2);
|
||||
if (! result)
|
||||
return 0;
|
||||
|
||||
grub_strcpy (result, "setparams");
|
||||
i = 9;
|
||||
|
||||
for (j = 0; j < argc; j++)
|
||||
{
|
||||
result[i++] = ' ';
|
||||
result[i++] = '"';
|
||||
i = strescpy (result + i, args[j], escape_characters) - result;
|
||||
result[i++] = '"';
|
||||
}
|
||||
result[i++] = '\n';
|
||||
result[i] = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
char ch;
|
||||
char *src;
|
||||
char *prefix;
|
||||
unsigned len;
|
||||
grub_err_t r;
|
||||
|
||||
if (! argc)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
|
||||
|
||||
if (ctxt->state[3].set && ctxt->script)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions");
|
||||
|
||||
if (! ctxt->state[3].set && ! ctxt->script)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
|
||||
|
||||
if (! ctxt->script)
|
||||
return append_menu_entry (argc, (const char **) args,
|
||||
ctxt->state[0].args, ctxt->state[1].arg,
|
||||
ctxt->state[2].arg, 0, ctxt->state[3].arg);
|
||||
|
||||
src = args[argc - 1];
|
||||
args[argc - 1] = NULL;
|
||||
|
||||
len = grub_strlen(src);
|
||||
ch = src[len - 1];
|
||||
src[len - 1] = '\0';
|
||||
|
||||
prefix = setparams_prefix (argc - 1, args);
|
||||
if (! prefix)
|
||||
return grub_errno;
|
||||
|
||||
r = append_menu_entry (argc - 1, (const char **) args,
|
||||
ctxt->state[0].args, ctxt->state[1].arg,
|
||||
ctxt->state[2].arg, prefix, src + 1);
|
||||
|
||||
src[len - 1] = ch;
|
||||
args[argc - 1] = src;
|
||||
grub_free (prefix);
|
||||
return r;
|
||||
}
|
||||
|
||||
static grub_extcmd_t cmd;
|
||||
|
||||
void
|
||||
grub_menu_init (void)
|
||||
{
|
||||
cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry,
|
||||
GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS,
|
||||
N_("BLOCK"), N_("Define a menuentry."), options);
|
||||
}
|
||||
|
||||
void
|
||||
grub_menu_fini (void)
|
||||
{
|
||||
grub_unregister_extcmd (cmd);
|
||||
}
|
|
@ -142,112 +142,6 @@ grub_mini_cmd_root (struct grub_command *cmd __attribute__ ((unused)),
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
grub_rescue_cmd_testload (int argc, char *argv[])
|
||||
{
|
||||
grub_file_t file;
|
||||
char *buf;
|
||||
grub_ssize_t size;
|
||||
grub_ssize_t pos;
|
||||
auto void read_func (unsigned long sector, unsigned offset, unsigned len);
|
||||
|
||||
void read_func (unsigned long sector __attribute__ ((unused)),
|
||||
unsigned offset __attribute__ ((unused)),
|
||||
unsigned len __attribute__ ((unused)))
|
||||
{
|
||||
grub_putchar ('.');
|
||||
grub_refresh ();
|
||||
}
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
|
||||
return;
|
||||
}
|
||||
|
||||
file = grub_file_open (argv[0]);
|
||||
if (! file)
|
||||
return;
|
||||
|
||||
size = grub_file_size (file) & ~(GRUB_DISK_SECTOR_SIZE - 1);
|
||||
if (size == 0)
|
||||
{
|
||||
grub_file_close (file);
|
||||
return;
|
||||
}
|
||||
|
||||
buf = grub_malloc (size);
|
||||
if (! buf)
|
||||
goto fail;
|
||||
|
||||
grub_printf ("Reading %s sequentially", argv[0]);
|
||||
file->read_hook = read_func;
|
||||
if (grub_file_read (file, buf, size) != size)
|
||||
goto fail;
|
||||
grub_printf (" Done.\n");
|
||||
|
||||
/* Read sequentially again. */
|
||||
grub_printf ("Reading %s sequentially again", argv[0]);
|
||||
if (grub_file_seek (file, 0) < 0)
|
||||
goto fail;
|
||||
|
||||
for (pos = 0; pos < size; pos += GRUB_DISK_SECTOR_SIZE)
|
||||
{
|
||||
char sector[GRUB_DISK_SECTOR_SIZE];
|
||||
|
||||
if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE)
|
||||
!= GRUB_DISK_SECTOR_SIZE)
|
||||
goto fail;
|
||||
|
||||
if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0)
|
||||
{
|
||||
grub_printf ("\nDiffers in %d\n", pos);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
grub_printf (" Done.\n");
|
||||
|
||||
/* Read backwards and compare. */
|
||||
grub_printf ("Reading %s backwards", argv[0]);
|
||||
pos = size;
|
||||
while (pos > 0)
|
||||
{
|
||||
char sector[GRUB_DISK_SECTOR_SIZE];
|
||||
|
||||
pos -= GRUB_DISK_SECTOR_SIZE;
|
||||
|
||||
if (grub_file_seek (file, pos) < 0)
|
||||
goto fail;
|
||||
|
||||
if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE)
|
||||
!= GRUB_DISK_SECTOR_SIZE)
|
||||
goto fail;
|
||||
|
||||
if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
grub_printf ("\nDiffers in %d\n", pos);
|
||||
|
||||
for (i = 0; i < GRUB_DISK_SECTOR_SIZE; i++)
|
||||
grub_putchar (buf[pos + i]);
|
||||
|
||||
if (i)
|
||||
grub_refresh ();
|
||||
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
grub_printf (" Done.\n");
|
||||
|
||||
fail:
|
||||
|
||||
grub_file_close (file);
|
||||
grub_free (buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* dump ADDRESS [SIZE] */
|
||||
static grub_err_t
|
||||
grub_mini_cmd_dump (struct grub_command *cmd __attribute__ ((unused)),
|
||||
|
|
|
@ -45,9 +45,9 @@ static const struct grub_arg_option options[] =
|
|||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_probe (grub_extcmd_t cmd, int argc, char **args)
|
||||
grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
grub_device_t dev;
|
||||
grub_fs_t fs;
|
||||
char *ptr;
|
||||
|
|
|
@ -20,37 +20,104 @@
|
|||
#include <grub/dl.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/script_sh.h>
|
||||
#include <regex.h>
|
||||
|
||||
static const struct grub_arg_option options[] =
|
||||
{
|
||||
{ "set", 's', GRUB_ARG_OPTION_REPEATABLE,
|
||||
N_("Variable names to update with matches."),
|
||||
N_("[NUMBER:]VARNAME"), ARG_TYPE_STRING },
|
||||
{ 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
set_matches (char **varnames, char *str, grub_size_t nmatches,
|
||||
regmatch_t *matches)
|
||||
{
|
||||
int i;
|
||||
char ch;
|
||||
char *p;
|
||||
char *q;
|
||||
grub_err_t err;
|
||||
unsigned long j;
|
||||
|
||||
auto void setvar (char *v, regmatch_t *m);
|
||||
void setvar (char *v, regmatch_t *m)
|
||||
{
|
||||
ch = str[m->rm_eo];
|
||||
str[m->rm_eo] = '\0';
|
||||
err = grub_env_set (v, str + m->rm_so);
|
||||
str[m->rm_eo] = ch;
|
||||
}
|
||||
|
||||
for (i = 0; varnames && varnames[i]; i++)
|
||||
{
|
||||
if (! (p = grub_strchr (varnames[i], ':')))
|
||||
{
|
||||
/* varname w/o index defaults to 1 */
|
||||
if (nmatches < 2 || matches[1].rm_so == -1)
|
||||
grub_env_unset (varnames[i]);
|
||||
else
|
||||
setvar (varnames[i], &matches[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
j = grub_strtoul (varnames[i], &q, 10);
|
||||
if (q != p)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"invalid variable name format %s", varnames[i]);
|
||||
|
||||
if (nmatches <= j || matches[j].rm_so == -1)
|
||||
grub_env_unset (p + 1);
|
||||
else
|
||||
setvar (p + 1, &matches[j]);
|
||||
}
|
||||
|
||||
if (err != GRUB_ERR_NONE)
|
||||
return err;
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_regexp (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
int argn = 0;
|
||||
int matches = 0;
|
||||
regex_t regex;
|
||||
int ret;
|
||||
grub_size_t s;
|
||||
char *comperr;
|
||||
grub_err_t err;
|
||||
regmatch_t *matches = 0;
|
||||
|
||||
if (argc != 2)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "2 arguments expected");
|
||||
|
||||
ret = regcomp (®ex, args[0], RE_SYNTAX_GNU_AWK);
|
||||
ret = regcomp (®ex, args[0], REG_EXTENDED);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = regexec (®ex, args[1], 0, 0, 0);
|
||||
matches = grub_zalloc (sizeof (*matches) * (regex.re_nsub + 1));
|
||||
if (! matches)
|
||||
goto fail;
|
||||
|
||||
ret = regexec (®ex, args[1], regex.re_nsub + 1, matches, 0);
|
||||
if (!ret)
|
||||
{
|
||||
err = set_matches (ctxt->state[0].args, args[1],
|
||||
regex.re_nsub + 1, matches);
|
||||
regfree (®ex);
|
||||
return GRUB_ERR_NONE;
|
||||
grub_free (matches);
|
||||
return err;
|
||||
}
|
||||
|
||||
fail:
|
||||
grub_free (matches);
|
||||
s = regerror (ret, ®ex, 0, 0);
|
||||
comperr = grub_malloc (s);
|
||||
if (!comperr)
|
||||
|
@ -65,16 +132,20 @@ grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)),
|
|||
return err;
|
||||
}
|
||||
|
||||
static grub_command_t cmd;
|
||||
static grub_extcmd_t cmd;
|
||||
|
||||
GRUB_MOD_INIT(regexp)
|
||||
{
|
||||
cmd = grub_register_command ("regexp", grub_cmd_regexp,
|
||||
N_("REGEXP STRING"),
|
||||
N_("Test if REGEXP matches STRING."));
|
||||
cmd = grub_register_extcmd ("regexp", grub_cmd_regexp,
|
||||
GRUB_COMMAND_FLAG_BOTH, N_("REGEXP STRING"),
|
||||
N_("Test if REGEXP matches STRING."), options);
|
||||
|
||||
/* Setup GRUB script wildcard translator. */
|
||||
grub_wildcard_translator = &grub_filename_translator;
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(regexp)
|
||||
{
|
||||
grub_unregister_command (cmd);
|
||||
grub_unregister_extcmd (cmd);
|
||||
grub_wildcard_translator = 0;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ FUNC_NAME (const char *key, const char *var, int no_floppy)
|
|||
if (! buf)
|
||||
return 1;
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (buf);
|
||||
if (file)
|
||||
{
|
||||
|
|
|
@ -50,9 +50,9 @@ enum options
|
|||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_search (grub_extcmd_t cmd, int argc, char **args)
|
||||
grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
const char *var = 0;
|
||||
|
||||
if (argc == 0)
|
||||
|
|
|
@ -155,7 +155,7 @@ grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv)
|
||||
grub_cmd_setpci (grub_extcmd_context_t ctxt, int argc, char **argv)
|
||||
{
|
||||
const char *ptr;
|
||||
unsigned i;
|
||||
|
@ -163,14 +163,14 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv)
|
|||
pciid_check_value = 0;
|
||||
pciid_check_mask = 0;
|
||||
|
||||
if (cmd->state[0].set)
|
||||
if (ctxt->state[0].set)
|
||||
{
|
||||
ptr = cmd->state[0].arg;
|
||||
ptr = ctxt->state[0].arg;
|
||||
pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff);
|
||||
if (grub_errno == GRUB_ERR_BAD_NUMBER)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
ptr = cmd->state[0].arg;
|
||||
ptr = ctxt->state[0].arg;
|
||||
}
|
||||
else
|
||||
pciid_check_mask |= 0xffff;
|
||||
|
@ -191,11 +191,11 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv)
|
|||
|
||||
check_bus = check_device = check_function = 0;
|
||||
|
||||
if (cmd->state[1].set)
|
||||
if (ctxt->state[1].set)
|
||||
{
|
||||
const char *optr;
|
||||
|
||||
ptr = cmd->state[1].arg;
|
||||
ptr = ctxt->state[1].arg;
|
||||
optr = ptr;
|
||||
bus = grub_strtoul (ptr, (char **) &ptr, 16);
|
||||
if (grub_errno == GRUB_ERR_BAD_NUMBER)
|
||||
|
@ -229,8 +229,8 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
if (cmd->state[2].set)
|
||||
varname = cmd->state[2].arg;
|
||||
if (ctxt->state[2].set)
|
||||
varname = ctxt->state[2].arg;
|
||||
else
|
||||
varname = NULL;
|
||||
|
||||
|
|
|
@ -60,9 +60,9 @@ grub_interruptible_millisleep (grub_uint32_t ms)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_sleep (grub_extcmd_t cmd, int argc, char **args)
|
||||
grub_cmd_sleep (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
int n;
|
||||
|
||||
if (argc != 1)
|
||||
|
|
|
@ -334,6 +334,7 @@ test_parse (char **args, int *argn, int argc)
|
|||
if (grub_strcmp (args[*argn], "-s") == 0)
|
||||
{
|
||||
grub_file_t file;
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (args[*argn + 1]);
|
||||
update_val (file && (grub_file_size (file) != 0));
|
||||
if (file)
|
||||
|
|
155
grub-core/commands/testload.c
Normal file
155
grub-core/commands/testload.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
/* minicmd.c - commands for the rescue mode */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2005,2006,2007,2009,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/loader.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_testload (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
grub_file_t file;
|
||||
char *buf;
|
||||
grub_size_t size;
|
||||
grub_off_t pos;
|
||||
auto void NESTED_FUNC_ATTR read_func (grub_disk_addr_t sector, unsigned offset, unsigned len);
|
||||
|
||||
void NESTED_FUNC_ATTR read_func (grub_disk_addr_t sector __attribute__ ((unused)),
|
||||
unsigned offset __attribute__ ((unused)),
|
||||
unsigned len __attribute__ ((unused)))
|
||||
{
|
||||
grub_xputs (".");
|
||||
grub_refresh ();
|
||||
}
|
||||
|
||||
if (argc < 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
|
||||
|
||||
file = grub_file_open (argv[0]);
|
||||
if (! file)
|
||||
return grub_errno;
|
||||
|
||||
size = grub_file_size (file) & ~(GRUB_DISK_SECTOR_SIZE - 1);
|
||||
if (size == 0)
|
||||
{
|
||||
grub_file_close (file);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
buf = grub_malloc (size);
|
||||
if (! buf)
|
||||
goto fail;
|
||||
|
||||
grub_printf ("Reading %s sequentially", argv[0]);
|
||||
file->read_hook = read_func;
|
||||
if (grub_file_read (file, buf, size) != (grub_ssize_t) size)
|
||||
goto fail;
|
||||
grub_printf (" Done.\n");
|
||||
|
||||
/* Read sequentially again. */
|
||||
grub_printf ("Reading %s sequentially again", argv[0]);
|
||||
grub_file_seek (file, 0);
|
||||
|
||||
for (pos = 0; pos < size; pos += GRUB_DISK_SECTOR_SIZE)
|
||||
{
|
||||
char sector[GRUB_DISK_SECTOR_SIZE];
|
||||
|
||||
if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE)
|
||||
!= GRUB_DISK_SECTOR_SIZE)
|
||||
goto fail;
|
||||
|
||||
if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0)
|
||||
{
|
||||
grub_printf ("\nDiffers in %lld\n", (unsigned long long) pos);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
grub_printf (" Done.\n");
|
||||
|
||||
/* Read backwards and compare. */
|
||||
grub_printf ("Reading %s backwards", argv[0]);
|
||||
pos = size;
|
||||
while (pos > 0)
|
||||
{
|
||||
char sector[GRUB_DISK_SECTOR_SIZE];
|
||||
|
||||
pos -= GRUB_DISK_SECTOR_SIZE;
|
||||
|
||||
grub_file_seek (file, pos);
|
||||
|
||||
if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE)
|
||||
!= GRUB_DISK_SECTOR_SIZE)
|
||||
goto fail;
|
||||
|
||||
if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
grub_printf ("\nDiffers in %lld\n", (unsigned long long) pos);
|
||||
|
||||
for (i = 0; i < GRUB_DISK_SECTOR_SIZE; i++)
|
||||
{
|
||||
grub_printf ("%02x ", buf[pos + i]);
|
||||
if ((i & 15) == 15)
|
||||
grub_printf ("\n");
|
||||
}
|
||||
|
||||
if (i)
|
||||
grub_refresh ();
|
||||
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
grub_printf (" Done.\n");
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
fail:
|
||||
|
||||
grub_file_close (file);
|
||||
grub_free (buf);
|
||||
|
||||
if (!grub_errno)
|
||||
grub_error (GRUB_ERR_IO, "bad read");
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_command_t cmd;
|
||||
|
||||
GRUB_MOD_INIT(testload)
|
||||
{
|
||||
cmd =
|
||||
grub_register_command ("testload", grub_cmd_testload,
|
||||
N_("FILE"),
|
||||
N_("Load the same file in multiple ways."));
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(testload)
|
||||
{
|
||||
grub_unregister_command (cmd);
|
||||
}
|
494
grub-core/commands/wildcard.c
Normal file
494
grub-core/commands/wildcard.c
Normal file
|
@ -0,0 +1,494 @@
|
|||
/* wildcard.c - Wildcard character expansion for GRUB script. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/fs.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/device.h>
|
||||
#include <grub/script_sh.h>
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
static inline int isregexop (char ch);
|
||||
static char ** merge (char **lhs, char **rhs);
|
||||
static char *make_dir (const char *prefix, const char *start, const char *end);
|
||||
static int make_regex (const char *regex_start, const char *regex_end,
|
||||
regex_t *regexp);
|
||||
static void split_path (const char *path, const char **suffix_end, const char **regex_end);
|
||||
static char ** match_devices (const regex_t *regexp, int noparts);
|
||||
static char ** match_files (const char *prefix, const char *suffix_start,
|
||||
const char *suffix_end, const regex_t *regexp);
|
||||
|
||||
static char* wildcard_escape (const char *s);
|
||||
static char* wildcard_unescape (const char *s);
|
||||
static grub_err_t wildcard_expand (const char *s, char ***strs);
|
||||
|
||||
struct grub_script_wildcard_translator grub_filename_translator = {
|
||||
.expand = wildcard_expand,
|
||||
.escape = wildcard_escape,
|
||||
.unescape = wildcard_unescape
|
||||
};
|
||||
|
||||
static char **
|
||||
merge (char **dest, char **ps)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
char **p;
|
||||
|
||||
if (! dest)
|
||||
return ps;
|
||||
|
||||
if (! ps)
|
||||
return dest;
|
||||
|
||||
for (i = 0; dest[i]; i++)
|
||||
;
|
||||
for (j = 0; ps[j]; j++)
|
||||
;
|
||||
|
||||
p = grub_realloc (dest, sizeof (char*) * (i + j + 1));
|
||||
if (! p)
|
||||
{
|
||||
grub_free (dest);
|
||||
grub_free (ps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dest = p;
|
||||
for (j = 0; ps[j]; j++)
|
||||
dest[i++] = ps[j];
|
||||
dest[i] = 0;
|
||||
|
||||
grub_free (ps);
|
||||
return dest;
|
||||
}
|
||||
|
||||
static inline int
|
||||
isregexop (char ch)
|
||||
{
|
||||
return grub_strchr ("*.\\", ch) ? 1 : 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
make_dir (const char *prefix, const char *start, const char *end)
|
||||
{
|
||||
char ch;
|
||||
unsigned i;
|
||||
unsigned n;
|
||||
char *result;
|
||||
|
||||
i = grub_strlen (prefix);
|
||||
n = i + end - start;
|
||||
|
||||
result = grub_malloc (n + 1);
|
||||
if (! result)
|
||||
return 0;
|
||||
|
||||
grub_strcpy (result, prefix);
|
||||
while (start < end && (ch = *start++))
|
||||
if (ch == '\\' && isregexop (*start))
|
||||
result[i++] = *start++;
|
||||
else
|
||||
result[i++] = ch;
|
||||
|
||||
result[i] = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
make_regex (const char *start, const char *end, regex_t *regexp)
|
||||
{
|
||||
char ch;
|
||||
int i = 0;
|
||||
unsigned len = end - start;
|
||||
char *buffer = grub_malloc (len * 2 + 2 + 1); /* worst case size. */
|
||||
|
||||
if (! buffer)
|
||||
return 1;
|
||||
|
||||
buffer[i++] = '^';
|
||||
while (start < end)
|
||||
{
|
||||
/* XXX Only * expansion for now. */
|
||||
switch ((ch = *start++))
|
||||
{
|
||||
case '\\':
|
||||
buffer[i++] = ch;
|
||||
if (*start != '\0')
|
||||
buffer[i++] = *start++;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
buffer[i++] = '\\';
|
||||
buffer[i++] = '.';
|
||||
break;
|
||||
|
||||
case '*':
|
||||
buffer[i++] = '.';
|
||||
buffer[i++] = '*';
|
||||
break;
|
||||
|
||||
default:
|
||||
buffer[i++] = ch;
|
||||
}
|
||||
}
|
||||
buffer[i++] = '$';
|
||||
buffer[i] = '\0';
|
||||
|
||||
if (regcomp (regexp, buffer, RE_SYNTAX_GNU_AWK))
|
||||
{
|
||||
grub_free (buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
grub_free (buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Split `str' into two parts: (1) dirname that is regexop free (2)
|
||||
dirname that has a regexop. */
|
||||
static void
|
||||
split_path (const char *str, const char **noregexop, const char **regexop)
|
||||
{
|
||||
char ch = 0;
|
||||
int regex = 0;
|
||||
|
||||
const char *end;
|
||||
const char *split; /* points till the end of dirnaname that doesn't
|
||||
need expansion. */
|
||||
|
||||
split = end = str;
|
||||
while ((ch = *end))
|
||||
{
|
||||
if (ch == '\\' && end[1])
|
||||
end++;
|
||||
|
||||
else if (isregexop (ch))
|
||||
regex = 1;
|
||||
|
||||
else if (ch == '/' && ! regex)
|
||||
split = end + 1; /* forward to next regexop-free dirname */
|
||||
|
||||
else if (ch == '/' && regex)
|
||||
break; /* stop at the first dirname with a regexop */
|
||||
|
||||
end++;
|
||||
}
|
||||
|
||||
*regexop = end;
|
||||
if (! regex)
|
||||
*noregexop = end;
|
||||
else
|
||||
*noregexop = split;
|
||||
}
|
||||
|
||||
static char **
|
||||
match_devices (const regex_t *regexp, int noparts)
|
||||
{
|
||||
int i;
|
||||
int ndev;
|
||||
char **devs;
|
||||
|
||||
auto int match (const char *name);
|
||||
int match (const char *name)
|
||||
{
|
||||
char **t;
|
||||
char *buffer;
|
||||
|
||||
/* skip partitions if asked to. */
|
||||
if (noparts && grub_strchr(name, ','))
|
||||
return 0;
|
||||
|
||||
buffer = grub_xasprintf ("(%s)", name);
|
||||
if (! buffer)
|
||||
return 1;
|
||||
|
||||
grub_dprintf ("expand", "matching: %s\n", buffer);
|
||||
if (regexec (regexp, buffer, 0, 0, 0))
|
||||
{
|
||||
grub_free (buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
t = grub_realloc (devs, sizeof (char*) * (ndev + 2));
|
||||
if (! t)
|
||||
return 1;
|
||||
|
||||
devs = t;
|
||||
devs[ndev++] = buffer;
|
||||
devs[ndev] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ndev = 0;
|
||||
devs = 0;
|
||||
|
||||
if (grub_device_iterate (match))
|
||||
goto fail;
|
||||
|
||||
return devs;
|
||||
|
||||
fail:
|
||||
|
||||
for (i = 0; devs && devs[i]; i++)
|
||||
grub_free (devs[i]);
|
||||
|
||||
if (devs)
|
||||
grub_free (devs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char **
|
||||
match_files (const char *prefix, const char *suffix, const char *end,
|
||||
const regex_t *regexp)
|
||||
{
|
||||
int i;
|
||||
int error;
|
||||
char **files;
|
||||
unsigned nfile;
|
||||
char *dir;
|
||||
const char *path;
|
||||
char *device_name;
|
||||
grub_fs_t fs;
|
||||
grub_device_t dev;
|
||||
|
||||
auto int match (const char *name, const struct grub_dirhook_info *info);
|
||||
int match (const char *name, const struct grub_dirhook_info *info)
|
||||
{
|
||||
char **t;
|
||||
char *buffer;
|
||||
|
||||
/* skip . and .. names */
|
||||
if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0)
|
||||
return 0;
|
||||
|
||||
grub_dprintf ("expand", "matching: %s in %s\n", name, dir);
|
||||
if (regexec (regexp, name, 0, 0, 0))
|
||||
return 0;
|
||||
|
||||
buffer = grub_xasprintf ("%s%s", dir, name);
|
||||
if (! buffer)
|
||||
return 1;
|
||||
|
||||
t = grub_realloc (files, sizeof (char*) * (nfile + 2));
|
||||
if (! t)
|
||||
{
|
||||
grub_free (buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
files = t;
|
||||
files[nfile++] = buffer;
|
||||
files[nfile] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nfile = 0;
|
||||
files = 0;
|
||||
dev = 0;
|
||||
device_name = 0;
|
||||
grub_error_push ();
|
||||
|
||||
dir = make_dir (prefix, suffix, end);
|
||||
if (! dir)
|
||||
goto fail;
|
||||
|
||||
device_name = grub_file_get_device_name (dir);
|
||||
dev = grub_device_open (device_name);
|
||||
if (! dev)
|
||||
goto fail;
|
||||
|
||||
fs = grub_fs_probe (dev);
|
||||
if (! fs)
|
||||
goto fail;
|
||||
|
||||
path = grub_strchr (dir, ')');
|
||||
if (! path)
|
||||
goto fail;
|
||||
path++;
|
||||
|
||||
if (fs->dir (dev, path, match))
|
||||
goto fail;
|
||||
|
||||
grub_free (dir);
|
||||
grub_device_close (dev);
|
||||
grub_free (device_name);
|
||||
grub_error_pop ();
|
||||
return files;
|
||||
|
||||
fail:
|
||||
|
||||
if (dir)
|
||||
grub_free (dir);
|
||||
|
||||
for (i = 0; files && files[i]; i++)
|
||||
grub_free (files[i]);
|
||||
|
||||
if (files)
|
||||
grub_free (files);
|
||||
|
||||
if (dev)
|
||||
grub_device_close (dev);
|
||||
|
||||
if (device_name)
|
||||
grub_free (device_name);
|
||||
|
||||
grub_error_pop ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char*
|
||||
wildcard_escape (const char *s)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
char ch;
|
||||
char *p;
|
||||
|
||||
len = grub_strlen (s);
|
||||
p = grub_malloc (len * 2 + 1);
|
||||
if (! p)
|
||||
return NULL;
|
||||
|
||||
i = 0;
|
||||
while ((ch = *s++))
|
||||
{
|
||||
if (isregexop (ch))
|
||||
p[i++] = '\\';
|
||||
p[i++] = ch;
|
||||
}
|
||||
p[i] = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char*
|
||||
wildcard_unescape (const char *s)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
char ch;
|
||||
char *p;
|
||||
|
||||
len = grub_strlen (s);
|
||||
p = grub_malloc (len + 1);
|
||||
if (! p)
|
||||
return NULL;
|
||||
|
||||
i = 0;
|
||||
while ((ch = *s++))
|
||||
{
|
||||
if (ch == '\\' && isregexop (*s))
|
||||
p[i++] = *s++;
|
||||
else
|
||||
p[i++] = ch;
|
||||
}
|
||||
p[i] = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
wildcard_expand (const char *s, char ***strs)
|
||||
{
|
||||
const char *start;
|
||||
const char *regexop;
|
||||
const char *noregexop;
|
||||
char **paths = 0;
|
||||
|
||||
unsigned i;
|
||||
regex_t regexp;
|
||||
|
||||
start = s;
|
||||
while (*start)
|
||||
{
|
||||
split_path (start, &noregexop, ®exop);
|
||||
if (noregexop >= regexop) /* no more wildcards */
|
||||
break;
|
||||
|
||||
if (make_regex (noregexop, regexop, ®exp))
|
||||
goto fail;
|
||||
|
||||
if (paths == 0)
|
||||
{
|
||||
if (start == noregexop) /* device part has regexop */
|
||||
paths = match_devices (®exp, *start != '(');
|
||||
|
||||
else if (*start == '(') /* device part explicit wo regexop */
|
||||
paths = match_files ("", start, noregexop, ®exp);
|
||||
|
||||
else if (*start == '/') /* no device part */
|
||||
{
|
||||
char **r;
|
||||
unsigned n;
|
||||
char *root;
|
||||
char *prefix;
|
||||
|
||||
root = grub_env_get ("root");
|
||||
if (! root)
|
||||
goto fail;
|
||||
|
||||
prefix = grub_xasprintf ("(%s)", root);
|
||||
if (! prefix)
|
||||
goto fail;
|
||||
|
||||
paths = match_files (prefix, start, noregexop, ®exp);
|
||||
grub_free (prefix);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char **r = 0;
|
||||
|
||||
for (i = 0; paths[i]; i++)
|
||||
{
|
||||
char **p;
|
||||
|
||||
p = match_files (paths[i], start, noregexop, ®exp);
|
||||
if (! p)
|
||||
continue;
|
||||
|
||||
r = merge (r, p);
|
||||
if (! r)
|
||||
goto fail;
|
||||
}
|
||||
paths = r;
|
||||
}
|
||||
|
||||
regfree (®exp);
|
||||
if (! paths)
|
||||
goto done;
|
||||
|
||||
start = regexop;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
*strs = paths;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
||||
for (i = 0; paths && paths[i]; i++)
|
||||
grub_free (paths[i]);
|
||||
grub_free (paths);
|
||||
regfree (®exp);
|
||||
return grub_errno;
|
||||
}
|
|
@ -248,6 +248,9 @@ grub_biosdisk_get_drive (const char *name)
|
|||
{
|
||||
unsigned long drive;
|
||||
|
||||
if (name[0] == 'c' && name[1] == 'd' && name[2] == 0 && cd_drive)
|
||||
return cd_drive;
|
||||
|
||||
if ((name[0] != 'f' && name[0] != 'h') || name[1] != 'd')
|
||||
goto fail;
|
||||
|
||||
|
@ -270,6 +273,9 @@ grub_biosdisk_call_hook (int (*hook) (const char *name), int drive)
|
|||
{
|
||||
char name[10];
|
||||
|
||||
if (cd_drive && drive == cd_drive)
|
||||
return hook ("cd");
|
||||
|
||||
grub_snprintf (name, sizeof (name),
|
||||
(drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80));
|
||||
return hook (name);
|
||||
|
|
|
@ -71,9 +71,9 @@ delete_loopback (const char *name)
|
|||
|
||||
/* The command to add and remove loopback devices. */
|
||||
static grub_err_t
|
||||
grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args)
|
||||
grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = state = cmd->state;
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
grub_file_t file;
|
||||
struct grub_loopback *newdev;
|
||||
grub_err_t ret;
|
||||
|
@ -167,8 +167,11 @@ grub_loopback_open (const char *name, grub_disk_t disk)
|
|||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
|
||||
|
||||
/* Use the filesize for the disk size, round up to a complete sector. */
|
||||
if (dev->file->size != GRUB_FILE_SIZE_UNKNOWN)
|
||||
disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1)
|
||||
/ GRUB_DISK_SECTOR_SIZE);
|
||||
else
|
||||
disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN;
|
||||
disk->id = (unsigned long) dev;
|
||||
|
||||
disk->has_partitions = dev->has_partitions;
|
||||
|
|
|
@ -274,6 +274,10 @@ grub_lvm_scan_device (const char *name)
|
|||
struct grub_lvm_vg *vg;
|
||||
struct grub_lvm_pv *pv;
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("scanning %s for LVM", name);
|
||||
#endif
|
||||
|
||||
disk = grub_disk_open (name);
|
||||
if (!disk)
|
||||
return 0;
|
||||
|
@ -294,7 +298,12 @@ grub_lvm_scan_device (const char *name)
|
|||
|
||||
/* Return if we didn't find a label. */
|
||||
if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("no LVM signature found\n");
|
||||
#endif
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
|
||||
|
||||
|
@ -318,6 +327,9 @@ grub_lvm_scan_device (const char *name)
|
|||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"we don't support multiple LVM data areas");
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("we don't support multiple LVM data areas\n");
|
||||
#endif
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -344,6 +356,9 @@ grub_lvm_scan_device (const char *name)
|
|||
{
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"unknown LVM metadata header");
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown LVM metadata header\n");
|
||||
#endif
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
|
@ -364,7 +379,12 @@ grub_lvm_scan_device (const char *name)
|
|||
q++;
|
||||
|
||||
if (q == metadatabuf + mda_size)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("error parsing metadata\n");
|
||||
#endif
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
vgname_len = q - p;
|
||||
vgname = grub_malloc (vgname_len + 1);
|
||||
|
@ -376,7 +396,12 @@ grub_lvm_scan_device (const char *name)
|
|||
|
||||
p = grub_strstr (q, "id = \"");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("couldn't find ID\n");
|
||||
#endif
|
||||
goto fail3;
|
||||
}
|
||||
p += sizeof ("id = \"") - 1;
|
||||
grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN);
|
||||
vg_id[GRUB_LVM_ID_STRLEN] = '\0';
|
||||
|
@ -399,7 +424,12 @@ grub_lvm_scan_device (const char *name)
|
|||
|
||||
vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown extent size\n");
|
||||
#endif
|
||||
goto fail4;
|
||||
}
|
||||
|
||||
vg->lvs = NULL;
|
||||
vg->pvs = NULL;
|
||||
|
@ -439,11 +469,21 @@ grub_lvm_scan_device (const char *name)
|
|||
|
||||
pv->start = grub_lvm_getvalue (&p, "pe_start = ");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown pe_start\n");
|
||||
#endif
|
||||
goto pvs_fail;
|
||||
}
|
||||
|
||||
p = grub_strchr (p, '}');
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("error parsing pe_start\n");
|
||||
#endif
|
||||
goto pvs_fail;
|
||||
}
|
||||
p++;
|
||||
|
||||
pv->disk = NULL;
|
||||
|
@ -500,7 +540,12 @@ grub_lvm_scan_device (const char *name)
|
|||
|
||||
lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown segment_count\n");
|
||||
#endif
|
||||
goto lvs_fail;
|
||||
}
|
||||
lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
|
||||
seg = lv->segments;
|
||||
|
||||
|
@ -510,14 +555,29 @@ grub_lvm_scan_device (const char *name)
|
|||
|
||||
p = grub_strstr (p, "segment");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown segment\n");
|
||||
#endif
|
||||
goto lvs_segment_fail;
|
||||
}
|
||||
|
||||
seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown start_extent\n");
|
||||
#endif
|
||||
goto lvs_segment_fail;
|
||||
}
|
||||
seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown extent_count\n");
|
||||
#endif
|
||||
goto lvs_segment_fail;
|
||||
}
|
||||
|
||||
if (grub_lvm_checkvalue (&p, "type = ", "snapshot"))
|
||||
{
|
||||
|
@ -528,7 +588,12 @@ grub_lvm_scan_device (const char *name)
|
|||
|
||||
seg->stripe_count = grub_lvm_getvalue (&p, "stripe_count = ");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown stripe_count\n");
|
||||
#endif
|
||||
goto lvs_segment_fail;
|
||||
}
|
||||
|
||||
lv->size += seg->extent_count * vg->extent_size;
|
||||
|
||||
|
@ -541,7 +606,12 @@ grub_lvm_scan_device (const char *name)
|
|||
|
||||
p = grub_strstr (p, "stripes = [");
|
||||
if (p == NULL)
|
||||
{
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("unknown stripes\n");
|
||||
#endif
|
||||
goto lvs_segment_fail2;
|
||||
}
|
||||
p += sizeof("stripes = [") - 1;
|
||||
|
||||
for (j = 0; j < seg->stripe_count; j++)
|
||||
|
|
|
@ -41,7 +41,7 @@ struct grub_pxe_disk_data
|
|||
grub_uint32_t gateway_ip;
|
||||
};
|
||||
|
||||
struct grub_pxenv *grub_pxe_pxenv;
|
||||
struct grub_pxe_bangpxe *grub_pxe_pxenv;
|
||||
static grub_uint32_t grub_pxe_your_ip;
|
||||
static grub_uint32_t grub_pxe_default_server_ip;
|
||||
static grub_uint32_t grub_pxe_default_gateway_ip;
|
||||
|
@ -58,41 +58,47 @@ struct grub_pxe_data
|
|||
|
||||
static grub_uint32_t pxe_rm_entry = 0;
|
||||
|
||||
static struct grub_pxenv *
|
||||
static struct grub_pxe_bangpxe *
|
||||
grub_pxe_scan (void)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
struct grub_pxenv *ret;
|
||||
void *pxe;
|
||||
struct grub_pxenv *pxenv;
|
||||
struct grub_pxe_bangpxe *bangpxe;
|
||||
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
|
||||
regs.ebx = 0;
|
||||
regs.ecx = 0;
|
||||
regs.eax = 0x5650;
|
||||
regs.es = 0;
|
||||
|
||||
grub_bios_interrupt (0x1a, ®s);
|
||||
|
||||
if ((regs.eax & 0xffff) != 0x564e)
|
||||
return NULL;
|
||||
ret = (struct grub_pxenv *) ((regs.es << 4) + (regs.ebx & 0xffff));
|
||||
if (grub_memcmp (ret->signature, GRUB_PXE_SIGNATURE, sizeof (ret->signature))
|
||||
|
||||
pxenv = (struct grub_pxenv *) ((regs.es << 4) + (regs.ebx & 0xffff));
|
||||
if (grub_memcmp (pxenv->signature, GRUB_PXE_SIGNATURE,
|
||||
sizeof (pxenv->signature))
|
||||
!= 0)
|
||||
return NULL;
|
||||
if (ret->version < 0x201)
|
||||
|
||||
if (pxenv->version < 0x201)
|
||||
return NULL;
|
||||
|
||||
pxe = (void *) ((((ret->pxe_ptr & 0xffff0000) >> 16) << 4)
|
||||
+ (ret->pxe_ptr & 0xffff));
|
||||
if (!pxe)
|
||||
bangpxe = (void *) ((((pxenv->pxe_ptr & 0xffff0000) >> 16) << 4)
|
||||
+ (pxenv->pxe_ptr & 0xffff));
|
||||
|
||||
if (!bangpxe)
|
||||
return NULL;
|
||||
|
||||
/* !PXE */
|
||||
if (*(grub_uint32_t *) pxe != 0x45585021)
|
||||
if (grub_memcmp (bangpxe->signature, GRUB_PXE_BANGPXE_SIGNATURE,
|
||||
sizeof (bangpxe->signature)) != 0)
|
||||
return NULL;
|
||||
|
||||
pxe_rm_entry = ret->rm_entry;
|
||||
return ret;
|
||||
pxe_rm_entry = bangpxe->rm_entry;
|
||||
|
||||
return bangpxe;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -276,6 +282,7 @@ grub_pxefs_open (struct grub_file *file, const char *name)
|
|||
}
|
||||
|
||||
file->data = data;
|
||||
file->not_easly_seekable = 1;
|
||||
grub_memcpy (file_int, file, sizeof (struct grub_file));
|
||||
curr_file = file_int;
|
||||
|
||||
|
@ -321,7 +328,7 @@ grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
o.gateway_ip = disk_data->gateway_ip;
|
||||
grub_strcpy ((char *)&o.filename[0], data->filename);
|
||||
o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
|
||||
o.packet_size = grub_pxe_blksize;
|
||||
o.packet_size = data->block_size;
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &o, pxe_rm_entry);
|
||||
if (o.status)
|
||||
{
|
||||
|
@ -483,7 +490,7 @@ parse_dhcp_vendor (void *vend, int limit)
|
|||
static void
|
||||
grub_pxe_detect (void)
|
||||
{
|
||||
struct grub_pxenv *pxenv;
|
||||
struct grub_pxe_bangpxe *pxenv;
|
||||
struct grub_pxenv_get_cached_info ci;
|
||||
struct grub_pxenv_boot_player *bp;
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <grub/normal.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/kernel.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
/*
|
||||
|
@ -219,7 +218,7 @@ grub_gettext_translate (const char *orig)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* This is similar to grub_gzfile_open. */
|
||||
/* This is similar to grub_file_open. */
|
||||
static grub_file_t
|
||||
grub_mofile_open (const char *filename)
|
||||
{
|
||||
|
@ -229,7 +228,7 @@ grub_mofile_open (const char *filename)
|
|||
/* Using fd_mo and not another variable because
|
||||
it's needed for grub_gettext_get_info. */
|
||||
|
||||
fd_mo = grub_gzfile_open (filename, 1);
|
||||
fd_mo = grub_file_open (filename);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
if (!fd_mo)
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <grub/i18n.h>
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_hello (struct grub_extcmd *cmd __attribute__ ((unused)),
|
||||
grub_cmd_hello (grub_extcmd_context_t ctxt __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
|
|
|
@ -74,6 +74,7 @@ grub_bufio_open (grub_file_t io, int size)
|
|||
file->data = bufio;
|
||||
file->read_hook = 0;
|
||||
file->fs = &grub_bufio_fs;
|
||||
file->not_easly_seekable = io->not_easly_seekable;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#include <grub/misc.h>
|
||||
#include <grub/fs.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/dl.h>
|
||||
|
||||
/*
|
||||
* Window Size
|
||||
|
@ -206,7 +206,7 @@ test_header (grub_file_t file)
|
|||
|| ((hdr.flags & ORIG_NAME) && eat_field (gzio->file, -1))
|
||||
|| ((hdr.flags & COMMENT) && eat_field (gzio->file, -1)))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA, "unsupported gzip format");
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "unsupported gzip format");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -214,12 +214,14 @@ test_header (grub_file_t file)
|
|||
|
||||
grub_file_seek (gzio->file, grub_file_size (gzio->file) - 4);
|
||||
|
||||
if (grub_file_seekable (gzio->file))
|
||||
{
|
||||
if (grub_file_read (gzio->file, &orig_len, 4) != 4)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported gzip format");
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
/* FIXME: this does not handle files whose original size is over 4GB.
|
||||
But how can we know the real original size? */
|
||||
file->size = grub_le_to_cpu32 (orig_len);
|
||||
|
@ -644,7 +646,7 @@ inflate_codes_in_window (grub_file_t file)
|
|||
{
|
||||
if (e == 99)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA,
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
||||
"an unused code found");
|
||||
return 1;
|
||||
}
|
||||
|
@ -683,7 +685,7 @@ inflate_codes_in_window (grub_file_t file)
|
|||
{
|
||||
if (e == 99)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA,
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
||||
"an unused code found");
|
||||
return 1;
|
||||
}
|
||||
|
@ -769,7 +771,7 @@ init_stored_block (grub_file_t file)
|
|||
DUMPBITS (16);
|
||||
NEEDBITS (16);
|
||||
if (gzio->block_len != (int) ((~b) & 0xffff))
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA,
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
||||
"the length of a stored block does not match");
|
||||
DUMPBITS (16);
|
||||
|
||||
|
@ -803,7 +805,7 @@ init_fixed_block (grub_file_t file)
|
|||
if (huft_build (l, 288, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0)
|
||||
{
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA,
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
||||
"failed in building a Huffman code table");
|
||||
return;
|
||||
}
|
||||
|
@ -815,7 +817,7 @@ init_fixed_block (grub_file_t file)
|
|||
if (huft_build (l, 30, 0, cpdist, cpdext, &gzio->td, &gzio->bd) > 1)
|
||||
{
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA,
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
||||
"failed in building a Huffman code table");
|
||||
huft_free (gzio->tl);
|
||||
gzio->tl = 0;
|
||||
|
@ -862,7 +864,7 @@ init_dynamic_block (grub_file_t file)
|
|||
DUMPBITS (4);
|
||||
if (nl > 286 || nd > 30)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA, "too much data");
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too much data");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -880,7 +882,7 @@ init_dynamic_block (grub_file_t file)
|
|||
gzio->bl = 7;
|
||||
if (huft_build (ll, 19, 19, NULL, NULL, &gzio->tl, &gzio->bl) != 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA,
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
||||
"failed in building a Huffman code table");
|
||||
return;
|
||||
}
|
||||
|
@ -904,7 +906,7 @@ init_dynamic_block (grub_file_t file)
|
|||
DUMPBITS (2);
|
||||
if ((unsigned) i + j > n)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA, "too many codes found");
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found");
|
||||
return;
|
||||
}
|
||||
while (j--)
|
||||
|
@ -917,7 +919,7 @@ init_dynamic_block (grub_file_t file)
|
|||
DUMPBITS (3);
|
||||
if ((unsigned) i + j > n)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA, "too many codes found");
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found");
|
||||
return;
|
||||
}
|
||||
while (j--)
|
||||
|
@ -932,7 +934,7 @@ init_dynamic_block (grub_file_t file)
|
|||
DUMPBITS (7);
|
||||
if ((unsigned) i + j > n)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA, "too many codes found");
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found");
|
||||
return;
|
||||
}
|
||||
while (j--)
|
||||
|
@ -954,7 +956,7 @@ init_dynamic_block (grub_file_t file)
|
|||
gzio->bl = lbits;
|
||||
if (huft_build (ll, nl, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA,
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
||||
"failed in building a Huffman code table");
|
||||
return;
|
||||
}
|
||||
|
@ -963,7 +965,7 @@ init_dynamic_block (grub_file_t file)
|
|||
{
|
||||
huft_free (gzio->tl);
|
||||
gzio->tl = 0;
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA,
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
||||
"failed in building a Huffman code table");
|
||||
return;
|
||||
}
|
||||
|
@ -1039,7 +1041,7 @@ inflate_window (grub_file_t file)
|
|||
}
|
||||
|
||||
if (gzio->block_type > INFLATE_DYNAMIC)
|
||||
grub_error (GRUB_ERR_BAD_GZIP_DATA,
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
||||
"unknown block type %d", gzio->block_type);
|
||||
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
|
@ -1111,8 +1113,8 @@ initialize_tables (grub_file_t file)
|
|||
/* Open a new decompressing object on the top of IO. If TRANSPARENT is true,
|
||||
even if IO does not contain data compressed by gzip, return a valid file
|
||||
object. Note that this function won't close IO, even if an error occurs. */
|
||||
grub_file_t
|
||||
grub_gzio_open (grub_file_t io, int transparent)
|
||||
static grub_file_t
|
||||
grub_gzio_open (grub_file_t io)
|
||||
{
|
||||
grub_file_t file;
|
||||
grub_gzio_t gzio = 0;
|
||||
|
@ -1135,6 +1137,7 @@ grub_gzio_open (grub_file_t io, int transparent)
|
|||
file->data = gzio;
|
||||
file->read_hook = 0;
|
||||
file->fs = &grub_gzio_fs;
|
||||
file->not_easly_seekable = 1;
|
||||
|
||||
if (! test_header (file))
|
||||
{
|
||||
|
@ -1142,33 +1145,11 @@ grub_gzio_open (grub_file_t io, int transparent)
|
|||
grub_free (file);
|
||||
grub_file_seek (io, 0);
|
||||
|
||||
if (grub_errno == GRUB_ERR_BAD_FILE_TYPE && transparent)
|
||||
if (grub_errno == GRUB_ERR_BAD_FILE_TYPE)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return io;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/* This is similar to grub_gzio_open, but takes a file name as an argument. */
|
||||
grub_file_t
|
||||
grub_gzfile_open (const char *name, int transparent)
|
||||
{
|
||||
grub_file_t io, file;
|
||||
|
||||
io = grub_file_open (name);
|
||||
if (! io)
|
||||
return 0;
|
||||
|
||||
file = grub_gzio_open (io, transparent);
|
||||
if (! file)
|
||||
{
|
||||
grub_file_close (io);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return file;
|
||||
|
@ -1249,3 +1230,13 @@ static struct grub_fs grub_gzio_fs =
|
|||
.label = 0,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT(gzio)
|
||||
{
|
||||
grub_file_filter_register (GRUB_FILE_FILTER_GZIO, grub_gzio_open);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(gzio)
|
||||
{
|
||||
grub_file_filter_unregister (GRUB_FILE_FILTER_GZIO);
|
||||
}
|
||||
|
|
353
grub-core/io/xzio.c
Normal file
353
grub-core/io/xzio.c
Normal file
|
@ -0,0 +1,353 @@
|
|||
/* xzio.c - decompression support for xz */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/fs.h>
|
||||
#include <grub/dl.h>
|
||||
|
||||
#include "xz.h"
|
||||
#include "xz_stream.h"
|
||||
|
||||
#define XZBUFSIZ 0x2000
|
||||
#define VLI_MAX_DIGITS 9
|
||||
#define XZ_STREAM_FOOTER_SIZE 12
|
||||
|
||||
struct grub_xzio
|
||||
{
|
||||
grub_file_t file;
|
||||
struct xz_buf buf;
|
||||
struct xz_dec *dec;
|
||||
grub_uint8_t inbuf[XZBUFSIZ];
|
||||
grub_uint8_t outbuf[XZBUFSIZ];
|
||||
grub_off_t saved_offset;
|
||||
};
|
||||
|
||||
typedef struct grub_xzio *grub_xzio_t;
|
||||
static struct grub_fs grub_xzio_fs;
|
||||
|
||||
static grub_size_t
|
||||
decode_vli (const grub_uint8_t buf[], grub_size_t size_max,
|
||||
grub_uint64_t * num)
|
||||
{
|
||||
if (size_max == 0)
|
||||
return 0;
|
||||
|
||||
if (size_max > VLI_MAX_DIGITS)
|
||||
size_max = VLI_MAX_DIGITS;
|
||||
|
||||
*num = buf[0] & 0x7F;
|
||||
grub_size_t i = 0;
|
||||
|
||||
while (buf[i++] & 0x80)
|
||||
{
|
||||
if (i >= size_max || buf[i] == 0x00)
|
||||
return 0;
|
||||
|
||||
*num |= (uint64_t) (buf[i] & 0x7F) << (i * 7);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
read_vli (grub_file_t file, grub_uint64_t * num)
|
||||
{
|
||||
grub_uint8_t buf[VLI_MAX_DIGITS];
|
||||
grub_ssize_t read;
|
||||
grub_size_t dec;
|
||||
|
||||
read = grub_file_read (file, buf, VLI_MAX_DIGITS);
|
||||
if (read < 0)
|
||||
return -1;
|
||||
|
||||
dec = decode_vli (buf, read, num);
|
||||
grub_file_seek (file, file->offset - (read - dec));
|
||||
return dec;
|
||||
}
|
||||
|
||||
/* Function xz_dec_run() should consume header and ask for more (XZ_OK)
|
||||
* else file is corrupted (or options not supported) or not xz. */
|
||||
static int
|
||||
test_header (grub_file_t file)
|
||||
{
|
||||
grub_xzio_t xzio = file->data;
|
||||
xzio->buf.in_size = grub_file_read (xzio->file, xzio->inbuf,
|
||||
STREAM_HEADER_SIZE);
|
||||
|
||||
if (xzio->buf.in_size != STREAM_HEADER_SIZE)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FILE_TYPE, "no xz magic found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum xz_ret ret = xz_dec_run (xzio->dec, &xzio->buf);
|
||||
|
||||
if (ret == XZ_FORMAT_ERROR)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FILE_TYPE, "no xz magic found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret != XZ_OK)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "not supported xz options");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Try to find out size of uncompressed data,
|
||||
* also do some footer sanity checks. */
|
||||
static int
|
||||
test_footer (grub_file_t file)
|
||||
{
|
||||
grub_xzio_t xzio = file->data;
|
||||
grub_uint8_t footer[FOOTER_MAGIC_SIZE];
|
||||
grub_uint32_t backsize;
|
||||
grub_uint8_t imarker;
|
||||
grub_uint64_t uncompressed_size_total = 0;
|
||||
grub_uint64_t uncompressed_size;
|
||||
grub_uint64_t records;
|
||||
|
||||
grub_file_seek (xzio->file, xzio->file->size - FOOTER_MAGIC_SIZE);
|
||||
if (grub_file_read (xzio->file, footer, FOOTER_MAGIC_SIZE) !=
|
||||
FOOTER_MAGIC_SIZE
|
||||
|| grub_memcmp (footer, FOOTER_MAGIC, FOOTER_MAGIC_SIZE) != 0)
|
||||
goto ERROR;
|
||||
|
||||
grub_file_seek (xzio->file, xzio->file->size - 8);
|
||||
if (grub_file_read (xzio->file, &backsize, sizeof (backsize))
|
||||
!= sizeof (backsize))
|
||||
goto ERROR;
|
||||
|
||||
/* Calculate real backward size. */
|
||||
backsize = (grub_le_to_cpu32 (backsize) + 1) * 4;
|
||||
|
||||
/* Set file to the beginning of stream index. */
|
||||
grub_file_seek (xzio->file,
|
||||
xzio->file->size - XZ_STREAM_FOOTER_SIZE - backsize);
|
||||
|
||||
/* Test index marker. */
|
||||
if (grub_file_read (xzio->file, &imarker, sizeof (imarker)) !=
|
||||
sizeof (imarker) && imarker != 0x00)
|
||||
goto ERROR;
|
||||
|
||||
if (read_vli (xzio->file, &records) <= 0)
|
||||
goto ERROR;
|
||||
|
||||
for (; records != 0; records--)
|
||||
{
|
||||
if (read_vli (xzio->file, &uncompressed_size) <= 0) /* Ignore unpadded. */
|
||||
goto ERROR;
|
||||
if (read_vli (xzio->file, &uncompressed_size) <= 0) /* Uncompressed. */
|
||||
goto ERROR;
|
||||
|
||||
uncompressed_size_total += uncompressed_size;
|
||||
}
|
||||
|
||||
file->size = uncompressed_size_total;
|
||||
grub_file_seek (xzio->file, STREAM_HEADER_SIZE);
|
||||
return 1;
|
||||
|
||||
ERROR:
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "bad footer magic");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_file_t
|
||||
grub_xzio_open (grub_file_t io)
|
||||
{
|
||||
grub_file_t file;
|
||||
grub_xzio_t xzio;
|
||||
|
||||
file = (grub_file_t) grub_zalloc (sizeof (*file));
|
||||
if (!file)
|
||||
return 0;
|
||||
|
||||
xzio = grub_zalloc (sizeof (*xzio));
|
||||
if (!xzio)
|
||||
{
|
||||
grub_free (file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xzio->file = io;
|
||||
xzio->saved_offset = 0;
|
||||
|
||||
file->device = io->device;
|
||||
file->offset = 0;
|
||||
file->data = xzio;
|
||||
file->read_hook = 0;
|
||||
file->fs = &grub_xzio_fs;
|
||||
file->size = GRUB_FILE_SIZE_UNKNOWN;
|
||||
file->not_easly_seekable = 1;
|
||||
|
||||
if (grub_file_tell (xzio->file) != 0)
|
||||
grub_file_seek (xzio->file, 0);
|
||||
|
||||
/* Allocated 64KiB for dictionary.
|
||||
* Decoder will relocate if bigger is needed. */
|
||||
xzio->dec = xz_dec_init (1 << 16);
|
||||
if (!xzio->dec)
|
||||
{
|
||||
grub_free (file);
|
||||
grub_free (xzio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xzio->buf.in = xzio->inbuf;
|
||||
xzio->buf.in_pos = 0;
|
||||
xzio->buf.in_size = 0;
|
||||
xzio->buf.out = xzio->outbuf;
|
||||
xzio->buf.out_pos = 0;
|
||||
xzio->buf.out_size = XZBUFSIZ;
|
||||
|
||||
if (!test_header (file) || !(grub_file_seekable (io) && test_footer (file)))
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_file_seek (io, 0);
|
||||
xz_dec_end (xzio->dec);
|
||||
grub_free (xzio);
|
||||
grub_free (file);
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_xzio_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
{
|
||||
grub_ssize_t ret = 0;
|
||||
grub_ssize_t readret;
|
||||
enum xz_ret xzret;
|
||||
grub_xzio_t xzio = file->data;
|
||||
grub_off_t current_offset;
|
||||
|
||||
/* If seek backward need to reset decoder and start from beginning of file.
|
||||
TODO Possible improvement by jumping blocks. */
|
||||
if (file->offset < xzio->saved_offset)
|
||||
{
|
||||
xz_dec_reset (xzio->dec);
|
||||
xzio->saved_offset = 0;
|
||||
xzio->buf.out_pos = 0;
|
||||
xzio->buf.in_pos = 0;
|
||||
xzio->buf.in_size = 0;
|
||||
grub_file_seek (xzio->file, 0);
|
||||
}
|
||||
|
||||
current_offset = xzio->saved_offset;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
xzio->buf.out_size = grub_min (file->offset + ret + len - current_offset,
|
||||
XZBUFSIZ);
|
||||
|
||||
/* Feed input. */
|
||||
if (xzio->buf.in_pos == xzio->buf.in_size)
|
||||
{
|
||||
readret = grub_file_read (xzio->file, xzio->inbuf, XZBUFSIZ);
|
||||
if (readret < 0)
|
||||
return -1;
|
||||
xzio->buf.in_size = readret;
|
||||
xzio->buf.in_pos = 0;
|
||||
}
|
||||
|
||||
xzret = xz_dec_run (xzio->dec, &xzio->buf);
|
||||
switch (xzret)
|
||||
{
|
||||
case XZ_MEMLIMIT_ERROR:
|
||||
case XZ_FORMAT_ERROR:
|
||||
case XZ_OPTIONS_ERROR:
|
||||
case XZ_DATA_ERROR:
|
||||
case XZ_BUF_ERROR:
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
||||
"file corrupted or unsupported block options");
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
grub_off_t new_offset = current_offset + xzio->buf.out_pos;
|
||||
|
||||
if (file->offset <= new_offset)
|
||||
/* Store first chunk of data in buffer. */
|
||||
{
|
||||
grub_size_t delta = new_offset - (file->offset + ret);
|
||||
grub_memmove (buf, xzio->buf.out + (xzio->buf.out_pos - delta),
|
||||
delta);
|
||||
len -= delta;
|
||||
buf += delta;
|
||||
ret += delta;
|
||||
}
|
||||
current_offset = new_offset;
|
||||
}
|
||||
xzio->buf.out_pos = 0;
|
||||
|
||||
if (xzret == XZ_STREAM_END) /* Stream end, EOF. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret >= 0)
|
||||
xzio->saved_offset = file->offset + ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Release everything, including the underlying file object. */
|
||||
static grub_err_t
|
||||
grub_xzio_close (grub_file_t file)
|
||||
{
|
||||
grub_xzio_t xzio = file->data;
|
||||
|
||||
xz_dec_end (xzio->dec);
|
||||
|
||||
grub_file_close (xzio->file);
|
||||
grub_free (xzio);
|
||||
|
||||
/* Device must not be closed twice. */
|
||||
file->device = 0;
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static struct grub_fs grub_xzio_fs = {
|
||||
.name = "xzio",
|
||||
.dir = 0,
|
||||
.open = 0,
|
||||
.read = grub_xzio_read,
|
||||
.close = grub_xzio_close,
|
||||
.label = 0,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT (xzio)
|
||||
{
|
||||
grub_file_filter_register (GRUB_FILE_FILTER_XZIO, grub_xzio_open);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (xzio)
|
||||
{
|
||||
grub_file_filter_unregister (GRUB_FILE_FILTER_XZIO);
|
||||
}
|
|
@ -66,10 +66,33 @@ grub_efi_set_prefix (void)
|
|||
path = grub_strdup (pptr);
|
||||
}
|
||||
|
||||
if (!device || !path)
|
||||
if ((!device || device[0] == ',' || !device[0]) || !path)
|
||||
image = grub_efi_get_loaded_image (grub_efi_image_handle);
|
||||
if (image && !device)
|
||||
if (image)
|
||||
{
|
||||
if (!device)
|
||||
device = grub_efidisk_get_device_name (image->device_handle);
|
||||
else if (device[0] == ',' || !device[0])
|
||||
{
|
||||
/* We have a partition, but still need to fill in the drive. */
|
||||
char *image_device, *comma, *new_device;
|
||||
|
||||
image_device = grub_efidisk_get_device_name (image->device_handle);
|
||||
comma = grub_strchr (image_device, ',');
|
||||
if (comma)
|
||||
{
|
||||
char *drive = grub_strndup (image_device, comma - image_device);
|
||||
new_device = grub_xasprintf ("%s%s", drive, device);
|
||||
grub_free (drive);
|
||||
}
|
||||
else
|
||||
new_device = grub_xasprintf ("%s%s", image_device, device);
|
||||
|
||||
grub_free (image_device);
|
||||
grub_free (device);
|
||||
device = new_device;
|
||||
}
|
||||
}
|
||||
|
||||
if (image && !path)
|
||||
{
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <grub/elf.h>
|
||||
#include <grub/elfload.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
|
@ -95,7 +94,7 @@ grub_elf_open (const char *name)
|
|||
grub_file_t file;
|
||||
grub_elf_t elf;
|
||||
|
||||
file = grub_gzfile_open (name, 1);
|
||||
file = grub_file_open (name);
|
||||
if (! file)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -197,6 +197,13 @@ main (int argc, char *argv[])
|
|||
|
||||
grub_init_all ();
|
||||
|
||||
grub_lvm_fini ();
|
||||
grub_mdraid_fini ();
|
||||
grub_raid_fini ();
|
||||
grub_raid_init ();
|
||||
grub_mdraid_init ();
|
||||
grub_lvm_init ();
|
||||
|
||||
/* Make sure that there is a root device. */
|
||||
if (! root_dev)
|
||||
{
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
#include <grub/fs.h>
|
||||
#include <grub/device.h>
|
||||
|
||||
grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX];
|
||||
grub_file_filter_t grub_file_filters_enabled[GRUB_FILE_FILTER_MAX];
|
||||
|
||||
/* Get the device part of the filename NAME. It is enclosed by parentheses. */
|
||||
char *
|
||||
grub_file_get_device_name (const char *name)
|
||||
|
@ -54,14 +57,15 @@ grub_file_get_device_name (const char *name)
|
|||
grub_file_t
|
||||
grub_file_open (const char *name)
|
||||
{
|
||||
grub_device_t device;
|
||||
grub_file_t file = 0;
|
||||
grub_device_t device = 0;
|
||||
grub_file_t file = 0, last_file = 0;
|
||||
char *device_name;
|
||||
char *file_name;
|
||||
grub_file_filter_id_t filter;
|
||||
|
||||
device_name = grub_file_get_device_name (name);
|
||||
if (grub_errno)
|
||||
return 0;
|
||||
goto fail;
|
||||
|
||||
/* Get the file part of NAME. */
|
||||
file_name = grub_strchr (name, ')');
|
||||
|
@ -94,6 +98,19 @@ grub_file_open (const char *name)
|
|||
if ((file->fs->open) (file, file_name) != GRUB_ERR_NONE)
|
||||
goto fail;
|
||||
|
||||
for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters_enabled);
|
||||
filter++)
|
||||
if (grub_file_filters_enabled[filter])
|
||||
{
|
||||
last_file = file;
|
||||
file = grub_file_filters_enabled[filter] (file);
|
||||
}
|
||||
if (!file)
|
||||
grub_file_close (last_file);
|
||||
|
||||
grub_memcpy (grub_file_filters_enabled, grub_file_filters_all,
|
||||
sizeof (grub_file_filters_enabled));
|
||||
|
||||
return file;
|
||||
|
||||
fail:
|
||||
|
@ -104,6 +121,9 @@ grub_file_open (const char *name)
|
|||
|
||||
grub_free (file);
|
||||
|
||||
grub_memcpy (grub_file_filters_enabled, grub_file_filters_all,
|
||||
sizeof (grub_file_filters_enabled));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ VARIABLE(grub_prefix)
|
|||
* Leave some breathing room for the prefix.
|
||||
*/
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_DATA_END
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
|
||||
|
||||
/*
|
||||
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
|
||||
|
|
|
@ -51,7 +51,7 @@ VARIABLE(grub_prefix)
|
|||
* Leave some breathing room for the prefix.
|
||||
*/
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_DATA_END
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
|
||||
|
||||
codestart:
|
||||
movl %eax, EXT_C(grub_ieee1275_entry_fn)
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/machine/init.h>
|
||||
#include <grub/machine/memory.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/multiboot.h>
|
||||
|
|
|
@ -100,14 +100,6 @@ VARIABLE(grub_install_dos_part)
|
|||
.long 0xFFFFFFFF
|
||||
VARIABLE(grub_install_bsd_part)
|
||||
.long 0xFFFFFFFF
|
||||
VARIABLE(grub_prefix)
|
||||
/* to be filled by grub-mkimage */
|
||||
|
||||
/*
|
||||
* Leave some breathing room for the prefix.
|
||||
*/
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_DATA_END
|
||||
|
||||
#ifdef APPLE_CC
|
||||
bss_start:
|
||||
|
@ -450,6 +442,16 @@ gate_a20_check_state:
|
|||
*/
|
||||
. = _start + GRUB_KERNEL_MACHINE_RAW_SIZE
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX
|
||||
VARIABLE(grub_prefix)
|
||||
/* to be filled by grub-mkimage */
|
||||
|
||||
/*
|
||||
* Leave some breathing room for the prefix.
|
||||
*/
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* grub_exit()
|
||||
|
|
|
@ -39,7 +39,7 @@ VARIABLE(grub_prefix)
|
|||
* Leave some breathing room for the prefix.
|
||||
*/
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_DATA_END
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
|
||||
|
||||
codestart:
|
||||
/* Relocate to low memory. First we figure out our location.
|
||||
|
|
|
@ -154,7 +154,7 @@ VARIABLE(grub_prefix)
|
|||
* Leave some breathing room for the prefix.
|
||||
*/
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_DATA_END
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
|
||||
#ifdef GRUB_MACHINE_MIPS_YEELOONG
|
||||
VARIABLE (grub_arch_busclock)
|
||||
.long 0
|
||||
|
|
|
@ -990,7 +990,7 @@ grub_abort (void)
|
|||
grub_exit ();
|
||||
}
|
||||
|
||||
#ifndef APPLE_CC
|
||||
#if ! defined (APPLE_CC) && !defined (GRUB_UTIL)
|
||||
/* GCC emits references to abort(). */
|
||||
void abort (void) __attribute__ ((alias ("grub_abort")));
|
||||
#endif
|
||||
|
|
|
@ -39,7 +39,7 @@ VARIABLE(grub_prefix)
|
|||
* Leave some breathing room for the prefix.
|
||||
*/
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_DATA_END
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
|
||||
|
||||
codestart:
|
||||
li 2, 0
|
||||
|
|
|
@ -42,7 +42,7 @@ VARIABLE(grub_prefix)
|
|||
* Leave some breathing room for the prefix.
|
||||
*/
|
||||
|
||||
. = EXT_C(_start) + GRUB_KERNEL_MACHINE_DATA_END
|
||||
. = EXT_C(_start) + GRUB_KERNEL_MACHINE_PREFIX_END
|
||||
|
||||
codestart:
|
||||
/* Copy the modules past the end of the kernel image.
|
||||
|
|
|
@ -209,10 +209,18 @@ parse_option (grub_extcmd_t cmd, int key, char *arg, struct grub_arg_list *usr)
|
|||
if (found == -1)
|
||||
return -1;
|
||||
|
||||
if (opt->flags & GRUB_ARG_OPTION_REPEATABLE)
|
||||
{
|
||||
usr[found].args[usr[found].set++] = arg;
|
||||
usr[found].args[usr[found].set] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
usr[found].set = 1;
|
||||
usr[found].arg = arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -230,10 +238,15 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
|
|||
|
||||
grub_err_t add_arg (char *s)
|
||||
{
|
||||
argl = grub_realloc (argl, (++num) * sizeof (char *));
|
||||
char **p = argl;
|
||||
argl = grub_realloc (argl, (++num + 1) * sizeof (char *));
|
||||
if (! argl)
|
||||
{
|
||||
grub_free (p);
|
||||
return grub_errno;
|
||||
}
|
||||
argl[num - 1] = s;
|
||||
argl[num] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -310,8 +323,11 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
|
|||
if (option) {
|
||||
arglen = option - arg - 2;
|
||||
option++;
|
||||
} else
|
||||
} else {
|
||||
arglen = grub_strlen (arg) - 2;
|
||||
if (argv[curarg + 1])
|
||||
option = argv[curarg + 1][0] == '-' ? 0 : argv[++curarg];
|
||||
}
|
||||
|
||||
opt = find_long (cmd->options, arg + 2, arglen);
|
||||
if (! opt)
|
||||
|
@ -390,3 +406,43 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
|
|||
fail:
|
||||
return complete;
|
||||
}
|
||||
|
||||
struct grub_arg_list*
|
||||
grub_arg_list_alloc(grub_extcmd_t extcmd, int argc,
|
||||
char **argv __attribute__((unused)))
|
||||
{
|
||||
int i;
|
||||
char **args;
|
||||
unsigned argcnt;
|
||||
struct grub_arg_list *list;
|
||||
const struct grub_arg_option *options;
|
||||
|
||||
options = extcmd->options;
|
||||
if (! options)
|
||||
return 0;
|
||||
|
||||
argcnt = 0;
|
||||
for (i = 0; options[i].doc; i++)
|
||||
{
|
||||
if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
|
||||
argcnt += (argc + 1) / 2 + 1; /* max possible for any option */
|
||||
}
|
||||
|
||||
list = grub_zalloc (sizeof (*list) * i + sizeof (char*) * argcnt);
|
||||
if (! list)
|
||||
return 0;
|
||||
|
||||
args = (char**) (list + i);
|
||||
for (i = 0; options[i].doc; i++)
|
||||
{
|
||||
list[i].set = 0;
|
||||
list[i].arg = 0;
|
||||
|
||||
if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
|
||||
{
|
||||
list[i].args = args;
|
||||
args += argc / 2 + 1;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,9 @@ extern grub_uint32_t grub_relocator32_ecx;
|
|||
extern grub_uint32_t grub_relocator32_edx;
|
||||
extern grub_uint32_t grub_relocator32_eip;
|
||||
extern grub_uint32_t grub_relocator32_esp;
|
||||
extern grub_uint32_t grub_relocator32_ebp;
|
||||
extern grub_uint32_t grub_relocator32_esi;
|
||||
extern grub_uint32_t grub_relocator32_edi;
|
||||
|
||||
extern grub_uint8_t grub_relocator64_start;
|
||||
extern grub_uint8_t grub_relocator64_end;
|
||||
|
@ -165,7 +167,9 @@ grub_relocator32_boot (struct grub_relocator *rel,
|
|||
grub_relocator32_edx = state.edx;
|
||||
grub_relocator32_eip = state.eip;
|
||||
grub_relocator32_esp = state.esp;
|
||||
grub_relocator32_ebp = state.ebp;
|
||||
grub_relocator32_esi = state.esi;
|
||||
grub_relocator32_edi = state.edi;
|
||||
|
||||
grub_memmove (get_virtual_current_address (ch), &grub_relocator32_start,
|
||||
RELOCATOR_SIZEOF (32));
|
||||
|
|
|
@ -65,6 +65,13 @@ VARIABLE(grub_relocator32_esp)
|
|||
|
||||
movl %eax, %esp
|
||||
|
||||
/* mov imm32, %eax */
|
||||
.byte 0xb8
|
||||
VARIABLE(grub_relocator32_ebp)
|
||||
.long 0
|
||||
|
||||
movl %eax, %ebp
|
||||
|
||||
/* mov imm32, %eax */
|
||||
.byte 0xb8
|
||||
VARIABLE(grub_relocator32_esi)
|
||||
|
@ -72,6 +79,13 @@ VARIABLE(grub_relocator32_esi)
|
|||
|
||||
movl %eax, %esi
|
||||
|
||||
/* mov imm32, %eax */
|
||||
.byte 0xb8
|
||||
VARIABLE(grub_relocator32_edi)
|
||||
.long 0
|
||||
|
||||
movl %eax, %edi
|
||||
|
||||
/* mov imm32, %eax */
|
||||
.byte 0xb8
|
||||
VARIABLE(grub_relocator32_eax)
|
||||
|
|
|
@ -22,11 +22,14 @@
|
|||
#include <grub/misc.h>
|
||||
|
||||
typedef grub_size_t size_t;
|
||||
typedef int bool;
|
||||
static const bool true = 1;
|
||||
static const bool false = 0;
|
||||
typedef enum { false = 0, true = 1 } bool;
|
||||
|
||||
#define ULONG_MAX GRUB_ULONG_MAX
|
||||
#define UCHAR_MAX 0xff
|
||||
|
||||
typedef grub_uint8_t uint8_t;
|
||||
typedef grub_uint16_t uint16_t;
|
||||
typedef grub_uint32_t uint32_t;
|
||||
typedef grub_uint64_t uint64_t;
|
||||
|
||||
#endif
|
||||
|
|
180
grub-core/lib/xzembed/xz.h
Normal file
180
grub-core/lib/xzembed/xz.h
Normal file
|
@ -0,0 +1,180 @@
|
|||
/* xz.h - XZ decompressor */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* This file is based on code from XZ embedded project
|
||||
* http://tukaani.org/xz/embedded.html
|
||||
*/
|
||||
|
||||
#ifndef XZ_H
|
||||
#define XZ_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* enum xz_ret - Return codes
|
||||
* @XZ_OK: Everything is OK so far. More input or more output
|
||||
* space is required to continue.
|
||||
* @XZ_STREAM_END: Operation finished successfully.
|
||||
* @XZ_MEMLIMIT_ERROR: Not enough memory was preallocated at decoder
|
||||
* initialization time.
|
||||
* @XZ_FORMAT_ERROR: File format was not recognized (wrong magic bytes).
|
||||
* @XZ_OPTIONS_ERROR: This implementation doesn't support the requested
|
||||
* compression options. In the decoder this means that
|
||||
* the header CRC32 matches, but the header itself
|
||||
* specifies something that we don't support.
|
||||
* @XZ_DATA_ERROR: Compressed data is corrupt.
|
||||
* @XZ_BUF_ERROR: Cannot make any progress. Details are slightly
|
||||
* different between multi-call and single-call mode;
|
||||
* more information below.
|
||||
*
|
||||
* In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
|
||||
* to XZ code cannot consume any input and cannot produce any new output.
|
||||
* This happens when there is no new input available, or the output buffer
|
||||
* is full while at least one output byte is still pending. Assuming your
|
||||
* code is not buggy, you can get this error only when decoding a compressed
|
||||
* stream that is truncated or otherwise corrupt.
|
||||
*
|
||||
* In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
|
||||
* is too small, or the compressed input is corrupt in a way that makes the
|
||||
* decoder produce more output than the caller expected. When it is
|
||||
* (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
|
||||
* is used instead of XZ_BUF_ERROR.
|
||||
*/
|
||||
enum xz_ret {
|
||||
XZ_OK,
|
||||
XZ_STREAM_END,
|
||||
XZ_MEMLIMIT_ERROR,
|
||||
XZ_FORMAT_ERROR,
|
||||
XZ_OPTIONS_ERROR,
|
||||
XZ_DATA_ERROR,
|
||||
XZ_BUF_ERROR
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xz_buf - Passing input and output buffers to XZ code
|
||||
* @in: Beginning of the input buffer. This may be NULL if and only
|
||||
* if in_pos is equal to in_size.
|
||||
* @in_pos: Current position in the input buffer. This must not exceed
|
||||
* in_size.
|
||||
* @in_size: Size of the input buffer
|
||||
* @out: Beginning of the output buffer. This may be NULL if and only
|
||||
* if out_pos is equal to out_size.
|
||||
* @out_pos: Current position in the output buffer. This must not exceed
|
||||
* out_size.
|
||||
* @out_size: Size of the output buffer
|
||||
*
|
||||
* Only the contents of the output buffer from out[out_pos] onward, and
|
||||
* the variables in_pos and out_pos are modified by the XZ code.
|
||||
*/
|
||||
struct xz_buf {
|
||||
const uint8_t *in;
|
||||
size_t in_pos;
|
||||
size_t in_size;
|
||||
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xz_dec - Opaque type to hold the XZ decoder state
|
||||
*/
|
||||
struct xz_dec;
|
||||
|
||||
/**
|
||||
* xz_dec_init() - Allocate and initialize a XZ decoder state
|
||||
* @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for
|
||||
* multi-call decoding, or special value of zero to indicate
|
||||
* single-call decoding mode.
|
||||
*
|
||||
* If dict_max > 0, the decoder is initialized to work in multi-call mode.
|
||||
* dict_max number of bytes of memory is preallocated for the LZMA2
|
||||
* dictionary. This way there is no risk that xz_dec_run() could run out
|
||||
* of memory, since xz_dec_run() will never allocate any memory. Instead,
|
||||
* if the preallocated dictionary is too small for decoding the given input
|
||||
* stream, xz_dec_run() will return XZ_MEMLIMIT_ERROR. Thus, it is important
|
||||
* to know what kind of data will be decoded to avoid allocating excessive
|
||||
* amount of memory for the dictionary.
|
||||
*
|
||||
* LZMA2 dictionary is always 2^n bytes or 2^n + 2^(n-1) bytes (the latter
|
||||
* sizes are less common in practice). In the kernel, dictionary sizes of
|
||||
* 64 KiB, 128 KiB, 256 KiB, 512 KiB, and 1 MiB are probably the only
|
||||
* reasonable values.
|
||||
*
|
||||
* If dict_max == 0, the decoder is initialized to work in single-call mode.
|
||||
* In single-call mode, xz_dec_run() decodes the whole stream at once. The
|
||||
* caller must provide enough output space or the decoding will fail. The
|
||||
* output space is used as the dictionary buffer, which is why there is
|
||||
* no need to allocate the dictionary as part of the decoder's internal
|
||||
* state.
|
||||
*
|
||||
* Because the output buffer is used as the workspace, streams encoded using
|
||||
* a big dictionary are not a problem in single-call. It is enough that the
|
||||
* output buffer is is big enough to hold the actual uncompressed data; it
|
||||
* can be smaller than the dictionary size stored in the stream headers.
|
||||
*
|
||||
* On success, xz_dec_init() returns a pointer to struct xz_dec, which is
|
||||
* ready to be used with xz_dec_run(). On error, xz_dec_init() returns NULL.
|
||||
*/
|
||||
struct xz_dec * xz_dec_init(uint32_t dict_max);
|
||||
|
||||
/**
|
||||
* xz_dec_run() - Run the XZ decoder
|
||||
* @s: Decoder state allocated using xz_dec_init()
|
||||
* @b: Input and output buffers
|
||||
*
|
||||
* In multi-call mode, this function may return any of the values listed in
|
||||
* enum xz_ret.
|
||||
*
|
||||
* In single-call mode, this function never returns XZ_OK. If an error occurs
|
||||
* in single-call mode (return value is not XZ_STREAM_END), b->in_pos and
|
||||
* b->out_pos are not modified, and the contents of the output buffer from
|
||||
* b->out[b->out_pos] onward are undefined.
|
||||
*
|
||||
* NOTE: In single-call mode, the contents of the output buffer are undefined
|
||||
* also after XZ_BUF_ERROR. This is because with some filter chains, there
|
||||
* may be a second pass over the output buffer, and this pass cannot be
|
||||
* properly done if the output buffer is truncated. Thus, you cannot give
|
||||
* the single-call decoder a too small buffer and then expect to get that
|
||||
* amount valid data from the beginning of the stream. You must use the
|
||||
* multi-call decoder if you don't want to uncompress the whole stream.
|
||||
*/
|
||||
enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b);
|
||||
|
||||
/**
|
||||
* xz_dec_reset() - Reset an already allocated decoder state
|
||||
* @s: Decoder state allocated using xz_dec_init()
|
||||
*
|
||||
* This function can be used to reset the multi-call decoder state without
|
||||
* freeing and reallocating memory with xz_dec_end() and xz_dec_init().
|
||||
*
|
||||
* In single-call mode, xz_dec_reset() is always called in the beginning of
|
||||
* xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
|
||||
* multi-call mode.
|
||||
*/
|
||||
void xz_dec_reset(struct xz_dec *s);
|
||||
|
||||
/**
|
||||
* xz_dec_end() - Free the memory allocated for the decoder state
|
||||
* @s: Decoder state allocated using xz_dec_init(). If s is NULL,
|
||||
* this function does nothing.
|
||||
*/
|
||||
void xz_dec_end(struct xz_dec *s);
|
||||
|
||||
#endif
|
141
grub-core/lib/xzembed/xz_config.h
Normal file
141
grub-core/lib/xzembed/xz_config.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
/* xz_config.h - Private includes and definitions for userspace use */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* This file is based on code from XZ embedded project
|
||||
* http://tukaani.org/xz/embedded.html
|
||||
*/
|
||||
|
||||
#ifndef XZ_CONFIG_H
|
||||
#define XZ_CONFIG_H
|
||||
|
||||
/* Enable BCJ filter decoders. */
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#define XZ_DEC_X86
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
#define XZ_DEC_POWERPC
|
||||
#endif
|
||||
|
||||
#ifdef __ia64__
|
||||
#define XZ_DEC_IA64
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
#define XZ_DEC_ARM
|
||||
#endif
|
||||
|
||||
#ifdef __thumb__
|
||||
#define XZ_DEC_ARMTHUMB
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
#define XZ_DEC_SPARC
|
||||
#endif
|
||||
|
||||
|
||||
#include "xz.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define kmalloc(size, flags) malloc(size)
|
||||
#define kfree(ptr) free(ptr)
|
||||
#define vmalloc(size) malloc(size)
|
||||
#define vfree(ptr) free(ptr)
|
||||
|
||||
#define memeq(a, b, size) (memcmp(a, b, size) == 0)
|
||||
#define memzero(buf, size) memset(buf, 0, size)
|
||||
|
||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define min_t(type, x, y) min(x, y)
|
||||
|
||||
/*
|
||||
* Some functions have been marked with __always_inline to keep the
|
||||
* performance reasonable even when the compiler is optimizing for
|
||||
* small code size. You may be able to save a few bytes by #defining
|
||||
* __always_inline to plain inline, but don't complain if the code
|
||||
* becomes slow.
|
||||
*
|
||||
* NOTE: System headers on GNU/Linux may #define this macro already,
|
||||
* so if you want to change it, it you need to #undef it first.
|
||||
*/
|
||||
#ifndef __always_inline
|
||||
# ifdef __GNUC__
|
||||
# define __always_inline \
|
||||
inline __attribute__((__always_inline__))
|
||||
# else
|
||||
# define __always_inline inline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some functions are marked to never be inlined to reduce stack usage.
|
||||
* If you don't care about stack usage, you may want to modify this so
|
||||
* that noinline_for_stack is #defined to be empty even when using GCC.
|
||||
* Doing so may save a few bytes in binary size.
|
||||
*/
|
||||
#ifndef noinline_for_stack
|
||||
# ifdef __GNUC__
|
||||
# define noinline_for_stack __attribute__((__noinline__))
|
||||
# else
|
||||
# define noinline_for_stack
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Inline functions to access unaligned unsigned 32-bit integers */
|
||||
static inline uint32_t get_unaligned_le32(const uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)buf[0]
|
||||
| ((uint32_t)buf[1] << 8)
|
||||
| ((uint32_t)buf[2] << 16)
|
||||
| ((uint32_t)buf[3] << 24);
|
||||
}
|
||||
|
||||
static inline uint32_t get_unaligned_be32(const uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)(buf[0] << 24)
|
||||
| ((uint32_t)buf[1] << 16)
|
||||
| ((uint32_t)buf[2] << 8)
|
||||
| (uint32_t)buf[3];
|
||||
}
|
||||
|
||||
static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (uint8_t)val;
|
||||
buf[1] = (uint8_t)(val >> 8);
|
||||
buf[2] = (uint8_t)(val >> 16);
|
||||
buf[3] = (uint8_t)(val >> 24);
|
||||
}
|
||||
|
||||
static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (uint8_t)(val >> 24);
|
||||
buf[1] = (uint8_t)(val >> 16);
|
||||
buf[2] = (uint8_t)(val >> 8);
|
||||
buf[3] = (uint8_t)val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use get_unaligned_le32() also for aligned access for simplicity. On
|
||||
* little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr))
|
||||
* could save a few bytes in code size.
|
||||
*/
|
||||
#define get_le32 get_unaligned_le32
|
||||
|
||||
#endif
|
569
grub-core/lib/xzembed/xz_dec_bcj.c
Normal file
569
grub-core/lib/xzembed/xz_dec_bcj.c
Normal file
|
@ -0,0 +1,569 @@
|
|||
/* xz_dec_bcj.c - Branch/Call/Jump (BCJ) filter decoders */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* This file is based on code from XZ embedded project
|
||||
* http://tukaani.org/xz/embedded.html
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
|
||||
struct xz_dec_bcj {
|
||||
/* Type of the BCJ filter being used */
|
||||
enum {
|
||||
BCJ_X86 = 4, /* x86 or x86-64 */
|
||||
BCJ_POWERPC = 5, /* Big endian only */
|
||||
BCJ_IA64 = 6, /* Big or little endian */
|
||||
BCJ_ARM = 7, /* Little endian only */
|
||||
BCJ_ARMTHUMB = 8, /* Little endian only */
|
||||
BCJ_SPARC = 9 /* Big or little endian */
|
||||
} type;
|
||||
|
||||
/*
|
||||
* Return value of the next filter in the chain. We need to preserve
|
||||
* this information across calls, because we must not call the next
|
||||
* filter anymore once it has returned XZ_STREAM_END.
|
||||
*/
|
||||
enum xz_ret ret;
|
||||
|
||||
/* True if we are operating in single-call mode. */
|
||||
bool single_call;
|
||||
|
||||
/*
|
||||
* Absolute position relative to the beginning of the uncompressed
|
||||
* data (in a single .xz Block). We care only about the lowest 32
|
||||
* bits so this doesn't need to be uint64_t even with big files.
|
||||
*/
|
||||
uint32_t pos;
|
||||
|
||||
/* x86 filter state */
|
||||
uint32_t x86_prev_mask;
|
||||
|
||||
/* Temporary space to hold the variables from struct xz_buf */
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
|
||||
struct {
|
||||
/* Amount of already filtered data in the beginning of buf */
|
||||
size_t filtered;
|
||||
|
||||
/* Total amount of data currently stored in buf */
|
||||
size_t size;
|
||||
|
||||
/*
|
||||
* Buffer to hold a mix of filtered and unfiltered data. This
|
||||
* needs to be big enough to hold Alignment + 2 * Look-ahead:
|
||||
*
|
||||
* Type Alignment Look-ahead
|
||||
* x86 1 4
|
||||
* PowerPC 4 0
|
||||
* IA-64 16 0
|
||||
* ARM 4 0
|
||||
* ARM-Thumb 2 2
|
||||
* SPARC 4 0
|
||||
*/
|
||||
uint8_t buf[16];
|
||||
} temp;
|
||||
};
|
||||
|
||||
#ifdef XZ_DEC_X86
|
||||
/*
|
||||
* This is macro used to test the most significant byte of a memory address
|
||||
* in an x86 instruction.
|
||||
*/
|
||||
#define bcj_x86_test_msbyte(b) ((b) == 0x00 || (b) == 0xFF)
|
||||
|
||||
static noinline_for_stack size_t bcj_x86(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
static const bool mask_to_allowed_status[8]
|
||||
= { true, true, true, false, true, false, false, false };
|
||||
|
||||
static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
|
||||
|
||||
size_t i;
|
||||
size_t prev_pos = (size_t)-1;
|
||||
uint32_t prev_mask = s->x86_prev_mask;
|
||||
uint32_t src;
|
||||
uint32_t dest;
|
||||
uint32_t j;
|
||||
uint8_t b;
|
||||
|
||||
if (size <= 4)
|
||||
return 0;
|
||||
|
||||
size -= 4;
|
||||
for (i = 0; i < size; ++i) {
|
||||
if ((buf[i] & 0xFE) != 0xE8)
|
||||
continue;
|
||||
|
||||
prev_pos = i - prev_pos;
|
||||
if (prev_pos > 3) {
|
||||
prev_mask = 0;
|
||||
} else {
|
||||
prev_mask = (prev_mask << (prev_pos - 1)) & 7;
|
||||
if (prev_mask != 0) {
|
||||
b = buf[i + 4 - mask_to_bit_num[prev_mask]];
|
||||
if (!mask_to_allowed_status[prev_mask]
|
||||
|| bcj_x86_test_msbyte(b)) {
|
||||
prev_pos = i;
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prev_pos = i;
|
||||
|
||||
if (bcj_x86_test_msbyte(buf[i + 4])) {
|
||||
src = get_unaligned_le32(buf + i + 1);
|
||||
while (true) {
|
||||
dest = src - (s->pos + (uint32_t)i + 5);
|
||||
if (prev_mask == 0)
|
||||
break;
|
||||
|
||||
j = mask_to_bit_num[prev_mask] * 8;
|
||||
b = (uint8_t)(dest >> (24 - j));
|
||||
if (!bcj_x86_test_msbyte(b))
|
||||
break;
|
||||
|
||||
src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
|
||||
}
|
||||
|
||||
dest &= 0x01FFFFFF;
|
||||
dest |= (uint32_t)0 - (dest & 0x01000000);
|
||||
put_unaligned_le32(dest, buf + i + 1);
|
||||
i += 4;
|
||||
} else {
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
}
|
||||
}
|
||||
|
||||
prev_pos = i - prev_pos;
|
||||
s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
static noinline_for_stack size_t bcj_powerpc(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t instr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4) {
|
||||
instr = get_unaligned_be32(buf + i);
|
||||
if ((instr & 0xFC000003) == 0x48000001) {
|
||||
instr &= 0x03FFFFFC;
|
||||
instr -= s->pos + (uint32_t)i;
|
||||
instr &= 0x03FFFFFC;
|
||||
instr |= 0x48000001;
|
||||
put_unaligned_be32(instr, buf + i);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_IA64
|
||||
static noinline_for_stack size_t bcj_ia64(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
static const uint8_t branch_table[32] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
4, 4, 6, 6, 0, 0, 7, 7,
|
||||
4, 4, 0, 0, 4, 4, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* The local variables take a little bit stack space, but it's less
|
||||
* than what LZMA2 decoder takes, so it doesn't make sense to reduce
|
||||
* stack usage here without doing that for the LZMA2 decoder too.
|
||||
*/
|
||||
|
||||
/* Loop counters */
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
|
||||
uint32_t slot;
|
||||
|
||||
/* Bitwise offset of the instruction indicated by slot */
|
||||
uint32_t bit_pos;
|
||||
|
||||
/* bit_pos split into byte and bit parts */
|
||||
uint32_t byte_pos;
|
||||
uint32_t bit_res;
|
||||
|
||||
/* Address part of an instruction */
|
||||
uint32_t addr;
|
||||
|
||||
/* Mask used to detect which instructions to convert */
|
||||
uint32_t mask;
|
||||
|
||||
/* 41-bit instruction stored somewhere in the lowest 48 bits */
|
||||
uint64_t instr;
|
||||
|
||||
/* Instruction normalized with bit_res for easier manipulation */
|
||||
uint64_t norm;
|
||||
|
||||
for (i = 0; i + 16 <= size; i += 16) {
|
||||
mask = branch_table[buf[i] & 0x1F];
|
||||
for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
|
||||
if (((mask >> slot) & 1) == 0)
|
||||
continue;
|
||||
|
||||
byte_pos = bit_pos >> 3;
|
||||
bit_res = bit_pos & 7;
|
||||
instr = 0;
|
||||
for (j = 0; j < 6; ++j)
|
||||
instr |= (uint64_t)(buf[i + j + byte_pos])
|
||||
<< (8 * j);
|
||||
|
||||
norm = instr >> bit_res;
|
||||
|
||||
if (((norm >> 37) & 0x0F) == 0x05
|
||||
&& ((norm >> 9) & 0x07) == 0) {
|
||||
addr = (norm >> 13) & 0x0FFFFF;
|
||||
addr |= ((uint32_t)(norm >> 36) & 1) << 20;
|
||||
addr <<= 4;
|
||||
addr -= s->pos + (uint32_t)i;
|
||||
addr >>= 4;
|
||||
|
||||
norm &= ~((uint64_t)0x8FFFFF << 13);
|
||||
norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
|
||||
norm |= (uint64_t)(addr & 0x100000)
|
||||
<< (36 - 20);
|
||||
|
||||
instr &= (1 << bit_res) - 1;
|
||||
instr |= norm << bit_res;
|
||||
|
||||
for (j = 0; j < 6; j++)
|
||||
buf[i + j + byte_pos]
|
||||
= (uint8_t)(instr >> (8 * j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_ARM
|
||||
static noinline_for_stack size_t bcj_arm(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t addr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4) {
|
||||
if (buf[i + 3] == 0xEB) {
|
||||
addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
|
||||
| ((uint32_t)buf[i + 2] << 16);
|
||||
addr <<= 2;
|
||||
addr -= s->pos + (uint32_t)i + 8;
|
||||
addr >>= 2;
|
||||
buf[i] = (uint8_t)addr;
|
||||
buf[i + 1] = (uint8_t)(addr >> 8);
|
||||
buf[i + 2] = (uint8_t)(addr >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
static noinline_for_stack size_t bcj_armthumb(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t addr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 2) {
|
||||
if ((buf[i + 1] & 0xF8) == 0xF0
|
||||
&& (buf[i + 3] & 0xF8) == 0xF8) {
|
||||
addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
|
||||
| ((uint32_t)buf[i] << 11)
|
||||
| (((uint32_t)buf[i + 3] & 0x07) << 8)
|
||||
| (uint32_t)buf[i + 2];
|
||||
addr <<= 1;
|
||||
addr -= s->pos + (uint32_t)i + 4;
|
||||
addr >>= 1;
|
||||
buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
|
||||
buf[i] = (uint8_t)(addr >> 11);
|
||||
buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
|
||||
buf[i + 2] = (uint8_t)addr;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_SPARC
|
||||
static noinline_for_stack size_t bcj_sparc(
|
||||
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t instr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4) {
|
||||
instr = get_unaligned_be32(buf + i);
|
||||
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
|
||||
instr <<= 2;
|
||||
instr -= s->pos + (uint32_t)i;
|
||||
instr >>= 2;
|
||||
instr = ((uint32_t)0x40000000 - (instr & 0x400000))
|
||||
| 0x40000000 | (instr & 0x3FFFFF);
|
||||
put_unaligned_be32(instr, buf + i);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Apply the selected BCJ filter. Update *pos and s->pos to match the amount
|
||||
* of data that got filtered.
|
||||
*
|
||||
* NOTE: This is implemented as a switch statement to avoid using function
|
||||
* pointers, which could be problematic in the kernel boot code, which must
|
||||
* avoid pointers to static data (at least on x86).
|
||||
*/
|
||||
static void bcj_apply(struct xz_dec_bcj *s,
|
||||
uint8_t *buf, size_t *pos, size_t size)
|
||||
{
|
||||
size_t filtered;
|
||||
|
||||
buf += *pos;
|
||||
size -= *pos;
|
||||
|
||||
switch (s->type) {
|
||||
#ifdef XZ_DEC_X86
|
||||
case BCJ_X86:
|
||||
filtered = bcj_x86(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
case BCJ_POWERPC:
|
||||
filtered = bcj_powerpc(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_IA64
|
||||
case BCJ_IA64:
|
||||
filtered = bcj_ia64(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARM
|
||||
case BCJ_ARM:
|
||||
filtered = bcj_arm(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
case BCJ_ARMTHUMB:
|
||||
filtered = bcj_armthumb(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_SPARC
|
||||
case BCJ_SPARC:
|
||||
filtered = bcj_sparc(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Never reached but silence compiler warnings. */
|
||||
filtered = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
*pos += filtered;
|
||||
s->pos += filtered;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush pending filtered data from temp to the output buffer.
|
||||
* Move the remaining mixture of possibly filtered and unfiltered
|
||||
* data to the beginning of temp.
|
||||
*/
|
||||
static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
|
||||
{
|
||||
size_t copy_size;
|
||||
|
||||
copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
|
||||
memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
|
||||
b->out_pos += copy_size;
|
||||
|
||||
s->temp.filtered -= copy_size;
|
||||
s->temp.size -= copy_size;
|
||||
memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
|
||||
}
|
||||
|
||||
/*
|
||||
* The BCJ filter functions are primitive in sense that they process the
|
||||
* data in chunks of 1-16 bytes. To hide this issue, this function does
|
||||
* some buffering.
|
||||
*/
|
||||
enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
|
||||
struct xz_dec_lzma2 *lzma2, struct xz_buf *b)
|
||||
{
|
||||
size_t out_start;
|
||||
|
||||
/*
|
||||
* Flush pending already filtered data to the output buffer. Return
|
||||
* immediatelly if we couldn't flush everything, or if the next
|
||||
* filter in the chain had already returned XZ_STREAM_END.
|
||||
*/
|
||||
if (s->temp.filtered > 0) {
|
||||
bcj_flush(s, b);
|
||||
if (s->temp.filtered > 0)
|
||||
return XZ_OK;
|
||||
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have more output space than what is currently pending in
|
||||
* temp, copy the unfiltered data from temp to the output buffer
|
||||
* and try to fill the output buffer by decoding more data from the
|
||||
* next filter in the chain. Apply the BCJ filter on the new data
|
||||
* in the output buffer. If everything cannot be filtered, copy it
|
||||
* to temp and rewind the output buffer position accordingly.
|
||||
*/
|
||||
if (s->temp.size < b->out_size - b->out_pos) {
|
||||
out_start = b->out_pos;
|
||||
memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
|
||||
b->out_pos += s->temp.size;
|
||||
|
||||
s->ret = xz_dec_lzma2_run(lzma2, b);
|
||||
if (s->ret != XZ_STREAM_END
|
||||
&& (s->ret != XZ_OK || s->single_call))
|
||||
return s->ret;
|
||||
|
||||
bcj_apply(s, b->out, &out_start, b->out_pos);
|
||||
|
||||
/*
|
||||
* As an exception, if the next filter returned XZ_STREAM_END,
|
||||
* we can do that too, since the last few bytes that remain
|
||||
* unfiltered are meant to remain unfiltered.
|
||||
*/
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
return XZ_STREAM_END;
|
||||
|
||||
s->temp.size = b->out_pos - out_start;
|
||||
b->out_pos -= s->temp.size;
|
||||
memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have unfiltered data in temp, try to fill by decoding more
|
||||
* data from the next filter. Apply the BCJ filter on temp. Then we
|
||||
* hopefully can fill the actual output buffer by copying filtered
|
||||
* data from temp. A mix of filtered and unfiltered data may be left
|
||||
* in temp; it will be taken care on the next call to this function.
|
||||
*/
|
||||
if (s->temp.size > 0) {
|
||||
/* Make b->out{,_pos,_size} temporarily point to s->temp. */
|
||||
s->out = b->out;
|
||||
s->out_pos = b->out_pos;
|
||||
s->out_size = b->out_size;
|
||||
b->out = s->temp.buf;
|
||||
b->out_pos = s->temp.size;
|
||||
b->out_size = sizeof(s->temp.buf);
|
||||
|
||||
s->ret = xz_dec_lzma2_run(lzma2, b);
|
||||
|
||||
s->temp.size = b->out_pos;
|
||||
b->out = s->out;
|
||||
b->out_pos = s->out_pos;
|
||||
b->out_size = s->out_size;
|
||||
|
||||
if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
|
||||
return s->ret;
|
||||
|
||||
bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
|
||||
|
||||
/*
|
||||
* If the next filter returned XZ_STREAM_END, we mark that
|
||||
* everything is filtered, since the last unfiltered bytes
|
||||
* of the stream are meant to be left as is.
|
||||
*/
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
s->temp.filtered = s->temp.size;
|
||||
|
||||
bcj_flush(s, b);
|
||||
if (s->temp.filtered > 0)
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
return s->ret;
|
||||
}
|
||||
|
||||
struct xz_dec_bcj * xz_dec_bcj_create(bool single_call)
|
||||
{
|
||||
struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (s != NULL)
|
||||
s->single_call = single_call;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
enum xz_ret xz_dec_bcj_reset(
|
||||
struct xz_dec_bcj *s, uint8_t id)
|
||||
{
|
||||
switch (id) {
|
||||
#ifdef XZ_DEC_X86
|
||||
case BCJ_X86:
|
||||
#endif
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
case BCJ_POWERPC:
|
||||
#endif
|
||||
#ifdef XZ_DEC_IA64
|
||||
case BCJ_IA64:
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARM
|
||||
case BCJ_ARM:
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
case BCJ_ARMTHUMB:
|
||||
#endif
|
||||
#ifdef XZ_DEC_SPARC
|
||||
case BCJ_SPARC:
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Unsupported Filter ID */
|
||||
return XZ_OPTIONS_ERROR;
|
||||
}
|
||||
|
||||
s->type = id;
|
||||
s->ret = XZ_OK;
|
||||
s->pos = 0;
|
||||
s->x86_prev_mask = 0;
|
||||
s->temp.filtered = 0;
|
||||
s->temp.size = 0;
|
||||
|
||||
return XZ_OK;
|
||||
}
|
1168
grub-core/lib/xzembed/xz_dec_lzma2.c
Normal file
1168
grub-core/lib/xzembed/xz_dec_lzma2.c
Normal file
File diff suppressed because it is too large
Load diff
854
grub-core/lib/xzembed/xz_dec_stream.c
Normal file
854
grub-core/lib/xzembed/xz_dec_stream.c
Normal file
|
@ -0,0 +1,854 @@
|
|||
/* xz_dec_stream.c - .xz Stream decoder */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* This file is based on code from XZ embedded project
|
||||
* http://tukaani.org/xz/embedded.html
|
||||
*/
|
||||
|
||||
#include "xz_config.h"
|
||||
#include "xz_private.h"
|
||||
#include "xz_stream.h"
|
||||
|
||||
#include <grub/crypto.h>
|
||||
|
||||
/* Hash used to validate the Index field */
|
||||
struct xz_dec_hash {
|
||||
vli_type unpadded;
|
||||
vli_type uncompressed;
|
||||
uint8_t *crc32_context;
|
||||
};
|
||||
|
||||
struct xz_dec {
|
||||
/* Position in dec_main() */
|
||||
enum {
|
||||
SEQ_STREAM_HEADER,
|
||||
SEQ_BLOCK_START,
|
||||
SEQ_BLOCK_HEADER,
|
||||
SEQ_BLOCK_UNCOMPRESS,
|
||||
SEQ_BLOCK_PADDING,
|
||||
SEQ_BLOCK_CHECK,
|
||||
SEQ_INDEX,
|
||||
SEQ_INDEX_PADDING,
|
||||
SEQ_INDEX_CRC32,
|
||||
SEQ_STREAM_FOOTER
|
||||
} sequence;
|
||||
|
||||
/* Position in variable-length integers and Check fields */
|
||||
uint32_t pos;
|
||||
|
||||
/* Variable-length integer decoded by dec_vli() */
|
||||
vli_type vli;
|
||||
|
||||
/* Saved in_pos and out_pos */
|
||||
size_t in_start;
|
||||
size_t out_start;
|
||||
|
||||
/* CRC32 value in Block or Index */
|
||||
uint32_t crc32_temp; /* need for crc32_validate*/
|
||||
uint8_t *crc32_context;
|
||||
|
||||
/* True if CRC32 is calculated from uncompressed data */
|
||||
bool has_crc32;
|
||||
|
||||
/* True if we are operating in single-call mode. */
|
||||
bool single_call;
|
||||
|
||||
/*
|
||||
* True if the next call to xz_dec_run() is allowed to return
|
||||
* XZ_BUF_ERROR.
|
||||
*/
|
||||
bool allow_buf_error;
|
||||
|
||||
/* Information stored in Block Header */
|
||||
struct {
|
||||
/*
|
||||
* Value stored in the Compressed Size field, or
|
||||
* VLI_UNKNOWN if Compressed Size is not present.
|
||||
*/
|
||||
vli_type compressed;
|
||||
|
||||
/*
|
||||
* Value stored in the Uncompressed Size field, or
|
||||
* VLI_UNKNOWN if Uncompressed Size is not present.
|
||||
*/
|
||||
vli_type uncompressed;
|
||||
|
||||
/* Size of the Block Header field */
|
||||
uint32_t size;
|
||||
} block_header;
|
||||
|
||||
/* Information collected when decoding Blocks */
|
||||
struct {
|
||||
/* Observed compressed size of the current Block */
|
||||
vli_type compressed;
|
||||
|
||||
/* Observed uncompressed size of the current Block */
|
||||
vli_type uncompressed;
|
||||
|
||||
/* Number of Blocks decoded so far */
|
||||
vli_type count;
|
||||
|
||||
/*
|
||||
* Hash calculated from the Block sizes. This is used to
|
||||
* validate the Index field.
|
||||
*/
|
||||
struct xz_dec_hash hash;
|
||||
} block;
|
||||
|
||||
/* Variables needed when verifying the Index field */
|
||||
struct {
|
||||
/* Position in dec_index() */
|
||||
enum {
|
||||
SEQ_INDEX_COUNT,
|
||||
SEQ_INDEX_UNPADDED,
|
||||
SEQ_INDEX_UNCOMPRESSED
|
||||
} sequence;
|
||||
|
||||
/* Size of the Index in bytes */
|
||||
vli_type size;
|
||||
|
||||
/* Number of Records (matches block.count in valid files) */
|
||||
vli_type count;
|
||||
|
||||
/*
|
||||
* Hash calculated from the Records (matches block.hash in
|
||||
* valid files).
|
||||
*/
|
||||
struct xz_dec_hash hash;
|
||||
} index;
|
||||
|
||||
/*
|
||||
* Temporary buffer needed to hold Stream Header, Block Header,
|
||||
* and Stream Footer. The Block Header is the biggest (1 KiB)
|
||||
* so we reserve space according to that. buf[] has to be aligned
|
||||
* to a multiple of four bytes; the size_t variables before it
|
||||
* should guarantee this.
|
||||
*/
|
||||
struct {
|
||||
size_t pos;
|
||||
size_t size;
|
||||
uint8_t buf[1024];
|
||||
} temp;
|
||||
|
||||
struct xz_dec_lzma2 *lzma2;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
struct xz_dec_bcj *bcj;
|
||||
bool bcj_active;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
|
||||
* must have set s->temp.pos to indicate how much data we are supposed
|
||||
* to copy into s->temp.buf. Return true once s->temp.pos has reached
|
||||
* s->temp.size.
|
||||
*/
|
||||
static bool fill_temp(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
size_t copy_size = min_t(size_t,
|
||||
b->in_size - b->in_pos, s->temp.size - s->temp.pos);
|
||||
|
||||
memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
|
||||
b->in_pos += copy_size;
|
||||
s->temp.pos += copy_size;
|
||||
|
||||
if (s->temp.pos == s->temp.size) {
|
||||
s->temp.pos = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Decode a variable-length integer (little-endian base-128 encoding) */
|
||||
static enum xz_ret dec_vli(struct xz_dec *s,
|
||||
const uint8_t *in, size_t *in_pos, size_t in_size)
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
if (s->pos == 0)
|
||||
s->vli = 0;
|
||||
|
||||
while (*in_pos < in_size) {
|
||||
byte = in[*in_pos];
|
||||
++*in_pos;
|
||||
|
||||
s->vli |= (vli_type)(byte & 0x7F) << s->pos;
|
||||
|
||||
if ((byte & 0x80) == 0) {
|
||||
/* Don't allow non-minimal encodings. */
|
||||
if (byte == 0 && s->pos != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->pos = 0;
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
s->pos += 7;
|
||||
if (s->pos == 7 * VLI_BYTES_MAX)
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the Compressed Data field from a Block. Update and validate
|
||||
* the observed compressed and uncompressed sizes of the Block so that
|
||||
* they don't exceed the values possibly stored in the Block Header
|
||||
* (validation assumes that no integer overflow occurs, since vli_type
|
||||
* is normally uint64_t). Update the CRC32 if presence of the CRC32
|
||||
* field was indicated in Stream Header.
|
||||
*
|
||||
* Once the decoding is finished, validate that the observed sizes match
|
||||
* the sizes possibly stored in the Block Header. Update the hash and
|
||||
* Block count, which are later used to validate the Index field.
|
||||
*/
|
||||
static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
s->in_start = b->in_pos;
|
||||
s->out_start = b->out_pos;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
if (s->bcj_active)
|
||||
ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
|
||||
else
|
||||
#endif
|
||||
ret = xz_dec_lzma2_run(s->lzma2, b);
|
||||
|
||||
s->block.compressed += b->in_pos - s->in_start;
|
||||
s->block.uncompressed += b->out_pos - s->out_start;
|
||||
|
||||
/*
|
||||
* There is no need to separately check for VLI_UNKNOWN, since
|
||||
* the observed sizes are always smaller than VLI_UNKNOWN.
|
||||
*/
|
||||
if (s->block.compressed > s->block_header.compressed
|
||||
|| s->block.uncompressed
|
||||
> s->block_header.uncompressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->has_crc32)
|
||||
GRUB_MD_CRC32->write(s->crc32_context,b->out + s->out_start,
|
||||
b->out_pos - s->out_start);
|
||||
|
||||
if (ret == XZ_STREAM_END) {
|
||||
if (s->block_header.compressed != VLI_UNKNOWN
|
||||
&& s->block_header.compressed
|
||||
!= s->block.compressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->block_header.uncompressed != VLI_UNKNOWN
|
||||
&& s->block_header.uncompressed
|
||||
!= s->block.uncompressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block.hash.unpadded += s->block_header.size
|
||||
+ s->block.compressed;
|
||||
if (s->has_crc32)
|
||||
s->block.hash.unpadded += 4;
|
||||
|
||||
s->block.hash.uncompressed += s->block.uncompressed;
|
||||
|
||||
GRUB_MD_CRC32->write(s->block.hash.crc32_context,
|
||||
(const uint8_t *)&s->block.hash, sizeof(s->block.hash));
|
||||
|
||||
++s->block.count;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Update the Index size and the CRC32 value. */
|
||||
static void index_update(struct xz_dec *s, const struct xz_buf *b)
|
||||
{
|
||||
size_t in_used = b->in_pos - s->in_start;
|
||||
s->index.size += in_used;
|
||||
GRUB_MD_CRC32->write(s->crc32_context,b->in + s->in_start, in_used);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the Number of Records, Unpadded Size, and Uncompressed Size
|
||||
* fields from the Index field. That is, Index Padding and CRC32 are not
|
||||
* decoded by this function.
|
||||
*
|
||||
* This can return XZ_OK (more input needed), XZ_STREAM_END (everything
|
||||
* successfully decoded), or XZ_DATA_ERROR (input is corrupt).
|
||||
*/
|
||||
static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
do {
|
||||
ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
|
||||
if (ret != XZ_STREAM_END) {
|
||||
index_update(s, b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (s->index.sequence) {
|
||||
case SEQ_INDEX_COUNT:
|
||||
s->index.count = s->vli;
|
||||
|
||||
/*
|
||||
* Validate that the Number of Records field
|
||||
* indicates the same number of Records as
|
||||
* there were Blocks in the Stream.
|
||||
*/
|
||||
if (s->index.count != s->block.count)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->index.sequence = SEQ_INDEX_UNPADDED;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX_UNPADDED:
|
||||
s->index.hash.unpadded += s->vli;
|
||||
s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX_UNCOMPRESSED:
|
||||
s->index.hash.uncompressed += s->vli;
|
||||
|
||||
GRUB_MD_CRC32->write(s->index.hash.crc32_context,
|
||||
(const uint8_t *)&s->index.hash,
|
||||
sizeof(s->index.hash));
|
||||
|
||||
--s->index.count;
|
||||
s->index.sequence = SEQ_INDEX_UNPADDED;
|
||||
break;
|
||||
}
|
||||
} while (s->index.count > 0);
|
||||
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the next four input bytes match the value of s->crc32.
|
||||
* s->pos must be zero when starting to validate the first byte.
|
||||
*/
|
||||
static enum xz_ret crc32_validate(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
if(s->crc32_temp == 0)
|
||||
{
|
||||
GRUB_MD_CRC32->final(s->crc32_context);
|
||||
s->crc32_temp = get_unaligned_be32(GRUB_MD_CRC32->read(s->crc32_context));
|
||||
}
|
||||
|
||||
do {
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
if (((s->crc32_temp >> s->pos) & 0xFF) != b->in[b->in_pos++])
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->pos += 8;
|
||||
|
||||
} while (s->pos < 32);
|
||||
|
||||
GRUB_MD_CRC32->init(s->crc32_context);
|
||||
s->crc32_temp = 0;
|
||||
s->pos = 0;
|
||||
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
|
||||
static enum xz_ret dec_stream_header(struct xz_dec *s)
|
||||
{
|
||||
if (! memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
|
||||
return XZ_FORMAT_ERROR;
|
||||
|
||||
uint8_t crc32_context[GRUB_MD_CRC32->contextsize];
|
||||
|
||||
GRUB_MD_CRC32->init(crc32_context);
|
||||
GRUB_MD_CRC32->write(crc32_context,s->temp.buf + HEADER_MAGIC_SIZE, 2);
|
||||
GRUB_MD_CRC32->final(crc32_context);
|
||||
|
||||
uint32_t resultcrc = get_unaligned_be32(GRUB_MD_CRC32->read(crc32_context));
|
||||
uint32_t readcrc = get_unaligned_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2);
|
||||
|
||||
if(resultcrc != readcrc)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/*
|
||||
* Decode the Stream Flags field. Of integrity checks, we support
|
||||
* only none (Check ID = 0) and CRC32 (Check ID = 1).
|
||||
*/
|
||||
if (s->temp.buf[HEADER_MAGIC_SIZE] != 0
|
||||
|| s->temp.buf[HEADER_MAGIC_SIZE + 1] > 1)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
s->has_crc32 = s->temp.buf[HEADER_MAGIC_SIZE + 1];
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
|
||||
static enum xz_ret dec_stream_footer(struct xz_dec *s)
|
||||
{
|
||||
if (! memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
uint8_t crc32_context[GRUB_MD_CRC32->contextsize];
|
||||
|
||||
GRUB_MD_CRC32->init(crc32_context);
|
||||
GRUB_MD_CRC32->write(crc32_context, s->temp.buf + 4, 6);
|
||||
GRUB_MD_CRC32->final(crc32_context);
|
||||
|
||||
uint32_t resultcrc = get_unaligned_be32(GRUB_MD_CRC32->read(crc32_context));
|
||||
uint32_t readcrc = get_unaligned_le32(s->temp.buf);
|
||||
|
||||
if(resultcrc != readcrc)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/*
|
||||
* Validate Backward Size. Note that we never added the size of the
|
||||
* Index CRC32 field to s->index.size, thus we use s->index.size / 4
|
||||
* instead of s->index.size / 4 - 1.
|
||||
*/
|
||||
if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->has_crc32)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/*
|
||||
* Use XZ_STREAM_END instead of XZ_OK to be more convenient
|
||||
* for the caller.
|
||||
*/
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/* Decode the Block Header and initialize the filter chain. */
|
||||
static enum xz_ret dec_block_header(struct xz_dec *s)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
/*
|
||||
* Validate the CRC32. We know that the temp buffer is at least
|
||||
* eight bytes so this is safe.
|
||||
*/
|
||||
s->temp.size -= 4;
|
||||
|
||||
uint8_t crc32_context[GRUB_MD_CRC32->contextsize];
|
||||
|
||||
GRUB_MD_CRC32->init(crc32_context);
|
||||
GRUB_MD_CRC32->write(crc32_context, s->temp.buf, s->temp.size);
|
||||
GRUB_MD_CRC32->final(crc32_context);
|
||||
|
||||
uint32_t resultcrc = get_unaligned_be32(GRUB_MD_CRC32->read(crc32_context));
|
||||
uint32_t readcrc = get_unaligned_le32(s->temp.buf + s->temp.size);
|
||||
|
||||
if (resultcrc != readcrc)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->temp.pos = 2;
|
||||
|
||||
/*
|
||||
* Catch unsupported Block Flags. We support only one or two filters
|
||||
* in the chain, so we catch that with the same test.
|
||||
*/
|
||||
#ifdef XZ_DEC_BCJ
|
||||
if (s->temp.buf[1] & 0x3E)
|
||||
#else
|
||||
if (s->temp.buf[1] & 0x3F)
|
||||
#endif
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Compressed Size */
|
||||
if (s->temp.buf[1] & 0x40) {
|
||||
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
|
||||
!= XZ_STREAM_END)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block_header.compressed = s->vli;
|
||||
} else {
|
||||
s->block_header.compressed = VLI_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Uncompressed Size */
|
||||
if (s->temp.buf[1] & 0x80) {
|
||||
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
|
||||
!= XZ_STREAM_END)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->block_header.uncompressed = s->vli;
|
||||
} else {
|
||||
s->block_header.uncompressed = VLI_UNKNOWN;
|
||||
}
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
/* If there are two filters, the first one must be a BCJ filter. */
|
||||
s->bcj_active = s->temp.buf[1] & 0x01;
|
||||
if (s->bcj_active) {
|
||||
if (s->temp.size - s->temp.pos < 2)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We don't support custom start offset,
|
||||
* so Size of Properties must be zero.
|
||||
*/
|
||||
if (s->temp.buf[s->temp.pos++] != 0x00)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Valid Filter Flags always take at least two bytes. */
|
||||
if (s->temp.size - s->temp.pos < 2)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/* Filter ID = LZMA2 */
|
||||
if (s->temp.buf[s->temp.pos++] != 0x21)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Size of Properties = 1-byte Filter Properties */
|
||||
if (s->temp.buf[s->temp.pos++] != 0x01)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
/* Filter Properties contains LZMA2 dictionary size. */
|
||||
if (s->temp.size - s->temp.pos < 1)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
/* The rest must be Header Padding. */
|
||||
while (s->temp.pos < s->temp.size)
|
||||
if (s->temp.buf[s->temp.pos++] != 0x00)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
s->temp.pos = 0;
|
||||
s->block.compressed = 0;
|
||||
s->block.uncompressed = 0;
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
|
||||
/*
|
||||
* Store the start position for the case when we are in the middle
|
||||
* of the Index field.
|
||||
*/
|
||||
s->in_start = b->in_pos;
|
||||
|
||||
while (true) {
|
||||
switch (s->sequence) {
|
||||
case SEQ_STREAM_HEADER:
|
||||
/*
|
||||
* Stream Header is copied to s->temp, and then
|
||||
* decoded from there. This way if the caller
|
||||
* gives us only little input at a time, we can
|
||||
* still keep the Stream Header decoding code
|
||||
* simple. Similar approach is used in many places
|
||||
* in this file.
|
||||
*/
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
ret = dec_stream_header(s);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_BLOCK_START;
|
||||
|
||||
case SEQ_BLOCK_START:
|
||||
/* We need one byte of input to continue. */
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
/* See if this is the beginning of the Index field. */
|
||||
if (b->in[b->in_pos] == 0) {
|
||||
s->in_start = b->in_pos++;
|
||||
s->sequence = SEQ_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the size of the Block Header and
|
||||
* prepare to decode it.
|
||||
*/
|
||||
s->block_header.size
|
||||
= ((uint32_t)b->in[b->in_pos] + 1) * 4;
|
||||
|
||||
s->temp.size = s->block_header.size;
|
||||
s->temp.pos = 0;
|
||||
s->sequence = SEQ_BLOCK_HEADER;
|
||||
|
||||
case SEQ_BLOCK_HEADER:
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
ret = dec_block_header(s);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_BLOCK_UNCOMPRESS;
|
||||
|
||||
case SEQ_BLOCK_UNCOMPRESS:
|
||||
ret = dec_block(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_BLOCK_PADDING;
|
||||
|
||||
case SEQ_BLOCK_PADDING:
|
||||
/*
|
||||
* Size of Compressed Data + Block Padding
|
||||
* must be a multiple of four. We don't need
|
||||
* s->block.compressed for anything else
|
||||
* anymore, so we use it here to test the size
|
||||
* of the Block Padding field.
|
||||
*/
|
||||
while (s->block.compressed & 3) {
|
||||
if (b->in_pos == b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
if (b->in[b->in_pos++] != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
++s->block.compressed;
|
||||
}
|
||||
|
||||
s->sequence = SEQ_BLOCK_CHECK;
|
||||
|
||||
case SEQ_BLOCK_CHECK:
|
||||
if (s->has_crc32) {
|
||||
ret = crc32_validate(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
}
|
||||
|
||||
s->sequence = SEQ_BLOCK_START;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX:
|
||||
ret = dec_index(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_INDEX_PADDING;
|
||||
|
||||
case SEQ_INDEX_PADDING:
|
||||
while ((s->index.size + (b->in_pos - s->in_start))
|
||||
& 3) {
|
||||
if (b->in_pos == b->in_size) {
|
||||
index_update(s, b);
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
if (b->in[b->in_pos++] != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* Finish the CRC32 value and Index size. */
|
||||
index_update(s, b);
|
||||
|
||||
/* Compare the hashes to validate the Index field. */
|
||||
if (! memeq(&s->block.hash, &s->index.hash, sizeof(s->block.hash)))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->sequence = SEQ_INDEX_CRC32;
|
||||
|
||||
case SEQ_INDEX_CRC32:
|
||||
ret = crc32_validate(s, b);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->temp.size = STREAM_HEADER_SIZE;
|
||||
s->sequence = SEQ_STREAM_FOOTER;
|
||||
|
||||
case SEQ_STREAM_FOOTER:
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
return dec_stream_footer(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reached */
|
||||
}
|
||||
|
||||
/*
|
||||
* xz_dec_run() is a wrapper for dec_main() to handle some special cases in
|
||||
* multi-call and single-call decoding.
|
||||
*
|
||||
* In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
|
||||
* are not going to make any progress anymore. This is to prevent the caller
|
||||
* from calling us infinitely when the input file is truncated or otherwise
|
||||
* corrupt. Since zlib-style API allows that the caller fills the input buffer
|
||||
* only when the decoder doesn't produce any new output, we have to be careful
|
||||
* to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
|
||||
* after the second consecutive call to xz_dec_run() that makes no progress.
|
||||
*
|
||||
* In single-call mode, if we couldn't decode everything and no error
|
||||
* occurred, either the input is truncated or the output buffer is too small.
|
||||
* Since we know that the last input byte never produces any output, we know
|
||||
* that if all the input was consumed and decoding wasn't finished, the file
|
||||
* must be corrupt. Otherwise the output buffer has to be too small or the
|
||||
* file is corrupt in a way that decoding it produces too big output.
|
||||
*
|
||||
* If single-call decoding fails, we reset b->in_pos and b->out_pos back to
|
||||
* their original values. This is because with some filter chains there won't
|
||||
* be any valid uncompressed data in the output buffer unless the decoding
|
||||
* actually succeeds (that's the price to pay of using the output buffer as
|
||||
* the workspace).
|
||||
*/
|
||||
enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
size_t in_start;
|
||||
size_t out_start;
|
||||
enum xz_ret ret;
|
||||
|
||||
if (s->single_call)
|
||||
xz_dec_reset(s);
|
||||
|
||||
in_start = b->in_pos;
|
||||
out_start = b->out_pos;
|
||||
ret = dec_main(s, b);
|
||||
|
||||
if (s->single_call) {
|
||||
if (ret == XZ_OK)
|
||||
ret = b->in_pos == b->in_size
|
||||
? XZ_DATA_ERROR : XZ_BUF_ERROR;
|
||||
|
||||
if (ret != XZ_STREAM_END) {
|
||||
b->in_pos = in_start;
|
||||
b->out_pos = out_start;
|
||||
}
|
||||
|
||||
} else if (ret == XZ_OK && in_start == b->in_pos
|
||||
&& out_start == b->out_pos) {
|
||||
if (s->allow_buf_error)
|
||||
ret = XZ_BUF_ERROR;
|
||||
|
||||
s->allow_buf_error = true;
|
||||
} else {
|
||||
s->allow_buf_error = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct xz_dec * xz_dec_init(uint32_t dict_max)
|
||||
{
|
||||
struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
/* prepare CRC32 calculators */
|
||||
if(GRUB_MD_CRC32 == NULL)
|
||||
{
|
||||
kfree(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->crc32_context = kmalloc(GRUB_MD_CRC32->contextsize, GFP_KERNEL);
|
||||
if (s->crc32_context == NULL)
|
||||
{
|
||||
kfree(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->index.hash.crc32_context = kmalloc(GRUB_MD_CRC32->contextsize, GFP_KERNEL);
|
||||
if (s->index.hash.crc32_context == NULL)
|
||||
{
|
||||
kfree(s->crc32_context);
|
||||
kfree(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->block.hash.crc32_context = kmalloc(GRUB_MD_CRC32->contextsize, GFP_KERNEL);
|
||||
if (s->block.hash.crc32_context == NULL)
|
||||
{
|
||||
kfree(s->index.hash.crc32_context);
|
||||
kfree(s->crc32_context);
|
||||
kfree(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
GRUB_MD_CRC32->init(s->crc32_context);
|
||||
s->crc32_temp = 0;
|
||||
GRUB_MD_CRC32->init(s->index.hash.crc32_context);
|
||||
GRUB_MD_CRC32->init(s->block.hash.crc32_context);
|
||||
|
||||
|
||||
s->single_call = dict_max == 0;
|
||||
|
||||
#ifdef XZ_DEC_BCJ
|
||||
s->bcj = xz_dec_bcj_create(s->single_call);
|
||||
if (s->bcj == NULL)
|
||||
goto error_bcj;
|
||||
#endif
|
||||
|
||||
s->lzma2 = xz_dec_lzma2_create(dict_max);
|
||||
if (s->lzma2 == NULL)
|
||||
goto error_lzma2;
|
||||
|
||||
xz_dec_reset(s);
|
||||
return s;
|
||||
|
||||
error_lzma2:
|
||||
#ifdef XZ_DEC_BCJ
|
||||
xz_dec_bcj_end(s->bcj);
|
||||
error_bcj:
|
||||
#endif
|
||||
kfree(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xz_dec_reset(struct xz_dec *s)
|
||||
{
|
||||
s->sequence = SEQ_STREAM_HEADER;
|
||||
s->allow_buf_error = false;
|
||||
s->pos = 0;
|
||||
|
||||
memzero(&s->block, sizeof(s->block));
|
||||
memzero(&s->index, sizeof(s->index));
|
||||
s->temp.pos = 0;
|
||||
s->temp.size = STREAM_HEADER_SIZE;
|
||||
|
||||
GRUB_MD_CRC32->init(s->crc32_context);
|
||||
s->crc32_temp = 0;
|
||||
GRUB_MD_CRC32->init(s->index.hash.crc32_context);
|
||||
GRUB_MD_CRC32->init(s->block.hash.crc32_context);
|
||||
|
||||
}
|
||||
|
||||
void xz_dec_end(struct xz_dec *s)
|
||||
{
|
||||
if (s != NULL) {
|
||||
xz_dec_lzma2_end(s->lzma2);
|
||||
#ifdef XZ_DEC_BCJ
|
||||
xz_dec_bcj_end(s->bcj);
|
||||
#endif
|
||||
kfree(s);
|
||||
}
|
||||
}
|
236
grub-core/lib/xzembed/xz_lzma2.h
Normal file
236
grub-core/lib/xzembed/xz_lzma2.h
Normal file
|
@ -0,0 +1,236 @@
|
|||
/* xz_lzma2.h - LZMA2 definitions */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* This file is based on code from XZ embedded project
|
||||
* http://tukaani.org/xz/embedded.html
|
||||
*/
|
||||
|
||||
#ifndef XZ_LZMA2_H
|
||||
#define XZ_LZMA2_H
|
||||
|
||||
/* dictionary size hard limit
|
||||
* actual size limit is calculated as shown in 5.3.1
|
||||
* http://tukaani.org/xz/xz-file-format.txt
|
||||
*
|
||||
* if bits > 39 dictionary_size = UINT32_MAX
|
||||
* else
|
||||
* dictionary_size = 2 | (bits & 1);
|
||||
* dictionary_size <<= bits / 2 + 11;
|
||||
*
|
||||
* i.e.
|
||||
* 0 - 4 KiB
|
||||
* 6 - 32 KiB
|
||||
* 30 - 128MiB
|
||||
* 39 - 3072 MiB
|
||||
* 40 - 4096 MiB - 1 B
|
||||
* note: implementation supports 39 at maximum
|
||||
*/
|
||||
#define DICT_BIT_SIZE 30
|
||||
|
||||
/* Range coder constants */
|
||||
#define RC_SHIFT_BITS 8
|
||||
#define RC_TOP_BITS 24
|
||||
#define RC_TOP_VALUE (1 << RC_TOP_BITS)
|
||||
#define RC_BIT_MODEL_TOTAL_BITS 11
|
||||
#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS)
|
||||
#define RC_MOVE_BITS 5
|
||||
|
||||
/*
|
||||
* Maximum number of position states. A position state is the lowest pb
|
||||
* number of bits of the current uncompressed offset. In some places there
|
||||
* are different sets of probabilities for different position states.
|
||||
*/
|
||||
#define POS_STATES_MAX (1 << 4)
|
||||
|
||||
/*
|
||||
* This enum is used to track which LZMA symbols have occurred most recently
|
||||
* and in which order. This information is used to predict the next symbol.
|
||||
*
|
||||
* Symbols:
|
||||
* - Literal: One 8-bit byte
|
||||
* - Match: Repeat a chunk of data at some distance
|
||||
* - Long repeat: Multi-byte match at a recently seen distance
|
||||
* - Short repeat: One-byte repeat at a recently seen distance
|
||||
*
|
||||
* The symbol names are in from STATE_oldest_older_previous. REP means
|
||||
* either short or long repeated match, and NONLIT means any non-literal.
|
||||
*/
|
||||
enum lzma_state {
|
||||
STATE_LIT_LIT,
|
||||
STATE_MATCH_LIT_LIT,
|
||||
STATE_REP_LIT_LIT,
|
||||
STATE_SHORTREP_LIT_LIT,
|
||||
STATE_MATCH_LIT,
|
||||
STATE_REP_LIT,
|
||||
STATE_SHORTREP_LIT,
|
||||
STATE_LIT_MATCH,
|
||||
STATE_LIT_LONGREP,
|
||||
STATE_LIT_SHORTREP,
|
||||
STATE_NONLIT_MATCH,
|
||||
STATE_NONLIT_REP
|
||||
};
|
||||
|
||||
/* Total number of states */
|
||||
#define STATES 12
|
||||
|
||||
/* The lowest 7 states indicate that the previous state was a literal. */
|
||||
#define LIT_STATES 7
|
||||
|
||||
/* Indicate that the latest symbol was a literal. */
|
||||
static inline void lzma_state_literal(enum lzma_state *state)
|
||||
{
|
||||
if (*state <= STATE_SHORTREP_LIT_LIT)
|
||||
*state = STATE_LIT_LIT;
|
||||
else if (*state <= STATE_LIT_SHORTREP)
|
||||
*state -= 3;
|
||||
else
|
||||
*state -= 6;
|
||||
}
|
||||
|
||||
/* Indicate that the latest symbol was a match. */
|
||||
static inline void lzma_state_match(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
|
||||
}
|
||||
|
||||
/* Indicate that the latest state was a long repeated match. */
|
||||
static inline void lzma_state_long_rep(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
|
||||
}
|
||||
|
||||
/* Indicate that the latest symbol was a short match. */
|
||||
static inline void lzma_state_short_rep(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
|
||||
}
|
||||
|
||||
/* Test if the previous symbol was a literal. */
|
||||
static inline bool lzma_state_is_literal(enum lzma_state state)
|
||||
{
|
||||
return state < LIT_STATES;
|
||||
}
|
||||
|
||||
/* Each literal coder is divided in three sections:
|
||||
* - 0x001-0x0FF: Without match byte
|
||||
* - 0x101-0x1FF: With match byte; match bit is 0
|
||||
* - 0x201-0x2FF: With match byte; match bit is 1
|
||||
*
|
||||
* Match byte is used when the previous LZMA symbol was something else than
|
||||
* a literal (that is, it was some kind of match).
|
||||
*/
|
||||
#define LITERAL_CODER_SIZE 0x300
|
||||
|
||||
/* Maximum number of literal coders */
|
||||
#define LITERAL_CODERS_MAX (1 << 4)
|
||||
|
||||
/* Minimum length of a match is two bytes. */
|
||||
#define MATCH_LEN_MIN 2
|
||||
|
||||
/* Match length is encoded with 4, 5, or 10 bits.
|
||||
*
|
||||
* Length Bits
|
||||
* 2-9 4 = Choice=0 + 3 bits
|
||||
* 10-17 5 = Choice=1 + Choice2=0 + 3 bits
|
||||
* 18-273 10 = Choice=1 + Choice2=1 + 8 bits
|
||||
*/
|
||||
#define LEN_LOW_BITS 3
|
||||
#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
|
||||
#define LEN_MID_BITS 3
|
||||
#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
|
||||
#define LEN_HIGH_BITS 8
|
||||
#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
|
||||
#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
|
||||
|
||||
/*
|
||||
* Maximum length of a match is 273 which is a result of the encoding
|
||||
* described above.
|
||||
*/
|
||||
#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
|
||||
|
||||
/*
|
||||
* Different sets of probabilities are used for match distances that have
|
||||
* very short match length: Lengths of 2, 3, and 4 bytes have a separate
|
||||
* set of probabilities for each length. The matches with longer length
|
||||
* use a shared set of probabilities.
|
||||
*/
|
||||
#define DIST_STATES 4
|
||||
|
||||
/*
|
||||
* Get the index of the appropriate probability array for decoding
|
||||
* the distance slot.
|
||||
*/
|
||||
static inline uint32_t lzma_get_dist_state(uint32_t len)
|
||||
{
|
||||
return len < DIST_STATES + MATCH_LEN_MIN
|
||||
? len - MATCH_LEN_MIN : DIST_STATES - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The highest two bits of a 32-bit match distance are encoded using six bits.
|
||||
* This six-bit value is called a distance slot. This way encoding a 32-bit
|
||||
* value takes 6-36 bits, larger values taking more bits.
|
||||
*/
|
||||
#define DIST_SLOT_BITS 6
|
||||
#define DIST_SLOTS (1 << DIST_SLOT_BITS)
|
||||
|
||||
/* Match distances up to 127 are fully encoded using probabilities. Since
|
||||
* the highest two bits (distance slot) are always encoded using six bits,
|
||||
* the distances 0-3 don't need any additional bits to encode, since the
|
||||
* distance slot itself is the same as the actual distance. DIST_MODEL_START
|
||||
* indicates the first distance slot where at least one additional bit is
|
||||
* needed.
|
||||
*/
|
||||
#define DIST_MODEL_START 4
|
||||
|
||||
/*
|
||||
* Match distances greater than 127 are encoded in three pieces:
|
||||
* - distance slot: the highest two bits
|
||||
* - direct bits: 2-26 bits below the highest two bits
|
||||
* - alignment bits: four lowest bits
|
||||
*
|
||||
* Direct bits don't use any probabilities.
|
||||
*
|
||||
* The distance slot value of 14 is for distances 128-191.
|
||||
*/
|
||||
#define DIST_MODEL_END 14
|
||||
|
||||
/* Distance slots that indicate a distance <= 127. */
|
||||
#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
|
||||
#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
|
||||
|
||||
/*
|
||||
* For match distances greater than 127, only the highest two bits and the
|
||||
* lowest four bits (alignment) is encoded using probabilities.
|
||||
*/
|
||||
#define ALIGN_BITS 4
|
||||
#define ALIGN_SIZE (1 << ALIGN_BITS)
|
||||
#define ALIGN_MASK (ALIGN_SIZE - 1)
|
||||
|
||||
/* Total number of all probability variables */
|
||||
#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE)
|
||||
|
||||
/*
|
||||
* LZMA remembers the four most recent match distances. Reusing these
|
||||
* distances tends to take less space than re-encoding the actual
|
||||
* distance value.
|
||||
*/
|
||||
#define REPS 4
|
||||
|
||||
#endif
|
96
grub-core/lib/xzembed/xz_private.h
Normal file
96
grub-core/lib/xzembed/xz_private.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/* xz_private.h - Private includes and definitions */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* This file is based on code from XZ embedded project
|
||||
* http://tukaani.org/xz/embedded.html
|
||||
*/
|
||||
|
||||
#ifndef XZ_PRIVATE_H
|
||||
#define XZ_PRIVATE_H
|
||||
|
||||
/*
|
||||
* For userspace builds, use a separate header to define the required
|
||||
* macros and functions. This makes it easier to adapt the code into
|
||||
* different environments and avoids clutter in the Linux kernel tree.
|
||||
*/
|
||||
#include "xz_config.h"
|
||||
|
||||
/*
|
||||
* If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ.
|
||||
* XZ_DEC_BCJ is used to enable generic support for BCJ decoders.
|
||||
*/
|
||||
#ifndef XZ_DEC_BCJ
|
||||
# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
|
||||
|| defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
|
||||
|| defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
|
||||
|| defined(XZ_DEC_SPARC)
|
||||
# define XZ_DEC_BCJ
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used
|
||||
* before calling xz_dec_lzma2_run().
|
||||
*/
|
||||
struct xz_dec_lzma2 * xz_dec_lzma2_create(
|
||||
uint32_t dict_max);
|
||||
|
||||
/*
|
||||
* Decode the LZMA2 properties (one byte) and reset the decoder. Return
|
||||
* XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not
|
||||
* big enough, and XZ_OPTIONS_ERROR if props indicates something that this
|
||||
* decoder doesn't support.
|
||||
*/
|
||||
enum xz_ret xz_dec_lzma2_reset(
|
||||
struct xz_dec_lzma2 *s, uint8_t props);
|
||||
|
||||
/* Decode raw LZMA2 stream from b->in to b->out. */
|
||||
enum xz_ret xz_dec_lzma2_run(
|
||||
struct xz_dec_lzma2 *s, struct xz_buf *b);
|
||||
|
||||
/* Free the memory allocated for the LZMA2 decoder. */
|
||||
void xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
|
||||
|
||||
/*
|
||||
* Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before
|
||||
* calling xz_dec_bcj_run().
|
||||
*/
|
||||
struct xz_dec_bcj * xz_dec_bcj_create(bool single_call);
|
||||
|
||||
/*
|
||||
* Decode the Filter ID of a BCJ filter. This implementation doesn't
|
||||
* support custom start offsets, so no decoding of Filter Properties
|
||||
* is needed. Returns XZ_OK if the given Filter ID is supported.
|
||||
* Otherwise XZ_OPTIONS_ERROR is returned.
|
||||
*/
|
||||
enum xz_ret xz_dec_bcj_reset(
|
||||
struct xz_dec_bcj *s, uint8_t id);
|
||||
|
||||
/*
|
||||
* Decode raw BCJ + LZMA2 stream. This must be used only if there actually is
|
||||
* a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run()
|
||||
* must be called directly.
|
||||
*/
|
||||
enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
|
||||
struct xz_dec_lzma2 *lzma2, struct xz_buf *b);
|
||||
|
||||
/* Free the memory allocated for the BCJ filters. */
|
||||
#define xz_dec_bcj_end(s) kfree(s)
|
||||
|
||||
#endif
|
53
grub-core/lib/xzembed/xz_stream.h
Normal file
53
grub-core/lib/xzembed/xz_stream.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* xz_stream.h - Definitions for handling the .xz file format */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* This file is based on code from XZ embedded project
|
||||
* http://tukaani.org/xz/embedded.html
|
||||
*/
|
||||
|
||||
#ifndef XZ_STREAM_H
|
||||
#define XZ_STREAM_H
|
||||
|
||||
/*
|
||||
* See the .xz file format specification at
|
||||
* http://tukaani.org/xz/xz-file-format.txt
|
||||
* to understand the container format.
|
||||
*/
|
||||
|
||||
#define STREAM_HEADER_SIZE 12
|
||||
|
||||
#define HEADER_MAGIC "\3757zXZ\0"
|
||||
#define HEADER_MAGIC_SIZE 6
|
||||
|
||||
#define FOOTER_MAGIC "YZ"
|
||||
#define FOOTER_MAGIC_SIZE 2
|
||||
|
||||
/*
|
||||
* Variable-length integer can hold a 63-bit unsigned integer, or a special
|
||||
* value to indicate that the value is unknown.
|
||||
*/
|
||||
typedef uint64_t vli_type;
|
||||
|
||||
#define VLI_MAX ((vli_type)-1 / 2)
|
||||
#define VLI_UNKNOWN ((vli_type)-1)
|
||||
|
||||
/* Maximum encoded size of a VLI */
|
||||
#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7)
|
||||
|
||||
#endif
|
|
@ -28,7 +28,6 @@
|
|||
#include <grub/elfload.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/aout.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/extcmd.h>
|
||||
|
@ -746,6 +745,7 @@ grub_freebsd_boot (void)
|
|||
grub_memcpy (&stack[9], &bi, sizeof (bi));
|
||||
state.eip = entry;
|
||||
state.esp = stack_target;
|
||||
state.ebp = stack_target;
|
||||
stack[0] = entry; /* "Return" address. */
|
||||
stack[1] = bootflags | FREEBSD_RB_BOOTINFO;
|
||||
stack[2] = bootdev;
|
||||
|
@ -830,7 +830,8 @@ grub_openbsd_boot (void)
|
|||
#endif
|
||||
|
||||
state.eip = entry;
|
||||
state.esp = ((grub_uint8_t *) stack - (grub_uint8_t *) buf0) + buf_target;
|
||||
state.ebp = state.esp
|
||||
= ((grub_uint8_t *) stack - (grub_uint8_t *) buf0) + buf_target;
|
||||
stack[0] = entry;
|
||||
stack[1] = bootflags;
|
||||
stack[2] = openbsd_root;
|
||||
|
@ -1045,6 +1046,7 @@ grub_netbsd_boot (void)
|
|||
|
||||
state.eip = entry;
|
||||
state.esp = stack_target;
|
||||
state.ebp = stack_target;
|
||||
stack[0] = entry;
|
||||
stack[1] = bootflags;
|
||||
stack[2] = 0;
|
||||
|
@ -1323,7 +1325,7 @@ grub_bsd_load (int argc, char *argv[])
|
|||
goto fail;
|
||||
}
|
||||
|
||||
file = grub_gzfile_open (argv[0], 1);
|
||||
file = grub_file_open (argv[0]);
|
||||
if (!file)
|
||||
goto fail;
|
||||
|
||||
|
@ -1369,10 +1371,10 @@ grub_bsd_parse_flags (const struct grub_arg_list *state,
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[])
|
||||
grub_cmd_freebsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
|
||||
{
|
||||
kernel_type = KERNEL_TYPE_FREEBSD;
|
||||
bootflags = grub_bsd_parse_flags (cmd->state, freebsd_flags);
|
||||
bootflags = grub_bsd_parse_flags (ctxt->state, freebsd_flags);
|
||||
|
||||
if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
|
||||
{
|
||||
|
@ -1393,7 +1395,7 @@ grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[])
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
file = grub_gzfile_open (argv[0], 1);
|
||||
file = grub_file_open (argv[0]);
|
||||
if (! file)
|
||||
return grub_errno;
|
||||
|
||||
|
@ -1426,16 +1428,16 @@ grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[])
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[])
|
||||
grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
|
||||
{
|
||||
grub_uint32_t bootdev;
|
||||
|
||||
kernel_type = KERNEL_TYPE_OPENBSD;
|
||||
bootflags = grub_bsd_parse_flags (cmd->state, openbsd_flags);
|
||||
bootflags = grub_bsd_parse_flags (ctxt->state, openbsd_flags);
|
||||
|
||||
if (cmd->state[OPENBSD_ROOT_ARG].set)
|
||||
if (ctxt->state[OPENBSD_ROOT_ARG].set)
|
||||
{
|
||||
const char *arg = cmd->state[OPENBSD_ROOT_ARG].arg;
|
||||
const char *arg = ctxt->state[OPENBSD_ROOT_ARG].arg;
|
||||
int unit, part;
|
||||
if (*(arg++) != 'w' || *(arg++) != 'd')
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
|
@ -1456,7 +1458,7 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[])
|
|||
else
|
||||
bootdev = 0;
|
||||
|
||||
if (cmd->state[OPENBSD_SERIAL_ARG].set)
|
||||
if (ctxt->state[OPENBSD_SERIAL_ARG].set)
|
||||
{
|
||||
struct grub_openbsd_bootarg_console serial;
|
||||
char *ptr;
|
||||
|
@ -1465,9 +1467,9 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[])
|
|||
|
||||
grub_memset (&serial, 0, sizeof (serial));
|
||||
|
||||
if (cmd->state[OPENBSD_SERIAL_ARG].arg)
|
||||
if (ctxt->state[OPENBSD_SERIAL_ARG].arg)
|
||||
{
|
||||
ptr = cmd->state[OPENBSD_SERIAL_ARG].arg;
|
||||
ptr = ctxt->state[OPENBSD_SERIAL_ARG].arg;
|
||||
if (grub_memcmp (ptr, "com", sizeof ("com") - 1) != 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"only com0-com3 are supported");
|
||||
|
@ -1511,11 +1513,11 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[])
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[])
|
||||
grub_cmd_netbsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
|
||||
{
|
||||
grub_err_t err;
|
||||
kernel_type = KERNEL_TYPE_NETBSD;
|
||||
bootflags = grub_bsd_parse_flags (cmd->state, netbsd_flags);
|
||||
bootflags = grub_bsd_parse_flags (ctxt->state, netbsd_flags);
|
||||
|
||||
if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
|
||||
{
|
||||
|
@ -1523,7 +1525,7 @@ grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[])
|
|||
{
|
||||
grub_file_t file;
|
||||
|
||||
file = grub_gzfile_open (argv[0], 1);
|
||||
file = grub_file_open (argv[0]);
|
||||
if (! file)
|
||||
return grub_errno;
|
||||
|
||||
|
@ -1548,15 +1550,15 @@ grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[])
|
|||
grub_bsd_add_meta (NETBSD_BTINFO_BOOTPATH, bootpath, sizeof (bootpath));
|
||||
}
|
||||
|
||||
if (cmd->state[NETBSD_ROOT_ARG].set)
|
||||
if (ctxt->state[NETBSD_ROOT_ARG].set)
|
||||
{
|
||||
char root[GRUB_NETBSD_MAX_ROOTDEVICE_LEN];
|
||||
grub_memset (root, 0, sizeof (root));
|
||||
grub_strncpy (root, cmd->state[NETBSD_ROOT_ARG].arg,
|
||||
grub_strncpy (root, ctxt->state[NETBSD_ROOT_ARG].arg,
|
||||
sizeof (root) - 1);
|
||||
grub_bsd_add_meta (NETBSD_BTINFO_ROOTDEVICE, root, sizeof (root));
|
||||
}
|
||||
if (cmd->state[NETBSD_SERIAL_ARG].set)
|
||||
if (ctxt->state[NETBSD_SERIAL_ARG].set)
|
||||
{
|
||||
struct grub_netbsd_btinfo_serial serial;
|
||||
char *ptr;
|
||||
|
@ -1564,9 +1566,9 @@ grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[])
|
|||
grub_memset (&serial, 0, sizeof (serial));
|
||||
grub_strcpy (serial.devname, "com");
|
||||
|
||||
if (cmd->state[NETBSD_SERIAL_ARG].arg)
|
||||
if (ctxt->state[NETBSD_SERIAL_ARG].arg)
|
||||
{
|
||||
ptr = cmd->state[NETBSD_SERIAL_ARG].arg;
|
||||
ptr = ctxt->state[NETBSD_SERIAL_ARG].arg;
|
||||
if (grub_memcmp (ptr, "com", sizeof ("com") - 1) == 0)
|
||||
{
|
||||
ptr += sizeof ("com") - 1;
|
||||
|
@ -1627,7 +1629,7 @@ grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)),
|
|||
goto fail;
|
||||
}
|
||||
|
||||
file = grub_gzfile_open (argv[0], 1);
|
||||
file = grub_file_open (argv[0]);
|
||||
if ((!file) || (!file->size))
|
||||
goto fail;
|
||||
|
||||
|
@ -1728,7 +1730,7 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)),
|
|||
return 0;
|
||||
}
|
||||
|
||||
file = grub_gzfile_open (argv[0], 1);
|
||||
file = grub_file_open (argv[0]);
|
||||
if ((!file) || (!file->size))
|
||||
goto fail;
|
||||
|
||||
|
@ -1779,7 +1781,7 @@ grub_netbsd_module_load (char *filename, grub_uint32_t type)
|
|||
void *src;
|
||||
grub_err_t err;
|
||||
|
||||
file = grub_gzfile_open (filename, 1);
|
||||
file = grub_file_open (filename);
|
||||
if ((!file) || (!file->size))
|
||||
goto fail;
|
||||
|
||||
|
@ -1865,7 +1867,7 @@ grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)),
|
|||
return 0;
|
||||
}
|
||||
|
||||
file = grub_gzfile_open (argv[0], 1);
|
||||
file = grub_file_open (argv[0]);
|
||||
if (!file)
|
||||
return grub_errno;
|
||||
if (!file->size)
|
||||
|
@ -1901,7 +1903,7 @@ grub_cmd_openbsd_ramdisk (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (!openbsd_ramdisk.max_size)
|
||||
return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD doesn't support ramdisk");
|
||||
|
||||
file = grub_gzfile_open (args[0], 1);
|
||||
file = grub_file_open (args[0]);
|
||||
if (! file)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
|
||||
"couldn't load ramdisk");
|
||||
|
@ -1937,6 +1939,9 @@ static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk;
|
|||
|
||||
GRUB_MOD_INIT (bsd)
|
||||
{
|
||||
/* Net and OpenBSD kernels are often compressed. */
|
||||
grub_dl_load ("gzio");
|
||||
|
||||
cmd_freebsd = grub_register_extcmd ("kfreebsd", grub_cmd_freebsd,
|
||||
GRUB_COMMAND_FLAG_BOTH,
|
||||
N_("FILE"), N_("Load kernel of FreeBSD."),
|
||||
|
|
|
@ -716,7 +716,7 @@ grub_linux_boot (void)
|
|||
|
||||
/* FIXME. */
|
||||
/* asm volatile ("lidt %0" : : "m" (idt_desc)); */
|
||||
state.ebx = 0;
|
||||
state.ebp = state.edi = state.ebx = 0;
|
||||
state.esi = real_mode_target;
|
||||
state.esp = real_mode_target;
|
||||
state.eip = params->code32_start;
|
||||
|
@ -1069,6 +1069,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
|||
goto fail;
|
||||
}
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (argv[0]);
|
||||
if (! file)
|
||||
goto fail;
|
||||
|
|
|
@ -69,6 +69,7 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
|
|||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (filename);
|
||||
if (! file)
|
||||
goto fail;
|
||||
|
|
|
@ -401,6 +401,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
addr_min = GRUB_LINUX_BZIMAGE_ADDR + grub_linux16_prot_size;
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (argv[0]);
|
||||
if (!file)
|
||||
goto fail;
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include <grub/charset.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/bitmap_scale.h>
|
||||
|
||||
|
@ -535,7 +534,7 @@ grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (argc != 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
|
||||
|
||||
file = grub_gzfile_open (args[0], 1);
|
||||
file = grub_file_open (args[0]);
|
||||
if (! file)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
|
||||
"couldn't load device-propertie dump");
|
||||
|
@ -836,6 +835,7 @@ grub_xnu_boot_resume (void)
|
|||
struct grub_relocator32_state state;
|
||||
|
||||
state.esp = grub_xnu_stack;
|
||||
state.ebp = grub_xnu_stack;
|
||||
state.eip = grub_xnu_entry_point;
|
||||
state.eax = grub_xnu_arg1;
|
||||
|
||||
|
@ -1114,6 +1114,7 @@ grub_xnu_boot (void)
|
|||
state.eip = grub_xnu_entry_point;
|
||||
state.eax = grub_xnu_arg1;
|
||||
state.esp = grub_xnu_stack;
|
||||
state.ebp = grub_xnu_stack;
|
||||
return grub_relocator32_boot (grub_xnu_relocator, state);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <grub/cpu/macho.h>
|
||||
#include <grub/machoload.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
|
@ -149,7 +148,7 @@ grub_macho_open (const char *name)
|
|||
grub_file_t file;
|
||||
grub_macho_t macho;
|
||||
|
||||
file = grub_gzfile_open (name, 1);
|
||||
file = grub_file_open (name);
|
||||
if (! file)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -344,6 +344,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (initrd_loaded)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd can be loaded.");
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (argv[0]);
|
||||
if (! file)
|
||||
return grub_errno;
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include <grub/dl.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/cpu/relocator.h>
|
||||
#include <grub/video.h>
|
||||
|
@ -225,7 +224,7 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (argc == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
|
||||
|
||||
file = grub_gzfile_open (argv[0], 1);
|
||||
file = grub_file_open (argv[0]);
|
||||
if (! file)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file");
|
||||
|
||||
|
@ -291,9 +290,9 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
|
|||
"you need to load the multiboot kernel first");
|
||||
|
||||
if (nounzip)
|
||||
grub_file_filter_disable_compression ();
|
||||
|
||||
file = grub_file_open (argv[0]);
|
||||
else
|
||||
file = grub_gzfile_open (argv[0], 1);
|
||||
if (! file)
|
||||
return grub_errno;
|
||||
|
||||
|
|
|
@ -301,6 +301,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
|||
goto fail;
|
||||
}
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (argv[0]);
|
||||
if (! file)
|
||||
goto fail;
|
||||
|
|
|
@ -305,7 +305,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
goto out;
|
||||
}
|
||||
|
||||
file = grub_gzfile_open (argv[0], 1);
|
||||
file = grub_file_open (argv[0]);
|
||||
if (!file)
|
||||
goto out;
|
||||
|
||||
|
@ -393,6 +393,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
|||
goto fail;
|
||||
}
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (argv[0]);
|
||||
if (! file)
|
||||
goto fail;
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <grub/machoload.h>
|
||||
#include <grub/macho.h>
|
||||
#include <grub/cpu/macho.h>
|
||||
#include <grub/gzio.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/extcmd.h>
|
||||
|
@ -661,7 +660,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile)
|
|||
macho = 0;
|
||||
|
||||
if (infoplistname)
|
||||
infoplist = grub_gzfile_open (infoplistname, 1);
|
||||
infoplist = grub_file_open (infoplistname);
|
||||
else
|
||||
infoplist = 0;
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
@ -756,7 +755,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (! grub_xnu_heap_size)
|
||||
return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
|
||||
|
||||
file = grub_gzfile_open (args[0], 1);
|
||||
file = grub_file_open (args[0]);
|
||||
if (! file)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
|
||||
"couldn't load driver package");
|
||||
|
@ -869,7 +868,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (! grub_xnu_heap_size)
|
||||
return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
|
||||
|
||||
file = grub_gzfile_open (args[0], 1);
|
||||
file = grub_file_open (args[0]);
|
||||
if (! file)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
|
||||
"couldn't load ramdisk");
|
||||
|
@ -909,7 +908,7 @@ grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq,
|
|||
if (binname)
|
||||
*binname = 0;
|
||||
|
||||
file = grub_gzfile_open (plistname, 1);
|
||||
file = grub_file_open (plistname);
|
||||
if (! file)
|
||||
{
|
||||
grub_file_close (file);
|
||||
|
@ -1166,7 +1165,7 @@ grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired,
|
|||
grub_strcpy (binname + grub_strlen (binname), "/");
|
||||
grub_strcpy (binname + grub_strlen (binname), binsuffix);
|
||||
grub_dprintf ("xnu", "%s:%s\n", plistname, binname);
|
||||
binfile = grub_gzfile_open (binname, 1);
|
||||
binfile = grub_file_open (binname);
|
||||
if (! binfile)
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
|
@ -1204,7 +1203,7 @@ grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)),
|
|||
/* User explicitly specified plist and binary. */
|
||||
if (grub_strcmp (args[1], "-") != 0)
|
||||
{
|
||||
binfile = grub_gzfile_open (args[1], 1);
|
||||
binfile = grub_file_open (args[1]);
|
||||
if (! binfile)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, "can't open file");
|
||||
|
@ -1364,15 +1363,15 @@ static const struct grub_arg_option xnu_splash_cmd_options[] =
|
|||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_xnu_splash (grub_extcmd_t cmd,
|
||||
grub_cmd_xnu_splash (grub_extcmd_context_t ctxt,
|
||||
int argc, char *args[])
|
||||
{
|
||||
grub_err_t err;
|
||||
if (argc != 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
|
||||
|
||||
if (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set &&
|
||||
grub_strcmp (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg,
|
||||
if (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set &&
|
||||
grub_strcmp (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg,
|
||||
"stretch") == 0)
|
||||
grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH;
|
||||
else
|
||||
|
|
|
@ -52,6 +52,7 @@ grub_xnu_resume (char *imagename)
|
|||
grub_addr_t target_image;
|
||||
grub_err_t err;
|
||||
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (imagename);
|
||||
if (! file)
|
||||
return 0;
|
||||
|
|
|
@ -500,8 +500,8 @@ grub_normal_do_completion (char *buf, int *restore,
|
|||
fail:
|
||||
if (argc != 0)
|
||||
{
|
||||
grub_free (argv);
|
||||
grub_free (argv[0]);
|
||||
grub_free (argv);
|
||||
}
|
||||
grub_free (match);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
|
|
@ -23,16 +23,21 @@
|
|||
#include <grub/misc.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/script_sh.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
static grub_err_t
|
||||
grub_dyncmd_dispatcher (struct grub_command *cmd,
|
||||
grub_dyncmd_dispatcher (struct grub_extcmd_context *ctxt,
|
||||
int argc, char **args)
|
||||
{
|
||||
char *modname = cmd->data;
|
||||
char *modname;
|
||||
grub_dl_t mod;
|
||||
grub_err_t ret;
|
||||
grub_extcmd_t extcmd = ctxt->extcmd;
|
||||
grub_command_t cmd = extcmd->cmd;
|
||||
|
||||
modname = extcmd->data;
|
||||
mod = grub_dl_load (modname);
|
||||
if (mod)
|
||||
{
|
||||
|
@ -42,11 +47,17 @@ grub_dyncmd_dispatcher (struct grub_command *cmd,
|
|||
grub_dl_ref (mod);
|
||||
|
||||
name = (char *) cmd->name;
|
||||
grub_unregister_command (cmd);
|
||||
grub_unregister_extcmd (extcmd);
|
||||
|
||||
cmd = grub_command_find (name);
|
||||
if (cmd)
|
||||
{
|
||||
if (cmd->flags & GRUB_COMMAND_FLAG_BLOCKS &&
|
||||
cmd->flags & GRUB_COMMAND_FLAG_EXTCMD)
|
||||
ret = grub_extcmd_dispatcher (cmd, argc, args, ctxt->script);
|
||||
else
|
||||
ret = (cmd->func) (cmd, argc, args);
|
||||
}
|
||||
else
|
||||
ret = grub_errno;
|
||||
|
||||
|
@ -81,13 +92,14 @@ read_command_list (const char *prefix)
|
|||
for (ptr = grub_command_list; ptr; ptr = next)
|
||||
{
|
||||
next = ptr->next;
|
||||
if (ptr->func == grub_dyncmd_dispatcher)
|
||||
if (ptr->flags & GRUB_COMMAND_FLAG_DYNCMD)
|
||||
{
|
||||
if (last)
|
||||
last->next = ptr->next;
|
||||
else
|
||||
grub_command_list = ptr->next;
|
||||
grub_free (ptr);
|
||||
grub_free (ptr->data); /* extcmd struct */
|
||||
}
|
||||
else
|
||||
last = ptr;
|
||||
|
@ -96,7 +108,7 @@ read_command_list (const char *prefix)
|
|||
for (;; grub_free (buf))
|
||||
{
|
||||
char *p, *name, *modname;
|
||||
grub_command_t cmd;
|
||||
grub_extcmd_t cmd;
|
||||
int prio = 0;
|
||||
|
||||
buf = grub_file_getline (file);
|
||||
|
@ -139,16 +151,20 @@ read_command_list (const char *prefix)
|
|||
continue;
|
||||
}
|
||||
|
||||
cmd = grub_register_command_prio (name,
|
||||
cmd = grub_register_extcmd_prio (name,
|
||||
grub_dyncmd_dispatcher,
|
||||
0, N_("not loaded"), prio);
|
||||
GRUB_COMMAND_FLAG_BLOCKS
|
||||
| GRUB_COMMAND_FLAG_EXTCMD
|
||||
| GRUB_COMMAND_FLAG_CMDLINE
|
||||
| GRUB_COMMAND_FLAG_DYNCMD,
|
||||
0, N_("not loaded"), 0,
|
||||
prio);
|
||||
if (! cmd)
|
||||
{
|
||||
grub_free (name);
|
||||
grub_free (modname);
|
||||
continue;
|
||||
}
|
||||
cmd->flags |= GRUB_COMMAND_FLAG_DYNCMD;
|
||||
cmd->data = modname;
|
||||
|
||||
/* Update the active flag. */
|
||||
|
|
|
@ -141,209 +141,6 @@ free_menu (grub_menu_t menu)
|
|||
grub_env_unset_menu ();
|
||||
}
|
||||
|
||||
static void
|
||||
free_menu_entry_classes (struct grub_menu_entry_class *head)
|
||||
{
|
||||
/* Free all the classes. */
|
||||
while (head)
|
||||
{
|
||||
struct grub_menu_entry_class *next;
|
||||
|
||||
grub_free (head->name);
|
||||
next = head->next;
|
||||
grub_free (head);
|
||||
head = next;
|
||||
}
|
||||
}
|
||||
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
int key;
|
||||
} hotkey_aliases[] =
|
||||
{
|
||||
{"backspace", '\b'},
|
||||
{"tab", '\t'},
|
||||
{"delete", GRUB_TERM_DC}
|
||||
};
|
||||
|
||||
/* Add a menu entry to the current menu context (as given by the environment
|
||||
variable data slot `menu'). As the configuration file is read, the script
|
||||
parser calls this when a menu entry is to be created. */
|
||||
grub_err_t
|
||||
grub_normal_add_menu_entry (int argc, const char **args,
|
||||
const char *sourcecode)
|
||||
{
|
||||
const char *menutitle = 0;
|
||||
const char *menusourcecode;
|
||||
grub_menu_t menu;
|
||||
grub_menu_entry_t *last;
|
||||
int failed = 0;
|
||||
int i;
|
||||
struct grub_menu_entry_class *classes_head; /* Dummy head node for list. */
|
||||
struct grub_menu_entry_class *classes_tail;
|
||||
char *users = NULL;
|
||||
int hotkey = 0;
|
||||
|
||||
/* Allocate dummy head node for class list. */
|
||||
classes_head = grub_zalloc (sizeof (struct grub_menu_entry_class));
|
||||
if (! classes_head)
|
||||
return grub_errno;
|
||||
classes_tail = classes_head;
|
||||
|
||||
menu = grub_env_get_menu ();
|
||||
if (! menu)
|
||||
return grub_error (GRUB_ERR_MENU, "no menu context");
|
||||
|
||||
last = &menu->entry_list;
|
||||
|
||||
menusourcecode = grub_strdup (sourcecode);
|
||||
if (! menusourcecode)
|
||||
return grub_errno;
|
||||
|
||||
/* Parse menu arguments. */
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
/* Capture arguments. */
|
||||
if (grub_strncmp ("--", args[i], 2) == 0 && i + 1 < argc)
|
||||
{
|
||||
const char *arg = &args[i][2];
|
||||
|
||||
/* Handle menu class. */
|
||||
if (grub_strcmp(arg, "class") == 0)
|
||||
{
|
||||
char *class_name;
|
||||
struct grub_menu_entry_class *new_class;
|
||||
|
||||
i++;
|
||||
class_name = grub_strdup (args[i]);
|
||||
if (! class_name)
|
||||
{
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Create a new class and add it at the tail of the list. */
|
||||
new_class = grub_zalloc (sizeof (struct grub_menu_entry_class));
|
||||
if (! new_class)
|
||||
{
|
||||
grub_free (class_name);
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
/* Fill in the new class node. */
|
||||
new_class->name = class_name;
|
||||
/* Link the tail to it, and make it the new tail. */
|
||||
classes_tail->next = new_class;
|
||||
classes_tail = new_class;
|
||||
continue;
|
||||
}
|
||||
else if (grub_strcmp(arg, "users") == 0)
|
||||
{
|
||||
i++;
|
||||
users = grub_strdup (args[i]);
|
||||
if (! users)
|
||||
{
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (grub_strcmp(arg, "hotkey") == 0)
|
||||
{
|
||||
unsigned j;
|
||||
|
||||
i++;
|
||||
if (args[i][1] == 0)
|
||||
{
|
||||
hotkey = args[i][0];
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE (hotkey_aliases); j++)
|
||||
if (grub_strcmp (args[i], hotkey_aliases[j].name) == 0)
|
||||
{
|
||||
hotkey = hotkey_aliases[j].key;
|
||||
break;
|
||||
}
|
||||
|
||||
if (j < ARRAY_SIZE (hotkey_aliases))
|
||||
continue;
|
||||
|
||||
failed = 1;
|
||||
grub_error (GRUB_ERR_MENU,
|
||||
"Invalid hotkey: '%s'.", args[i]);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle invalid argument. */
|
||||
failed = 1;
|
||||
grub_error (GRUB_ERR_MENU,
|
||||
"invalid argument for menuentry: %s", args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Capture title. */
|
||||
if (! menutitle)
|
||||
{
|
||||
menutitle = grub_strdup (args[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
failed = 1;
|
||||
grub_error (GRUB_ERR_MENU,
|
||||
"too many titles for menuentry: %s", args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Validate arguments. */
|
||||
if ((! failed) && (! menutitle))
|
||||
{
|
||||
grub_error (GRUB_ERR_MENU, "menuentry is missing title");
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
/* If argument parsing failed, free any allocated resources. */
|
||||
if (failed)
|
||||
{
|
||||
free_menu_entry_classes (classes_head);
|
||||
grub_free ((void *) menutitle);
|
||||
grub_free ((void *) menusourcecode);
|
||||
|
||||
/* Here we assume that grub_error has been used to specify failure details. */
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* Add the menu entry at the end of the list. */
|
||||
while (*last)
|
||||
last = &(*last)->next;
|
||||
|
||||
*last = grub_zalloc (sizeof (**last));
|
||||
if (! *last)
|
||||
{
|
||||
free_menu_entry_classes (classes_head);
|
||||
grub_free ((void *) menutitle);
|
||||
grub_free ((void *) menusourcecode);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
(*last)->title = menutitle;
|
||||
(*last)->hotkey = hotkey;
|
||||
(*last)->classes = classes_head;
|
||||
if (users)
|
||||
(*last)->restricted = 1;
|
||||
(*last)->users = users;
|
||||
(*last)->sourcecode = menusourcecode;
|
||||
|
||||
menu->size++;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_menu_t
|
||||
read_config_file (const char *config)
|
||||
{
|
||||
|
@ -677,8 +474,12 @@ static void (*grub_xputs_saved) (const char *str);
|
|||
|
||||
GRUB_MOD_INIT(normal)
|
||||
{
|
||||
/* Previously many modules depended on gzio. Be nice to user and load it. */
|
||||
grub_dl_load ("gzio");
|
||||
|
||||
grub_context_init ();
|
||||
grub_script_init ();
|
||||
grub_menu_init ();
|
||||
|
||||
grub_xputs_saved = grub_xputs;
|
||||
grub_xputs = grub_xputs_normal;
|
||||
|
@ -718,6 +519,7 @@ GRUB_MOD_FINI(normal)
|
|||
{
|
||||
grub_context_fini ();
|
||||
grub_script_fini ();
|
||||
grub_menu_fini ();
|
||||
|
||||
grub_xputs = grub_xputs_saved;
|
||||
|
||||
|
|
|
@ -153,44 +153,6 @@ get_and_remove_first_entry_number (const char *name)
|
|||
return entry;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_menu_execute_entry_real (grub_menu_entry_t entry)
|
||||
{
|
||||
const char *source;
|
||||
|
||||
auto grub_err_t getline (char **line, int cont);
|
||||
grub_err_t getline (char **line, int cont __attribute__ ((unused)))
|
||||
{
|
||||
const char *p;
|
||||
|
||||
if (!source)
|
||||
{
|
||||
*line = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = grub_strchr (source, '\n');
|
||||
|
||||
if (p)
|
||||
*line = grub_strndup (source, p - source);
|
||||
else
|
||||
*line = grub_strdup (source);
|
||||
source = p ? p + 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
source = entry->sourcecode;
|
||||
|
||||
while (source)
|
||||
{
|
||||
char *line;
|
||||
|
||||
getline (&line, 0);
|
||||
grub_normal_parse_line (line, getline);
|
||||
grub_free (line);
|
||||
}
|
||||
}
|
||||
|
||||
/* Run a menu entry. */
|
||||
void
|
||||
grub_menu_execute_entry(grub_menu_entry_t entry)
|
||||
|
@ -208,8 +170,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry)
|
|||
}
|
||||
|
||||
grub_env_set ("chosen", entry->title);
|
||||
|
||||
grub_menu_execute_entry_real (entry);
|
||||
grub_script_execute_sourcecode (entry->sourcecode, entry->argc, entry->args);
|
||||
|
||||
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
|
||||
/* Implicit execution of boot, only if something is loaded. */
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/script_sh.h>
|
||||
|
||||
/* Return nearest power of two that is >= v. */
|
||||
|
@ -55,6 +56,24 @@ grub_script_argv_free (struct grub_script_argv *argv)
|
|||
|
||||
argv->argc = 0;
|
||||
argv->args = 0;
|
||||
argv->script = 0;
|
||||
}
|
||||
|
||||
/* Make argv from argc, args pair. */
|
||||
int
|
||||
grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args)
|
||||
{
|
||||
int i;
|
||||
struct grub_script_argv r = { 0, 0, 0 };
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
if (grub_script_argv_next (&r) || grub_script_argv_append (&r, args[i]))
|
||||
{
|
||||
grub_script_argv_free (&r);
|
||||
return 1;
|
||||
}
|
||||
*argv = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prepare for next argc. */
|
||||
|
@ -63,7 +82,7 @@ grub_script_argv_next (struct grub_script_argv *argv)
|
|||
{
|
||||
char **p = argv->args;
|
||||
|
||||
if (argv->args && argv->args[argv->argc - 1] == 0)
|
||||
if (argv->args && argv->argc && argv->args[argv->argc - 1] == 0)
|
||||
return 0;
|
||||
|
||||
p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *)));
|
||||
|
@ -83,7 +102,8 @@ grub_script_argv_next (struct grub_script_argv *argv)
|
|||
int
|
||||
grub_script_argv_append (struct grub_script_argv *argv, const char *s)
|
||||
{
|
||||
int a, b;
|
||||
int a;
|
||||
int b;
|
||||
char *p = argv->args[argv->argc - 1];
|
||||
|
||||
if (! s)
|
||||
|
@ -98,6 +118,7 @@ grub_script_argv_append (struct grub_script_argv *argv, const char *s)
|
|||
|
||||
grub_strcpy (p + a, s);
|
||||
argv->args[argv->argc - 1] = p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <grub/menu.h>
|
||||
#include <grub/lib/arg.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/extcmd.h>
|
||||
|
||||
/* Max digits for a char is 3 (0xFF is 255), similarly for an int it
|
||||
is sizeof (int) * 3, and one extra for a possible -ve sign. */
|
||||
|
@ -33,14 +34,40 @@
|
|||
static unsigned long is_continue;
|
||||
static unsigned long active_loops;
|
||||
static unsigned long active_breaks;
|
||||
static unsigned long function_return;
|
||||
|
||||
#define GRUB_SCRIPT_SCOPE_MALLOCED 1
|
||||
#define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2
|
||||
|
||||
/* Scope for grub script functions. */
|
||||
struct grub_script_scope
|
||||
{
|
||||
unsigned flags;
|
||||
unsigned shifts;
|
||||
struct grub_script_argv argv;
|
||||
};
|
||||
static struct grub_script_scope *scope = 0;
|
||||
|
||||
/* Wildcard translator for GRUB script. */
|
||||
struct grub_script_wildcard_translator *grub_wildcard_translator;
|
||||
|
||||
static void
|
||||
replace_scope (struct grub_script_scope *new_scope)
|
||||
{
|
||||
if (scope)
|
||||
{
|
||||
scope->argv.argc += scope->shifts;
|
||||
scope->argv.args -= scope->shifts;
|
||||
|
||||
if (scope->flags & GRUB_SCRIPT_SCOPE_ARGS_MALLOCED)
|
||||
grub_script_argv_free (&scope->argv);
|
||||
|
||||
if (scope->flags & GRUB_SCRIPT_SCOPE_MALLOCED)
|
||||
grub_free (scope);
|
||||
}
|
||||
scope = new_scope;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_script_break (grub_command_t cmd, int argc, char *argv[])
|
||||
{
|
||||
|
@ -85,11 +112,65 @@ grub_script_shift (grub_command_t cmd __attribute__((unused)),
|
|||
if (n > scope->argv.argc)
|
||||
return GRUB_ERR_BAD_ARGUMENT;
|
||||
|
||||
scope->shifts += n;
|
||||
scope->argv.argc -= n;
|
||||
scope->argv.args += n;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_script_setparams (grub_command_t cmd __attribute__((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
struct grub_script_scope *new_scope;
|
||||
struct grub_script_argv argv = { 0, 0, 0 };
|
||||
|
||||
if (! scope)
|
||||
return GRUB_ERR_INVALID_COMMAND;
|
||||
|
||||
new_scope = grub_malloc (sizeof (*new_scope));
|
||||
if (! new_scope)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_script_argv_make (&argv, argc, args))
|
||||
{
|
||||
grub_free (new_scope);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
new_scope->shifts = 0;
|
||||
new_scope->argv = argv;
|
||||
new_scope->flags = GRUB_SCRIPT_SCOPE_MALLOCED |
|
||||
GRUB_SCRIPT_SCOPE_ARGS_MALLOCED;
|
||||
|
||||
replace_scope (new_scope);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_script_return (grub_command_t cmd __attribute__((unused)),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
char *p;
|
||||
unsigned long n;
|
||||
|
||||
if (! scope || argc > 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in function scope");
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
function_return = 1;
|
||||
return grub_strtoul (grub_env_get ("?"), NULL, 10);
|
||||
}
|
||||
|
||||
n = grub_strtoul (argv[0], &p, 10);
|
||||
if (*p != '\0')
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad argument");
|
||||
|
||||
function_return = 1;
|
||||
return n ? grub_error (GRUB_ERR_TEST_FAILURE, "false") : GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_env_special (const char *name)
|
||||
{
|
||||
|
@ -104,7 +185,8 @@ grub_env_special (const char *name)
|
|||
static char **
|
||||
grub_script_env_get (const char *name, grub_script_arg_type_t type)
|
||||
{
|
||||
struct grub_script_argv result = { 0, 0 };
|
||||
unsigned i;
|
||||
struct grub_script_argv result = { 0, 0, 0 };
|
||||
|
||||
if (grub_script_argv_next (&result))
|
||||
goto fail;
|
||||
|
@ -138,8 +220,6 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type)
|
|||
}
|
||||
else if (grub_strcmp (name, "*") == 0)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < scope->argv.argc; i++)
|
||||
if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
|
||||
{
|
||||
|
@ -160,8 +240,6 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type)
|
|||
}
|
||||
else if (grub_strcmp (name, "@") == 0)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < scope->argv.argc; i++)
|
||||
{
|
||||
if (i != 0 && grub_script_argv_next (&result))
|
||||
|
@ -214,7 +292,7 @@ grub_script_env_set (const char *name, const char *val)
|
|||
return grub_env_set (name, val);
|
||||
}
|
||||
|
||||
/* Expand arguments in ARGLIST into multiple arguments. */
|
||||
/* Convert arguments in ARGLIST into ARGV form. */
|
||||
static int
|
||||
grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
|
||||
struct grub_script_argv *argv)
|
||||
|
@ -222,7 +300,29 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
|
|||
int i;
|
||||
char **values = 0;
|
||||
struct grub_script_arg *arg = 0;
|
||||
struct grub_script_argv result = { 0, 0 };
|
||||
struct grub_script_argv result = { 0, 0, 0 };
|
||||
|
||||
auto int append (char *s, int escape_type);
|
||||
int append (char *s, int escape_type)
|
||||
{
|
||||
int r;
|
||||
char *p = 0;
|
||||
|
||||
if (! grub_wildcard_translator || escape_type == 0)
|
||||
return grub_script_argv_append (&result, s);
|
||||
|
||||
if (escape_type > 0)
|
||||
p = grub_wildcard_translator->escape (s);
|
||||
else if (escape_type < 0)
|
||||
p = grub_wildcard_translator->unescape (s);
|
||||
|
||||
if (! p)
|
||||
return 1;
|
||||
|
||||
r = grub_script_argv_append (&result, p);
|
||||
grub_free (p);
|
||||
return r;
|
||||
}
|
||||
|
||||
for (; arglist && arglist->arg; arglist = arglist->next)
|
||||
{
|
||||
|
@ -242,12 +342,30 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
|
|||
if (i != 0 && grub_script_argv_next (&result))
|
||||
goto fail;
|
||||
|
||||
if (arg->type == GRUB_SCRIPT_ARG_TYPE_VAR)
|
||||
{
|
||||
if (grub_script_argv_append (&result, values[i]))
|
||||
goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (append (values[i], 1))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
grub_free (values[i]);
|
||||
}
|
||||
grub_free (values);
|
||||
break;
|
||||
|
||||
case GRUB_SCRIPT_ARG_TYPE_BLOCK:
|
||||
if (grub_script_argv_append (&result, "{") ||
|
||||
grub_script_argv_append (&result, arg->str) ||
|
||||
grub_script_argv_append (&result, "}"))
|
||||
goto fail;
|
||||
result.script = arg->script;
|
||||
break;
|
||||
|
||||
case GRUB_SCRIPT_ARG_TYPE_TEXT:
|
||||
if (grub_strlen (arg->str) &&
|
||||
grub_script_argv_append (&result, arg->str))
|
||||
|
@ -267,6 +385,51 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
|
|||
if (! result.args[result.argc - 1])
|
||||
result.argc--;
|
||||
|
||||
/* Perform wildcard expansion. */
|
||||
|
||||
if (grub_wildcard_translator)
|
||||
{
|
||||
int j;
|
||||
int failed = 0;
|
||||
char **expansions = 0;
|
||||
struct grub_script_argv unexpanded = result;
|
||||
|
||||
result.argc = 0;
|
||||
result.args = 0;
|
||||
for (i = 0; unexpanded.args[i]; i++)
|
||||
{
|
||||
if (grub_wildcard_translator->expand (unexpanded.args[i],
|
||||
&expansions))
|
||||
{
|
||||
grub_script_argv_free (&unexpanded);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (! expansions)
|
||||
{
|
||||
grub_script_argv_next (&result);
|
||||
append (unexpanded.args[i], -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = 0; expansions[j]; j++)
|
||||
{
|
||||
failed = (failed || grub_script_argv_next (&result) ||
|
||||
append (expansions[j], -1));
|
||||
grub_free (expansions[j]);
|
||||
}
|
||||
grub_free (expansions);
|
||||
|
||||
if (failed)
|
||||
{
|
||||
grub_script_argv_free (&unexpanded);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
grub_script_argv_free (&unexpanded);
|
||||
}
|
||||
|
||||
*argv = result;
|
||||
return 0;
|
||||
|
||||
|
@ -302,6 +465,8 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args)
|
|||
struct grub_script_scope new_scope;
|
||||
|
||||
active_loops = 0;
|
||||
new_scope.flags = 0;
|
||||
new_scope.shifts = 0;
|
||||
new_scope.argv.argc = argc;
|
||||
new_scope.argv.args = args;
|
||||
|
||||
|
@ -310,7 +475,64 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args)
|
|||
|
||||
ret = grub_script_execute (func->func);
|
||||
|
||||
function_return = 0;
|
||||
active_loops = loops;
|
||||
replace_scope (old_scope); /* free any scopes by setparams */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Execute a source script. */
|
||||
grub_err_t
|
||||
grub_script_execute_sourcecode (const char *source, int argc, char **args)
|
||||
{
|
||||
grub_err_t ret = 0;
|
||||
struct grub_script *parsed_script;
|
||||
struct grub_script_scope new_scope;
|
||||
struct grub_script_scope *old_scope;
|
||||
|
||||
auto grub_err_t getline (char **line, int cont);
|
||||
grub_err_t getline (char **line, int cont __attribute__ ((unused)))
|
||||
{
|
||||
const char *p;
|
||||
|
||||
if (! source)
|
||||
{
|
||||
*line = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = grub_strchr (source, '\n');
|
||||
|
||||
if (p)
|
||||
*line = grub_strndup (source, p - source);
|
||||
else
|
||||
*line = grub_strdup (source);
|
||||
source = p ? p + 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_scope.argv.argc = argc;
|
||||
new_scope.argv.args = args;
|
||||
|
||||
old_scope = scope;
|
||||
scope = &new_scope;
|
||||
|
||||
while (source)
|
||||
{
|
||||
char *line;
|
||||
|
||||
getline (&line, 0);
|
||||
parsed_script = grub_script_parse (line, getline);
|
||||
if (! parsed_script)
|
||||
{
|
||||
ret = grub_errno;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = grub_script_execute (parsed_script);
|
||||
grub_free (line);
|
||||
}
|
||||
|
||||
scope = old_scope;
|
||||
return ret;
|
||||
}
|
||||
|
@ -325,13 +547,32 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
|
|||
grub_script_function_t func = 0;
|
||||
char errnobuf[18];
|
||||
char *cmdname;
|
||||
struct grub_script_argv argv = { 0, 0 };
|
||||
int argc;
|
||||
char **args;
|
||||
int invert;
|
||||
struct grub_script_argv argv = { 0, 0, 0 };
|
||||
|
||||
/* Lookup the command. */
|
||||
if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0])
|
||||
return grub_errno;
|
||||
|
||||
invert = 0;
|
||||
argc = argv.argc - 1;
|
||||
args = argv.args + 1;
|
||||
cmdname = argv.args[0];
|
||||
if (grub_strcmp (cmdname, "!") == 0)
|
||||
{
|
||||
if (argv.argc < 2 || ! argv.args[1])
|
||||
{
|
||||
grub_script_argv_free (&argv);
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
|
||||
}
|
||||
|
||||
invert = 1;
|
||||
argc = argv.argc - 2;
|
||||
args = argv.args + 2;
|
||||
cmdname = argv.args[1];
|
||||
}
|
||||
grubcmd = grub_command_find (cmdname);
|
||||
if (! grubcmd)
|
||||
{
|
||||
|
@ -369,9 +610,28 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
|
|||
|
||||
/* Execute the GRUB command or function. */
|
||||
if (grubcmd)
|
||||
ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1);
|
||||
{
|
||||
if ((grubcmd->flags & GRUB_COMMAND_FLAG_BLOCKS) &&
|
||||
(grubcmd->flags & GRUB_COMMAND_FLAG_EXTCMD))
|
||||
ret = grub_extcmd_dispatcher (grubcmd, argc, args, argv.script);
|
||||
else
|
||||
ret = grub_script_function_call (func, argv.argc - 1, argv.args + 1);
|
||||
ret = (grubcmd->func) (grubcmd, argc, args);
|
||||
}
|
||||
else
|
||||
ret = grub_script_function_call (func, argc, args);
|
||||
|
||||
if (invert)
|
||||
{
|
||||
if (ret == GRUB_ERR_TEST_FAILURE)
|
||||
grub_errno = ret = GRUB_ERR_NONE;
|
||||
else if (ret == GRUB_ERR_NONE)
|
||||
ret = grub_error (GRUB_ERR_TEST_FAILURE, "false");
|
||||
else
|
||||
{
|
||||
grub_print_error ();
|
||||
ret = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free arguments. */
|
||||
grub_script_argv_free (&argv);
|
||||
|
@ -395,9 +655,17 @@ grub_script_execute_cmdlist (struct grub_script_cmd *list)
|
|||
struct grub_script_cmd *cmd;
|
||||
|
||||
/* Loop over every command and execute it. */
|
||||
for (cmd = list->next; cmd && ! active_breaks; cmd = cmd->next)
|
||||
for (cmd = list->next; cmd; cmd = cmd->next)
|
||||
{
|
||||
if (active_breaks)
|
||||
break;
|
||||
|
||||
ret = grub_script_execute_cmd (cmd);
|
||||
|
||||
if (function_return)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -405,14 +673,17 @@ grub_script_execute_cmdlist (struct grub_script_cmd *list)
|
|||
grub_err_t
|
||||
grub_script_execute_cmdif (struct grub_script_cmd *cmd)
|
||||
{
|
||||
struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
|
||||
int ret;
|
||||
char *result;
|
||||
struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
|
||||
|
||||
/* Check if the commands results in a true or a false. The value is
|
||||
read from the env variable `?'. */
|
||||
grub_script_execute_cmd (cmdif->exec_to_evaluate);
|
||||
result = grub_env_get ("?");
|
||||
ret = grub_script_execute_cmd (cmdif->exec_to_evaluate);
|
||||
if (function_return)
|
||||
return ret;
|
||||
|
||||
result = grub_env_get ("?");
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
/* Execute the `if' or the `else' part depending on the value of
|
||||
|
@ -429,8 +700,7 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
|
|||
{
|
||||
unsigned i;
|
||||
grub_err_t result;
|
||||
struct grub_script_argv argv = { 0, 0 };
|
||||
|
||||
struct grub_script_argv argv = { 0, 0, 0 };
|
||||
struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd;
|
||||
|
||||
if (grub_script_arglist_to_argv (cmdfor->words, &argv))
|
||||
|
@ -447,6 +717,8 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
|
|||
{
|
||||
grub_script_env_set (cmdfor->name->str, argv.args[i]);
|
||||
result = grub_script_execute_cmd (cmdfor->list);
|
||||
if (function_return)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -462,18 +734,21 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
|
|||
grub_err_t
|
||||
grub_script_execute_cmdwhile (struct grub_script_cmd *cmd)
|
||||
{
|
||||
int cond;
|
||||
int result;
|
||||
struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd;
|
||||
|
||||
active_loops++;
|
||||
result = 0;
|
||||
do {
|
||||
cond = grub_script_execute_cmd (cmdwhile->cond);
|
||||
if (cmdwhile->until ? !cond : cond)
|
||||
result = grub_script_execute_cmd (cmdwhile->cond);
|
||||
if (function_return)
|
||||
break;
|
||||
|
||||
if (cmdwhile->until ? !result : result)
|
||||
break;
|
||||
|
||||
result = grub_script_execute_cmd (cmdwhile->list);
|
||||
if (function_return)
|
||||
break;
|
||||
|
||||
if (active_breaks == 1 && is_continue)
|
||||
active_breaks = 0;
|
||||
|
@ -490,31 +765,6 @@ grub_script_execute_cmdwhile (struct grub_script_cmd *cmd)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Execute the menu entry generate statement. */
|
||||
grub_err_t
|
||||
grub_script_execute_menuentry (struct grub_script_cmd *cmd)
|
||||
{
|
||||
struct grub_script_cmd_menuentry *cmd_menuentry;
|
||||
struct grub_script_argv argv = { 0, 0 };
|
||||
|
||||
cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd;
|
||||
|
||||
if (cmd_menuentry->arglist)
|
||||
{
|
||||
if (grub_script_arglist_to_argv (cmd_menuentry->arglist, &argv))
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_normal_add_menu_entry (argv.argc, (const char **) argv.args,
|
||||
cmd_menuentry->sourcecode);
|
||||
|
||||
grub_script_argv_free (&argv);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Execute any GRUB pre-parsed command or script. */
|
||||
grub_err_t
|
||||
grub_script_execute (struct grub_script *script)
|
||||
|
|
|
@ -38,68 +38,57 @@ grub_script_lexer_deref (struct grub_lexer_param *state)
|
|||
}
|
||||
|
||||
/* Start recording all characters passing through the lexer. */
|
||||
void
|
||||
unsigned
|
||||
grub_script_lexer_record_start (struct grub_parser_param *parser)
|
||||
{
|
||||
struct grub_lexer_param *lexer = parser->lexerstate;
|
||||
|
||||
lexer->record = 1;
|
||||
lexer->recordpos = 0;
|
||||
if (lexer->recording) /* reuse last record */
|
||||
return;
|
||||
lexer->record++;
|
||||
if (lexer->recording)
|
||||
return lexer->recordpos;
|
||||
|
||||
lexer->recordpos = 0;
|
||||
lexer->recordlen = GRUB_LEXER_INITIAL_RECORD_SIZE;
|
||||
lexer->recording = grub_malloc (lexer->recordlen);
|
||||
if (!lexer->recording)
|
||||
{
|
||||
grub_script_yyerror (parser, 0);
|
||||
lexer->record = 0;
|
||||
lexer->recordlen = 0;
|
||||
}
|
||||
return lexer->recordpos;
|
||||
}
|
||||
|
||||
char *
|
||||
grub_script_lexer_record_stop (struct grub_parser_param *parser)
|
||||
grub_script_lexer_record_stop (struct grub_parser_param *parser, unsigned offset)
|
||||
{
|
||||
char *ptr;
|
||||
int count;
|
||||
char *result;
|
||||
struct grub_lexer_param *lexer = parser->lexerstate;
|
||||
|
||||
auto char *compact (char *start, char *end);
|
||||
char *compact (char *start, char *end)
|
||||
{
|
||||
/* Delete '{' and '}' characters and whitespaces. */
|
||||
while (*start && grub_isspace (*start)) start++;
|
||||
if (*start == '{') start++;
|
||||
while (*start && grub_isspace (*start)) start++;
|
||||
|
||||
while (*end && grub_isspace (*end)) end--;
|
||||
if (*end == '}') end--;
|
||||
while (*end && grub_isspace (*end)) end--;
|
||||
end[1] = '\0';
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
if (!lexer->record || !lexer->recording)
|
||||
if (!lexer->record)
|
||||
return 0;
|
||||
|
||||
/* XXX This is not necessary in BASH. */
|
||||
lexer->record--;
|
||||
if (!lexer->recording)
|
||||
return 0;
|
||||
|
||||
ptr = compact (lexer->recording, lexer->recording + lexer->recordpos - 1);
|
||||
lexer->record = 0;
|
||||
count = lexer->recordpos - offset;
|
||||
result = grub_script_malloc (parser, count + 1);
|
||||
if (result) {
|
||||
grub_strncpy (result, lexer->recording + offset, count);
|
||||
result[count] = '\0';
|
||||
}
|
||||
|
||||
if (lexer->record == 0)
|
||||
{
|
||||
grub_free (lexer->recording);
|
||||
lexer->recording = 0;
|
||||
lexer->recordlen = 0;
|
||||
lexer->recordpos = 0;
|
||||
|
||||
/* This memory would be freed by, grub_script_free. */
|
||||
result = grub_script_malloc (parser, grub_strlen (ptr) + 1);
|
||||
if (result)
|
||||
grub_strcpy (result, ptr);
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#define MAX(a,b) ((a) < (b) ? (b) : (a))
|
||||
|
||||
/* Record STR if input recording is enabled. */
|
||||
void
|
||||
grub_script_lexer_record (struct grub_parser_param *parser, char *str)
|
||||
|
@ -108,21 +97,20 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str)
|
|||
char *old;
|
||||
struct grub_lexer_param *lexer = parser->lexerstate;
|
||||
|
||||
if (!lexer->record)
|
||||
if (!lexer->record || !lexer->recording)
|
||||
return;
|
||||
|
||||
len = grub_strlen (str);
|
||||
if (lexer->recordpos + len + 1 > lexer->recordlen)
|
||||
{
|
||||
old = lexer->recording;
|
||||
lexer->recordlen = MAX (len, lexer->recordlen) * 2;
|
||||
lexer->recordlen = grub_max (len, lexer->recordlen) * 2;
|
||||
lexer->recording = grub_realloc (lexer->recording, lexer->recordlen);
|
||||
if (!lexer->recording)
|
||||
{
|
||||
grub_free (old);
|
||||
lexer->record = 0;
|
||||
lexer->recordpos = 0;
|
||||
lexer->recordlen /= 2;
|
||||
lexer->recordlen = 0;
|
||||
grub_script_yyerror (parser, 0);
|
||||
return;
|
||||
}
|
||||
|
@ -131,85 +119,92 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str)
|
|||
lexer->recordpos += len;
|
||||
}
|
||||
|
||||
/* Append '\n' to SRC, before '\0' */
|
||||
static char *
|
||||
append_newline (const char *src)
|
||||
{
|
||||
char *line;
|
||||
grub_size_t len;
|
||||
|
||||
len = grub_strlen (src);
|
||||
line = grub_malloc (len + 2);
|
||||
if (!line)
|
||||
return 0;
|
||||
|
||||
grub_strcpy (line, src);
|
||||
|
||||
line[len] = '\n';
|
||||
line[len + 1] = '\0';
|
||||
return line;
|
||||
}
|
||||
|
||||
/* Read next line of input if necessary, and set yyscanner buffers. */
|
||||
int
|
||||
grub_script_lexer_yywrap (struct grub_parser_param *parserstate)
|
||||
grub_script_lexer_yywrap (struct grub_parser_param *parserstate,
|
||||
const char *input)
|
||||
{
|
||||
int len;
|
||||
char *line;
|
||||
char *line2;
|
||||
char *p = 0;
|
||||
char *line = 0;
|
||||
YY_BUFFER_STATE buffer;
|
||||
struct grub_lexer_param *lexerstate = parserstate->lexerstate;
|
||||
|
||||
if (!lexerstate->refs)
|
||||
return 0;
|
||||
if (! lexerstate->refs && ! lexerstate->prefix && ! input)
|
||||
return 1;
|
||||
|
||||
if (!lexerstate->getline)
|
||||
if (! lexerstate->getline && ! input)
|
||||
{
|
||||
grub_script_yyerror (parserstate, "unexpected end of file");
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
line = 0;
|
||||
buffer = 0;
|
||||
if (! input)
|
||||
lexerstate->getline (&line, 1);
|
||||
if (!line)
|
||||
{
|
||||
grub_script_yyerror (parserstate, 0); /* XXX this could be for ^C case? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = grub_strlen (line);
|
||||
if (line[len - 1] == '\n')
|
||||
{
|
||||
buffer = yy_scan_string (line, lexerstate->yyscanner);
|
||||
}
|
||||
else
|
||||
line = grub_strdup (input);
|
||||
|
||||
/* Ensure '\n' at the end. */
|
||||
if (line && line[0] == '\0')
|
||||
{
|
||||
line2 = append_newline (line);
|
||||
if (line2)
|
||||
{
|
||||
buffer = yy_scan_string (line2, lexerstate->yyscanner);
|
||||
grub_free (line2);
|
||||
}
|
||||
grub_free (line);
|
||||
line = grub_strdup ("\n");
|
||||
}
|
||||
|
||||
if (line && (len = grub_strlen(line)) && line[len - 1] != '\n')
|
||||
{
|
||||
p = grub_realloc (line, len + 2);
|
||||
if (p)
|
||||
{
|
||||
p[len++] = '\n';
|
||||
p[len] = '\0';
|
||||
}
|
||||
line = p;
|
||||
}
|
||||
|
||||
if (! line)
|
||||
{
|
||||
grub_script_yyerror (parserstate, "out of memory");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Prepend any left over unput-text. */
|
||||
if (lexerstate->prefix)
|
||||
{
|
||||
int plen = grub_strlen (lexerstate->prefix);
|
||||
|
||||
p = grub_malloc (len + plen + 1);
|
||||
if (! p)
|
||||
{
|
||||
grub_free (line);
|
||||
if (!buffer)
|
||||
return 1;
|
||||
}
|
||||
grub_strcpy (p, lexerstate->prefix);
|
||||
lexerstate->prefix = 0;
|
||||
|
||||
grub_strcpy (p + plen, line);
|
||||
grub_free (line);
|
||||
|
||||
line = p;
|
||||
len = len + plen;
|
||||
}
|
||||
|
||||
buffer = yy_scan_string (line, lexerstate->yyscanner);
|
||||
grub_free (line);
|
||||
|
||||
if (! buffer)
|
||||
{
|
||||
grub_script_yyerror (parserstate, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct grub_lexer_param *
|
||||
grub_script_lexer_init (struct grub_parser_param *parser, char *script,
|
||||
grub_reader_getline_t getline)
|
||||
{
|
||||
int len;
|
||||
char *script2;
|
||||
YY_BUFFER_STATE buffer;
|
||||
struct grub_lexer_param *lexerstate;
|
||||
|
||||
lexerstate = grub_zalloc (sizeof (*lexerstate));
|
||||
|
@ -232,34 +227,18 @@ grub_script_lexer_init (struct grub_parser_param *parser, char *script,
|
|||
return 0;
|
||||
}
|
||||
|
||||
buffer = 0;
|
||||
script = script ? : "\n";
|
||||
len = grub_strlen (script);
|
||||
yyset_extra (parser, lexerstate->yyscanner);
|
||||
parser->lexerstate = lexerstate;
|
||||
|
||||
if (len != 0 && script[len - 1] == '\n')
|
||||
{
|
||||
buffer = yy_scan_string (script, lexerstate->yyscanner);
|
||||
}
|
||||
else
|
||||
{
|
||||
script2 = append_newline (script);
|
||||
if (script2)
|
||||
{
|
||||
buffer = yy_scan_string (script2, lexerstate->yyscanner);
|
||||
grub_free (script2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
if (grub_script_lexer_yywrap (parser, script ?: "\n"))
|
||||
{
|
||||
parser->lexerstate = 0;
|
||||
yylex_destroy (lexerstate->yyscanner);
|
||||
grub_free (lexerstate->yyscanner);
|
||||
|
||||
grub_free (lexerstate->text);
|
||||
grub_free (lexerstate);
|
||||
return 0;
|
||||
}
|
||||
yyset_extra (parser, lexerstate->yyscanner);
|
||||
|
||||
return lexerstate;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline)
|
|||
grub_script_execute (parsed_script);
|
||||
|
||||
/* The parsed script was executed, throw it away. */
|
||||
grub_script_free (parsed_script);
|
||||
grub_script_unref (parsed_script);
|
||||
}
|
||||
|
||||
return grub_errno;
|
||||
|
@ -44,6 +44,8 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline)
|
|||
static grub_command_t cmd_break;
|
||||
static grub_command_t cmd_continue;
|
||||
static grub_command_t cmd_shift;
|
||||
static grub_command_t cmd_setparams;
|
||||
static grub_command_t cmd_return;
|
||||
|
||||
void
|
||||
grub_script_init (void)
|
||||
|
@ -54,6 +56,11 @@ grub_script_init (void)
|
|||
N_("[n]"), N_("Continue loops"));
|
||||
cmd_shift = grub_register_command ("shift", grub_script_shift,
|
||||
N_("[n]"), N_("Shift positional parameters."));
|
||||
cmd_setparams = grub_register_command ("setparams", grub_script_setparams,
|
||||
N_("[VALUE]..."),
|
||||
N_("Set positional parameters."));
|
||||
cmd_return = grub_register_command ("return", grub_script_return,
|
||||
N_("[n]"), N_("Return from a function."));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -70,4 +77,12 @@ grub_script_fini (void)
|
|||
if (cmd_shift)
|
||||
grub_unregister_command (cmd_shift);
|
||||
cmd_shift = 0;
|
||||
|
||||
if (cmd_setparams)
|
||||
grub_unregister_command (cmd_setparams);
|
||||
cmd_setparams = 0;
|
||||
|
||||
if (cmd_return)
|
||||
grub_unregister_command (cmd_return);
|
||||
cmd_return = 0;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
%{
|
||||
#include <grub/script_sh.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
#define YYFREE grub_free
|
||||
#define YYMALLOC grub_malloc
|
||||
|
@ -34,6 +35,11 @@
|
|||
struct grub_script_arglist *arglist;
|
||||
struct grub_script_arg *arg;
|
||||
char *string;
|
||||
struct {
|
||||
unsigned offset;
|
||||
struct grub_script_mem *memory;
|
||||
struct grub_script *scripts;
|
||||
};
|
||||
}
|
||||
|
||||
%token GRUB_PARSER_TOKEN_BAD
|
||||
|
@ -70,15 +76,15 @@
|
|||
%token <arg> GRUB_PARSER_TOKEN_WHILE "while"
|
||||
%token <arg> GRUB_PARSER_TOKEN_TIME "time"
|
||||
%token <arg> GRUB_PARSER_TOKEN_FUNCTION "function"
|
||||
%token <arg> GRUB_PARSER_TOKEN_MENUENTRY "menuentry"
|
||||
%token <arg> GRUB_PARSER_TOKEN_NAME "name"
|
||||
%token <arg> GRUB_PARSER_TOKEN_WORD "word"
|
||||
|
||||
%type <arg> block block0
|
||||
%type <arglist> word argument arguments0 arguments1
|
||||
|
||||
%type <cmd> script_init script
|
||||
%type <cmd> grubcmd ifclause ifcmd forcmd whilecmd untilcmd
|
||||
%type <cmd> command commands1 menuentry statement
|
||||
%type <cmd> command commands1 statement
|
||||
|
||||
%pure-parser
|
||||
%lex-param { struct grub_parser_param *state };
|
||||
|
@ -124,7 +130,6 @@ word: GRUB_PARSER_TOKEN_NAME { $$ = grub_script_add_arglist (state, 0, $1); }
|
|||
|
||||
statement: command { $$ = $1; }
|
||||
| function { $$ = 0; }
|
||||
| menuentry { $$ = $1; }
|
||||
;
|
||||
|
||||
argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); }
|
||||
|
@ -142,10 +147,77 @@ argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); }
|
|||
| "until" { $$ = grub_script_add_arglist (state, 0, $1); }
|
||||
| "while" { $$ = grub_script_add_arglist (state, 0, $1); }
|
||||
| "function" { $$ = grub_script_add_arglist (state, 0, $1); }
|
||||
| "menuentry" { $$ = grub_script_add_arglist (state, 0, $1); }
|
||||
| word { $$ = $1; }
|
||||
;
|
||||
|
||||
/*
|
||||
Block parameter is passed to commands in two forms: as unparsed
|
||||
string and as pre-parsed grub_script object. Passing as grub_script
|
||||
object makes memory management difficult, because:
|
||||
|
||||
(1) Command may want to keep a reference to grub_script objects for
|
||||
later use, so script framework may not free the grub_script
|
||||
object after command completes.
|
||||
|
||||
(2) Command may get called multiple times with same grub_script
|
||||
object under loops, so we should not let command implementation
|
||||
to free the grub_script object.
|
||||
|
||||
To solve above problems, we rely on reference counting for
|
||||
grub_script objects. Commands that want to keep the grub_script
|
||||
object must take a reference to it.
|
||||
|
||||
Other complexity comes with arbitrary nesting of grub_script
|
||||
objects: a grub_script object may have commands with several block
|
||||
parameters, and each block parameter may further contain multiple
|
||||
block parameters nested. We use temporary variable, state->scripts
|
||||
to collect nested child scripts (that are linked by siblings and
|
||||
children members), and will build grub_scripts tree from bottom.
|
||||
*/
|
||||
block: "{"
|
||||
{
|
||||
grub_script_lexer_ref (state->lexerstate);
|
||||
$<offset>$ = grub_script_lexer_record_start (state);
|
||||
$<memory>$ = grub_script_mem_record (state);
|
||||
|
||||
/* save currently known scripts. */
|
||||
$<scripts>$ = state->scripts;
|
||||
state->scripts = 0;
|
||||
}
|
||||
commands1 delimiters0 "}"
|
||||
{
|
||||
char *p;
|
||||
struct grub_script_mem *memory;
|
||||
struct grub_script *s = $<scripts>2;
|
||||
|
||||
memory = grub_script_mem_record_stop (state, $<memory>2);
|
||||
if ((p = grub_script_lexer_record_stop (state, $<offset>2)))
|
||||
*grub_strrchr (p, '}') = '\0';
|
||||
|
||||
$$ = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p);
|
||||
if (! $$ || ! ($$->script = grub_script_create ($3, memory)))
|
||||
grub_script_mem_free (memory);
|
||||
|
||||
else {
|
||||
/* attach nested scripts to $$->script as children */
|
||||
$$->script->children = state->scripts;
|
||||
|
||||
/* restore old scripts; append $$->script to siblings. */
|
||||
state->scripts = $<scripts>2 ?: $$->script;
|
||||
if (s) {
|
||||
while (s->next_siblings)
|
||||
s = s->next_siblings;
|
||||
s->next_siblings = $$->script;
|
||||
}
|
||||
}
|
||||
|
||||
grub_script_lexer_deref (state->lexerstate);
|
||||
}
|
||||
;
|
||||
block0: /* Empty */ { $$ = 0; }
|
||||
| block { $$ = $1; }
|
||||
;
|
||||
|
||||
arguments0: /* Empty */ { $$ = 0; }
|
||||
| arguments1 { $$ = $1; }
|
||||
;
|
||||
|
@ -161,12 +233,17 @@ arguments1: argument arguments0
|
|||
}
|
||||
;
|
||||
|
||||
grubcmd: word arguments0
|
||||
grubcmd: word arguments0 block0
|
||||
{
|
||||
if ($1 && $2) {
|
||||
$1->next = $2;
|
||||
$1->argcount += $2->argcount;
|
||||
$2->argcount = 0;
|
||||
struct grub_script_arglist *x = $2;
|
||||
|
||||
if ($3)
|
||||
x = grub_script_add_arglist (state, $2, $3);
|
||||
|
||||
if ($1 && x) {
|
||||
$1->next = x;
|
||||
$1->argcount += x->argcount;
|
||||
x->argcount = 0;
|
||||
}
|
||||
$$ = grub_script_create_cmdline (state, $1);
|
||||
}
|
||||
|
@ -195,6 +272,9 @@ function: "function" "name"
|
|||
{
|
||||
grub_script_lexer_ref (state->lexerstate);
|
||||
state->func_mem = grub_script_mem_record (state);
|
||||
|
||||
$<scripts>$ = state->scripts;
|
||||
state->scripts = 0;
|
||||
}
|
||||
delimiters0 "{" commands1 delimiters1 "}"
|
||||
{
|
||||
|
@ -202,30 +282,18 @@ function: "function" "name"
|
|||
state->func_mem = grub_script_mem_record_stop (state,
|
||||
state->func_mem);
|
||||
script = grub_script_create ($6, state->func_mem);
|
||||
if (script)
|
||||
if (! script)
|
||||
grub_script_mem_free (state->func_mem);
|
||||
else {
|
||||
script->children = state->scripts;
|
||||
grub_script_function_create ($2, script);
|
||||
}
|
||||
|
||||
state->scripts = $<scripts>3;
|
||||
grub_script_lexer_deref (state->lexerstate);
|
||||
}
|
||||
;
|
||||
|
||||
menuentry: "menuentry"
|
||||
{
|
||||
grub_script_lexer_ref (state->lexerstate);
|
||||
}
|
||||
arguments1
|
||||
{
|
||||
grub_script_lexer_record_start (state);
|
||||
}
|
||||
delimiters0 "{" commands1 delimiters1 "}"
|
||||
{
|
||||
char *menu_entry;
|
||||
menu_entry = grub_script_lexer_record_stop (state);
|
||||
grub_script_lexer_deref (state->lexerstate);
|
||||
$$ = grub_script_create_cmdmenu (state, $3, menu_entry, 0);
|
||||
}
|
||||
;
|
||||
|
||||
ifcmd: "if"
|
||||
{
|
||||
grub_script_lexer_ref (state->lexerstate);
|
||||
|
|
|
@ -54,7 +54,7 @@ grub_script_malloc (struct grub_parser_param *state, grub_size_t size)
|
|||
}
|
||||
|
||||
/* Free all memory described by MEM. */
|
||||
static void
|
||||
void
|
||||
grub_script_mem_free (struct grub_script_mem *mem)
|
||||
{
|
||||
struct grub_script_mem *memfree;
|
||||
|
@ -94,9 +94,21 @@ grub_script_mem_record_stop (struct grub_parser_param *state,
|
|||
void
|
||||
grub_script_free (struct grub_script *script)
|
||||
{
|
||||
if (!script)
|
||||
struct grub_script *s;
|
||||
struct grub_script *t;
|
||||
|
||||
if (! script)
|
||||
return;
|
||||
|
||||
if (script->mem)
|
||||
grub_script_mem_free (script->mem);
|
||||
|
||||
s = script->children;
|
||||
while (s) {
|
||||
t = s->next_siblings;
|
||||
grub_script_unref (s);
|
||||
s = t;
|
||||
}
|
||||
grub_free (script);
|
||||
}
|
||||
|
||||
|
@ -119,6 +131,8 @@ grub_script_arg_add (struct grub_parser_param *state,
|
|||
return arg;
|
||||
|
||||
argpart->type = type;
|
||||
argpart->script = 0;
|
||||
|
||||
len = grub_strlen (str) + 1;
|
||||
argpart->str = grub_script_malloc (state, len);
|
||||
if (!argpart->str)
|
||||
|
@ -267,30 +281,6 @@ grub_script_create_cmdwhile (struct grub_parser_param *state,
|
|||
return (struct grub_script_cmd *) cmd;
|
||||
}
|
||||
|
||||
/* Create a command that adds a menu entry to the menu. Title is an
|
||||
argument that is parsed to generate a string that can be used as
|
||||
the title. The sourcecode for this entry is passed in SOURCECODE.
|
||||
The options for this entry are passed in OPTIONS. */
|
||||
struct grub_script_cmd *
|
||||
grub_script_create_cmdmenu (struct grub_parser_param *state,
|
||||
struct grub_script_arglist *arglist,
|
||||
char *sourcecode, int options)
|
||||
{
|
||||
struct grub_script_cmd_menuentry *cmd;
|
||||
|
||||
cmd = grub_script_malloc (state, sizeof (*cmd));
|
||||
if (!cmd)
|
||||
return 0;
|
||||
|
||||
cmd->cmd.exec = grub_script_execute_menuentry;
|
||||
cmd->cmd.next = 0;
|
||||
cmd->sourcecode = sourcecode;
|
||||
cmd->arglist = arglist;
|
||||
cmd->options = options;
|
||||
|
||||
return (struct grub_script_cmd *) cmd;
|
||||
}
|
||||
|
||||
/* Create a chain of commands. LAST contains the command that should
|
||||
be added at the end of LIST's list. If LIST is zero, a new list
|
||||
will be created. */
|
||||
|
@ -335,16 +325,14 @@ grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem)
|
|||
struct grub_script *parsed;
|
||||
|
||||
parsed = grub_malloc (sizeof (*parsed));
|
||||
if (!parsed)
|
||||
{
|
||||
grub_script_mem_free (mem);
|
||||
grub_free (cmd);
|
||||
|
||||
if (! parsed)
|
||||
return 0;
|
||||
}
|
||||
|
||||
parsed->mem = mem;
|
||||
parsed->cmd = cmd;
|
||||
parsed->refcnt = 0;
|
||||
parsed->children = 0;
|
||||
parsed->next_siblings = 0;
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
@ -359,7 +347,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline)
|
|||
struct grub_lexer_param *lexstate;
|
||||
struct grub_parser_param *parsestate;
|
||||
|
||||
parsed = grub_malloc (sizeof (*parsed));
|
||||
parsed = grub_script_create (0, 0);
|
||||
if (!parsed)
|
||||
return 0;
|
||||
|
||||
|
@ -397,6 +385,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline)
|
|||
|
||||
parsed->mem = grub_script_mem_record_stop (parsestate, membackup);
|
||||
parsed->cmd = parsestate->parsed;
|
||||
parsed->children = parsestate->scripts;
|
||||
|
||||
grub_script_lexer_fini (lexstate);
|
||||
grub_free (parsestate);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue