diff --git a/.bzrignore b/.bzrignore index 56e3516b5..46e8637b6 100644 --- a/.bzrignore +++ b/.bzrignore @@ -25,6 +25,8 @@ docs/version.texi *.exec genkernsyms.sh gensymlist.sh +gentrigtables +grub-bin2h grub-dumpbios grub-editenv grub-emu @@ -35,12 +37,18 @@ grub_fstest_init.c grub_fstest_init.h grub-install grub-mk* +grub-pbkdf2 grub-pe2elf grub-probe grub_probe_init.c grub_probe_init.h +grub-reboot +grub-script-check +grub_script_check_init.c +grub_script_check_init.h grub_script.tab.c grub_script.tab.h +grub-set-default grub-setup grub_setup_init.c grub_setup_init.h @@ -61,4 +69,5 @@ stamp-h stamp-h1 stamp-h.in symlist.c +trigtables.c update-grub_lib diff --git a/ChangeLog b/ChangeLog index 573ac3bf0..02d16e835 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5329 @@ +2010-05-21 Vladimir Serbinenko + + * kern/i386/pc/mmap.c (grub_machine_mmap_iterate): Zero-fill entry + before calling BIOS. + +2010-05-21 Vladimir Serbinenko + + * include/grub/i18n.h: Always enable grub_gettext. + +2010-05-21 Vladimir Serbinenko + + * kern/i386/pc/init.c (make_install_device): Fix a leftover usage of old + partition naming style. + +2010-05-21 Colin Watson + + * util/grub-mkconfig.in: Fix handling of -o so that it works when + not the first option. + +2010-05-20 Colin Watson + + * util/grub-mkrelpath.c (usage): Remove excess apostrophe. + +2010-05-20 Colin Watson + + * util/misc.c: Move inclusion of to ... + * kern/emu/misc.c: ... here. Needed for canonicalize_file_name. + +2010-05-20 Grégoire Sutre + + * kern/emu/hostdisk.c (grub_util_biosdisk_get_grub_dev) [__NetBSD__]: + Fix merge error in NetBSD code. + (find_partition_start) [__NetBSD__]: Likewise. + +2010-05-19 BVK Chaitanya + + Fix grub-mkrescue usage unit testing. + + * tests/util/grub-shell.in: Use --grub-mkimage with grub-mkrescue. + +2010-05-18 Christian Franke + + * util/grub.d/10_windows.in: Use path names instead of + drive letters to prevent warning from Cygwin 1.7. + Add drivemap command to menuentry if needed. + +2010-05-18 Justus Winter <4winter@informatik.uni-hamburg.de> + + * util/grub.d/10_hurd.in: Include all gnumach* kernels, not only + gnumach and gnumach.gz. + +2010-05-18 Vladimir Serbinenko + + * include/grub/i18n.h (gettext): Inline instead of using #define. + (grub_gettext): Likewise. + (_): Likewise. + +2010-05-18 Vladimir Serbinenko + + * Makefile.in (CPPFLAGS): Replace -DGRUB_LIBDIR with + -DGRUB_PKGLIBROOTDIR= and prepend @PACKAGE_TARNAME@. All users updated. + * util/grub-mkimage.c (image_targets): Add i386-multiboot. + (main): Add a slash after pkglibdirroot. + +2010-05-18 Vladimir Serbinenko + + * util/grub-install.in: Add missing "in" keyword. + +2010-05-18 Vladimir Serbinenko + + * util/grub-mkrescue.in: Remove -O i386-pc duplication. + Reported by: Seth Goldberg. + +2010-05-18 Vladimir Serbinenko + + * po/POTFILES: Rename util/grub-mkrawimage.c to util/grub-mkimage.c. + +2010-05-18 Colin Watson + + * configure.ac: Check for Linux device-mapper support. + + * util/hostdisk.c (device_is_mapped): New function. + (find_partition_start): New function, partly broken out from + linux_find_partition and grub_util_biosdisk_get_grub_dev but with + device-mapper support added. + (linux_find_partition): Use find_partition_start. + (convert_system_partition_to_system_disk): Add `st' argument. + Support Linux /dev/mapper/* devices if device-mapper support is + available; only DM-RAID devices are understood at present. + (find_system_device): Add `st' argument. Pass it to + convert_system_partition_to_system_disk. + (grub_util_biosdisk_get_grub_dev): Pass stat result to + find_system_device and convert_system_partition_to_system_disk. Use + find_partition_start. + + * conf/common.rmk (grub_mkdevicemap_SOURCES): Add kern/env.c, + kern/err.c, kern/list.c, kern/misc.c, and kern/emu/mm.c. + * util/deviceiter.c [__linux__]: Define MINOR. + (grub_util_iterate_devices): Add support for DM-RAID disk devices. + * util/mkdevicemap.c (grub_putchar): New function. + (grub_getkey): New function. + (grub_refresh): New function. + (main): Set debug=all if -v -v is used. + +2010-05-18 Colin Watson + + Fix build with non-GNU libcs. + + * util/misc.c (canonicalize_file_name): Move to ... + * kern/emu/misc.c (canonicalize_file_name): ... here. Needed by + grub_make_system_path_relative_to_its_root. + +2010-05-18 Colin Watson + + * util/grub-mkrescue.in: Sync up with grub-install in terms of how + we handle finding grub-mkimage. Default to finding grub-mkimage in + ${bindir} with program_transform_name applied, and provide a + --grub-mkimage option to override this. + +2010-05-17 Vladimir Serbinenko + + Remove grub-mkisofs. + + * conf/common.rmk (bin_UTILITIES): Remove grub-mkisofs. + (grub_mkisofs_SOURCES): Removed. + (grub_mkisofs_CFLAGS): Removed. + * util/mkisofs/defaults.h: Removed. + * util/mkisofs/eltorito.c: Likewise. + * util/mkisofs/exclude.h: Likewise. + * util/mkisofs/hash.c: Likewise. + * util/mkisofs/include/: Likewise. + * util/mkisofs/include/fctldefs.h: Likewise. + * util/mkisofs/include/mconfig.h: Likewise. + * util/mkisofs/include/prototyp.h: Likewise. + * util/mkisofs/include/statdefs.h: Likewise. + * util/mkisofs/iso9660.h: Likewise. + * util/mkisofs/joliet.c: Likewise. + * util/mkisofs/match.c: Likewise. + * util/mkisofs/match.h: Likewise. + * util/mkisofs/mkisofs.c: Likewise. + * util/mkisofs/mkisofs.h: Likewise. + * util/mkisofs/msdos_partition.h: Likewise. + * util/mkisofs/multi.c: Likewise. + * util/mkisofs/name.c: Likewise. + * util/mkisofs/rock.c: Likewise. + * util/mkisofs/tree.c: Likewise. + * util/mkisofs/write.c: Likewise. + +2010-05-17 Vladimir Serbinenko + + Unify grub-mkimage accross platforms. + + * Makefile.in (CPPFLAGS): Set GRUB_LIBDIR to $(libdir). + * conf/common.rmk (bin_UTILITIES): Removed grub-mkelfimage. + (grub_mkelfimage_SOURCES): Removed. + (util/elf/grub-mkimage.c_DEPENDENCIES): Renamed to .. + (util/grub-mkimage.c_DEPENDENCIES): .. this. + (bin_UTILITIES): Add grub-mkimage. + (grub_mkimage_SOURCES): New variable. + (kernel_img_HEADERS): Remove machine/kernel.h. + * conf/i386-pc.rmk (pkglib_IMAGES): Remove kernel.img. + (pkglib_PROGRAMS): Add kernel.img. + (kernel_img_HEADERS): Add machine/kernel.h. + (kernel_img_FORMAT): Removed. + (bin_UTILITIES): Remove grub-mkimage. + (grub_mkimage_SOURCES): Removed. + (grub_mkimage_CFLAGS): Likewise. + (util/grub-mkrawimage.c_DEPENDENCIES): Likewise. + * conf/i386-qemu.rmk (pkglib_IMAGES): Remove kernel.img. + (pkglib_PROGRAMS): Add kernel.img. + (bin_UTILITIES): Remove grub-mkimage. + (grub_mkimage_SOURCES): Removed. + (grub_mkimage_CFLAGS): Likewise. + (util/grub-mkrawimage.c_DEPENDENCIES): Likewise. + * conf/mips-qemu-mips.rmk (pkglib_IMAGES): Remove kernel.img. + (pkglib_PROGRAMS): Add kernel.img. + * conf/mips-yeeloong.rmk (pkglib_IMAGES): Remove kernel.img. + (pkglib_PROGRAMS): Add kernel.img. + * conf/mips.rmk (bin_UTILITIES): Remove grub-mkimage. + (grub_mkimage_SOURCES): Removed. + (grub_mkimage_CFLAGS): Likewise. + (util/grub-mkrawimage.c_DEPENDENCIES): Likewise. + * conf/sparc64-ieee1275.rmk (pkglib_IMAGES): Remove kernel.img. + (pkglib_PROGRAMS): Add kernel.img. + (bin_UTILITIES): Remove grub-mkimage. + (grub_mkimage_SOURCES): Removed. + (grub_mkimage_CFLAGS): Likewise. + (util/grub-mkrawimage.c_DEPENDENCIES): Likewise. + * conf/x86-efi.rmk (bin_UTILITIES): Remove grub-mkimage. + (grub_mkimage_SOURCES): Removed. + (grub_mkimage_CFLAGS): Likewise. + (util/grub-mkrawimage.c_DEPENDENCIES): Likewise. + * configure.ac (machine_CFLAGS): Add "-DMACHINE". + * include/grub/efi/pe32.h (grub_pe32_optional_header): Split into ... + (grub_pe32_optional_header): ... this. + (grub_pe64_optional_header): ... and this. All users updated. + (GRUB_PE32_PE32_MAGIC): Split into .. + (GRUB_PE32_PE32_MAGIC): .. this. + (GRUB_PE32_PE64_MAGIC): .. and this. + (GRUB_PE32_SIGNATURE_SIZE): New definition. + * include/grub/elf.h (PT_GNU_STACK): New definition. + * include/grub/i386/coreboot/kernel.h: Merged into include/grub/offsets.h. All users updated. + * include/grub/i386/efi/kernel.h: Likewise. + * include/grub/i386/kernel.h: Likewise. + * include/grub/i386/pc/kernel.h: Likewise. + * include/grub/i386/qemu/boot.h: Likewise. + * include/grub/mips/kernel.h: Likewise. + * include/grub/mips/qemu-mips/kernel.h: Likewise. + * include/grub/powerpc/ieee1275/kernel.h: Likewise. + * include/grub/powerpc/kernel.h: Likewise. + * include/grub/sparc64/ieee1275/boot.h: Likewise. + * include/grub/sparc64/ieee1275/kernel.h: Likewise. + * include/grub/sparc64/kernel.h: Likewise. + * include/grub/x86_64/efi/kernel.h: Likewise. + * include/grub/x86_64/kernel.h: Likewise. + * include/grub/offsets.h: New file. + * include/grub/kernel.h (grub_module_info): Split into ... + (grub_module_info32): ... this. + (grub_module_info64): ... and this. + * include/grub/i386/pc/boot.h (GRUB_BOOT_MACHINE_KERNEL_SEG): Moved from here ... + * include/grub/offsets.h (GRUB_BOOT_I386_PC_KERNEL_SEG): ... here. + (grub_boot_blocklist): Moved from here ... + * include/grub/offsets.h (grub_pc_bios_boot_blocklist): ... here. + * include/grub/i386/pc/memory.h (GRUB_MEMORY_MACHINE_UPPER): Moved from here. + * include/grub/offsets.h (GRUB_MEMORY_I386_PC_UPPER): .. here. + * include/grub/types.h (grub_target_to_host16): Removed. + (grub_target_to_host32): Likewise. + (grub_target_to_host64): Likewise. + (grub_host_to_target16): Likewise. + (grub_host_to_target32): Likewise. + (grub_host_to_target64): Likewise. + (grub_host_to_target_addr): Likewise. + + Support grub-mkrescue for efi, coreboot and qemu. + + * conf/x86-efi.rmk (bin_SCRIPTS): Add grub-mkrescue. + * kern/efi/init.c (grub_efi_set_prefix): Handle baked in prefix. + * util/elf/grub-mkimage.c: Merged into util/grub-mkimage.c. + * util/grub-mkrawimage.c: Moved from here ... + * util/grub-mkimage.c: ... here. All users updated. + (ALIGN_ADDR): Use image_target. + (TARGET_NO_FIELD): New const. + (image_target_desc): New type. + (image_targets): New array. + (grub_target_to_host64): Use image_target. + (grub_target_to_host32): Likewise. + (grub_target_to_host16): Likewise. + (grub_host_to_target64): Likewise. + (grub_host_to_target32): Likewise. + (grub_host_to_target16): Likewise. + (grub_host_to_target_addr): Likewise. + (generate_image): Handle multiimage. + (main): Require -O parameter. All users updated. + * util/grub-mkimagexx.c: New file. Based on util/grub-mkrawimage.c and + util/efi/grub-mkimage.c + * util/grub-mkrescue.in: Handle coreboot, efi and qemu. + New option --rom-directory. + Use xorriso. + * util/i386/efi/grub-mkimage.c: Removed. + * util/i386/pc/grub-setup.c (grub_target_to_host16): New definition. + (grub_target_to_host32): Likewise. + (grub_target_to_host64): Likewise. + (grub_host_to_target16): Likewise. + (grub_host_to_target32): Likewise. + (grub_host_to_target64): Likewise. + * util/sparc64/ieee1275/grub-setup.c (grub_target_to_host16): New definition. + (grub_target_to_host32): Likewise. + (grub_target_to_host64): Likewise. + (grub_host_to_target16): Likewise. + (grub_host_to_target32): Likewise. + (grub_host_to_target64): Likewise. + +2010-05-17 BVK Chaitanya + + Source tree is reorganized for emu build. + + * include/grub/util/console.h: Move from here... + * include/grub/emu/console.h: ...to here. + * include/grub/util/getroot.h: Move from here... + * include/grub/emu/getroot.h: ...to here. + * include/grub/util/hostdisk.h: Move from here... + * include/grub/emu/hostdisk.h: ...to here. + * util/console.c: Move from here... + * kern/emu/console.c: ...to here. + * util/getroot.c: Move from here... + * kern/emu/getroot.c: ...to here. + * util/grub-emu.c: Move from here... + * kern/emu/main.c: ...to here. + * util/hostdisk.c: Move from here... + * kern/emu/hostdisk.c: ...to here. + * util/hostfs.c: Move from here... + * kern/emu/hostfs.c: ...to here. + * util/mm.c: Move from here... + * kern/emu/mm.c: ...to here. + * util/pci.c: Move from here... + * bus/emu/pci.c: ...to here. + * util/sdl.c: Move from here... + * video/emu/sdl.c: ...to here. + * util/time.c: Move from here... + * kern/emu/time.c: ...to here. + * util/usb.c: Move from here... + * bus/usb/emu/usb.c: ...to here. + + * include/grub/emu/misc.h: New header for grub-emu functions. + * kern/emu/misc.c: grub-emu functions separated from util/misc.c + + * conf/any-emu.rmk: Rule updates for above renames. + * conf/common.rmk: Likewise. + * conf/i386-pc.rmk: Likewise. + * conf/i386-qemu.rmk: Likewise. + * conf/mips.rmk: Likewise. + * conf/sparc64-ieee1275.rmk: Likewise. + * conf/x86-efi.rmk: Likewise. + + * disk/lvm.h: #include updates for above renames. + * util/grub-mkrelpath.c: Likewise. + * util/grub-probe.c: Likewise. + * util/i386/pc/grub-setup.c: Likewise. + * util/sparc64/ieee1275/grub-setup.c: Likewise. + * kern/emu/console.c: Likewise. + * kern/emu/getroot.c: Likewise. + * kern/emu/hostdisk.c: Likewise. + * kern/emu/main.c: Likewise. (was grub-emu.c earlier) + + * include/grub/dl.h: Remove grub_dl_{ref,unref}. + * include/grub/util/misc.h: Move grub-emu functions to emu/misc.h. + * kern/dl.c: Handle null mod in grub_dl_{ref,unref}. + * util/misc.c: Remove grub-emu functions. + +2010-05-13 Vladimir Serbinenko + + Fix gfxmenu crash. + Reported by: Thorsten Grützmacher. + + * gfxmenu/gui_circular_progress.c (circprog_destroy): Unregister + timeout hook. + (circprog_set_property): Register and unregister timeout hook. + * gfxmenu/gui_label.c (grub_gui_label): New fields template and value. + (label_destroy): Free template. and unregister hook. + (label_set_state): New function. + (label_set_property): Handle templates and hooks. + * gfxmenu/gui_progress_bar.c (progress_bar_destroy): Unregister + timeout hook. + (progress_bar_set_property): Register and unregister timeout hook. + * gfxmenu/view.c (TIMEOUT_COMPONENT_ID): Move from here ... + * include/grub/gui.h (GRUB_GFXMENU_TIMEOUT_COMPONENT_ID): ...to here + * gfxmenu/view.c (grub_gfxmenu_timeout_notifications): New variable. + (update_timeout_visit): Removed. + (update_timeouts): New function. + (redraw_timeouts): Likewise. + (grub_gfxmenu_print_timeout): Use update_timeouts and redraw_timeouts. + (grub_gfxmenu_clear_timeout): Likewise. + * include/grub/gui.h (grub_gfxmenu_set_state_t): New type. + (grub_gfxmenu_timeout_notify): Likewise. + (grub_gfxmenu_timeout_notifications): New external variable. + (grub_gfxmenu_timeout_register): New function. + (grub_gfxmenu_timeout_unregister): Likewise. + +2010-05-09 Vladimir Serbinenko + + Transform (broken) vga terminal into (working) vga video driver. + + * conf/i386-pc.rmk (vga_mod_SOURCES): Change term/i386/pc/vga.c to + video/i386/pc/vga.c. + * include/grub/video.h (grub_video_driver_id): + Add GRUB_VIDEO_DRIVER_VGA. + * term/i386/pc/vga.c: Renamed to ... + * video/i386/pc/vga.c: ...this + (DEBUG_VGA): Removed. + (CHAR_WIDTH): Likewise. + (CHAR_HEIGHT): Likewise. + (TEXT_WIDTH): Likewise. + (TEXT_HEIGHT): Likewise. + (DEFAULT_FG_COLOR): Likewise. + (DEFAULT_BG_COLOR): Likewise. + (colored_char): Likewise. + (xpos): Likewise. + (ypos): Likewise. + (cursor_state): Likewise. + (fg_color): Likewise. + (bg_color): Likewise. + (text_buf): Likewise. + (page): Likewise. + (font): Likewise. + (framebuffer): New variable. + (set_read_map): Disabled. + (setup): New variable. + (is_target): Likewise. + (grub_vga_mod_init): Likewise. + (grub_vga_mod_fini): Likewise. + (check_vga_mem): Likewise. + (write_char): Likewise. + (write_cursor): Likewise. + (scroll_up): Likewise. + (grub_vga_putchar): Likewise. + (grub_vga_getcharwidth): Likewise. + (grub_vga_getwh): Likewise. + (grub_vga_getxy): Likewise. + (grub_vga_gotoxy): Likewise. + (grub_vga_cls): Likewise. + (grub_vga_setcolorstate): Likewise. + (grub_vga_setcursor): Likewise. + (grub_video_vga_init): New function. + (grub_video_vga_setup): Likewise. + (grub_video_vga_fini): Likewise. + (update_target): Likewise. + (grub_video_vga_blit_bitmap): Likewise. + (grub_video_vga_blit_render_target): Likewise. + (grub_video_vga_set_active_render_target): Likewise. + (grub_video_vga_get_active_render_target): Likewise. + (grub_video_vga_swap_buffers): Likewise. + (grub_video_vga_set_palette): Likewise. + (grub_video_vga_get_info_and_fini): Likewise. + (grub_vga_term): Removed. + (grub_video_vga_adapter): New variable. + (GRUB_MOD_INIT): Register a video driver instead of terminal. + (GRUB_MOD_FINI): Unrefister a video driver instead of terminal. + +2010-05-05 Vladimir Serbinenko + + * video/readers/jpeg.c: Indented. + +2010-05-05 Vladimir Serbinenko + + Various jpeg cleanups. + + * video/readers/jpeg.c (grub_jpeg_get_huff_code): Use ARRAY_SIZE. + (grub_jpeg_decode_quan_table): Use sizeof. + (grub_jpeg_decode_du): Use ARRAY_SIZE. + +2010-05-05 Peter Hurley (tiny change) + + * video/readers/jpeg.c (grub_jpeg_decode_huff_table): Loop over all + tables. Ignore non-last ac bit. + (grub_jpeg_decode_quan_table): Likewise. + +2010-05-05 Vladimir Serbinenko + + * include/grub/ieee1275/ieee1275.h (grub_ieee1275_flag): New value + GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM. + * kern/ieee1275/cmain.c (grub_ieee1275_find_options): Set + GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM on qemu. + * kern/ieee1275/init.c (grub_claim_heap): Don0t allocate below + 1.5MiB if GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM is set. + +2010-05-05 Vladimir Serbinenko + + * term/ieee1275/ofconsole.c (grub_ofconsole_getkey): Fix off-by-one + error. + +2010-05-05 Vladimir Serbinenko + + * term/ieee1275/ofconsole.c (grub_ofconsole_readkey): Support C0 code. + +2010-05-03 Vladimir Serbinenko + + * commands/parttool.c (grub_cmd_parttool): Fix #if !GRUB_NO_MODULES + condition. + +2010-05-03 Vladimir Serbinenko + + * kern/mm.c (grub_real_malloc): Put magic and size assignment in common + part. + +2010-05-03 Vladimir Serbinenko + + * kern/mm.c (grub_mm_init_region): Check for region size after aligning + pointers. + +2010-05-03 Vladimir Serbinenko + + * kern/mm.c (grub_real_malloc): Fix size calculation when extra == 0. + +2010-05-01 Christian Franke + + * util/grub-mkconfig_lib.in (make_system_path_relative_to_its_root): + Remove broken Cygwin path conversion. + * util/misc.c: [__CYGWIN__] Add include and define. + [__CYGWIN__] (get_win32_path): Copy function from getroot.c, modify + for Cygwin 1.7. + (make_system_path_relative_to_its_root): Simplify loop, replace early + return by break. + [__CYGWIN__] Add conversion to win32 path. + Include "/" case in trailing slash removal. + +2010-05-01 Vladimir Serbinenko + + * kern/main.c (grub_load_config): Fix copy-pasted comment. + Reported by: Seth Goldberg + +2010-05-01 Vladimir Serbinenko + + * commands/help.c (grub_cmd_help): Fix a typo. + Reported by: Seth Goldberg + +2010-05-01 Vladimir Serbinenko + + * commands/hashsum.c (GRUB_MOD_INIT): Remove duplication of command + name and add N_. + * commands/i386/pc/drivemap.c (GRUB_MOD_INIT): Likewise. + * commands/iorw.c (GRUB_MOD_INIT): Likewise. + * commands/password_pbkdf2.c (GRUB_MOD_INIT): Likewise. + * commands/regexp.c (GRUB_MOD_INIT): Likewise. + * commands/setpci.c (GRUB_MOD_INIT): Likewise. + * commands/terminal.c (GRUB_MOD_INIT): Likewise. + * efiemu/main.c (GRUB_MOD_INIT): Likewise. + * font/font_cmd.c (GRUB_MOD_INIT): Likewise. + * kern/corecmd.c (GRUB_MOD_INIT): Likewise. + * mmap/mmap.c (GRUB_MOD_INIT): Likewise. + * normal/context.c (GRUB_MOD_INIT): Likewise. + * normal/main.c (GRUB_MOD_INIT): Likewise. + * term/gfxterm.c (GRUB_MOD_INIT): Likewise. + * term/serial.c (GRUB_MOD_INIT): Likewise. + * term/terminfo.c (GRUB_MOD_INIT): Likewise. + +2010-05-01 Vladimir Serbinenko + + * kern/mm.c (grub_real_malloc): Satisfy alignment requirement when + extra == 0. + +2010-05-01 Vladimir Serbinenko + + * commands/iorw.c: New file. + * conf/i386.rmk (pkglib_MODULES): Add iorw.mod. + (iorw_mod_SOURCES): New variable. + (iorw_mod_CFLAGS): Likewise. + (iorw_mod_LDFLAGS): Likewise. + +2010-05-01 Vladimir Serbinenko + + Hotkey support + + * include/grub/menu.h (grub_menu_entry): New field 'hotkey'. + * normal/main.c (hotkey_aliases): New variable. + (grub_normal_add_menu_entry): Parse "--hotkey". + * normal/menu_text.c (run_menu): Handle hotkeys. + +2010-05-01 Vladimir Serbinenko + + * kern/i386/coreboot/init.c (grub_machine_init): Call + grub_machine_mmap_init on qemu. + +2010-05-01 Vladimir Serbinenko + + * boot/i386/qemu/boot.S: Add a missing .code16. + +2010-05-01 Vladimir Serbinenko + + Use LBIO on coreboot. + + * conf/i386-coreboot.rmk (kernel_img_SOURCES): Change + kern/i386/multiboot_mmap.c to kern/i386/coreboot/mmap.c. + * include/grub/i386/coreboot/memory.h (GRUB_LINUXBIOS_MEMBER_LINK): + New declaration. + * kern/i386/coreboot/init.c (grub_machine_init): Don't call + grub_machine_mmap_init on coreboot. + * kern/i386/coreboot/mmap.c (grub_linuxbios_table_iterate): Handle + GRUB_LINUXBIOS_MEMBER_LINK. + (grub_machine_mmap_iterate): Fix declaration. + * kern/i386/coreboot/startup.S: Don't save mbi location on coreboot. + +2010-05-01 Vladimir Serbinenko + + Split coreboot and multiboot ports. + + * conf/i386-multiboot.rmk: New file. + * configure.ac: Add multiboot port. + * include/grub/i386/multiboot/boot.h: New file. + * include/grub/i386/multiboot/console.h: Likewise. + * include/grub/i386/multiboot/init.h: Likewise. + * include/grub/i386/multiboot/kernel.h: Likewise. + * include/grub/i386/multiboot/loader.h: Likewise. + * include/grub/i386/multiboot/memory.h: Likewise. + * include/grub/i386/multiboot/serial.h: Likewise. + * include/grub/i386/multiboot/time.h: Likewise. + * include/grub/multiboot.h: Add GRUB_MACHINE_MULTIBOOT to ifdef. + * loader/multiboot.c: Likewise. + * loader/multiboot_mbi2.c: Likewise. + * util/grub-mkrescue.in: Generate multiboot rescue. + +2010-05-01 Vladimir Serbinenko + + * kern/parser.c (grub_parser_execute): Cope with read-only config. + +2010-05-01 Vladimir Serbinenko + + Merge handling of input and output terminals. Fix a hang. + + * commands/terminal.c (abstract_terminal): New struct. + (handle_command): New function. Based on grub_cmd_terminal_input. + (grub_cmd_terminal_input): Use handle_command. + (grub_cmd_terminal_output): Use handle_command. + +2010-05-01 BVK Chaitanya + + Fix comment handling. + + * tests/grub_script_comments.in: New testcase. + * conf/tests.rmk: Rules for new testcase. + * script/yylex.l: Updated flex rules. + +2010-04-28 Samuel Thibault + + * docs/grub.texi (play): Document that zero pitches produce rests. + * commands/i386/pc/play.c (grub_cmd_play): Call 'grub_file_open' only + if argc is 1. + +2010-04-27 Vladimir Serbinenko + + * conf/x86-efi.rmk (linux_mod_SOURCES): Write explicitly to avoid + autogen issues. + +2010-04-26 Christian Franke + + * include/grub/util/getroot.h (grub_get_prefix): Remove prototype. + * util/getroot.c [__CYGWIN__] (get_win32_path): Remove function. + (grub_get_prefix): Remove function. + * util/grub-emu.c (main): Replace grub_get_prefix () call by + make_system_path_relative_to_its_root (). + * util/sparc64/ieee1275/grub-setup.c (main): Likewise. + +2010-04-24 Christian Franke + + * Makefile.in (TARGET_LDFLAGS): Add -static-libgcc. + (kernel_img_LDFLAGS): Remove -static-libgcc. + +2010-04-24 Christian Franke + + * configure.ac: Do not CHECK_BSS_START_SYMBOL + and CHECK_END_SYMBOL if grub-emu is built. + Unset TARGET_OBJ2ELF if grub-emu is built + without module support. + +2010-04-24 Jiro SEKIBA + + Nilfs2 support. + + * conf/common.rmk (grub_probe_SOURCES): Add fs/nilfs2.c. + (grub_fstest_SOURCES): Likewise. + (pkglib_MODULES): Add nilfs2.mod. + (nilfs2_mod_SOURCES): New variable. + (nilfs2_mod_CFLAGS): Likewise. + (nilfs2_mod_LDFLAGS): Likewise. + * conf/i386-pc.rmk (grub_setup_SOURCES): Add fs/nilfs2.c. + * conf/sparc64-ieee1275.rmk (grub_setup_SOURCES): Add fs/nilfs2.c. + * fs/nilfs2.c: New file. + +2010-04-21 Vladimir Serbinenko + + * configure.ac: Refuse to compile for x86_64-efi is mcmodel=large + is not supported. + +2010-04-19 Grégoire Sutre + + Add grub-mkconfig support for NetBSD. + + * util/grub.d/10_netbsd.in: grub-mkconfig helper script for NetBSD. + * util/grub-mkconfig.in: export new NetBSD specific variables. + * po/POTFILES-shell: added 10_netbsd.in. + * util/grub-mkconfig_lib.in: check for gettext binary, default to echo. + +2010-04-19 BVK Chaitanya + + Fix emu build with grub-emu-pci and grub-emu-modules. + + * include/grub/util/misc.h: Export grub_util_{info,error,warn} + functions. + * include/grub/libpciaccess.h: New file. + * conf/any-emu.rmk: Update kernel headers for emu build. + +2010-04-19 Vladimir Serbinenko + + * fs/udf.c (grub_udf_iterate_dir): Silence a spurious warning. + +2010-04-19 Vladimir Serbinenko + + * fs/udf.c (grub_udf_iterate_dir): Decode the Unicode filenames. + +2010-04-18 Vladimir Serbinenko + + * boot/sparc64/ieee1275/boot.S: Various size-reducing changes. + Retrieve chosen/bootpath if bootpath isn't hardcoded. + * conf/sparc64-ieee1275.rmk (grub_setup_SOURCES): Add + util/ieee1275/ofpath.c. + * util/sparc64/ieee1275/grub-ofpathname.c: Renamed to ... + * util/ieee1275/grub-ofpathname.c: ... this. All users updated + * include/grub/sparc64/ieee1275/boot.h + (GRUB_BOOT_MACHINE_KERNEL_SECTOR): Renamed to ... + (GRUB_BOOT_MACHINE_KERNEL_BYTE): ...this. Moved 8 bytes lower. + * util/hostdisk.c (grub_util_biosdisk_get_osdev): New function. + * util/ieee1275/ofpath.c (grub_util_devname_to_ofpath): Make argument + const char *. + * util/sparc64/ieee1275/grub-setup.c (compute_dest_ofpath): Removed. + (setup): Use KERNEL_BYTE instead of KERNEL_SECTOR. + Use grub_util_devname_to_ofpath. Zero-fill boot_devpath on same disk + install. + +2010-04-18 Grégoire Sutre + + * util/grub-mkconfig.in: Corrected two == equality tests. + Set grub_prefix as in grub-install for NetBSD and OpenBSD. + * configure.ac: All definitions and uses of TARGET_IMG_LDFLAGS_AC now + expect a number appended to it. + * acinclude.m4 (grub_PROG_OBJCOPY_ABSOLUTE): ${TARGET_IMG_LDFLAGS_AC} + expects a number appended to it. + +2010-04-18 Vladimir Serbinenko + + * po/POTFILES: Renamed multiboot_loader.c to multiboot.c + +2010-04-18 Vladimir Serbinenko + + * util/hostdisk.c (make_device_name): Change to new partition naming. + +2010-04-17 Vladimir Serbinenko + + * disk/lvm.c (grub_lvm_memberlist): Issue an error if pv->disk = 0. + +2010-04-17 Christian Franke + + * Makefile.in: Add missing localedir setting. + +2010-04-14 Colin Watson + + Restore TEXTDOMAINDIR correction from r1889, lost apparently by + mistake in r2156. Noticed by Anthony Fok. + + * util/grub.d/10_kfreebsd.in (TEXTDOMAINDIR): Set to lowercased + @localedir@. + * util/grub.d/10_linux.in (TEXTDOMAINDIR): Likewise. + +2010-04-14 BVK Chaitanya + + Fix a spurious, uninitialized variable warning. + + * loader/i386/bsdXX.c (grub_freebsd_load_elfmodule_obj): + Initialize variable, shdr. + (grub_freebsd_load_elfmodule): Likewise. + (grub_freebsd_load_elf_meta): Likewise. + +2010-04-13 BVK Chaitanya + + Fix for escaped dollar in double quoted strings. + + * script/yylex.l: Updated flex rules. + * conf/tests.rmk: Rule for new testcase. + * tests/grub_script_dollar.in: New testcase. + +2010-04-13 Carles Pina i Estany +2010-04-13 Colin Watson + + Enclose all translated strings in grub.cfg in single quotes, and + escape them appropriately (Ubuntu bug #552921). + + * util/grub-mkconfig_lib.in (gettext_quoted): New function. + * util/grub.d/10_hurd.in: Use it. + * util/grub.d/10_kfreebsd.in (kfreebsd_entry): Likewise. + * util/grub.d/10_linux.in (linux_entry): Likewise. + +2010-04-11 Vladimir Serbinenko + + Fix cygwin compilation. + + * configure.ac: Define NEED_REGISTER_FRAME_INFO. + * include/grub/misc.h (__register_frame_info) + [NEED_REGISTER_FRAME_INFO && !UTIL]: New export. + (__deregister_frame_info) [NEED_REGISTER_FRAME_INFO && !UTIL]: Likewise. + * kern/misc.c (__register_frame_info) + [NEED_REGISTER_FRAME_INFO && !UTIL]: New empty function. + (__deregister_frame_info) [NEED_REGISTER_FRAME_INFO && !UTIL]: Likewise. + +2010-04-11 Vladimir Serbinenko + + * configure.ac: Respect grub_cv_asm_uscore when defining dummy symbols. + +2010-04-11 Vladimir Serbinenko + + Unify libgcc processing. + + * Makefile.in (kernel_img_LDFLAGS): New variable. + * conf/common.rmk (kernel_img_HEADERS): Add libgcc.h. + * conf/i386-coreboot.rmk (kernel_img_LDFLAGS): Append instead of + overwriting. + * conf/i386-ieee1275.rmk (kernel_img_LDFLAGS): Likewise. + * conf/i386-pc.rmk (kernel_img_LDFLAGS): Likewise. + * conf/i386-qemu.rmk (kernel_img_LDFLAGS): Likewise. + * conf/x86-efi.rmk (kernel_img_LDFLAGS): Likewise. + * conf/mips-qemu-mips.rmk (kernel_img_LDFLAGS): Append instead of + overwriting. Remove -lgcc and -static-libgcc + * conf/mips-yeeloong.rmk (kernel_img_LDFLAGS): Likewise. + * conf/mips.rmk (kernel_img_HEADERS): Remove cpu/libgcc.h + * conf/powerpc-ieee1275.rmk (kernel_img_HEADERS): Remove cpu/libgcc.h + (kernel_img_LDFLAGS): Append instead of overwriting. + Remove -lgcc and -static-libgcc + * conf/sparc64-ieee1275.rmk: Likewise. + * include/grub/powerpc/libgcc.h: Move to ... + * include/grub/libgcc.h: .. this. + * include/grub/libgcc.h: Don't export most of the function on x86. + (__bswapsi2): New export. + (__bswapdi2): Likewise. + * include/grub/mips/libgcc.h: Removed. + * include/grub/sparc64/libgcc.h: Likewise. + +2010-04-10 Vladimir Serbinenko + + * util/hostdisk.c (grub_util_biosdisk_get_grub_dev): Remove + disk_info_msg (conflicts with gettexting into languages with cases). + +2010-04-10 Grégoire Sutre + + Add grub-probe support for NetBSD. + + * util/getroot.c (find_root_device): Convert block device to + character device on NetBSD. + * util/probe.c (probe): Require character device on NetBSD. + * util/hostdisk.c: NetBSD specific headers. + (configure_device_driver): new function to tune device driver + parameters (currently only for NetBSD floppy driver). + (grub_util_biosdisk_open): NetBSD specific code (get disk size + via disklabel ioctl). + (open_device): call configure_device_driver on NetBSD. + (convert_system_partition_to_system_disk): NetBSD specific code. + (device_is_wholedisk): Likewise. + (grub_util_biosdisk_get_grub_dev): Likewise. + (make_device_name): Fixed a typo in bsd_part_str. + * configure.ac: check for opendisk() and getrawpartition() on + NetBSD and set LIBUTIL. + * Makefile.in: add LIBUTIL to LIBS. + +2010-04-10 BVK Chaitanya + + Documentation fix. + + * util/grub-script-check.c: Better help message. + +2010-04-10 BVK Chaitanya + + Fix FreeBSD build. + + * configure.ac: Flex version check. + * conf/common.rmk: Add -Wno-error to sh.mod. + * script/yylex.l: Remove all #pragma. + +2010-04-10 Vladimir Serbinenko + + * include/grub/util/misc.h (canonicalise_file_name): Add missing + prototype. + Reported by: Seth Goldberg. + +2010-04-10 Vladimir Serbinenko + + * loader/multiboot.c (GRUB_MOD_INIT) [GRUB_USE_MULTIBOOT2]: + Rename "module" to "module2". + Reported by: Seth Goldberg. + +2010-04-10 Vladimir Serbinenko + + * include/grub/efi/memory.h (grub_machine_mmap_iterate): Remove + EXPORT_FUNC. + Reported by: Seth Goldberg. + +2010-04-10 Vladimir Serbinenko + + * lib/posix_wrap/locale.h: Add missing file. + Reported by: Seth Goldberg. + +2010-04-10 Vladimir Serbinenko + + grub-emu module load support. + + * Makefile.in (TARGET_NO_MODULES): New variable. All users of + NO_DYNAMIC_MODULES switched to this. + (TARGET_CFLAGS): Add -DGRUB_TARGET_NO_MODULES=1 if applicable. + (CFLAGS): Likewise. + * conf/any-emu.rmk: Generate symlist. + (kernel_img_HEADERS): Add util/datetime.h. + (kernel_img_HEADERS) [sdl]: Add sdl.h. + (kernel_img_HEADERS) [libusb]: Add libusb.h. + (kernel_img_SOURCES) [TARGET_NO_MODULES = no && !x86]: Add + kern/$(target_cpu)/cache.S. + * configure.ac (grub-emu-modules): New option. + * genmk.rb: Handle multiple source lists. + * include/grub/sdl.h: New file. + * include/grub/libusb.h: Likewise. + * util/grub-emu.c (main): Hanle (host) root. + * util/hostdisk.c (grub_util_biosdisk_get_grub_dev): Error with + GRUB_ERR_UNKNOWN_DEVICE. + * util/misc.c: Move mm functions to ... + * util/mm.c: ... here. All users updated. + +2010-04-09 Vladimir Serbinenko + + * Makefile.in (RMKFILES): Search in srcdir and not current directory. + (MAINTAINER_CLEANFILES): Don't add $(srcdir) to MKFILES. Add few + missing files. + (maintainer-clean): Remove libgcrypt-grub. + +2010-04-09 Vladimir Serbinenko + + * term/efi/console.c (grub_console_checkkey): Macroify key contants. + +2010-04-09 EFI Coder + + * normal/menu_text.c (print_message): Clean up the message and show + the Fn information when on EFI + * term/efi/console.c (grub_console_checkkey): Add F4 support. + +2010-04-09 Vladimir Serbinenko + + * normal/autofs.c (read_fs_list): New parameter 'prefix'. + All users updated. + * normal/crypto.c (read_crypto_list): Likewise. + * normal/dyncmd.c (read_command_list): Likewise. + * normal/term.c (read_terminal_list): Likewise. + * normal/main.c (read_lists): Use explicit prefix. + (read_lists_hook): Use read_lists. + (grub_normal_execute): Likewise. + +2010-04-09 Vladimir Serbinenko + + * util/grub-mkrescue.in: Fix incorrect path in coreboot part. + Reported by: Thomas Schmitt. + Add -no-emul-boot to grub-mkisofs parameters. + +2010-04-09 Vladimir Serbinenko + + * font/font.c: Indented. + +2010-04-09 BVK Chaitanya + + Elif support to GRUB script (by Deepak Vankadaru). + + * tests/grub_script_if.in: New testcase. + * conf/tests.rmk: Rule for new testcase. + * script/parser.y: Grammar rules for elif. + +2010-04-09 BVK Chaitanya + + While and until loops support to GRUB script. + + * include/grub/script_sh.h (grub_script_cmdwhile): New struct. + (grub_script_create_cmdwhile): New function prototype. + (grub_script_execute_cmdwhile): New function prototype. + * script/execute.c (grub_script_execute_cmdwhile): New function. + * script/parser.y (command): New commands. + (whilecmd): New grammar rule. + (untilcmd): New grammar rule. + * script/script.c (grub_script_create_cmdwhile): New function. + * util/grub-script-check.c (grub_script_execute_cmdwhile): New + function. + + * tests/grub_script_while1.in: New testcase. + * conf/tests.rmk: Rule for new testcase. + +2010-04-09 Vladimir Serbinenko + + * util/grub.d/00_header.in: Add few missing quotes. Recognise *.jpeg + as *.jpg. + +2010-04-09 Mario Vazquez + + GRUB_BACKGROUND support. + + * util/grub-mkconfig.in: Export GRUB_BACKGROUND. + * util/grub.d/00_header.in: Parse GRUB_BACKGROUND. + +2010-04-09 Vladimir Serbinenko + + Load fonts and modules for gfxmenu in grub-mkconfig. + Idea by: Mario Vazquez + + * util/grub.d/00_header.in: Load pf2 and image modules. + +2010-04-09 Vladimir Serbinenko + + grub-mkconfig multiple terminal support. + + * util/grub-mkconfig.in: Handle multiple terminals correctly. + * util/grub.d/00_header.in: Likewise. + +2010-04-09 Vladimir Serbinenko + + * Makefile.in: Specify files explicitly instead of using $< and $@ since + we use cd $(srcdir). + +2010-04-08 Colin Watson + + * util/grub.d/10_linux.in: Only use the first word of + GRUB_DISTRIBUTOR for --class, to avoid problems if somebody puts + spaces in GRUB_DISTRIBUTOR. + * util/grub.d/10_kfreebsd.in: Likewise. + * util/grub.d/10_hurd.in: Likewise. + +2010-04-06 BVK Chaitanya + + Fix unit testing framework for Qemu 0.12. + + * tests/util/grub-shell.in: Remove -serial stdio option. + +2010-04-06 Vladimir Serbinenko + + POSIX header file wrappers. + + * lib/posix_wrap/assert.h: New file. Wrapper for its POSIX + equivalents. + * lib/posix_wrap/ctype.h: Likewise. + * lib/posix_wrap/errno.h: Likewise. + * lib/posix_wrap/langinfo.h: Likewise. + * lib/posix_wrap/limits.h: Likewise. + * lib/posix_wrap/localcharset.h: Likewise. + * lib/posix_wrap/stdint.h: Likewise. + * lib/posix_wrap/stdio.h: Likewise. + * lib/posix_wrap/stdlib.h: Likewise. + * lib/posix_wrap/string.h: Likewise. + * lib/posix_wrap/sys/types.h: Likewise. + * lib/posix_wrap/unistd.h: Likewise. + * lib/posix_wrap/wchar.h: Likewise. + * lib/posix_wrap/wctype.h: Likewise. + * conf/common.rmk (grub_script.yy.c): Remove #include elimination. + (grub_script.yy.h): Likewise. + * script/yylex.l: Remove POSIX emulation #defines. + * Makefile.in (POSIX_CFLAGS): New variable. + (GNULIB_UTIL_CFLAGS): Likewise. + + Regexp support. + + * conf/common.rmk (pkglib_MODULES): Add regexp.mod. + (regexp_mod_SOURCES): New variable. + (regexp_mod_CFLAGS): Likewise. + (regexp_mod_LDFLAGS): Likewise. + * commands/regexp.c: New file. + * gnulib/regcomp.c: New file. Imported from gnulib. + * gnulib/regex.c: Likewise. + * gnulib/regex_internal.c: Likewise. + * gnulib/regex_internal.h: Likewise. + * gnulib/regexec.c: Likewise. + * gnulib/regex.h: Likewise. + +2010-04-05 Vladimir Serbinenko + + * loader/i386/multiboot_mbi.c (grub_multiboot_load): Correctly report + unsupported video mode types. + +2010-04-05 Vladimir Serbinenko + + * kern/i386/pc/startup.S (grub_getrtsecs): Removed (dead code). + +2010-04-05 Vladimir Serbinenko + + * include/grub/i386/pc/init.h (grub_get_mmap_entry): Don't export. + * conf/i386-pc.rmk (kernel_img_HEADERS): Remove machine/init.h. + +2010-04-04 Vladimir Serbinenko + + Remove unused grub_vga_get_font. + + * kern/i386/pc/startup.S (grub_vga_get_font): Removed. + * include/grub/i386/pc/vga.h (grub_vga_get_font): Likewise. + +2010-04-03 Grégoire Sutre + + * kern/misc.c: Disable the __enable_execute_stack hack for utilities. + * include/grub/misc.h: Likewise. + +2010-04-03 Grégoire Sutre + + * util/grub-install.in: Add `|| exit 1' to all grub-probe calls + for which failure is fatal. + +2010-04-03 Grégoire Sutre + + * util/grub-install.in: Use mkdir -p to create grub directory. + * util/i386/efi/grub-install.in: Likewise. + * util/ieee1275/grub-install.in: Likewise. + +2010-04-03 Grégoire Sutre + + * Makefile.in (LEX): new variable. + +2010-04-03 Grégoire Sutre + + * util/i386/efi/grub-dumpdevtree: replaced the non-portable `==' by + `=' and added double quotes on operands of this equality test. + +2010-04-03 Vladimir Serbinenko + + * Makefile.in (uninstall): Remove a leftover debug echo. + Reported by: Grégoire Sutre + +2010-04-03 Vladimir Serbinenko + + MIPS multiboot2 support. + + * conf/mips.rmk (pkglib_MODULES): Add multiboot2.mod. + (multiboot2_mod_SOURCES): New variable. + (multiboot2_mod_CFLAGS): Likewise. + (multiboot2_mod_LDFLAGS): Likewise. + (multiboot2_mod_ASFLAGS): Likewise. + * include/grub/i386/multiboot.h (MULTIBOOT_INITIAL_STATE): New + definition. + (MULTIBOOT_ENTRY_REGISTER): Likewise. + (MULTIBOOT_MBI_REGISTER): Likewise. + (MULTIBOOT_ARCHITECTURE_CURRENT): Likewise. + (MULTIBOOT_ELF32_MACHINE): Likewise. + (MULTIBOOT_ELF64_MACHINE): Likewise. + * include/grub/mips/multiboot.h: New file. + * include/grub/video.h (grub_video_driver_id): New type + GRUB_VIDEO_DRIVER_SM712. + (grub_video_get_info_and_fini): Export. + (grub_video_get_palette): Likewise. + (grub_video_get_driver_id): Likewise. + * include/multiboot2.h: Resynced with spec. + * loader/i386/multiboot.c: Moved from here ... + * loader/multiboot.c: ... here. All users updated. + (grub_multiboot_boot): Use platform-specific macros. + * loader/i386/multiboot_elfxx.c: Moved from here ... + * loader/multiboot_elfxx.c: ... here. All users updated. + (E_MACHINE): Use MULTIBOOT_ELF32_MACHINE and MULTIBOOT_ELF64_MACHINE. + * loader/i386/multiboot_mbi2.c (grub_multiboot_load): Check arcitecture. + * video/sm712.c (grub_video_sm712_adapter): Add missing id field. + +2010-04-02 Vladimir Serbinenko + + Import gnulib argp module. + + * gnulib/argp-ba.c: New file. + * gnulib/argp-eexst.c: Likewise. + * gnulib/argp-fmtstream.c: Likewise. + * gnulib/argp-fmtstream.h: Likewise. + * gnulib/argp-fs-xinl.c: Likewise. + * gnulib/argp-help.c: Likewise. + * gnulib/argp-namefrob.h: Likewise. + * gnulib/argp-parse.c: Likewise. + * gnulib/argp-pin.c: Likewise. + * gnulib/argp-pv.c: Likewise. + * gnulib/argp-pvh.c: Likewise. + * gnulib/argp-version-etc.c: Likewise. + * gnulib/argp-version-etc.h: Likewise. + * gnulib/argp-xinl.c: Likewise. + * gnulib/argp.h: Likewise. + +2010-03-31 Vladimir Serbinenko + + * kern/device.c (grub_device_iterate): Clear errors after failed + opening device. + +2010-03-31 Vladimir Serbinenko + + * kern/ieee1275/openfw.c (grub_children_iterate): Skip device itself if + returned by firmware. + +2010-03-30 Vladimir Serbinenko + + * loader/i386/multiboot_mbi2.c (retrieve_video_parameters): Fix + compilation on coreboot and qemu + +2010-03-28 Vladimir Serbinenko + + * include/multiboot2.h: Resync with spec. + +2010-03-28 Vladimir Serbinenko + + Multiboot2 tag support + + * conf/i386.rmk (multiboot2_mod_SOURCES): Replace + loader/i386/multiboot_mbi.c with loader/i386/multiboot_mbi2.c. + Remove loader/multiboot_loader.c. + * include/grub/i386/multiboot.h (grub_multiboot_real_boot): Removed. + (grub_multiboot2_real_boot): Likewise. + * include/grub/multiboot.h (grub_multiboot_set_accepts_video): Removed. + (grub_get_multiboot_mmap_count): New proto. + (grub_fill_multiboot_mmap): Likewise. + (grub_multiboot_set_video_mode): Likewise. + (grub_multiboot_set_console): Likewise. + (grub_multiboot_load): Likewise. + (grub_multiboot_load_elf): Likewise. + (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT): New definition. + (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER): Likewise. + * include/multiboot.h: Resynced with specification. + * include/multiboot2.h: Resynced with specification. + * loader/i386/multiboot_mbi.c (DEFAULT_VIDEO_MODE): Moved from here... + * loader/i386/multiboot.c (DEFAULT_VIDEO_MODE): ... here. + * loader/i386/multiboot_mbi.c (HAS_VGA_TEXT): Moved from here .. + * include/grub/multiboot.h (GRUB_MACHINE_HAS_VGA_TEXT): ... here. All + users updated. + * loader/i386/multiboot_mbi.c (accepts_video): Moved from here... + * loader/i386/multiboot.c (accepts_video): ... here. All users updated. + * loader/i386/multiboot_mbi.c (grub_multiboot_set_accepts_video): + Removed. + * loader/i386/multiboot_mbi.c (grub_get_multiboot_mmap_len): + Moved from here... + * loader/i386/multiboot.c (grub_get_multiboot_mmap_len): ... here. + * loader/i386/multiboot_mbi.c (grub_fill_multiboot_mmap): + Moved from here... + * loader/i386/multiboot.c (grub_fill_multiboot_mmap): ... here. + * loader/i386/multiboot_mbi.c (set_video_mode): Moved from here... + * loader/i386/multiboot.c (grub_multiboot_set_video_mode): ... here. + All users updated. + * loader/i386/multiboot_mbi2.c: New file. + +2010-03-27 Vladimir Serbinenko + + Resync with gnulib. + + * Makefile.in (GNULIB_CFLAGS): New variable. + * conf/common.rmk (grub_mkisofs_CFLAGS): Add GNULIB_CFLAGS. + (grub_script_check_CFLAGS): New variable. + * gnulib/alloca.h: Resync with gnulib. + * gnulib/error.c: Likewise. + * gnulib/error.h: Likewise. + * gnulib/fnmatch.c: Likewise. + * gnulib/fnmatch_loop.c: Likewise. + * gnulib/getdelim.c: Likewise. + * gnulib/getline.c: Likewise. + * gnulib/getopt.c: Likewise. + * gnulib/getopt1.c: Likewise. + * gnulib/getopt_int.h: Likewise. + * gnulib/gettext.h: Likewise. + * gnulib/progname.c: Likewise. + * gnulib/progname.h: Likewise. + +2010-03-27 Grégoire Sutre + + Fix a build failure (-Wundef -Werror) when ENABLE_NLS is not defined, + which is the case with --disabled-nls. + + * include/grub/i18n.h: Use (defined(ENABLE_NLS) + && ENABLE_NLS) instead of ENABLE_NLS in all #if preprocessor macros. + * util/misc.c: Likewise. + * util/mkisofs/mkisofs.c: Likewise. + * util/mkisofs/mkisofs.h: Likewise. + +2010-03-27 Vladimir Serbinenko + + Simplify Apple CC support. + + * commands/i386/pc/drivemap_int13h.S: Use LOCAL when possible. + Add 0 byte at the end not to have a symbol with empty target. + * mmap/i386/pc/mmap_helper.S: Likewise. + * genmk.rb: Ignore errors 2030 and 2050. + * kern/i386/pc/startup.S: Use LOCAL when possible. + +2010-03-26 BVK Chaitanya + + Testcase and the fix for final semicolon on cmdline. + + * tests/grub_script_final_semicolon.in: New testcase. + * conf/tests.rmk: Rules for the new testcase. + * script/parser.y: Grammar fix. + +2010-03-26 BVK Chaitanya + + Blank lines testcase for GRUB script. + + * tests/grub_script_blanklines.in: New testcase. + * conf/tests.rmk: Rules for the new testcase. + +2010-03-26 Vladimir Serbinenko + + Don't use __FILE__. + + * genmk.rb: Add -DGRUB_FILE to all C targets. + * fs/reiserfs.c: Replace __FILE__ with GRUB_FILE. + * include/grub/list.h: Likewise. + * include/grub/misc.h: Likewise. + * include/grub/mm.h: Likewise. + * include/grub/test.h: Likewise. + * kern/mm.c: Likewise. + * lib/libgcrypt_wrap/cipher_wrap.h: Likewise. + +2010-03-26 Vladimir Serbinenko + + Sunpc partitions support. + + * conf/common.rmk (grub_probe_SOURCES): Add partmap/sunpc.c. + (grub_fstest_SOURCES): Likewise. + (pkglib_MODULES): Add part_sunpc.mod. + (part_sunpc_mod_SOURCES): New variable. + (part_sunpc_mod_CFLAGS): Likewise. + (part_sunpc_mod_LDFLAGS): Likewise. + * conf/i386-pc.rmk (grub_setup_SOURCES): Add partmap/sunpc.c. + * partmap/sunpc.c: New file. + +2010-03-26 BVK Chaitanya + + For loop support to GRUB script. + + * include/grub/script_sh.h (grub_script_cmdfor): New struct. + (grub_script_create_cmdfor): New function prototype. + (grub_script_execute_cmdfor): New function prototype. + * script/execute.c (grub_script_execute_cmdfor): New function. + * script/parser.y (command): New for command. + (forcmd): New grammar rule. + * script/script.c (grub_script_create_cmdfor): New function. + * util/grub-script-check.c (grub_script_execute_cmdfor): New + function. + * tests/grub_script_for1.in: New testcase. + * conf/tests.rmk: Rules for new testcase. + +2010-03-26 Vladimir Serbinenko + + Nested partitions + + * commands/blocklist.c (grub_cmd_blocklist): Don't check whether + 'partition' is NULL, grub_partition_get_start already does that. + * commands/loadenv.c (check_blocklists): Likewise. + (write_blocklists): Likewise. + * conf/common.rmk (grub_probe_SOURCES): Add partmap/bsdlabel.c. + (grub_fstest_SOURCES): Likewise. + (pkglib_MODULES): Add part_bsd.mod. + (part_bsd_mod_SOURCES): New variable. + (part_bsd_mod_CFLAGS): Likewise. + (part_bsd_mod_LDFLAGS): Likewise. + * conf/i386-pc.rmk (grub_setup_SOURCES): Add partmap/bsdlabel.c. + (grub_emu_SOURCES): Likewise. + * conf/sparc64-ieee1275.rmk (grub_emu_SOURCES): Likewise. + * include/grub/bsdlabel.h: New file. + * include/grub/partition.h (grub_partition_map): Remove 'probe' and + 'get_name'. + (grub_partition): Add 'parent' and 'number'. Remove 'data'. + (grub_partition_map_list): New variable. + (grub_partition_map_register): Inline. + (grub_partition_map_unregister): Likewise. + (FOR_PARTITION_MAPS): New macro. + (grub_partition_map_iterate): Removed. + (grub_partition_get_start): Handle nested partitions. + * include/grub/msdos_partition.h: Remove bsd-related entries. + (grub_pc_partition): Remove. + * kern/disk.c (grub_disk_close): Free partition data. + (grub_disk_adjust_range): Handle nested partitions. + * kern/partition.c (grub_partition_map_probe): New function. + (grub_partition_probe): Parse name to number, handle subpartitions. + (get_partmap): New function. + (grub_partition_iterate): Handle subpartitions. + (grub_partition_get_name): Likewise. + * loader/i386/pc/bsd.c (grub_bsd_get_device): Likewise. + * loader/i386/multiboot.c (grub_multiboot_get_bootdev): Likewise. + * loader/i386/pc/chainloader.c (grub_chainloader_cmd): Likewise. + * partmap/acorn.c (acorn_partition_map_iterate): Don't force raw access. + Set 'number'. + (acorn_partition_map_probe): Remove. + (acorn_partition_map_get_name): Likewise. + * partmap/amiga.c (amiga_partition_map_iterate): Don't force raw access. + Set 'number'. + Set 'index' to 0 since there can be only one partition entry per sector. + (amiga_partition_map_probe): Remove. + (amiga_partition_map_get_name): Likewise. + * partmap/apple.c (apple_partition_map_iterate): Don't force raw access. + Set 'number'. + Set 'offset' and 'index' to real positions of partitions. + (apple_partition_map_probe): Remove. + (apple_partition_map_get_name): Likewise. + * partmap/bsdlabel.c: New file. + * partmap/gpt.c (gpt_partition_map_iterate): Don't force raw access. + Set 'number'. + Allocate 'data' so it can be correctly freed. + Set 'index' to offset inside sector. + (gpt_partition_map_probe): Remove. + (gpt_partition_map_get_name): Likewise. + * partmap/msdos.c (grub_partition_parse): Remove. + (pc_partition_map_iterate): Don't force raw access. + Set 'number'. + Make 'ext_offset' a local variable. + (pc_partition_map_probe): Remove. + (pc_partition_map_get_name): Remove. + * partmap/sun.c (sun_partition_map_iterate): Don't force raw access. + Set 'number'. + (sun_partition_map_probe): Remove. + (sun_partition_map_get_name): Likewise. + * parttool/msdospart.c (grub_pcpart_boot): Handle nested partitions. + (grub_pcpart_type): Likewise. + * util/hostdisk.c (open_device): Handle new numbering scheme. + (grub_util_biosdisk_get_grub_dev): Handle nested partitions. + * util/i386/pc/grub-setup.c (setup): Handle new numbering scheme. + * util/grub-probe.c (probe_partmap): Handle nested paritions. + * util/grub-install.in: Insert all subpartition modules. + * util/ieee1275/grub-install.in: Likewise. + +2010-03-24 Adrian Glaubitz + + * kern/dl.c (grub_dl_resolve_symbols): Improve error message + grammar. + +2010-03-24 Colin Watson + + * .bzrignore: Add grub-bin2h, grub-reboot, and grub-set-default. + +2010-03-21 Colin Watson + + * util/grub-install.in: Copy .mo files from @datadir@/locale, to + match where 'make install' puts them. + * util/i386/efi/grub-install.in: Likewise. + +2010-03-19 Colin Watson + + * .bzrignore: Add gentrigtables, grub-script-check, + grub_script_check_init.c, grub_script_check_init.h, and + trigtables.c. + +2010-03-18 Vladimir Serbinenko + + * kern/parser.c: Indented. + +2010-03-17 Vladimir Serbinenko + + * term/i386/pc/vesafb.c: Removed (orphaned, deprecated and broken). + +2010-03-17 Vladimir Serbinenko + + * video/fb/fbblit.c (grub_video_fbblit_blend_XXXA8888_1bit): Handle + alpha_mask_size == 0 case. + +2010-03-14 BVK Chaitanya + + GRUB shell lexer and parser improvements. + + * conf/any-emu.rmk: Build rule updates. + * conf/common.rmk: Likewise. + * conf/i386-coreboot.rmk: Likewise. + * conf/i386-efi.rmk: Likewise. + * conf/i386-ieee1275.rmk: Likewise. + * conf/i386-pc.rmk: Likewise. + * conf/powerpc-ieee1275.rmk: Likewise. + * conf/x86_64-efi.rmk: Likewise. + + * configure.ac: Configure check for flex. + + * include/grub/script_sh.h (grub_script_arg_type_t): More argument + types. + (grub_lexer_param): Struct member updates. + (grub_parser_param): Likewise. + (GRUB_LEXER_TOKEN_MAX): Maximum token size. + (GRUB_LEXER_RECORD_INCREMENT): Memory increments' size. + (grub_script_lexer_init): Prototype update. + (grub_script_lexer_record_start): Likewise. + (grub_script_lexer_record_stop): Likewise. + (grub_script_lexer_yywrap): New function prototype. + (grub_script_lexer_fini): Likewise. + (grub_script_execute_argument_to_string): Removed by... + (grub_script_execute_argument_to_argv): ...better version. + + * script/execute.c (ROUND_UPTO): New macro. + (grub_script_execute_cmdline): Out of memory fixes. + (grub_script_execute_menuentry): Likewise. + (grub_script_execute_argument_to_string): Removed. Update all + users by... + (grub_script_execute_argument_to_argv): ...better version. + * script/function.c (grub_script_function_create): Use + grub_script_execute_argument_to_argv instead of + grub_script_execute_argument_to_string. + + * script/lexer.c (check_varstate): Removed. + (check_textstate): Removed. + (grub_script_lexer_record_start): Likewise. + (grub_script_lexer_record_stop): Likewise. + (recordchar): Replaced with... + (grub_script_lexer_record): ...new function. + (nextchar): Removed. + (grub_script_lexer_init): Rewritten. + (grub_script_yylex): Rewritten. + (append_newline): New function. + (grub_script_lexer_yywrap): New function. + (grub_script_lexer_fini): New function. + (grub_script_yyerror): Sets error flag. + + * script/yylex.l: New file. + (grub_lexer_yyfree): Wrapper for flex yyffre. + (grub_lexer_yyalloc): Likewise. + (grub_lexer_yyrealloc): Likewise. + * script/parser.y: Refactored. + + * script/script.c (grub_script_arg_add): Out of memory fixes. + (grub_script_add_arglist): Likewise. + (grub_script_create_cmdline): Likewise. + (grub_script_create_cmdmenu): Likewise. + (grub_script_add_cmd): Likewise. + (grub_script_parse): Use grub_script_lexer_fini to deallocated. + * util/grub-script-check.c (grub_script_execute_menuentry): Remove + unnecessary code. + + * tests/grub_script_echo1.in: New testcase. + * tests/grub_script_vars1.in: New testcase. + * tests/grub_script_echo_keywords.in: New testcase. + +2010-03-14 Vladimir Serbinenko + + Remove some redundancy in build system. + + * Makefile.in (TARGET_CFLAGS): Add -ffreestanding. + (TARGET_ASFLAGS): Add -nostdinc -fno-builtin. + (TARGET_LDFLAGS): Add -nostdlib. + (TARGET_IMG_LDFLAGS): Likewise. + * commands/lsmmap.c (grub_cmd_lsmmap) [GRUB_MACHINE_EMU]: Don't do + anything since mmap isn't available. + * conf/any-emu.rmk (kernel_img_SOURCES): Remove commands/boot.c. + Add util/time.c. + (pkglib_MODULES): Remove reboot.mod. + (reboot_mod_SOURCES): Removed. + (reboot_mod_CFLAGS): Likewise. + (reboot_mod_LDFLAGS): Likewise. + * conf/common.rmk (script/lexer.c_DEPENDENCIES): New variable. + (MOSTLYCLEANFILES): Add symlist.c kernel_syms.lst. + (DEFSYMFILES): Add kernel_syms.lst. + (kernel_img_HEADERS): Add common headers. + (symlist.c): New target. + (kernel_syms.lst): Likewise. + (pkglib_MODULES): Add memdisk.mod. + (memdisk_mod_SOURCES): New variable. + (memdisk_mod_CFLAGS): Likewise. + (memdisk_mod_LDFLAGS): Likewise. + (pkglib_MODULES): Add reboot.mod. + (reboot_mod_SOURCES): New variable. + (reboot_mod_CFLAGS): Likewise. + (reboot_mod_LDFLAGS): Likewise. + (pkglib_MODULES): Add date.mod. + (date_mod_SOURCES): New variable. + (date_mod_CFLAGS): Likewise. + (date_mod_LDFLAGS): Likewise. + (pkglib_MODULES): Add datehook.mod. + (datehook_mod_SOURCES): New variable. + (datehook_mod_CFLAGS): Likewise. + (datehook_mod_LDFLAGS): Likewise. + (pkglib_MODULES): Add lsmmap.mod. + (lsmmap_mod_SOURCES): New variable. + (lsmmap_mod_CFLAGS): Likewise. + (lsmmap_mod_LDFLAGS): Likewise. + (pkglib_MODULES): Add boot.mod. + (boot_mod_SOURCES): New variable. + (boot_mod_CFLAGS): Likewise. + (boot_mod_LDFLAGS): Likewise. + * conf/i386-coreboot.rmk: Removed redundant parts. + * conf/i386-ieee1275.rmk: Likewise. + * conf/i386-pc.rmk: Likewise. + * conf/mips-yeeloong.rmk: Likewise. + * conf/mips.rmk: Likewise. + * conf/powerpc-ieee1275.rmk: Likewise. + * conf/sparc64-ieee1275.rmk: Likewise. + * conf/x86_64-efi.rmk: Likewise. + * conf/i386-coreboot.rmk: Moved qemu parts .. + * conf/i386-qemu.rmk: ... here + * conf/i386-efi.rmk: Moved common parts to... + * conf/x86-efi.rmk: ... here. + * conf/i386.rmk: Added modules common to all x86 variants. + * configure.ac: Add -m32/-m64 to TARGET_ASFLAGS. + * disk/memdisk.c: Remove grub/machine/kernel.h. + * gensymlist.sh.in: Include symbol.h. + * hook/datehook.c: Correct module name. + * include/grub/datetime.h (grub_get_datetime) [GRUB_MACHINE_EMU]: Export. + (grub_set_datetime) [GRUB_MACHINE_EMU]: Likewise. + * include/grub/i386/efi/serial.h: New file. + * include/grub/x86_64/efi/serial.h: Likewise. + * util/time.c: Likewise. + * video/ieee1275.c (grub_video_ieee1275_setup): Handle 64-bit void *. + +2010-03-14 Colin King +2010-03-14 Colin Watson + + Shrink the pre-partition-table part of boot.img by eight bytes. + + * boot/i386/pc/boot.S (ERR): New macro. + (chs_mode): Use ERR. + (geometry_error): Likewise. + (hd_probe_error): Remove. This is only used once, so we wrwite + it inline instead. + (read_error): Instead of printing read_error_string, just set up + %si and fall through to ... + (error_message): ... this new function, also used by ERR. + +2010-03-14 Colin Watson + + Speed up consecutive hostdisk operations on the same device. + + * util/hostdisk.c (struct grub_util_biosdisk_data): New structure. + (grub_util_biosdisk_open): Initialise disk->data. + (struct linux_partition_cache): New structure. + (linux_find_partition): Cache partition start positions; these are + expensive to compute on every read and write. + (open_device): Cache open file descriptor in disk->data, so that we + don't have to reopen it and flush the buffer cache for consecutive + operations on the same device. + (grub_util_biosdisk_close): New function. + (grub_util_biosdisk_dev): Set `close' member. + + * conf/common.rmk (grub_probe_SOURCES): Add kern/list.c. + * conf/i386-efi.rmk (grub_setup_SOURCES): Likewise. + * conf/i386-pc.rmk (grub_setup_SOURCES): Likewise. + * conf/sparc64-ieee1275.rmk (grub_setup_SOURCES): Likewise. + * conf/x86_64-efi.rmk (grub_setup_SOURCES): Likewise. + +2010-03-14 Vladimir Serbinenko + + Compile parts of grub-emu as modules. + + * Makefile.in (TARGET_CPPFLAGS) [emu]: Remove -nostdinc -isystem. + (pkglib_DATA) [emu]: Remove moddep.lst command.lst fs.lst + partmap.lst parttool.lst handler.lst video.lst crypto.lst terminal.lst. + (all-local): Add $(GRUB_EMU). + (install-local): Install $(GRUB_EMU). + (uninstall): Uninstall $(GRUB_EMU). + * commands/parttool.c: Replace GRUB_UTIL with GRUB_NO_MODULES. + * kern/dl.c: Likewise. + * commands/sleep.c: Not include machine/time.h. + * conf/any-emu.rmk (COMMON_LDFLAGS): New variable. + (COMMON_CFLAGS): Likewise. + (sbin_UTILITIES): Remove grub-emu. + (grub_emu_SOURCES): Removed. + (kernel_img_RELOCATABLE): New variable. + (pkglib_PROGRAMS): Add kernel.img. + (kernel_img_SOURCES): New variable + (kernel_img_CFLAGS): Likewise. + (kernel_img_LDFLAGS): Likewise. + (TARGET_NO_STRIP): Likewise. + (TARGET_NO_DYNAMIC_MODULES): Likewise. + (pkglib_MODULES): Add progname.mod, hostfs.mod, host.mod, reboot.mod, + halt.mod, cpuid.mod, usb.mod, sdl.mod and pci.mod. + (grub-emu): New target. + (GRUB_EMU): New variable. + * configure.ac: Whitelist -emu as possible x86_64 architecture. + * efiemu/main.c: Replace GRUB_UTIL with GRUB_MACHINE_EMU. + * loader/xnu.c: Likewise. + * include/grub/pci.h: Likewise. + * genemuinit.sh: New file. + * genemuinitheader.sh: Likewise. + * genmk.rb: Don't strip if TARGET_NO_STRIP is yes. + Support TARGET_NO_DYNAMIC_MODULES. + * include/grub/dl.h (GRUB_NO_MODULES): New variable. + * commands/search.c: Fix GRUB_MOD_INIT and GRUB_MOD_FINI arguments. + * disk/loopback.c: Likewise. + * font/font_cmd.c: Likewise. + * partmap/acorn.c: Likewise. + * partmap/amiga.c: Likewise. + * partmap/apple.c: Likewise. + * partmap/gpt.c: Likewise. + * partmap/msdos.c: Likewise. + * partmap/sun.c: Likewise. + * parttool/msdospart.c: Likewise. + * term/gfxterm.c: Likewise. + * video/bitmap.c: Likewise. + * video/readers/jpeg.c: Likewise. + * video/readers/png.c: Likewise. + * video/readers/tga.c: Likewise. + * video/video.c: Likewise. + * util/grub-emu.c (read_command_list): Removed. + (main): Don't call util_init_nls. + * util/misc.c (grub_err_printf) [!GRUB_UTIL]: Removed. + (grub_util_init_nls) [!GRUB_UTIL]: Likewise. + +2010-03-14 Vladimir Serbinenko + + * conf/powerpc-ieee1275.rmk (pkglib_MODULES): Add datetime.mod, + date.mod, datehook.mod. + (datetime_mod_SOURCES): New variable. + (datetime_mod_CFLAGS): Likewise. + (datetime_mod_LDFLAGS): Likewise. + (date_mod_SOURCES): Likewise. + (date_mod_CFLAGS): Likewise. + (date_mod_LDFLAGS): Likewise. + (datehook_mod_SOURCES): Likewise. + (datehook_mod_CFLAGS): Likewise. + (datehook_mod_LDFLAGS): Likewise. + * conf/sparc64-ieee1275.rmk: Likewise. + * lib/ieee1275/datetime.c: New file. + +2010-03-14 Vladimir Serbinenko + + * conf/powerpc-ieee1275.rmk (pkglib_MODULES): Add ieee1275_fb.mod. + (ieee1275_fb_mod_SOURCES): New variable. + (ieee1275_fb_mod_CFLAGS): Likewise. + (ieee1275_fb_mod_LDFLAGS): Likewise. + * include/grub/ieee1275/ieee1275.h (grub_ieee1275_devices_iterate): + New proto. + * kern/ieee1275/init.c (HEAP_MAX_SIZE): Increased. + (HEAP_MAX_ADDR): Likewise. + * kern/ieee1275/openfw.c (grub_children_iterate): Don't skip empty + type. + Correct stop condition. + (grub_ieee1275_devices_iterate): New function. + * video/ieee1275.c: New file. + +2010-03-14 Vladimir Serbinenko + + Merge sparc grub-mkimage into generic grub-mkimage and a.out support. + + * boot/sparc64/ieee1275/boot.S (boot_continue): Use SCRATCH_PAD_BOOT + as scratch. + * boot/sparc64/ieee1275/diskboot.S (after_info_block): Use + SCRATCH_PAD_DISKBOOT as scratch. + (bootit): Pass Openfirmware pointer in %o4. + * conf/sparc64-ieee1275.rmk (kernel_img_LDFLAGS): Link at 0x4400 instead + of 0x200000. + (grub_mkimage_SOURCES): Replace util/sparc64/ieee1275/grub-mkimage.c + with util/grub-mkrawimage.c. + * configure.ac: Handle GRUB_MACHINE_SPARC64 and GRUB_MACHINE_MIPS. + * include/grub/aout.h (AOUT_MID_SUN): New definition. + (grub_aout_get_type) [GRUB_UTIL]: Removed. + (grub_aout_load) [GRUB_UTIL]: Likewise. + * include/grub/kernel.h (grub_modules_get_end): New proto. + * include/grub/sparc64/ieee1275/boot.h (SCRATCH_PAD): Removed. + (SCRATCH_PAD_BOOT): New definition. + (SCRATCH_PAD_DISKBOOT): Likewise. + (GRUB_BOOT_MACHINE_IMAGE_ADDRESS): Set to 0x4400. + * include/grub/sparc64/ieee1275/ieee1275.h + (grub_ieee1275_original_stack): New variable + * include/grub/sparc64/ieee1275/kernel.h (GRUB_KERNEL_MACHINE_RAW_SIZE): + New definition + (GRUB_KERNEL_MACHINE_STACK_SIZE): Likewise. + (GRUB_PLATFORM_IMAGE_FORMATS): Likewise. + (GRUB_PLATFORM_IMAGE_DEFAULT_FORMAT): Likewise. + (GRUB_PLATFORM_IMAGE_DEFAULT): Likewise. + (GRUB_PLATFORM_IMAGE_RAW): Likewise. + (GRUB_PLATFORM_IMAGE_AOUT): Likewise. + (grub_platform_image_format_t): New type. + * kern/mips/yeeloong/init.c (grub_modules_get_end): Move from here ... + * kern/main.c (grub_modules_get_end) + [GRUB_MACHINE_MIPS_YEELOONG || GRUB_MACHINE_SPARC64]: ... here. + * kern/sparc64/ieee1275/crt0.S: Store firmware entry point in %o0. + (codestart): Switch stacks. + * kern/sparc64/ieee1275/init.c (grub_ieee1275_original_stack): New + variable. + (grub_heap_init): Use grub_modules_get_end. + * loader/sparc64/ieee1275/linux.c (grub_linux_boot): Restore original + stack. + * util/grub-mkrawimage.c (generate_image): Support sparc64. + (main): Likewise. + * util/sparc64/ieee1275/grub-mkimage.c: Removed. + +2010-03-14 Thorsten Glaser + + * util/grub-mkrescue.in: Base ISO UUID on UTC. + +2010-03-08 Matt Kraai + + * util/i386/pc/grub-setup.c (setup): Fix a grammatical error (Debian + bug #559005). + +2010-03-07 Vladimir Serbinenko + + * genmoddep.awk: Output all missing symbols and not only first. + +2010-03-06 Vladimir Serbinenko + + * NEWS: Put the date of 1.98 release. + +2010-03-06 Vladimir Serbinenko + + * configure.ac: Update CPPFLAGS and not CFLAGS when checking for + ft2build.h. + +2010-03-06 Vladimir Serbinenko + + * normal/cmdline.c (grub_cmdline_get): Fix gabled line after + completition in the middle of string. + +2010-03-06 Vladimir Serbinenko + + * util/grub-mkrescue.in: Use mktemp with explicit template. + +2010-03-06 Vladimir Serbinenko + + * loader/i386/bsd.c (grub_bsd_get_device): Fix a memory leak. + +2010-03-06 Vladimir Serbinenko + + * loader/i386/multiboot_mbi.c (grub_multiboot_set_bootdev): Free the + right pointer. + +2010-03-05 Vladimir Serbinenko + + Fix FreeBSD compilation. + + * Makefile.in (TARGET_CPPFLAGS): Remove -nostdinc -isystem. + * configure.ac: Add -nostdinc -isystem to TARGET_CPPFLAGS if it works. + +2010-03-05 Vladimir Serbinenko + + * util/import_gcry.py: Add autogenerated files to MAINTAINER_CLEANFILES. + +2010-03-04 Vladimir Serbinenko + + * gettext/gettext.c (grub_gettext_init_ext): Fix a memory leak. + +2010-03-04 Vladimir Serbinenko + + * disk/scsi.c (grub_scsi_iterate): Fix a memory leak. + +2010-03-04 Robert Millan + + Support relative image path in theme file. + + * gfxmenu/gui_image.c (grub_gui_image): New member theme_dir. + (image_set_property): Handle theme_dir and relative path. + +2010-03-04 Vladimir Serbinenko + + * configure.ac: Alias amd64 to x86_64. + +2010-03-04 Vladimir Serbinenko + + * NEWS: mention multiboot on EFI. + +2010-03-04 Vladimir Serbinenko + + * kern/main.c (grub_load_modules): Handle errors from init functions of + embeded modules. + +2010-03-04 Vladimir Serbinenko + + * normal/autofs.c (autoload_fs_module): Handle errors. + +2010-03-04 Vladimir Serbinenko + + Disable linux.mod on qemu-mips since it's not functional and leads + to compilation failure. + + * conf/mips.rmk (pkglib_MODULES): Remove linux.mod. + * conf/mips-yeeloong.rmk (pkglib_MODULES): Add linux.mod. + * conf/mips.rmk (linux_mod_SOURCES): Move from here ... + * conf/mips-yeeloong.rmk (linux_mod_SOURCES): ... here + * conf/mips.rmk (linux_mod_CFLAGS): Move from here ... + * conf/mips-yeeloong.rmk (linux_mod_CFLAGS): ... here + * conf/mips.rmk (linux_mod_ASFLAGS): Move from here ... + * conf/mips-yeeloong.rmk (linux_mod_ASFLAGS): ... here + * conf/mips.rmk (linux_mod_LDFLAGS): Move from here ... + * conf/mips-yeeloong.rmk (linux_mod_LDFLAGS): ... here + Reported by: BVK Chaitanya + +2010-03-04 Jordan Uggla + + * INSTALL: Add gettext as a dependency and add qemu to a new section + "Prerequisites for make-check". + +2010-03-04 Christian Franke + + * util/grub-pe2elf.c: Add missing include "progname.h". + +2010-03-04 Vladimir Serbinenko + + * normal/crypto.c (read_crypto_list): Fix a typo. + Reported by: Seth Goldberg. + +2010-03-04 Vladimir Serbinenko + + * Makefile.in (DISTCLEANFILES): Add stamp-h1. + Reported by: Seth Goldberg. + +2010-03-04 Vladimir Serbinenko + + * Makefile.in (CLEANFILES) [FONT_SOURCE && grub_mkfont]: Add + ascii.bitmaps. + +2010-03-04 Vladimir Serbinenko + + * genmk.rb: Remove terminal*.lst in make clean. + Reported by: Seth Goldberg. + +2010-03-04 Vladimir Serbinenko + + * util/i386/efi/grub-install.in: Copy gettext files. + +2010-03-01 Vladimir Serbinenko + + * fs/ext2.c (grub_ext2_read_block): Fix an integer overflow. + +2010-03-01 Vladimir Serbinenko + + Wait for user entry basing on presence of output rather than on errors. + + * include/grub/normal.h (grub_normal_get_line_counter): New proto. + (grub_install_newline_hook): Likewise. + * normal/main.c (GRUB_MOD_INIT): Call grub_install_newline_hook. + * normal/menu.c (show_menu): Check line_counter to determine presence + of output. + * normal/term.c (grub_normal_line_counter): New variable. + (grub_normal_get_line_counter): New function. + (grub_install_newline_hook): Likewise. + +2010-03-01 Vladimir Serbinenko + + * commands/cat.c (grub_cmd_cat): Propagate grub_gzfile_open error. + +2010-03-01 Vladimir Serbinenko + + * configure.ac: Update version to 1.98. + +2010-02-26 Vladimir Serbinenko + + * util/grub.d/10_linux.in (linux_entry): Don't default to + gfxpayload=keep if Linux doesn't support video handover. + +2010-02-25 Vladimir Serbinenko + + Don't compile video modules on yeeloong since video subsystem is part + of kernel. + + * conf/common.rmk (pkglib_MODULES) [yeeloong]: Remove video.mod, + video_fb.mod, bitmap.mod, font.mod, gfxterm.mod and bufio.mod + * conf/mips-yeeloong.rmk (kernel_img_HEADERS): Add bitmap.h, + video.h, gfxterm.h, font.h, bitmap_scale.h and bufio.h. + * conf/mips.rmk (kernel_img_HEADERS): Add values instead of overwriting. + * include/grub/bitmap.h: Add EXPORT_FUNC and EXPORT_VAR. + * include/grub/bitmap_scale.h: Likewise. + * include/grub/bufio.h: Likewise. + * include/grub/font.h: Likewise. + * include/grub/gfxterm.h: Likewise. + * include/grub/video.h: Likewise. + * include/grub/vbe.h: Don't include video_fb.h. + * video/i386/pc/vbe.c: Include video_fb.h. + * commands/i386/pc/vbetest.c: Include video.h. + +2010-02-25 Jordan Uggla + + * util/grub-mkconfig.in (GRUB_SAVEDEFAULT): Export new variable. + * util/grub-mkconfig_lib.in (save_default_entry): Only save a new + default entry if GRUB_SAVEDEFAULT=true. This allows using + GRUB_DEFAULT=saved on its own to let grub-reboot work, without + saving a new default on every boot. + +2010-02-24 Vladimir Serbinenko + + * normal/crypto.c (read_crypto_list): Fix a memory leak. + * normal/term.c (read_terminal_list): Likewise. + * normal/main.c (grub_normal_init_page): Likewise. + (grub_normal_read_line_real): Likewise. + +2010-02-24 Vladimir Serbinenko + + * loader/i386/multiboot_mbi.c (grub_multiboot_set_bootdev): Fix a + memory leak. + Reported by: Seth Goldberg. + +2010-02-24 Joey Korkames + + * term/ieee1275/ofconsole.c (grub_ofconsole_readkey): Remove + duplicate declaration of `start'. + +2010-02-20 Vladimir Serbinenko + + * fs/iso9660.c (grub_iso9660_iterate_dir): Strip version from joliet + filename. + Reported by: Georgy Buranov + +2010-02-20 Carles Pina i Estany + + * util/grub-mkrawimage.c (usage): Change string formatting to + improve gettext. + +2010-02-20 Manoel Rebelo Abranches + + * term/ieee1275/ofconsole.c (grub_ofconsole_readkey): Add delete and + backspace keys. + +2010-02-20 Vladimir Serbinenko + + * video/fb/video_fb.c (grub_video_fb_scroll): Fix a pixel size bug. + Reported by: Michael Suchanek. + +2010-02-18 Samuel Thibault + + * util/grub-mkconfig.in: Export GRUB_INIT_TUNE. + * util/grub.d/00_header.in: Handle GRUB_INIT_TUNE. + +2010-02-16 Vladimir Serbinenko + + Remove any reference to non-free fonts. + + * commands/videotest.c (grub_cmd_videotest): Use unifont by default. + * docs/gfxmenu-theme-example.txt: Removed. It's both outdated and + uses non-free components. + * font/font.c (grub_font_get_name): Remove example name. + * gfxmenu/gui_label.c (grub_gui_label_new): Use unifont by default. + * gfxmenu/gui_list.c (grub_gui_list_new): Likewise. + * gfxmenu/gui_progress_bar.c (grub_gui_progress_bar_new): Likewise. + * gfxmenu/view.c (grub_gfxmenu_view_new): Likewise. + +2010-02-16 Georgy Buranov + + * disk/efi/efidisk.c (grub_efidisk_get_device_name): Fix a typo. + +2010-02-15 Vladimir Serbinenko + + * term/serial.c (serial_get_divisor) [GRUB_MACHINE_MIPS_YEELOONG]: + Double divisor. + (serial_hw_init) [GRUB_MACHINE_MIPS_YEELOONG]: Don't enable advanced + features. + (GRUB_MOD_INIT) [GRUB_MACHINE_MIPS_YEELOONG]: Default to 115200. + +2010-02-15 Vladimir Serbinenko + + * gensymlist.sh.in: Use TARGET_CC instead of CC. + +2010-02-14 Samuel Thibault + + * commands/i386/pc/play.c (GRUB_MOD_INIT(play)): Fix help. + * docs/grub.texi (Command-line and menu entry commands): Document play + command. + +2010-02-14 Samuel Thibault + + * commands/i386/pc/play.c (grub_cmd_play): If grub_file_open fails, + parse arguments as inline tempo and notes. Move code for playing notes + to... + (play): ... new function. + +2010-02-14 Samuel Thibault + + * commands/i386/pc/play.c (T_REST, T_FINE, struct note, beep_on): Use + grub_uint16_t instead of short. + (grub_cmd_play): Use grub_uint32_t instead of int, convert data from + disk from little endian to cpu endianness. + +2010-02-07 Samuel Thibault + + * commands/i386/pc/play.c (BASE_TEMPO): Set to 60 * + GRUB_TICKS_PER_SECOND instead of 120. + +2010-02-14 Vladimir Serbinenko + + * term/ieee1275/ofconsole.c (grub_ofconsole_readkey): Wait for possible + escape sequence after \e. + +2010-02-14 Vladimir Serbinenko + + * term/ieee1275/ofconsole.c (grub_ofconsole_putchar): Don't output + non-ASCII characters. + +2010-02-14 Vladimir Serbinenko + + * util/grub-mkconfig_lib.in (prepare_grub_to_access_device): Enclose + set root in single quotes to prevent \, from being unescaped. + +2010-02-14 Vladimir Serbinenko + + Prevent unknown commands from stopping menuentry execution. + + * script/execute.c (grub_script_execute_cmdline): Print error after + unknown command. + +2010-02-14 Vladimir Serbinenko + + * fs/i386/pc/pxe.c (GRUB_MOD_INIT): Fix typo. + Reported by: Pavel Pisa. + +2010-02-13 Vladimir Serbinenko + + * io/gzio.c (grub_gzio_open): Use grub_zalloc. + +2010-02-13 Vladimir Serbinenko + + Merge grub_ieee1275_map_physical into grub_map and rename to + grub_ieee1275_map + + * include/grub/ieee1275/ieee1275.h (grub_ieee1275_map): New proto. + * include/grub/sparc64/ieee1275/ieee1275.h (grub_ieee1275_map_physical): + Remove. + * kern/ieee1275/openfw.c (grub_map): Rename to ... + (grub_ieee1275_map): ... this. All users updated. Add phys_lo when + necessary. + * kern/sparc64/ieee1275/ieee1275.c (grub_ieee1275_map_physical): Remove. + +2010-02-13 Vladimir Serbinenko + + * disk/ieee1275/ofdisk.c (grub_ofdisk_open): Check device type before + opening and not after. + +2010-02-13 Vladimir Serbinenko + + * term/ieee1275/ofconsole.c (grub_ofconsole_readkey): Macroify + constants. + +2010-02-13 Vladimir Serbinenko + + * loader/sparc64/ieee1275/linux.c (align_addr): Remove. + (alloc_phys): Use ALIGN_UP instead of align_addr. + +2010-02-13 Vladimir Serbinenko + + * loader/sparc64/ieee1275/linux.c (alloc_phys): Correct bounds checking. + +2010-02-13 Vladimir Serbinenko + + * kern/sparc64/ieee1275/crt0.S (codestart): Move modules backwards. + +2010-02-13 Vladimir Serbinenko + + * disk/ieee1275/ofdisk.c (grub_ofdisk_read): Remove excessively + verbose dprintf. + +2010-02-13 Vladimir Serbinenko + + Fix over-4GiB seek on sparc64. + + * include/grub/ieee1275/ieee1275.h (grub_ieee1275_seek): + Replace pos_i and pos_lo with pos. All users updated. + * include/grub/powerpc/ieee1275/ieee1275.h (GRUB_IEEE1275_CELL_SIZEOF): + New constant. + * include/grub/sparc64/ieee1275/ieee1275.h (GRUB_IEEE1275_CELL_SIZEOF): + Likewise. + * kern/ieee1275/ieee1275.c (grub_ieee1275_seek): Split pos into pos_hi + and pos_lo. + +2010-02-13 Vladimir Serbinenko + + * util/grub-mkrawimage.c (main): Call set_program_name. + +2010-02-13 Vladimir Serbinenko + + Properly align 64-bit targets. + + * util/grub-mkrawimage.c (ALIGN_ADDR): New macro. + (generate_image): Use ALIGN_ADDR. + +2010-02-13 Vladimir Serbinenko + + Properly create cross-endian images. + + * include/grub/types.h (grub_host_to_target_addr): New macro + * util/grub-mkrawimage.c (generate_image): Add missing host_to_target. + +2010-02-13 Vladimir Serbinenko + + * util/grub-mkrawimage.c (generate_image): Add forgotten ALIGN_UP. + +2010-02-10 Vladimir Serbinenko + + Pass SIMPLE framebuffer size in bytes and not 64K blocks. + + * loader/i386/efi/linux.c (grub_linux_setup_video): Don't divide by 64K. + * loader/i386/linux.c (grub_linux_setup_video): Likewise. + (grub_linux_boot): Divide by 64K when on VESA. + +2010-02-10 Vladimir Serbinenko + + Support GRUB_GFXPAYLOAD_LINUX. + + * util/grub-mkconfig.in: Export GRUB_GFXPAYLOAD_LINUX. + * util/grub.d/10_linux.in (linux_entry): Handle GRUB_GFXPAYLOAD_LINUX. + +2010-02-10 Vladimir Serbinenko + + * script/execute.c (grub_script_execute_cmdline): Use grub_print_error + to show messages instead of discarding them. + Process errors after executing command and not before. Keep old method + too as precaution. + +2010-02-09 Vladimir Serbinenko + + * configure.ac: Check for ft2build.h. + +2010-02-07 Vladimir Serbinenko + + * kern/ieee1275/openfw.c (grub_halt): Try executing "poweroff". + +2010-02-07 Vladimir Serbinenko + + * genkernsyms.sh.in: Use TARGET_CC. + +2010-02-07 Colin Watson + + * NEWS: Update. + +2010-02-07 Vladimir Serbinenko + + * include/grub/multiboot2.h: Remove leftover file. + * include/grub/normal.h [GRUB_UTIL]: Remove leftover declarations. + * include/grub/partition.h [GRUB_UTIL]: Likewise. + +2010-02-07 Yves Blusseau + + * gnulib/getdelim.c: add missing header (type ssize_t must be defined). + +2010-02-07 Vladimir Serbinenko + + Fix warnings in grub-emu when compiling with maximum warning options. + + * util/grub-emu.c (ENABLE_RELOCATABLE): New definition. + (grub_arch_modules_addr): Return 0 and not NULL. + * util/misc.c (ENABLE_RELOCATABLE): New definition. + (xstrdup): Use newstr instead of dup. + * util/hostdisk.c (grub_util_biosdisk_get_grub_dev): Rename one instance + of disk to dsk to avoid shadowing. + (find_free_slot): Fix prototype. + * util/getroot.c (grub_util_is_dmraid): Make static. + * include/grub/time.h (grub_get_rtc) [GRUB_MACHINE_EMU || GRUB_UTIL]: + Add missing prototype. + * util/sdl.c (grub_video_sdl_set_viewport): Remove. + +2010-02-07 Vladimir Serbinenko + + * loader/i386/linux.c (grub_linux_setup_video): Handle error + appropriately. + +2010-02-07 Vladimir Serbinenko + + * fs/reiserfs.c (grub_reiserfs_read): Use #if 0 instead of commenting + code out. + +2010-02-07 Vladimir Serbinenko + + * include/grub/cache.h (grub_arch_sync_caches) [i386 || x86_64]: Inline. + * kern/i386/coreboot/init.c (grub_arch_sync_caches): Remove. + * kern/i386/efi/init.c (grub_arch_sync_caches): Likewise. + * kern/i386/ieee1275/init.c (grub_arch_sync_caches): Likewise. + * kern/i386/pc/init.c (grub_arch_sync_caches): Likewise. + * util/misc.c (grub_arch_sync_caches) [i386 || x86_64]: Likewise. + +2010-02-07 Vladimir Serbinenko + + * include/grub/err.h (grub_err_printf): Don't export. + +2010-02-07 Vladimir Serbinenko + + * include/grub/dl.h (grub_dl_register_symbol): Don't export. + +2010-02-07 Vladimir Serbinenko + + * include/grub/i18n.h (grub_gettext_dummy): Removed. + * kern/misc.c (grub_gettext_dummy): Make static. + +2010-02-06 Vladimir Serbinenko + + * kern/misc.c (grub_utf8_to_ucs4): Don't eat valid characters preceeded + by non-valid ones. + * kern/term.c (grub_putchar): Likewise. + +2010-02-06 Vladimir Serbinenko + + * partmap/sun.c (sun_partition_map_iterate): Restructure flow to fix + buggy hook call and memory leak. + +2010-02-06 Vladimir Serbinenko + + * commands/ls.c (grub_ls_list_files): Free pathname on exit. + +2010-02-06 Vladimir Serbinenko + + * fs/fat.c (grub_fat_iterate_dir): Free unibuf at exit. + +2010-02-06 Vladimir Serbinenko + + * loader/i386/pc/xnu.c (grub_xnu_set_video): Add const qualifier to + modevar. + Return grub_errno on allocation error. + +2010-02-06 Vladimir Serbinenko + + * disk/ieee1275/ofdisk.c (grub_ofdisk_read): Correct error handling. + +2010-02-06 Yves Blusseau + + * conf/common.rmk (grub_script_check_SOURCES): add missing dependencies. + (grub_mkpasswd_pbkdf2_SOURCES): Likewise. + +2010-02-06 Vladimir Serbinenko + + * fs/i386/pc/pxe.c (grub_pxefs_dir): Return with failure on + non-pxe disk. + (grub_pxefs_open): Likewise. + +2010-02-06 Robert Millan + + * util/grub.d/10_hurd.in: Add --class information to menuentries. + * util/grub.d/10_kfreebsd.in: Likewise. + * util/grub.d/10_linux.in: Likewise. + +2010-02-06 Colin D Bennett + + * conf/common.rmk (pkglib_MODULES): Add gfxmenu.mod. + (gfxmenu_mod_SOURCES): New variable. + (gfxmenu_mod_CFLAGS): Likewise. + (gfxmenu_mod_LDFLAGS): Likewise. + * include/grub/term.h (grub_term_set_current_output): Declare + argument as const. + * docs/gfxmenu-theme-example.txt: New file. + * gfxmenu/gfxmenu.c: Likewise. + * gfxmenu/gui_box.c: Likewise. + * gfxmenu/gui_canvas.c: Likewise. + * gfxmenu/gui_circular_progress.c: Likewise. + * gfxmenu/gui_image.c: Likewise. + * gfxmenu/gui_label.c: Likewise. + * gfxmenu/gui_list.c: Likewise. + * gfxmenu/gui_progress_bar.c: Likewise. + * gfxmenu/gui_string_util.c: Likewise. + * gfxmenu/gui_util.c: Likewise. + * gfxmenu/icon_manager.c: Likewise. + * gfxmenu/model.c: Likewise. + * gfxmenu/named_colors.c: Likewise. + * gfxmenu/theme_loader.c: Likewise. + * gfxmenu/view.c: Likewise. + * gfxmenu/widget-box.c: Likewise. + * include/grub/gfxmenu_model.h: Likewise. + * include/grub/gfxmenu_view.h: Likewise. + * include/grub/gfxwidgets.h: Likewise. + * include/grub/gui.h: Likewise. + * include/grub/gui_string_util.h: Likewise. + * include/grub/icon_manager.h: Likewise. + +2010-02-06 Vladimir Serbinenko + + Agglomerate scrolling in gfxterm. + + * term/gfxterm.c (grub_virtual_screen): New member 'total_screen'. + (grub_virtual_screen_setup): Initialise 'total_screen'. + (write_char): Split to ... + (paint_char): ... this ... + (write_char): ... and this. + (paint_char): Handle delayed scrolling. + (draw_cursor): Likewise. + (scroll_up): Split to ... + (real_scroll): ... this ... + (scroll_up): ... and this. + (real_scroll): Handle multi-line scroll and draw below-the-bottom + characters. + (grub_gfxterm_refresh): Call real_scroll. + +2010-02-06 Colin D Bennett + + * include/grub/misc.h (grub_iscntrl): New inline function. + (grub_isalnum): Likewise. + (grub_strtol): Likewise. + +2010-02-06 Colin D Bennett + + * normal/menu_text.c (get_entry_number): Move from here ... + * normal/menu.c (get_entry_number): ... moved here. + * include/grub/menu.h (grub_menu_get_default_entry_index): + New prototype. + * normal/menu.c (grub_menu_get_default_entry_index): New function. + * normal/menu_text.c (run_menu): Use grub_menu_get_default_entry_index. + * include/grub/menu_viewer.h (grub_menu_viewer_init): New prototype. + (grub_menu_viewer_should_return): Likewise. + * normal/main.c (GRUB_MOD_INIT (normal)): Call grub_menu_viewer_init. + * normal/menu_text.c (run_menu): Enable menu switching. + * normal/menu_viewer.c (should_return): New variable. + (menu_viewer_changed): Likewise. + (grub_menu_viewer_show_menu): Handle menu viewer changes. + (grub_menu_viewer_should_return): New function. + (menuviewer_write_hook): Likewise. + (grub_menu_viewer_init): Likewise. + +2010-02-06 Colin D Bennet +2010-02-06 Vladimir Serbinenko + + Support for gfxterm in a window. + + * include/grub/gfxterm.h: New file. + * include/grub/video.h (struct grub_video_rect): New declaration. + (grub_video_rect_t): Likewise. + * term/gfxterm.c (struct grub_gfxterm_window): New type. + (refcount): New variable. + (render_target): Likewise. + (window): Likewise. + (repaint_callback): Likewise. + (grub_virtual_screen_setup): Use 'render_target'. + (init_window): New function. + (grub_gfxterm_init_window): Likewise. + (grub_gfxterm_init): Check reference counter. + Use init_window. + (destroy_window): New function. + (grub_gfxterm_destroy_window): Likewise. + (grub_gfxterm_fini): Check reference counter. + Use destroy_window. + (redraw_screen_rect): Restore viewport. + Use 'render_target' and 'window'. + Call 'repaint_callback'. + (write_char): Use 'render_target'. + (draw_cursor): Likewise. + (scroll_up): Restore viewport. + Use 'render_target' and 'window'. + Call 'repaint_callback'. + (grub_gfxterm_cls): Likewise. + (grub_gfxterm_refresh): Use 'window'. + (grub_gfxterm_set_repaint_callback): New function. + (grub_gfxterm_background_image_cmd): Use 'window'. + (grub_gfxterm_get_term): New function. + (GRUB_MOD_INIT(term_gfxterm)): Set 'refcount' to 0. + +2010-02-06 Colin D Bennett + + Bitmap scaling support. + + * conf/common.rmk (pkglib_MODULES): Add bitmap_scale.mod. + (bitmap_scale_mod_SOURCES): New variable. + (bitmap_scale_mod_CFLAGS): Likewise. + (bitmap_scale_mod_LDFLAGS): Likewise. + * include/grub/bitmap_scale.h: New file. + * term/gfxterm.c (BACKGROUND_CMD_ARGINDEX_MODE): New definiton. + (background_image_cmd_options): New variable. + (grub_gfxterm_background_image_cmd): Support bitmap stretching. + (cmd): Rename and change type to ... + (background_image_cmd_handle): ... this. All users updated. + (GRUB_MOD_INIT(term_gfxterm)): Make background_image extended command. + * video/bitmap_scale.c: New file. + +2010-02-06 Vladimir Serbinenko + + SDL support. + + * Makefile.in (LIBSDL): New variable. + (enable_grub_emu_sdl): Likewise. + * conf/i386-pc.rmk (grub_emu_SOURCES): Add video files. + (grub_emu_SOURCES) [enable_grub_emu_sdl]: Add util/sdl.c. + (grub_emu_LDFLAGS) [enable_grub_emu_sdl]: Add $(LIBSDL). + * configure.ac: Detect SDL availability and add --enable-grub-emu-sdl + * util/sdl.c: New file. + +2010-02-06 Colin D Bennett +2010-02-06 Vladimir Serbinenko + + Double buffering support. + + * commands/i386/pc/videotest.c (grub_cmd_videotest): Swap doublebuffers. + * include/grub/video.h: Update comment. + * include/grub/video_fb.h (grub_video_fb_doublebuf_update_screen_t): + New type. + (grub_video_fb_doublebuf_blit_init): New prototype. + * term/gfxterm.c (scroll_up): Support double buffering. + (grub_gfxterm_refresh): Likewise. + * video/fb/video_fb.c (doublebuf_blit_update_screen): New function. + (grub_video_fb_doublebuf_blit_init): Likewise. + * video/i386/pc/vbe.c (framebuffer): Remove 'render_target'. Add + 'front_target', 'back_target', 'offscreen_buffer', 'page_size', + 'displayed_page', 'render_page' and 'update_screen'. + (grub_video_vbe_fini): Free offscreen buffer. + (doublebuf_pageflipping_commit): New function. + (doublebuf_pageflipping_update_screen): Likewise. + (doublebuf_pageflipping_init): Likewise. + (double_buffering_init): Likewise. + (grub_video_vbe_setup): Enable doublebuffering. + (grub_video_vbe_swap_buffers): Implement. + (grub_video_vbe_set_active_render_target): Handle double buffering. + (grub_video_vbe_get_active_render_target): Likewise. + (grub_video_vbe_get_info_and_fini): Likewise. Free offscreen_buffer. + (grub_video_vbe_adapter): Use grub_video_vbe_get_active_render_target. + (grub_video_vbe_enable_double_buffering): Likewise. + (grub_video_vbe_swap_buffers): Use update_screen. + (grub_video_set_mode): Use double buffering. + +2010-02-06 Robert Millan + + * maintainance/gentrigtables.py: Remove. + * lib/trig.c: Likewise. + + * gentrigtables.c: New file. C rewrite of gentrigtables.py. + + * conf/common.rmk (trig_mod_SOURCES): Replace `lib/trig.c' with + `trigtables.c'. + (trigtables.c): New rule. + (gentrigtables): Likewise. + (DISTCLEANFILES): Add `trigtables.c' and `gentrigtables'. + +2010-02-06 Robert Millan + + * maintainance/gentrigtables.py: Avoid duplicate hardcoding of + integer constants. + +2010-02-06 Colin D Bennet + + Trigonometry support. + + * include/grub/trig.h: New file. + * lib/trig.c: Likewise. + * maintainance/gentrigtables.py: Likewise. + * conf/common.rmk (pkglib_MODULES): Add trig.mod. + (trig_mod_SOURCES): New variable. + (trig_mod_CFLAGS): Likewise. + (trig_mod_LDFLAGS): Likewise. + +2010-02-06 Vladimir Serbinenko + + * kern/ieee1275/openfw.c (grub_ieee1275_encode_devname): Support whole + disk devices. + +2010-02-06 Vladimir Serbinenko + + * kern/ieee1275/openfw.c (grub_devalias_iterate): Stop iterating on + error. + +2010-02-03 Vladimir Serbinenko + + * util/hostdisk.c (open_device): Don't use partition device when reading + before the partition. + (grub_util_biosdisk_read): Don't read from partition and before the + partition in single operation. + (grub_util_biosdisk_write): Don't write to partition and before the + partition in single operation. + +2010-02-03 Torsten Landschoff + + * kern/disk.c (grub_disk_read): Fix offset computation when reading + last sectors. + +2010-02-03 Vladimir Serbinenko + + * disk/i386/pc/biosdisk.c (grub_biosdisk_read): Handle non-2048 aligned + CDROM reads. + (grub_biosdisk_write): Refuse to write to CDROM. + +2010-01-31 Vladimir Serbinenko + + * disk/ieee1275/ofdisk.c (grub_ofdisk_iterate): Fix off-by-one error. + +2010-01-31 Vladimir Serbinenko + + * font/font.c (find_glyph): Check that bmp_idx is available before + using it. + (grub_font_get_string_width): Never call grub_font_get_glyph_internal + with (font == NULL). + +2010-01-28 Christian Schmitt + + * util/ieee1275/grub-install.in: Fix nvsetenv arguments. + +2010-01-28 BVK Chaitanya + + * include/grub/script_sh.h (sourcecode): Add const qualifier. + * util/grub-script-check.c (getline): Fix empty lines case. + +2010-01-28 Robert Millan + + * Makefile.in (check): Exit with fail status when one of the tests + fails. + * tests/example_functional_test.c (example_test): Fix reversed assert. + * tests/example_unit_test.c (example_test): Likewise. + +2010-01-28 Colin Watson + + * util/grub.d/10_linux.in: This script does not use any of the + contents of gettext.sh, only the external command `gettext', so stop + sourcing it. (Moreover, gettext.sh isn't necessarily installed in + the same prefix as GRUB.) + * util/grub.d/10_kfreebsd.in: Likewise. + +2010-01-27 Vladimir Serbinenko + + * normal/cmdline.c (grub_cmdline_get): Fix completion in the middle + of the line. + +2010-01-27 Vladimir Serbinenko + + * kern/disk.c (grub_disk_read): Fix offset computation when reading + last sectors. + +2010-01-27 Vladimir Serbinenko + + * commands/hashsum.c (hash_file): Avoid possible stack overflow by + having a 4KiB and not 32KiB buffer size. + +2010-01-27 Robert Millan + + * util/hostfs.c: Include `'. + (grub_hostfs_read): Handle errors from fseeko() and fread(). + +2010-01-27 Robert Millan + + * kern/disk.c (grub_disk_read): Fix bug that would cause infinite + loop when using read hooks on files whose size isn't sector-aligned. + +2010-01-27 Robert Millan + + Remove unused parameter. + + * fs/iso9660.c (struct grub_iso9660_data): Remove `length' parameter. + (grub_iso9660_open): Remove initialization of `data->length'. + +2010-01-27 Robert Millan + + * util/grub-fstest.c (fstest): Rewrite allocation, fixing a few + memleak conditions. + +2010-01-27 Carles Pina i Estany + + * util/lvm.c: New macro LVM_DEV_MAPPER_STRING. + (grub_util_lvm_isvolume): Use LVM_DEV_MAPPER_STRING. + +2010-01-26 Carles Pina i Estany + + * util/bin2h.c (usage): Fix warning (space after backslash). + +2010-01-26 Carles Pina i Estany + + * font/font.c: Include `grub/fontformat.h. + Remove font file format constants. + (grub_font_load): Use the new macros. + * include/grub/fontformat.h: New file. + * util/grub-mkfont.c: Include `grub/fontformat.c'. + (write_font_pf2): Use the new macros. + +2010-01-26 Robert Millan + + * util/bin2h.c (usage): Make --help actually explain what `grub-bin2h' + does. + +2010-01-26 Robert Millan + + * include/grub/i386/pc/boot.h (GRUB_BOOT_MACHINE_PXE_DL): New macro. + + * boot/i386/pc/pxeboot.S: Include `'. + (_start): Macroify `0x7F'. + + * kern/i386/pc/init.c: Include `'. + (make_install_device): Use "(pxe)" as fallback prefix when booting + via PXE. + +2010-01-26 Vladimir Serbinenko + + * configure.ac: Reset LIBS after check for libgcc symbols. + +2010-01-25 Colin Watson + + * util/hostdisk.c (open_device): Add trailing newline to debug + message. + +2010-01-25 Grégoire Sutre + + * configure.ac: Check for `limits.h'. + * util/misc.c: Include `' (for PATH_MAX). + +2010-01-24 Robert Millan + + * loader/mips/linux.c (grub_cmd_linux, grub_cmd_initrd): Don't + capitalize error strings. + +2010-01-24 Samuel Thibault + + * util/grub.d/10_hurd.in: Add a recovery mode. + +2010-01-23 Vladimir Serbinenko + + * configure.ac: Check for libgcc symbols with -nostdlib. + +2010-01-23 BVK Chaitanya + + * acinclude.m4: Quote underquoted AC_DEFUN parameters. + +2010-01-22 Vladimir Serbinenko + + * term/ieee1275/ofconsole.c (grub_ofconsole_setcolorstate): Allocate on + stack since heap may be unavailable at that point. + (grub_ofconsole_gotoxy): Likewise. + +2010-01-22 Vladimir Serbinenko + + * configure.ac: Check for _restgpr_14_x. + * include/grub/powerpc/libgcc.h [HAVE__RESTGPR_14_X]: Add _restgpr_*_x + and _savegpr_* prototypes. + +2010-01-22 Robert Millan + + Use generic grub_reboot() for i386-efi. + + * kern/efi/efi.c [__i386__] (grub_reboot): Remove. + * kern/i386/efi/startup.S: Include `"../realmode.S"'. + * kern/i386/realmode.S: Include `'. + +2010-01-22 Vladimir Serbinenko + + * kern/ieee1275/init.c (grub_machine_set_prefix): Don't check for + presence of "prefix" variable as it breaks when normal.mod is + embedded. + +2010-01-21 Vladimir Serbinenko + + * term/ieee1275/ofconsole.c (grub_ofconsole_dimensions): Allocate on + stack since heap is unavailable at that point. + +2010-01-21 Vladimir Serbinenko + + * include/grub/i386/bsd.h (FREEBSD_N_BIOS_GEOM): Removed. + (grub_freebsd_bootinfo): Rewritten. + * loader/i386/bsd.c (grub_freebsd_boot): Use new grub_freebsd_bootinfo. + +2010-01-21 Vladimir Serbinenko + + * util/misc.c (make_system_path_relative_to_its_root): Fix typo. + +2010-01-21 Robert Millan + + * po/POTFILES: Remove mkisofs-related files. They have their own TLP + domain now. + +2010-01-20 Felix Zielcke + + * util/misc.c (make_system_path_relative_to_its_root): Change the work + around for handling "/" to the correct fix. Fix a memory leak. Use + xstrdup instead of strdup. + +2010-01-20 Vladimir Serbinenko + + * conf/mips.rmk (kernel_img_HEADERS): Add env_private.h + +2010-01-20 Vladimir Serbinenko + + Optimise glyph lookup by Basic Multilingual Plane lookup array. + + * font/font.c (struct grub_font): New member 'bmp_idx'. + (font_init): Initialise 'bmp_idx'. + (load_font_index): Fill 'bmp_idx'. + (find_glyph): Make inline. Use bmp_idx for BMP characters. + +2010-01-20 Vladimir Serbinenko + + * video/fb/video_fb.c (grub_video_fb_scroll): Optimise by avoiding + unnecessary calls. + +2010-01-20 Vladimir Serbinenko + + Move context handling out of the kernel. + + * conf/any-emu.rmk (grub_emu_SOURCES): Add normal/context.c. + * conf/common.rmk (normal_mod_SOURCES): Add normal/context.c. + * conf/i386-coreboot.rmk (kernel_img_HEADERS): Add env_private.h. + * conf/i386-efi.rmk: Likewise. + * conf/i386-ieee1275.rmk: Likewise. + * conf/i386-pc.rmk: Likewise. + * conf/powerpc-ieee1275.rmk: Likewise. + * conf/sparc64-ieee1275.rmk: Likewise. + * conf/x86_64-efi.rmk: Likewise. + * include/grub/env.h: Include grub/menu.h. + (grub_env_var_type): Removed. + (grub_env_var): Replaced field 'type' with 'global'. + (grub_env_find): New prototype. + (grub_env_context_open): Remove EXPORT_FUNC. + (grub_env_context_close): Likewise. + (grub_env_export): Likewise. + (grub_env_set_data_slot): Removed. + (grub_env_get_data_slot): Likewise. + (grub_env_unset_data_slot): Likewise. + (grub_env_unset_menu): New prototype. + (grub_env_set_menu): Likewise. + (grub_env_get_menu): Likewise. + * include/grub/env_private.h: New file. + * include/grub/normal.h (grub_context_init): New prototype. + (grub_context_fini): Likewise. + * kern/corecmd.c (grub_core_cmd_export): Moved from here ... + * normal/context.c (grub_cmd_export): ... to here. + * kern/env.c: Include env_private.h. + (HASHSZ): Moved to include/grub/env_private.h. + (grub_env_context): Likewise. + (grub_env_sorted_var): Likewise. + (current_context): Renamed from this ... + (grub_current_context): ...to this. 'static' removed. All users updated. + (grub_env_find): Removed 'static'. + (grub_env_context_open): Moved to normal/context.c. + (grub_env_context_close): Likewise. + (grub_env_export): Likewise. + (mangle_data_slot_name): Removed. + (grub_env_set_data_slot): Likewise. + (grub_env_get_data_slot): Likewise. + (grub_env_unset_data_slot): Likewise. + * kern/main.c (grub_set_root_dev): Don't export root. + It will be done later. + (grub_main): Don't export prefix. + It will be done later. + * normal/context.c: New file. + * normal/main.c (free_menu): Use grub_env_unset_menu. + (grub_normal_add_menu_entry): Use grub_env_get_menu. + (read_config_file): Use grub_env_get_menu and grub_env_set_menu. + (GRUB_MOD_INIT(normal)): Call grub_context_init. + (GRUB_MOD_FINI(normal)): Call grub_context_fini. + +2010-01-20 Vladimir Serbinenko + + setpci support. + + * commands/setpci.c: New file. + * conf/i386.rmk (pkglib_MODULES): Add setpci.mod. + (setpci_mod_SOURCES): New variable. + (setpci_mod_CFLAGS): Likewise. + (setpci_mod_LDFLAGS): Likewise. + +2010-01-20 Vladimir Serbinenko + + Byte-addressable PCI configuration space. + + * bus/pci.c (grub_pci_make_address): Use byte address instead of + dword address. + (grub_pci_iterate): Use macroses GRUB_PCI_REG_PCI_ID and + GRUB_PCI_REG_CACHELINE. + * bus/usb/ohci.c (grub_ohci_pci_iter): Use macroses + GRUB_PCI_REG_CLASS and GRUB_PCI_REG_ADDRESS_REG0. + * bus/usb/uhci.c (grub_ohci_pci_iter): Use macroses + GRUB_PCI_REG_CLASS and GRUB_PCI_REG_ADDRESS_REG4. + * commands/efi/fixvideo.c (scan_card): Use macros GRUB_PCI_REG_CLASS. + * commands/efi/loadbios.c (enable_rom_area): Pass byte-address to + grub_pci_make_address. + (lock_rom_area): Likewise. + * commands/lspci.c (grub_lspci_iter): Use macroses + GRUB_PCI_REG_CLASS and GRUB_PCI_REG_ADDRESSES. Handle byte-addressing + of grub_pci_make_address. + * disk/ata.c (grub_ata_pciinit): Likewise. + * include/grub/pci.h (GRUB_PCI_REG_PCI_ID): New macro. + (GRUB_PCI_REG_VENDOR): Likewise. + (GRUB_PCI_REG_DEVICE): Likewise. + (GRUB_PCI_REG_COMMAND): Likewise. + (GRUB_PCI_REG_STATUS): Likewise. + (GRUB_PCI_REG_REVISION): Likewise. + (GRUB_PCI_REG_CLASS): Likewise. + (GRUB_PCI_REG_CACHELINE): Likewise. + (GRUB_PCI_REG_LAT_TIMER): Likewise. + (GRUB_PCI_REG_HEADER_TYPE): Likewise. + (GRUB_PCI_REG_BIST): Likewise. + (GRUB_PCI_REG_ADDRESSES): Likewise. + (GRUB_PCI_REG_ADDRESS_REG): Likewise. + (GRUB_PCI_REG_ADDRESS_REG): Likewise. + (GRUB_PCI_REG_ADDRESS_REG): Likewise. + (GRUB_PCI_REG_ADDRESS_REG): Likewise. + (GRUB_PCI_REG_ADDRESS_REG): Likewise. + (GRUB_PCI_REG_ADDRESS_REG): Likewise. + (GRUB_PCI_REG_CIS_POINTER): Likewise. + (GRUB_PCI_REG_SUBVENDOR): Likewise. + (GRUB_PCI_REG_SUBSYSTEM): Likewise. + (GRUB_PCI_REG_ROM_ADDRESS): Likewise. + (GRUB_PCI_REG_CAP_POINTER): Likewise. + (GRUB_PCI_REG_IRQ_LINE): Likewise. + (GRUB_PCI_REG_IRQ_PIN): Likewise. + (GRUB_PCI_REG_MIN_GNT): Likewise. + (GRUB_PCI_REG_MAX_LAT): Likewise. + * loader/i386/efi/linux.c (find_framebuf): Use GRUB_PCI_REG_CLASS. + * loader/i386/efi/xnu.c (find_framebuf): Likewise. + * video/efi_uga.c (find_framebuf): Likewise. + * video/sm712.c (grub_video_sm712_setup): Likewise. + * util/pci.c (grub_pci_make_address): Use byte-addressed configuration + space. + +2010-01-20 Robert Millan + + * util/grub.d/10_linux.in (linux_entry): Set gfxpayload=keep when it + can be reliably determined to be supported. + +2010-01-20 Robert Millan + + * loader/i386/linux.c (grub_cmd_linux): If `vga=' was used, write down + that VESA is supported. + (grub_linux_boot): Use generic framebuffer unless VESA is known to be + supported. + +2010-01-20 Vladimir Serbinenko + + * conf/common.rmk (font/font.c_DEPENDENCIES): Condition on FONT_SOURCE. + +2010-01-20 Robert Millan + + * util/misc.c (make_system_path_relative_to_its_root): Work around + special-casing of "/", as previous incarnation of this routine did. + +2010-01-20 Vladimir Serbinenko + + Fix any-emu compilation. + + * conf/any-emu.rmk (bin_UTILITIES): Add grub-bin2h. + * grub_bin2h_SOURCES: New variable. + +2010-01-20 Robert Millan + + * util/grub.d/00_header.in: Fix stupid mistake from last commit. + +2010-01-20 Robert Millan + + * util/grub.d/00_header.in: Fix handling of locale_dir. + +2010-01-20 Vladimir Serbinenko + + * configure.ac: Add /usr/share/fonts/unifont/unifont.pcf.gz + as possible unifont location (Gentoo). + Reported by: Alexander Brüning + +2010-01-20 Vladimir Serbinenko + + Don't try to generate lists for kernel.img. + + * conf/i386-efi.rmk (pkglib_PROGRAMS): New variable. + (pkglib_MODULES): Remove kernel.img. + (kernel_img_EXPORTS): Removed. + (kernel_img_RELOCATABLE): New variable. + * conf/x86_64-efi.rmk: Likewise. + * genmk.rb: Remove *_EXPORTS support and add *_RELOCATABLE support. + +2010-01-20 Vladimir Serbinenko + + * include/grub/misc.h (grub_sprintf): Removed. All users switched to + grub_xasprintf or grub_snprintf. + (grub_vsprintf): Likewise. + (grub_snprintf): New proto. + (grub_vsnprintf): Likewise. + (grub_xasprintf): Likewise. + (grub_xvasprintf): Likewise. + * kern/misc.c (grub_vprintf): Use grub_vsnprintf_real. + (grub_sprintf): Removed. + (grub_vsnprintf): New function. + (grub_snprintf): Likewise. + (grub_xvasprintf): Likewise. + (grub_xasprintf): Likewise. + (grub_vsprintf): Renamed to ... + (grub_vsnprintf_real): ...this. New argument max_len. + +2010-01-20 BVK Chaitanya + + * include/grub/script_sh.h (sourcecode): Remove const qualifier to + fix grub-script-check warning. + +2010-01-20 Vladimir Serbinenko + + * include/grub/font.h (grub_font_load): Fix prototype. + +2010-01-20 Vladimir Serbinenko + + * conf/mips.rmk (kernel_img_HEADERS) [yeeloong]: Add pci.h. + +2010-01-20 Vladimir Serbinenko + + * include/grub/x86_64/at_keyboard.h: New file. + +2010-01-20 Vladimir Serbinenko + + * loader/mips/linux.c: Include missing grub/i18n.h. + +2009-12-20 Robert Millan + + * normal/menu.c (notify_execution_failure): Clarify error message. + +2009-12-20 Robert Millan + + * commands/loadenv.c (check_blocklists): Use `grub_err_t' as + return value (and revert all return statements). Update users. + +2010-01-20 Dan Merillat + + * kern/device.c (grub_device_iterate): Allocate new part_ent + structure based on sizeof (*p) rather than sizeof (p->next), to + account for structure padding. + + * util/grub-probe.c (probe_raid_level): Return -1 immediately if + disk is NULL, which might happen for LVM physical volumes with no + LVM signature. + +2009-12-20 Robert Millan + + * loader/mips/linux.c (grub_cmd_initrd) + (GRUB_MOD_INIT(linux)): Adjust and gettextize a few strings. + +2009-12-20 Robert Millan + + * kern/mips/yeeloong/init.c (grub_video_sm712_init) + (grub_video_video_init, grub_video_bitmap_init) + (grub_font_manager_init, grub_term_gfxterm_init) + (grub_at_keyboard_init): New extern declarations. + (grub_machine_init): Initialize gfxterm and at_keyboard. + + * kern/main.c (grub_main): Revert grub_printf delay kludge. + + * util/grub-install.in: Revert embed of `at_keyboard.mod' and + `gfxterm.mod' into core image. + + * conf/mips.rmk (pkglib_IMAGES, kernel_img_SOURCES) + (kernel_img_CFLAGS, kernel_img_ASFLAGS, kernel_img_LDFLAGS) + (kernel_img_FORMAT): Copy to ... + + * conf/mips-qemu-mips.rmk (pkglib_IMAGES, kernel_img_SOURCES) + (kernel_img_CFLAGS, kernel_img_ASFLAGS, kernel_img_LDFLAGS) + (kernel_img_FORMAT): ... here, and ... + + * conf/mips-yeeloong.rmk (pkglib_IMAGES, kernel_img_SOURCES) + (kernel_img_CFLAGS, kernel_img_ASFLAGS, kernel_img_LDFLAGS) + (kernel_img_FORMAT): ... here. + + (kernel_img_SOURCES): Add files necessary for output (gfxterm) + and input (at_keyboard) terminals in kernel. + (kernel_img_CFLAGS): Add `-DUSE_ASCII_FAILBACK'. + + (pkglib_MODULES): Remove `pci.mod'. + (pci_mod_SOURCES, pci_mod_CFLAGS, pci_mod_LDFLAGS) + (sm712_mod_SOURCES, sm712_mod_CFLAGS, sm712_mod_LDFLAGS) + (at_keyboard_mod_SOURCES, at_keyboard_mod_CFLAGS) + (at_keyboard_mod_LDFLAGS): Remove variables. + +2010-01-11 Felix Zielcke + + * po/POTFILES: Replace `term/i386/pc/serial.c' with `term/serial.c'. + +2009-12-10 Robert Millan + + * include/grub/mips/libgcc.h: Only export symbols for functions + that libgcc provides. + +2009-12-02 Vladimir Serbinenko + + MIPS support. + + * bus/bonito.c: New file. + * bus/pci.c (grub_pci_iterate): Use GRUB_PCI_NUM_BUS and + GRUB_PCI_NUM_DEVICES. + * term/i386/pc/serial.c: Move to ... + * term/serial.c: ... here. All users updated. + * util/i386/pc/grub-mkimage.c: Move to ... + * util/grub-mkrawimage.c: ... here. All users updated. + * term/i386/pc/at_keyboard.c: Move to ... + * term/at_keyboard.c: ... here. All users updated. + * conf/mips-qemu-mips.rmk: New file. + * conf/mips-yeeloong.rmk: Likewise. + * conf/mips.rmk: Likewise. + * configure.ac: New platforms mipsel-yeeloong, mips-qemu-mips and + mipsel-qemu-mips. + * disk/ata.c (grub_ata_device_initialize): Add GRUB_MACHINE_PCI_IO_BASE + to port addresses. + (grub_ata_pciinit): Support CS5536. + * font/font.c (grub_font_load): Use grub_file_t instead of filename. + * font/font_cmd.c (loadfont_command): Open file before passing it to + grub_font_load. + (pseudo_file_read): New function. + (pseudo_file_close): Likewise. + (pseudo_fs): New structure. + (load_font_module): New function. + (GRUB_MOD_INIT(font_manager)): Load embedded font. + * fs/cpio.c (grub_cpio_open): Handle partial matches correctly. + * genmk.rb: Strip .rel.dyn, .reginfo, .note and .comment. + * genmoddep.awk: Ignore __gnu_local_gp. It's defined by linker. + * include/grub/i386/at_keyboard.h: Split into ... + * include/grub/at_keyboard.h: ... this ... + * include/grub/i386/at_keyboard.h: ... and this. + * include/grub/dl.h (grub_arch_dl_init_linker) [_mips && !GRUB_UTIL]: + New prototype. + * include/grub/elfload.h (grub_elf32_size): New parameter. All users + updated. + (grub_elf64_size): Likewise. + * include/grub/font.h (grub_font_load): Use grub_file_t instead of + filename. + * include/grub/i386/io.h (grub_port_t): New type. All users updated. + * include/grub/i386/coreboot/serial.h: Rewritten. + * include/grub/i386/ieee1275/serial.h: Include + grub/i386/coreboot/serial.h instead of grub/i386/pc/serial.h. + * include/grub/i386/pc/serial.h: Moved from here ... + * include/grub/serial.h: ... to here. All users updated. + * include/grub/i386/pci.h (GRUB_MACHINE_PCI_IO_BASE): New definition. + (GRUB_PCI_NUM_BUS): Likewise. + (GRUB_PCI_NUM_DEVICES): Likewise. + (grub_pci_device_map_range): Add missing volatile keyword. + * include/grub/kernel.h (OBJ_TYPE_FONT): New enum value. + * include/grub/mips/at_keyboard.h: New file. + * include/grub/mips/cache.h: Likewise. + * include/grub/mips/io.h: Likewise. + * include/grub/mips/kernel.h: Likewise. + * include/grub/mips/libgcc.h: Likewise. + * include/grub/mips/pci.h: Likewise. + * include/grub/mips/qemu-mips/boot.h: Likewise. + * include/grub/mips/qemu-mips/kernel.h: Likewise. + * include/grub/mips/qemu-mips/loader.h: Likewise. + * include/grub/mips/qemu-mips/memory.h: Likewise. + * include/grub/mips/qemu-mips/serial.h: Likewise. + * include/grub/mips/qemu-mips/time.h: Likewise. + * include/grub/mips/relocator.h: Likewise. + * include/grub/mips/time.h: Likewise. + * include/grub/mips/types.h: Likewise. + * include/grub/mips/yeeloong/at_keyboard.h: Likewise. + * include/grub/mips/yeeloong/boot.h: Likewise. + * include/grub/mips/yeeloong/kernel.h: Likewise. + * include/grub/mips/yeeloong/loader.h: Likewise. + * include/grub/mips/yeeloong/memory.h: Likewise. + * include/grub/mips/yeeloong/pci.h: Likewise. + * include/grub/mips/yeeloong/serial.h: Likewise. + * include/grub/mips/yeeloong/time.h: Likewise. + * kern/dl.c (grub_dl_resolve_symbols): Handle STT_OBJECT correctly. + * kern/elf.c (grub_elf32_size): New parameter. All users + updated. + (grub_elf64_size): Likewise. + * kern/main.c (grub_main): Call grub_arch_dl_init_linker if necessary. + Load modules before saying "Welcome to GRUB!". + Call grub_refresh after saying "Welcome to GRUB!". + * kern/mips/cache.S: New file. + * kern/mips/cache_flush.S: Likewise. + * kern/mips/dl.c: Likewise. + * kern/mips/init.c: Likewise. + * kern/mips/qemu-mips/init.c: Likewise. + * kern/mips/startup.S: Likewise. + * kern/mips/yeeloong/init.c: Likewise. + * kern/term.c (grub_putcode): Handle NULL terminal. + (grub_getcharwidth): Likewise. + (grub_getkey): Likewise. + (grub_checkkey): Likewise. + (grub_getkeystatus): Likewise. + (grub_getxy): Likewise. + (grub_getwh): Likewise. + (grub_gotoxy): Likewise. + (grub_cls): Likewise. + (grub_setcolorstate): Likewise. + (grub_setcolor): Likewise. + (grub_getcolor): Likewise. + (grub_refresh): Likewise. + * lib/mips/relocator.c (JUMP_SIZEOF): Fix incorrect value. + (write_jump): Add hatch nop. + * lib/mips/relocator_asm.S: Use kern/mips/cache_flush.S. + * lib/mips/setjmp.S: New file. + * loader/mips/linux.c: Likewise. + * term/i386/pc/at_keyboard.c: Move from here ... + * term/at_keyboard.c: ... to here. + * term/i386/pc/serial.c: Moved from here ... + * term/serial.c: ... to here. All users updated. + (TEXT_HEIGHT): Set to 24 to fit linux terminal. + (serial_hw_io_addr): Use GRUB_MACHINE_SERIAL_PORTS. + (serial_translate_key_sequence): Avoid deadlock. + (grub_serial_getkey): Handle backspace. + (grub_serial_putchar): Fix newline handling. + * util/i386/pc/grub-mkimage.c: Move from here ... + * util/grub-mkrawimage.c: ... to here. All users updated. + (generate_image): New parameters 'font_path' and 'format'. + Support embedding font. + Use grub_host_to_target* instead of grub_cpu_to_le*. + (generate_image) [GRUB_MACHINE_MIPS]: Support ELF encapsulation. + (options) [GRUB_PLATFORM_IMAGE_DEFAULT]: New option "--format". + (options): New option "--font". + (usage): Likewise. + (main) [GRUB_PLATFORM_IMAGE_DEFAULT]: Handle "--format". + (main): Handle "--font". + * term/gfxterm.c (grub_virtual_screen): New member bg_color_display. + (grub_virtual_screen_setup): Set bg_color_display. + (redraw_screen_rect): Use bg_color_display instead of incorrect + bg_color. + (grub_gfxterm_cls): Likewise. + * util/elf/grub-mkimage.c (load_modules): New parameter 'config_path'. + Support embedding config file. + (add_segments): Likewise. + (options): New option "--config". + (main): Handle "--config". + * video/sm712.c: New file. + +2010-01-18 Robert Millan + + Fix parallel builds. + + * conf/common.rmk (font/font.c_DEPENDENCIES): New variable (makes + font.c depend on ascii.h). + +2010-01-12 Carles Pina i Estany + + * Makefile.in (DUSE_ASCII_FAILBACK): New macro. + +2010-01-11 Carles Pina i Estany + + * font/font.c (GENERATE_ASCII): Change the name to USE_ASCII_FAILBACK. + By default: disabled. + * Makefile.in (ascii.h): Remove the non-needed grub/bin2h size + parameter. + +2010-01-10 Carles Pina i Estany + + * font/font.c: Update copyright years. + * util/grub-mkfont.c (write_font_ascii_bitmap): Change comment format. + +2010-01-10 Carles Pina i Estany + + * font/font.c: Include `ascii.h'. + (ASCII_BITMAP_SIZE): New macro. + (ascii_font_glyph): Define. + (ascii_glyph_lookup): New function. + (grub_font_get_string_width): Change comment. If glyph not found, use + ascii_glyph_lookup. + (grub_font_get_glyph_with_fallback): If glyph not available returns + ascii_glyph_lookup. + * util/grub-mkfont.c (file_formats): New enum. + (options): Add `ascii-bitmaps' new option. + (usage): Add `asii-bitmaps' new option. + (write_font_ascii_bitmap): New function. + (write_font): Rename to ... + (write_font_p2): ... this. Remove print_glyphs call. + (main): Use file_format. Implement code for ranges if ascii-bitmaps is + used. Call print_glyphs. + * Makefile.in (pkgdata_DATA): Add `ascii.h'. + +2010-01-14 Robert Millan + + * conf/common.rmk (bin_UTILITIES): Add `grub-bin2h'. + (grub_bin2h_SOURCES): New variable. + * util/bin2h.c: New file. + +2010-01-20 Vladimir Serbinenko + + * include/multiboot.h: Resynced with spec. + * include/multiboot2.h: Likewise. + * loader/i386/multiboot_mbi.c (grub_fill_multiboot_mmap): Handle + GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE and GRUB_MACHINE_MEMORY_NVS. + +2010-01-18 Robert Millan + + * include/grub/term.h (grub_term_register_input, + grub_term_register_output): Check return of terminal init() + routines, and abort if errors are raised. + + * commands/terminal.c: Update copyright year. + +2010-01-18 Robert Millan + + * commands/terminal.c (grub_cmd_terminal_input) + (grub_cmd_terminal_output): Check return of terminal init() + routines, and abort if errors are raised. + +2010-01-18 Vladimir Serbinenko + + * include/grub/i386/bsd.h: Fix include pathes. + +2010-01-18 Vladimir Serbinenko + + Add missing *BSD copyright headers. + + * include/grub/aout.h: Add BSD licence. + * include/grub/i386/bsd.h: Parts under different licences moved to ... + * include/grub/i386/freebsd_linker.h: ... here, + * include/grub/i386/freebsd_reboot.h: ... here, + * include/grub/i386/netbsd_bootinfo.h: ... here, + * include/grub/i386/netbsd_reboot.h: ... here, + * include/grub/i386/openbsd_bootarg.h: ... here, + * include/grub/i386/openbsd_reboot.h: ... and here. Added appropriate + licence to each file. + +2010-01-18 Robert Millan + + * acinclude.m4: Remove `nop' assembly instruction; it's not + implemented by all architectures. + +2010-01-18 Robert Millan + + * loader/i386/efi/linux.c (grub_cmd_linux): Stop pretending we're + ELILO. This is no longer necessary. + +2010-01-18 BVK Chaitanya + + Added new tool, grub-scrit-check to verify grub.cfg syntax. + + * util/grub-script-check.c: grub-script-check tool. + * conf/common.rmk: Make rules for grub-script-check. + +2010-01-18 Robert Millan + + Fix annoying UI bug in rescue mode. Thanks to Tristan Gingold for + spotting it back in 2008. Shame on me for forgetting he did. + + * kern/rescue_reader.c (grub_rescue_run): Skip zero-length lines. + +2010-01-18 Robert Millan + + * include/grub/i386/linux.h (GRUB_VIDEO_TYPE_TEXT): Rename to ... + (GRUB_VIDEO_LINUX_TYPE_TEXT): ... this. Update all users. + (GRUB_VIDEO_TYPE_VLFB): Rename to ... + (GRUB_VIDEO_LINUX_TYPE_VESA): ... this. Update all users. + (GRUB_VIDEO_TYPE_EFI): Rename to ... + (GRUB_VIDEO_LINUX_TYPE_SIMPLE): ... this. Update all users. + +2010-01-17 Robert Millan + + * include/grub/test.h: Add license header. + * tests/example_functional_test.c: Likewise. + * tests/example_unit_test.c: Likewise. + * tests/lib/functional_test.c: Likewise. + * tests/lib/test.c: Likewise. + * tests/lib/unit_test.c: Likewise. + +2010-01-17 Vladimir Serbinenko + + Use flag-based instead of hook-based video mode selection and "auto" + keyword. + + * include/grub/video.h (grub_video_adapter): Changed 'setup' member. + (grub_video_set_mode): Changed prototype. All users updated. + (grub_video_check_mode_flag): New inline function. + * video/video.c (parse_modespec): New function. + (grub_video_set_mode): Parse flags and keywords. + +2010-01-17 Carles Pina i Estany + + * util/misc.c (grub_util_info): Fix the order of the parameters in a + fprintf call. + +2010-01-16 Grégoire Sutre + + * genmk.rb (class SCRIPT): Replace option -i of sed by a pipe. + +2010-01-16 Carles Pina i Estany + + * util/grub-editenv.c (usage): Use `program_name' instead of hardcoded + string. + * util/grub-emu.c (usage): Likewise. + * util/grub-mkpasswd-pbkdf2.c (usage): Likewise. + * util/i386/efi/grub-mkimage.c (usage): Likewise. + * util/i386/pc/grub-mkimage.c (usage): Likewise. + * util/i386/pc/grub-setup.c (usage): Likewise. + +2010-01-16 Carles Pina i Estany + + * util/misc.c (grub_util_warn): Gettextizze, print full stop after + the message. + (grub_util_info): Likewise. + (grub_util_error): Likewise. + * util/elf/grub-mkimage.c: Fix capitalisation, quotes, full stops + and/or new lines in `grub_util_warna', `grub_util_info', + `grub_util_error' calls. + * util/getroot.c: Likewise. + * util/grub-editenv.c: Likewise. + * util/grub-emu.c: Likewise. + * util/grub-fstest.c: Likewise. + * util/grub-mkdevicemap.c: Likewise. + * util/grub-mkfont.c: Likewise. + * util/grub-mkpasswd-pbkdf2.c: Likewise. + * util/grub-mkrelpath.c: Likewise. + * util/grub-pe2elf.c: Likewise. + * util/grub-probe.c: Likewise. + * util/hostdisk.c: Likewise. + * util/i386/efi/grub-mkimage.c: Likewise. + * util/i386/pc/grub-mkimage.c: Likewise. + * util/i386/pc/grub-setup.c: Likewise. + * util/ieee1275/ofpath.c: Likewise. + * util/mkisofs/eltorito.c: Likewise. + * util/mkisofs/rock.c: Likewise. + * util/mkisofs/write.c: Likewise. + * util/raid.c: Likewise. + * util/sparc64/ieee1275/grub-mkimage.c: Likewise. + * util/sparc64/ieee1275/grub-setup.c: Likewise. + +2010-01-15 Vladimir Serbinenko + + Enable multiboot on non-pc. + + * conf/i386-coreboot.rmk, conf/i386-pc.rmk (pkglib_MODULES): Move + multiboot.mod and multiboot2.mod to ... + * conf/i386.rmk (pkglib_MODULES): ... here. + * conf/i386-coreboot.rmk, conf/i386-pc.rmk (multiboot_mod_SOURCES): + Moved to ... + * conf/i386.rmk (multiboot_mod_SOURCES): .. here. + * conf/i386-coreboot.rmk, conf/i386-pc.rmk (multiboot_mod_CFLAGS): + Moved to ... + * conf/i386.rmk (multiboot_mod_CFLAGS): .. here. + * conf/i386-coreboot.rmk, conf/i386-pc.rmk (multiboot_mod_ASFLAGS): + Moved to ... + * conf/i386.rmk (multiboot_mod_ASFLAGS): .. here. + * conf/i386-coreboot.rmk, conf/i386-pc.rmk (multiboot_mod_LDFLAGS): + Moved to ... + * conf/i386.rmk (multiboot_mod_LDFLAGS): .. here. + * conf/x86_64-efi.rmk (pkglib_MODULES): Remove ata.mod and + relocator.mod. + (ata_mod_SOURCES): Removed. + (ata_mod_CFLAGS): Likewise. + (ata_mod_LDFLAGS): Likewise. + (relocator_mod_SOURCES): Removed. + (relocator_mod_CFLAGS): Likewise. + (relocator_mod_ASFLAGS): Likewise. + (relocator_mod_LDFLAGS): Likewise. + Include i386.mk. + * include/grub/x86_64/multiboot.h: New file. + * loader/i386/multiboot.c (grub_multiboot_boot) [GRUB_MACHINE_EFI]: + Terminate EFI. + +2010-01-15 Vladimir Serbinenko + + Video multiboot support. + + * include/grub/multiboot.h (grub_multiboot_set_accepts_video): + New prototype. + * include/multiboot.h: Resynced with multiboot specification. + * include/multiboot2.h: Likewise. + * loader/i386/multiboot.c (UNSUPPORTED_FLAGS): Support video flags. + (grub_multiboot): Parse MULTIBOOT_VIDEO_MODE fields. + * loader/i386/multiboot_mbi.c (DEFAULT_VIDEO_MODE): New constant. + (HAS_VGA_TEXT): Likewise. + (accepts_video): New variable. + (grub_multiboot_set_accepts_video): New function. + (grub_multiboot_get_mbi_size): Account for video structures. + (set_video_mode): New function. + (retrieve_video_parameters): Likewise. + (grub_multiboot_make_mbi): Fill video fields. + +2010-01-15 Vladimir Serbinenko + + Video driver ids. + + * include/grub/video.h (grub_video_driver_id): New type. + (grub_video_adapter): New member 'id'. All users updated. + (grub_video_get_driver_id): New proto. + * video/video.c (grub_video_get_driver_id): New function. + +2010-01-14 Carles Pina i Estany + + * util/grub.d/30_os-prober.in: Use `set var=val' rather than plain + `var=val'. + +2010-01-14 Carles Pina i Estany + + * normal/cmdline.c (print_completion): Gettextizze. + +2001-01-14 Carles Pina i Estany + + * loader/i386/pc/chainloader.c: Include `'. + +2010-01-14 Carles Pina i Estany + + * gettext/gettext.c (grub_gettext_translate): Push and pop + grub_errno. + (grub_gettext_delete_list): Change comment style. + * kern/err.c (grub_error): Gettextizze. + (grub_fatal): Gettextizze. + +2010-01-14 Robert Millan + + * include/grub/i386/loader.h (grub_linux16_boot): Renamed to ... + (grub_linux16_real_boot): ... this. + * kern/i386/loader.S: Likewise. + * loader/i386/pc/linux.c: Include `' and `'. + (grub_linux16_boot): New function. Switches to text mode and calls + grub_linux16_real_boot(). + + * loader/i386/bsd.c: Include `'. + (grub_freebsd_boot, grub_openbsd_boot, grub_netbsd_boot): Switch to + text mode before calling grub_unix_real_boot(). + + * loader/i386/multiboot.c: Include `'. + (grub_multiboot_boot): Switch to text mode before calling + grub_relocator32_boot(). + + * loader/i386/pc/chainloader.c: Include `'. + (grub_chainloader_boot): Switch to text mode before calling + grub_chainloader_real_boot(). + +2010-01-05 Jordan Uggla +2010-01-05 Colin Watson + + * util/grub-reboot.in: Make sure prev_saved_entry always gets a + non-empty value. + +2010-01-05 Jordan Uggla +2010-01-05 Colin Watson + + * util/grub.d/00_header.in: Define a "savedefault" function for use + in menu entries. + * util/grub-mkconfig_lib.in (save_default_entry): Use it. + +2010-01-05 Jordan Uggla +2010-01-05 Colin Watson + + * util/grub-mkconfig_lib.in (save_default_entry): Only set + saved_entry if boot_once is unset. + * util/grub.d/00_header.in: Set boot_once to "true" if there was a + previous saved entry (i.e. grub-reboot). + +2009-12-08 Colin Watson + + * util/grub.d/30_os-prober.in: Call save_default_entry for hurd. + +2009-12-08 Colin Watson + + * util/grub.d/00_header.in: Use `set var=val' rather than plain + `var=val'. + * util/grub-mkconfig_lib.in (save_default_entry): Likewise. + +2009-12-08 Colin Watson + + * util/grub-reboot.in: Fix --version output. + * util/grub-set-default.in: Likewise. + +2009-12-08 Colin Watson + + * util/grub.d/00_header.in: Silently ignore zero-sized environment + blocks. + +2009-12-08 Colin Watson + + * util/grub.d/00_header.in: Quote the value assigned to `default', + in case it contains spaces. + +2009-12-08 Colin Watson + + * util/grub.d/30_os-prober.in: Fix merge error that moved a + `save_default_entry' call from the macosx case to the linux case. + +2009-10-25 Vladimir Serbinenko +2009-10-25 Colin Watson + + * normal/menu.c (grub_menu_execute_entry): Save selected entry title + in `chosen' environment variable. + * normal/menu_text.c (get_entry_number): Check if the variable + matches the title of a menu entry. + (run_menu): Pass menu to get_entry_number. + + * util/grub-reboot.in: New file. + * util/grub-set-default.in: New file. + * conf/common.rmk (grub-reboot): New utility. + (grub-set-default): New utility. + + * util/grub-mkconfig_lib.in (save_default_entry): New function. + * util/grub.d/00_header.in: If GRUB_DEFAULT is `saved', set + default to `${saved_entry}'. If `${prev_saved_entry}' is non-empty, + move it to `saved_entry' for the next boot. Load environment on + initialisation. + * util/grub.d/10_kfreebsd.in: Call save_default_entry. + * util/grub.d/10_hurd.in: Likewise. + * util/grub.d/10_linux.in (linux_entry): Likewise. + * util/grub.d/10_windows.in: Likewise. + * util/grub.d/30_os-prober.in: Likewise. + + * util/grub-install.in: Create environment block. + * util/i386/efi/grub-install.in: Likewise. + * util/ieee1275/grub-install.in: Likewise. + * util/sparc64/ieee1275/grub-install.in: Likewise. + +2010-01-14 BVK Chaitanya + + Unit testing framework for GRUB. + + * Makefile.in: Test framework build rules for 'make check'. + * conf/tests.rmk: Build rules for individual tests and framework. + + * include/grub/test.h: Header file for whitebox tests. + * tests/lib/functional_test.c: Framework support for whitebox + functional tests. + * tests/lib/test.c: Common whitebox testing code for unit and + functional tests. + * tests/lib/unit_test.c: Framework support for whitebox unit + tests. + + * tests/util/grub-shell-tester.in: Support utility for grub-script + tests. + * tests/util/grub-shell.in: Utility to execute grub-script + commands in a Qemu instance. + + * tests/example_functional_test.c: Example whitebox functional + test. + * tests/example_grub_script_test.in: Example grub-script test. + * tests/example_scripted_test.in: Example scripted test. + * tests/example_unit_test.c: Example whitebox unit test. + +2010-01-14 Vladimir Serbinenko + + * conf/i386-coreboot.rmk (multiboot_mod_SOURCES): + Add loader/i386/multiboot_mbi.c. + (multiboot2_mod_SOURCES): Likewise. + * conf/i386-pc.rmk (multiboot_mod_SOURCES): Likewise. + (multiboot2_mod_SOURCES): Likewise. + * include/grub/multiboot.h (grub_multiboot_get_mbi_size): New proto. + (grub_multiboot_make_mbi): Likewise. + (grub_multiboot_free_mbi): Likewise. + (grub_multiboot_init_mbi): Likewise. + (grub_multiboot_add_module): Likewise. + (grub_multiboot_set_bootdev): Likewise. + * loader/i386/multiboot.c (mbi): Removed. + (mbi_dest): Likewise. + (alloc_mbi): New variable. + (grub_multiboot_payload_size): Removed. All users updated. + (grub_multiboot_pure_size): New variable. + (grub_multiboot_boot): Use grub_multiboot_make_mbi. + (grub_multiboot_unload): Use grub_multiboot_free_mbi. + (grub_get_multiboot_mmap_len): Moved to loader/i386/multiboot_mbi.c. + (grub_fill_multiboot_mmap): Likewise. + (grub_multiboot_get_bootdev): Likewise. + (grub_multiboot): Use multiboot_mbi functions. + * loader/i386/multiboot_mbi.c: New file. + +2010-01-13 Vladimir Serbinenko + + * kern/efi/init.c (grub_efi_fini): Don't call grub_efi_mm_fini as + it would result in module crash. + +2010-01-13 Vladimir Serbinenko + + * term/ieee1275/ofconsole.c (grub_ofconsole_putchar): Handle '\r'. + (grub_ofconsole_getwh): Split to ... + (grub_ofconsole_getwh): ... this. + (grub_ofconsole_dimensions): ...and this. + (grub_ofconsole_init_output): Call grub_ofconsole_dimensions. + +2010-01-13 Robert Millan + + * util/mkisofs/rock.c (generate_rock_ridge_attributes): Fix a typo. + +2010-01-12 Vladimir Serbinenko + + * loader/i386/pc/multiboot2.c: Removed stalled file. + +2010-01-12 Vladimir Serbinenko + + * util/grub-mkpasswd-pbkdf2.c (main): Use grub_util_init_nls. + Reported by: Grégoire Sutre + +2010-01-11 Robert Millan + + * util/misc.c (canonicalize_file_name): New function. + (make_system_path_relative_to_its_root): Use canonicalize_file_name() + instead of realpath(). + +2010-01-11 Colin Watson + + * util/grub-install.in (usage): Clarify meaning of --root-directory, + and make it clearer that it's optional. Based on confusion + witnessed on IRC. + +2010-01-10 Vladimir Serbinenko + + * term/i386/pc/vga_text.c (inc_y): Fix off-by-one error which resulted + in premature implicit newline. + +2010-01-10 Vladimir Serbinenko + + * normal/cmdline.c (grub_cmdline_get): Fix off-by-one error + which resulted in garbled command line at the end of screen. + +2010-01-10 Robert Millan + + * loader/i386/ieee1275/linux.c (grub_linux_boot): Rework video position + initialization with similar approach as with other Linux loaders. + +2010-01-10 Robert Millan + + Fix i386-ieee1275 build. + + * loader/i386/ieee1275/linux.c (grub_linux_boot): Use grub_term_width() + and grub_term_height() for video_{width,height} initialization. + +2010-01-10 Robert Millan + + Fix grub-emu build. + + * conf/any-emu.rmk (grub_emu_SOURCES): Remove `kern/reader.c'. + +2010-01-07 Vladimir Serbinenko +2010-01-09 Robert Millan + + Support for multiple terminals. + + * Makefile.in (pkglib_DATA): terminal.lst. + (terminal.lst): New target. + * commands/handler.c (grub_cmd_handler): Don't handle terminals. + (GRUB_MOD_INIT(handler)): Likewise. + (GRUB_MOD_FINI(handler)): Likewise. + * commands/help.c (grub_cmd_help): Handle multiple terminals. + * commands/keystatus.c (grub_cmd_keystatus): Likewise. + * commands/sleep.c (do_print): Use grub_term_restore_pos. + (grub_cmd_sleep): Use grub_term_save_pos. + * commands/terminal.c: New file. + * conf/any-emu.rmk (grub_emu_SOURCES): Add normal/term.c + commands/terminal.c and lib/charset.c. + * conf/common.rmk (normal_mod_SOURCES): Add normal/term.c. + (pkglib_MODULES): Add terminal.mod. + (terminal_mod_SOURCES): New variable. + (terminal_mod_CFLAGS): Likewise. + (terminal_mod_LDFLAGS): Likewise. + * genhandlerlist.sh: Don't handle terminals. + * genmk.rb: Generate terminal-*.lst. + * genterminallist.sh: New file. + * include/grub/charset.h (grub_ucs4_to_utf8_alloc): New proto. + (grub_is_valid_utf8): Likewise. + (grub_utf8_to_ucs4_alloc): Likewise. + * include/grub/menu_viewer.h (grub_menu_viewer): Rewritten. + (grub_menu_register_viewer): Changed argument. + (grub_menu_try_text): New proto. + (grub_gfxmenu_try_hook): New declaration. + * include/grub/normal.h (grub_normal_exit_level): New declaration. + (grub_menu_init_page): Additional argument term. + (grub_normal_init_page): Likewise. + (grub_cmdline_get): Arguments simplified. + (grub_utf8_to_ucs4_alloc): Removed. + (grub_print_ucs4): Additional argument term. + (grub_getstringwidth): Likewise. + (grub_print_message_indented): Likewise. + (grub_menu_text_register_instances): New proto. + (grub_show_menu): Likewise. + (read_terminal_list): Likewise. + (grub_set_more): Likewise. + * include/grub/parser.h: Include handler.h. + * include/grub/reader.h: Rewritten. + * include/grub/term.h (GRUB_TERM_NEED_INIT): Removed. + (GRUB_TERM_WIDTH): Changed to function. + (GRUB_TERM_HEIGHT): Likewise. + (GRUB_TERM_BORDER_WIDTH): Likewise. + (GRUB_TERM_BORDER_HEIGHT): Likewise. + (GRUB_TERM_NUM_ENTRIES): Likewise. + (GRUB_TERM_ENTRY_WIDTH): Likewise. + (GRUB_TERM_CURSOR_X): Likewise. + (grub_term_input_class): Likewise. + (grub_term_output_class): Likewise. + (grub_term_outputs_disabled): New declaration. + (grub_term_inputs_disabled): Likewise. + (grub_term_outputs): Likewise. + (grub_term_inputs): Likewise. + (grub_term_register_input): Rewritten. + (grub_term_register_output): Likewise. + (grub_term_unregister_input): Likewise. + (grub_term_unregister_output): Likewise. + (FOR_ACTIVE_TERM_INPUTS): New macro. + (FOR_DISABLED_TERM_INPUTS): Likewise. + (FOR_ACTIVE_TERM_OUTPUTS): Likewise. + (FOR_DISABLED_TERM_OUTPUTS): Likewise. + * include/grub/terminfo.h: Add oterm argument to all protypes. + * kern/main.c (grub_main): Don't call grub_register_rescue_reader. + Use grub_rescue_run. + * kern/misc.c (grub_utf8_to_ucs4): Put '?' for invalid characters. + All users updated. + * kern/reader.c: Removed. All users updated. + * kern/rescue_reader.c (grub_rescue_init): Removed. + (grub_rescue_reader): Likewise. + (grub_register_rescue_reader): Likewise. + (grub_rescue_run): New function based on kern/reader.c. + * kern/term.c: Adapted for multiterm. + * lib/charset.c (grub_ucs4_to_utf8_alloc): New function. + (grub_is_valid_utf8): Likewise. + (grub_utf8_to_ucs4_alloc): Moved from normal/menu_text.c. + * loader/i386/efi/linux.c (grub_cmd_linux): Retrieve parameters of + right terminal. + * loader/i386/linux.c (grub_linux_boot): Likewise. + * normal/auth.c (grub_username_get): New function. + (grub_auth_check_authentication): Use grub_username_get. + * normal/cmdline.c: Changed to UCS4. Adapted for multiterm. + * normal/color.c: Adapt for multiterm. + * normal/main.c (read_config_file): Don't use grub_reader_loop. + (grub_normal_init_page): Additional argument term. + (read_lists): Call read_terminal_lists. + (grub_enter_normal_mode): Call grub_cmdline_run. + Handle grub_normal_exit_level. + (grub_cmd_normal): Make reentrant. + (grub_cmd_normal_exit): New function. + (grub_normal_reader_init): Additional argument nested. Handle multiterm. + * normal/menu.c: Adapt for multiterm. + * normal/menu_entry.c: Likewise. + * normal/menu_text.c: Likewise. + * normal/menu_viewer.c: Removed. All users updated. + * normal/term.c: New file. + * util/console.c: Change order of includes to workaround a bug in + ncurses headers. + * term/terminfo.c: New argument oterm on all exported functions. + All users updated. + * util/grub-editenv.c (grub_term_input_class): Removed. + (grub_term_output_class): Likewise. + +2010-01-09 Robert Millan + + Make loader output a bit more user-friendly. + + * util/grub.d/10_hurd.in: Print message indicating that GNU Mach + is being loaded. Likewise for the Hurd. + + * util/grub.d/10_kfreebsd.in (kfreebsd_entry): Print message indicating + that kernel of FreeBSD ${version} is being loaded. + + * loader/i386/linux.c (grub_cmd_linux): Move debug info to + grub_dprintf(). + (grub_cmd_initrd): Likewise. + * util/grub.d/10_linux.in (linux_entry): Print message indicating + that Linux ${version} is being loaded. Likewise for initrd. + +2010-01-09 Carles Pina i Estany + + * gettext/gettext.c (GRUB_MOD_INIT): Gettextizze. + +2010-01-08 Carles Pina i Estany + + * loader/efi/appleloader.c: Include `'. + (GRUB_MOD_INIT): Gettextizze. + * loader/efi/chainloader.c: Include `'. + (GRUB_MOD_INIT): Gettextizze. + * loader/i386/efi/linux.c: Include `'. + (grub_cmd_linux): Capitalise Linux. + (GRUB_MOD_INIT): Gettextizze. + * loader/i386/ieee1275/linux.c: Include `'. + (grub_cmd_linux): Capitalise Linux. + (GRUB_MOD_INIT): Gettextizze. + * loader/i386/linux.c: Include `'. + (grub_cmd_linux): Capitalise Linux. + (GRUB_MOD_INIT): Gettextizze. + * loader/i386/pc/chainloader.c: Include `'. + (GRUB_MOD_INIT): Gettextizze. + * loader/i386/pc/linux.c: Include `'. + (grub_cmd_linux): Capitalise Linux. + (GRUB_MOD_INIT): Gettextizze. + * loader/i386/xnu.c: Include `'. + (grub_cpu_xnu_init): Gettextizze. + * loader/multiboot_loader.c: Include `'. + (GRUB_MOD_INIT): Gettextizze. + * loader/powerpc/ieee1275/linux.c: Include `'. + (GRUB_MOD_INIT): Gettextizze. + * loader/sparc64/ieee1275/linux.c: Include `'. + (grub_linux_load64): Capitalise Linux. + (GRUB_MOD_INIT): Gettextizze. + * loader/xnu.c: Include `'. + (GRUB_MOD_INIT): Gettextizze. + * po/POTFILES: Add `loader/efi/appleloader.c', + `loader/efi/chainloader.c', `loader/i386/efi/linux.c', + `loader/i386/ieee1275/linux.c', `loader/i386/linux.c', + `loader/i386/pc/chainloader.c', `loader/i386/pc/linux.c', + `loader/i386/xnu.c', `loader/multiboot_loader.c', + `loader/powerpc/ieee1275/linux.c', `loader/sparc64/ieee1275/linux.c' + and `loader/xnu.c'. + +2010-01-08 Robert Millan + + * src/mkisofs.c: Remove `ifdef linux' portability kludge. + +2010-01-08 Robert Millan + + * util/mkisofs/defaults.h (APPID_DEFAULT): Redefine using PACKAGE_NAME. + (SYSTEM_ID_DEFAULT): Set to "GNU" unconditionally. + * util/mkisofs/mkisofs.c (main): Readjust --version output. + +2010-01-07 Robert Millan + + Reset Multiboot 2 support. New loader implements the draft in + /branches/multiboot2 and shares as much code as possible with the + production Multiboot 1 implementation. + + * loader/ieee1275/multiboot2.c: Remove file. Update all users. + * loader/multiboot2.c: Likewise. + * loader/i386/multiboot_helper.S: Likewise. + * include/multiboot2.h: Replace with latest version from the draft + in /branches/multiboot2. + + * conf/i386-coreboot.rmk (multiboot_mod_SOURCES): Remove + `loader/i386/multiboot_helper.S', `loader/i386/pc/multiboot2.c' + and `loader/multiboot2.c'. + (pkglib_MODULES): Add `multiboot2.mod'. + (multiboot2_mod_SOURCES): New variable. + (multiboot2_mod_LDFLAGS): Likewise. + (multiboot2_mod_CFLAGS): Likewise. Define `GRUB_USE_MULTIBOOT2'. + + * conf/i386-pc.rmk: Likewise. + + * conf/powerpc-ieee1275.rmk (pkglib_MODULES): Remove `multiboot.mod'. + (multiboot_mod_SOURCES): Remove variable. + (multiboot_mod_LDFLAGS): Likewise. + (multiboot_mod_CFLAGS): Likewise. + + * include/grub/multiboot.h [GRUB_USE_MULTIBOOT2]: Include + `' instead of `'. + [GRUB_USE_MULTIBOOT2] (MULTIBOOT_BOOTLOADER_MAGIC) + (MULTIBOOT_HEADER_MAGIC): New macros. + + * loader/multiboot_loader.c (module_version_status): Remove variable. + (find_multi_boot2_header): Remove function. + (grub_cmd_multiboot_loader): Remove Multiboot 2 / Multiboot 1 selection + logic. Always check for the Multiboot version we're compiling for. + (grub_cmd_module_loader): Likewise. + [GRUB_USE_MULTIBOOT2] (GRUB_MOD_INIT(multiboot)): Register `multiboot2' + command instead of `multiboot'. + +2010-01-07 Robert Millan + + * include/multiboot.h (MULTIBOOT_UNSUPPORTED): Moved from here ... + * loader/i386/multiboot.c (UNSUPPORTED_FLAGS): ... to here. Update + all users. + +2010-01-07 Robert Millan +2010-01-07 Vladimir Serbinenko + + Fix breakage introduced with previous commit. + + * normal/dyncmd.c (read_command_list): Avoid unregistering kernel + commands. + * normal/handler.c (read_handler_list): Revert part of previous commit + affecting this file. + * normal/main.c (read_lists): Move read_handler_list() call back to ... + (grub_normal_execute): ... here. + +2010-01-07 Robert Millan + + Merge prefix-redefinition-fix branch. + + * normal/autofs.c (read_fs_list): Make function capable of being + run multiple times, gracefuly replacing the previous data + structures. + * normal/dyncmd.c (read_command_list): Likewise. + * normal/handler.c (read_handler_list): Likewise. + * normal/main.c (read_lists): New function. Calls all the + list reading functions. + (grub_normal_execute): Use read_lists() instead of calling all + list reading functions explicitly. Register read_lists() as a + variable hook attached to ${prefix}. + +2010-01-07 Vladimir Serbinenko + + Merge crypto branch. + + * Makefile.in (pkglib_DATA): Add crypto.lst. + (crypto.lst): New target. + * commands/hashsum.c: New file. + * commands/password.c (check_password): Use grub_crypto_memcmp. + * commands/password_pbkdf2.c: New file. + * commands/xnu_uuid.c: Remove MD5. Use GRUB_MD_MD5. + * conf/any-emu.rmk (grub_emu_SOURCES): Add lib/crypto.c, + normal/crypto.c and lib/libgcrypt-grub/cipher/md5.c. + (grub_emu_CFLAGS): Add -Wno-missing-field-initializers -Wno-error + -I$(srcdir)/lib/libgcrypt_wrap. + * conf/common.rmk (normal_mod_SOURCES): Add normal/crypto.c. + (pkglib_MODULES): Add crypto.mod, hashsum.mod, pbkdf2.mod and + password_pbkdf2.mod. + (crypto_mod_SOURCES): New variable. + (crypto_mod_CFLAGS): Likewise. + (crypto_mod_LDFLAGS): Likewise. + (hashsum_mod_SOURCES): New variable. + (hashsum_mod_CFLAGS): Likewise. + (hashsum_mod_LDFLAGS): Likewise. + (pbkdf2_mod_SOURCES): New variable. + (pbkdf2_mod_CFLAGS): Likewise. + (pbkdf2_mod_LDFLAGS): Likewise. + (password_pbkdf2_mod_SOURCES): New variable. + (password_pbkdf2_mod_CFLAGS): Likewise. + (password_pbkdf2_mod_LDFLAGS): Likewise. + (bin_UTILITIES): Add grub-mkpasswd-pbkdf2. + (grub_mkpasswd_pbkdf2_SOURCES): New variable. + (grub_mkpasswd_pbkdf2_CFLAGS): Likewise. + Include conf/gcry.rmk. + * include/grub/auth.h: Rewritten. + * include/grub/crypto.h: New file. + * include/grub/disk.h (grub_disk_dev_id): Add GRUB_DISK_DEVICE_LUKS_ID. + * include/grub/normal.h (read_crypto_list): New prototype. + * lib/crypto.c: New file. + * lib/libgcrypt_wrap/cipher_wrap.h: Likewise. + * lib/pbkdf2.c: Likewise. + * normal/auth.c (grub_auth_strcmp): Removed. + (grub_iswordseparator): Likewise. + (grub_auth_strword): Likewise. + (is_authenticated): Use grub_strword. + (grub_auth_check_authentication): Use grub_strcmp, grub_password_get + and grub_strword. Pass entered password to authentication callback. + * normal/crypto.c: New file. + * normal/main.c: Call read_crypto_list. + * util/grub-mkpasswd-pbkdf2.c: New file. + * util/import_gcry.py: Generate crypto.lst. Add hash blocklen. + +2010-01-06 Vladimir Serbinenko + + Fix descent and ascent calculation. + + * util/grub-mkfont.c (grub_font_info): New fields 'asce' and 'max_y'. + (options): New option "asce". + (usage): Likewise. + (add_char): Ignore invalid glyphs for descent calculation. + Calculate ascent from actual content. + (print_glyphs): Use 'asce'. + (write_font): Likewise. Allow ascent override. + (main): Handle "asce" option. + +2010-01-06 Carles Pina i Estany + + * kern/err.c: Include `'. + (grub_print_error): Add full stop. Gettextizze. + * loader/i386/bsd.c (grub_netbsd_boot): Change grub_error description. + (grub_bsd_load_elf): Capitalise ELF. + (grub_cmd_freebsd_loadenv): Add `s' in error string. + (grub_cmd_freebsd_module): Likewise. + (grub_cmd_freebsd_module_elf): Likewise. + * loader/i386/bsdXX.c (SUFFIX): Capitalise ELF. + +2010-01-06 Carles Pina i Estany + + * commands/search.c (GRUB_MOD_INIT): Use HELP_MESSAGE. + * commands/search_file.c (HELP_MESSAGE): New macro. + * commands/search_label.c (HELP_MESSAGE): Likewise. + * commands/search_uuid.c (HELP_MESSAGE): Likewise. + * po/POTFILES: Add `commands/search_file.c', + `commands/search_label.c', `commands_uuid.c'. Remove duplicate + `commands/search.c'. + +2010-01-05 Robert Millan + + * config.rpath: Update from Gnulib. + +2010-01-05 Yves Blusseau + + * commands/acpi.c (grub_acpi_create_ebda): fix incorrect message. + +2010-01-05 Yves Blusseau + + * util/sparc64/ieee1275/grub-mkimage.c (main): Typo fix. + +2010-01-05 Colin Watson + + * util/mkisofs/write.c (padblock_write): Switch size and nmemb + arguments to fread so that we get a return value in bytes, rather + than something that will normally be rounded down to 0. + Adjust error handling to avoid producing garbage when size_t is not + the same size as long long. + +2010-01-05 Colin Watson + + * util/mkisofs/write.c (padblock_write): Check return value of + fread. + +2010-01-05 Robert Millan + + Remove grub-mkfloppy. Images produced by grub-mkrescue are valid + floppy images now. + + * util/i386/pc/grub-mkfloppy.in: Remove. Update all users. + +2010-01-04 Robert Millan + + * disk/i386/pc/biosdisk.c (grub_biosdisk_rw): Use ALIGN_UP macro + instead of manual alignment. + * kern/disk.c (grub_disk_read): Remove grub_dprintf call (excessively + verbose). Avoid attempts to read past end of the device + (grub_disk_adjust_range() guarantees that we can read `size' bytes, + but GRUB_DISK_CACHE_SIZE may exceed that). + +2010-01-04 Robert Millan + + * commands/crc.c (grub_cmd_crc): Abort on read errors. + * fs/iso9660.c (grub_iso9660_read): Check for read error and pass + it to upper layer. + +2010-01-04 Vladimir Serbinenko + + * include/grub/efi/api.h (GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE): + New constant. + (grub_efi_piwg_device_path): New structure + (grub_efi_piwg_device_path_t): New type. + * loader/efi/appleloader.c (piwg_full_device_path): New structure. + (devpath_1): Transform to a structure. All users updated. + (devpath_2): Likewise. + (devpath_3): Likewise. + (devpath_4): Likewise. + (devpath_5): Likewise. + +2010-01-04 Vladimir Serbinenko + + * loader/efi/appleloader.c: Restored. Update all users. + +2010-01-03 Robert Millan + + * boot/i386/pc/diskboot.S: Fix inaccurate comment. + + * util/i386/pc/grub-setup.c: Include `'. + (struct boot_blocklist): Move from here ... + * include/grub/i386/pc/boot.h [ASM_FILE] + (struct grub_boot_blocklist): ... to here. Update all users. + (setup): Only initialize `start' member of `first_block' + structure. Add assert() calls to verify the other members. + + * util/i386/pc/grub-mkimage.c: Include `'. + (generate_image): Fix broken blocklist length initialization. + Add assert() call to verify blocklist `segment' field. + +2010-01-03 Robert Millan + + * loader/efi/appleloader.c: Remove. Update all users. + +2010-01-03 Robert Millan + + * boot/i386/pc/boot.S: Update copyright year. + * boot/i386/pc/cdboot.S: Likewise. + * boot/i386/pc/diskboot.S: Likewise. + * boot/i386/pc/lnxboot.S: Likewise. + * boot/i386/pc/pxeboot.S: Likewise. + * bus/pci.c: Likewise. + * commands/cmp.c: Likewise. + * commands/help.c: Likewise. + * commands/hexdump.c: Likewise. + * commands/i386/pc/halt.c: Likewise. + * commands/i386/pc/play.c: Likewise. + * commands/i386/pc/vbeinfo.c: Likewise. + * commands/ls.c: Likewise. + * commands/test.c: Likewise. + * disk/dmraid_nvidia.c: Likewise. + * disk/i386/pc/biosdisk.c: Likewise. + * disk/ieee1275/nand.c: Likewise. + * disk/ieee1275/ofdisk.c: Likewise. + * disk/lvm.c: Likewise. + * disk/raid.c: Likewise. + * disk/raid6_recover.c: Likewise. + * disk/scsi.c: Likewise. + * fs/affs.c: Likewise. + * fs/cpio.c: Likewise. + * fs/ext2.c: Likewise. + * fs/hfs.c: Likewise. + * fs/iso9660.c: Likewise. + * fs/ntfs.c: Likewise. + * fs/sfs.c: Likewise. + * fs/udf.c: Likewise. + * fs/ufs.c: Likewise. + * fs/xfs.c: Likewise. + * gencmdlist.sh: Likewise. + * genmk.rb: Likewise. + * include/grub/disk.h: Likewise. + * include/grub/efi/api.h: Likewise. + * include/grub/efi/efi.h: Likewise. + * include/grub/efi/pe32.h: Likewise. + * include/grub/elf.h: Likewise. + * include/grub/fs.h: Likewise. + * include/grub/i386/at_keyboard.h: Likewise. + * include/grub/i386/pc/memory.h: Likewise. + * include/grub/i386/pc/vbe.h: Likewise. + * include/grub/i386/pci.h: Likewise. + * include/grub/i386/tsc.h: Likewise. + * include/grub/ieee1275/ieee1275.h: Likewise. + * include/grub/ntfs.h: Likewise. + * include/grub/sparc64/ieee1275/ieee1275.h: Likewise. + * include/grub/sparc64/libgcc.h: Likewise. + * include/grub/symbol.h: Likewise. + * include/grub/types.h: Likewise. + * include/multiboot2.h: Likewise. + * io/gzio.c: Likewise. + * kern/device.c: Likewise. + * kern/disk.c: Likewise. + * kern/efi/efi.c: Likewise. + * kern/efi/mm.c: Likewise. + * kern/elf.c: Likewise. + * kern/file.c: Likewise. + * kern/i386/dl.c: Likewise. + * kern/i386/pc/init.c: Likewise. + * kern/i386/pc/startup.S: Likewise. + * kern/ieee1275/ieee1275.c: Likewise. + * kern/ieee1275/init.c: Likewise. + * kern/main.c: Likewise. + * kern/mm.c: Likewise. + * kern/powerpc/dl.c: Likewise. + * kern/sparc64/dl.c: Likewise. + * kern/x86_64/dl.c: Likewise. + * lib/hexdump.c: Likewise. + * loader/efi/appleloader.c: Likewise. + * loader/i386/ieee1275/linux.c: Likewise. + * loader/i386/pc/chainloader.c: Likewise. + * loader/i386/pc/linux.c: Likewise. + * loader/i386/pc/multiboot2.c: Likewise. + * loader/ieee1275/multiboot2.c: Likewise. + * loader/multiboot2.c: Likewise. + * loader/multiboot_loader.c: Likewise. + * loader/powerpc/ieee1275/linux.c: Likewise. + * normal/completion.c: Likewise. + * normal/menu_entry.c: Likewise. + * partmap/apple.c: Likewise. + * util/grub.d/10_hurd.in: Likewise. + * util/hostfs.c: Likewise. + * video/readers/png.c: Likewise. + +2010-01-03 Colin Watson + + * include/grub/misc.h (GNUC_PREREQ): New macro. + (ATTRIBUTE_ERROR): New macro. + * include/grub/list.h (grub_bad_type_cast_real): Use + ATTRIBUTE_ERROR. + +2010-01-03 Carles Pina i Estany + + * normal/menu_text.c (print_message): Change messages. + +2010-01-03 Carles Pina i Estany + + * normal/menu_entry.c (store_completion): Gettextizze. + +2010-01-03 Carles Pina i Estany + + * kern/env.c (grub_env_unset): Set the variable to "" if has hooks. + +2010-01-03 Carles Pina i Estany + + * po/POTFILES: Sort correctly. + +2010-01-03 Carles Pina i Estany + + * commands/acpi.c (GRUB_MOD_INIT): Capitalise some words from help. + * commands/efi/loadbios.c (GRUB_MOD_INIT): Capitalise BIOS. + * commands/i386/pc/drivemap.c (GRUB_MOD_INIT): Remove space. Add + full stop. + * commands/loadenv.c (GRUB_MOD_INIT): Remove command name from + summary. Gettextizze the strings. + * commands/probe.c (grub_cmd_probe): Capitalise UUID and FS. + * commands/xnu_uuid.c (GRUB_MOD_INIT): Capitalise XNU. + * disk/loopback.c (grub_arg_options): Capitalise first letter. Add + full stop. + (GRUB_MOD_INIT): Remove command name from summary. + * hello/hello.c (GRUD_MOT_INIT): Add missing full stop. Improve the + summary. + * loader/i386/bsd.c (grub_arg_option): Capitalise CDROM. + * term/i386/pc/serial.c (options): Add full stops. + (GRUB_MOD_INIT): Remove command name from the summary. + +2010-01-03 Carles Pina i Estany + + * commands/acpi.c: Gettextizze help strings and/or options. Include + `grub/i18n.h' if needed. + * commands/blocklist.c: Likewise. + * commands/boot.c: Likewise. + * commands/cat.c: Likewise. + * commands/cmp.c: Likewise. + * commands/configfile.c: Likewise. + * commands/crc.c: Likewise. + * commands/date.c: Likewise. + * commands/echo.c: Likewise. + * commands/efi/fixvideo.c: Likewise. + * commands/efi/loadbios.c: Likewise. + * commands/gptsync.c: Likewise. + * commands/halt.c: Likewise. + * commands/handler.c: Likewise. + * commands/hdparm.c: Likewise. + * commands/hexdump.c: Likewise. + * commands/i386/cpuid.c: Likewise. + * commands/i386/pc/drivemap.c: Likewise. + * commands/i386/pc/halt.c: Likewise. + * commands/i386/pc/pxecmd.c: Likewise. + * commands/i386/pc/vbeinfo.c: Likewise. + * commands/i386/pc/vbetest.c: Likewise. + * commands/ieee1275/suspend.c: Likewise. + * commands/keystatus.c: Likewise. + * commands/loadenv.c: Likewise. + * commands/ls.c: Likewise. + * commands/lsmmap.c: Likewise. + * commands/lspci.c: Likewise. + * commands/memrw.c: Likewise. + * commands/minicmd.c: Likewise. + * commands/parttool.c: Likewise. + * commands/password.c: Likewise. + * commands/probe.c: Likewise. + * commands/read.c: Likewise. + * commands/reboot.c: Likewise. + * commands/search.c: Likewise. + * commands/sleep.c: Likewise. + * commands/test.c: Likewise. + * commands/true.c: Likewise. + * commands/usbtest.c: Likewise. + * commands/videotest.c: Likewise. + * commands/xnu_uuid.c: Likewise. + * disk/loopback.c: Likewise. + * hello/hello.c: Likewise. + * loader/i386/bsd.c: Likewise. + * term/i386/pc/serial.c: Likewise. + * po/POTFILES: Add new files. + +2010-01-02 Colin Watson + + * term/i386/pc/at_keyboard.c + (keyboard_controller_wait_untill_ready): Rename to ... + (keyboard_controller_wait_until_ready): ... this. Update all users. + +2010-01-01 Carles Pina i Estany + + * commands/help.c: Include `grub/mm.h' and `grub/normal.h'. + (grub_cmd_help): Print the cmd->name before the cmd->summary. Cut the + string using string width. + * normal/menu_text.c (grub_print_message_indented): Use + grub_print_spaces and not print_spaces. + (print_timeout): Likewise. + (print_spaces): Move to... + * include/grub/term.h: ... here. Change the name to grub_print_spaces. + +2010-01-01 Robert Millan + + Import from Gnulib. + + * gnulib/getdelim.c: New file. + * gnulib/getline.c: Likewise. + +2009-12-31 BVK Chaitanya + + * include/grub/list.h (grub_assert_fail): Removed. + (grub_bad_type_cast_real): New function. + (grub_bad_type_cast): New macro. + (GRUB_AS_LIST): Use grub_bad_type_cast. + (GRUB_AS_LIST_P): Likewise. + (GRUB_AS_NAMED_LIST): Likewise. + (GRUB_AS_NAMED_LIST_P): Likewise. + (GRUB_AS_PRIO_LIST): Likewise. + (GRUB_AS_PRIO_LIST_P): Likewise. + * include/grub/handler.h (GRUB_AS_HANDLER): Likewise. + +2009-12-29 Vladimir Serbinenko + + * loader/sparc64/ieee1275/linux.c (GRUB_MOD_INIT (linux)): + Fix syntax error. + +2009-12-29 Robert Millan + + * configure.ac: Check for TARGET_CFLAGS initialization before we + initialize it ourselves (sigh). + Move a few modifications to TARGET_CFLAGS to be unconditional + (extra warning flags, loop alignment, i386 CPU extensions, GCC 4.4 + eh_frame) + + * gettext/gettext.c (grub_gettext_delete_list): Add `void' argument. + * term/i386/pc/at_keyboard.c + (keyboard_controller_wait_untill_ready): Likewise. + (keyboard_controller_led): Rename `led_status' paramter to avoid + name conflict. + +2009-12-28 Carles Pina i Estany + + * normal/misc.c (grub_normal_print_device_info): Add spaces and double + quotes. + +2009-12-27 Vladimir Serbinenko + + * kern/parser.c (grub_parser_split_cmdline): Don't dereference NULL. + +2009-12-27 Vladimir Serbinenko + + * normal/menu_text.c (grub_print_message_indented): Prevent + past-the-end-of-array dereference. + +2009-12-27 Vladimir Serbinenko + + * video/readers/jpeg.c (GRUB_MOD_FINI (grub_cmd_jpegtest)): Rename to .. + (GRUB_MOD_FINI (video_reader_jpeg)): ...this + +2009-12-27 Carles Pina i Estany + + * normal/cmdline.c (grub_cmdline_get): Print a space after prompt. + * normal/main.c (grub_normal_read_line): Remove a space from the + default prompt. + +2009-12-27 Carles Pina i Estany + + * loader/i386/efi/linux.c (GRUB_MOD_INIT): Improve command summary. + * loader/i386/ieee1275/linux.c (GRUB_MOD_INIT): Likewise. + * loader/i386/linux.c (GRUB_MOD_INIT): Likewise. + * loader/i386/pc/linux.c (GRUB_MOD_INIT): Likewise. + * loader/powerpc/ieee1275/linux.c (GRUB_MOD_INIT): Likewise. + * loader/sparc64/ieee1275/linux.c (GRUB_MOD_INIT): Likewise. + * loader/xnu.c (GRUB_MOD_INIT): Likewise. + +2009-12-26 Carles Pina i Estany + + * video/readers/jpeg.c (cmd): Declare. + (grub_cmd_jpegtest): Use `grub_command_t' type. + (GRUB_MOD_INIT): Fix arguments passed to `grub_register_command'. + Assign to `cmd'. + (GRUB_MOD_FINI): Use `cmd' to unregister. + * video/readers/png.c (cmd): Declare. + (grub_cmd_pngtest): Use `grub_command_t' type. + (GRUB_MOD_INIT): Fix arguments passed to `grub_register_command'. + Assign to `cmd'. + (GRUB_MOD_FINI): Use `cmd' to unregister. + * video/readers/tga.c (cmd): Declare. + (grub_cmd_tgatest): Use `grub_command_t' type. + (GRUB_MOD_INIT): Fix arguments passed to `grub_register_command'. + Assign to `cmd'. + (GRUB_MOD_FINI): Use `cmd' to unregister. + +2009-12-26 Carles Pina i Estany + + * efiemu/main.c (GRUB_MOD_INIT): Fix capitalizations and/or full + stops. + * kern/corecmd.c (grub_register_core_commands): Likewise. + * loader/efi/chainloader.c (GRUB_MOD_INIT): Likewise. + * loader/i386/bsd.c (GRUB_MOD_INIT): Likewise. + * loader/i386/efi/linux.c (GRUB_MOD_INIT): Likewise. + * loader/i386/ieee1275/linux.c (GRUB_MOD_INIT): Likewise. + * loader/i386/linux.c (GRUB_MOD_INIT): Likewise. + * loader/i386/pc/chainloader.c (GRUB_MOD_INIT): Likewise. + * loader/i386/pc/linux.c (GRUB_MOD_INIT): Likewise. + * loader/multiboot_loader.c (GRUB_MOD_INIT): Likewise. + * loader/powerpc/ieee1275/linux.c (GRUB_MOD_INIT): Likewise. + * loader/sparc64/ieee1275/linux.c (GRUB_MOD_INIT): Likewise. + * loader/xnu.c (GRUB_MOD_INIT): Likewise. + * mmap/mmap.c (GRUB_MOD_INIT): Likewise. + * normal/handler.c (insert_handler): Likewise. + * normal/main.c (GRUB_MOD_INIT): Likewise. + * term/gfxterm.c (GRUB_MOD_INIT): Likewise. + +2009-12-26 Carles Pina i Estany + + * commands/help.c (grub_cmd_help): Print the command name before the + summary. + (GRUB_MOD_INIT): Remove command name from the summary. + * kern/command.c (GRUB_MOD_INIT): If summary is null assign an empty + string as summary. + * lib/arg.c (find_long): Print the command name before the summary. + * commands/acpi.c (GRUB_MOD_INIT): Remove command name from the + summary. + * commands/blocklist.c (GRUB_MOD_INIT): Likewise. + * commands/cat.c (GRUB_MOD_INIT): Likewise. + * commands/cmp.c (GRUB_MOD_INIT): Likewise. + * commands/configfile.c (GRUB_MOD_INIT): Likewise. + * commands/crc.c (GRUB_MOD_INIT): Likewise. + * commands/date.c (GRUB_MOD_INIT): Likewise. + * commands/echo.c (GRUB_MOD_INIT): Likewise. + * commands/efi/loadbios.c (GRUB_MOD_INIT): Likewise. + * commands/gptsync.c (GRUB_MOD_INIT): Likewise. + * commands/handler.c (GRUB_MOD_INIT): Likewise. + * commands/hdparm.c (GRUB_MOD_INIT): Likewise. + * commands/hexdump.c (GRUB_MOD_INIT): Likewise. + * commands/i386/cpuid.c (GRUB_MOD_INIT): Likewise. + * commands/i386/pc/halt.c (GRUB_MOD_INIT): Likewise. + * commands/i386/pc/play.c (GRUB_MOD_INIT): Likewise. + * commands/i386/pc/pxecmd.c (GRUB_MOD_INIT): Likewise. + * commands/keystatus.c (GRUB_MOD_INIT): Likewise. + * commands/loadenv.c (GRUB_MOD_INIT): Likewise. + * commands/ls.c (GRUB_MOD_INIT): Likewise. + * commands/lspci.c (GRUB_MOD_INIT): Likewise. + * commands/memrw.c (GRUB_MOD_INIT): Likewise. + * commands/minicmd.c (GRUB_MOD_INIT): Likewise. + * commands/parttool.c (GRUB_MOD_INIT): Likewise. + * commands/password.c (GRUB_MOD_INIT): Likewise. + * commands/probe.c (GRUB_MOD_INIT): Likewise. + * commands/read.c (GRUB_MOD_INIT): Likewise. + * commands/search.c (GRUB_MOD_INIT): Likewise. + * commands/sleep.c (GRUB_MOD_INIT): Likewise. + * commands/test.c (GRUB_MOD_INIT): Likewise. + * commands/xnu_uuid.c (GRUB_MOD_INIT): Likewise. + * efiemu/main.c (GRUB_MOD_INIT): Likewise. + * font/font_cmd.c (GRUB_MOD_INIT): Likewise. + * gettext/gettext.c (GRUB_MOD_INIT): Likewise. + * kern/corecmd.c (GRUB_MOD_INIT): Likewise. + * lib/arg.c (GRUB_MOD_INIT): Likewise. + * loader/efi/appleloader.c (GRUB_MOD_INIT): Likewise. + * loader/i386/bsd.c (GRUB_MOD_INIT): Likewise. + * loader/xnu.c (GRUB_MOD_INIT): Likewise. + * mmap/mmap.c (GRUB_MOD_INIT): Likewise. + * term/terminfo.c (GRUB_MOD_INIT): Likewise. + * video/readers/jpeg.c (GRUB_MOD_INIT): Likewise. + * video/readers/png.c (GRUB_MOD_INIT): Likewise. + * video/readers/tga.c (GRUB_MOD_INIT): Likewise. + +2009-12-25 Vladimir Serbinenko + + Use search command for preliminar UUID search. + + * commands/search.c: Split into ... + * commands/search_wrap.c: ...this + * commands/search.c: ...and this. + * commands/search_file.c: New file. + * commands/search_label.c: New file. + * commands/search_uuid.c: New file. + * conf/any-emu.rmk (grub_emu_SOURCES): Remove commands/search.c. + Add commands/search_wrap.c, commands/search_file.c, + commands/search_label.c and commands/search_uuid.c. + * conf/common.rmk (pkglib_MODULES): Remove fs_uuid.mod and fs_file.mod. + (search_mod_SOURCES): Set to commands/search_wrap.c. + (pkglib_MODULES): Add search_fs_file.mod, search_fs_uuid.mod and + search_label.mod. + (search_fs_file_mod_SOURCES): New variable. + (search_fs_file_mod_CFLAGS): Likewise. + (search_fs_file_mod_LDFLAGS): Likewise. + (search_label_mod_SOURCES): Likewise. + (search_label_mod_CFLAGS): Likewise. + (search_label_mod_LDFLAGS): Likewise. + (search_fs_uuid_mod_SOURCES): New variable. + (search_fs_uuid_mod_CFLAGS): Likewise. + (search_fs_uuid_mod_LDFLAGS): Likewise. + (fs_file_mod_SOURCES): Removed. + (fs_file_mod_CFLAGS): Likewise. + (fs_file_mod_LDFLAGS): Likewise. + (fs_uuid_mod_SOURCES): Removed. + (fs_uuid_mod_CFLAGS): Likewise. + (fs_uuid_mod_LDFLAGS): Likewise. + * conf/sparc64-ieee1275.rmk (grub_install_SOURCES): + Set to util/grub-install.in. + * disk/fs_file.c: Removed. + * disk/fs_uuid.c: Likewise. + * include/grub/search.h: New file. + * util/grub-install.in: Handle sparc64. + Create and use load.cfg. + * util/sparc64/ieee1275/grub-install.in: Removed. + +2009-12-25 Vladimir Serbinenko + + * kern/i386/pc/startup.S (grub_biosdisk_get_diskinfo_int13_extensions): + Ignore return status if CF is cleared. + (grub_biosdisk_get_diskinfo_standard): Likewise. + +2009-12-25 Robert Millan + + * term/i386/pc/at_keyboard.c + (keyboard_controller_wait_untill_ready): New function. + (grub_keyboard_controller_write, grub_keyboard_controller_read) + (keyboard_controller_led): Use keyboard_controller_wait_untill_ready() + for keyboard polling, rather than duplicate the same loop. This + saves a few bytes in code size. + +2009-12-25 Vladimir Serbinenko + + Support for (pxe[:server[:gateway]]) syntax and + use environment variable for PXE. + + * commands/i386/pc/pxecmd.c (options): Removed. + (print_ip): Removed. + (grub_cmd_pxe): Removed + (grub_cmd_pxe_unload): New function. + * fs/i386/pc/pxe.c (grub_pxe_disk_data): New structure. + (grub_pxe_your_ip): Made static. + (grub_pxe_default_server_ip): Likewise. + (grub_pxe_default_gateway_ip): Likewise. + (grub_pxe_blksize): Likewise. + (parse_ip): New function. + (grub_pxe_open): Support server and gateway specification. + (grub_pxe_close): Free disk->data. + (grub_pxefs_open): Use disk->data. + (grub_pxefs_read): Likewise. + (grub_env_write_readonly): New function. + (set_mac_env): Likewise. + (set_env_limn_ro): Likewise. + (parse_dhcp_vendor): Likewise. + (grub_pxe_detect): Set the environment variables. + (set_ip_env): New function. + (write_ip_env): Likewise. + (grub_env_write_pxe_default_server): Likewise. + (grub_env_write_pxe_default_gateway): Likewise. + (grub_env_write_pxe_blocksize): Likewise. + (GRUB_MOD_INIT(pxe)): Set environment variables. + * include/grub/i386/pc/pxe.h (grub_pxe_mac_addr): Rename to ... + (grub_pxe_mac_addr_t): ... this. All users updated. + (grub_pxe_your_ip): Removed. + (grub_pxe_server_ip): Likewise. + (grub_pxe_gateway_ip): Likewise. + (grub_pxe_blksize): Likewise. + +2009-12-25 Carles Pina i Estany + + * commands/help.c: Include `'. + (grub_cmd_help): Gettextizze. + (GRUB_MOD_INIT): Likewise. + * commands/i386/pc/play.c: Include `'. + (GRUB_MOD_INIT): Gettextizze. + * commands/search.c: Include `'. + (options): Gettextizze. + (GRUB_MOD_INIT): Gettextizze. + * lib/arg.c: Include `'. + (help_options): Gettextizze. + (find_long): Likewise. + (grub_arg_show_help): Likewise. + * normal/dyncmd.c: Include `'. + (read_command_list): Gettextizze. + * po/POTFILES: Add `commands/i386/pc/play.c', `commands/search.c', + `commands/help.c', `lib/arg.c' and `normal/dyncmd.c'. + +2009-12-25 Robert Millan + + * include/grub/i386/at_keyboard.h (NUM_LOCK, SCROLL_LOCK): New macros. + * term/i386/pc/at_keyboard.c (KEYBOARD_STATUS_NUM_LOCK) + (KEYBOARD_LED_SCROLL, KEYBOARD_LED_NUM, KEYBOARD_LED_CAPS): New macros. + (led_status): New variable. + (keyboard_controller_led): New function. + (grub_at_keyboard_getkey_noblock): Handle num lock and scroll lock, + update led status for caps lock, num lock and scroll lock. + +2009-12-25 Felix Zielcke + + * util/hostdisk.c (open_device): Fix a comment. + +2009-12-24 Robert Millan + + * util/grub-install.in (host_os): New variable. + * util/i386/efi/grub-install.in (host_os): Likewise. + +2009-12-24 Robert Millan + + * util/mkisofs/write.c (padblock_write): Abort when given an + excedingly large embed image, instead of silently truncating it. + +2009-12-24 Robert Millan + + * include/multiboot.h: Indentation fixes. + +2009-12-24 Robert Millan + + * include/multiboot.h (struct multiboot_aout_symbol_table) + (struct multiboot_elf_section_header_table): New structure + declarations (stolen from GRUB Legacy). + (struct multiboot_info): Replace opaque `syms' with a.out and ELF + table information. + + (multiboot_aout_symbol_table_t, multiboot_elf_section_header_table_t) + (multiboot_info_t, multiboot_memory_map_t, multiboot_module_t): New + type aliases. + +2009-12-24 Robert Millan + + * include/multiboot.h: Make comments src2texi-friendly. + +2009-12-24 Robert Millan + + For consistency with [multiboot]/docs/boot.S. + + * include/multiboot.h (MULTIBOOT_MAGIC): Rename from this ... + (MULTIBOOT_HEADER_MAGIC): ... to this. Update all users. + (MULTIBOOT_MAGIC2): Rename from this ... + (MULTIBOOT_BOOTLOADER_MAGIC): ... to this. Update all users. + +2009-12-24 Robert Millan + + * include/multiboot.h: Remove `'. + (multiboot_uint16_t, multiboot_uint32_t, multiboot_uint64_t): New + types. Update all users. + +2009-12-25 Carles Pina i Estany + + * commands/efi/loadbios.c: Capitalize acronyms, replace `could not' by + `couldn't' and `can not' by `cannot'. + * commands/i386/pc/drivemap.c: Likewise. + * disk/ata.c: Likewise. + * disk/ieee1275/nand.c: Likewise. + * fs/affs.c: Likewise. + * fs/fat.c: Likewise. + * fs/hfs.c: Likewise. + * fs/hfsplus.c: Likewise. + * fs/iso9660.c: Likewise. + * fs/jfs.c: Likewise. + * fs/minix.c: Likewise. + * fs/reiserfs.c: Likewise. + * fs/sfs.c: Likewise. + * fs/udf.c: Likewise. + * fs/ufs.c: Likewise. + * fs/xfs.c: Likewise. + * loader/powerpc/ieee1275/linux.c: Likewise. + * loader/sparc64/ieee1275/linux.c: Likewise. + * util/grub-probe.c: Likewise. + * util/misc.c: Likewise. + +2009-12-24 Carles Pina i Estany + + * bus/usb/usbhub.c: Fix capitalization, fullstop and newlines in + grub_errno calls. + * commands/acpi.c: Likewise. + * commands/blocklist.c: Likewise. + * commands/efi/loadbios.c: Likewise. + * commands/i386/pc/drivemap.c: Likewise. + * commands/loadenv.c: Likewise. + * commands/memrw.c: Likewise. + * commands/password.c: Likewise. + * commands/videotest.c: Likewise. + * disk/ata.c: Likewise. + * disk/ata_pthru.c: Likewise. + * disk/dmraid_nvidia.c: Likewise. + * disk/ieee1275/nand.c: Likewise. + * disk/ieee1275/ofdisk.c: Likewise. + * disk/loopback.c: Likewise. + * disk/lvm.c: Likewise. + * disk/mdraid_linux.c: Likewise. + * disk/raid.c: Likewise. + * disk/raid6_recover.c: Likewise. + * disk/scsi.c: Likewise. + * efiemu/main.c: Likewise. + * efiemu/mm.c: Likewise. + * efiemu/pnvram.c: Likewise. + * efiemu/symbols.c: Likewise. + * font/font.c: Likewise. + * fs/cpio.c: Likewise. + * fs/hfsplus.c: Likewise. + * fs/iso9660.c: Likewise. + * fs/jfs.c: Likewise. + * fs/minix.c: Likewise. + * fs/ntfs.c: Likewise. + * fs/ntfscomp.c: Likewise. + * fs/reiserfs.c: Likewise. + * fs/ufs.c: Likewise. + * fs/xfs.c: Likewise. + * gettext/gettext.c: Likewise. + * include/grub/auth.h: Likewise. + * kern/elf.c: Likewise. + * kern/file.c: Likewise. + * kern/ieee1275/init.c: Likewise. + * kern/ieee1275/mmap.c: Likewise. + * kern/ieee1275/openfw.c: Likewise. + * kern/powerpc/dl.c: Likewise. + * kern/sparc64/dl.c: Likewise. + * lib/arg.c: Likewise. + * loader/i386/bsd.c: Likewise. + * loader/i386/bsdXX.c: Likewise. + * loader/i386/efi/linux.c: Likewise. + * loader/i386/efi/xnu.c: Likewise. + * loader/i386/ieee1275/linux.c: Likewise. + * loader/i386/linux.c: Likewise. + * loader/i386/multiboot.c: Likewise. + * loader/i386/pc/linux.c: Likewise. + * loader/i386/pc/multiboot2.c: Likewise. + * loader/i386/xnu.c: Likewise. + * loader/ieee1275/multiboot2.c: Likewise. + * loader/macho.c: Likewise. + * loader/machoXX.c: Likewise. + * loader/multiboot2.c: Likewise. + * loader/multiboot_loader.c: Likewise. + * loader/powerpc/ieee1275/linux.c: Likewise. + * loader/sparc64/ieee1275/linux.c: Likewise. + * loader/xnu.c: Likewise. + * loader/xnu_resume.c: Likewise. + * mmap/i386/pc/mmap.c: Likewise. + * normal/menu_viewer.c: Likewise. + * partmap/acorn.c: Likewise. + * partmap/amiga.c: Likewise. + * partmap/apple.c: Likewise. + * script/lexer.c: Likewise. + * term/gfxterm.c: Likewise. + * term/i386/pc/serial.c: Likewise. + * term/i386/pc/vga.c: Likewise. + * term/ieee1275/ofconsole.c: Likewise. + * term/terminfo.c: Likewise. + * video/bitmap.c: Likewise. + * video/efi_gop.c: Likewise. + * video/efi_uga.c: Likewise. + * video/fb/video_fb.c: Likewise. + * video/i386/pc/vbe.c: Likewise. + * video/readers/tga.c: Likewise. + * video/video.c: Likewise. + +2009-12-23 Felix Zielcke + + * commands/i386/pc/drivemap.c: Remove all trailing whitespace. + * commands/lspci.c: Likewise. + * commands/probe.c: Likewise. + * commands/xnu_uuid.c: Likewise. + * conf/i386-coreboot.rmk: Likewise. + * conf/i386-efi.rmk: Likewise. + * conf/i386-ieee1275.rmk: Likewise. + * conf/i386-pc.rmk: Likewise. + * conf/powerpc-ieee1275.rmk: Likewise. + * conf/sparc64-ieee1275.rmk: Likewise. + * conf/x86_64-efi.rmk: Likewise. + * fs/i386/pc/pxe.c: Likewise. + * gettext/gettext.c: Likewise. + * include/grub/efi/graphics_output.h: Likewise. + * include/grub/i386/pc/memory.h: Likewise. + * kern/env.c: Likewise. + * kern/i386/qemu/startup.S: Likewise. + * lib/i386/pc/biosnum.c: Likewise. + * lib/i386/relocator.c: Likewise. + * lib/i386/relocator_asm.S: Likewise. + * lib/relocator.c: Likewise. + * loader/i386/bsd.c: Likewise. + * loader/i386/multiboot.c: Likewise. + * loader/i386/pc/chainloader.c: Likewise. + * loader/i386/xnu.c: Likewise. + * loader/xnu.c: Likewise. + * normal/main.c: Likewise. + * normal/menu_text.c: Likewise. + * util/getroot.c: Likewise. + * util/grub-mkconfig_lib.in: Likewise. + * util/grub.d/00_header.in: Likewise. + * util/i386/pc/grub-mkimage.c: Likewise. + * util/mkisofs/eltorito.c: Likewise. + * util/mkisofs/exclude.h: Likewise. + * util/mkisofs/hash.c: Likewise. + * util/mkisofs/iso9660.h: Likewise. + * util/mkisofs/joliet.c: Likewise. + * util/mkisofs/mkisofs.c: Likewise. + * util/mkisofs/mkisofs.h: Likewise. + * util/mkisofs/multi.c: Likewise. + * util/mkisofs/name.c: Likewise. + * util/mkisofs/rock.c: Likewise. + * util/mkisofs/tree.c: Likewise. + * util/mkisofs/write.c: Likewise. + * video/efi_gop.c: Likewise. + +2009-12-23 Vladimir Serbinenko + + * video/efi_gop.c (grub_video_gop_get_bitmask): Fix off-by-one in mask + size counting. + +2009-12-22 Felix Zielcke + + * util/grub-mkrescue.in (pkglib_DATA): Set to @pkglib_DATA@. + * genmk.rb (class SCRIPT): Modify the target file instead of source. + +2009-12-22 Vladimir Serbinenko + + * commands/memrw.c (grub_cmd_write): Support for mask parameter. + (GRUB_MOD_INIT(memrw)): Update help line. + +2009-12-22 Vladimir Serbinenko + + * commands/memrw.c (cmd_read_byte, cmd_read_word, cmd_read_dword): + Use grub_extcmd_t. All users updated. + (options): New variable. + (grub_cmd_read): Restructure for readability. Support "-v" option. + (grub_cmd_write): Restructure for readability. + +2009-12-22 Felix Zielcke + + * genmk.rb (class SCRIPT): Prepend #{src} path with $(srcdir). + +2009-12-22 Felix Zielcke + + * genmk.rb (class SCRIPT): Use sed to substitute @pkglib_DATA@ + with the actual contents of the correspondending make variable. + * util/grub-mkrescue.in (pkglib_DATA): New variable. + (process_input_dir): Copy all $pkglib_DATA files instead of explicitly + specifying `*.lst' and `efiemu??.o' + +2009-12-22 Felix Zielcke + + * util/grub.d/30_os-prober.in (osx_entry): Add round brackets + after function name. + Noticed by Rene Engelhard . + +2009-12-22 Vladimir Serbinenko + + * commands/lspci.c (grub_pci_classes): Add "USB Controller". + (options): New variable. + (iospace): Likewise. + (grub_lspci_iter): List IO spaces if "-i" was given. + (grub_cmd_lspci): Parse options. + (GRUB_MOD_INIT(lspci)): Use extcmd. + (GRUB_MOD_FINI(lspci)): Likewise. + +2009-12-22 Felix Zielcke + + * util/grub.d/30_os-prober.in (osx_entry): Remove non POSIX compliant + `function' keyword. + Patch by Tony Mancill . + +2009-12-22 Vladimir Serbinenko + + * bus/usb/uhci.c (grub_uhci_transfer): Set a limit transaction time. + (grub_uhci_portstatus): Likewise. + (grub_uhci_portstatus): Add necessary delay. + * bus/usb/usbhub.c (grub_usb_hub_add_dev): Fix loop-break condition. + +2009-12-21 Carles Pina i Estany + + * commands/acpi.c (options): Fix capitalizations and/or full stops. + (GRUB_MOD_INIT): Likewise. + * commands/boot.c (GRUB_MOD_INIT): Likewise. + * commands/cmp.c (grub_cmd_cmp): Improve the help message. + * commands/echo.c (options): Fix capitalizations and/or full stops. + * commands/efi/loadbios.c (enable_rom_area): Likewise. + (enable_rom_area): Likewise. + (GRUB_MOD_INIT): Likewise. + * commands/gptsync.c (GRUB_MOD_INIT): Likewise. + * commands/halt.c (GRUB_MOD_INIT): Improve the help message. + * commands/handler.c (GRUB_MOD_INIT): Likewise. + * commands/hdparm.c (options): Fix capitalizations and/or full stops. + * commands/hexdump.c (options): Likewise. + * commands/i386/cpuid.c (options): Likewise. + (GRUB_MOD_INIT): Likewise. + * commands/i386/pc/drivemap.c (options): Likewise. + (GRUB_MOD_INIT): Likewise. + * commands/i386/pc/halt (options): Likewise. + (GRUB_MOD_INIT): Likewise. + * commands/i386/pc/play.c (GRUB_MOD_INIT): Likewise. + * commands/i386/pc/pxecmd.c (options): Likewise. + * commands/i386/pc/vbetest.c (GRUB_MOD_INIT): Likewise. + * commands/ieee1275/suspend.c (GRUB_MOD_INIT): Likewise. + * commands/keystatus.c (options): Likewise. + (GRUB_MOD_INIT): Likewise. + * commands/loadenv.c (options): Likewise. + * commands/ls.c (options): Likewise. + * commands/lspci.c (GRUB_MOD_INIT): Likewise. + * commands/memrw.c (GRUB_MOD_INIT): Likewise. + * commands/minicmd.c (GRUB_MOD_INIT): Likewise. + * commands/parttool.c (helpmsg): Likewise. + * commands/probe.c (options): Likewise. + * commands/read.c (GRUB_MOD_INIT): Likewise. + * commands/reboot.c (GRUB_MOD_INIT): Likewise. + * commands/search.c (options): Likewise. + * commands/sleep.c (options): Likewise. + * commands/test.c (GRUB_MOD_INIT): Likewise. + * commands/true.c (GRUB_MOD_INIT): Likewise. + * commands/usbtest.c (GRUB_MOD_INIT): Likewise. + * commands/videotest.c (GRUB_MOD_INIT): Likewise. + * lib/arg.c (help_options): Likewise. + * Makefile.in ($(srcdir)/po/$(PACKAGE).pot): Pass -ctranslate to + `$(XGETTEXT)'. + * po/POTFILES: Add `commands/loadenv.c'. + +2009-12-21 Felix Zielcke + + * util/grub-mkrescue.in (process_input_dir): Copy `*.lst' files + instead of specifying them explicit. + +2009-12-21 Robert Millan + + * NEWS: Add grub-probe support for GNU/Hurd. + +2009-12-21 Robert Millan + + * NEWS: gettext was added after 1.97. + +2009-12-21 Robert Millan + + * util/mkisofs/msdos_partition.h: New file (based on + include/grub/msdos_partition.h). + * util/mkisofs/mkisofs.c (use_protective_msdos_label): New variable. + (OPTION_PROTECTIVE_MSDOS_LABEL): New macro. + (ld_options, main): Recognize --protective-msdos-label. + * util/mkisofs/mkisofs.h (use_protective_msdos_label): New declaration. + * util/mkisofs/write.c: Include `"msdos_partition.h"'. + (padblock_write): If `use_protective_msdos_label' is set, patch a + protective DOS-style label in the output image. + + * util/grub-mkrescue.in: Use --protective-msdos-label. + +2009-12-21 Robert Millan + + * util/grub-mkrescue.in: Do not zero-pad image for BIOS-based disk + boot. + +2009-12-21 Robert Millan + + * util/mkisofs/mkisofs.c (use_embedded_boot, boot_image_embed): New + variables. + (ld_options, main): Recognize `--embedded-boot'. + * util/mkisofs/mkisofs.h (use_embedded_boot, boot_image_embed): New + declarations. + * util/mkisofs/write.c (PADBLOCK_SIZE): New variable. + (padblock_size): Use `PADBLOCK_SIZE' instead of hardcoding 16. + (padblock_write): Likewise. Rewrite to support embedded boot image. + + * util/grub-mkrescue.in: When building i386-pc images, embed core.img + for BIOS-based disk boot instead of only ElTorito. + +2009-12-21 Robert Millan + + * util/grub-mkrescue.in: Remove `configfile' and `sh' from i386-pc + build (not needed for bootstrap). + +2009-12-21 Robert Millan + + * util/grub-mkrescue.in: Remove `memdisk', `tar' and `search' modules + from i386-pc build (not needed for bootstrap). + Rewrite a pair of strings. + +2009-12-21 Robert Millan + + * normal/main.c (grub_normal_reader_init): Set left margin back to 3. + +2009-12-21 Vladimir Serbinenko + + * video/i386/pc/vbe.c (grub_video_vbe_fini): Set 'last_set_mode'. + +2009-12-21 Andreas Born + + * kern/env.c (grub_env_context_open): Mark exported variable for + reexport. + +2009-12-21 Andreas Born + + * kern/env.c (grub_env_export): Create nonexistent variables before + exporting. + +2009-12-20 Carles Pina i Estany + + * include/grub/auth.h: Include `'. + (GRUB_GET_PASSWORD): Gettextizze string. + * include/grub/normal.h (STANDARD_MARGIN): New macro, moved from + menu_text.c. + (grub_utf8_to_ucs4_alloc): Fix indentation. + (grub_print_ucs4): Likewise. + (grub_getstringwidth): Likewise. + (print_message_indented): New declaration. + * normal/auth.c: Include `'. + (grub_auth_check_authentication): Gettexttize string. + * normal/cmdline.c: Include `'. + (grub_cmdline_get): Gettextizze. + * normal/color.c: Include `'. + (grub_parse_color_name_pair): Gettexttize strings. + * normal/main.c (grub_normal_reader_init): Cleanup gettexttized + string (use `print_message_indented'). + * normal/menu_text.c (STANDARD_MARGIN): Moved from here to + `include/grub/normal.h'. + (print_message_indented): Renamed to ... + (grub_print_message_indented): ... this. Remove `static' qualifer (now + used in normal/main.c). + (print_message): Use `grub_print_message_indented' instead of + `print_message_indented'. + (print_timeout): Likewise. + * normal/misc.c: Include `' and `'. + (grub_normal_print_device_info): Gettexttize strings. + * po/POTFILES: Add `auth.c', `color.c' and `misc.c'. + +2009-12-20 Vladimir Serbinenko + + * kern/parser.c (grub_parser_split_cmdline): Fix incorrect counting + of arguments. Return number of tokens and not arguments. All users + updated. + +2009-12-20 Vladimir Serbinenko + + * util/i386/pc/grub-setup.c (setup): Don't install on non-GPT, + non-MSDOS paritions. + +2009-12-19 Vladimir Serbinenko + + * include/grub/types.h (UNUSED): Removed since it conflicts with + NetBSD headers. All users changed to direct __attribute__ ((unused)). + Reported by Grégoire Sutre. + +2009-12-19 Carles Pina i Estany + + * include/grub/normal.h (grub_utf8_to_ucs4): New declaration. + (grub_print_ucs4_alloc): Likewise. + (grub_getstringwidth): Likewise. + * normal/main.c (grub_normal_init_page): Gettextize version string. + * normal/menu_text.c (grub_utf8_to_ucs4_alloc): New definition. + (getstringwidth): Renamed to ... + (grub_getstringwidth): ... this. Remove `static' qualifier (now used + in normal/main.c). Use `grub_utf8_to_ucs4_alloc'. + (grub_print_ucs4): Remove `static' qualifer (now used in + normal/main.c). + * po/POTFILES: Add normal/main.c. + +2009-12-19 Carles Pina i Estany + + * normal/menu_text.c (STANDARD_MARGIN): New macro. + (print_message_indented): Add `margin_left' and `margin_right' + parameters. + (print_message): Update `print_message_indented' calls. Adds '\n' to the + strings. + (print_timeout): Use `print_message_indented' to print the message. + Deletes `second_stage' parameter. + (run_menu): Update `print_timeout' calls. + +2009-12-18 Vladimir Serbinenko + + Fix console palette on OpenFirmware. + + * term/ieee1275/ofconsole.c (MAX): Removed. + (colors): Redone based on VGA palette. + (grub_ofconsole_setcolor): Discard brightness bit since only 8 + colors are supported. + (grub_ofconsole_init_output): Use ARRAY_SIZE instead of hardcoded size. + +2009-12-18 Vladimir Serbinenko + + Fix potential EfiEmu double prepare. + + * efiemu/main.c (prepared): New variable + (grub_efiemu_unload): Set prepare to '0'. + (grub_efiemu_prepare): Return if already prepared. Set prepared. + + set_virtual_address_map support. + + * include/grub/efi/efi.h (grub_efi_set_virtual_address_map): New + prototype. + * include/grub/efiemu/efiemu.h (grub_efiemu_write_sym_markers): New + prototype. + (grub_efiemu_crc32): Likewise. + (grub_efiemu_crc64): Likewise. + (grub_efiemu_set_virtual_address_map): Likewise. + * include/grub/autoefi.h (grub_autoefi_exit_boot_services): + New definition. + (grub_autoefi_set_virtual_address_map): Likewise. + * kern/efi/efi.c (grub_efi_set_virtual_address_map): New function. + * loader/i386/xnu.c (grub_xnu_boot): Call set_virtual_address_map. + Restructure flow to accomodate it. + * efiemu/prepare.c (grub_efiemu_prepare): Support set_virtual_address_map. + (grub_efiemu_crc): Recompute CRC32. + * efiemu/runtime/efiemu.c (ptv_relocated): Renamed to ... + (efiemu_ptv_relocated): ... this. Made global. All users updated. + * efiemu/symbols.c (relocated_handle): New variable. + (grub_efiemu_free_syms): Free relocated_handle. + (grub_efiemu_alloc_syms): Allocate relocated_handle. + (grub_efiemu_write_sym_markers): New function. + (grub_efiemu_set_virtual_address_map): Likewise. + + Newer XNU parameters. + + * include/grub/i386/xnu.h (GRUB_XNU_BOOTARGS_VERMINOR): Change to 5. + * include/grub/xnu.h (grub_xnu_extheader): Add nameaddr and namesize. + (grub_xnu_fill_devicetree): New prototype. + (grub_xnu_heap_real_start): New variable. + * loader/xnu.c (get_name_ptr): New function. + (grub_xnu_load_driver): Fill namelen and name. + + 64-bit xnu support. + + * conf/i386-efi.rmk (xnu_mod_SOURCES): Add 'loader/macho32.c' + and 'loader/macho64.c'. + * conf/i386-pc.rmk: Likewise. + * conf/x86_64-efi.rmk: Likewise. + * include/grub/i386/macho.h (grub_macho_thread64): New structure. + * include/grub/xnu.h (grub_xnu_is_64bit): New variable. + * include/grub/macho.h (grub_macho_segment64): New structure. + * include/grub/machoload.h (grub_macho32_size): Renamed from ... + (grub_macho_size32): ... to this. + (grub_macho32_get_entry_point): Renamed from ... + (grub_macho_get_entry_point32): ... to this. + (grub_macho_contains_macho64): New prototype. + (grub_macho_size64): Likewise. + (grub_macho_get_entry_point64): Likewise. + (grub_macho32_load): Renamed from ... + (grub_macho_load32): ... to this. + (grub_macho32_filesize): Renamed from ... + (grub_macho_filesize32): ... to this. + (grub_macho32_readfile): Renamed from ... + (grub_macho_readfile32): ... to this. + (grub_macho_filesize64): New prototype. + (grub_macho_readfile64): Likewise. + (grub_macho_parse32): Likewise. + (grub_macho_parse64): Likewise. + * loader/macho.c: Split into ... + * loader/machoXX.c: ... and this. Replace 32 with XX. + * loader/macho32.c: New file. + * loader/macho64.c: Likewise. + * loader/xnu.c (grub_xnu_is_64bit): New variable. + (grub_cmd_xnu_kernel): Make 32-bit only. + (grub_cmd_xnu_kernel64): New function. + (grub_xnu_load_driver): Support Mach-O 64. + (grub_cmd_xnu_mkext): Likewise. + * util/grub.d/30_os-prober.in (osx_entry): New function. + Generate entries for 64-bit boot too. + + Eliminate ad-hoc tree format in XNU and EfiEmu. + + * efiemu/main.c (grub_efiemu_prepare): Update comment. + * efiemu/pnvram.c: Rewritten to use environment variables. + All users updated. + + Inline utf16_to_utf8. + + * kern/misc.c (grub_utf16_to_utf8): Move from here ... + * include/grub/charset.h (grub_utf16_to_utf8): ... to here. Inlined. + All users updated. + * include/grub/misc.h (grub_utf16_to_utf8): Removed. + + * bus/usb/usb.c (grub_usb_get_string): Move from here ... + * commands/usbtest.c (grub_usb_get_string): ... move here. + (usb_print_str): Fix error handling. + * include/grub/usb.h (grub_usb_get_string): Remove. + + UTF-8 to UTF-16 transformation. + + * conf/common.rmk (pkglib_MODULES): Add charset.mod + (charset_mod_SOURCES): New variable. + (charset_mod_CFLAGS): Likewise. + (charset_mod_LDFLAGS): Likewise. + * include/grub/utf.h: New file. + * lib/utf.c: New file. (Based on grub_utf8_to_ucs4 from kern/misc.c) + + Support for device properties. + + * include/grub/i386/xnu.h (grub_xnu_devprop_header): New structure. + (grub_xnu_devprop_device_header): Likewise. + (grub_xnu_devprop_device_descriptor): Likewise. + (grub_xnu_devprop_add_device): New prototype. + (grub_xnu_devprop_remove_device): Likewise. + (grub_xnu_devprop_remove_property): Likewise. + (grub_xnu_devprop_add_property_utf8): Likewise. + (grub_xnu_devprop_add_property_utf16): Likewise. + (grub_cpu_xnu_init): Likewise. + (grub_cpu_xnu_fini): Likewise. + (grub_cpu_xnu_unload): Likewise. + * loader/i386/xnu.c (grub_xnu_devprop_device_descriptor): New structure. + (property_descriptor): Likewise. + (devices): New variable. + (grub_xnu_devprop_remove_property): New function. + (grub_xnu_devprop_add_device): Likewise. + (grub_xnu_devprop_remove_device): Likewise. + (grub_xnu_devprop_add_property): Likewise. + (grub_xnu_devprop_add_property_utf8): Likewise. + (grub_xnu_devprop_add_property_utf16): Likewise. + (hextoval): Likewise. + (grub_cpu_xnu_fill_devprop): Likewise. + (grub_cmd_devprop_load): Likewise. + (grub_xnu_boot): Call grub_cpu_xnu_fill_devprop, + grub_xnu_fill_devicetree, grub_xnu_fill_devicetree + (cmd_devprop_load): New variable. + (grub_cpu_xnu_init): New function. + (grub_cpu_xnu_fini): Likewise. + * loader/i386/xnu.c (grub_xnu_unload): Call grub_cpu_xnu_unload. + * loader/xnu.c (grub_xnu_parse_devtree): Remove. + (grub_cmd_xnu_devtree): Likewise. + (hextoval): New function. + (unescape): Likewise. + (grub_xnu_fill_devicetree): Likewise. + + * util/grub.d/30_os-prober.in: Load devprop.bin. Don't load devtree.txt. + * util/i386/efi/grub-dumpdevtree: Generate devprop.bin. + +2009-12-18 Vladimir Serbinenko + + Workaround for broken ATI VBE. + + * video/i386/pc/vbe.c (last_set_mode): New variable. + (grub_vbe_set_video_mode): Set 'last_set_mode'. + (grub_vbe_get_video_mode): Use 'last_set_mode' if get_mode fails. + (grub_video_vbe_setup): Don't check for reserved flag. + +2009-12-17 Felix Zielcke + + * gendistlist.sh: Use POSIX compliant `!' instead of `-not' in + the `find' command. + +2009-12-16 Vladimir Serbinenko + + UUID support for HFS. + + * fs/hfs.c (grub_hfs_uuid): New function. + (grub_hfs_fs): New value .uuid. + * include/grub/hfs.h (grub_hfs_sblock): New field 'num_serial'. + +2009-12-14 Felix Zielcke + + Fix a segfault with parsing unknown long options. + + * util/grub-mkrelpath.c (options): Zero terminate it. + +2009-12-13 Carles Pina i Estany + + * include/grub/misc.h (grub_puts): New declaration. + (grub_puts_): Likewise. + * kern/misc.c (grub_puts): New definition. + (grub_puts_): Likewise. + +2009-12-13 Robert Millan + + * util/grub-probe.c (probe): Improve error message. + +2009-12-13 Robert Millan + + * loader/i386/multiboot_elfxx.c + (CONCAT(grub_multiboot_load_elf, XX)): Fix `grub_multiboot_payload_eip' + initialization. + +2009-12-13 Vladimir Serbinenko + + Relocator framework + + * loader/i386/xnu_helper.S: Removed. All users updated. + * conf/i386.rmk (pkglib_MODULES): Add relocator.mod. + (relocator_mod_SOURCES): New variable. + (relocator_mod_CFLAGS): Likewise. + (relocator_mod_LDFLAGS): Likewise. + (relocator_mod_ASFLAGS): Likewise. + * conf/x86_64.rmk: Likewise. + * include/grub/i386/multiboot.h (grub_multiboot_payload_orig): Removed. + (grub_multiboot_payload_entry_offset): Likewise. + (grub_multiboot_forward_relocator): Likewise. + (grub_multiboot_forward_relocator_end): Likewise. + (grub_multiboot_backward_relocator): Likewise. + (grub_multiboot_backward_relocator_end): Likewise. + (grub_multiboot_payload_eip): New variable. + (grub_multiboot_payload_orig): Likewise. + * include/grub/i386/pc/memory.h: Include grub/i386/memory.h. + (GRUB_MEMORY_MACHINE_CR0_PE_ON): Move from here ... + * include/grub/i386/memory.h + (GRUB_MEMORY_CPU_CR0_PE_ON): ... to here + (GRUB_MEMORY_CPU_CR4_PAE_ON): New definition. + (GRUB_MEMORY_CPU_CR0_PAGING_ON): Likewise. + (GRUB_MEMORY_CPU_AMD64_MSR): Likewise. + (GRUB_MEMORY_CPU_AMD64_MSR_ON): Likewise. + * include/grub/i386/relocator.h: New file. + * include/grub/x86_64/relocator.h: Likewise. + * include/grub/i386/xnu.h: Include grub/cpu/relocator.h. + (XNU_RELOCATOR): New macro. + (grub_xnu_launcher_start): Remove. + (grub_xnu_launcher_end): Likewise. + * include/grub/xnu.h (grub_xnu_boot_resume): New prototype. + (grub_xnu_heap_real_start): Remove. + (grub_xnu_heap_start): Change to void *. All users updated. + * kern/i386/realmode.S (real_to_prot): Use GRUB_MEMORY_CPU_CR0_PE_ON. + * lib/i386/relocator.c: New file. + * lib/i386/relocator_asm.S: Likewise. + * lib/i386/relocator_backward.S: Likewise. + * lib/mips/relocator.c: Likewise. + * lib/mips/relocator_asm.S: Likewise. + * lib/relocator.c: Likewise. + * loader/i386/multiboot.c: Include grub/i386/relocator.h. + (entry): Removed. + (playground): Likewise. + (grub_multiboot_payload_orig): New variable. + (grub_multiboot_payload_dest): Likewise. + (grub_multiboot_payload_size): Likewise. + (grub_multiboot_payload_eip): Likewise. + (grub_multiboot_payload_esp): Likewise. + (grub_multiboot_boot): Use grub_relocator32_boot. + (grub_multiboot_unload): Free relocators. + (grub_multiboot): Setup stack. Use relocators. + * loader/i386/multiboot_elfxx.c: Include grub/i386/relocator.h. + (grub_multiboot_load_elfXX): Use relocators. + * loader/i386/multiboot_helper.S (grub_multiboot_payload_orig): Removed. + (grub_multiboot_payload_size): Likewise. + (grub_multiboot_payload_dest): Likewise. + (grub_multiboot_payload_entry_offset): Likewise. + (grub_multiboot_forward_relocator): Likewise. + (grub_multiboot_backward_relocator): Likewise. + (grub_multiboot_real_boot): Likewise. + * loader/i386/xnu.c (grub_xnu_heap_will_be_at): New variable. + (grub_xnu_entry_point): Likewise. + (grub_xnu_arg1): Likewise. + (grub_xnu_stack): Likewise. + (grub_xnu_launch): Removed. + (grub_xnu_boot_resume): New function. + (grub_xnu_boot): Use relocators. + * loader/i386/xnu_helper.S: Removed. + * loader/xnu.c (grub_xnu_heap_start): New variable. + (grub_xnu_heap_size): Likewise. + (grub_xnu_heap_malloc): Use relocators. + * loader/xnu_resume.c (grub_xnu_resume): Use relocators. + +2009-12-13 Vladimir Serbinenko + + * kern/i386/pc/startup.S (multiboot_entry): Setup stack before calling + anything. + +2009-12-13 Carles Pina i Estany + + * script/execute.c (grub_script_execute_cmdline): Set grub_errno to + GRUB_ERR_NONE before calling grub_env_set. + +2009-12-12 Robert Millan + + * gendistlist.sh (EXTRA_DISTFILES): Add `genvideolist.sh'. + * genmk.rb (video): New variable. + (CLEANFILES, VIDEOFILES): Add #{video}. + (#{video}): New target rule. + * genvideolist.sh: New file. + * Makefile.in (pkglib_DATA): Add video.lst. + (video.lst): New target rule. + * util/grub-mkconfig.in: Initialize ${GRUB_VIDEO_BACKEND} using + `video.lst'. + * util/grub.d/30_os-prober.in: Replace `vbe' with + ${GRUB_VIDEO_BACKEND}. + +2009-12-11 Robert Millan + + * THANKS: Add David Miller. + +2009-12-11 Vladimir Serbinenko + + libpciaccess support. + + * Makefile.in (LIBPCIACCESS): New variable. + (enable_grub_emu_pci): Likewise. + * conf/any-emu.rmk (grub_emu_SOURCES) [enable_grub_emu_pci]: Add + util/pci.c and commands/lspci.c. + (grub_emu_LDFLAGS) [enable_grub_emu_pci]: Add $(LIBPCIACCESS). + * configure.ac (grub-emu-pci): New option. + * include/grub/i386/pci.h (grub_pci_device_map_range): New function. + (grub_pci_device_unmap_range): Likewise. + * include/grub/pci.h [GRUB_UTIL]: Include grub/pciutils.h. + (grub_pci_device) [!GRUB_UTIL]: New structure. All users updated. + (grub_pci_address_t) [!GRUB_UTIL]: New type. + (grub_pci_device_t) [!GRUB_UTIL]: Likewise. + (grub_pci_get_bus) [!GRUB_UTIL]: New function. + (grub_pci_get_device) [!GRUB_UTIL]: Likewise. + (grub_pci_get_function) [!GRUB_UTIL]: Likewise. + * include/grub/pciutils.h: New file. + * util/pci.c: Likewise. + +2009-12-11 Felix Zielcke + + * util/misc.c: Don't include twice. + +2009-12-10 Felix Zielcke + + * disk/i386/pc/biosdisk.c (grub_biosdisk_open): Show the disk + name in an error message. + (grub_biosdisk_rw): Likewise. + 2009-12-10 Vladimir Serbinenko Eliminate NTFS 4Gib barrier. @@ -88,7 +5414,7 @@ * disk/ieee1275/ofdisk.c (grub_ofdisk_iterate): Recognize anything even prefixed with 'cdrom' as a cdrom. -2009-12-06 Felix Zielcke +2009-12-06 Felix Zielcke * util/misc.c (make_system_path_relative_to_its_root): Correctly cope with mount points. @@ -99,7 +5425,7 @@ grub_gettext_msg_list. (grub_gettext_gettranslation_from_position): Return const char * and not char *. - (grub_gettext_translate): Add the translated strings into a list, + (grub_gettext_translate): Add the translated strings into a list, returns from the list if existing there. (grub_gettext_init_ext): Add \n at the end of grub_dprintf string. (grub_gettext_delete_list): Delete the list. @@ -140,7 +5466,7 @@ (run_menu): Replaces grub_printf by print_spaces and dynamic terminal width. (get_entry_number): Gettextize and uses dynamic terminal width. - (notify_booting, notify_fallback, notify_execution_failure): + (notify_booting, notify_fallback, notify_execution_failure): Gettextize. * normal/menu_entry.c (store_completion): Cleanup the gettextized string. @@ -304,7 +5630,7 @@ ($(foreach lang, $(LINGUAS), $(srcdir)/po/$(lang).po)): Rewrite as ... (po/%.po): ... this. -2009-11-26 Felix Zielcke +2009-11-26 Felix Zielcke * util/i386/efi/grub-mkimage.c: Include "progname.h". (main): Use `program_name' instead of nonexistent `progname'. @@ -411,7 +5737,7 @@ * include/grub/i18n.h: ... to here * include/grub/i18n.h: ... to here. * kern/misc.c: Include - (grub_gettext_dummy): Move above user. + (grub_gettext_dummy): Move above user. 2009-11-24 Felix Zielcke @@ -21124,7 +26450,7 @@ * genmk.rb (PModule#rule): Make sure to get only symbol names from the output of nm. - Reported by Robert Millan . + Reported by Robert Millan . 2003-09-25 Yoshinori K. Okuji diff --git a/INSTALL b/INSTALL index cfade2026..0dd408bcc 100644 --- a/INSTALL +++ b/INSTALL @@ -14,6 +14,7 @@ configuring the GRUB. * GCC 4.1.3 or later * GNU Make * GNU Bison 2.3 or later +* GNU gettext 0.17 or later * GNU binutils 2.9.1.0.23 or later * Other standard GNU/Unix tools @@ -25,6 +26,10 @@ need the following. * Autoconf 2.60 or later * Automake 1.10.1 or later +Prerequisites for make-check: + +* qemu, specifically the binary 'qemu-system-i386' + Configuring the GRUB ==================== diff --git a/Makefile.in b/Makefile.in index 9c7c735d7..75388e3c8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,6 +1,6 @@ # -*- makefile -*- # -# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2001,2002,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. +# Copyright (C) 1994,1995,1996,1997,1998,1999,2000,2001,2002,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. # # This Makefile.in is free software; the author # gives unlimited permission to copy and/or distribute it, @@ -35,12 +35,20 @@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ +localedir = @localedir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ pkgdatadir = $(datadir)/`echo @PACKAGE_TARNAME@ | sed '$(transform)'` pkglibdir = $(libdir)/`echo @PACKAGE_TARNAME@/$(target_cpu)-$(platform) | sed '$(transform)'` +# Internationalization library. +LIBINTL = @LIBINTL@ +TARGET_NO_MODULES = @TARGET_NO_MODULES@ + +# Util library. +LIBUTIL = @LIBUTIL@ + XGETTEXT = @XGETTEXT@ MSGMERGE = @MSGMERGE@ MSGFMT = @MSGFMT@ @@ -72,25 +80,31 @@ MKDIR_P = @MKDIR_P@ mkinstalldirs = $(srcdir)/mkinstalldirs +LIBS = @LIBS@ $(LIBINTL) $(LIBUTIL) + CC = @CC@ CFLAGS = @CFLAGS@ +POSIX_CFLAGS = -I$(srcdir)/lib/posix_wrap +GNULIB_UTIL_CFLAGS = -Wno-undef -Wno-sign-compare -Wno-unused -D_GL_UNUSED="__attribute__ ((unused))" -I$(srcdir)/gnulib +GNULIB_CFLAGS = $(GNULIB_UTIL_CFLAGS) $(POSIX_CFLAGS) ASFLAGS = @ASFLAGS@ -LDFLAGS = @LDFLAGS@ +LDFLAGS = @LDFLAGS@ $(LIBS) CPPFLAGS = @CPPFLAGS@ -I$(builddir) -I$(builddir)/include -I$(srcdir)/gnulib -I$(srcdir)/include -Wall -W \ - -DGRUB_LIBDIR=\"$(pkglibdir)\" -DLOCALEDIR=\"$(localedir)\" + -DGRUB_PKGLIBROOTDIR=\"$(libdir)/`echo @PACKAGE_TARNAME@ | sed '$(transform)'`\" -DLOCALEDIR=\"$(localedir)\" TARGET_CC = @TARGET_CC@ -TARGET_CFLAGS = @TARGET_CFLAGS@ -TARGET_ASFLAGS = @TARGET_ASFLAGS@ +TARGET_CFLAGS = -ffreestanding @TARGET_CFLAGS@ +TARGET_ASFLAGS = -nostdinc -fno-builtin @TARGET_ASFLAGS@ TARGET_MODULE_FORMAT = @TARGET_MODULE_FORMAT@ TARGET_APPLE_CC = @TARGET_APPLE_CC@ OBJCONV = @OBJCONV@ -TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ -nostdinc -isystem $(shell $(TARGET_CC) -print-file-name=include) -I$(srcdir)/include -I$(builddir) -I$(builddir)/include \ +TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ -I$(srcdir)/include -I$(builddir) -I$(builddir)/include \ -Wall -W -TARGET_LDFLAGS = @TARGET_LDFLAGS@ +TARGET_LDFLAGS = -nostdlib -static-libgcc @TARGET_LDFLAGS@ TARGET_IMG_LDSCRIPT = @TARGET_IMG_LDSCRIPT@ -TARGET_IMG_LDFLAGS = @TARGET_IMG_LDFLAGS@ +TARGET_IMG_LDFLAGS = -nostdlib @TARGET_IMG_LDFLAGS@ TARGET_IMG_CFLAGS = @TARGET_IMG_CFLAGS@ TARGET_OBJ2ELF = @TARGET_OBJ2ELF@ +kernel_img_LDFLAGS = -lgcc EXEEXT = @EXEEXT@ OBJCOPY = @OBJCOPY@ STRIP = @STRIP@ @@ -109,11 +123,16 @@ endif AWK = @AWK@ LIBCURSES = @LIBCURSES@ LIBUSB = @LIBUSB@ +LIBSDL = @LIBSDL@ +LIBPCIACCESS = @LIBPCIACCESS@ +LEX = @LEX@ YACC = @YACC@ FONT_SOURCE = @FONT_SOURCE@ # Options. enable_grub_emu_usb = @enable_grub_emu_usb@ +enable_grub_emu_sdl = @enable_grub_emu_sdl@ +enable_grub_emu_pci = @enable_grub_emu_pci@ enable_grub_fstest = @enable_grub_fstest@ enable_grub_pe2elf = @enable_grub_pe2elf@ enable_grub_mkfont = @enable_grub_mkfont@ @@ -123,7 +142,7 @@ enable_efiemu = @enable_efiemu@ ### General variables. -RMKFILES = $(wildcard conf/*.rmk) +RMKFILES = $(wildcard $(srcdir)/conf/*.rmk) MKFILES = $(patsubst %.rmk,%.mk,$(RMKFILES)) @@ -138,11 +157,13 @@ INFOS = $(info_INFOS) CLEANFILES = MOSTLYCLEANFILES = DISTCLEANFILES = config.status config.cache config.log config.h \ - Makefile stamp-h include/grub/cpu include/grub/machine \ + Makefile stamp-h stamp-h1 include/grub/cpu include/grub/machine \ gensymlist.sh genkernsyms.sh build_env.mk \ docs/grub.info docs/version.texi docs/stamp-vti -MAINTAINER_CLEANFILES = $(srcdir)/configure $(addprefix $(srcdir)/,$(MKFILES)) \ +MAINTAINER_CLEANFILES = $(srcdir)/configure $(srcdir)/aclocal.m4 \ + $(MKFILES) $(srcdir)/config.guess \ + $(srcdir)/config.sub $(srcdir)/install-sh $(srcdir)/missing \ $(srcdir)/DISTLIST $(srcdir)/config.h.in $(srcdir)/stamp-h.in $(INFOS) # The default target. @@ -160,14 +181,23 @@ ifeq ($(platform), emu) include $(srcdir)/conf/any-emu.mk else include $(srcdir)/conf/$(target_cpu)-$(platform).mk +# For tests. +include $(srcdir)/conf/tests.mk # For external modules. -include $(wildcard $(GRUB_CONTRIB)/*/conf/common.mk) endif +ifeq ($(TARGET_NO_MODULES), yes) + TARGET_CFLAGS += -DGRUB_TARGET_NO_MODULES=1 + CFLAGS += -DGRUB_TARGET_NO_MODULES=1 +endif + ### General targets. CLEANFILES += $(pkglib_DATA) $(pkgdata_DATA) po/*.mo -pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst +ifneq ($(TARGET_NO_MODULES), yes) +pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst terminal.lst +endif moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep.awk cat $(DEFSYMFILES) /dev/null \ | $(AWK) -f $(srcdir)/genmoddep.awk $(UNDSYMFILES) > $@ \ @@ -185,9 +215,18 @@ partmap.lst: $(PARTMAPFILES) handler.lst: $(HANDLERFILES) cat $^ /dev/null | sort > $@ +terminal.lst: $(TERMINALFILES) + cat $^ /dev/null | sort > $@ + parttool.lst: $(PARTTOOLFILES) cat $^ /dev/null | sort | uniq > $@ +video.lst: $(VIDEOFILES) + cat $^ /dev/null | sort | uniq > $@ + +crypto.lst: lib/libgcrypt-grub/cipher/crypto.lst + cp $^ $@ + ifneq (true, $(MAKEINFO)) info_INFOS += docs/grub.info endif @@ -218,7 +257,8 @@ else ifeq ($(enable_grub_mkfont),yes) -pkgdata_DATA += unicode.pf2 ascii.pf2 +pkgdata_DATA += unicode.pf2 ascii.pf2 ascii.h +CLEANFILES += ascii.bitmaps # Arrows and lines are needed to draw the menu, so we always include them UNICODE_ARROWS=0x2190-0x2193 @@ -229,6 +269,14 @@ unicode.pf2: $(FONT_SOURCE) grub-mkfont ascii.pf2: $(FONT_SOURCE) grub-mkfont $(builddir)/grub-mkfont -o $@ $(FONT_SOURCE) -r 0x0-0x7f,$(UNICODE_ARROWS),$(UNICODE_LINES) + +ascii.bitmaps: $(FONT_SOURCE) grub-mkfont + $(builddir)/grub-mkfont --ascii-bitmaps -o $@ $(FONT_SOURCE) + +ascii.h: ascii.bitmaps grub-bin2h + $(builddir)/grub-bin2h ascii_bitmaps < $< > $@ + +TARGET_CFLAGS += -DUSE_ASCII_FAILBACK=1 endif endif @@ -250,7 +298,7 @@ build_env.mk: Makefile ) > $@ pkglib_BUILDDIR += config.h grub_script.tab.h -all-local: $(PROGRAMS) $(PKGLIB) $(PKGDATA) $(SCRIPTS) $(INFOS) $(MKFILES) $(foreach lang, $(LINGUAS), po/$(lang).mo) +all-local: $(PROGRAMS) $(GRUB_EMU) $(PKGLIB) $(PKGDATA) $(SCRIPTS) $(INFOS) $(MKFILES) $(foreach lang, $(LINGUAS), po/$(lang).mo) install: install-local @@ -271,7 +319,7 @@ install-local: all $(INSTALL_DATA) $$dir$$file $(DESTDIR)$(pkgdatadir)/$$dest; \ done $(SHELL) $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(mandir)/man1 - @list='$(bin_UTILITIES)'; for file in $$list; do \ + @list='$(bin_UTILITIES) $(GRUB_EMU)'; for file in $$list; do \ if test -f "$$file"; then dir=; else dir="$(srcdir)/"; fi; \ dest="`echo $$file | sed 's,.*/,,' | sed '$(transform)'`"; \ $(INSTALL_PROGRAM) $$dir$$file $(DESTDIR)$(bindir)/$$dest; \ @@ -347,7 +395,7 @@ uninstall: dest="`echo $$file | sed 's,.*/,,'`"; \ rm -f $(DESTDIR)$(pkgdatadir)/$$dest; \ done - @list='$(bin_UTILITIES) $(bin_SCRIPTS)'; for file in $$list; do \ + @list='$(bin_UTILITIES) $(bin_SCRIPTS) $(GRUB_EMU)'; for file in $$list; do \ dest="`echo $$file | sed 's,.*/,,' | sed '$(transform)'`"; \ rm -f $(DESTDIR)$(bindir)/$$dest; \ rm -f $(DESTDIR)$(mandir)/man1/$$dest.1; \ @@ -364,7 +412,6 @@ uninstall: @list='$(lib_SCRIPTS)'; \ for file in $$list; do \ dest="`echo $$file | sed 's,.*/,,'`"; \ - echo rm -f $(DESTDIR)$(libdir)/$$dest; \ rm -f $(DESTDIR)$(libdir)/grub/$$dest; \ done @list='$(info_INFOS)'; \ @@ -393,6 +440,8 @@ distclean: mostlyclean maintainer-clean: distclean -test -z "$(MAINTAINER_CLEANFILES)" || rm -f $(MAINTAINER_CLEANFILES) + -rmdir $(srcdir)/lib/libgcrypt-grub/cipher + -rmdir $(srcdir)/lib/libgcrypt-grub info: @@ -445,7 +494,24 @@ distcheck: dist @echo "$(distdir).tar.gz is ready for distribution" | \ sed 'h;s/./=/g;p;x;p;x' -check: +check: all $(UNIT_TESTS) $(FUNCTIONAL_TESTS) $(SCRIPTED_TESTS) + @list="$(UNIT_TESTS)"; \ + set -e; \ + for file in $$list; do \ + $(builddir)/$$file; \ + done + @list="$(FUNCTIONAL_TESTS)"; \ + set -e; \ + for file in $$list; do \ + mod=`basename $$file .mod`; \ + echo "insmod functional_test; insmod $$mod; functional_test" \ + | $(builddir)/grub-shell; \ + done + @list="$(SCRIPTED_TESTS)"; \ + set -e; \ + for file in $$list; do \ + $(builddir)/$$file; \ + done .SUFFIX: .SUFFIX: .c .o .S .d @@ -479,8 +545,8 @@ genkernsyms.sh: genkernsyms.sh.in config.status $(SHELL) ./config.status $(srcdir)/po/$(PACKAGE).pot: po/POTFILES po/POTFILES-shell - cd $(srcdir) && $(XGETTEXT) --from-code=utf-8 -o $@ -f $< --keyword=_ --keyword=N_ - cd $(srcdir) && $(XGETTEXT) --from-code=utf-8 -o $@ -f po/POTFILES-shell -j --language=Shell + cd $(srcdir) && $(XGETTEXT) -ctranslate --from-code=utf-8 -o po/$(PACKAGE).pot -f po/POTFILES --keyword=_ --keyword=N_ + cd $(srcdir) && $(XGETTEXT) -ctranslate --from-code=utf-8 -o po/$(PACKAGE).pot -f po/POTFILES-shell -j --language=Shell $(foreach lang, $(LINGUAS), $(srcdir)/po/$(lang).po): po/$(PACKAGE).pot $(MSGMERGE) -U $@ $^ diff --git a/NEWS b/NEWS index bf7492c6d..1e3334f18 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,28 @@ -New in 1.97 - : +New in 1.98 - 2010-03-06: + +* Multiboot on EFI support. + +* Graphical menu support. + +* MIPS support. + +* Saved default menu entry support, with new utilities `grub-reboot' and + `grub-set-default'. + +* Unit testing framework. + +* Support for multiple terminals. + +* Encrypted password support, with a new utility `grub-mkpasswd-pbkdf2'. + +* `grub-mkfloppy' removed; use `grub-mkrescue' to create floppy images. + +* Add grub-probe support for GNU/Hurd. * Add support for gettext. +New in 1.97: + * Add support for loading XNU (MacOS X kernel). * ACPI override support. diff --git a/THANKS b/THANKS index 5ce190944..82b4bc838 100644 --- a/THANKS +++ b/THANKS @@ -8,6 +8,7 @@ generally assist in the GRUB 2 maintainership process: Andrey Shuvikov Bibo Mao +David Miller Guillem Jover Harley D. Eades III Hitoshi Ozeki diff --git a/acinclude.m4 b/acinclude.m4 index 6f9baf18f..72483b5d0 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -14,11 +14,11 @@ $2 dnl Check whether target compiler is working -AC_DEFUN(grub_PROG_TARGET_CC, +AC_DEFUN([grub_PROG_TARGET_CC], [AC_MSG_CHECKING([whether target compiler is working]) AC_CACHE_VAL(grub_cv_prog_target_cc, [AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -asm (".globl start; start: nop"); +asm (".globl start; start:"); int main (void); ]], [[]])], [grub_cv_prog_target_cc=yes], @@ -36,7 +36,7 @@ dnl grub_ASM_USCORE checks if C symbols get an underscore after dnl compiling to assembler. dnl Written by Pavel Roskin. Based on grub_ASM_EXT_C written by dnl Erich Boleyn and modified by Yoshinori K. Okuji. -AC_DEFUN(grub_ASM_USCORE, +AC_DEFUN([grub_ASM_USCORE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING([if C symbols get an underscore after compilation]) AC_CACHE_VAL(grub_cv_asm_uscore, @@ -75,7 +75,7 @@ AC_MSG_RESULT([$grub_cv_asm_uscore]) dnl Some versions of `objcopy -O binary' vary their output depending dnl on the link address. -AC_DEFUN(grub_PROG_OBJCOPY_ABSOLUTE, +AC_DEFUN([grub_PROG_OBJCOPY_ABSOLUTE], [AC_MSG_CHECKING([whether ${OBJCOPY} works for absolute addresses]) AC_CACHE_VAL(grub_cv_prog_objcopy_absolute, [cat > conftest.c <<\EOF @@ -93,7 +93,7 @@ else fi grub_cv_prog_objcopy_absolute=yes for link_addr in 0x2000 0x8000 0x7C00; do - if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -nostdlib ${TARGET_IMG_LDFLAGS_AC} -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then : + if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -nostdlib ${TARGET_IMG_LDFLAGS_AC}$link_addr conftest.o -o conftest.exec]); then : else AC_MSG_ERROR([${CC-cc} cannot link at address $link_addr]) fi @@ -119,7 +119,7 @@ fi dnl Supply --build-id=none to ld if building modules. dnl This suppresses warnings from ld on some systems -AC_DEFUN(grub_PROG_LD_BUILD_ID_NONE, +AC_DEFUN([grub_PROG_LD_BUILD_ID_NONE], [AC_MSG_CHECKING([whether linker accepts --build-id=none]) AC_CACHE_VAL(grub_cv_prog_ld_build_id_none, [save_LDFLAGS="$LDFLAGS" @@ -150,7 +150,7 @@ dnl dnl We only support the newer versions, because the old versions cause dnl major pain, by requiring manual assembly to get 16-bit instructions into dnl asm files. -AC_DEFUN(grub_I386_ASM_ADDR32, +AC_DEFUN([grub_I386_ASM_ADDR32], [AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([grub_I386_ASM_PREFIX_REQUIREMENT]) AC_MSG_CHECKING([for .code16 addr32 assembler support]) @@ -178,7 +178,7 @@ AC_MSG_RESULT([$grub_cv_i386_asm_addr32])]) dnl check if our compiler is apple cc dnl because it requires numerous workarounds -AC_DEFUN(grub_apple_cc, +AC_DEFUN([grub_apple_cc], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING([whether our compiler is apple cc]) AC_CACHE_VAL(grub_cv_apple_cc, @@ -193,7 +193,7 @@ AC_MSG_RESULT([$grub_cv_apple_cc])]) dnl check if our target compiler is apple cc dnl because it requires numerous workarounds -AC_DEFUN(grub_apple_target_cc, +AC_DEFUN([grub_apple_target_cc], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING([whether our target compiler is apple cc]) AC_CACHE_VAL(grub_cv_apple_target_cc, @@ -210,7 +210,7 @@ AC_MSG_RESULT([$grub_cv_apple_target_cc])]) dnl Later versions of GAS requires that addr32 and data32 prefixes dnl appear in the same lines as the instructions they modify, while dnl earlier versions requires that they appear in separate lines. -AC_DEFUN(grub_I386_ASM_PREFIX_REQUIREMENT, +AC_DEFUN([grub_I386_ASM_PREFIX_REQUIREMENT], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(dnl [whether addr32 must be in the same line as the instruction]) @@ -246,7 +246,7 @@ AC_MSG_RESULT([$grub_cv_i386_asm_prefix_requirement])]) dnl Older versions of GAS require that absolute indirect calls/jumps are dnl not prefixed with `*', while later versions warn if not prefixed. -AC_DEFUN(grub_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK, +AC_DEFUN([grub_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(dnl [whether an absolute indirect call/jump must not be prefixed with an asterisk]) @@ -276,7 +276,7 @@ AC_MSG_RESULT([$grub_cv_i386_asm_absolute_without_asterisk])]) dnl Check what symbol is defined as a bss start symbol. dnl Written by Michael Hohmoth and Yoshinori K. Okuji. -AC_DEFUN(grub_CHECK_BSS_START_SYMBOL, +AC_DEFUN([grub_CHECK_BSS_START_SYMBOL], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING([if __bss_start is defined by the compiler]) AC_CACHE_VAL(grub_cv_check_uscore_uscore_bss_start_symbol, @@ -320,7 +320,7 @@ fi dnl Check what symbol is defined as an end symbol. dnl Written by Yoshinori K. Okuji. -AC_DEFUN(grub_CHECK_END_SYMBOL, +AC_DEFUN([grub_CHECK_END_SYMBOL], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING([if end is defined by the compiler]) AC_CACHE_VAL(grub_cv_check_end_symbol, @@ -352,7 +352,7 @@ fi ]) dnl Check if the C compiler generates calls to `__enable_execute_stack()'. -AC_DEFUN(grub_CHECK_ENABLE_EXECUTE_STACK,[ +AC_DEFUN([grub_CHECK_ENABLE_EXECUTE_STACK],[ AC_MSG_CHECKING([whether `$CC' generates calls to `__enable_execute_stack()']) AC_LANG_CONFTEST([[ void f (int (*p) (void)); @@ -379,7 +379,7 @@ rm -f conftest* dnl Check if the C compiler supports `-fstack-protector'. -AC_DEFUN(grub_CHECK_STACK_PROTECTOR,[ +AC_DEFUN([grub_CHECK_STACK_PROTECTOR],[ [# Smashing stack protector. ssp_possible=yes] AC_MSG_CHECKING([whether `$CC' accepts `-fstack-protector']) @@ -398,7 +398,7 @@ else ]) dnl Check if the C compiler supports `-mstack-arg-probe' (Cygwin). -AC_DEFUN(grub_CHECK_STACK_ARG_PROBE,[ +AC_DEFUN([grub_CHECK_STACK_ARG_PROBE],[ [# Smashing stack arg probe. sap_possible=yes] AC_MSG_CHECKING([whether `$CC' accepts `-mstack-arg-probe']) @@ -414,7 +414,7 @@ else ]) dnl Check if ln can handle directories properly (mingw). -AC_DEFUN(grub_CHECK_LINK_DIR,[ +AC_DEFUN([grub_CHECK_LINK_DIR],[ AC_MSG_CHECKING([whether ln can handle directories properly]) [mkdir testdir 2>/dev/null case $srcdir in @@ -432,7 +432,7 @@ rm -rf testdir] ]) dnl Check if the C compiler supports `-fPIE'. -AC_DEFUN(grub_CHECK_PIE,[ +AC_DEFUN([grub_CHECK_PIE],[ [# Position independent executable. pie_possible=yes] AC_MSG_CHECKING([whether `$CC' has `-fPIE' as default]) diff --git a/boot/i386/pc/boot.S b/boot/i386/pc/boot.S index 865326ee2..4afc57349 100644 --- a/boot/i386/pc/boot.S +++ b/boot/i386/pc/boot.S @@ -1,7 +1,7 @@ /* -*-Asm-*- */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2005,2006,2007,2008,2009 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 @@ -27,6 +27,7 @@ /* Print message string */ #define MSG(x) movw $x, %si; call LOCAL(message) +#define ERR(x) movw $x, %si; jmp LOCAL(error_message) .file "boot.S" @@ -233,7 +234,7 @@ LOCAL(chs_mode): jz LOCAL(floppy_probe) /* Nope, we definitely have a hard disk, and we're screwed. */ - jmp LOCAL(hd_probe_error) + ERR(hd_probe_error_string) LOCAL(final_init): /* set the mode to zero */ @@ -360,22 +361,15 @@ LOCAL(copy_buffer): * BIOS Geometry translation error (past the end of the disk geometry!). */ LOCAL(geometry_error): - MSG(geometry_error_string) - jmp LOCAL(general_error) - -/* - * Disk probe failure. - */ -LOCAL(hd_probe_error): - MSG(hd_probe_error_string) - jmp LOCAL(general_error) + ERR(geometry_error_string) /* * Read error on the disk. */ LOCAL(read_error): - MSG(read_error_string) - + movw $read_error_string, %si +LOCAL(error_message): + call LOCAL(message) LOCAL(general_error): MSG(general_error_string) diff --git a/boot/i386/pc/cdboot.S b/boot/i386/pc/cdboot.S index ccc9d64de..33569ce9d 100644 --- a/boot/i386/pc/cdboot.S +++ b/boot/i386/pc/cdboot.S @@ -1,7 +1,7 @@ /* -*-Asm-*- */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 diff --git a/boot/i386/pc/diskboot.S b/boot/i386/pc/diskboot.S index e5e4a4ef3..92f223f0d 100644 --- a/boot/i386/pc/diskboot.S +++ b/boot/i386/pc/diskboot.S @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2006,2007 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,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 @@ -370,7 +370,7 @@ blocklist_default_start: the start of the disk, sector 0 */ .long 2, 0 blocklist_default_len: - /* this is the number of sectors to read the command "install" + /* this is the number of sectors to read. grub-mkimage will fill this up */ .word 0 blocklist_default_seg: diff --git a/boot/i386/pc/lnxboot.S b/boot/i386/pc/lnxboot.S index c51741d42..b4f0030b8 100644 --- a/boot/i386/pc/lnxboot.S +++ b/boot/i386/pc/lnxboot.S @@ -1,7 +1,7 @@ /* -*-Asm-*- */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2007,2008,2009 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 @@ -185,7 +185,7 @@ real_code_2: call LOCAL(move_memory) /* Check for multiboot signature. */ - cmpl $MULTIBOOT_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_DATA_END) + cmpl $MULTIBOOT_HEADER_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_DATA_END) jz 1f movl (ramdisk_image - start), %esi diff --git a/boot/i386/pc/pxeboot.S b/boot/i386/pc/pxeboot.S index 2fc53bc81..446bfc781 100644 --- a/boot/i386/pc/pxeboot.S +++ b/boot/i386/pc/pxeboot.S @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2000,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2000,2005,2007,2008,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 @@ -16,6 +16,8 @@ * along with GRUB. If not, see . */ +#include + .file "pxeboot.S" .text @@ -28,7 +30,7 @@ _start: start: /* Use drive number 0x7F for PXE */ - movb $0x7F, %dl + movb $GRUB_BOOT_MACHINE_PXE_DL, %dl /* Jump to the real world */ ljmp $0, $0x8200 diff --git a/boot/i386/qemu/boot.S b/boot/i386/qemu/boot.S index a93fe3943..a84bd77a8 100644 --- a/boot/i386/qemu/boot.S +++ b/boot/i386/qemu/boot.S @@ -31,7 +31,7 @@ _start: jmp 1f - . = _start + GRUB_BOOT_MACHINE_CORE_ENTRY_ADDR + . = _start + GRUB_BOOT_I386_QEMU_CORE_ENTRY_ADDR VARIABLE(grub_core_entry_addr) .long 0 1: @@ -63,5 +63,8 @@ VARIABLE(grub_core_entry_addr) *right here* and this is why we need this kludge. */ . = GRUB_BOOT_MACHINE_SIZE - 16 + + .code16 + jmp _start . = GRUB_BOOT_MACHINE_SIZE diff --git a/boot/sparc64/ieee1275/boot.S b/boot/sparc64/ieee1275/boot.S index 74f4ee014..f08258f47 100644 --- a/boot/sparc64/ieee1275/boot.S +++ b/boot/sparc64/ieee1275/boot.S @@ -45,8 +45,9 @@ boot_version: .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR * load address plus the size of the prepended A.OUT header (32 bytes). */ boot_path: - . = _start + GRUB_BOOT_MACHINE_KERNEL_SECTOR -kernel_sector: .xword 2 + . = _start + GRUB_BOOT_MACHINE_KERNEL_BYTE +boot_path_end: +kernel_byte: .xword (2 << 9) kernel_address: .word GRUB_BOOT_MACHINE_KERNEL_ADDR prom_finddev_name: .asciz "finddevice" @@ -77,11 +78,23 @@ prom_error: /* %o0: OF call name * %o1: input arg 1 */ -prom_call_1_1: - mov 1, %g1 - ba prom_call - mov 1, %o5 +prom_call_1_1_o2: + clr %o2 + ba prom_call_x_1 + mov 1, %g1 +prom_call_getprop: + mov 4, %g1 + stx %g1, [%l1 + 256] + mov CHOSEN_NODE_REG, %o1 + ba prom_call_x_1 + GET_ABS(prom_getprop_name, %o0) + +prom_call_3_1_o1: + ba prom_call_3_1 + mov BOOTDEV_REG, %o1 + + /* %o2: message string * %o3: message length */ @@ -95,8 +108,9 @@ console_write: * %o2: input arg 2 * %o3: input arg 3 */ -prom_call_3_1: +prom_call_3_1: mov 3, %g1 +prom_call_x_1: mov 1, %o5 /* fallthru */ @@ -118,7 +132,7 @@ prom_call: boot_continue: mov %o7, PIC_REG /* PIC base */ - sethi %hi(SCRATCH_PAD), %l1 /* OF argument slots */ + sethi %hi(SCRATCH_PAD_BOOT), %l1 /* OF argument slots */ /* Find the /chosen node so we can fetch the stdout handle, * and thus perform console output. @@ -126,23 +140,17 @@ boot_continue: * chosen_node = prom_finddevice("/chosen") */ GET_ABS(prom_finddev_name, %o0) - GET_ABS(prom_chosen_path, %o1) - call prom_call_1_1 - clr %o2 + call prom_call_1_1_o2 + GET_ABS(prom_chosen_path, %o1) ldx [%l1 + 0x20], CHOSEN_NODE_REG brz CHOSEN_NODE_REG, prom_error /* getprop(chosen_node, "stdout", &buffer, buffer_size) */ - GET_ABS(prom_getprop_name, %o0) - mov 4, %g1 - mov 1, %o5 - mov CHOSEN_NODE_REG, %o1 - GET_ABS(prom_stdout_name, %o2) + GET_ABS(prom_stdout_name, %o2) add %l1, 256, %o3 - mov 1024, %o4 - call prom_call - stx %g1, [%l1 + 256] + call prom_call_getprop + mov 1024, %o4 lduw [%l1 + 256], STDOUT_NODE_REG brz,pn STDOUT_NODE_REG, prom_error @@ -152,15 +160,25 @@ boot_continue: call console_write mov GRUB_NAME_LEN, %o3 + GET_ABS(boot_path, %o3) + ldub [%o3], %o1 + brnz,pn %o1, bootpath_known + + /* getprop(chosen_node, "bootpath", &buffer, buffer_size) */ + GET_ABS(prom_bootpath_name, %o2) + call prom_call_getprop + mov (boot_path_end - boot_path), %o4 + +bootpath_known: + /* Open up the boot_path, and use that handle to read the * first block of the GRUB kernel image. * * bootdev_handle = open(boot_path) */ GET_ABS(prom_open_name, %o0) - GET_ABS(boot_path, %o1) - call prom_call_1_1 - clr %o2 + call prom_call_1_1_o2 + GET_ABS(boot_path, %o1) ldx [%l1 + 0x20], BOOTDEV_REG brz,pn BOOTDEV_REG, prom_open_error @@ -168,28 +186,23 @@ boot_continue: /* Since we have 64-bit cells, the high cell of the seek offset * is zero and the low cell is the entire value. * - * seek(bootdev, 0, *kernel_sector << 9) + * seek(bootdev, 0, *kernel_byte) */ GET_ABS(prom_seek_name, %o0) - mov BOOTDEV_REG, %o1 clr %o2 - LDX_ABS(kernel_sector, 0x00, %o3) - call prom_call_3_1 - sllx %o3, 9, %o3 + call prom_call_3_1_o1 + LDX_ABS(kernel_byte, 0x00, %o3) /* read(bootdev, *kernel_address, 512) */ GET_ABS(prom_read_name, %o0) - mov BOOTDEV_REG, %o1 LDUW_ABS(kernel_address, 0x00, %o2) - call prom_call_3_1 + call prom_call_3_1_o1 mov 512, %o3 LDUW_ABS(kernel_address, 0x00, %o2) jmpl %o2, %o7 nop -1: ba,a 1b - . = _start + GRUB_BOOT_MACHINE_CODE_END /* the last 4 bytes in the sector 0 contain the signature */ diff --git a/boot/sparc64/ieee1275/diskboot.S b/boot/sparc64/ieee1275/diskboot.S index 68ed0eee0..83dfee098 100644 --- a/boot/sparc64/ieee1275/diskboot.S +++ b/boot/sparc64/ieee1275/diskboot.S @@ -19,6 +19,7 @@ #include #include +#include .text .align 4 @@ -81,14 +82,14 @@ prom_call: after_info_block: - sethi %hi(SCRATCH_PAD), %l1 /* OF argument slots */ + sethi %hi(SCRATCH_PAD_DISKBOOT), %l1 /* OF argument slots */ GET_ABS(notification_string, %o2) call console_write mov NOTIFICATION_STRING_LEN, %o3 - GET_ABS(firstlist - GRUB_BOOT_MACHINE_LIST_SIZE, %l2) - set GRUB_BOOT_MACHINE_IMAGE_ADDRESS, %l3 + GET_ABS(firstlist - GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE, %l2) + set GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS, %l3 bootloop: lduw [%l2 + 0x08], %o0 brz %o0, bootit @@ -115,7 +116,7 @@ bootloop: mov NOTIFICATION_STEP_LEN, %o3 ba bootloop - sub %l2, GRUB_BOOT_MACHINE_LIST_SIZE, %l2 + sub %l2, GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE, %l2 bootit: GET_ABS(prom_close_name, %o0) @@ -127,16 +128,16 @@ bootit: GET_ABS(notification_done, %o2) call console_write mov NOTIFICATION_DONE_LEN, %o3 - sethi %hi(GRUB_BOOT_MACHINE_IMAGE_ADDRESS), %o2 - jmpl %o2 + %lo(GRUB_BOOT_MACHINE_IMAGE_ADDRESS), %o7 - mov CIF_REG, %o0 + sethi %hi(GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS), %o2 + jmpl %o2 + %lo(GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS), %o7 + mov CIF_REG, %o4 1: ba,a 1b lastlist: .word 0 .word 0 - . = _start + (0x200 - GRUB_BOOT_MACHINE_LIST_SIZE) + . = _start + (0x200 - GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE) blocklist_default_start: .word 0 .word 2 diff --git a/bus/bonito.c b/bus/bonito.c new file mode 100644 index 000000000..3f794c45a --- /dev/null +++ b/bus/bonito.c @@ -0,0 +1,90 @@ +/* bonito.c - PCI bonito interface. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include + +static grub_uint32_t base_win[GRUB_MACHINE_PCI_NUM_WIN]; +static const grub_size_t sizes_win[GRUB_MACHINE_PCI_NUM_WIN] = + {GRUB_MACHINE_PCI_WIN1_SIZE, GRUB_MACHINE_PCI_WIN_SIZE, + GRUB_MACHINE_PCI_WIN_SIZE}; +/* Usage counters. */ +static int usage_win[GRUB_MACHINE_PCI_NUM_WIN]; +static grub_addr_t addr_win[GRUB_MACHINE_PCI_NUM_WIN] = + {GRUB_MACHINE_PCI_WIN1_ADDR, GRUB_MACHINE_PCI_WIN2_ADDR, + GRUB_MACHINE_PCI_WIN3_ADDR}; + +static inline void +write_bases (void) +{ + int i; + grub_uint32_t reg = 0; + for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++) + reg |= (((base_win[i] >> GRUB_MACHINE_PCI_WIN_SHIFT) + & GRUB_MACHINE_PCI_WIN_MASK) + >> (i * GRUB_MACHINE_PCI_WIN_MASK_SIZE)); + GRUB_MACHINE_PCI_IO_CTRL_REG = reg; +} + +volatile void * +grub_pci_device_map_range (grub_pci_device_t dev __attribute__ ((unused)), + grub_addr_t base, grub_size_t size) +{ + int i; + grub_addr_t newbase; + + /* First try already used registers. */ + for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++) + if (usage_win[i] && base_win[i] <= base + && base_win[i] + sizes_win[i] > base + size) + { + usage_win[i]++; + return (void *) + (addr_win[i] | (base & GRUB_MACHINE_PCI_WIN_OFFSET_MASK)); + } + /* Map new register. */ + newbase = base & ~GRUB_MACHINE_PCI_WIN_OFFSET_MASK; + for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++) + if (!usage_win[i] && newbase <= base + && newbase + sizes_win[i] > base + size) + { + usage_win[i]++; + base_win[i] = newbase; + write_bases (); + return (void *) + (addr_win[i] | (base & GRUB_MACHINE_PCI_WIN_OFFSET_MASK)); + } + grub_fatal ("Out of PCI windows."); +} + +void +grub_pci_device_unmap_range (grub_pci_device_t dev __attribute__ ((unused)), + volatile void *mem __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ + int i; + for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++) + if (usage_win[i] && addr_win[i] + == (((grub_addr_t) mem) & ~GRUB_MACHINE_PCI_WIN_OFFSET_MASK)) + { + usage_win[i]--; + return; + } + grub_fatal ("Tried to unmap not mapped region"); +} diff --git a/bus/emu/pci.c b/bus/emu/pci.c new file mode 100644 index 000000000..420ae320b --- /dev/null +++ b/bus/emu/pci.c @@ -0,0 +1,76 @@ +/* pci.c - Generic PCI interfaces. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007,2009 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 . + */ + +#include +#include +#include + +grub_pci_address_t +grub_pci_make_address (grub_pci_device_t dev, int reg) +{ + grub_pci_address_t ret; + ret.dev = dev; + ret.pos = reg; + return ret; +} + +void +grub_pci_iterate (grub_pci_iteratefunc_t hook) +{ + struct pci_device_iterator *iter; + struct pci_slot_match slot; + struct pci_device *dev; + slot.domain = PCI_MATCH_ANY; + slot.bus = PCI_MATCH_ANY; + slot.dev = PCI_MATCH_ANY; + slot.func = PCI_MATCH_ANY; + iter = pci_slot_match_iterator_create (&slot); + while ((dev = pci_device_next (iter))) + hook (dev, dev->vendor_id | (dev->device_id << 16)); + pci_iterator_destroy (iter); +} + +void * +grub_pci_device_map_range (grub_pci_device_t dev, grub_addr_t base, + grub_size_t size) +{ + void *addr; + int err; + err = pci_device_map_range (dev, base, size, PCI_DEV_MAP_FLAG_WRITABLE, &addr); + if (err) + grub_util_error ("mapping 0x%x failed (error %d)\n", base, err); + return addr; +} + +void +grub_pci_device_unmap_range (grub_pci_device_t dev, void *mem, + grub_size_t size) +{ + pci_device_unmap_range (dev, mem, size); +} + +GRUB_MOD_INIT (pci) +{ + pci_system_init (); +} + +GRUB_MOD_FINI (pci) +{ + pci_system_cleanup (); +} diff --git a/bus/pci.c b/bus/pci.c index 2c29c03ab..a08e53446 100644 --- a/bus/pci.c +++ b/bus/pci.c @@ -1,7 +1,7 @@ /* pci.c - Generic PCI interfaces. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007 Free Software Foundation, Inc. + * Copyright (C) 2007,2009 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 @@ -21,41 +21,40 @@ #include grub_pci_address_t -grub_pci_make_address (int bus, int device, int function, int reg) +grub_pci_make_address (grub_pci_device_t dev, int reg) { - return (1 << 31) | (bus << 16) | (device << 11) | (function << 8) | (reg << 2); + return (1 << 31) | (dev.bus << 16) | (dev.device << 11) + | (dev.function << 8) | reg; } void grub_pci_iterate (grub_pci_iteratefunc_t hook) { - int bus; - int dev; - int func; + grub_pci_device_t dev; grub_pci_address_t addr; grub_pci_id_t id; grub_uint32_t hdr; - for (bus = 0; bus < 256; bus++) + for (dev.bus = 0; dev.bus < GRUB_PCI_NUM_BUS; dev.bus++) { - for (dev = 0; dev < 32; dev++) + for (dev.device = 0; dev.device < GRUB_PCI_NUM_DEVICES; dev.device++) { - for (func = 0; func < 8; func++) + for (dev.function = 0; dev.function < 8; dev.function++) { - addr = grub_pci_make_address (bus, dev, func, 0); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_PCI_ID); id = grub_pci_read (addr); /* Check if there is a device present. */ if (id >> 16 == 0xFFFF) continue; - if (hook (bus, dev, func, id)) + if (hook (dev, id)) return; /* Probe only func = 0 if the device if not multifunction */ - if (func == 0) + if (dev.function == 0) { - addr = grub_pci_make_address (bus, dev, func, 3); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CACHELINE); hdr = grub_pci_read (addr); if (!(hdr & 0x800000)) break; diff --git a/util/usb.c b/bus/usb/emu/usb.c similarity index 97% rename from util/usb.c rename to bus/usb/emu/usb.c index a687eea9b..187857b5b 100644 --- a/util/usb.c +++ b/bus/usb/emu/usb.c @@ -105,14 +105,14 @@ grub_usb_root_hub (grub_usb_controller_t controller __attribute__((unused))) grub_usb_err_t grub_usb_control_msg (grub_usb_device_t dev, grub_uint8_t reqtype, grub_uint8_t request, grub_uint16_t value, - grub_uint16_t index, grub_size_t size, char *data) + grub_uint16_t idx, grub_size_t size, char *data) { usb_dev_handle *devh; struct usb_device *d = dev->data; devh = usb_open (d); if (usb_control_msg (devh, reqtype, request, - value, index, data, size, 20) < 0) + value, idx, data, size, 20) < 0) { usb_close (devh); return GRUB_USB_ERR_STALL; diff --git a/bus/usb/ohci.c b/bus/usb/ohci.c index 32fb7cf91..6d185bc7f 100644 --- a/bus/usb/ohci.c +++ b/bus/usb/ohci.c @@ -113,7 +113,7 @@ grub_ohci_writereg32 (struct grub_ohci *o, /* Iterate over all PCI devices. Determine if a device is an OHCI controller. If this is the case, initialize it. */ static int NESTED_FUNC_ATTR -grub_ohci_pci_iter (int bus, int device, int func, +grub_ohci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__((unused))) { grub_uint32_t class_code; @@ -126,7 +126,7 @@ grub_ohci_pci_iter (int bus, int device, int func, grub_uint32_t revision; grub_uint32_t frame_interval; - addr = grub_pci_make_address (bus, device, func, 2); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); class_code = grub_pci_read (addr) >> 8; interf = class_code & 0xFF; @@ -138,7 +138,7 @@ grub_ohci_pci_iter (int bus, int device, int func, return 0; /* Determine IO base address. */ - addr = grub_pci_make_address (bus, device, func, 4); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); base = grub_pci_read (addr); #if 0 diff --git a/bus/usb/uhci.c b/bus/usb/uhci.c index 88ff5b3d8..947f2367b 100644 --- a/bus/usb/uhci.c +++ b/bus/usb/uhci.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -138,7 +137,7 @@ grub_uhci_portstatus (grub_usb_controller_t dev, /* Iterate over all PCI devices. Determine if a device is an UHCI controller. If this is the case, initialize it. */ static int NESTED_FUNC_ATTR -grub_uhci_pci_iter (int bus, int device, int func, +grub_uhci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__((unused))) { grub_uint32_t class_code; @@ -151,7 +150,7 @@ grub_uhci_pci_iter (int bus, int device, int func, struct grub_uhci *u; int i; - addr = grub_pci_make_address (bus, device, func, 2); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); class_code = grub_pci_read (addr) >> 8; interf = class_code & 0xFF; @@ -163,7 +162,7 @@ grub_uhci_pci_iter (int bus, int device, int func, return 0; /* Determine IO base address. */ - addr = grub_pci_make_address (bus, device, func, 8); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG4); base = grub_pci_read (addr); /* Stop if there is no IO space base address defined. */ if (! (base & 1)) @@ -435,6 +434,7 @@ grub_uhci_transfer (grub_usb_controller_t dev, grub_uhci_td_t td_prev = NULL; grub_usb_err_t err = GRUB_USB_ERR_NONE; int i; + grub_uint64_t endtime; /* Allocate a queue head for the transfer queue. */ qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL); @@ -483,6 +483,7 @@ grub_uhci_transfer (grub_usb_controller_t dev, /* Wait until either the transaction completed or an error occurred. */ + endtime = grub_get_time_ms () + 1000; for (;;) { grub_uhci_td_t errtd; @@ -534,6 +535,13 @@ grub_uhci_transfer (grub_usb_controller_t dev, updated. */ grub_dprintf ("uhci", "transaction fallthrough\n"); } + if (grub_get_time_ms () > endtime) + { + err = GRUB_USB_ERR_STALL; + grub_dprintf ("uhci", "transaction timed out\n"); + goto fail; + } + grub_cpu_idle (); } grub_dprintf ("uhci", "transaction complete\n"); @@ -573,6 +581,7 @@ grub_uhci_portstatus (grub_usb_controller_t dev, struct grub_uhci *u = (struct grub_uhci *) dev->data; int reg; unsigned int status; + grub_uint64_t endtime; grub_dprintf ("uhci", "enable=%d port=%d\n", enable, port); @@ -595,6 +604,7 @@ grub_uhci_portstatus (grub_usb_controller_t dev, status = grub_uhci_readreg16 (u, reg); grub_uhci_writereg16 (u, reg, status & ~(1 << 9)); grub_dprintf ("uhci", "reset completed\n"); + grub_millisleep (10); /* Enable the port. */ grub_uhci_writereg16 (u, reg, enable << 2); @@ -602,7 +612,10 @@ grub_uhci_portstatus (grub_usb_controller_t dev, grub_dprintf ("uhci", "waiting for the port to be enabled\n"); - while (! (grub_uhci_readreg16 (u, reg) & (1 << 2))); + endtime = grub_get_time_ms () + 1000; + while (! (grub_uhci_readreg16 (u, reg) & (1 << 2))) + if (grub_get_time_ms () > endtime) + return grub_error (GRUB_ERR_IO, "UHCI Timed out"); status = grub_uhci_readreg16 (u, reg); grub_dprintf ("uhci", ">3detect=0x%02x\n", status); diff --git a/bus/usb/usb.c b/bus/usb/usb.c index 310b8cc6a..8289185da 100644 --- a/bus/usb/usb.c +++ b/bus/usb/usb.c @@ -155,42 +155,6 @@ grub_usb_get_endpdescriptor (grub_usb_device_t usbdev, int addr) return NULL; } -grub_usb_err_t -grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid, - char **string) -{ - struct grub_usb_desc_str descstr; - struct grub_usb_desc_str *descstrp; - grub_usb_err_t err; - - /* Only get the length. */ - err = grub_usb_control_msg (dev, 1 << 7, - 0x06, (3 << 8) | index, - langid, 1, (char *) &descstr); - if (err) - return err; - - descstrp = grub_malloc (descstr.length); - if (! descstrp) - return GRUB_USB_ERR_INTERNAL; - err = grub_usb_control_msg (dev, 1 << 7, - 0x06, (3 << 8) | index, - langid, descstr.length, (char *) descstrp); - - *string = grub_malloc (descstr.length / 2); - if (! *string) - { - grub_free (descstrp); - return GRUB_USB_ERR_INTERNAL; - } - - grub_utf16_to_utf8 ((grub_uint8_t *) *string, descstrp->str, descstrp->length / 2 - 1); - (*string)[descstr.length / 2 - 1] = '\0'; - grub_free (descstrp); - - return GRUB_USB_ERR_NONE; -} - grub_usb_err_t grub_usb_device_initialize (grub_usb_device_t dev) { diff --git a/bus/usb/usbhub.c b/bus/usb/usbhub.c index 6881ce000..523abf93e 100644 --- a/bus/usb/usbhub.c +++ b/bus/usb/usbhub.c @@ -48,9 +48,9 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed) if (! grub_usb_devs[i]) break; } - if (grub_usb_devs[i]) + if (i == 128) { - grub_error (GRUB_ERR_IO, "Can't assign address to USB device"); + grub_error (GRUB_ERR_IO, "can't assign address to USB device"); return NULL; } @@ -60,6 +60,7 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed) | GRUB_USB_REQTYPE_TARGET_DEV), GRUB_USB_REQ_SET_ADDRESS, i, 0, 0, NULL); + dev->addr = i; dev->initialized = 1; grub_usb_devs[i] = dev; diff --git a/commands/acpi.c b/commands/acpi.c index 1a7bf8018..5bbfd008b 100644 --- a/commands/acpi.c +++ b/commands/acpi.c @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef GRUB_MACHINE_EFI #include @@ -36,23 +37,23 @@ static const struct grub_arg_option options[] = { {"exclude", 'x', 0, - "Don't load host tables specified by comma-separated list", + N_("Don't load host tables specified by comma-separated list."), 0, ARG_TYPE_STRING}, {"load-only", 'n', 0, - "Load only tables specified by comma-separated list", 0, ARG_TYPE_STRING}, - {"v1", '1', 0, "Expose v1 tables", 0, ARG_TYPE_NONE}, - {"v2", '2', 0, "Expose v2 and v3 tables", 0, ARG_TYPE_NONE}, - {"oemid", 'o', 0, "Set OEMID of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING}, + N_("Load only tables specified by comma-separated list."), 0, ARG_TYPE_STRING}, + {"v1", '1', 0, N_("Expose v1 tables."), 0, ARG_TYPE_NONE}, + {"v2", '2', 0, N_("Expose v2 and v3 tables."), 0, ARG_TYPE_NONE}, + {"oemid", 'o', 0, N_("Set OEMID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING}, {"oemtable", 't', 0, - "Set OEMTABLE ID of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING}, + N_("Set OEMTABLE ID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING}, {"oemtablerev", 'r', 0, - "Set OEMTABLE revision of RSDP, XSDT and RSDT", 0, ARG_TYPE_INT}, + N_("Set OEMTABLE revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT}, {"oemtablecreator", 'c', 0, - "Set creator field of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING}, + N_("Set creator field of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING}, {"oemtablecreatorrev", 'd', 0, - "Set creator revision of RSDP, XSDT and RSDT", 0, ARG_TYPE_INT}, - {"no-ebda", 'e', 0, "Don't update EBDA. May fix failures or hangs on some" - " BIOSes but makes it ineffective with OS not receiving RSDP from GRUB", + N_("Set creator revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT}, + {"no-ebda", 'e', 0, N_("Don't update EBDA. May fix failures or hangs on some." + " BIOSes but makes it ineffective with OS not receiving RSDP from GRUB."), 0, ARG_TYPE_NONE}, {0, 0, 0, 0, 0, 0} }; @@ -228,7 +229,7 @@ grub_acpi_create_ebda (void) sizeof (struct grub_acpi_rsdp_v10)) == 0) { grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10)); - grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target); + grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target); v1inebda = target; target += sizeof (struct grub_acpi_rsdp_v10); target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1); @@ -277,7 +278,7 @@ grub_acpi_create_ebda (void) { grub_mmap_unregister (mmapregion); return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Couldn't find suitable spot in EBDA"); + "couldn't find suitable spot in EBDA"); } /* Remove any other RSDT. */ @@ -551,7 +552,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd, grub_free (exclude); grub_free (load_only); return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Couldn't allocate table"); + "couldn't allocate table"); } grub_memcpy (table_dsdt, dsdt, dsdt->length); } @@ -578,7 +579,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd, grub_free (exclude); grub_free (load_only); return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Couldn't allocate table structure"); + "couldn't allocate table structure"); } table->size = curtable->length; table->addr = grub_malloc (table->size); @@ -587,7 +588,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd, { free_tables (); return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Couldn't allocate table"); + "couldn't allocate table"); } table->next = acpi_tables; acpi_tables = table; @@ -674,7 +675,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd, { free_tables (); return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Couldn't allocate table structure"); + "couldn't allocate table structure"); } table->size = size; @@ -709,7 +710,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd, { free_tables (); return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Couldn't allocate space for ACPI tables"); + "couldn't allocate space for ACPI tables"); } setup_common_tables (); @@ -759,11 +760,11 @@ GRUB_MOD_INIT(acpi) { cmd = grub_register_extcmd ("acpi", grub_cmd_acpi, GRUB_COMMAND_FLAG_BOTH, - "acpi [-1|-2] [--exclude=table1,table2|" - "--load-only=table1,table2] filename1 " - " [filename2] [...]", - "Load host acpi tables and tables " - "specified by arguments", + N_("[-1|-2] [--exclude=TABLE1,TABLE2|" + "--load-only=table1,table2] FILE1" + " [FILE2] [...]"), + N_("Load host ACPI tables and tables " + "specified by arguments."), options); } diff --git a/commands/blocklist.c b/commands/blocklist.c index b457b7c39..cace31113 100644 --- a/commands/blocklist.c +++ b/commands/blocklist.c @@ -24,6 +24,7 @@ #include #include #include +#include static grub_err_t grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)), @@ -87,10 +88,9 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)), if (! file->device->disk) return grub_error (GRUB_ERR_BAD_DEVICE, - "this command is available only for disk devices."); + "this command is available only for disk devices"); - if (file->device->disk->partition) - part_start = grub_partition_get_start (file->device->disk->partition); + part_start = grub_partition_get_start (file->device->disk->partition); file->read_hook = read_blocklist; @@ -110,7 +110,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(blocklist) { cmd = grub_register_command ("blocklist", grub_cmd_blocklist, - "blocklist FILE", "Print a block list."); + N_("FILE"), N_("Print a block list.")); } GRUB_MOD_FINI(blocklist) diff --git a/commands/boot.c b/commands/boot.c index e77b5ceb8..1ec1e6f77 100644 --- a/commands/boot.c +++ b/commands/boot.c @@ -23,6 +23,7 @@ #include #include #include +#include static grub_err_t (*grub_loader_boot_func) (void); static grub_err_t (*grub_loader_unload_func) (void); @@ -186,7 +187,7 @@ GRUB_MOD_INIT(boot) { cmd_boot = grub_register_command ("boot", grub_cmd_boot, - 0, "boot an operating system"); + 0, N_("Boot an operating system.")); } GRUB_MOD_FINI(boot) diff --git a/commands/cat.c b/commands/cat.c index 1a2374360..3bdafc4c6 100644 --- a/commands/cat.c +++ b/commands/cat.c @@ -24,6 +24,7 @@ #include #include #include +#include static grub_err_t grub_cmd_cat (grub_command_t cmd __attribute__ ((unused)), @@ -40,7 +41,7 @@ grub_cmd_cat (grub_command_t cmd __attribute__ ((unused)), file = grub_gzfile_open (args[0], 1); if (! file) - return 0; + return grub_errno; while ((size = grub_file_read (file, buf, sizeof (buf))) > 0 && key != GRUB_TERM_ESC) @@ -78,7 +79,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(cat) { cmd = grub_register_command_p1 ("cat", grub_cmd_cat, - "cat FILE", "Show the contents of a file."); + N_("FILE"), N_("Show the contents of a file.")); } GRUB_MOD_FINI(cat) diff --git a/commands/cmp.c b/commands/cmp.c index 1258b1d63..626e1d022 100644 --- a/commands/cmp.c +++ b/commands/cmp.c @@ -1,7 +1,7 @@ /* cmd.c - command to cmp an operating system */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2005,2006,2007 Free Software Foundation, Inc. + * Copyright (C) 2003,2005,2006,2007,2009 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 @@ -23,6 +23,7 @@ #include #include #include +#include #define BUFFER_SIZE 512 @@ -40,7 +41,7 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), if (argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments required"); - grub_printf ("Compare `%s' and `%s':\n", args[0], + grub_printf ("Compare file `%s' with `%s':\n", args[0], args[1]); file1 = grub_gzfile_open (args[0], 1); @@ -49,7 +50,7 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), goto cleanup; if (grub_file_size (file1) != grub_file_size (file2)) - grub_printf ("Differ in size: %llu [%s], %llu [%s]\n", + grub_printf ("Files differ in size: %llu [%s], %llu [%s]\n", (unsigned long long) grub_file_size (file1), args[0], (unsigned long long) grub_file_size (file2), args[1]); else @@ -76,7 +77,7 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), { if (buf1[i] != buf2[i]) { - grub_printf ("Differ at the offset %llu: 0x%x [%s], 0x%x [%s]\n", + grub_printf ("Files differ at the offset %llu: 0x%x [%s], 0x%x [%s]\n", (unsigned long long) (i + pos), buf1[i], args[0], buf2[i], args[1]); goto cleanup; @@ -109,7 +110,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(cmp) { cmd = grub_register_command ("cmp", grub_cmd_cmp, - "cmp FILE1 FILE2", "Compare two files."); + N_("FILE1 FILE2"), N_("Compare two files.")); } GRUB_MOD_FINI(cmp) diff --git a/commands/configfile.c b/commands/configfile.c index 852932216..469447711 100644 --- a/commands/configfile.c +++ b/commands/configfile.c @@ -22,6 +22,7 @@ #include #include #include +#include static grub_err_t grub_cmd_source (grub_command_t cmd, int argc, char **args) @@ -53,16 +54,16 @@ GRUB_MOD_INIT(configfile) { cmd_configfile = grub_register_command ("configfile", grub_cmd_source, - "configfile FILE", "Load another config file."); + N_("FILE"), N_("Load another config file.")); cmd_source = grub_register_command ("source", grub_cmd_source, - "source FILE", - "Load another config file without changing context." + N_("FILE"), + N_("Load another config file without changing context.") ); cmd_dot = grub_register_command (".", grub_cmd_source, - ". FILE", - "Load another config file without changing context." + N_("FILE"), + N_("Load another config file without changing context.") ); } diff --git a/commands/crc.c b/commands/crc.c index 6b4b1d1b5..1c1a690aa 100644 --- a/commands/crc.c +++ b/commands/crc.c @@ -1,7 +1,7 @@ /* crc.c - command to calculate the crc32 checksum of a file */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,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 @@ -23,6 +23,7 @@ #include #include #include +#include static grub_err_t grub_cmd_crc (grub_command_t cmd __attribute__ ((unused)), @@ -45,10 +46,13 @@ grub_cmd_crc (grub_command_t cmd __attribute__ ((unused)), while ((size = grub_file_read (file, buf, sizeof (buf))) > 0) crc = grub_getcrc32 (crc, buf, size); - grub_file_close (file); + if (grub_errno) + goto fail; grub_printf ("%08x\n", crc); + fail: + grub_file_close (file); return 0; } @@ -57,8 +61,8 @@ static grub_command_t cmd; GRUB_MOD_INIT(crc) { cmd = grub_register_command ("crc", grub_cmd_crc, - "crc FILE", - "Calculate the crc32 checksum of a file."); + N_("FILE"), + N_("Calculate the crc32 checksum of a file.")); } GRUB_MOD_FINI(crc) diff --git a/commands/date.c b/commands/date.c index 1d609642e..623db4943 100644 --- a/commands/date.c +++ b/commands/date.c @@ -22,6 +22,7 @@ #include #include #include +#include #define GRUB_DATETIME_SET_YEAR 1 #define GRUB_DATETIME_SET_MONTH 2 @@ -135,8 +136,8 @@ GRUB_MOD_INIT(date) { cmd = grub_register_command ("date", grub_cmd_date, - "date [[year-]month-day] [hour:minute[:second]]", - "Command to display/set current datetime."); + N_("[[year-]month-day] [hour:minute[:second]]"), + N_("Command to display/set current datetime.")); } GRUB_MOD_FINI(date) diff --git a/commands/echo.c b/commands/echo.c index 69aa3be3c..4fea091cb 100644 --- a/commands/echo.c +++ b/commands/echo.c @@ -20,11 +20,12 @@ #include #include #include +#include static const struct grub_arg_option options[] = { - {0, 'n', 0, "do not output the trailing newline", 0, 0}, - {0, 'e', 0, "enable interpretation of backslash escapes", 0, 0}, + {0, 'n', 0, N_("Do not output the trailing newline."), 0, 0}, + {0, 'e', 0, N_("Enable interpretation of backslash escapes."), 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -113,7 +114,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(echo) { cmd = grub_register_extcmd ("echo", grub_cmd_echo, GRUB_COMMAND_FLAG_BOTH, - "echo [-e|-n] STRING", "Display a line of text.", + N_("[-e|-n] STRING"), N_("Display a line of text."), options); } diff --git a/commands/efi/fixvideo.c b/commands/efi/fixvideo.c index f97d83787..6430be5e3 100644 --- a/commands/efi/fixvideo.c +++ b/commands/efi/fixvideo.c @@ -22,6 +22,7 @@ #include #include #include +#include static struct grub_video_patch { @@ -38,11 +39,11 @@ static struct grub_video_patch }; static int NESTED_FUNC_ATTR -scan_card (int bus, int dev, int func, grub_pci_id_t pciid) +scan_card (grub_pci_device_t dev, grub_pci_id_t pciid) { grub_pci_address_t addr; - addr = grub_pci_make_address (bus, dev, func, 2); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); if (grub_pci_read_byte (addr + 3) == 0x3) { struct grub_video_patch *p = video_patches; @@ -99,7 +100,7 @@ static grub_command_t cmd_fixvideo; GRUB_MOD_INIT(fixvideo) { cmd_fixvideo = grub_register_command ("fix_video", grub_cmd_fixvideo, - 0, "Fix video problem."); + 0, N_("Fix video problem.")); } diff --git a/commands/efi/loadbios.c b/commands/efi/loadbios.c index 9967bb122..8c7c25abd 100644 --- a/commands/efi/loadbios.c +++ b/commands/efi/loadbios.c @@ -23,6 +23,7 @@ #include #include #include +#include static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID; static grub_efi_guid_t acpi2_guid = GRUB_EFI_ACPI_20_TABLE_GUID; @@ -41,15 +42,17 @@ enable_rom_area (void) { grub_pci_address_t addr; grub_uint32_t *rom_ptr; + grub_pci_device_t dev = { .bus = 0, .device = 0, .function = 0}; rom_ptr = (grub_uint32_t *) VBIOS_ADDR; if (*rom_ptr != BLANK_MEM) { - grub_printf ("ROM image present.\n"); + grub_printf ("ROM image is present.\n"); return 0; } - addr = grub_pci_make_address (0, 0, 0, 36); + /* FIXME: should be macroified. */ + addr = grub_pci_make_address (dev, 144); grub_pci_write_byte (addr++, 0x30); grub_pci_write_byte (addr++, 0x33); grub_pci_write_byte (addr++, 0x33); @@ -62,7 +65,7 @@ enable_rom_area (void) *rom_ptr = 0; if (*rom_ptr != 0) { - grub_printf ("Can\'t enable rom area.\n"); + grub_printf ("Can\'t enable ROM area.\n"); return 0; } @@ -73,8 +76,10 @@ static void lock_rom_area (void) { grub_pci_address_t addr; + grub_pci_device_t dev = { .bus = 0, .device = 0, .function = 0}; - addr = grub_pci_make_address (0, 0, 0, 36); + /* FIXME: should be macroified. */ + addr = grub_pci_make_address (dev, 144); grub_pci_write_byte (addr++, 0x10); grub_pci_write_byte (addr++, 0x11); grub_pci_write_byte (addr++, 0x11); @@ -158,7 +163,7 @@ grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)), int size; if (argc == 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "No rom image specified"); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no ROM image specified"); if (argc > 1) { @@ -167,7 +172,7 @@ grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)), return grub_errno; if (file->size != 4) - grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid int10 dump size"); + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid int10 dump size"); else grub_file_read (file, (void *) 0x40, 4); @@ -182,7 +187,7 @@ grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)), size = file->size; if ((size < 0x10000) || (size > 0x40000)) - grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid bios dump size"); + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid bios dump size"); else if (enable_rom_area ()) { grub_file_read (file, (void *) VBIOS_ADDR, size); @@ -199,11 +204,11 @@ static grub_command_t cmd_fakebios, cmd_loadbios; GRUB_MOD_INIT(loadbios) { cmd_fakebios = grub_register_command ("fakebios", grub_cmd_fakebios, - 0, "fake bios."); + 0, N_("Fake BIOS.")); cmd_loadbios = grub_register_command ("loadbios", grub_cmd_loadbios, - "loadbios BIOS_DUMP [INT10_DUMP]", - "Load bios dump."); + "BIOS_DUMP [INT10_DUMP]", + N_("Load BIOS dump.")); } GRUB_MOD_FINI(loadbios) diff --git a/commands/gptsync.c b/commands/gptsync.c index a603746a2..d217b5d5c 100644 --- a/commands/gptsync.c +++ b/commands/gptsync.c @@ -27,6 +27,7 @@ #include #include #include +#include /* Convert a LBA address to a CHS address in the INT 13 format. */ /* Taken from grub1. */ @@ -240,13 +241,13 @@ GRUB_MOD_INIT(gptsync) { (void) mod; /* To stop warning. */ cmd = grub_register_command ("gptsync", grub_cmd_gptsync, - "gptsync DEVICE [PARTITION[+/-[TYPE]]] ...", - "Fill hybrid MBR of GPT drive DEVICE. " + N_("DEVICE [PARTITION[+/-[TYPE]]] ..."), + N_("Fill hybrid MBR of GPT drive DEVICE. " "specified partitions will be a part " "of hybrid mbr. Up to 3 partitions are " "allowed. TYPE is an MBR type. " "+ means that partition is active. " - "Only one partition can be active"); + "Only one partition can be active.")); } GRUB_MOD_FINI(gptsync) diff --git a/commands/halt.c b/commands/halt.c index 8fa8db5be..3400115a0 100644 --- a/commands/halt.c +++ b/commands/halt.c @@ -20,6 +20,7 @@ #include #include #include +#include static grub_err_t grub_cmd_halt (grub_command_t cmd __attribute__ ((unused)), @@ -35,8 +36,8 @@ static grub_command_t cmd; GRUB_MOD_INIT(halt) { cmd = grub_register_command ("halt", grub_cmd_halt, - 0, "halts the computer. This command does not" - " work on all firmware."); + 0, N_("Halts the computer. This command does" + " not work on all firmware implementations.")); } GRUB_MOD_FINI(halt) diff --git a/commands/handler.c b/commands/handler.c index 2070c391c..f9270972b 100644 --- a/commands/handler.c +++ b/commands/handler.c @@ -23,12 +23,12 @@ #include #include #include +#include static grub_err_t -grub_cmd_handler (struct grub_command *cmd, +grub_cmd_handler (struct grub_command *cmd __attribute__ ((unused)), int argc, char **args) { - char *class_name; void *curr_item = 0; grub_handler_class_t head; @@ -43,23 +43,19 @@ grub_cmd_handler (struct grub_command *cmd, return 0; } - class_name = (grub_strcmp (cmd->name, "handler")) ? (char *) cmd->name : 0; - head = grub_handler_class_list; - if ((argc == 0) && (class_name == 0)) + if (argc == 0) { grub_list_iterate (GRUB_AS_LIST (head), (grub_list_hook_t) list_item); } else { + char *class_name; grub_handler_class_t class; - if (class_name == 0) - { - class_name = args[0]; - argc--; - args++; - } + class_name = args[0]; + argc--; + args++; class = grub_named_list_find (GRUB_AS_NAMED_LIST (head), class_name); if (! class) @@ -89,27 +85,17 @@ grub_cmd_handler (struct grub_command *cmd, return 0; } -static grub_command_t cmd_handler, cmd_terminal_input, cmd_terminal_output; +static grub_command_t cmd_handler; GRUB_MOD_INIT(handler) { cmd_handler = grub_register_command ("handler", grub_cmd_handler, - "handler [class [handler]]", - "List or select a handler"); - cmd_terminal_input = - grub_register_command ("terminal_input", grub_cmd_handler, - "terminal_input [handler]", - "List or select a handler"); - cmd_terminal_output = - grub_register_command ("terminal_output", grub_cmd_handler, - "terminal_output [handler]", - "List or select a handler"); + N_("[class [handler]]"), + N_("List or select a handler.")); } GRUB_MOD_FINI(handler) { grub_unregister_command (cmd_handler); - grub_unregister_command (cmd_terminal_input); - grub_unregister_command (cmd_terminal_output); } diff --git a/commands/hashsum.c b/commands/hashsum.c new file mode 100644 index 000000000..d5f551dbb --- /dev/null +++ b/commands/hashsum.c @@ -0,0 +1,277 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct grub_arg_option options[] = { + {"hash", 'h', 0, N_("Specify hash to use."), N_("HASH"), ARG_TYPE_STRING}, + {"check", 'c', 0, N_("Check hash list file."), N_("FILE"), ARG_TYPE_STRING}, + {"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}, + {0, 0, 0, 0, 0, 0} +}; + +struct { const char *name; const char *hashname; } aliases[] = + { + {"sha256sum", "sha256"}, + {"sha512sum", "sha512"}, + {"md5sum", "md5"}, + }; + +static inline int +hextoval (char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +static grub_err_t +hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result) +{ + grub_uint8_t context[hash->contextsize]; + grub_uint8_t readbuf[4096]; + + grub_memset (context, 0, sizeof (context)); + hash->init (context); + while (1) + { + grub_ssize_t r; + r = grub_file_read (file, readbuf, sizeof (readbuf)); + if (r < 0) + return grub_errno; + if (r == 0) + break; + hash->write (context, readbuf, r); + } + hash->final (context); + grub_memcpy (result, hash->read (context), hash->mdlen); + + return GRUB_ERR_NONE; +} + +static grub_err_t +check_list (const gcry_md_spec_t *hash, const char *hashfilename, + const char *prefix, int keep) +{ + grub_file_t hashlist, file; + char *buf = NULL; + grub_uint8_t expected[hash->mdlen]; + grub_uint8_t actual[hash->mdlen]; + grub_err_t err; + unsigned i; + unsigned unread = 0, mismatch = 0; + + hashlist = grub_file_open (hashfilename); + if (!hashlist) + return grub_errno; + + while (grub_free (buf), (buf = grub_file_getline (hashlist))) + { + const char *p = buf; + for (i = 0; i < hash->mdlen; i++) + { + int high, low; + high = hextoval (*p++); + low = hextoval (*p++); + if (high < 0 || low < 0) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); + expected[i] = (high << 4) | low; + } + if (*p++ != ' ' || *p++ != ' ') + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); + if (prefix) + { + char *filename; + + filename = grub_xasprintf ("%s/%s", prefix, p); + if (!filename) + return grub_errno; + file = grub_file_open (filename); + grub_free (filename); + } + else + file = grub_file_open (p); + if (!file) + { + grub_file_close (hashlist); + grub_free (buf); + return grub_errno; + } + err = hash_file (file, hash, actual); + grub_file_close (file); + if (err) + { + grub_printf ("%s: READ ERROR\n", p); + if (!keep) + { + grub_file_close (hashlist); + grub_free (buf); + return err; + } + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + if (grub_crypto_memcmp (expected, actual, hash->mdlen) != 0) + { + grub_printf ("%s: HASH MISMATCH\n", p); + if (!keep) + { + grub_file_close (hashlist); + grub_free (buf); + return grub_error (GRUB_ERR_TEST_FAILURE, + "hash of '%s' mismatches", p); + } + mismatch++; + continue; + } + grub_printf ("%s: OK\n", p); + } + if (mismatch || unread) + return grub_error (GRUB_ERR_TEST_FAILURE, + "%d files couldn't be read and hash " + "of %d files mismatches", unread, mismatch); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_hashsum (struct grub_extcmd *cmd, + int argc, char **args) +{ + struct grub_arg_list *state = cmd->state; + const char *hashname = NULL; + const char *prefix = NULL; + const gcry_md_spec_t *hash; + unsigned i; + int keep = state[3].set; + unsigned unread = 0; + + for (i = 0; i < ARRAY_SIZE (aliases); i++) + if (grub_strcmp (cmd->cmd->name, aliases[i].name) == 0) + hashname = aliases[i].hashname; + if (state[0].set) + hashname = state[0].arg; + + if (!hashname) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no hash specified"); + + hash = grub_crypto_lookup_md_by_name (hashname); + if (!hash) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown hash"); + + if (state[2].set) + prefix = state[2].arg; + + if (state[1].set) + { + 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); + } + + for (i = 0; i < (unsigned) argc; i++) + { + grub_uint8_t result[hash->mdlen]; + grub_file_t file; + grub_err_t err; + unsigned j; + file = grub_file_open (args[i]); + if (!file) + { + if (!keep) + return grub_errno; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + err = hash_file (file, hash, result); + grub_file_close (file); + if (err) + { + if (!keep) + return err; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + for (j = 0; j < hash->mdlen; j++) + grub_printf ("%02x", result[j]); + grub_printf (" %s\n", args[i]); + } + + if (unread) + return grub_error (GRUB_ERR_TEST_FAILURE, "%d files couldn't be read.", + unread); + return GRUB_ERR_NONE; +} + +static grub_extcmd_t cmd, cmd_md5, cmd_sha256, cmd_sha512; + +GRUB_MOD_INIT(hashsum) +{ + cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + "hashsum -h HASH [-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]", + "Compute or check hash checksum.", + options); + cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + N_("[-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]"), + N_("Compute or check hash checksum."), + options); + cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + N_("[-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]"), + "Compute or check hash checksum.", + options); + cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + N_("[-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]"), + N_("Compute or check hash checksum."), + options); +} + +GRUB_MOD_FINI(hashsum) +{ + grub_unregister_extcmd (cmd); + grub_unregister_extcmd (cmd_md5); + grub_unregister_extcmd (cmd_sha256); + grub_unregister_extcmd (cmd_sha512); +} diff --git a/commands/hdparm.c b/commands/hdparm.c index 389954c45..a3f8bbff0 100644 --- a/commands/hdparm.c +++ b/commands/hdparm.c @@ -24,29 +24,30 @@ #include #include #include +#include static const struct grub_arg_option options[] = { - {"apm", 'B', 0, "set Advanced Power Management\n" - "(1=low, ..., 254=high, 255=off)", + {"apm", 'B', 0, N_("Set Advanced Power Management\n" + "(1=low, ..., 254=high, 255=off)."), 0, ARG_TYPE_INT}, - {"power", 'C', 0, "check power mode", 0, ARG_TYPE_NONE}, - {"security-freeze", 'F', 0, "freeze ATA security settings until reset", + {"power", 'C', 0, N_("Check power mode."), 0, ARG_TYPE_NONE}, + {"security-freeze", 'F', 0, N_("Freeze ATA security settings until reset."), 0, ARG_TYPE_NONE}, - {"health", 'H', 0, "check SMART health status", 0, ARG_TYPE_NONE}, - {"aam", 'M', 0, "set Automatic Acoustic Management\n" - "(0=off, 128=quiet, ..., 254=fast)", + {"health", 'H', 0, N_("Check SMART health status."), 0, ARG_TYPE_NONE}, + {"aam", 'M', 0, N_("Set Automatic Acoustic Management\n" + "(0=off, 128=quiet, ..., 254=fast)."), 0, ARG_TYPE_INT}, - {"standby-timeout", 'S', 0, "set standby timeout\n" - "(0=off, 1=5s, 2=10s, ..., 240=20m, 241=30m, ...)", + {"standby-timeout", 'S', 0, N_("Set standby timeout\n" + "(0=off, 1=5s, 2=10s, ..., 240=20m, 241=30m, ...)."), 0, ARG_TYPE_INT}, - {"standby", 'y', 0, "set drive to standby mode", 0, ARG_TYPE_NONE}, - {"sleep", 'Y', 0, "set drive to sleep mode", 0, ARG_TYPE_NONE}, - {"identify", 'i', 0, "print drive identity and settings", + {"standby", 'y', 0, N_("Set drive to standby mode."), 0, ARG_TYPE_NONE}, + {"sleep", 'Y', 0, N_("Set drive to sleep mode."), 0, ARG_TYPE_NONE}, + {"identify", 'i', 0, N_("Print drive identity and settings."), 0, ARG_TYPE_NONE}, - {"dumpid", 'I', 0, "dump contents of ATA IDENTIFY sector", + {"dumpid", 'I', 0, N_("Dump contents of ATA IDENTIFY sector."), 0, ARG_TYPE_NONE}, - {"smart", -1, 0, "disable/enable SMART (0/1)", 0, ARG_TYPE_INT}, - {"quiet", 'q', 0, "do not print messages", 0, ARG_TYPE_NONE}, + {"smart", -1, 0, N_("Disable/enable SMART (0/1)."), 0, ARG_TYPE_INT}, + {"quiet", 'q', 0, N_("Do not print messages."), 0, ARG_TYPE_NONE}, {0, 0, 0, 0, 0, 0} }; @@ -410,8 +411,8 @@ GRUB_MOD_INIT(hdparm) { cmd = grub_register_extcmd ("hdparm", grub_cmd_hdparm, GRUB_COMMAND_FLAG_BOTH, - "hdparm [OPTIONS] DISK", - "Get/set ATA disk parameters.", options); + N_("[OPTIONS] DISK"), + N_("Get/set ATA disk parameters."), options); } GRUB_MOD_FINI(hdparm) diff --git a/commands/help.c b/commands/help.c index c18ec6b83..c2aad03b2 100644 --- a/commands/help.c +++ b/commands/help.c @@ -1,7 +1,7 @@ /* help.c - command to show a help text. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2005,2007,2008,2009 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 @@ -21,6 +21,10 @@ #include #include #include +#include +#include +#include +#include static grub_err_t grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc, @@ -37,18 +41,49 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc, if ((cmd->prio & GRUB_PRIO_LIST_FLAG_ACTIVE) && (cmd->flags & GRUB_COMMAND_FLAG_CMDLINE)) { - char description[GRUB_TERM_WIDTH / 2]; - int desclen = grub_strlen (cmd->summary); + struct grub_term_output *term; + const char *summary_translated = _(cmd->summary); + char *command_help; + grub_uint32_t *unicode_command_help; + grub_uint32_t *unicode_last_position; + + command_help = grub_xasprintf ("%s %s", cmd->name, summary_translated); + if (!command_help) + return 1; - /* Make a string with a length of GRUB_TERM_WIDTH / 2 - 1 filled - with the description followed by spaces. */ - grub_memset (description, ' ', GRUB_TERM_WIDTH / 2 - 1); - description[GRUB_TERM_WIDTH / 2 - 1] = '\0'; - grub_memcpy (description, cmd->summary, - (desclen < GRUB_TERM_WIDTH / 2 - 1 - ? desclen : GRUB_TERM_WIDTH / 2 - 1)); + grub_utf8_to_ucs4_alloc (command_help, &unicode_command_help, + &unicode_last_position); - grub_printf ("%s%s", description, (cnt++) % 2 ? "\n" : " "); + FOR_ACTIVE_TERM_OUTPUTS(term) + { + unsigned stringwidth; + grub_uint32_t *unicode_last_screen_position; + + unicode_last_screen_position = unicode_command_help; + + stringwidth = 0; + + while (unicode_last_screen_position < unicode_last_position && + stringwidth < ((grub_term_width (term) / 2) - 2)) + { + stringwidth + += grub_term_getcharwidth (term, + *unicode_last_screen_position); + unicode_last_screen_position++; + } + + grub_print_ucs4 (unicode_command_help, + unicode_last_screen_position, term); + if (!(cnt % 2)) + grub_print_spaces (term, grub_term_width (term) / 2 + - stringwidth); + } + if (cnt % 2) + grub_printf ("\n"); + cnt++; + + grub_free (command_help); + grub_free (unicode_command_help); } return 0; } @@ -65,15 +100,19 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc, if (cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) grub_arg_show_help ((grub_extcmd_t) cmd->data); else - grub_printf ("Usage: %s\n%s\b", cmd->summary, - cmd->description); + grub_printf ("%s %s %s\n%s\n", _("Usage:"), cmd->name, _(cmd->summary), + _(cmd->description)); } } return 0; } if (argc == 0) - grub_command_iterate (print_command_info); + { + grub_command_iterate (print_command_info); + if (!(cnt % 2)) + grub_printf ("\n"); + } else { int i; @@ -94,8 +133,8 @@ GRUB_MOD_INIT(help) { cmd = grub_register_extcmd ("help", grub_cmd_help, GRUB_COMMAND_FLAG_CMDLINE, - "help [PATTERN ...]", - "Show a help message.", 0); + N_("[PATTERN ...]"), + N_("Show a help message."), 0); } GRUB_MOD_FINI(help) diff --git a/commands/hexdump.c b/commands/hexdump.c index 4b3e3ef29..c1d4ecba9 100644 --- a/commands/hexdump.c +++ b/commands/hexdump.c @@ -1,7 +1,7 @@ /* hexdump.c - command to dump the contents of a file or memory */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2007,2008,2009 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 @@ -24,11 +24,12 @@ #include #include #include +#include static const struct grub_arg_option options[] = { - {"skip", 's', 0, "skip offset bytes from the beginning of file.", 0, + {"skip", 's', 0, N_("Skip offset bytes from the beginning of file."), 0, ARG_TYPE_INT}, - {"length", 'n', 0, "read only length bytes", 0, ARG_TYPE_INT}, + {"length", 'n', 0, N_("Read only LENGTH bytes."), 0, ARG_TYPE_INT}, {0, 0, 0, 0, 0, 0} }; @@ -121,8 +122,8 @@ GRUB_MOD_INIT (hexdump) { cmd = grub_register_extcmd ("hexdump", grub_cmd_hexdump, GRUB_COMMAND_FLAG_BOTH, - "hexdump [OPTIONS] FILE_OR_DEVICE", - "Dump the contents of a file or memory.", + N_("[OPTIONS] FILE_OR_DEVICE"), + N_("Dump the contents of a file or memory."), options); } diff --git a/commands/i386/cmostest.c b/commands/i386/cmostest.c index 7171766cd..36c35e6c4 100644 --- a/commands/i386/cmostest.c +++ b/commands/i386/cmostest.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include static grub_err_t grub_cmd_cmostest (struct grub_command *cmd __attribute__ ((unused)), diff --git a/commands/i386/cpuid.c b/commands/i386/cpuid.c index a8bbfe69b..6eebf91a1 100644 --- a/commands/i386/cpuid.c +++ b/commands/i386/cpuid.c @@ -25,6 +25,7 @@ #include #include #include +#include #define cpuid(num,a,b,c,d) \ asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \ @@ -33,7 +34,7 @@ static const struct grub_arg_option options[] = { - {"long-mode", 'l', 0, "check for long mode flag (default)", 0, 0}, + {"long-mode", 'l', 0, N_("Check for long mode flag (default)."), 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -88,7 +89,7 @@ done: #endif cmd = grub_register_extcmd ("cpuid", grub_cmd_cpuid, GRUB_COMMAND_FLAG_BOTH, - "cpuid [-l]", "Check for CPU features", options); + "[-l]", N_("Check for CPU features."), options); } GRUB_MOD_FINI(cpuid) diff --git a/commands/i386/pc/drivemap.c b/commands/i386/pc/drivemap.c index 52424c3d1..4afc43358 100644 --- a/commands/i386/pc/drivemap.c +++ b/commands/i386/pc/drivemap.c @@ -26,6 +26,7 @@ #include #include #include +#include /* Real mode IVT slot (seg:off far pointer) for interrupt 0x13. */ @@ -33,9 +34,9 @@ static grub_uint32_t *const int13slot = UINT_TO_PTR (4 * 0x13); /* Remember to update enum opt_idxs accordingly. */ static const struct grub_arg_option options[] = { - {"list", 'l', 0, "show the current mappings", 0, 0}, - {"reset", 'r', 0, "reset all mappings to the default values", 0, 0}, - {"swap", 's', 0, "perform both direct and reverse mappings", 0, 0}, + {"list", 'l', 0, N_("Show the current mappings."), 0, 0}, + {"reset", 'r', 0, N_("Reset all mappings to the default values."), 0, 0}, + {"swap", 's', 0, N_("Perform both direct and reverse mappings."), 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -308,7 +309,7 @@ install_int13_handler (int noret __attribute__ ((unused))) GRUB_MACHINE_MEMORY_RESERVED, GRUB_MMAP_MALLOC_LOW); if (! handler_base) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not reserve " + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't reserve " "memory for the int13h handler"); /* Copy int13h handler bundle to reserved area. */ @@ -370,7 +371,7 @@ grub_get_root_biosnumber_drivemap (void) return grub_strtoul (biosnum, 0, 0); dev = grub_device_open (0); - if (dev && dev->disk && dev->disk->dev + if (dev && dev->disk && dev->disk->dev && dev->disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID) { drivemap_node_t *curnode = map_head; @@ -401,11 +402,10 @@ GRUB_MOD_INIT (drivemap) grub_get_root_biosnumber_saved = grub_get_root_biosnumber; grub_get_root_biosnumber = grub_get_root_biosnumber_drivemap; cmd = grub_register_extcmd ("drivemap", grub_cmd_drivemap, - GRUB_COMMAND_FLAG_BOTH, - "drivemap" - " -l | -r | [-s] grubdev osdisk", - "Manage the BIOS drive mappings", - options); + GRUB_COMMAND_FLAG_BOTH, + N_("-l | -r | [-s] grubdev osdisk."), + N_("Manage the BIOS drive mappings."), + options); drivemap_hook = grub_loader_register_preboot_hook (&install_int13_handler, &uninstall_int13_handler, diff --git a/commands/i386/pc/drivemap_int13h.S b/commands/i386/pc/drivemap_int13h.S index 440349685..b460cd7b5 100644 --- a/commands/i386/pc/drivemap_int13h.S +++ b/commands/i386/pc/drivemap_int13h.S @@ -19,7 +19,7 @@ #include -#define INT13H_OFFSET(x) ((x) - EXT_C(grub_drivemap_handler)) +#define INT13H_OFFSET(x) ((x) - LOCAL (base)) .code16 @@ -27,6 +27,7 @@ /* The replacement int13 handler. Preserve all registers. */ FUNCTION(grub_drivemap_handler) +LOCAL (base): /* Save %dx for future restore. */ push %dx /* Push flags. Used to simulate interrupt with original flags. */ @@ -35,12 +36,7 @@ FUNCTION(grub_drivemap_handler) /* Map the drive number (always in DL). */ push %ax push %bx -#ifdef APPLE_CC - grub_drivemap_mapstart_ofs = INT13H_OFFSET(EXT_C(grub_drivemap_mapstart)) - movw $grub_drivemap_mapstart_ofs, %bx -#else - movw $INT13H_OFFSET(EXT_C(grub_drivemap_mapstart)), %bx -#endif + movw $INT13H_OFFSET(LOCAL (mapstart)), %bx more_remaining: movw %cs:(%bx), %ax @@ -66,12 +62,7 @@ not_found: popf pushf -#ifdef APPLE_CC - grub_drivemap_oldhandler_ofs = INT13H_OFFSET (EXT_C (grub_drivemap_oldhandler)) - lcall *%cs:grub_drivemap_oldhandler_ofs -#else - lcall *%cs:INT13H_OFFSET (EXT_C (grub_drivemap_oldhandler)) -#endif + lcall *%cs:INT13H_OFFSET (LOCAL (oldhandler)) push %bp mov %sp, %bp @@ -94,11 +85,7 @@ norestore: popf pushf -#ifdef APPLE_CC - lcall *%cs:grub_drivemap_oldhandler_ofs -#else - lcall *%cs:INT13H_OFFSET (EXT_C (grub_drivemap_oldhandler)) -#endif + lcall *%cs:INT13H_OFFSET (LOCAL (oldhandler)) push %bp mov %sp, %bp @@ -111,9 +98,13 @@ norestore: /* Far pointer to the old handler. Stored as a CS:IP in the style of real-mode IVT entries (thus PI:SC in mem). */ VARIABLE(grub_drivemap_oldhandler) +LOCAL (oldhandler): .word 0x0, 0x0 /* This label MUST be at the end of the copied block, since the installer code reserves additional space for mappings at runtime and copies them over it. */ -.align 2 + .align 2 + VARIABLE(grub_drivemap_mapstart) +LOCAL (mapstart): + .byte 0 diff --git a/commands/i386/pc/halt.c b/commands/i386/pc/halt.c index 344dcecd8..4c39612ae 100644 --- a/commands/i386/pc/halt.c +++ b/commands/i386/pc/halt.c @@ -1,7 +1,7 @@ /* halt.c - command to halt the computer. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007 Free Software Foundation, Inc. + * Copyright (C) 2005,2007,2009 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 @@ -20,10 +20,11 @@ #include #include #include +#include static const struct grub_arg_option options[] = { - {"no-apm", 'n', 0, "do not use APM to halt the computer", 0, 0}, + {"no-apm", 'n', 0, N_("Do not use APM to halt the computer."), 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -46,8 +47,8 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(halt) { cmd = grub_register_extcmd ("halt", grub_cmd_halt, GRUB_COMMAND_FLAG_BOTH, - "halt [-n]", - "Halt the system, if possible using APM", + "[-n]", + N_("Halt the system, if possible using APM."), options); } diff --git a/commands/i386/pc/play.c b/commands/i386/pc/play.c index 23150ea1f..4ed937d4a 100644 --- a/commands/i386/pc/play.c +++ b/commands/i386/pc/play.c @@ -1,7 +1,7 @@ /* play.c - command to play a tune */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007 Free Software Foundation, Inc. + * Copyright (C) 2005,2007,2009 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 @@ -27,8 +27,9 @@ #include #include #include +#include -#define BASE_TEMPO 120 +#define BASE_TEMPO (60 * GRUB_TICKS_PER_SECOND) /* The speaker port. */ #define SPEAKER 0x61 @@ -100,13 +101,13 @@ #define PIT_CTRL_COUNT_BINARY 0x00 /* 16-bit binary counter. */ #define PIT_CTRL_COUNT_BCD 0x01 /* 4-decade BCD counter. */ -#define T_REST ((short) 0) -#define T_FINE ((short) -1) +#define T_REST ((grub_uint16_t) 0) +#define T_FINE ((grub_uint16_t) -1) struct note { - short pitch; - short duration; + grub_uint16_t pitch; + grub_uint16_t duration; }; static void @@ -119,7 +120,7 @@ beep_off (void) } static void -beep_on (short pitch) +beep_on (grub_uint16_t pitch) { unsigned char status; unsigned int counter; @@ -142,60 +143,115 @@ beep_on (short pitch) grub_outb (status | SPEAKER_TMR2 | SPEAKER_DATA, SPEAKER); } +/* Returns whether playing should continue. */ +static int +play (unsigned tempo, struct note *note) +{ + unsigned int to; + + if (note->pitch == T_FINE || grub_checkkey () >= 0) + return 1; + + grub_dprintf ("play", "pitch = %d, duration = %d\n", note->pitch, + note->duration); + + switch (note->pitch) + { + case T_REST: + beep_off (); + break; + + default: + beep_on (note->pitch); + break; + } + + to = grub_get_rtc () + BASE_TEMPO * note->duration / tempo; + while (((unsigned int) grub_get_rtc () <= to) && (grub_checkkey () < 0)) + ; + + return 0; +} + static grub_err_t grub_cmd_play (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { - grub_file_t file; - struct note buf; - int tempo; - unsigned int to; - if (argc != 1) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name or tempo and notes required"); - file = grub_file_open (args[0]); - if (! file) - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); - - if (grub_file_read (file, &tempo, sizeof(tempo)) != sizeof(tempo)) + if (argc == 1) { - grub_file_close (file); - return grub_error (GRUB_ERR_FILE_READ_ERROR, - "file doesn't even contains a full tempo record"); - } + struct note buf; + grub_uint32_t tempo; + grub_file_t file; - grub_dprintf ("play","tempo = %d\n", tempo); + file = grub_file_open (args[0]); - while (grub_file_read (file, &buf, - sizeof (struct note)) == sizeof (struct note) - && buf.pitch != T_FINE && grub_checkkey () < 0) - { + if (! file) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); - grub_dprintf ("play", "pitch = %d, duration = %d\n", buf.pitch, - buf.duration); - - switch (buf.pitch) + if (grub_file_read (file, &tempo, sizeof (tempo)) != sizeof (tempo)) { - case T_REST: - beep_off (); - break; + grub_file_close (file); + return grub_error (GRUB_ERR_FILE_READ_ERROR, + "file doesn't even contains a full tempo record"); + } - default: - beep_on (buf.pitch); + tempo = grub_le_to_cpu32 (tempo); + grub_dprintf ("play","tempo = %d\n", tempo); + + while (grub_file_read (file, &buf, + sizeof (struct note)) == sizeof (struct note)) + { + buf.pitch = grub_le_to_cpu16 (buf.pitch); + buf.duration = grub_le_to_cpu16 (buf.duration); + + if (play (tempo, &buf)) break; } - to = grub_get_rtc () + BASE_TEMPO * buf.duration / tempo; - while (((unsigned int) grub_get_rtc () <= to) && (grub_checkkey () < 0)) - ; + grub_file_close (file); + } + else + { + char *end; + unsigned tempo; + struct note note; + int i; + tempo = grub_strtoul (args[0], &end, 0); + + if (*end) + /* Was not a number either, assume it was supposed to be a file name. */ + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + + grub_dprintf ("play","tempo = %d\n", tempo); + + for (i = 1; i + 1 < argc; i += 2) + { + note.pitch = grub_strtoul (args[i], &end, 0); + if (*end) + { + grub_error (GRUB_ERR_BAD_NUMBER, "bogus pitch number"); + break; + } + + note.duration = grub_strtoul (args[i + 1], &end, 0); + if (*end) + { + grub_error (GRUB_ERR_BAD_NUMBER, "bogus duration number"); + break; + } + + if (play (tempo, ¬e)) + break; + } } beep_off (); - grub_file_close (file); - while (grub_checkkey () > 0) grub_getkey (); @@ -207,7 +263,8 @@ static grub_command_t cmd; GRUB_MOD_INIT(play) { cmd = grub_register_command ("play", grub_cmd_play, - "play FILE", "Play a tune"); + N_("FILE | TEMPO [PITCH1 DURATION1] [PITCH2 DURATION2] ... "), + N_("Play a tune.")); } GRUB_MOD_FINI(play) diff --git a/commands/i386/pc/pxecmd.c b/commands/i386/pc/pxecmd.c index df538704c..b576a8ea4 100644 --- a/commands/i386/pc/pxecmd.c +++ b/commands/i386/pc/pxecmd.c @@ -1,7 +1,7 @@ /* pxe.c - command to control the pxe driver */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 @@ -21,79 +21,32 @@ #include #include #include -#include - -static const struct grub_arg_option options[] = -{ - {"info", 'i', 0, "show PXE information.", 0, 0}, - {"bsize", 'b', 0, "set PXE block size", 0, ARG_TYPE_INT}, - {"unload", 'u', 0, "unload PXE stack.", 0, 0}, - {0, 0, 0, 0, 0, 0} - }; - -static void -print_ip (grub_uint32_t ip) -{ - int i; - - for (i = 0; i < 3; i++) - { - grub_printf ("%d.", ip & 0xFF); - ip >>= 8; - } - grub_printf ("%d", ip); -} +#include +#include static grub_err_t -grub_cmd_pxe (grub_extcmd_t cmd, int argc __attribute__ ((unused)), - char **args __attribute__ ((unused))) +grub_cmd_pxe_unload (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) { - struct grub_arg_list *state = cmd->state; - if (! grub_pxe_pxenv) return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no pxe environment"); - if (state[1].set) - { - int size; - - size = grub_strtoul (state[1].arg, 0, 0); - if (size < GRUB_PXE_MIN_BLKSIZE) - size = GRUB_PXE_MIN_BLKSIZE; - else if (size > GRUB_PXE_MAX_BLKSIZE) - size = GRUB_PXE_MAX_BLKSIZE; - - grub_pxe_blksize = size; - } - - if (state[0].set) - { - grub_printf ("blksize : %d\n", grub_pxe_blksize); - grub_printf ("client ip : "); - print_ip (grub_pxe_your_ip); - grub_printf ("\nserver ip : "); - print_ip (grub_pxe_server_ip); - grub_printf ("\ngateway ip : "); - print_ip (grub_pxe_gateway_ip); - grub_printf ("\n"); - } - - if (state[2].set) - grub_pxe_unload (); + grub_pxe_unload (); return 0; } -static grub_extcmd_t cmd; +static grub_command_t cmd; GRUB_MOD_INIT(pxecmd) { - cmd = grub_register_extcmd ("pxe", grub_cmd_pxe, GRUB_COMMAND_FLAG_BOTH, - "pxe [-i|-b|-u]", - "Command to control the PXE device.", options); + cmd = grub_register_command ("pxe_unload", grub_cmd_pxe_unload, + 0, + N_("Unload PXE environment.")); } GRUB_MOD_FINI(pxecmd) { - grub_unregister_extcmd (cmd); + grub_unregister_command (cmd); } diff --git a/commands/i386/pc/vbeinfo.c b/commands/i386/pc/vbeinfo.c index ee9f3c186..c266bbfcb 100644 --- a/commands/i386/pc/vbeinfo.c +++ b/commands/i386/pc/vbeinfo.c @@ -1,7 +1,7 @@ /* vbeinfo.c - command to list compatible VBE video modes. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2005,2007,2008,2009 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 @@ -24,6 +24,7 @@ #include #include #include +#include static void * real2pm (grub_vbe_farptr_t ptr) @@ -175,7 +176,7 @@ GRUB_MOD_INIT(vbeinfo) { cmd = grub_register_command ("vbeinfo", grub_cmd_vbeinfo, 0, - "List compatible VESA BIOS extension video modes."); + N_("List compatible VESA BIOS extension video modes.")); } GRUB_MOD_FINI(vbeinfo) diff --git a/commands/i386/pc/vbetest.c b/commands/i386/pc/vbetest.c index 314320d07..d2921c09d 100644 --- a/commands/i386/pc/vbetest.c +++ b/commands/i386/pc/vbetest.c @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include static grub_err_t grub_cmd_vbetest (grub_command_t cmd __attribute__ ((unused)), @@ -168,7 +170,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(vbetest) { cmd = grub_register_command ("vbetest", grub_cmd_vbetest, - 0, "Test VESA BIOS Extension 2.0+ support"); + 0, N_("Test VESA BIOS Extension 2.0+ support.")); } GRUB_MOD_FINI(vbetest) diff --git a/commands/ieee1275/suspend.c b/commands/ieee1275/suspend.c index 028dd3cd8..f096cc9ba 100644 --- a/commands/ieee1275/suspend.c +++ b/commands/ieee1275/suspend.c @@ -22,6 +22,7 @@ #include #include #include +#include static grub_err_t grub_cmd_suspend (grub_command_t cmd __attribute__ ((unused)), @@ -39,7 +40,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(ieee1275_suspend) { cmd = grub_register_command ("suspend", grub_cmd_suspend, - 0, "Return to Open Firmware prompt"); + 0, N_("Return to Open Firmware prompt.")); } GRUB_MOD_FINI(ieee1275_suspend) diff --git a/commands/iorw.c b/commands/iorw.c new file mode 100644 index 000000000..474c8712e --- /dev/null +++ b/commands/iorw.c @@ -0,0 +1,150 @@ +/* memrw.c - command to read / write physical memory */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include +#include +#include +#include +#include + +static grub_extcmd_t cmd_read_byte, cmd_read_word, cmd_read_dword; +static grub_command_t cmd_write_byte, cmd_write_word, cmd_write_dword; + +static const struct grub_arg_option options[] = + { + {0, 'v', 0, N_("Save read value into variable VARNAME."), + N_("VARNAME"), ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + + +static grub_err_t +grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) +{ + grub_target_addr_t addr; + grub_uint32_t value = 0; + char buf[sizeof ("XXXXXXXX")]; + + if (argc != 1) + 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]) + { + case 'l': + value = grub_inl (addr); + break; + + case 'w': + value = grub_inw (addr); + break; + + case 'b': + value = grub_inb (addr); + break; + } + + if (cmd->state[0].set) + { + grub_snprintf (buf, sizeof (buf), "%x", value); + grub_env_set (cmd->state[0].arg, buf); + } + else + grub_printf ("0x%x\n", value); + + return 0; +} + +static grub_err_t +grub_cmd_write (grub_command_t cmd, int argc, char **argv) +{ + grub_target_addr_t addr; + grub_uint32_t value; + grub_uint32_t mask = 0xffffffff; + + if (argc != 2 && argc != 3) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments"); + + addr = grub_strtoul (argv[0], 0, 0); + value = grub_strtoul (argv[1], 0, 0); + if (argc == 3) + mask = grub_strtoul (argv[2], 0, 0); + value &= mask; + switch (cmd->name[sizeof ("out") - 1]) + { + case 'l': + if (mask != 0xffffffff) + grub_outl ((grub_inl (addr) & ~mask) | value, addr); + else + grub_outl (value, addr); + break; + + case 'w': + if ((mask & 0xffff) != 0xffff) + grub_outw ((grub_inw (addr) & ~mask) | value, addr); + else + grub_outw (value, addr); + break; + + case 'b': + if ((mask & 0xff) != 0xff) + grub_outb ((grub_inb (addr) & ~mask) | value, addr); + else + grub_outb (value, addr); + break; + } + + return 0; +} + +GRUB_MOD_INIT(memrw) +{ + cmd_read_byte = + grub_register_extcmd ("inb", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + N_("PORT"), N_("Read byte from PORT."), options); + cmd_read_word = + grub_register_extcmd ("inw", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + N_("PORT"), N_("Read word from PORT."), options); + cmd_read_dword = + grub_register_extcmd ("inl", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + N_("PORT"), N_("Read dword from PORT."), options); + cmd_write_byte = + grub_register_command ("outb", grub_cmd_write, + N_("PORT VALUE [MASK]"), + N_("Write byte VALUE to PORT.")); + cmd_write_word = + grub_register_command ("outw", grub_cmd_write, + N_("PORT VALUE [MASK]"), + N_("Write word VALUE to PORT.")); + cmd_write_dword = + grub_register_command ("outl", grub_cmd_write, + N_("ADDR VALUE [MASK]"), + N_("Write dword VALUE to PORT.")); +} + +GRUB_MOD_FINI(memrw) +{ + grub_unregister_extcmd (cmd_read_byte); + grub_unregister_extcmd (cmd_read_word); + grub_unregister_extcmd (cmd_read_dword); + grub_unregister_command (cmd_write_byte); + grub_unregister_command (cmd_write_word); + grub_unregister_command (cmd_write_dword); +} diff --git a/commands/keystatus.c b/commands/keystatus.c index 28ceb2d0b..838792889 100644 --- a/commands/keystatus.c +++ b/commands/keystatus.c @@ -21,12 +21,13 @@ #include #include #include +#include static const struct grub_arg_option options[] = { - {"shift", 's', 0, "check Shift key", 0, 0}, - {"ctrl", 'c', 0, "check Control key", 0, 0}, - {"alt", 'a', 0, "check Alt key", 0, 0}, + {"shift", 's', 0, N_("Check Shift key."), 0, 0}, + {"ctrl", 'c', 0, N_("Check Control key."), 0, 0}, + {"alt", 'a', 0, N_("Check Alt key."), 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -48,13 +49,24 @@ grub_cmd_keystatus (grub_extcmd_t cmd, if (state[2].set) expect_mods |= GRUB_TERM_STATUS_ALT; + grub_dprintf ("keystatus", "expect_mods: %d\n", expect_mods); + /* Without arguments, just check whether getkeystatus is supported at all. */ - if (!grub_cur_term_input->getkeystatus) - return grub_error (GRUB_ERR_TEST_FAILURE, "false"); - grub_dprintf ("keystatus", "expect_mods: %d\n", expect_mods); - if (!expect_mods) - return 0; + if (expect_mods == 0) + { + grub_term_input_t term; + int nterms = 0; + + FOR_ACTIVE_TERM_INPUTS (term) + if (!term->getkeystatus) + return grub_error (GRUB_ERR_TEST_FAILURE, "false"); + else + nterms++; + if (!nterms) + return grub_error (GRUB_ERR_TEST_FAILURE, "false"); + return 0; + } mods = grub_getkeystatus (); grub_dprintf ("keystatus", "mods: %d\n", mods); @@ -70,8 +82,8 @@ GRUB_MOD_INIT(keystatus) { cmd = grub_register_extcmd ("keystatus", grub_cmd_keystatus, GRUB_COMMAND_FLAG_BOTH, - "keystatus [--shift] [--ctrl] [--alt]", - "Check key modifier status", + N_("[--shift] [--ctrl] [--alt]"), + N_("Check key modifier status."), options); } diff --git a/commands/loadenv.c b/commands/loadenv.c index c60eb835c..d763b2d5e 100644 --- a/commands/loadenv.c +++ b/commands/loadenv.c @@ -1,7 +1,7 @@ /* loadenv.c - command to load/save environment variable. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2008,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 @@ -26,10 +26,11 @@ #include #include #include +#include static const struct grub_arg_option options[] = { - {"file", 'f', 0, "specify filename", 0, ARG_TYPE_PATHNAME}, + {"file", 'f', 0, N_("Specify filename."), 0, ARG_TYPE_PATHNAME}, {0, 0, 0, 0, 0, 0} }; @@ -195,7 +196,7 @@ free_blocklists (struct blocklist *p) } } -static int +static grub_err_t check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, grub_file_t file) { @@ -218,8 +219,7 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, { /* This might be actually valid, but it is unbelievable that any filesystem makes such a silly allocation. */ - grub_error (GRUB_ERR_BAD_FS, "malformed file"); - return 0; + return grub_error (GRUB_ERR_BAD_FS, "malformed file"); } } @@ -229,17 +229,14 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, if (total_length != grub_file_size (file)) { /* Maybe sparse, unallocated sectors. No way in GRUB. */ - grub_error (GRUB_ERR_BAD_FILE_TYPE, "sparse file not allowed"); - return 0; + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "sparse file not allowed"); } /* One more sanity check. Re-read all sectors by blocklists, and compare those with the data read via a file. */ disk = file->device->disk; - if (disk->partition) - part_start = grub_partition_get_start (disk->partition); - else - part_start = 0; + + part_start = grub_partition_get_start (disk->partition); buf = grub_envblk_buffer (envblk); for (p = blocklists, index = 0; p; index += p->length, p = p->next) @@ -248,16 +245,13 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, if (grub_disk_read (disk, p->sector - part_start, p->offset, p->length, blockbuf)) - return 0; + return grub_errno; if (grub_memcmp (buf + index, blockbuf, p->length) != 0) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "invalid blocklist"); - return 0; - } + return grub_error (GRUB_ERR_FILE_READ_ERROR, "invalid blocklist"); } - return 1; + return GRUB_ERR_NONE; } static int @@ -272,10 +266,7 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, buf = grub_envblk_buffer (envblk); disk = file->device->disk; - if (disk->partition) - part_start = grub_partition_get_start (disk->partition); - else - part_start = 0; + part_start = grub_partition_get_start (disk->partition); index = 0; for (p = blocklists; p; index += p->length, p = p->next) @@ -328,7 +319,7 @@ grub_cmd_save_env (grub_extcmd_t cmd, int argc, char **args) } if (! argc) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "No variable is specified"); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no variable is specified"); file = open_envblk_file ((state[0].set) ? state[0].arg : 0); if (! file) @@ -346,7 +337,7 @@ grub_cmd_save_env (grub_extcmd_t cmd, int argc, char **args) if (! envblk) goto fail; - if (! check_blocklists (envblk, head, file)) + if (check_blocklists (envblk, head, file)) goto fail; while (argc) @@ -384,20 +375,20 @@ GRUB_MOD_INIT(loadenv) cmd_load = grub_register_extcmd ("load_env", grub_cmd_load_env, GRUB_COMMAND_FLAG_BOTH, - "load_env [-f FILE]", - "Load variables from environment block file.", + N_("[-f FILE]"), + N_("Load variables from environment block file."), options); cmd_list = grub_register_extcmd ("list_env", grub_cmd_list_env, GRUB_COMMAND_FLAG_BOTH, - "list_env [-f FILE]", - "List variables from environment block file.", + N_("[-f FILE]"), + N_("List variables from environment block file."), options); cmd_save = grub_register_extcmd ("save_env", grub_cmd_save_env, GRUB_COMMAND_FLAG_BOTH, - "save_env [-f FILE] variable_name [...]", - "Save variables to environment block file.", + N_("[-f FILE] variable_name [...]"), + N_("Save variables to environment block file."), options); } diff --git a/commands/ls.c b/commands/ls.c index 15b4c6bab..eb1049617 100644 --- a/commands/ls.c +++ b/commands/ls.c @@ -1,7 +1,7 @@ /* ls.c - command to list files and devices */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2003,2005,2007,2008,2009 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 @@ -30,12 +30,13 @@ #include #include #include +#include static const struct grub_arg_option options[] = { - {"long", 'l', 0, "show a long list with more detailed information", 0, 0}, - {"human-readable", 'h', 0, "print sizes in a human readable format", 0, 0}, - {"all", 'a', 0, "list all files", 0, 0}, + {"long", 'l', 0, N_("Show a long list with more detailed information."), 0, 0}, + {"human-readable", 'h', 0, N_("Print sizes in a human readable format."), 0, 0}, + {"all", 'a', 0, N_("List all files."), 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -86,19 +87,21 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) int print_files_long (const char *filename, const struct grub_dirhook_info *info) { - char pathname[grub_strlen (dirname) + grub_strlen (filename) + 1]; - if ((! all) && (filename[0] == '.')) return 0; if (! info->dir) { grub_file_t file; + char *pathname; if (dirname[grub_strlen (dirname) - 1] == '/') - grub_sprintf (pathname, "%s%s", dirname, filename); + pathname = grub_xasprintf ("%s%s", dirname, filename); else - grub_sprintf (pathname, "%s/%s", dirname, filename); + pathname = grub_xasprintf ("%s/%s", dirname, filename); + + if (!pathname) + return 1; /* XXX: For ext2fs symlinks are detected as files while they should be reported as directories. */ @@ -106,6 +109,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) if (! file) { grub_errno = 0; + grub_free (pathname); return 0; } @@ -130,8 +134,9 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) grub_uint32_t whole, fraction; whole = grub_divmod64 (fsize, 100, &fraction); - grub_sprintf (buf, "%u.%02u%c", whole, fraction, - grub_human_sizes[units]); + grub_snprintf (buf, sizeof (buf), + "%u.%02u%c", whole, fraction, + grub_human_sizes[units]); grub_printf ("%-12s", buf); } else @@ -139,6 +144,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) } grub_file_close (file); + grub_free (pathname); } else grub_printf ("%-12s", "DIR"); @@ -260,8 +266,8 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(ls) { cmd = grub_register_extcmd ("ls", grub_cmd_ls, GRUB_COMMAND_FLAG_BOTH, - "ls [-l|-h|-a] [FILE]", - "List devices and files.", options); + N_("[-l|-h|-a] [FILE]"), + N_("List devices and files."), options); } GRUB_MOD_FINI(ls) diff --git a/commands/lsmmap.c b/commands/lsmmap.c index 09f141ea0..2755df9c4 100644 --- a/commands/lsmmap.c +++ b/commands/lsmmap.c @@ -16,10 +16,13 @@ * along with GRUB. If not, see . */ +#ifndef GRUB_MACHINE_EMU #include +#endif #include #include #include +#include static grub_err_t grub_cmd_lsmmap (grub_command_t cmd __attribute__ ((unused)), @@ -33,7 +36,9 @@ grub_cmd_lsmmap (grub_command_t cmd __attribute__ ((unused)), (long long) addr, (long long) size, type); return 0; } +#ifndef GRUB_MACHINE_EMU grub_machine_mmap_iterate (hook); +#endif return 0; } @@ -43,7 +48,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(lsmmap) { cmd = grub_register_command ("lsmmap", grub_cmd_lsmmap, - 0, "List memory map provided by firmware."); + 0, N_("List memory map provided by firmware.")); } GRUB_MOD_FINI(lsmmap) diff --git a/commands/lspci.c b/commands/lspci.c index 5b3360a37..a69bb35ad 100644 --- a/commands/lspci.c +++ b/commands/lspci.c @@ -20,7 +20,8 @@ #include #include #include -#include +#include +#include struct grub_pci_classname { @@ -84,6 +85,7 @@ static const struct grub_pci_classname grub_pci_classes[] = { 11, 0x30, "MIPS Processor" }, { 11, 0x40, "Co-Processor" }, { 11, 0x80, "Unknown Processor" }, + { 12, 3, "USB Controller" }, { 12, 0x80, "Serial Bus Controller" }, { 13, 0x80, "Wireless Controller" }, { 14, 0, "I2O" }, @@ -114,16 +116,26 @@ grub_pci_get_class (int class, int subclass) return 0; } +static const struct grub_arg_option options[] = + { + {"iospace", 'i', 0, "show I/O spaces", 0, 0}, + {0, 0, 0, 0, 0, 0} + }; + +static int iospace; + static int NESTED_FUNC_ATTR -grub_lspci_iter (int bus, int dev, int func, grub_pci_id_t pciid) +grub_lspci_iter (grub_pci_device_t dev, grub_pci_id_t pciid) { grub_uint32_t class; const char *sclass; grub_pci_address_t addr; + int reg; - grub_printf ("%02x:%02x.%x %04x:%04x", bus, dev, func, pciid & 0xFFFF, - pciid >> 16); - addr = grub_pci_make_address (bus, dev, func, 2); + grub_printf ("%02x:%02x.%x %04x:%04x", grub_pci_get_bus (dev), + grub_pci_get_device (dev), grub_pci_get_function (dev), + pciid & 0xFFFF, pciid >> 16); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); class = grub_pci_read (addr); /* Lookup the class name, if there isn't a specific one, @@ -142,27 +154,81 @@ grub_lspci_iter (int bus, int dev, int func, grub_pci_id_t pciid) grub_printf ("\n"); + if (iospace) + { + reg = GRUB_PCI_REG_ADDRESSES; + while (reg < GRUB_PCI_REG_CIS_POINTER) + { + grub_uint64_t space; + addr = grub_pci_make_address (dev, reg); + space = grub_pci_read (addr); + + reg += sizeof (grub_uint32_t); + + if (space == 0) + continue; + + switch (space & GRUB_PCI_ADDR_SPACE_MASK) + { + case GRUB_PCI_ADDR_SPACE_IO: + grub_printf ("\tIO space %d at 0x%llx\n", + (unsigned) ((reg - GRUB_PCI_REG_ADDRESSES) + / sizeof (grub_uint32_t)) - 1, + (unsigned long long) + (space & GRUB_PCI_ADDR_IO_MASK)); + break; + case GRUB_PCI_ADDR_SPACE_MEMORY: + if ((space & GRUB_PCI_ADDR_MEM_TYPE_MASK) + == GRUB_PCI_ADDR_MEM_TYPE_64) + { + addr = grub_pci_make_address (dev, reg); + space |= ((grub_uint64_t) grub_pci_read (addr)) << 32; + reg += sizeof (grub_uint32_t); + grub_printf ("\t64-bit memory space %d at 0x%016llx [%s]\n", + (unsigned) ((reg - GRUB_PCI_REG_ADDRESSES) + / sizeof (grub_uint32_t)) - 2, + (unsigned long long) + (space & GRUB_PCI_ADDR_MEM_MASK), + space & GRUB_PCI_ADDR_MEM_PREFETCH + ? "prefetchable" : "non-prefetchable"); + + } + else + grub_printf ("\t32-bit memory space %d at 0x%016llx [%s]\n", + (unsigned) ((reg - GRUB_PCI_REG_ADDRESSES) + / sizeof (grub_uint32_t)) - 1, + (unsigned long long) + (space & GRUB_PCI_ADDR_MEM_MASK), + space & GRUB_PCI_ADDR_MEM_PREFETCH + ? "prefetchable" : "non-prefetchable"); + break; + } + } + } + + return 0; } static grub_err_t -grub_cmd_lspci (grub_command_t cmd __attribute__ ((unused)), +grub_cmd_lspci (grub_extcmd_t cmd, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { + iospace = cmd->state[0].set; grub_pci_iterate (grub_lspci_iter); return GRUB_ERR_NONE; } -static grub_command_t cmd; +static grub_extcmd_t cmd; -GRUB_MOD_INIT(pci) +GRUB_MOD_INIT(lspci) { - cmd = grub_register_command ("lspci", grub_cmd_lspci, - 0, "List PCI devices"); + cmd = grub_register_extcmd ("lspci", grub_cmd_lspci, GRUB_COMMAND_FLAG_BOTH, + "[-i]", N_("List PCI devices."), options); } -GRUB_MOD_FINI(pci) +GRUB_MOD_FINI(lspci) { - grub_unregister_command (cmd); + grub_unregister_extcmd (cmd); } diff --git a/commands/memrw.c b/commands/memrw.c index adffb7fc8..6a4d43be2 100644 --- a/commands/memrw.c +++ b/commands/memrw.c @@ -19,29 +19,54 @@ #include #include -#include +#include +#include +#include -static grub_command_t cmd_read_byte, cmd_read_word, cmd_read_dword; +static grub_extcmd_t cmd_read_byte, cmd_read_word, cmd_read_dword; static grub_command_t cmd_write_byte, cmd_write_word, cmd_write_dword; +static const struct grub_arg_option options[] = + { + {0, 'v', 0, N_("Save read value into variable VARNAME."), + "VARNAME", ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + + static grub_err_t -grub_cmd_read (grub_command_t cmd, int argc, char **argv) +grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) { grub_target_addr_t addr; - grub_uint32_t value; + grub_uint32_t value = 0; + char buf[sizeof ("XXXXXXXX")]; if (argc != 1) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments"); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid number of arguments"); addr = grub_strtoul (argv[0], 0, 0); - if (cmd->name[5] == 'd') - value = *((grub_uint32_t *) addr); - else if (cmd->name[5] == 'w') - value = *((grub_uint16_t *) addr); - else - value = *((grub_uint8_t *) addr); + switch (cmd->cmd->name[sizeof ("read_") - 1]) + { + case 'd': + value = *((volatile grub_uint32_t *) addr); + break; - grub_printf ("0x%x\n", value); + case 'w': + value = *((volatile grub_uint16_t *) addr); + break; + + case 'b': + value = *((volatile grub_uint8_t *) addr); + break; + } + + if (cmd->state[0].set) + { + grub_snprintf (buf, sizeof (buf), "%x", value); + grub_env_set (cmd->state[0].arg, buf); + } + else + grub_printf ("0x%x\n", value); return 0; } @@ -51,18 +76,42 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) { grub_target_addr_t addr; grub_uint32_t value; + grub_uint32_t mask = 0xffffffff; - if (argc != 2) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments"); + if (argc != 2 && argc != 3) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid number of arguments"); addr = grub_strtoul (argv[0], 0, 0); value = grub_strtoul (argv[1], 0, 0); - if (cmd->name[6] == 'd') - *((grub_uint32_t *) addr) = value; - else if (cmd->name[6] == 'w') - *((grub_uint16_t *) addr) = (grub_uint16_t) value; - else - *((grub_uint8_t *) addr) = (grub_uint8_t) value; + if (argc == 3) + mask = grub_strtoul (argv[2], 0, 0); + value &= mask; + switch (cmd->name[sizeof ("write_") - 1]) + { + case 'd': + if (mask != 0xffffffff) + *((volatile grub_uint32_t *) addr) + = (*((volatile grub_uint32_t *) addr) & ~mask) | value; + else + *((volatile grub_uint32_t *) addr) = value; + break; + + case 'w': + if ((mask & 0xffff) != 0xffff) + *((volatile grub_uint16_t *) addr) + = (*((volatile grub_uint16_t *) addr) & ~mask) | value; + else + *((volatile grub_uint16_t *) addr) = value; + break; + + case 'b': + if ((mask & 0xff) != 0xff) + *((volatile grub_uint8_t *) addr) + = (*((volatile grub_uint8_t *) addr) & ~mask) | value; + else + *((volatile grub_uint8_t *) addr) = value; + break; + } return 0; } @@ -70,30 +119,30 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) GRUB_MOD_INIT(memrw) { cmd_read_byte = - grub_register_command ("read_byte", grub_cmd_read, - "read_byte ADDR", "read byte."); + grub_register_extcmd ("read_byte", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + N_("ADDR"), N_("Read byte from ADDR."), options); cmd_read_word = - grub_register_command ("read_word", grub_cmd_read, - "read_word ADDR", "read word."); + grub_register_extcmd ("read_word", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + N_("ADDR"), N_("Read word from ADDR."), options); cmd_read_dword = - grub_register_command ("read_dword", grub_cmd_read, - "read_dword ADDR", "read dword."); + grub_register_extcmd ("read_dword", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + N_("ADDR"), N_("Read dword from ADDR."), options); cmd_write_byte = grub_register_command ("write_byte", grub_cmd_write, - "write_byte ADDR VALUE", "write byte."); + N_("ADDR VALUE [MASK]"), N_("Write byte VALUE to ADDR.")); cmd_write_word = grub_register_command ("write_word", grub_cmd_write, - "write_word ADDR VALUE", "write word."); + N_("ADDR VALUE [MASK]"), N_("Write word VALUE to ADDR.")); cmd_write_dword = grub_register_command ("write_dword", grub_cmd_write, - "write_dword ADDR VALUE", "write dword."); + N_("ADDR VALUE [MASK]"), N_("Write dword VALUE to ADDR.")); } GRUB_MOD_FINI(memrw) { - grub_unregister_command (cmd_read_byte); - grub_unregister_command (cmd_read_word); - grub_unregister_command (cmd_read_dword); + grub_unregister_extcmd (cmd_read_byte); + grub_unregister_extcmd (cmd_read_word); + grub_unregister_extcmd (cmd_read_dword); grub_unregister_command (cmd_write_byte); grub_unregister_command (cmd_write_word); grub_unregister_command (cmd_write_dword); diff --git a/commands/minicmd.c b/commands/minicmd.c index 6c9c33a0e..4ea9efead 100644 --- a/commands/minicmd.c +++ b/commands/minicmd.c @@ -27,6 +27,7 @@ #include #include #include +#include /* cat FILE */ static grub_err_t @@ -315,7 +316,6 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)), grub_printf ("%s", dep->mod->name); } grub_putchar ('\n'); - grub_refresh (); return 0; } @@ -354,28 +354,28 @@ GRUB_MOD_INIT(minicmd) { cmd_cat = grub_register_command ("cat", grub_mini_cmd_cat, - "cat FILE", "show the contents of a file"); + N_("FILE"), N_("Show the contents of a file.")); cmd_help = grub_register_command ("help", grub_mini_cmd_help, - 0, "show this message"); + 0, N_("Show this message.")); cmd_root = grub_register_command ("root", grub_mini_cmd_root, - "root [DEVICE]", "set the root device"); + N_("[DEVICE]"), N_("Set the root device.")); cmd_dump = grub_register_command ("dump", grub_mini_cmd_dump, - "dump ADDR", "dump memory"); + N_("ADDR"), N_("Dump memory.")); cmd_rmmod = grub_register_command ("rmmod", grub_mini_cmd_rmmod, - "rmmod MODULE", "remove a module"); + N_("MODULE"), N_("Remove a module.")); cmd_lsmod = grub_register_command ("lsmod", grub_mini_cmd_lsmod, - 0, "show loaded modules"); + 0, N_("Show loaded modules.")); cmd_exit = grub_register_command ("exit", grub_mini_cmd_exit, - 0, "exit from GRUB"); + 0, N_("Exit from GRUB.")); cmd_clear = grub_register_command ("clear", grub_mini_cmd_clear, - 0, "clear the screen"); + 0, N_("Clear the screen.")); } GRUB_MOD_FINI(minicmd) diff --git a/commands/parttool.c b/commands/parttool.c index 8c985fc4b..528cf43d7 100644 --- a/commands/parttool.c +++ b/commands/parttool.c @@ -29,14 +29,15 @@ #include #include #include +#include static struct grub_parttool *parts = 0; static int curhandle = 0; static grub_dl_t mymod; static char helpmsg[] = - "perform COMMANDS on partition.\n" + "Perform COMMANDS on partition.\n" "Use \"parttool PARTITION help\" for the list " - "of available commands"; + "of available commands."; int grub_parttool_register(const char *part_name, @@ -174,7 +175,7 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)), } /* Load modules. */ -#ifndef GRUB_UTIL +#if !GRUB_NO_MODULES { const char *prefix; prefix = grub_env_get ("prefix"); @@ -182,12 +183,11 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)), { char *filename; - filename = grub_malloc (grub_strlen (prefix) + sizeof ("/parttool.lst")); + filename = grub_xasprintf ("%s/parttool.lst", prefix); if (filename) { grub_file_t file; - grub_sprintf (filename, "%s/parttool.lst", prefix); file = grub_file_open (filename); if (file) { @@ -322,7 +322,7 @@ GRUB_MOD_INIT(parttool) { mymod = mod; cmd = grub_register_command ("parttool", grub_cmd_parttool, - "parttool PARTITION COMMANDS", + N_("PARTITION COMMANDS"), helpmsg); } diff --git a/commands/password.c b/commands/password.c index 0e048797e..04285254e 100644 --- a/commands/password.c +++ b/commands/password.c @@ -17,27 +17,22 @@ */ #include +#include #include #include #include #include #include #include +#include static grub_dl_t my_mod; static grub_err_t -check_password (const char *user, +check_password (const char *user, const char *entered, void *password) { - char entered[1024]; - - grub_memset (entered, 0, sizeof (entered)); - - if (!GRUB_GET_PASSWORD (entered, sizeof (entered) - 1)) - return GRUB_ACCESS_DENIED; - - if (grub_auth_strcmp (entered, password) != 0) + if (grub_crypto_memcmp (entered, password, GRUB_AUTH_MAX_PASSLEN) != 0) return GRUB_ACCESS_DENIED; grub_auth_authenticate (user); @@ -51,13 +46,18 @@ grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), { grub_err_t err; char *pass; + int copylen; if (argc != 2) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected."); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments expected"); - pass = grub_strdup (args[1]); + pass = grub_zalloc (GRUB_AUTH_MAX_PASSLEN); if (!pass) return grub_errno; + copylen = grub_strlen (args[1]); + if (copylen >= GRUB_AUTH_MAX_PASSLEN) + copylen = GRUB_AUTH_MAX_PASSLEN - 1; + grub_memcpy (pass, args[1], copylen); err = grub_auth_register_authentication (args[0], check_password, pass); if (err) @@ -75,9 +75,9 @@ GRUB_MOD_INIT(password) { my_mod = mod; cmd = grub_register_command ("password", grub_cmd_password, - "password USER PASSWORD", - "Set user password (plaintext). " - "Unrecommended and insecure."); + N_("USER PASSWORD"), + N_("Set user password (plaintext). " + "Unrecommended and insecure.")); } GRUB_MOD_FINI(password) diff --git a/commands/password_pbkdf2.c b/commands/password_pbkdf2.c new file mode 100644 index 000000000..6886987da --- /dev/null +++ b/commands/password_pbkdf2.c @@ -0,0 +1,197 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_dl_t my_mod; + +struct pbkdf2_password +{ + grub_uint8_t *salt; + grub_size_t saltlen; + unsigned int c; + grub_uint8_t *expected; + grub_size_t buflen; +}; + +static grub_err_t +check_password (const char *user, const char *entered, void *pin) +{ + grub_uint8_t *buf; + struct pbkdf2_password *pass = pin; + gcry_err_code_t err; + + buf = grub_malloc (pass->buflen); + if (!buf) + return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY); + + err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, (grub_uint8_t *) entered, + grub_strlen (entered), + pass->salt, pass->saltlen, pass->c, + buf, pass->buflen); + if (err) + { + grub_free (buf); + return grub_crypto_gcry_error (err); + } + + if (grub_crypto_memcmp (buf, pass->expected, pass->buflen) != 0) + return GRUB_ACCESS_DENIED; + + grub_auth_authenticate (user); + + return GRUB_ERR_NONE; +} + +static inline int +hex2val (char hex) +{ + if ('0' <= hex && hex <= '9') + return hex - '0'; + if ('a' <= hex && hex <= 'f') + return hex - 'a' + 10; + if ('A' <= hex && hex <= 'F') + return hex - 'A' + 10; + return -1; +} + +static grub_err_t +grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_err_t err; + char *ptr, *ptr2; + grub_uint8_t *ptro; + struct pbkdf2_password *pass; + + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected."); + + if (grub_memcmp (args[1], "grub.pbkdf2.sha512.", + sizeof ("grub.pbkdf2.sha512.") - 1) != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); + + ptr = args[1] + sizeof ("grub.pbkdf2.sha512.") - 1; + + pass = grub_malloc (sizeof (*pass)); + if (!pass) + return grub_errno; + + pass->c = grub_strtoul (ptr, &ptr, 0); + if (*ptr != '.') + { + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); + } + ptr++; + + ptr2 = grub_strchr (ptr, '.'); + if (!ptr2 || ((ptr2 - ptr) & 1) || grub_strlen (ptr2 + 1) & 1) + { + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); + } + + pass->saltlen = (ptr2 - ptr) >> 1; + pass->buflen = grub_strlen (ptr2 + 1) >> 1; + ptro = pass->salt = grub_malloc (pass->saltlen); + if (!ptro) + { + grub_free (pass); + return grub_errno; + } + while (ptr < ptr2) + { + int hex1, hex2; + hex1 = hex2val (*ptr); + ptr++; + hex2 = hex2val (*ptr); + ptr++; + if (hex1 < 0 || hex2 < 0) + { + grub_free (pass->salt); + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Incorrect PBKDF2 password."); + } + + *ptro = (hex1 << 4) | hex2; + ptro++; + } + + ptro = pass->expected = grub_malloc (pass->buflen); + if (!ptro) + { + grub_free (pass->salt); + grub_free (pass); + return grub_errno; + } + ptr = ptr2 + 1; + ptr2 += grub_strlen (ptr2); + while (ptr < ptr2) + { + int hex1, hex2; + hex1 = hex2val (*ptr); + ptr++; + hex2 = hex2val (*ptr); + ptr++; + if (hex1 < 0 || hex2 < 0) + { + grub_free (pass->expected); + grub_free (pass->salt); + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Incorrect PBKDF2 password."); + } + + *ptro = (hex1 << 4) | hex2; + ptro++; + } + + err = grub_auth_register_authentication (args[0], check_password, pass); + if (err) + { + grub_free (pass); + return err; + } + grub_dl_ref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(password_pbkdf2) +{ + my_mod = mod; + cmd = grub_register_command ("password_pbkdf2", grub_cmd_password, + N_("USER PBKDF2_PASSWORD"), + N_("Set user password (PBKDF2). ")); +} + +GRUB_MOD_FINI(password_pbkdf2) +{ + grub_unregister_command (cmd); +} diff --git a/commands/probe.c b/commands/probe.c index fabdb2a4a..c2cc599e9 100644 --- a/commands/probe.c +++ b/commands/probe.c @@ -30,16 +30,17 @@ #include #include #include +#include -static const struct grub_arg_option options[] = +static const struct grub_arg_option options[] = { {"set", 's', GRUB_ARG_OPTION_OPTIONAL, - "set a variable to return value", "VAR", ARG_TYPE_STRING}, - {"driver", 'd', 0, "determine driver", 0, 0}, - {"partmap", 'p', 0, "determine partition map type", 0, 0}, - {"fs", 'f', 0, "determine filesystem type", 0, 0}, - {"fs-uuid", 'u', 0, "determine filesystem UUID", 0, 0}, - {"label", 'l', 0, "determine filesystem label", 0, 0}, + N_("Set a variable to return value."), "VAR", ARG_TYPE_STRING}, + {"driver", 'd', 0, N_("Determine driver."), 0, 0}, + {"partmap", 'p', 0, N_("Determine partition map type."), 0, 0}, + {"fs", 'f', 0, N_("Determine filesystem type."), 0, 0}, + {"fs-uuid", 'u', 0, N_("Determine filesystem UUID."), 0, 0}, + {"label", 'l', 0, N_("Determine filesystem label."), 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -150,8 +151,8 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT (probe) { cmd = grub_register_extcmd ("probe", grub_cmd_probe, GRUB_COMMAND_FLAG_BOTH, - "probe [DEVICE]", - "Retrieve device info.", options); + N_("[DEVICE]"), + N_("Retrieve device info."), options); } GRUB_MOD_FINI (probe) diff --git a/commands/read.c b/commands/read.c index 82b30b461..8a7c4a01f 100644 --- a/commands/read.c +++ b/commands/read.c @@ -24,6 +24,7 @@ #include #include #include +#include static char * grub_getline (void) @@ -62,7 +63,7 @@ grub_getline (void) } static grub_err_t -grub_cmd_read (grub_command_t cmd UNUSED, int argc, char **args) +grub_cmd_read (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { char *line = grub_getline (); if (! line) @@ -79,8 +80,8 @@ static grub_command_t cmd; GRUB_MOD_INIT(read) { cmd = grub_register_command ("read", grub_cmd_read, - "read [ENVVAR]", - "Set variable with user input"); + N_("[ENVVAR]"), + N_("Set variable with user input.")); } GRUB_MOD_FINI(read) diff --git a/commands/reboot.c b/commands/reboot.c index 86c9e2dd9..eedd53c91 100644 --- a/commands/reboot.c +++ b/commands/reboot.c @@ -20,6 +20,7 @@ #include #include #include +#include static grub_err_t grub_cmd_reboot (grub_command_t cmd __attribute__ ((unused)), @@ -35,7 +36,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(reboot) { cmd = grub_register_command ("reboot", grub_cmd_reboot, - 0, "Reboot the computer"); + 0, N_("Reboot the computer.")); } GRUB_MOD_FINI(reboot) diff --git a/commands/regexp.c b/commands/regexp.c new file mode 100644 index 000000000..e8e8243b5 --- /dev/null +++ b/commands/regexp.c @@ -0,0 +1,80 @@ +/* regexp.c -- The regexp command. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2007 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 . + */ + +#include +#include +#include +#include +#include +#include + +static grub_err_t +grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), + 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; + + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "2 arguments expected"); + + ret = regcomp (®ex, args[0], RE_SYNTAX_GNU_AWK); + if (ret) + goto fail; + + ret = regexec (®ex, args[1], 0, 0, 0); + if (!ret) + { + regfree (®ex); + return GRUB_ERR_NONE; + } + + fail: + s = regerror (ret, ®ex, 0, 0); + comperr = grub_malloc (s); + if (!comperr) + { + regfree (®ex); + return grub_errno; + } + regerror (ret, ®ex, comperr, s); + err = grub_error (GRUB_ERR_TEST_FAILURE, "%s", comperr); + regfree (®ex); + grub_free (comperr); + return err; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(regexp) +{ + cmd = grub_register_command ("regexp", grub_cmd_regexp, + N_("REGEXP STRING"), + N_("Test if REGEXP matches STRING.")); +} + +GRUB_MOD_FINI(regexp) +{ + grub_unregister_command (cmd); +} diff --git a/commands/search.c b/commands/search.c index 0cfd0ebbc..71267b117 100644 --- a/commands/search.c +++ b/commands/search.c @@ -25,32 +25,14 @@ #include #include #include -#include +#include +#include +#include -static const struct grub_arg_option options[] = - { - {"file", 'f', 0, "search devices by a file", 0, 0}, - {"label", 'l', 0, "search devices by a filesystem label", 0, 0}, - {"fs-uuid", 'u', 0, "search devices by a filesystem UUID", 0, 0}, - {"set", 's', GRUB_ARG_OPTION_OPTIONAL, "set a variable to the first device found", "VAR", ARG_TYPE_STRING}, - {"no-floppy", 'n', 0, "do not probe any floppy drive", 0, 0}, - {0, 0, 0, 0, 0, 0} - }; - -enum options - { - SEARCH_FILE, - SEARCH_LABEL, - SEARCH_FS_UUID, - SEARCH_SET, - SEARCH_NO_FLOPPY, - }; - -static void -search_fs (const char *key, const char *var, int no_floppy, enum options type) +void +FUNC_NAME (const char *key, const char *var, int no_floppy) { int count = 0; - char *buf = NULL; grub_fs_autoload_hook_t saved_autoload; auto int iterate_device (const char *name); @@ -63,48 +45,46 @@ search_fs (const char *key, const char *var, int no_floppy, enum options type) name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') return 0; - if (type == SEARCH_FILE) +#ifdef DO_SEARCH_FILE { - grub_size_t len; - char *p; + char *buf; grub_file_t file; - len = grub_strlen (name) + 2 + grub_strlen (key) + 1; - p = grub_realloc (buf, len); - if (! p) + buf = grub_xasprintf ("(%s)%s", name, key); + if (! buf) return 1; - buf = p; - grub_sprintf (buf, "(%s)%s", name, key); - file = grub_file_open (buf); if (file) { found = 1; grub_file_close (file); } + grub_free (buf); } - else +#else { - /* type is SEARCH_FS_UUID or SEARCH_LABEL */ + /* SEARCH_FS_UUID or SEARCH_LABEL */ grub_device_t dev; grub_fs_t fs; - int (*compare_fn) (const char *, const char *); char *quid; dev = grub_device_open (name); if (dev) { fs = grub_fs_probe (dev); - compare_fn = - (type == SEARCH_FS_UUID) ? grub_strcasecmp : grub_strcmp; - if (fs && ((type == SEARCH_FS_UUID) ? fs->uuid : fs->label)) +#ifdef DO_SEARCH_FS_UUID +#define compare_fn grub_strcasecmp +#define read_fn uuid +#else +#define compare_fn grub_strcmp +#define read_fn label +#endif + + if (fs && fs->read_fn) { - if (type == SEARCH_FS_UUID) - fs->uuid (dev, &quid); - else - fs->label (dev, &quid); + fs->read_fn (dev, &quid); if (grub_errno == GRUB_ERR_NONE && quid) { @@ -118,6 +98,7 @@ search_fs (const char *key, const char *var, int no_floppy, enum options type) grub_device_close (dev); } } +#endif if (found) { @@ -149,52 +130,45 @@ search_fs (const char *key, const char *var, int no_floppy, enum options type) else grub_device_iterate (iterate_device); - grub_free (buf); - if (grub_errno == GRUB_ERR_NONE && count == 0) grub_error (GRUB_ERR_FILE_NOT_FOUND, "no such device: %s", key); } static grub_err_t -grub_cmd_search (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_do_search (grub_command_t cmd __attribute__ ((unused)), int argc, + char **args) { - struct grub_arg_list *state = cmd->state; - const char *var = 0; - if (argc == 0) - return grub_error (GRUB_ERR_INVALID_COMMAND, "no argument specified"); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no argument specified"); - if (state[SEARCH_SET].set) - var = state[SEARCH_SET].arg ? state[SEARCH_SET].arg : "root"; - - if (state[SEARCH_LABEL].set) - search_fs (args[0], var, state[SEARCH_NO_FLOPPY].set, SEARCH_LABEL); - else if (state[SEARCH_FS_UUID].set) - search_fs (args[0], var, state[SEARCH_NO_FLOPPY].set, SEARCH_FS_UUID); - else if (state[SEARCH_FILE].set) - search_fs (args[0], var, state[SEARCH_NO_FLOPPY].set, SEARCH_FILE); - else - return grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type"); + FUNC_NAME (args[0], argc == 1 ? 0 : args[1], 0); return grub_errno; } -static grub_extcmd_t cmd; +static grub_command_t cmd; -GRUB_MOD_INIT(search) +#ifdef DO_SEARCH_FILE +GRUB_MOD_INIT(search_fs_file) +#elif defined (DO_SEARCH_FS_UUID) +GRUB_MOD_INIT(search_fs_uuid) +#else +GRUB_MOD_INIT(search_label) +#endif { cmd = - grub_register_extcmd ("search", grub_cmd_search, - GRUB_COMMAND_FLAG_BOTH, - "search [-f|-l|-u|-s|-n] NAME", - "Search devices by file, filesystem label or filesystem UUID." - " If --set is specified, the first device found is" - " set to a variable. If no variable name is" - " specified, \"root\" is used.", - options); + grub_register_command (COMMAND_NAME, grub_cmd_do_search, + N_("NAME [VARIABLE]"), + HELP_MESSAGE); } -GRUB_MOD_FINI(search) +#ifdef DO_SEARCH_FILE +GRUB_MOD_FINI(search_fs_file) +#elif defined (DO_SEARCH_FS_UUID) +GRUB_MOD_FINI(search_fs_uuid) +#else +GRUB_MOD_FINI(search_label) +#endif { - grub_unregister_extcmd (cmd); + grub_unregister_command (cmd); } diff --git a/commands/search_file.c b/commands/search_file.c new file mode 100644 index 000000000..73ce89ccc --- /dev/null +++ b/commands/search_file.c @@ -0,0 +1,6 @@ +#define DO_SEARCH_FILE 1 +#define FUNC_NAME grub_search_fs_file +#define COMMAND_NAME "search.file" +#define SEARCH_TARGET "file" +#define HELP_MESSAGE N_("Search devices by file. If VARIABLE is specified, the first device found is set to a variable.") +#include "search.c" diff --git a/commands/search_label.c b/commands/search_label.c new file mode 100644 index 000000000..ee9c792be --- /dev/null +++ b/commands/search_label.c @@ -0,0 +1,6 @@ +#define DO_SEARCH_FS_LABEL 1 +#define FUNC_NAME grub_search_label +#define COMMAND_NAME "search.fs_label" +#define SEARCH_TARGET "filesystem label" +#define HELP_MESSAGE N_("Search devices by label. If VARIABLE is specified, the first device found is set to a variable.") +#include "search.c" diff --git a/commands/search_uuid.c b/commands/search_uuid.c new file mode 100644 index 000000000..52f83812c --- /dev/null +++ b/commands/search_uuid.c @@ -0,0 +1,6 @@ +#define DO_SEARCH_FS_UUID 1 +#define FUNC_NAME grub_search_fs_uuid +#define COMMAND_NAME "search.fs_uuid" +#define SEARCH_TARGET "filesystem UUID" +#define HELP_MESSAGE N_("Search devices by UUID. If VARIABLE is specified, the first device found is set to a variable.") +#include "search.c" diff --git a/commands/search_wrap.c b/commands/search_wrap.c new file mode 100644 index 000000000..2891d85d7 --- /dev/null +++ b/commands/search_wrap.c @@ -0,0 +1,95 @@ +/* search.c - search devices based on a file or a filesystem label */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2007,2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct grub_arg_option options[] = + { + {"file", 'f', 0, N_("Search devices by a file."), 0, 0}, + {"label", 'l', 0, N_("Search devices by a filesystem label."), + 0, 0}, + {"fs-uuid", 'u', 0, N_("Search devices by a filesystem UUID."), + 0, 0}, + {"set", 's', GRUB_ARG_OPTION_OPTIONAL, + N_("Set a variable to the first device found."), "VAR", ARG_TYPE_STRING}, + {"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0}, + {0, 0, 0, 0, 0, 0} + }; + +enum options + { + SEARCH_FILE, + SEARCH_LABEL, + SEARCH_FS_UUID, + SEARCH_SET, + SEARCH_NO_FLOPPY, + }; + +static grub_err_t +grub_cmd_search (grub_extcmd_t cmd, int argc, char **args) +{ + struct grub_arg_list *state = cmd->state; + const char *var = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no argument specified"); + + if (state[SEARCH_SET].set) + var = state[SEARCH_SET].arg ? state[SEARCH_SET].arg : "root"; + + if (state[SEARCH_LABEL].set) + grub_search_label (args[0], var, state[SEARCH_NO_FLOPPY].set); + else if (state[SEARCH_FS_UUID].set) + grub_search_fs_uuid (args[0], var, state[SEARCH_NO_FLOPPY].set); + else if (state[SEARCH_FILE].set) + grub_search_fs_file (args[0], var, state[SEARCH_NO_FLOPPY].set); + else + return grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type"); + + return grub_errno; +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(search) +{ + cmd = + grub_register_extcmd ("search", grub_cmd_search, + GRUB_COMMAND_FLAG_BOTH, + N_("search [-f|-l|-u|-s|-n] NAME"), + N_("Search devices by file, filesystem label" + " or filesystem UUID." + " If --set is specified, the first device found is" + " set to a variable. If no variable name is" + " specified, \"root\" is used."), + options); +} + +GRUB_MOD_FINI(search) +{ + grub_unregister_extcmd (cmd); +} diff --git a/commands/setpci.c b/commands/setpci.c new file mode 100644 index 000000000..fbc7c214e --- /dev/null +++ b/commands/setpci.c @@ -0,0 +1,341 @@ +/* lspci.c - List PCI devices. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008, 2009 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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +struct pci_register +{ + const char *name; + grub_uint16_t addr; + unsigned size; +}; + +struct pci_register pci_registers[] = + { + {"VENDOR_ID", GRUB_PCI_REG_VENDOR , 2}, + {"DEVICE_ID", GRUB_PCI_REG_DEVICE , 2}, + {"COMMAND", GRUB_PCI_REG_COMMAND , 2}, + {"STATUS", GRUB_PCI_REG_STATUS , 2}, + {"REVISION", GRUB_PCI_REG_REVISION , 1}, + {"CLASS_PROG", GRUB_PCI_REG_CLASS + 1 , 1}, + {"CLASS_DEVICE", GRUB_PCI_REG_CLASS + 2 , 2}, + {"CACHE_LINE_SIZE", GRUB_PCI_REG_CACHELINE , 1}, + {"LATENCY_TIMER", GRUB_PCI_REG_LAT_TIMER , 1}, + {"HEADER_TYPE", GRUB_PCI_REG_HEADER_TYPE , 1}, + {"BIST", GRUB_PCI_REG_BIST , 1}, + {"BASE_ADDRESS_0", GRUB_PCI_REG_ADDRESS_REG0, 4}, + {"BASE_ADDRESS_1", GRUB_PCI_REG_ADDRESS_REG1, 4}, + {"BASE_ADDRESS_2", GRUB_PCI_REG_ADDRESS_REG2, 4}, + {"BASE_ADDRESS_3", GRUB_PCI_REG_ADDRESS_REG3, 4}, + {"BASE_ADDRESS_4", GRUB_PCI_REG_ADDRESS_REG4, 4}, + {"BASE_ADDRESS_5", GRUB_PCI_REG_ADDRESS_REG5, 4}, + {"CARDBUS_CIS", GRUB_PCI_REG_CIS_POINTER , 4}, + {"SUBVENDOR_ID", GRUB_PCI_REG_SUBVENDOR , 2}, + {"SUBSYSTEM_ID", GRUB_PCI_REG_SUBSYSTEM , 2}, + {"ROM_ADDRESS", GRUB_PCI_REG_ROM_ADDRESS , 4}, + {"CAP_POINTER", GRUB_PCI_REG_CAP_POINTER , 1}, + {"INTERRUPT_LINE", GRUB_PCI_REG_IRQ_LINE , 1}, + {"INTERRUPT_PIN", GRUB_PCI_REG_IRQ_PIN , 1}, + {"MIN_GNT", GRUB_PCI_REG_MIN_GNT , 1}, + {"MAX_LAT", GRUB_PCI_REG_MIN_GNT , 1}, + }; + +static const struct grub_arg_option options[] = + { + {0, 'd', 0, "Select device by vendor and device IDs.", + "[vendor]:[device]", ARG_TYPE_STRING}, + {0, 's', 0, "Select device by its position on the bus.", + "[bus]:[slot][.func]", ARG_TYPE_STRING}, + {0, 'v', 0, "Save read value into variable VARNAME.", + "VARNAME", ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +static grub_uint32_t pciid_check_mask, pciid_check_value; +static int bus, device, function; +static int check_bus, check_device, check_function; +static grub_uint32_t write_mask, regwrite; +static int regsize; +static grub_uint16_t regaddr; +static const char *varname; + +static int NESTED_FUNC_ATTR +grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid) +{ + grub_uint32_t regval = 0; + grub_pci_address_t addr; + + if ((pciid & pciid_check_mask) != pciid_check_value) + return 0; + + if (check_bus && grub_pci_get_bus (dev) != bus) + return 0; + + if (check_device && grub_pci_get_device (dev) != device) + return 0; + + if (check_function && grub_pci_get_function (dev) != device) + return 0; + + addr = grub_pci_make_address (dev, regaddr); + + switch (regsize) + { + case 1: + regval = grub_pci_read_byte (addr); + break; + + case 2: + regval = grub_pci_read_word (addr); + break; + + case 4: + regval = grub_pci_read (addr); + break; + } + + if (varname) + { + char buf[sizeof ("XXXXXXXX")]; + grub_snprintf (buf, sizeof (buf), "%x", regval); + grub_env_set (varname, buf); + return 1; + } + + if (!write_mask) + { + grub_printf ("Register %x of %d:%d.%d is %x\n", regaddr, + grub_pci_get_bus (dev), + grub_pci_get_device (dev), + grub_pci_get_function (dev), + regval); + return 0; + } + + regval = (regval & ~write_mask) | regwrite; + + switch (regsize) + { + case 1: + grub_pci_write_byte (addr, regval); + break; + + case 2: + grub_pci_write_word (addr, regval); + break; + + case 4: + grub_pci_write (addr, regval); + break; + } + + return 0; +} + +static grub_err_t +grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv) +{ + const char *ptr; + unsigned i; + + pciid_check_value = 0; + pciid_check_mask = 0; + + if (cmd->state[0].set) + { + ptr = cmd->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; + } + else + pciid_check_mask |= 0xffff; + if (grub_errno) + return grub_errno; + if (*ptr != ':') + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Colon expected."); + ptr++; + pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff) + << 16; + if (grub_errno == GRUB_ERR_BAD_NUMBER) + grub_errno = GRUB_ERR_NONE; + else + pciid_check_mask |= 0xffff0000; + } + + pciid_check_value &= pciid_check_mask; + + check_bus = check_device = check_function = 0; + + if (cmd->state[1].set) + { + const char *optr; + + ptr = cmd->state[1].arg; + optr = ptr; + bus = grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno == GRUB_ERR_BAD_NUMBER) + { + grub_errno = GRUB_ERR_NONE; + ptr = optr; + } + else + check_bus = 1; + if (grub_errno) + return grub_errno; + if (*ptr != ':') + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Colon expected."); + ptr++; + optr = ptr; + device = grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno == GRUB_ERR_BAD_NUMBER) + { + grub_errno = GRUB_ERR_NONE; + ptr = optr; + } + else + check_device = 1; + if (*ptr == '.') + { + ptr++; + function = grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + return grub_errno; + check_function = 1; + } + } + + if (cmd->state[2].set) + varname = cmd->state[2].arg; + else + varname = NULL; + + write_mask = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Command expected."); + + if (argc > 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Only one command is supported."); + + ptr = argv[0]; + + for (i = 0; i < ARRAY_SIZE (pci_registers); i++) + { + if (grub_strncmp (ptr, pci_registers[i].name, + grub_strlen (pci_registers[i].name)) == 0) + break; + } + if (i == ARRAY_SIZE (pci_registers)) + { + regsize = 0; + regaddr = grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown register"); + } + else + { + regaddr = pci_registers[i].addr; + regsize = pci_registers[i].size; + ptr += grub_strlen (pci_registers[i].name); + } + + if (grub_errno) + return grub_errno; + + if (*ptr == '+') + { + ptr++; + regaddr += grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + return grub_errno; + } + + if (grub_memcmp (ptr, ".L", sizeof (".L") - 1) == 0 + || grub_memcmp (ptr, ".l", sizeof (".l") - 1) == 0) + { + regsize = 4; + ptr += sizeof (".l") - 1; + } + else if (grub_memcmp (ptr, ".W", sizeof (".W") - 1) == 0 + || grub_memcmp (ptr, ".w", sizeof (".w") - 1) == 0) + { + regsize = 2; + ptr += sizeof (".w") - 1; + } + else if (grub_memcmp (ptr, ".B", sizeof (".B") - 1) == 0 + || grub_memcmp (ptr, ".b", sizeof (".b") - 1) == 0) + { + regsize = 1; + ptr += sizeof (".b") - 1; + } + + if (!regsize) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Unknown register size."); + + write_mask = 0; + if (*ptr == '=') + { + ptr++; + regwrite = grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + return grub_errno; + write_mask = 0xffffffff; + if (*ptr == ':') + { + ptr++; + write_mask = grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + return grub_errno; + write_mask = 0xffffffff; + } + regwrite &= write_mask; + } + + if (write_mask && varname) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Option -v isn't valid for writes."); + + grub_pci_iterate (grub_setpci_iter); + return GRUB_ERR_NONE; +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(setpci) +{ + cmd = grub_register_extcmd ("setpci", grub_cmd_setpci, GRUB_COMMAND_FLAG_BOTH, + N_("[-s POSITION] [-d DEVICE] [-v VAR] " + "[REGISTER][=VALUE[:MASK]]"), + N_("Manipulate PCI devices."), options); +} + +GRUB_MOD_FINI(setpci) +{ + grub_unregister_extcmd (cmd); +} diff --git a/commands/sleep.c b/commands/sleep.c index c9d533369..ead279506 100644 --- a/commands/sleep.c +++ b/commands/sleep.c @@ -22,22 +22,22 @@ #include #include #include -#include #include +#include static const struct grub_arg_option options[] = { - {"verbose", 'v', 0, "verbose countdown", 0, 0}, - {"interruptible", 'i', 0, "interruptible with ESC", 0, 0}, + {"verbose", 'v', 0, N_("Verbose countdown."), 0, 0}, + {"interruptible", 'i', 0, N_("Interruptible with ESC."), 0, 0}, {0, 0, 0, 0, 0, 0} }; -static grub_uint8_t x, y; +static grub_uint16_t *pos; static void do_print (int n) { - grub_gotoxy (x, y); + grub_term_restore_pos (pos); /* NOTE: Do not remove the trailing space characters. They are required to clear the line. */ grub_printf ("%d ", n); @@ -63,7 +63,6 @@ static grub_err_t grub_cmd_sleep (grub_extcmd_t cmd, int argc, char **args) { struct grub_arg_list *state = cmd->state; - grub_uint16_t xy; int n; if (argc != 1) @@ -77,9 +76,7 @@ grub_cmd_sleep (grub_extcmd_t cmd, int argc, char **args) return 0; } - xy = grub_getxy (); - x = xy >> 8; - y = xy & 0xff; + pos = grub_term_save_pos (); for (; n; n--) { @@ -105,8 +102,8 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(sleep) { cmd = grub_register_extcmd ("sleep", grub_cmd_sleep, GRUB_COMMAND_FLAG_BOTH, - "sleep NUMBER_OF_SECONDS", - "Wait for a specified number of seconds", + N_("NUMBER_OF_SECONDS"), + N_("Wait for a specified number of seconds."), options); } diff --git a/commands/terminal.c b/commands/terminal.c new file mode 100644 index 000000000..1129c39bd --- /dev/null +++ b/commands/terminal.c @@ -0,0 +1,246 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#include +#include +#include +#include +#include +#include + +struct grub_term_autoload *grub_term_input_autoload = NULL; +struct grub_term_autoload *grub_term_output_autoload = NULL; + +struct abstract_terminal +{ + struct abstract_terminal *next; + const char *name; + grub_err_t (*init) (void); + grub_err_t (*fini) (void); +}; + +static grub_err_t +handle_command (int argc, char **args, struct abstract_terminal **enabled, + struct abstract_terminal **disabled, + struct grub_term_autoload *autoloads, + const char *active_str, + const char *available_str) +{ + int i; + struct abstract_terminal *term; + struct grub_term_autoload *aut; + + if (argc == 0) + { + grub_puts_ (active_str); + for (term = *enabled; term; term = term->next) + grub_printf ("%s ", term->name); + grub_printf ("\n"); + grub_puts_ (available_str); + for (term = *disabled; term; term = term->next) + grub_printf ("%s ", term->name); + /* This is quadratic but we don't expect mode than 30 terminal + modules ever. */ + for (aut = autoloads; aut; aut = aut->next) + { + for (term = *disabled; term; term = term->next) + if (grub_strcmp (term->name, aut->name) == 0) + break; + if (!term) + for (term = *enabled; term; term = term->next) + if (grub_strcmp (term->name, aut->name) == 0) + break; + if (!term) + grub_printf ("%s ", aut->name); + } + grub_printf ("\n"); + return GRUB_ERR_NONE; + } + i = 0; + + if (grub_strcmp (args[0], "--append") == 0 + || grub_strcmp (args[0], "--remove") == 0) + i++; + + if (i == argc) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no terminal specified")); + + for (; i < argc; i++) + { + int again = 0; + while (1) + { + for (term = *disabled; term; term = term->next) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term == 0) + for (term = *enabled; term; term = term->next) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + break; + if (again) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n", + args[i]); + for (aut = autoloads; aut; aut = aut->next) + if (grub_strcmp (args[i], aut->name) == 0) + { + grub_dl_t mod; + mod = grub_dl_load (aut->modname); + if (mod) + grub_dl_ref (mod); + grub_errno = GRUB_ERR_NONE; + break; + } + if (!aut) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n", + args[i]); + again = 1; + } + } + + if (grub_strcmp (args[0], "--append") == 0) + { + for (i = 1; i < argc; i++) + { + for (term = *disabled; term; term = term->next) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + { + if (term->init && term->init () != GRUB_ERR_NONE) + return grub_errno; + + grub_list_remove (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); + grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); + } + } + return GRUB_ERR_NONE; + } + + if (grub_strcmp (args[0], "--remove") == 0) + { + for (i = 1; i < argc; i++) + { + for (term = *enabled; term; term = term->next) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + { + if (!term->next && term == *enabled) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "can't remove the last terminal"); + grub_list_remove (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); + if (term->fini) + term->fini (); + grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); + } + } + return GRUB_ERR_NONE; + } + for (i = 0; i < argc; i++) + { + for (term = *disabled; term; term = term->next) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (term) + { + if (term->init && term->init () != GRUB_ERR_NONE) + return grub_errno; + + grub_list_remove (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); + grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); + } + } + + { + struct abstract_terminal *next; + for (term = *enabled; term; term = next) + { + next = term->next; + for (i = 0; i < argc; i++) + if (grub_strcmp (args[i], term->name) == 0) + break; + if (i == argc) + { + if (!term->next && term == *enabled) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "can't remove the last terminal"); + grub_list_remove (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); + if (term->fini) + term->fini (); + grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); + } + } + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, next); + (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, name); + (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, init); + (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, fini); + return handle_command (argc, args, + (struct abstract_terminal **) &grub_term_inputs, + (struct abstract_terminal **) &grub_term_inputs_disabled, + grub_term_input_autoload, + N_ ("Active input terminals:"), + N_ ("Available input terminals:")); +} + +static grub_err_t +grub_cmd_terminal_output (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, next); + (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, name); + (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, init); + (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, fini); + return handle_command (argc, args, (struct abstract_terminal **) &grub_term_outputs, + (struct abstract_terminal **) &grub_term_outputs_disabled, + grub_term_output_autoload, + N_ ("Active output terminals:"), + N_ ("Available output terminals:")); +} + +static grub_command_t cmd_terminal_input, cmd_terminal_output; + +GRUB_MOD_INIT(terminal) +{ + cmd_terminal_input = + grub_register_command ("terminal_input", grub_cmd_terminal_input, + N_("[--append|--remove] " + "[TERMINAL1] [TERMINAL2] ..."), + N_("List or select an input terminal.")); + cmd_terminal_output = + grub_register_command ("terminal_output", grub_cmd_terminal_output, + N_("[--append|--remove] " + "[TERMINAL1] [TERMINAL2] ..."), + N_("List or select an output terminal.")); +} + +GRUB_MOD_FINI(terminal) +{ + grub_unregister_command (cmd_terminal_input); + grub_unregister_command (cmd_terminal_output); +} diff --git a/commands/test.c b/commands/test.c index 9c813c820..6995165cf 100644 --- a/commands/test.c +++ b/commands/test.c @@ -1,7 +1,7 @@ /* test.c -- The test command.. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007 Free Software Foundation, Inc. + * Copyright (C) 2005,2007,2009 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 @@ -25,6 +25,7 @@ #include #include #include +#include /* A simple implementation for signed numbers. */ static int @@ -420,9 +421,9 @@ static grub_command_t cmd_1, cmd_2; GRUB_MOD_INIT(test) { cmd_1 = grub_register_command ("[", grub_cmd_test, - "[ EXPRESSION ]", "Evaluate an expression"); + N_("EXPRESSION ]"), N_("Evaluate an expression.")); cmd_2 = grub_register_command ("test", grub_cmd_test, - "test EXPRESSION", "Evaluate an expression"); + N_("EXPRESSION"), N_("Evaluate an expression.")); } GRUB_MOD_FINI(test) diff --git a/commands/true.c b/commands/true.c index 16ca31579..aa8125853 100644 --- a/commands/true.c +++ b/commands/true.c @@ -19,6 +19,7 @@ #include #include +#include static grub_err_t grub_cmd_true (struct grub_command *cmd __attribute__ ((unused)), @@ -43,10 +44,10 @@ GRUB_MOD_INIT(true) { cmd_true = grub_register_command ("true", grub_cmd_true, - 0, "do nothing, successfully"); + 0, N_("Do nothing, successfully.")); cmd_false = grub_register_command ("false", grub_cmd_false, - 0, "do nothing, unsuccessfully"); + 0, N_("Do nothing, unsuccessfully.")); } GRUB_MOD_FINI(true) diff --git a/commands/usbtest.c b/commands/usbtest.c index 018c1a25b..b884a93f1 100644 --- a/commands/usbtest.c +++ b/commands/usbtest.c @@ -19,11 +19,13 @@ #include #include +#include #include #include #include #include #include +#include static const char *usb_classes[] = { @@ -59,18 +61,60 @@ static const char *usb_devspeed[] = "High" }; +static grub_usb_err_t +grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid, + char **string) +{ + struct grub_usb_desc_str descstr; + struct grub_usb_desc_str *descstrp; + grub_usb_err_t err; + + /* Only get the length. */ + err = grub_usb_control_msg (dev, 1 << 7, + 0x06, (3 << 8) | index, + langid, 1, (char *) &descstr); + if (err) + return err; + + descstrp = grub_malloc (descstr.length); + if (! descstrp) + return GRUB_USB_ERR_INTERNAL; + err = grub_usb_control_msg (dev, 1 << 7, + 0x06, (3 << 8) | index, + langid, descstr.length, (char *) descstrp); + + *string = grub_malloc (descstr.length / 2); + if (! *string) + { + grub_free (descstrp); + return GRUB_USB_ERR_INTERNAL; + } + + grub_utf16_to_utf8 ((grub_uint8_t *) *string, descstrp->str, descstrp->length / 2 - 1); + (*string)[descstr.length / 2 - 1] = '\0'; + grub_free (descstrp); + + return GRUB_USB_ERR_NONE; +} + static void usb_print_str (const char *description, grub_usb_device_t dev, int idx) { char *name; + grub_usb_err_t err; /* XXX: LANGID */ if (! idx) return; - grub_usb_get_string (dev, idx, 0x0409, &name); - grub_printf ("%s: `%s'\n", description, name); - grub_free (name); + err = grub_usb_get_string (dev, idx, 0x0409, &name); + if (err) + grub_printf ("Error %d retrieving %s\n", err, description); + else + { + grub_printf ("%s: `%s'\n", description, name); + grub_free (name); + } } static int @@ -152,7 +196,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(usbtest) { cmd = grub_register_command ("usb", grub_cmd_usbtest, - 0, "Test USB support"); + 0, N_("Test USB support.")); } GRUB_MOD_FINI(usbtest) diff --git a/commands/videotest.c b/commands/videotest.c index 6fe4b9bd1..390811a71 100644 --- a/commands/videotest.c +++ b/commands/videotest.c @@ -24,15 +24,14 @@ #include #include #include +#include static grub_err_t grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - if (grub_video_set_mode ("1024x768;800x600;640x480", 0) != GRUB_ERR_NONE) - return grub_errno; - + grub_err_t err; grub_video_color_t color; unsigned int x; unsigned int y; @@ -49,6 +48,10 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), const char *str; int texty; + err = grub_video_set_mode ("auto", GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); + if (err) + return err; + grub_video_get_viewport (&x, &y, &width, &height); grub_video_create_render_target (&text_layer, width, height, @@ -66,12 +69,12 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), color = grub_video_map_rgb (0, 255, 255); grub_video_fill_rect (color, 100, 100, 100, 100); - sansbig = grub_font_get ("Helvetica Bold 24"); - sans = grub_font_get ("Helvetica Bold 14"); - sanssmall = grub_font_get ("Helvetica 8"); + sansbig = grub_font_get ("Unknown Regular 16"); + sans = grub_font_get ("Unknown Regular 16"); + sanssmall = grub_font_get ("Unknown Regular 16"); fixed = grub_font_get ("Fixed 20"); if (! sansbig || ! sans || ! sanssmall || ! fixed) - return grub_error (GRUB_ERR_BAD_FONT, "No font loaded."); + return grub_error (GRUB_ERR_BAD_FONT, "no font loaded"); glyph = grub_font_get_glyph (fixed, '*'); grub_font_draw_glyph (glyph, color, 200 ,0); @@ -123,11 +126,6 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), grub_font_draw_string (str, fixed, color, 16, texty); texty += grub_font_get_descent (fixed) + grub_font_get_leading (fixed); - /* Some character don't exist in the Helvetica font, so the font engine - will fall back to using glyphs from another font that does contain them. - TODO The font engine should be smart about selecting a replacement font - and prioritize fonts with similar sizes. */ - texty += grub_font_get_ascent(sansbig); grub_font_draw_string (str, sansbig, color, 16, texty); texty += grub_font_get_descent (sansbig) + grub_font_get_leading (sansbig); @@ -152,12 +150,13 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - for (i = 0; i < 255; i++) + for (i = 0; i < 5; i++) { color = grub_video_map_rgb (i, 33, 77); grub_video_fill_rect (color, 0, 0, width, height); grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, 0, 0, 0, 0, width, height); + grub_video_swap_buffers (); } grub_getkey (); @@ -178,7 +177,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(videotest) { cmd = grub_register_command ("videotest", grub_cmd_videotest, - 0, "Test video subsystem"); + 0, N_("Test video subsystem.")); } GRUB_MOD_FINI(videotest) diff --git a/commands/xnu_uuid.c b/commands/xnu_uuid.c index 06e88e560..382d3196b 100644 --- a/commands/xnu_uuid.c +++ b/commands/xnu_uuid.c @@ -1,4 +1,4 @@ -/* xnu_uuid.c - transform 64-bit serial number +/* xnu_uuid.c - transform 64-bit serial number to 128-bit uuid suitable for xnu. */ /* * GRUB -- GRand Unified Bootloader @@ -31,325 +31,37 @@ #include #include #include +#include +#include -struct tohash -{ - grub_uint8_t prefix[16]; - grub_uint64_t serial; -} __attribute__ ((packed)); - -/* This prefix is used by xnu and boot-132 to hash +/* This prefix is used by xnu and boot-132 to hash together with volume serial. */ -static grub_uint8_t hash_prefix[16] - = {0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, +static grub_uint8_t hash_prefix[16] + = {0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC}; -#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) -#define ror(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) ) - -typedef struct { - grub_uint32_t A,B,C,D; /* chaining variables */ - grub_uint32_t nblocks; - grub_uint8_t buf[64]; - int count; -} MD5_CONTEXT; - -static void -md5_init( void *context ) -{ - MD5_CONTEXT *ctx = context; - - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; - - ctx->nblocks = 0; - ctx->count = 0; -} - -/* These are the four functions used in the four steps of the MD5 algorithm - and defined in the RFC 1321. The first function is a little bit optimized - (as found in Colin Plumbs public domain implementation). */ -/* #define FF(b, c, d) ((b & c) | (~b & d)) */ -#define FF(b, c, d) (d ^ (b & (c ^ d))) -#define FG(b, c, d) FF (d, b, c) -#define FH(b, c, d) (b ^ c ^ d) -#define FI(b, c, d) (c ^ (b | ~d)) - - -/**************** - * transform n*64 grub_uint8_ts - */ -static void -transform ( MD5_CONTEXT *ctx, const unsigned char *data ) -{ - grub_uint32_t correct_words[16]; - register grub_uint32_t A = ctx->A; - register grub_uint32_t B = ctx->B; - register grub_uint32_t C = ctx->C; - register grub_uint32_t D = ctx->D; - grub_uint32_t *cwp = correct_words; - -#ifdef GRUB_CPU_WORDS_BIGENDIAN - { - int i; - const grub_uint32_t *p = (const grub_uint32_t *) data; - - for (i = 0; i < 16; i++) - correct_words[i] = grub_le_to_cpu32 (p[i]); - } -#else - grub_memcpy (correct_words, data, 64); -#endif - -#define OP(a, b, c, d, s, T) \ - do \ - { \ - a += FF (b, c, d) + (*cwp++) + T; \ - a = rol(a, s); \ - a += b; \ - } \ - while (0) - - /* Before we start, one word about the strange constants. - They are defined in RFC 1321 as - - T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 - */ - - /* Round 1. */ - OP (A, B, C, D, 7, 0xd76aa478); - OP (D, A, B, C, 12, 0xe8c7b756); - OP (C, D, A, B, 17, 0x242070db); - OP (B, C, D, A, 22, 0xc1bdceee); - OP (A, B, C, D, 7, 0xf57c0faf); - OP (D, A, B, C, 12, 0x4787c62a); - OP (C, D, A, B, 17, 0xa8304613); - OP (B, C, D, A, 22, 0xfd469501); - OP (A, B, C, D, 7, 0x698098d8); - OP (D, A, B, C, 12, 0x8b44f7af); - OP (C, D, A, B, 17, 0xffff5bb1); - OP (B, C, D, A, 22, 0x895cd7be); - OP (A, B, C, D, 7, 0x6b901122); - OP (D, A, B, C, 12, 0xfd987193); - OP (C, D, A, B, 17, 0xa679438e); - OP (B, C, D, A, 22, 0x49b40821); - -#undef OP -#define OP(f, a, b, c, d, k, s, T) \ - do \ - { \ - a += f (b, c, d) + correct_words[k] + T; \ - a = rol(a, s); \ - a += b; \ - } \ - while (0) - - /* Round 2. */ - OP (FG, A, B, C, D, 1, 5, 0xf61e2562); - OP (FG, D, A, B, C, 6, 9, 0xc040b340); - OP (FG, C, D, A, B, 11, 14, 0x265e5a51); - OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); - OP (FG, A, B, C, D, 5, 5, 0xd62f105d); - OP (FG, D, A, B, C, 10, 9, 0x02441453); - OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); - OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); - OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); - OP (FG, D, A, B, C, 14, 9, 0xc33707d6); - OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); - OP (FG, B, C, D, A, 8, 20, 0x455a14ed); - OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); - OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); - OP (FG, C, D, A, B, 7, 14, 0x676f02d9); - OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); - - /* Round 3. */ - OP (FH, A, B, C, D, 5, 4, 0xfffa3942); - OP (FH, D, A, B, C, 8, 11, 0x8771f681); - OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); - OP (FH, B, C, D, A, 14, 23, 0xfde5380c); - OP (FH, A, B, C, D, 1, 4, 0xa4beea44); - OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); - OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); - OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); - OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); - OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); - OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); - OP (FH, B, C, D, A, 6, 23, 0x04881d05); - OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); - OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); - OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); - OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); - - /* Round 4. */ - OP (FI, A, B, C, D, 0, 6, 0xf4292244); - OP (FI, D, A, B, C, 7, 10, 0x432aff97); - OP (FI, C, D, A, B, 14, 15, 0xab9423a7); - OP (FI, B, C, D, A, 5, 21, 0xfc93a039); - OP (FI, A, B, C, D, 12, 6, 0x655b59c3); - OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); - OP (FI, C, D, A, B, 10, 15, 0xffeff47d); - OP (FI, B, C, D, A, 1, 21, 0x85845dd1); - OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); - OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); - OP (FI, C, D, A, B, 6, 15, 0xa3014314); - OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); - OP (FI, A, B, C, D, 4, 6, 0xf7537e82); - OP (FI, D, A, B, C, 11, 10, 0xbd3af235); - OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); - OP (FI, B, C, D, A, 9, 21, 0xeb86d391); - - /* Put checksum in context given as argument. */ - ctx->A += A; - ctx->B += B; - ctx->C += C; - ctx->D += D; -} - -/* The routine updates the message-digest context to - * account for the presence of each of the characters inBuf[0..inLen-1] - * in the message whose digest is being computed. - */ -static void -md5_write( void *context, const void *inbuf_arg , grub_size_t inlen) -{ - const unsigned char *inbuf = inbuf_arg; - MD5_CONTEXT *hd = context; - - if( hd->count == 64 ) /* flush the buffer */ - { - transform( hd, hd->buf ); - // _gcry_burn_stack (80+6*sizeof(void*)); - hd->count = 0; - hd->nblocks++; - } - if( !inbuf ) - return; - - if( hd->count ) - { - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; - md5_write( hd, NULL, 0 ); - if( !inlen ) - return; - } - // _gcry_burn_stack (80+6*sizeof(void*)); - - while( inlen >= 64 ) - { - transform( hd, inbuf ); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; - -} - - - -/* The routine final terminates the message-digest computation and - * ends with the desired message digest in mdContext->digest[0...15]. - * The handle is prepared for a new MD5 cycle. - * Returns 16 grub_uint8_ts representing the digest. - */ -static void -md5_final( void *context) -{ - MD5_CONTEXT *hd = context; - grub_uint32_t t, msb, lsb; - grub_uint32_t *p; - - md5_write(hd, NULL, 0); /* flush */; - - t = hd->nblocks; - /* multiply by 64 to make a grub_uint8_t count */ - lsb = t << 6; - msb = t >> 26; - /* add the count */ - t = lsb; - if( (lsb += hd->count) < t ) - msb++; - /* multiply by 8 to make a bit count */ - t = lsb; - lsb <<= 3; - msb <<= 3; - msb |= t >> 29; - - if( hd->count < 56 ) /* enough room */ - { - hd->buf[hd->count++] = 0x80; /* pad */ - while( hd->count < 56 ) - hd->buf[hd->count++] = 0; /* pad */ - } - else /* need one extra block */ - { - hd->buf[hd->count++] = 0x80; /* pad character */ - while( hd->count < 64 ) - hd->buf[hd->count++] = 0; - md5_write(hd, NULL, 0); /* flush */; - grub_memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ - } - /* append the 64 bit count */ - hd->buf[56] = lsb ; - hd->buf[57] = lsb >> 8; - hd->buf[58] = lsb >> 16; - hd->buf[59] = lsb >> 24; - hd->buf[60] = msb ; - hd->buf[61] = msb >> 8; - hd->buf[62] = msb >> 16; - hd->buf[63] = msb >> 24; - transform( hd, hd->buf ); - // _gcry_burn_stack (80+6*sizeof(void*)); - - p = (grub_uint32_t *) hd->buf; -#define X(a) do { *p = grub_le_to_cpu32 (hd->a); p++; } while (0) - X(A); - X(B); - X(C); - X(D); -#undef X - -} - -/** - * GRUB2 Crypto Interface - * Written by Michael Gorven - */ -static grub_err_t -md5 (const char *in, grub_size_t insize, char *out) -{ - MD5_CONTEXT hd; - - md5_init (&hd); - md5_write (&hd, in, insize); - md5_final (&hd); - grub_memcpy (out, hd.buf, 16); - - return GRUB_ERR_NONE; -} - static grub_err_t grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { - struct tohash hashme; - grub_uint8_t xnu_uuid[16]; + grub_uint64_t serial; + grub_uint8_t *xnu_uuid; char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; char *ptr; + grub_uint8_t ctx[GRUB_MD_MD5->contextsize]; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required"); - hashme.serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); - grub_memcpy (hashme.prefix, hash_prefix, sizeof (hashme.prefix)); + serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); - md5 ((char *) &hashme, sizeof (hashme), (char *) xnu_uuid); - grub_sprintf (uuid_string, + GRUB_MD_MD5->init (&ctx); + GRUB_MD_MD5->write (&ctx, hash_prefix, sizeof (hash_prefix)); + GRUB_MD_MD5->write (&ctx, &serial, sizeof (serial)); + GRUB_MD_MD5->final (&ctx); + xnu_uuid = GRUB_MD_MD5->read (&ctx); + + grub_snprintf (uuid_string, sizeof (uuid_string), "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", (unsigned int) xnu_uuid[0], (unsigned int) xnu_uuid[1], (unsigned int) xnu_uuid[2], (unsigned int) xnu_uuid[3], @@ -377,9 +89,9 @@ static grub_command_t cmd; GRUB_MOD_INIT (xnu_uuid) { cmd = grub_register_command ("xnu_uuid", grub_cmd_xnu_uuid, - "xnu_uuid GRUBUUID [VARNAME]", - "Transform 64-bit UUID to format " - "suitable for xnu."); + N_("GRUBUUID [VARNAME]"), + N_("Transform 64-bit UUID to format " + "suitable for XNU.")); } GRUB_MOD_FINI (xnu_uuid) diff --git a/conf/any-emu.rmk b/conf/any-emu.rmk index 6c6f3657f..3f0df06aa 100644 --- a/conf/any-emu.rmk +++ b/conf/any-emu.rmk @@ -1,89 +1,114 @@ # -*- makefile -*- -# Used by various components. These rules need to precede them. -script/lexer.c_DEPENDENCIES = grub_script.tab.h +COMMON_CFLAGS += -nostdinc -isystem $(shell $(TARGET_CC) -print-file-name=include) -sbin_UTILITIES += grub-emu -util/grub-emu.c_DEPENDENCIES = grub_emu_init.h -grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ - commands/configfile.c commands/echo.c commands/help.c \ - commands/handler.c commands/ls.c commands/test.c \ - commands/search.c commands/blocklist.c commands/hexdump.c \ - lib/hexdump.c commands/halt.c commands/reboot.c \ - lib/envblk.c commands/loadenv.c \ - commands/gptsync.c commands/probe.c commands/xnu_uuid.c \ - commands/password.c commands/keystatus.c \ - disk/host.c disk/loopback.c disk/scsi.c \ - fs/fshelp.c \ - \ - io/gzio.c \ - kern/device.c kern/disk.c kern/dl.c kern/elf.c kern/env.c \ - kern/err.c kern/list.c kern/handler.c \ - kern/command.c kern/corecmd.c commands/extcmd.c kern/file.c \ - kern/fs.c commands/boot.c kern/main.c kern/misc.c kern/parser.c \ - kern/partition.c kern/reader.c kern/term.c \ +kernel_img_RELOCATABLE = yes +pkglib_PROGRAMS = kernel.img +kernel_img_SOURCES = kern/device.c kern/disk.c kern/dl.c kern/env.c \ + kern/err.c kern/list.c kern/handler.c kern/command.c \ + kern/corecmd.c kern/file.c kern/fs.c kern/main.c kern/misc.c \ + kern/parser.c kern/partition.c kern/term.c \ kern/rescue_reader.c kern/rescue_parser.c \ - lib/arg.c normal/cmdline.c normal/datetime.c normal/misc.c \ - normal/handler.c normal/auth.c normal/autofs.c \ - normal/completion.c normal/main.c normal/color.c \ - normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ - normal/menu_text.c \ - script/main.c script/execute.c script/function.c \ - script/lexer.c script/script.c grub_script.tab.c \ - partmap/amiga.c partmap/apple.c partmap/msdos.c partmap/sun.c \ - partmap/acorn.c partmap/gpt.c \ - \ - fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \ - fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \ - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \ - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \ - fs/befs.c fs/befs_be.c fs/tar.c \ - \ - util/console.c util/hostfs.c util/grub-emu.c util/misc.c \ - util/hostdisk.c util/getroot.c \ - \ - disk/raid.c disk/raid5_recover.c disk/raid6_recover.c \ - disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ - commands/parttool.c parttool/msdospart.c \ - grub_emu_init.c gnulib/progname.c + \ + kern/emu/main.c kern/emu/mm.c kern/emu/misc.c \ + kern/emu/getroot.c kern/emu/time.c kern/emu/hostdisk.c \ + kern/emu/hostfs.c kern/emu/console.c \ + \ + gnulib/progname.c disk/host.c +kernel_img_HEADERS += datetime.h emu/misc.h +kernel_img_CFLAGS = $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-char-subscripts -Wno-unused -Wno-deprecated-declarations -Wno-undef -I$(srcdir)/gnulib +kernel_img_LDFLAGS = $(COMMON_LDFLAGS) +TARGET_NO_STRIP = yes + +ifneq ($(TARGET_NO_MODULES), yes) +kernel_img_SOURCES += symlist.c kern/$(target_cpu)/dl.c +ifneq ($(target_cpu), i386) +ifneq ($(target_cpu), x86_64) +kernel_img_SOURCES += kern/$(target_cpu)/cache.S +endif +endif +else +kernel_img_SOURCES += grub_emu_init.c +endif + +# For halt.mod. +pkglib_MODULES += halt.mod +halt_mod_SOURCES = commands/halt.c +halt_mod_CFLAGS = $(COMMON_CFLAGS) +halt_mod_LDFLAGS = $(COMMON_LDFLAGS) ifeq ($(target_cpu), i386) -grub_emu_SOURCES += commands/i386/cpuid.c +pkglib_MODULES += cpuid.mod +cpuid_mod_SOURCES = commands/i386/cpuid.c +cpuid_mod_CFLAGS = $(COMMON_CFLAGS) +cpuid_mod_LDFLAGS = $(COMMON_LDFLAGS) endif grub_emu_LDFLAGS = $(LIBCURSES) ifeq ($(enable_grub_emu_usb), yes) -grub_emu_SOURCES += disk/usbms.c util/usb.c bus/usb/usb.c \ - commands/usbtest.c -grub_emu_LDFLAGS += $(LIBCURSES) $(LIBUSB) +kernel_img_HEADERS += libusb.h + +pkglib_MODULES += libusb.mod +libusb_mod_SOURCES = bus/usb/emu/usb.c +libusb_mod_CFLAGS = +libusb_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For usb.mod +pkglib_MODULES += usb.mod +usb_mod_SOURCES = bus/usb/usb.c +usb_mod_CFLAGS = $(COMMON_CFLAGS) +usb_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For usbtest.mod +pkglib_MODULES += usbtest.mod +usbtest_mod_SOURCES = commands/usbtest.c +usbtest_mod_CFLAGS = $(COMMON_CFLAGS) +usbtest_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For usbms.mod +pkglib_MODULES += usbms.mod +usbms_mod_SOURCES = disk/usbms.c +usbms_mod_CFLAGS = $(COMMON_CFLAGS) +usbms_mod_LDFLAGS = $(COMMON_LDFLAGS) + +grub_emu_LDFLAGS += $(LIBUSB) endif -grub_emu_init.lst: geninit.sh $(filter-out grub_emu_init.c,$(grub_emu_SOURCES)) - rm -f $@; grep GRUB_MOD_INIT $(filter %.c,$^) /dev/null > $@ -DISTCLEANFILES += grub_emu_init.lst +ifeq ($(enable_grub_emu_sdl), yes) +pkglib_MODULES += sdl.mod +sdl_mod_SOURCES = video/emu/sdl.c +sdl_mod_CFLAGS = +sdl_mod_LDFLAGS = $(COMMON_LDFLAGS) +grub_emu_LDFLAGS += $(LIBSDL) +kernel_img_HEADERS += sdl.h +endif -grub_emu_init.h: grub_emu_init.lst $(filter-out grub_emu_init.c,$(grub_emu_SOURCES)) geninitheader.sh - rm -f $@; sh $(srcdir)/geninitheader.sh $< > $@ +ifeq ($(enable_grub_emu_pci), yes) +pkglib_MODULES += pci.mod +pci_mod_SOURCES = bus/emu/pci.c commands/lspci.c +pci_mod_LDFLAGS = $(COMMON_LDFLAGS) +grub_emu_LDFLAGS += $(LIBPCIACCESS) +kernel_img_HEADERS += libpciaccess.h +endif + +include $(srcdir)/conf/common.mk + +grub_emu_init.h: genemuinitheader.sh $(pkglib_MODULES) + rm -f $@; echo $(pkglib_MODULES) | sh $(srcdir)/genemuinitheader.sh $(NM) > $@ DISTCLEANFILES += grub_emu_init.h -grub_emu_init.c: grub_emu_init.lst $(filter-out grub_emu_init.c,$(grub_emu_SOURCES)) geninit.sh grub_emu_init.h - rm -f $@; sh $(srcdir)/geninit.sh $< $(filter %.c,$^) > $@ +grub_emu_init.c: genemuinit.sh $(pkglib_MODULES) grub_emu_init.h + rm -f $@; echo $(pkglib_MODULES) | sh $(srcdir)/genemuinit.sh $(NM) > $@ DISTCLEANFILES += grub_emu_init.c - - - -# FIXME: this could be shared with common.rmk - -# For grub-mkfont. -ifeq ($(enable_grub_mkfont), yes) -bin_UTILITIES += grub-mkfont -grub_mkfont_SOURCES = gnulib/progname.c util/grub-mkfont.c util/misc.c -grub_mkfont_CFLAGS = $(freetype_cflags) -grub_mkfont_LDFLAGS = $(freetype_libs) +CLEANFILES += grub-emu +ifneq ($(TARGET_NO_MODULES), yes) +grub-emu: $(pkglib_PROGRAMS) + $(CC) -o $@ $^ $(grub_emu_LDFLAGS) $(LDFLAGS) +else +grub-emu: $(pkglib_MODULES) $(pkglib_PROGRAMS) + $(CC) -o $@ $^ $(grub_emu_LDFLAGS) $(LDFLAGS) endif +GRUB_EMU=grub-emu -grub_script.tab.c grub_script.tab.h: script/parser.y - $(YACC) -d -p grub_script_yy -b grub_script $(srcdir)/script/parser.y -DISTCLEANFILES += grub_script.tab.c grub_script.tab.h diff --git a/conf/common.rmk b/conf/common.rmk index 56f17e4e7..beee25be9 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -1,9 +1,13 @@ # -*- makefile -*- +# Used by various components. These rules need to precede them. +script/lexer.c_DEPENDENCIES = grub_script.tab.h + sbin_UTILITIES += grub-mkdevicemap grub_mkdevicemap_SOURCES = gnulib/progname.c util/grub-mkdevicemap.c \ util/deviceiter.c \ - util/misc.c + util/misc.c kern/emu/misc.c \ + kern/env.c kern/err.c kern/list.c kern/misc.c kern/emu/mm.c ifeq ($(target_cpu)-$(platform), sparc64-ieee1275) grub_mkdevicemap_SOURCES += util/ieee1275/ofpath.c util/ieee1275/devicemap.c @@ -11,28 +15,28 @@ else grub_mkdevicemap_SOURCES += util/devicemap.c endif -# For grub-mkelfimage. -bin_UTILITIES += grub-mkelfimage -grub_mkelfimage_SOURCES = gnulib/progname.c \ - util/elf/grub-mkimage.c util/misc.c \ - util/resolve.c -util/elf/grub-mkimage.c_DEPENDENCIES = Makefile +# For grub-mkimage. +bin_UTILITIES += grub-mkimage +grub_mkimage_SOURCES = gnulib/progname.c util/grub-mkimage.c util/misc.c \ + util/resolve.c kern/emu/misc.c lib/LzmaEnc.c lib/LzFind.c +util/grub-mkimage.c_DEPENDENCIES = Makefile # For grub-probe. sbin_UTILITIES += grub-probe util/grub-probe.c_DEPENDENCIES = grub_probe_init.h grub_probe_SOURCES = gnulib/progname.c util/grub-probe.c \ - util/hostdisk.c util/misc.c util/getroot.c \ + kern/emu/hostdisk.c util/misc.c kern/emu/misc.c kern/emu/getroot.c kern/emu/mm.c \ kern/device.c kern/disk.c kern/err.c kern/misc.c \ - kern/parser.c kern/partition.c kern/file.c \ + kern/parser.c kern/partition.c kern/file.c kern/list.c \ \ fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \ fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \ - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \ - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \ - fs/befs.c fs/befs_be.c fs/tar.c \ + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \ + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \ + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \ \ - partmap/msdos.c partmap/apple.c partmap/sun.c partmap/gpt.c\ + partmap/msdos.c partmap/bsdlabel.c partmap/apple.c \ + partmap/sun.c partmap/sunpc.c partmap/gpt.c \ kern/fs.c kern/env.c fs/fshelp.c \ disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c @@ -40,24 +44,10 @@ ifeq ($(enable_grub_fstest), yes) bin_UTILITIES += grub-fstest endif -bin_UTILITIES += grub-mkisofs -grub_mkisofs_SOURCES = util/mkisofs/eltorito.c \ - util/mkisofs/hash.c util/mkisofs/joliet.c \ - util/mkisofs/match.c util/mkisofs/mkisofs.c \ - util/mkisofs/multi.c util/mkisofs/name.c \ - util/mkisofs/rock.c util/mkisofs/tree.c \ - util/mkisofs/write.c \ - \ - gnulib/fnmatch.c gnulib/getopt1.c gnulib/getopt.c \ - gnulib/error.c gnulib/progname.c -grub_mkisofs_CFLAGS = -D_FILE_OFFSET_BITS=64 \ - -I$(srcdir)/util/mkisofs/include \ - -Wno-all -Werror - # For grub-fstest. util/grub-fstest.c_DEPENDENCIES = grub_fstest_init.h -grub_fstest_SOURCES = gnulib/progname.c util/grub-fstest.c util/hostfs.c \ - util/misc.c \ +grub_fstest_SOURCES = gnulib/progname.c util/grub-fstest.c kern/emu/hostfs.c \ + util/misc.c kern/emu/misc.c kern/emu/mm.c \ kern/file.c kern/device.c kern/disk.c kern/err.c kern/misc.c \ disk/host.c disk/loopback.c kern/list.c kern/command.c \ lib/arg.c commands/extcmd.c normal/datetime.c normal/misc.c \ @@ -65,12 +55,12 @@ grub_fstest_SOURCES = gnulib/progname.c util/grub-fstest.c util/hostfs.c \ \ fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \ fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \ - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \ + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \ fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c fs/befs.c \ fs/befs_be.c fs/tar.c \ \ - kern/partition.c partmap/msdos.c partmap/apple.c partmap/sun.c \ - partmap/gpt.c \ + kern/partition.c partmap/msdos.c partmap/bsdlabel.c \ + partmap/apple.c partmap/sun.c partmap/sunpc.c partmap/gpt.c \ kern/fs.c kern/env.c fs/fshelp.c disk/raid.c \ disk/raid5_recover.c disk/raid6_recover.c \ disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ @@ -79,20 +69,69 @@ grub_fstest_SOURCES = gnulib/progname.c util/grub-fstest.c util/hostfs.c \ # For grub-mkfont. ifeq ($(enable_grub_mkfont), yes) bin_UTILITIES += grub-mkfont -grub_mkfont_SOURCES = gnulib/progname.c util/grub-mkfont.c util/misc.c +grub_mkfont_SOURCES = gnulib/progname.c util/grub-mkfont.c util/misc.c kern/emu/misc.c grub_mkfont_CFLAGS = $(freetype_cflags) grub_mkfont_LDFLAGS = $(freetype_libs) endif # For grub-mkrelpath. bin_UTILITIES += grub-mkrelpath -grub_mkrelpath_SOURCES = gnulib/progname.c util/grub-mkrelpath.c util/misc.c +grub_mkrelpath_SOURCES = gnulib/progname.c util/grub-mkrelpath.c util/misc.c kern/emu/misc.c + +bin_UTILITIES += grub-bin2h +grub_bin2h_SOURCES = gnulib/progname.c util/bin2h.c + +# For the lexer. +grub_script.yy.c grub_script.yy.h: script/yylex.l + $(LEX) -o grub_script.yy.c --header-file=grub_script.yy.h $(srcdir)/script/yylex.l +DISTCLEANFILES += grub_script.yy.c grub_script.yy.h + +# For grub-script-check. +bin_UTILITIES += grub-script-check +util/grub-script-check.c_DEPENDENCIES = grub_script_check_init.h +grub_script_check_SOURCES = gnulib/progname.c gnulib/getdelim.c gnulib/getline.c \ + util/grub-script-check.c util/misc.c kern/emu/misc.c kern/emu/mm.c \ + script/main.c script/script.c script/function.c script/lexer.c \ + kern/handler.c kern/err.c kern/parser.c kern/list.c \ + kern/misc.c kern/env.c grub_script_check_init.c grub_script.tab.c \ + grub_script.yy.c +grub_script_check_CFLAGS = $(GNULIB_UTIL_CFLAGS) +MOSTLYCLEANFILES += symlist.c kernel_syms.lst +DEFSYMFILES += kernel_syms.lst + +kernel_img_HEADERS += boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ + env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ + partition.h msdos_partition.h reader.h symbol.h term.h time.h types.h \ + list.h handler.h command.h i18n.h env_private.h libgcc.h + +ifneq ($(platform), emu) +kernel_img_HEADERS += machine/memory.h machine/loader.h +endif + +symlist.c: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h gensymlist.sh + /bin/sh gensymlist.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) + +kernel_syms.lst: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h genkernsyms.sh + /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) # For the parser. grub_script.tab.c grub_script.tab.h: script/parser.y $(YACC) -d -p grub_script_yy -b grub_script $(srcdir)/script/parser.y DISTCLEANFILES += grub_script.tab.c grub_script.tab.h +# For grub-script-check. +grub_script_check_init.lst: geninit.sh $(filter-out grub_script_check_init.c,$(grub_script_check_SOURCES)) + rm -f $@; grep GRUB_MOD_INIT $(filter %.c,$^) /dev/null > $@ +DISTCLEANFILES += grub_script_check_init.lst + +grub_script_check_init.h: grub_script_check_init.lst $(filter-out grub_script_check_init.c,$(grub_script_check_SOURCES)) geninitheader.sh + rm -f $@; sh $(srcdir)/geninitheader.sh $< > $@ +DISTCLEANFILES += grub_script_check_init.h + +grub_script_check_init.c: grub_script_check_init.lst $(filter-out grub_script_check_init.c,$(grub_script_check_SOURCES)) geninit.sh + rm -f $@; sh $(srcdir)/geninit.sh $< $(filter %.c,$^) > $@ +DISTCLEANFILES += grub_script_check_init.c + # For grub-probe. grub_probe_init.lst: geninit.sh $(filter-out grub_probe_init.c,$(grub_probe_SOURCES)) rm -f $@; grep GRUB_MOD_INIT $(filter %.c,$^) /dev/null > $@ @@ -134,7 +173,7 @@ DISTCLEANFILES += grub_fstest_init.c # for grub-editenv bin_UTILITIES += grub-editenv -grub_editenv_SOURCES = gnulib/progname.c util/grub-editenv.c lib/envblk.c util/misc.c kern/misc.c kern/err.c +grub_editenv_SOURCES = gnulib/progname.c util/grub-editenv.c lib/envblk.c util/misc.c kern/emu/misc.c kern/emu/mm.c kern/misc.c kern/err.c CLEANFILES += grub-editenv # Needed for genmk.rb to work @@ -142,7 +181,7 @@ ifeq (0,1) bin_UTILITIES += grub-macho2img grub-pe2elf endif -grub_pe2elf_SOURCES = gnulib/progname.c util/grub-pe2elf.c util/misc.c +grub_pe2elf_SOURCES = gnulib/progname.c util/grub-pe2elf.c util/misc.c kern/emu/misc.c CLEANFILES += grub-pe2elf grub_macho2img_SOURCES = util/grub-macho2img.c @@ -185,6 +224,20 @@ CLEANFILES += $(grub-mkconfig_SCRIPTS) grub-mkconfig_DATA += util/grub.d/README +# For grub-set-default. +grub-set-default: util/grub-set-default.in config.status + ./config.status --file=$@:$< + chmod +x $@ +sbin_SCRIPTS += grub-set-default +CLEANFILES += grub-set-default + +# For grub-reboot. +grub-reboot: util/grub-reboot.in config.status + ./config.status --file=$@:$< + chmod +x $@ +sbin_SCRIPTS += grub-reboot +CLEANFILES += grub-reboot + # Filing systems. pkglib_MODULES += fshelp.mod fat.mod ufs1.mod ufs2.mod ext2.mod ntfs.mod \ ntfscomp.mod minix.mod hfs.mod jfs.mod iso9660.mod xfs.mod \ @@ -231,6 +284,12 @@ minix_mod_SOURCES = fs/minix.c minix_mod_CFLAGS = $(COMMON_CFLAGS) minix_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For nilfs2.mod. +pkglib_MODULES += nilfs2.mod +nilfs2_mod_SOURCES = fs/nilfs2.c +nilfs2_mod_CFLAGS = $(COMMON_CFLAGS) +nilfs2_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For hfs.mod. hfs_mod_SOURCES = fs/hfs.c hfs_mod_CFLAGS = $(COMMON_CFLAGS) @@ -338,6 +397,16 @@ part_gpt_mod_SOURCES = partmap/gpt.c part_gpt_mod_CFLAGS = $(COMMON_CFLAGS) part_gpt_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += part_bsd.mod +part_bsd_mod_SOURCES = partmap/bsdlabel.c +part_bsd_mod_CFLAGS = $(COMMON_CFLAGS) +part_bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += part_sunpc.mod +part_sunpc_mod_SOURCES = partmap/sunpc.c +part_sunpc_mod_CFLAGS = $(COMMON_CFLAGS) +part_sunpc_mod_LDFLAGS = $(COMMON_LDFLAGS) + # Special disk structures and generic drivers pkglib_MODULES += raid.mod raid5rec.mod raid6rec.mod mdraid.mod dm_nv.mod \ @@ -381,7 +450,7 @@ scsi_mod_LDFLAGS = $(COMMON_LDFLAGS) # Commands. pkglib_MODULES += minicmd.mod extcmd.mod hello.mod handler.mod \ ls.mod cmp.mod cat.mod help.mod search.mod loopback.mod \ - fs_file.mod fs_uuid.mod configfile.mod echo.mod \ + configfile.mod echo.mod \ terminfo.mod test.mod blocklist.mod hexdump.mod \ read.mod sleep.mod loadenv.mod crc.mod parttool.mod \ msdospart.mod memrw.mod normal.mod sh.mod \ @@ -413,6 +482,28 @@ hello_mod_SOURCES = hello/hello.c hello_mod_CFLAGS = $(COMMON_CFLAGS) hello_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For gfxmenu.mod. +pkglib_MODULES += gfxmenu.mod +gfxmenu_mod_SOURCES = \ + gfxmenu/gfxmenu.c \ + gfxmenu/model.c \ + gfxmenu/view.c \ + gfxmenu/icon_manager.c \ + gfxmenu/theme_loader.c \ + gfxmenu/widget-box.c \ + gfxmenu/gui_canvas.c \ + gfxmenu/gui_circular_progress.c \ + gfxmenu/gui_box.c \ + gfxmenu/gui_label.c \ + gfxmenu/gui_list.c \ + gfxmenu/gui_image.c \ + gfxmenu/gui_progress_bar.c \ + gfxmenu/gui_util.c \ + gfxmenu/gui_string_util.c \ + gfxmenu/named_colors.c +gfxmenu_mod_CFLAGS = $(COMMON_CFLAGS) +gfxmenu_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For parttool.mod. parttool_mod_SOURCES = commands/parttool.c parttool_mod_CFLAGS = $(COMMON_CFLAGS) @@ -454,10 +545,27 @@ help_mod_CFLAGS = $(COMMON_CFLAGS) help_mod_LDFLAGS = $(COMMON_LDFLAGS) # For search.mod. -search_mod_SOURCES = commands/search.c +search_mod_SOURCES = commands/search_wrap.c search_mod_CFLAGS = $(COMMON_CFLAGS) search_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += search_fs_file.mod search_fs_uuid.mod search_label.mod + +# For search.mod. +search_fs_file_mod_SOURCES = commands/search_file.c +search_fs_file_mod_CFLAGS = $(COMMON_CFLAGS) +search_fs_file_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For search.mod. +search_label_mod_SOURCES = commands/search_label.c +search_label_mod_CFLAGS = $(COMMON_CFLAGS) +search_label_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For search.mod. +search_fs_uuid_mod_SOURCES = commands/search_uuid.c +search_fs_uuid_mod_CFLAGS = $(COMMON_CFLAGS) +search_fs_uuid_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For test.mod. test_mod_SOURCES = commands/test.c test_mod_CFLAGS = $(COMMON_CFLAGS) @@ -468,16 +576,6 @@ loopback_mod_SOURCES = disk/loopback.c loopback_mod_CFLAGS = $(COMMON_CFLAGS) loopback_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For fs_file.mod -fs_file_mod_SOURCES = disk/fs_file.c -fs_file_mod_CFLAGS = $(COMMON_CFLAGS) -fs_file_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For fs_uuid.mod -fs_uuid_mod_SOURCES = disk/fs_uuid.c -fs_uuid_mod_CFLAGS = $(COMMON_CFLAGS) -fs_uuid_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For configfile.mod configfile_mod_SOURCES = commands/configfile.c configfile_mod_CFLAGS = $(COMMON_CFLAGS) @@ -542,68 +640,89 @@ keystatus_mod_LDFLAGS = $(COMMON_LDFLAGS) normal_mod_SOURCES = normal/main.c normal/cmdline.c normal/dyncmd.c \ normal/auth.c normal/autofs.c normal/handler.c \ normal/color.c normal/completion.c normal/datetime.c normal/menu.c \ - normal/menu_entry.c normal/menu_text.c normal/menu_viewer.c \ - normal/misc.c + normal/menu_entry.c normal/menu_text.c \ + normal/misc.c normal/crypto.c normal/term.c normal/context.c normal_mod_CFLAGS = $(COMMON_CFLAGS) normal_mod_LDFLAGS = $(COMMON_LDFLAGS) # For sh.mod. sh_mod_SOURCES = script/main.c script/script.c script/execute.c \ - script/function.c script/lexer.c grub_script.tab.c -sh_mod_CFLAGS = $(COMMON_CFLAGS) + script/function.c script/lexer.c grub_script.tab.c grub_script.yy.c +sh_mod_CFLAGS = $(COMMON_CFLAGS) $(POSIX_CFLAGS) -Wno-error sh_mod_LDFLAGS = $(COMMON_LDFLAGS) +ifneq (, $(FONT_SOURCE)) +font/font.c_DEPENDENCIES = ascii.h +endif + # Common Video Subsystem specific modules. -pkglib_MODULES += video.mod videotest.mod bitmap.mod tga.mod jpeg.mod \ - png.mod font.mod gfxterm.mod video_fb.mod +# On Yeeloong it's part of kernel +ifneq ($(platform), yeeloong) # For video.mod. +pkglib_MODULES += video.mod video_mod_SOURCES = video/video.c video_mod_CFLAGS = $(COMMON_CFLAGS) video_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += video_fb.mod video_fb_mod_SOURCES = video/fb/video_fb.c video/fb/fbblit.c \ video/fb/fbfill.c video/fb/fbutil.c video_fb_mod_CFLAGS = $(COMMON_CFLAGS) video_fb_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For videotest.mod. -videotest_mod_SOURCES = commands/videotest.c -videotest_mod_CFLAGS = $(COMMON_CFLAGS) -videotest_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For bitmap.mod +pkglib_MODULES += bitmap.mod bitmap_mod_SOURCES = video/bitmap.c bitmap_mod_CFLAGS = $(COMMON_CFLAGS) bitmap_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For tga.mod -tga_mod_SOURCES = video/readers/tga.c -tga_mod_CFLAGS = $(COMMON_CFLAGS) -tga_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For bitmap_scale.mod +pkglib_MODULES += bitmap_scale.mod +bitmap_scale_mod_SOURCES = video/bitmap_scale.c +bitmap_scale_mod_CFLAGS = $(COMMON_CFLAGS) +bitmap_scale_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For jpeg.mod. -jpeg_mod_SOURCES = video/readers/jpeg.c -jpeg_mod_CFLAGS = $(COMMON_CFLAGS) -jpeg_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For png.mod. -png_mod_SOURCES = video/readers/png.c -png_mod_CFLAGS = $(COMMON_CFLAGS) -png_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For font.mod. +pkglib_MODULES += font.mod font_mod_SOURCES = font/font_cmd.c font/font.c font_mod_CFLAGS = $(COMMON_CFLAGS) font_mod_LDFLAGS = $(COMMON_LDFLAGS) # For gfxterm.mod. +pkglib_MODULES += gfxterm.mod gfxterm_mod_SOURCES = term/gfxterm.c gfxterm_mod_CFLAGS = $(COMMON_CFLAGS) gfxterm_mod_LDFLAGS = $(COMMON_LDFLAGS) +endif + +# For videotest.mod. +pkglib_MODULES += videotest.mod +videotest_mod_SOURCES = commands/videotest.c +videotest_mod_CFLAGS = $(COMMON_CFLAGS) +videotest_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For tga.mod +pkglib_MODULES += tga.mod +tga_mod_SOURCES = video/readers/tga.c +tga_mod_CFLAGS = $(COMMON_CFLAGS) +tga_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For jpeg.mod. +pkglib_MODULES += jpeg.mod +jpeg_mod_SOURCES = video/readers/jpeg.c +jpeg_mod_CFLAGS = $(COMMON_CFLAGS) +jpeg_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For png.mod. +pkglib_MODULES += png.mod +png_mod_SOURCES = video/readers/png.c +png_mod_CFLAGS = $(COMMON_CFLAGS) +png_mod_LDFLAGS = $(COMMON_LDFLAGS) + + # Misc. -pkglib_MODULES += gzio.mod bufio.mod elf.mod +pkglib_MODULES += gzio.mod elf.mod # For elf.mod. elf_mod_SOURCES = kern/elf.c @@ -615,10 +734,14 @@ gzio_mod_SOURCES = io/gzio.c gzio_mod_CFLAGS = $(COMMON_CFLAGS) gzio_mod_LDFLAGS = $(COMMON_LDFLAGS) +# On Yeeloong it's part of kernel +ifneq ($(platform), yeeloong) # For bufio.mod. +pkglib_MODULES += bufio.mod bufio_mod_SOURCES = io/bufio.c bufio_mod_CFLAGS = $(COMMON_CFLAGS) bufio_mod_LDFLAGS = $(COMMON_LDFLAGS) +endif # For gettext.mod. pkglib_MODULES += gettext.mod @@ -634,7 +757,97 @@ xnu_uuid_mod_SOURCES = commands/xnu_uuid.c xnu_uuid_mod_CFLAGS = $(COMMON_CFLAGS) xnu_uuid_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += trig.mod +trig_mod_SOURCES = trigtables.c +trig_mod_CFLAGS = $(COMMON_CFLAGS) +trig_mod_LDFLAGS = $(COMMON_LDFLAGS) + +trigtables.c: gentrigtables + ./gentrigtables > $@ +DISTCLEANFILES += trigtables.c +gentrigtables: gentrigtables.c + $(CC) -o $@ $^ $(CPPFLAGS) -lm +DISTCLEANFILES += gentrigtables + pkglib_MODULES += setjmp.mod setjmp_mod_SOURCES = lib/$(target_cpu)/setjmp.S setjmp_mod_ASFLAGS = $(COMMON_ASFLAGS) setjmp_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += charset.mod +charset_mod_SOURCES = lib/charset.c +charset_mod_CFLAGS = $(COMMON_CFLAGS) +charset_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += regexp.mod +regexp_mod_SOURCES = gnulib/regex.c commands/regexp.c +regexp_mod_CFLAGS = $(COMMON_CFLAGS) $(GNULIB_CFLAGS) +regexp_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += terminal.mod +terminal_mod_SOURCES = commands/terminal.c +terminal_mod_CFLAGS = $(COMMON_CFLAGS) +terminal_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += crypto.mod +crypto_mod_SOURCES = lib/crypto.c +crypto_mod_CFLAGS = $(COMMON_CFLAGS) +crypto_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += hashsum.mod +hashsum_mod_SOURCES = commands/hashsum.c +hashsum_mod_CFLAGS = $(COMMON_CFLAGS) +hashsum_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += pbkdf2.mod +pbkdf2_mod_SOURCES = lib/pbkdf2.c +pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS) +pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For password_pbkdf2.mod. +pkglib_MODULES += password_pbkdf2.mod +password_pbkdf2_mod_SOURCES = commands/password_pbkdf2.c +password_pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS) +password_pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For memdisk.mod. +pkglib_MODULES += memdisk.mod +memdisk_mod_SOURCES = disk/memdisk.c +memdisk_mod_CFLAGS = $(COMMON_CFLAGS) +memdisk_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For reboot.mod. +pkglib_MODULES += reboot.mod +reboot_mod_SOURCES = commands/reboot.c +reboot_mod_CFLAGS = $(COMMON_CFLAGS) +reboot_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For date.mod +pkglib_MODULES += date.mod +date_mod_SOURCES = commands/date.c +date_mod_CFLAGS = $(COMMON_CFLAGS) +date_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For datehook.mod +pkglib_MODULES += datehook.mod +datehook_mod_SOURCES = hook/datehook.c +datehook_mod_CFLAGS = $(COMMON_CFLAGS) +datehook_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For lsmmap.mod +pkglib_MODULES += lsmmap.mod +lsmmap_mod_SOURCES = commands/lsmmap.c +lsmmap_mod_CFLAGS = $(COMMON_CFLAGS) +lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For boot.mod. +pkglib_MODULES += boot.mod +boot_mod_SOURCES = commands/boot.c lib/i386/pc/biosnum.c +boot_mod_CFLAGS = $(COMMON_CFLAGS) +boot_mod_LDFLAGS = $(COMMON_LDFLAGS) + +bin_UTILITIES += grub-mkpasswd-pbkdf2 +grub_mkpasswd_pbkdf2_SOURCES = gnulib/progname.c gnulib/getdelim.c gnulib/getline.c util/grub-mkpasswd-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/emu/misc.c kern/emu/mm.c kern/err.c +grub_mkpasswd_pbkdf2_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap -DGRUB_MKPASSWD=1 + +include $(srcdir)/conf/gcry.mk diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index b49af84ce..f6a375624 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -1,27 +1,18 @@ # -*- makefile -*- -COMMON_ASFLAGS = -nostdinc -fno-builtin -m32 -COMMON_CFLAGS = -fno-builtin -mrtd -mregparm=3 -m32 -COMMON_LDFLAGS = -m32 -nostdlib - -# Used by various components. These rules need to precede them. -script/lexer.c_DEPENDENCIES = grub_script.tab.h +COMMON_CFLAGS = -mrtd -mregparm=3 # Images. -GRUB_KERNEL_MACHINE_LINK_ADDR = 0x8200 - -ifeq ($(platform), coreboot) - pkglib_PROGRAMS += kernel.img kernel_img_SOURCES = kern/i386/coreboot/startup.S \ kern/i386/misc.S \ kern/i386/coreboot/init.c \ - kern/i386/multiboot_mmap.c \ + kern/i386/coreboot/mmap.c \ kern/i386/halt.c \ kern/main.c kern/device.c \ kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ - kern/misc.c kern/mm.c kern/reader.c kern/term.c \ + kern/misc.c kern/mm.c kern/term.c \ kern/rescue_parser.c kern/rescue_reader.c \ kern/time.c kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ kern/$(target_cpu)/dl.c kern/parser.c kern/partition.c \ @@ -31,69 +22,9 @@ kernel_img_SOURCES = kern/i386/coreboot/startup.S \ kern/env.c \ term/i386/pc/vga_text.c term/i386/vga_common.c \ symlist.c -kernel_img_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ - env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ - partition.h msdos_partition.h reader.h symbol.h term.h time.h types.h \ - machine/boot.h machine/console.h machine/init.h \ - machine/memory.h machine/loader.h list.h handler.h command.h i18n.h kernel_img_CFLAGS = $(COMMON_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -kernel_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-S,-Ttext,$(GRUB_KERNEL_MACHINE_LINK_ADDR),-Bstatic - -endif - -ifeq ($(platform), qemu) - -GRUB_BOOT_MACHINE_LINK_ADDR = 0xffe00 - -pkglib_IMAGES += boot.img -boot_img_SOURCES = boot/i386/qemu/boot.S -boot_img_ASFLAGS = $(COMMON_ASFLAGS) -DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR) -boot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)$(GRUB_BOOT_MACHINE_LINK_ADDR) -boot_img_FORMAT = binary - -bin_UTILITIES += grub-mkimage -grub_mkimage_SOURCES = util/i386/pc/grub-mkimage.c util/misc.c \ - util/resolve.c gnulib/progname.c -grub_mkimage_CFLAGS = -DGRUB_KERNEL_MACHINE_LINK_ADDR=$(GRUB_KERNEL_MACHINE_LINK_ADDR) - -pkglib_IMAGES += kernel.img -kernel_img_SOURCES = kern/i386/qemu/startup.S \ - kern/i386/misc.S \ - kern/i386/coreboot/init.c \ - kern/i386/qemu/mmap.c \ - kern/i386/halt.c \ - kern/main.c kern/device.c \ - kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ - kern/misc.c kern/mm.c kern/reader.c kern/term.c \ - kern/rescue_parser.c kern/rescue_reader.c \ - kern/time.c kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ - kern/$(target_cpu)/dl.c kern/parser.c kern/partition.c \ - kern/i386/tsc.c kern/i386/pit.c \ - kern/generic/rtc_get_time_ms.c \ - kern/generic/millisleep.c \ - kern/env.c \ - term/i386/pc/vga_text.c term/i386/vga_common.c \ - symlist.c -kernel_img_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ - env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ - partition.h msdos_partition.h reader.h symbol.h term.h time.h types.h \ - machine/boot.h machine/console.h machine/init.h \ - machine/memory.h machine/loader.h list.h handler.h command.h i18n.h -kernel_img_CFLAGS = $(COMMON_CFLAGS) -DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR) -kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -DGRUB_KERNEL_MACHINE_LINK_ADDR=$(GRUB_KERNEL_MACHINE_LINK_ADDR) -kernel_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)$(GRUB_KERNEL_MACHINE_LINK_ADDR) -kernel_img_FORMAT = binary -endif - -MOSTLYCLEANFILES += symlist.c kernel_syms.lst -DEFSYMFILES += kernel_syms.lst - -symlist.c: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h gensymlist.sh - /bin/sh gensymlist.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) - -kernel_syms.lst: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h genkernsyms.sh - /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) +kernel_img_LDFLAGS += $(COMMON_LDFLAGS) -Wl,-N,-S,-Ttext,0x8200,-Bstatic sbin_SCRIPTS += grub-install grub_install_SOURCES = util/grub-install.in @@ -102,17 +33,7 @@ bin_SCRIPTS += grub-mkrescue grub_mkrescue_SOURCES = util/grub-mkrescue.in # Modules. -pkglib_MODULES = linux.mod multiboot.mod \ - aout.mod play.mod serial.mod \ - memdisk.mod pci.mod lspci.mod reboot.mod \ - halt.mod datetime.mod date.mod datehook.mod \ - lsmmap.mod mmap.mod - -# For boot.mod. -pkglib_MODULES += boot.mod -boot_mod_SOURCES = commands/boot.c -boot_mod_CFLAGS = $(COMMON_CFLAGS) -boot_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES = linux.mod aout.mod halt.mod datetime.mod mmap.mod # For mmap.mod. mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c @@ -125,31 +46,11 @@ linux_mod_SOURCES = loader/i386/linux.c linux_mod_CFLAGS = $(COMMON_CFLAGS) linux_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For reboot.mod. -reboot_mod_SOURCES = commands/reboot.c -reboot_mod_CFLAGS = $(COMMON_CFLAGS) -reboot_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For halt.mod. halt_mod_SOURCES = commands/halt.c halt_mod_CFLAGS = $(COMMON_CFLAGS) halt_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For serial.mod. -serial_mod_SOURCES = term/i386/pc/serial.c -serial_mod_CFLAGS = $(COMMON_CFLAGS) -serial_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For multiboot.mod. -multiboot_mod_SOURCES = loader/i386/multiboot.c \ - loader/i386/multiboot_helper.S \ - loader/i386/pc/multiboot2.c \ - loader/multiboot2.c \ - loader/multiboot_loader.c -multiboot_mod_CFLAGS = $(COMMON_CFLAGS) -multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) -multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS) - # For aout.mod. aout_mod_SOURCES = loader/aout.c aout_mod_CFLAGS = $(COMMON_CFLAGS) @@ -162,46 +63,11 @@ bsd_mod_CFLAGS = $(COMMON_CFLAGS) bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) bsd_mod_ASFLAGS = $(COMMON_ASFLAGS) -# For play.mod. -play_mod_SOURCES = commands/i386/pc/play.c -play_mod_CFLAGS = $(COMMON_CFLAGS) -play_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For memdisk.mod. -memdisk_mod_SOURCES = disk/memdisk.c -memdisk_mod_CFLAGS = $(COMMON_CFLAGS) -memdisk_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For pci.mod -pci_mod_SOURCES = bus/pci.c -pci_mod_CFLAGS = $(COMMON_CFLAGS) -pci_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For lspci.mod -lspci_mod_SOURCES = commands/lspci.c -lspci_mod_CFLAGS = $(COMMON_CFLAGS) -lspci_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For datetime.mod -datetime_mod_SOURCES = lib/i386/datetime.c +datetime_mod_SOURCES = lib/cmos_datetime.c datetime_mod_CFLAGS = $(COMMON_CFLAGS) datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For date.mod -date_mod_SOURCES = commands/date.c -date_mod_CFLAGS = $(COMMON_CFLAGS) -date_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For datehook.mod -datehook_mod_SOURCES = hook/datehook.c -datehook_mod_CFLAGS = $(COMMON_CFLAGS) -datehook_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For lsmmap.mod -lsmmap_mod_SOURCES = commands/lsmmap.c -lsmmap_mod_CFLAGS = $(COMMON_CFLAGS) -lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For cmostest.mod pkglib_MODULES += cmostest.mod cmostest_mod_SOURCES = commands/i386/cmostest.c diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index df9ef8082..e826cb333 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -1,164 +1,5 @@ # -*- makefile -*- -COMMON_ASFLAGS = -nostdinc -fno-builtin -m32 -COMMON_CFLAGS = -fno-builtin -m32 -COMMON_LDFLAGS = -melf_i386 -nostdlib +COMMON_LDFLAGS = -melf_i386 -# Used by various components. These rules need to precede them. -script/lexer.c_DEPENDENCIES = grub_script.tab.h - -# Utilities. -bin_UTILITIES = grub-mkimage - -# For grub-mkimage. -grub_mkimage_SOURCES = gnulib/progname.c util/i386/efi/grub-mkimage.c \ - util/misc.c util/resolve.c -util/i386/efi/grub-mkimage.c_DEPENDENCIES = Makefile - -# For grub-setup. -#grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c \ -# util/misc.c util/getroot.c kern/device.c kern/disk.c \ -# kern/err.c kern/misc.c fs/fat.c fs/ext2.c fs/xfs.c fs/affs.c \ -# fs/sfs.c kern/parser.c kern/partition.c partmap/msdos.c \ -# fs/ufs.c fs/ufs2.c fs/minix.c fs/hfs.c fs/jfs.c fs/hfsplus.c kern/file.c \ -# kern/fs.c kern/env.c fs/fshelp.c - -# Scripts. -sbin_SCRIPTS = grub-install - -# For grub-install. -grub_install_SOURCES = util/i386/efi/grub-install.in - -# Modules. -pkglib_MODULES = kernel.img chain.mod appleldr.mod \ - linux.mod halt.mod reboot.mod pci.mod lspci.mod \ - datetime.mod date.mod datehook.mod loadbios.mod \ - fixvideo.mod mmap.mod acpi.mod - -# For kernel.img. -kernel_img_EXPORTS = no -kernel_img_SOURCES = kern/i386/efi/startup.S kern/main.c kern/device.c \ - kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ - kern/misc.c kern/mm.c kern/reader.c kern/term.c \ - kern/rescue_parser.c kern/rescue_reader.c \ - kern/$(target_cpu)/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \ - kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \ - term/efi/console.c disk/efi/efidisk.c \ - kern/time.c kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ - kern/i386/tsc.c kern/i386/pit.c \ - kern/generic/rtc_get_time_ms.c \ - kern/generic/millisleep.c -kernel_img_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ - env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ - partition.h msdos_partition.h reader.h symbol.h term.h time.h types.h \ - efi/efi.h efi/time.h efi/disk.h i386/pit.h list.h handler.h command.h i18n.h -kernel_img_CFLAGS = $(COMMON_CFLAGS) -kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -kernel_img_LDFLAGS = $(COMMON_LDFLAGS) - -MOSTLYCLEANFILES += symlist.c -MOSTLYCLEANFILES += symlist.c kernel_syms.lst -DEFSYMFILES += kernel_syms.lst - -symlist.c: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h gensymlist.sh - /bin/sh gensymlist.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) - -kernel_syms.lst: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h genkernsyms.sh - /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) - -# For boot.mod. -pkglib_MODULES += boot.mod -boot_mod_SOURCES = commands/boot.c -boot_mod_CFLAGS = $(COMMON_CFLAGS) -boot_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For acpi.mod. -acpi_mod_SOURCES = commands/acpi.c commands/efi/acpi.c -acpi_mod_CFLAGS = $(COMMON_CFLAGS) -acpi_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For mmap.mod. -mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \ - mmap/efi/mmap.c -mmap_mod_CFLAGS = $(COMMON_CFLAGS) -mmap_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For chain.mod. -chain_mod_SOURCES = loader/efi/chainloader.c -chain_mod_CFLAGS = $(COMMON_CFLAGS) -chain_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For appleldr.mod. -appleldr_mod_SOURCES = loader/efi/appleloader.c -appleldr_mod_CFLAGS = $(COMMON_CFLAGS) -appleldr_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For linux.mod. -linux_mod_SOURCES = loader/i386/efi/linux.c -linux_mod_CFLAGS = $(COMMON_CFLAGS) -linux_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For halt.mod. -halt_mod_SOURCES = commands/halt.c -halt_mod_CFLAGS = $(COMMON_CFLAGS) -halt_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For reboot.mod. -reboot_mod_SOURCES = commands/reboot.c -reboot_mod_CFLAGS = $(COMMON_CFLAGS) -reboot_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For pci.mod -pci_mod_SOURCES = bus/pci.c -pci_mod_CFLAGS = $(COMMON_CFLAGS) -pci_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For lspci.mod -lspci_mod_SOURCES = commands/lspci.c -lspci_mod_CFLAGS = $(COMMON_CFLAGS) -lspci_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For datetime.mod -datetime_mod_SOURCES = lib/efi/datetime.c -datetime_mod_CFLAGS = $(COMMON_CFLAGS) -datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For date.mod -date_mod_SOURCES = commands/date.c -date_mod_CFLAGS = $(COMMON_CFLAGS) -date_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For datehook.mod -datehook_mod_SOURCES = hook/datehook.c -datehook_mod_CFLAGS = $(COMMON_CFLAGS) -datehook_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For loadbios.mod -loadbios_mod_SOURCES = commands/efi/loadbios.c -loadbios_mod_CFLAGS = $(COMMON_CFLAGS) -loadbios_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For fixvideo.mod -fixvideo_mod_SOURCES = commands/efi/fixvideo.c -fixvideo_mod_CFLAGS = $(COMMON_CFLAGS) -fixvideo_mod_LDFLAGS = $(COMMON_LDFLAGS) - -pkglib_MODULES += efi_uga.mod -efi_uga_mod_SOURCES = video/efi_uga.c -efi_uga_mod_CFLAGS = $(COMMON_CFLAGS) -efi_uga_mod_LDFLAGS = $(COMMON_LDFLAGS) - -pkglib_MODULES += efi_gop.mod -efi_gop_mod_SOURCES = video/efi_gop.c -efi_gop_mod_CFLAGS = $(COMMON_CFLAGS) -efi_gop_mod_LDFLAGS = $(COMMON_LDFLAGS) - -pkglib_MODULES += xnu.mod -xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/i386/efi/xnu.c\ - loader/macho.c loader/xnu.c loader/i386/xnu_helper.S -xnu_mod_CFLAGS = $(COMMON_CFLAGS) -xnu_mod_LDFLAGS = $(COMMON_LDFLAGS) -xnu_mod_ASFLAGS = $(COMMON_ASFLAGS) - -include $(srcdir)/conf/i386.mk -include $(srcdir)/conf/common.mk +include $(srcdir)/conf/x86-efi.mk diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 8d9577844..05ba38a65 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -1,11 +1,6 @@ # -*- makefile -*- -COMMON_ASFLAGS = -m32 -nostdinc -fno-builtin -COMMON_CFLAGS = -ffreestanding -mrtd -mregparm=3 -COMMON_LDFLAGS = -nostdlib - -# Used by various components. These rules need to precede them. -script/lexer.c_DEPENDENCIES = grub_script.tab.h +COMMON_CFLAGS = -mrtd -mregparm=3 # Images. pkglib_PROGRAMS = kernel.img @@ -19,7 +14,7 @@ kernel_img_SOURCES = kern/i386/ieee1275/startup.S \ kern/ieee1275/cmain.c kern/ieee1275/openfw.c \ kern/main.c kern/device.c \ kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ - kern/misc.c kern/mm.c kern/reader.c kern/term.c \ + kern/misc.c kern/mm.c kern/term.c \ kern/rescue_parser.c kern/rescue_reader.c \ kern/$(target_cpu)/dl.c kern/parser.c kern/partition.c \ kern/env.c \ @@ -29,23 +24,10 @@ kernel_img_SOURCES = kern/i386/ieee1275/startup.S \ term/ieee1275/ofconsole.c \ disk/ieee1275/ofdisk.c \ symlist.c -kernel_img_HEADERS = cache.h device.h disk.h dl.h elf.h elfload.h \ - env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ - partition.h msdos_partition.h reader.h symbol.h term.h time.h types.h \ - ieee1275/ieee1275.h machine/kernel.h machine/loader.h machine/memory.h \ - list.h handler.h command.h i18n.h +kernel_img_HEADERS += ieee1275/ieee1275.h kernel_img_CFLAGS = $(COMMON_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -kernel_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-S,-Ttext,0x10000,-Bstatic - -MOSTLYCLEANFILES += symlist.c kernel_syms.lst -DEFSYMFILES += kernel_syms.lst - -symlist.c: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h gensymlist.sh - /bin/sh gensymlist.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) - -kernel_syms.lst: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h genkernsyms.sh - /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) +kernel_img_LDFLAGS += $(COMMON_LDFLAGS) -Wl,-N,-S,-Ttext,0x10000,-Bstatic # Scripts. sbin_SCRIPTS = grub-install @@ -54,16 +36,10 @@ sbin_SCRIPTS = grub-install grub_install_SOURCES = util/ieee1275/grub-install.in # Modules. -pkglib_MODULES = halt.mod reboot.mod suspend.mod \ - aout.mod serial.mod linux.mod \ - nand.mod memdisk.mod pci.mod lspci.mod datetime.mod \ - date.mod datehook.mod lsmmap.mod mmap.mod - -# For boot.mod. -pkglib_MODULES += boot.mod -boot_mod_SOURCES = commands/boot.c -boot_mod_CFLAGS = $(COMMON_CFLAGS) -boot_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES = halt.mod suspend.mod \ + aout.mod linux.mod \ + nand.mod datetime.mod \ + mmap.mod # For mmap.mod. mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c @@ -81,21 +57,11 @@ suspend_mod_SOURCES = commands/ieee1275/suspend.c suspend_mod_CFLAGS = $(COMMON_CFLAGS) suspend_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For reboot.mod -reboot_mod_SOURCES = commands/reboot.c -reboot_mod_CFLAGS = $(COMMON_CFLAGS) -reboot_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For halt.mod halt_mod_SOURCES = commands/halt.c halt_mod_CFLAGS = $(COMMON_CFLAGS) halt_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For serial.mod. -serial_mod_SOURCES = term/i386/pc/serial.c -serial_mod_CFLAGS = $(COMMON_CFLAGS) -serial_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For linux.mod. linux_mod_SOURCES = loader/i386/ieee1275/linux.c linux_mod_CFLAGS = $(COMMON_CFLAGS) @@ -106,40 +72,10 @@ nand_mod_SOURCES = disk/ieee1275/nand.c nand_mod_CFLAGS = $(COMMON_CFLAGS) nand_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For memdisk.mod. -memdisk_mod_SOURCES = disk/memdisk.c -memdisk_mod_CFLAGS = $(COMMON_CFLAGS) -memdisk_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For pci.mod -pci_mod_SOURCES = bus/pci.c -pci_mod_CFLAGS = $(COMMON_CFLAGS) -pci_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For lspci.mod -lspci_mod_SOURCES = commands/lspci.c -lspci_mod_CFLAGS = $(COMMON_CFLAGS) -lspci_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For datetime.mod -datetime_mod_SOURCES = lib/i386/datetime.c +datetime_mod_SOURCES = lib/cmos_datetime.c datetime_mod_CFLAGS = $(COMMON_CFLAGS) datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For date.mod -date_mod_SOURCES = commands/date.c -date_mod_CFLAGS = $(COMMON_CFLAGS) -date_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For datehook.mod -datehook_mod_SOURCES = hook/datehook.c -datehook_mod_CFLAGS = $(COMMON_CFLAGS) -datehook_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For lsmmap.mod -lsmmap_mod_SOURCES = commands/lsmmap.c -lsmmap_mod_CFLAGS = $(COMMON_CFLAGS) -lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS) - include $(srcdir)/conf/i386.mk include $(srcdir)/conf/common.mk diff --git a/conf/i386-multiboot.rmk b/conf/i386-multiboot.rmk new file mode 100644 index 000000000..69b8e9a48 --- /dev/null +++ b/conf/i386-multiboot.rmk @@ -0,0 +1,74 @@ +# -*- makefile -*- + +COMMON_CFLAGS = -mrtd -mregparm=3 + +# Images. + +GRUB_KERNEL_MACHINE_LINK_ADDR = 0x8200 + +pkglib_PROGRAMS += kernel.img +kernel_img_SOURCES = kern/i386/coreboot/startup.S \ + kern/i386/misc.S \ + kern/i386/coreboot/init.c \ + kern/i386/multiboot_mmap.c \ + kern/i386/halt.c \ + kern/main.c kern/device.c \ + kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ + kern/misc.c kern/mm.c kern/term.c \ + kern/rescue_parser.c kern/rescue_reader.c \ + kern/time.c kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ + kern/$(target_cpu)/dl.c kern/parser.c kern/partition.c \ + kern/i386/tsc.c kern/i386/pit.c \ + kern/generic/rtc_get_time_ms.c \ + kern/generic/millisleep.c \ + kern/env.c \ + term/i386/pc/vga_text.c term/i386/vga_common.c \ + symlist.c +kernel_img_CFLAGS = $(COMMON_CFLAGS) +kernel_img_ASFLAGS = $(COMMON_ASFLAGS) +kernel_img_LDFLAGS += $(COMMON_LDFLAGS) -Wl,-N,-S,-Ttext,$(GRUB_KERNEL_MACHINE_LINK_ADDR),-Bstatic + +sbin_SCRIPTS += grub-install +grub_install_SOURCES = util/grub-install.in + +bin_SCRIPTS += grub-mkrescue +grub_mkrescue_SOURCES = util/grub-mkrescue.in + +# Modules. +pkglib_MODULES = linux.mod aout.mod halt.mod datetime.mod mmap.mod + +# For mmap.mod. +mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c +mmap_mod_CFLAGS = $(COMMON_CFLAGS) +mmap_mod_LDFLAGS = $(COMMON_LDFLAGS) +mmap_mod_ASFLAGS = $(COMMON_ASFLAGS) + +# For linux.mod. +linux_mod_SOURCES = loader/i386/linux.c +linux_mod_CFLAGS = $(COMMON_CFLAGS) +linux_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For halt.mod. +halt_mod_SOURCES = commands/halt.c +halt_mod_CFLAGS = $(COMMON_CFLAGS) +halt_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For aout.mod. +aout_mod_SOURCES = loader/aout.c +aout_mod_CFLAGS = $(COMMON_CFLAGS) +aout_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For bsd.mod +pkglib_MODULES += bsd.mod +bsd_mod_SOURCES = loader/i386/bsd.c loader/i386/bsd32.c loader/i386/bsd64.c loader/i386/bsd_helper.S loader/i386/bsd_trampoline.S +bsd_mod_CFLAGS = $(COMMON_CFLAGS) +bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) +bsd_mod_ASFLAGS = $(COMMON_ASFLAGS) + +# For datetime.mod +datetime_mod_SOURCES = lib/cmos_datetime.c +datetime_mod_CFLAGS = $(COMMON_CFLAGS) +datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) + +include $(srcdir)/conf/i386.mk +include $(srcdir)/conf/common.mk diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 8d373e30b..fa8394b52 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -1,17 +1,9 @@ # -*- makefile -*- -GRUB_KERNEL_MACHINE_LINK_ADDR = 0x8200 - -COMMON_ASFLAGS = -nostdinc -fno-builtin -m32 -COMMON_CFLAGS = -fno-builtin -mrtd -mregparm=3 -m32 -COMMON_LDFLAGS = -m32 -nostdlib - -# Used by various components. These rules need to precede them. -script/lexer.c_DEPENDENCIES = grub_script.tab.h +COMMON_CFLAGS = -mrtd -mregparm=3 # Images. -pkglib_IMAGES = boot.img cdboot.img diskboot.img kernel.img lnxboot.img \ - pxeboot.img +pkglib_IMAGES = boot.img cdboot.img diskboot.img lnxboot.img pxeboot.img # For boot.img. boot_img_SOURCES = boot/i386/pc/boot.S @@ -44,11 +36,12 @@ cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)0x7C00 cdboot_img_FORMAT = binary # For kernel.img. +pkglib_PROGRAMS = kernel.img kernel_img_SOURCES = kern/i386/pc/startup.S \ kern/i386/misc.S \ kern/main.c kern/device.c \ kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ - kern/misc.c kern/mm.c kern/reader.c kern/term.c \ + kern/misc.c kern/mm.c kern/term.c \ kern/rescue_parser.c kern/rescue_reader.c \ kern/time.c kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ kern/$(target_cpu)/dl.c kern/i386/pc/init.c kern/i386/pc/mmap.c \ @@ -59,54 +52,34 @@ kernel_img_SOURCES = kern/i386/pc/startup.S \ kern/env.c \ term/i386/pc/console.c term/i386/vga_common.c \ symlist.c -kernel_img_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ - env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ - partition.h msdos_partition.h reader.h symbol.h term.h time.h types.h \ - machine/biosdisk.h machine/boot.h machine/console.h machine/init.h \ - machine/memory.h machine/loader.h machine/vga.h machine/vbe.h \ - machine/kernel.h machine/pxe.h i386/pit.h list.h handler.h command.h i18n.h +kernel_img_HEADERS += machine/biosdisk.h machine/vga.h machine/vbe.h \ + machine/pxe.h i386/pit.h machine/kernel.h kernel_img_CFLAGS = $(COMMON_CFLAGS) $(TARGET_IMG_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -kernel_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)$(GRUB_KERNEL_MACHINE_LINK_ADDR) $(COMMON_CFLAGS) -kernel_img_FORMAT = binary - -MOSTLYCLEANFILES += symlist.c kernel_syms.lst -DEFSYMFILES += kernel_syms.lst - -symlist.c: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h gensymlist.sh - /bin/sh gensymlist.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) - -kernel_syms.lst: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h genkernsyms.sh - /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) +kernel_img_LDFLAGS += $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)0x8200 $(COMMON_CFLAGS) # Utilities. -bin_UTILITIES = grub-mkimage sbin_UTILITIES = grub-setup -# For grub-mkimage. -grub_mkimage_SOURCES = gnulib/progname.c util/i386/pc/grub-mkimage.c util/misc.c \ - util/resolve.c lib/LzmaEnc.c lib/LzFind.c -grub_mkimage_CFLAGS = -DGRUB_KERNEL_MACHINE_LINK_ADDR=$(GRUB_KERNEL_MACHINE_LINK_ADDR) -util/i386/pc/grub-mkimage.c_DEPENDENCIES = Makefile - # For grub-setup. util/i386/pc/grub-setup.c_DEPENDENCIES = grub_setup_init.h -grub_setup_SOURCES = gnulib/progname.c \ - util/i386/pc/grub-setup.c util/hostdisk.c \ - util/misc.c util/getroot.c kern/device.c kern/disk.c \ - kern/err.c kern/misc.c kern/parser.c kern/partition.c \ - kern/file.c kern/fs.c kern/env.c fs/fshelp.c \ - \ - fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \ - fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \ - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \ - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \ - fs/befs.c fs/befs_be.c fs/tar.c \ - \ - partmap/msdos.c partmap/gpt.c \ - \ - disk/raid.c disk/mdraid_linux.c disk/lvm.c \ - util/raid.c util/lvm.c \ +grub_setup_SOURCES = gnulib/progname.c util/i386/pc/grub-setup.c \ + util/misc.c kern/emu/misc.c kern/emu/getroot.c \ + kern/emu/hostdisk.c kern/device.c kern/disk.c kern/err.c \ + kern/misc.c kern/parser.c kern/partition.c kern/file.c \ + kern/emu/mm.c kern/fs.c kern/env.c kern/list.c fs/fshelp.c \ + \ + fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \ + fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \ + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \ + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \ + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \ + \ + partmap/msdos.c partmap/bsdlabel.c partmap/sunpc.c \ + partmap/gpt.c \ + \ + disk/raid.c disk/mdraid_linux.c disk/lvm.c \ + util/raid.c util/lvm.c \ grub_setup_init.c sbin_SCRIPTS += grub-install @@ -115,24 +88,15 @@ grub_install_SOURCES = util/grub-install.in bin_SCRIPTS += grub-mkrescue grub_mkrescue_SOURCES = util/grub-mkrescue.in -bin_SCRIPTS += grub-mkfloppy -grub_mkfloppy_SOURCES = util/i386/pc/grub-mkfloppy.in - pkglib_MODULES = biosdisk.mod chain.mod \ - multiboot.mod reboot.mod halt.mod \ - vbe.mod vbetest.mod vbeinfo.mod play.mod serial.mod \ - vga.mod memdisk.mod pci.mod lspci.mod \ - aout.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \ - datehook.mod lsmmap.mod ata_pthru.mod hdparm.mod \ + halt.mod \ + vbe.mod vbetest.mod vbeinfo.mod \ + vga.mod \ + aout.mod bsd.mod pxe.mod pxecmd.mod datetime.mod \ + ata_pthru.mod hdparm.mod \ usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod \ efiemu.mod mmap.mod acpi.mod drivemap.mod -# For boot.mod. -pkglib_MODULES += boot.mod -boot_mod_SOURCES = commands/boot.c lib/i386/pc/biosnum.c -boot_mod_CFLAGS = $(COMMON_CFLAGS) -boot_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For drivemap.mod. drivemap_mod_SOURCES = commands/i386/pc/drivemap.c \ commands/i386/pc/drivemap_int13h.S @@ -183,37 +147,17 @@ linux_mod_CFLAGS = $(COMMON_CFLAGS) linux_mod_LDFLAGS = $(COMMON_LDFLAGS) pkglib_MODULES += xnu.mod -xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/i386/pc/xnu.c\ - loader/macho.c loader/xnu.c loader/i386/xnu_helper.S +xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/i386/pc/xnu.c \ + loader/macho32.c loader/macho64.c loader/macho.c loader/xnu.c xnu_mod_CFLAGS = $(COMMON_CFLAGS) xnu_mod_LDFLAGS = $(COMMON_LDFLAGS) xnu_mod_ASFLAGS = $(COMMON_ASFLAGS) -# For reboot.mod. -reboot_mod_SOURCES = commands/reboot.c -reboot_mod_CFLAGS = $(COMMON_CFLAGS) -reboot_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For halt.mod. halt_mod_SOURCES = commands/i386/pc/halt.c halt_mod_CFLAGS = $(COMMON_CFLAGS) halt_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For serial.mod. -serial_mod_SOURCES = term/i386/pc/serial.c -serial_mod_CFLAGS = $(COMMON_CFLAGS) -serial_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For multiboot.mod. -multiboot_mod_SOURCES = loader/i386/multiboot.c \ - loader/i386/multiboot_helper.S \ - loader/i386/pc/multiboot2.c \ - loader/multiboot2.c \ - loader/multiboot_loader.c -multiboot_mod_CFLAGS = $(COMMON_CFLAGS) -multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) -multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS) - # For vbe.mod. vbe_mod_SOURCES = video/i386/pc/vbe.c vbe_mod_CFLAGS = $(COMMON_CFLAGS) @@ -229,31 +173,11 @@ vbetest_mod_SOURCES = commands/i386/pc/vbetest.c vbetest_mod_CFLAGS = $(COMMON_CFLAGS) vbetest_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For play.mod. -play_mod_SOURCES = commands/i386/pc/play.c -play_mod_CFLAGS = $(COMMON_CFLAGS) -play_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For vga.mod. -vga_mod_SOURCES = term/i386/pc/vga.c +vga_mod_SOURCES = video/i386/pc/vga.c vga_mod_CFLAGS = $(COMMON_CFLAGS) vga_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For memdisk.mod. -memdisk_mod_SOURCES = disk/memdisk.c -memdisk_mod_CFLAGS = $(COMMON_CFLAGS) -memdisk_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For pci.mod -pci_mod_SOURCES = bus/pci.c -pci_mod_CFLAGS = $(COMMON_CFLAGS) -pci_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For lspci.mod -lspci_mod_SOURCES = commands/lspci.c -lspci_mod_CFLAGS = $(COMMON_CFLAGS) -lspci_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For aout.mod aout_mod_SOURCES = loader/aout.c aout_mod_CFLAGS = $(COMMON_CFLAGS) @@ -306,25 +230,10 @@ pxecmd_mod_CFLAGS = $(COMMON_CFLAGS) pxecmd_mod_LDFLAGS = $(COMMON_LDFLAGS) # For datetime.mod -datetime_mod_SOURCES = lib/i386/datetime.c +datetime_mod_SOURCES = lib/cmos_datetime.c datetime_mod_CFLAGS = $(COMMON_CFLAGS) datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For date.mod -date_mod_SOURCES = commands/date.c -date_mod_CFLAGS = $(COMMON_CFLAGS) -date_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For datehook.mod -datehook_mod_SOURCES = hook/datehook.c -datehook_mod_CFLAGS = $(COMMON_CFLAGS) -datehook_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For lsmmap.mod -lsmmap_mod_SOURCES = commands/lsmmap.c -lsmmap_mod_CFLAGS = $(COMMON_CFLAGS) -lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For ata_pthru.mod. ata_pthru_mod_SOURCES = disk/ata_pthru.c ata_pthru_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/conf/i386-qemu.rmk b/conf/i386-qemu.rmk index 573a5d0f3..ff263245d 100644 --- a/conf/i386-qemu.rmk +++ b/conf/i386-qemu.rmk @@ -1,2 +1,82 @@ # -*- makefile -*- -include $(srcdir)/conf/i386-coreboot.mk + +COMMON_CFLAGS = -mrtd -mregparm=3 + +# Images. + +GRUB_KERNEL_MACHINE_LINK_ADDR = 0x8200 +GRUB_BOOT_MACHINE_LINK_ADDR = 0xffe00 + +pkglib_IMAGES += boot.img +boot_img_SOURCES = boot/i386/qemu/boot.S +boot_img_ASFLAGS = $(COMMON_ASFLAGS) -DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR) +boot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)$(GRUB_BOOT_MACHINE_LINK_ADDR) +boot_img_FORMAT = binary + +pkglib_PROGRAMS += kernel.img +kernel_img_SOURCES = kern/i386/qemu/startup.S \ + kern/i386/misc.S \ + kern/i386/coreboot/init.c \ + kern/i386/qemu/mmap.c \ + kern/i386/halt.c \ + kern/main.c kern/device.c \ + kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ + kern/misc.c kern/mm.c kern/term.c \ + kern/rescue_parser.c kern/rescue_reader.c \ + kern/time.c kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ + kern/$(target_cpu)/dl.c kern/parser.c kern/partition.c \ + kern/i386/tsc.c kern/i386/pit.c \ + kern/generic/rtc_get_time_ms.c \ + kern/generic/millisleep.c \ + kern/env.c \ + term/i386/pc/vga_text.c term/i386/vga_common.c \ + symlist.c +kernel_img_CFLAGS = $(COMMON_CFLAGS) -DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR) +kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -DGRUB_KERNEL_MACHINE_LINK_ADDR=$(GRUB_KERNEL_MACHINE_LINK_ADDR) +kernel_img_LDFLAGS += $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)$(GRUB_KERNEL_MACHINE_LINK_ADDR) +kernel_img_FORMAT = binary + +sbin_SCRIPTS += grub-install +grub_install_SOURCES = util/grub-install.in + +bin_SCRIPTS += grub-mkrescue +grub_mkrescue_SOURCES = util/grub-mkrescue.in + +# Modules. +pkglib_MODULES = linux.mod aout.mod halt.mod datetime.mod mmap.mod + +# For mmap.mod. +mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c +mmap_mod_CFLAGS = $(COMMON_CFLAGS) +mmap_mod_LDFLAGS = $(COMMON_LDFLAGS) +mmap_mod_ASFLAGS = $(COMMON_ASFLAGS) + +# For linux.mod. +linux_mod_SOURCES = loader/i386/linux.c +linux_mod_CFLAGS = $(COMMON_CFLAGS) +linux_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For halt.mod. +halt_mod_SOURCES = commands/halt.c +halt_mod_CFLAGS = $(COMMON_CFLAGS) +halt_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For aout.mod. +aout_mod_SOURCES = loader/aout.c +aout_mod_CFLAGS = $(COMMON_CFLAGS) +aout_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For bsd.mod +pkglib_MODULES += bsd.mod +bsd_mod_SOURCES = loader/i386/bsd.c loader/i386/bsd32.c loader/i386/bsd64.c loader/i386/bsd_helper.S loader/i386/bsd_trampoline.S +bsd_mod_CFLAGS = $(COMMON_CFLAGS) +bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) +bsd_mod_ASFLAGS = $(COMMON_ASFLAGS) + +# For datetime.mod +datetime_mod_SOURCES = lib/cmos_datetime.c +datetime_mod_CFLAGS = $(COMMON_CFLAGS) +datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) + +include $(srcdir)/conf/i386.mk +include $(srcdir)/conf/common.mk diff --git a/conf/i386.rmk b/conf/i386.rmk index bf102a9b6..02ce39817 100644 --- a/conf/i386.rmk +++ b/conf/i386.rmk @@ -6,7 +6,7 @@ cpuid_mod_CFLAGS = $(COMMON_CFLAGS) cpuid_mod_LDFLAGS = $(COMMON_LDFLAGS) pkglib_MODULES += at_keyboard.mod -at_keyboard_mod_SOURCES = term/i386/pc/at_keyboard.c +at_keyboard_mod_SOURCES = term/at_keyboard.c at_keyboard_mod_CFLAGS = $(COMMON_CFLAGS) at_keyboard_mod_LDFLAGS = $(COMMON_LDFLAGS) @@ -15,7 +15,61 @@ vga_text_mod_SOURCES = term/i386/pc/vga_text.c term/i386/vga_common.c vga_text_mod_CFLAGS = $(COMMON_CFLAGS) vga_text_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += relocator.mod +relocator_mod_SOURCES = lib/i386/relocator.c lib/i386/relocator_asm.S lib/i386/relocator_backward.S +relocator_mod_CFLAGS = $(COMMON_CFLAGS) +relocator_mod_ASFLAGS = $(COMMON_ASFLAGS) +relocator_mod_LDFLAGS = $(COMMON_LDFLAGS) + pkglib_MODULES += ata.mod ata_mod_SOURCES = disk/ata.c ata_mod_CFLAGS = $(COMMON_CFLAGS) ata_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For setpci.mod +pkglib_MODULES += setpci.mod +setpci_mod_SOURCES = commands/setpci.c +setpci_mod_CFLAGS = $(COMMON_CFLAGS) +setpci_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += multiboot.mod +multiboot_mod_SOURCES = loader/multiboot.c loader/i386/multiboot_mbi.c +multiboot_mod_CFLAGS = $(COMMON_CFLAGS) +multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) +multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS) + +pkglib_MODULES += multiboot2.mod +multiboot2_mod_SOURCES = loader/multiboot.c loader/multiboot_mbi2.c +multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) -DGRUB_USE_MULTIBOOT2 +multiboot2_mod_LDFLAGS = $(COMMON_LDFLAGS) +multiboot2_mod_ASFLAGS = $(COMMON_ASFLAGS) + +# For serial.mod. +pkglib_MODULES += serial.mod +serial_mod_SOURCES = term/serial.c +serial_mod_CFLAGS = $(COMMON_CFLAGS) +serial_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For pci.mod +pkglib_MODULES += pci.mod +pci_mod_SOURCES = bus/pci.c +pci_mod_CFLAGS = $(COMMON_CFLAGS) +pci_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For lspci.mod +pkglib_MODULES += lspci.mod +lspci_mod_SOURCES = commands/lspci.c +lspci_mod_CFLAGS = $(COMMON_CFLAGS) +lspci_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For play.mod. +pkglib_MODULES += play.mod +play_mod_SOURCES = commands/i386/pc/play.c +play_mod_CFLAGS = $(COMMON_CFLAGS) +play_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For iorw.mod. +pkglib_MODULES += iorw.mod +iorw_mod_SOURCES = commands/iorw.c +iorw_mod_CFLAGS = $(COMMON_CFLAGS) +iorw_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/conf/mips-qemu-mips.rmk b/conf/mips-qemu-mips.rmk new file mode 100644 index 000000000..2f80ab2e3 --- /dev/null +++ b/conf/mips-qemu-mips.rmk @@ -0,0 +1,22 @@ +# -*- makefile -*- +LINK_BASE = 0x80010000 +target_machine=qemu-mips +COMMON_CFLAGS += -march=mips3 +COMMON_ASFLAGS += -march=mips3 +include $(srcdir)/conf/mips.mk + +pkglib_PROGRAMS = kernel.img +kernel_img_SOURCES = kern/$(target_cpu)/startup.S \ + kern/main.c kern/device.c kern/$(target_cpu)/init.c \ + kern/$(target_cpu)/$(target_machine)/init.c \ + kern/disk.c kern/dl.c kern/err.c kern/file.c kern/fs.c \ + kern/misc.c kern/mm.c kern/term.c \ + kern/rescue_parser.c kern/rescue_reader.c \ + kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ + kern/parser.c kern/partition.c kern/env.c kern/$(target_cpu)/dl.c \ + kern/generic/millisleep.c kern/generic/rtc_get_time_ms.c kern/time.c \ + symlist.c kern/$(target_cpu)/cache.S +kernel_img_CFLAGS = $(COMMON_CFLAGS) +kernel_img_ASFLAGS = $(COMMON_ASFLAGS) +kernel_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-S,-Ttext,$(LINK_BASE),-Bstatic +kernel_img_FORMAT = binary diff --git a/conf/mips-yeeloong.rmk b/conf/mips-yeeloong.rmk new file mode 100644 index 000000000..5ce8ede9d --- /dev/null +++ b/conf/mips-yeeloong.rmk @@ -0,0 +1,73 @@ +# -*- makefile -*- +LINK_BASE = 0x80200000 +target_machine=yeeloong +COMMON_CFLAGS += -march=mips3 +COMMON_ASFLAGS += -march=mips3 + +kernel_img_HEADERS += pci.h bitmap.h video.h gfxterm.h font.h bitmap_scale.h bufio.h + +include $(srcdir)/conf/mips.mk + +pkglib_PROGRAMS = kernel.img +kernel_img_SOURCES = kern/$(target_cpu)/startup.S \ + kern/main.c kern/device.c kern/$(target_cpu)/init.c \ + kern/$(target_cpu)/$(target_machine)/init.c \ + kern/disk.c kern/dl.c kern/err.c kern/file.c kern/fs.c \ + kern/misc.c kern/mm.c kern/term.c \ + kern/rescue_parser.c kern/rescue_reader.c \ + kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ + kern/parser.c kern/partition.c kern/env.c kern/$(target_cpu)/dl.c \ + kern/generic/millisleep.c kern/generic/rtc_get_time_ms.c kern/time.c \ + kern/$(target_cpu)/cache.S \ + \ + term/at_keyboard.c \ + font/font_cmd.c font/font.c io/bufio.c \ + video/video.c video/fb/video_fb.c video/fb/fbblit.c \ + video/fb/fbfill.c video/fb/fbutil.c video/bitmap.c \ + video/bitmap_scale.c video/sm712.c bus/pci.c bus/bonito.c \ + term/gfxterm.c commands/extcmd.c lib/arg.c \ + symlist.c +kernel_img_CFLAGS = $(COMMON_CFLAGS) -DUSE_ASCII_FAILBACK +kernel_img_ASFLAGS = $(COMMON_ASFLAGS) +kernel_img_LDFLAGS += $(COMMON_LDFLAGS) -Wl,-N,-S,-Ttext,$(LINK_BASE),-Bstatic +kernel_img_FORMAT = binary + +# For ata.mod. +pkglib_MODULES += ata.mod +ata_mod_SOURCES = disk/ata.c +ata_mod_CFLAGS = $(COMMON_CFLAGS) +ata_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For lspci.mod +pkglib_MODULES += lspci.mod +lspci_mod_SOURCES = commands/lspci.c +lspci_mod_CFLAGS = $(COMMON_CFLAGS) +lspci_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For ata_pthru.mod. +pkglib_MODULES += ata_pthru.mod +ata_pthru_mod_SOURCES = disk/ata_pthru.c +ata_pthru_mod_CFLAGS = $(COMMON_CFLAGS) +ata_pthru_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For mmap.mod. +pkglib_MODULES += mmap.mod +mmap_mod_SOURCES = mmap/mmap.c mmap/mips/yeeloong/uppermem.c +mmap_mod_CFLAGS = $(COMMON_CFLAGS) +mmap_mod_LDFLAGS = $(COMMON_LDFLAGS) +mmap_mod_ASFLAGS = $(COMMON_ASFLAGS) + +# For datetime.mod +pkglib_MODULES += datetime.mod +datetime_mod_SOURCES = lib/cmos_datetime.c +datetime_mod_CFLAGS = $(COMMON_CFLAGS) +datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += linux.mod +linux_mod_SOURCES = loader/$(target_cpu)/linux.c +linux_mod_CFLAGS = $(COMMON_CFLAGS) +linux_mod_ASFLAGS = $(COMMON_ASFLAGS) +linux_mod_LDFLAGS = $(COMMON_LDFLAGS) + +sbin_SCRIPTS += grub-install +grub_install_SOURCES = util/grub-install.in diff --git a/conf/mips.rmk b/conf/mips.rmk new file mode 100644 index 000000000..7d30f55f1 --- /dev/null +++ b/conf/mips.rmk @@ -0,0 +1,33 @@ + +# -*- makefile -*- + +COMMON_CFLAGS += -mexplicit-relocs -mflush-func=grub_cpu_flush_cache + +# Images. +kernel_img_HEADERS += cpu/cache.h + +# Scripts. +sbin_SCRIPTS = +bin_SCRIPTS = + +# For serial.mod. +pkglib_MODULES += serial.mod +serial_mod_SOURCES = term/serial.c +serial_mod_CFLAGS = $(COMMON_CFLAGS) +serial_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For relocator.mod. +pkglib_MODULES += relocator.mod +relocator_mod_SOURCES = lib/$(target_cpu)/relocator.c lib/$(target_cpu)/relocator_asm.S +relocator_mod_CFLAGS = $(COMMON_CFLAGS) +relocator_mod_ASFLAGS = $(COMMON_ASFLAGS) +relocator_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += multiboot2.mod +multiboot2_mod_SOURCES = loader/multiboot.c \ + loader/multiboot_mbi2.c +multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) -DGRUB_USE_MULTIBOOT2 +multiboot2_mod_LDFLAGS = $(COMMON_LDFLAGS) +multiboot2_mod_ASFLAGS = $(COMMON_ASFLAGS) + +include $(srcdir)/conf/common.mk diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index 85b1fa211..d5968ac8e 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -1,29 +1,9 @@ # -*- makefile -*- -COMMON_ASFLAGS = -nostdinc -D__ASSEMBLY__ -COMMON_CFLAGS = -ffreestanding -COMMON_LDFLAGS += -nostdlib - -# Used by various components. These rules need to precede them. -script/lexer.c_DEPENDENCIES = grub_script.tab.h - # Images. -MOSTLYCLEANFILES += symlist.c kernel_syms.lst -DEFSYMFILES += kernel_syms.lst - -kernel_img_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ - env.h err.h file.h fs.h kernel.h misc.h mm.h net.h parser.h reader.h \ - symbol.h term.h time.h types.h powerpc/libgcc.h loader.h partition.h \ - msdos_partition.h ieee1275/ieee1275.h machine/kernel.h handler.h list.h \ - command.h i18n.h - -symlist.c: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h gensymlist.sh - /bin/sh gensymlist.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) - -kernel_syms.lst: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h genkernsyms.sh - /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) +kernel_img_HEADERS += ieee1275/ieee1275.h # Programs pkglib_PROGRAMS = kernel.img @@ -31,7 +11,7 @@ pkglib_PROGRAMS = kernel.img kernel_img_SOURCES = kern/powerpc/ieee1275/startup.S kern/ieee1275/cmain.c \ kern/ieee1275/ieee1275.c kern/main.c kern/device.c \ kern/disk.c kern/dl.c kern/err.c kern/file.c kern/fs.c \ - kern/misc.c kern/mm.c kern/reader.c kern/term.c \ + kern/misc.c kern/mm.c kern/term.c \ kern/rescue_parser.c kern/rescue_reader.c \ kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ kern/ieee1275/init.c \ @@ -43,8 +23,7 @@ kernel_img_SOURCES = kern/powerpc/ieee1275/startup.S kern/ieee1275/cmain.c \ symlist.c kern/$(target_cpu)/cache.S kernel_img_CFLAGS = $(COMMON_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -kernel_img_LDFLAGS = $(COMMON_LDFLAGS) -static-libgcc -lgcc \ - -Wl,-N,-S,-Ttext,0x200000,-Bstatic +kernel_img_LDFLAGS += $(COMMON_LDFLAGS) -Wl,-N,-S,-Ttext,0x200000,-Bstatic # Scripts. sbin_SCRIPTS = grub-install @@ -57,55 +36,33 @@ grub_install_SOURCES = util/ieee1275/grub-install.in grub_mkrescue_SOURCES = util/powerpc/ieee1275/grub-mkrescue.in # Modules. -pkglib_MODULES = halt.mod \ - linux.mod \ - reboot.mod \ - suspend.mod \ - multiboot.mod \ - memdisk.mod \ - lsmmap.mod - -# For boot.mod. -pkglib_MODULES += boot.mod -boot_mod_SOURCES = commands/boot.c lib/i386/pc/biosnum.c -boot_mod_CFLAGS = $(COMMON_CFLAGS) -boot_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += ieee1275_fb.mod +ieee1275_fb_mod_SOURCES = video/ieee1275.c +ieee1275_fb_mod_CFLAGS = $(COMMON_CFLAGS) +ieee1275_fb_mod_LDFLAGS = $(COMMON_LDFLAGS) # For linux.mod. +pkglib_MODULES += linux.mod linux_mod_SOURCES = loader/powerpc/ieee1275/linux.c linux_mod_CFLAGS = $(COMMON_CFLAGS) linux_mod_LDFLAGS = $(COMMON_LDFLAGS) # For suspend.mod +pkglib_MODULES += suspend.mod suspend_mod_SOURCES = commands/ieee1275/suspend.c suspend_mod_CFLAGS = $(COMMON_CFLAGS) suspend_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For reboot.mod -reboot_mod_SOURCES = commands/reboot.c -reboot_mod_CFLAGS = $(COMMON_CFLAGS) -reboot_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For halt.mod +pkglib_MODULES += halt.mod halt_mod_SOURCES = commands/halt.c halt_mod_CFLAGS = $(COMMON_CFLAGS) halt_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For multiboot.mod -multiboot_mod_SOURCES = loader/ieee1275/multiboot2.c \ - loader/multiboot2.c \ - loader/multiboot_loader.c -multiboot_mod_CFLAGS = $(COMMON_CFLAGS) -multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For memdisk.mod. -memdisk_mod_SOURCES = disk/memdisk.c -memdisk_mod_CFLAGS = $(COMMON_CFLAGS) -memdisk_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For lsmmap.mod -lsmmap_mod_SOURCES = commands/lsmmap.c -lsmmap_mod_CFLAGS = $(COMMON_CFLAGS) -lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For datetime.mod +pkglib_MODULES += datetime.mod +datetime_mod_SOURCES = lib/ieee1275/datetime.c +datetime_mod_CFLAGS = $(COMMON_CFLAGS) +datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) include $(srcdir)/conf/common.mk diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk index d19e927a5..0aac67104 100644 --- a/conf/sparc64-ieee1275.rmk +++ b/conf/sparc64-ieee1275.rmk @@ -1,15 +1,12 @@ # -*- makefile -*- -COMMON_ASFLAGS = -nostdinc -m64 -COMMON_CFLAGS = -ffreestanding -m64 -mno-app-regs -COMMON_LDFLAGS = -melf64_sparc -nostdlib -mno-relax - -# Used by various components. These rules need to precede them. -script/lexer.c_DEPENDENCIES = grub_script.tab.h +COMMON_CFLAGS = -mno-app-regs +COMMON_LDFLAGS = -melf64_sparc -mno-relax # Images. -pkglib_IMAGES = boot.img diskboot.img kernel.img +pkglib_IMAGES = boot.img diskboot.img +pkglib_PROGRAMS = kernel.img # For boot.img. boot_img_SOURCES = boot/sparc64/ieee1275/boot.S @@ -23,19 +20,11 @@ diskboot_img_ASFLAGS = $(COMMON_ASFLAGS) diskboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,0x4200 diskboot_img_FORMAT = binary -MOSTLYCLEANFILES += symlist.c kernel_syms.lst -DEFSYMFILES += kernel_syms.lst - -kernel_img_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ - env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ - partition.h msdos_partition.h reader.h symbol.h term.h time.h types.h \ - list.h handler.h command.h i18n.h \ - sparc64/libgcc.h ieee1275/ieee1275.h machine/kernel.h \ - sparc64/ieee1275/ieee1275.h +kernel_img_HEADERS += ieee1275/ieee1275.h cpu/ieee1275/ieee1275.h kernel_img_SOURCES = kern/sparc64/ieee1275/crt0.S kern/ieee1275/cmain.c \ kern/ieee1275/ieee1275.c kern/main.c kern/device.c \ kern/disk.c kern/dl.c kern/err.c kern/file.c kern/fs.c \ - kern/misc.c kern/mm.c kern/reader.c kern/term.c \ + kern/misc.c kern/mm.c kern/term.c \ kern/rescue_parser.c kern/rescue_reader.c \ kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ kern/sparc64/ieee1275/ieee1275.c \ @@ -48,89 +37,66 @@ kernel_img_SOURCES = kern/sparc64/ieee1275/crt0.S kern/ieee1275/cmain.c \ symlist.c kern/$(target_cpu)/cache.S kernel_img_CFLAGS = $(COMMON_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -kernel_img_LDFLAGS = -nostdlib -Wl,-N,-Ttext,0x200000,-Bstatic,-melf64_sparc -static-libgcc -lgcc +kernel_img_LDFLAGS += -nostdlib -Wl,-N,-Ttext,0x4400,-Bstatic,-melf64_sparc kernel_img_FORMAT = binary -symlist.c: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h gensymlist.sh - /bin/sh gensymlist.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) - -kernel_syms.lst: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h genkernsyms.sh - /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) - # Utilities. -bin_UTILITIES = grub-mkimage sbin_UTILITIES = grub-setup grub-ofpathname -# For grub-mkimage. -grub_mkimage_SOURCES = util/sparc64/ieee1275/grub-mkimage.c util/misc.c \ - util/resolve.c gnulib/progname.c - # For grub-setup. util/sparc64/ieee1275/grub-setup.c_DEPENDENCIES = grub_setup_init.h -grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c \ - util/misc.c util/getroot.c kern/device.c kern/disk.c \ - kern/err.c kern/misc.c kern/parser.c kern/partition.c \ - kern/file.c kern/fs.c kern/env.c fs/fshelp.c \ - \ - fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \ - fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \ - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \ - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \ - fs/befs.c fs/befs_be.c fs/tar.c \ - \ - partmap/amiga.c partmap/apple.c partmap/msdos.c \ - partmap/sun.c partmap/acorn.c \ - \ - disk/raid.c disk/mdraid_linux.c disk/lvm.c \ - util/raid.c util/lvm.c gnulib/progname.c \ - grub_setup_init.c +grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c \ + util/ieee1275/ofpath.c util/misc.c kern/emu/hostdisk.c \ + kern/emu/misc.c kern/emu/getroot.c kern/emu/mm.c kern/device.c \ + kern/disk.c kern/err.c kern/misc.c kern/parser.c \ + kern/partition.c kern/file.c kern/fs.c kern/env.c kern/list.c \ + fs/fshelp.c \ + \ + fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \ + fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \ + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \ + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \ + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \ + \ + partmap/amiga.c partmap/apple.c partmap/msdos.c \ + partmap/bsdlabel.c partmap/sun.c partmap/acorn.c \ + \ + disk/raid.c disk/mdraid_linux.c disk/lvm.c util/raid.c \ + util/lvm.c gnulib/progname.c grub_setup_init.c # For grub-ofpathname. -grub_ofpathname_SOURCES = util/sparc64/ieee1275/grub-ofpathname.c \ - util/ieee1275/ofpath.c util/misc.c gnulib/progname.c +grub_ofpathname_SOURCES = util/ieee1275/grub-ofpathname.c \ + util/ieee1275/ofpath.c util/misc.c kern/emu/misc.c \ + gnulib/progname.c # Scripts. sbin_SCRIPTS = grub-install # For grub-install. -grub_install_SOURCES = util/sparc64/ieee1275/grub-install.in +grub_install_SOURCES = util/grub-install.in # Modules. -pkglib_MODULES = halt.mod \ - linux.mod \ - reboot.mod \ - memdisk.mod \ - lsmmap.mod - -# For boot.mod. -pkglib_MODULES += boot.mod -boot_mod_SOURCES = commands/boot.c lib/i386/pc/biosnum.c -boot_mod_CFLAGS = $(COMMON_CFLAGS) -boot_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += ieee1275_fb.mod +ieee1275_fb_mod_SOURCES = video/ieee1275.c +ieee1275_fb_mod_CFLAGS = $(COMMON_CFLAGS) +ieee1275_fb_mod_LDFLAGS = $(COMMON_LDFLAGS) # For linux.mod. +pkglib_MODULES += linux.mod linux_mod_SOURCES = loader/sparc64/ieee1275/linux.c linux_mod_CFLAGS = $(COMMON_CFLAGS) linux_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For reboot.mod. -reboot_mod_SOURCES = commands/reboot.c -reboot_mod_CFLAGS = $(COMMON_CFLAGS) -reboot_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For halt.mod. +pkglib_MODULES += halt.mod halt_mod_SOURCES = commands/halt.c halt_mod_CFLAGS = $(COMMON_CFLAGS) halt_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For memdisk.mod. -memdisk_mod_SOURCES = disk/memdisk.c -memdisk_mod_CFLAGS = $(COMMON_CFLAGS) -memdisk_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For lsmmap.mod -lsmmap_mod_SOURCES = commands/lsmmap.c -lsmmap_mod_CFLAGS = $(COMMON_CFLAGS) -lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For datetime.mod +pkglib_MODULES += datetime.mod +datetime_mod_SOURCES = lib/ieee1275/datetime.c +datetime_mod_CFLAGS = $(COMMON_CFLAGS) +datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) include $(srcdir)/conf/common.mk diff --git a/conf/tests.rmk b/conf/tests.rmk new file mode 100644 index 000000000..9af2f8f86 --- /dev/null +++ b/conf/tests.rmk @@ -0,0 +1,94 @@ +# -*- makefile -*- + +# For grub-shell +grub-shell: tests/util/grub-shell.in config.status + ./config.status --file=$@:$< + chmod +x $@ +check_SCRIPTS += grub-shell +CLEANFILES += grub-shell + +# For grub-shell-tester +grub-shell-tester: tests/util/grub-shell-tester.in config.status + ./config.status --file=$@:$< + chmod +x $@ +check_SCRIPTS += grub-shell-tester +CLEANFILES += grub-shell-tester + +pkglib_MODULES += functional_test.mod +functional_test_mod_SOURCES = tests/lib/functional_test.c tests/lib/test.c +functional_test_mod_CFLAGS = $(COMMON_CFLAGS) +functional_test_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# Rules for unit tests +check_UTILITIES += example_unit_test +example_unit_test_SOURCES = tests/example_unit_test.c kern/list.c kern/misc.c tests/lib/test.c tests/lib/unit_test.c +example_unit_test_CFLAGS = -Wno-format + +# Rules for functional tests +pkglib_MODULES += example_functional_test.mod +example_functional_test_mod_SOURCES = tests/example_functional_test.c +example_functional_test_mod_CFLAGS = -Wno-format $(COMMON_CFLAGS) +example_functional_test_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# Rules for scripted tests +check_SCRIPTS += example_scripted_test +example_scripted_test_SOURCES = tests/example_scripted_test.in + +check_SCRIPTS += example_grub_script_test +example_grub_script_test_SOURCES = tests/example_grub_script_test.in + +# +# Rules for real tests +# + +check_SCRIPTS += grub_script_echo1 +grub_script_echo1_SOURCES = tests/grub_script_echo1.in + +check_SCRIPTS += grub_script_echo_keywords +grub_script_echo_keywords_SOURCES = tests/grub_script_echo_keywords.in + +check_SCRIPTS += grub_script_vars1 +grub_script_vars1_SOURCES = tests/grub_script_vars1.in + +check_SCRIPTS += grub_script_for1 +grub_script_for1_SOURCES = tests/grub_script_for1.in + +check_SCRIPTS += grub_script_while1 +grub_script_while1_SOURCES = tests/grub_script_while1.in + +check_SCRIPTS += grub_script_if +grub_script_if_SOURCES = tests/grub_script_if.in + +check_SCRIPTS += grub_script_blanklines +grub_script_blanklines_SOURCES = tests/grub_script_blanklines.in + +check_SCRIPTS += grub_script_final_semicolon +grub_script_final_semicolon_SOURCES = tests/grub_script_final_semicolon.in + +check_SCRIPTS += grub_script_dollar +grub_script_dollar_SOURCES = tests/grub_script_dollar.in + +check_SCRIPTS += grub_script_comments +grub_script_comments_SOURCES = tests/grub_script_comments.in + +# List of tests to execute on "make check" +# SCRIPTED_TESTS = example_scripted_test +# SCRIPTED_TESTS += example_grub_script_test +# UNIT_TESTS = example_unit_test +# FUNCTIONAL_TESTS = example_functional_test.mod + +SCRIPTED_TESTS = grub_script_echo1 +SCRIPTED_TESTS += grub_script_echo_keywords +SCRIPTED_TESTS += grub_script_vars1 +SCRIPTED_TESTS += grub_script_for1 +SCRIPTED_TESTS += grub_script_while1 +SCRIPTED_TESTS += grub_script_if +SCRIPTED_TESTS += grub_script_blanklines +SCRIPTED_TESTS += grub_script_final_semicolon +SCRIPTED_TESTS += grub_script_dollar +SCRIPTED_TESTS += grub_script_comments + +# dependencies between tests and testing-tools +$(SCRIPTED_TESTS): grub-shell grub-shell-tester +$(FUNCTIONAL_TESTS): functional_test.mod + diff --git a/conf/x86-efi.rmk b/conf/x86-efi.rmk new file mode 100644 index 000000000..1011a3e64 --- /dev/null +++ b/conf/x86-efi.rmk @@ -0,0 +1,112 @@ +# -*- makefile -*- + +# Scripts. +sbin_SCRIPTS = grub-install + +# For grub-install. +grub_install_SOURCES = util/i386/efi/grub-install.in + +bin_SCRIPTS += grub-mkrescue +grub_mkrescue_SOURCES = util/grub-mkrescue.in + +# Modules. +pkglib_PROGRAMS = kernel.img +pkglib_MODULES = chain.mod appleldr.mod \ + linux.mod halt.mod \ + datetime.mod loadbios.mod \ + fixvideo.mod mmap.mod acpi.mod + +# For kernel.img. +kernel_img_RELOCATABLE = yes +kernel_img_SOURCES = kern/$(target_cpu)/efi/startup.S kern/main.c kern/device.c \ + kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ + kern/misc.c kern/mm.c kern/term.c \ + kern/rescue_parser.c kern/rescue_reader.c \ + kern/$(target_cpu)/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \ + kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \ + term/efi/console.c disk/efi/efidisk.c \ + kern/time.c kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ + kern/i386/tsc.c kern/i386/pit.c \ + kern/generic/rtc_get_time_ms.c \ + kern/generic/millisleep.c +ifeq ($(target_cpu),x86_64) +kernel_img_SOURCES += kern/x86_64/efi/callwrap.S +endif +kernel_img_HEADERS += efi/efi.h efi/time.h efi/disk.h i386/pit.h +kernel_img_CFLAGS = $(COMMON_CFLAGS) +kernel_img_ASFLAGS = $(COMMON_ASFLAGS) +kernel_img_LDFLAGS += $(COMMON_LDFLAGS) + +# For acpi.mod. +acpi_mod_SOURCES = commands/acpi.c commands/efi/acpi.c +acpi_mod_CFLAGS = $(COMMON_CFLAGS) +acpi_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For mmap.mod. +mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \ + mmap/efi/mmap.c +mmap_mod_CFLAGS = $(COMMON_CFLAGS) +mmap_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For chain.mod. +chain_mod_SOURCES = loader/efi/chainloader.c +chain_mod_CFLAGS = $(COMMON_CFLAGS) +chain_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For appleldr.mod. +appleldr_mod_SOURCES = loader/efi/appleloader.c +appleldr_mod_CFLAGS = $(COMMON_CFLAGS) +appleldr_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For linux.mod. +ifeq ($(target_cpu), x86_64) +linux_mod_SOURCES = loader/i386/efi/linux.c loader/i386/linux_trampoline.S +linux_mod_CFLAGS = $(COMMON_CFLAGS) +linux_mod_ASFLAGS = $(COMMON_ASFLAGS) +linux_mod_LDFLAGS = $(COMMON_LDFLAGS) +else +linux_mod_SOURCES = loader/i386/efi/linux.c +linux_mod_CFLAGS = $(COMMON_CFLAGS) +linux_mod_ASFLAGS = $(COMMON_ASFLAGS) +linux_mod_LDFLAGS = $(COMMON_LDFLAGS) +endif + +# For halt.mod. +halt_mod_SOURCES = commands/halt.c +halt_mod_CFLAGS = $(COMMON_CFLAGS) +halt_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For datetime.mod +datetime_mod_SOURCES = lib/efi/datetime.c +datetime_mod_CFLAGS = $(COMMON_CFLAGS) +datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For loadbios.mod +loadbios_mod_SOURCES = commands/efi/loadbios.c +loadbios_mod_CFLAGS = $(COMMON_CFLAGS) +loadbios_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For fixvideo.mod +fixvideo_mod_SOURCES = commands/efi/fixvideo.c +fixvideo_mod_CFLAGS = $(COMMON_CFLAGS) +fixvideo_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += efi_uga.mod +efi_uga_mod_SOURCES = video/efi_uga.c +efi_uga_mod_CFLAGS = $(COMMON_CFLAGS) +efi_uga_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += efi_gop.mod +efi_gop_mod_SOURCES = video/efi_gop.c +efi_gop_mod_CFLAGS = $(COMMON_CFLAGS) +efi_gop_mod_LDFLAGS = $(COMMON_LDFLAGS) + +pkglib_MODULES += xnu.mod +xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/i386/efi/xnu.c \ + loader/macho32.c loader/macho64.c loader/macho.c loader/xnu.c +xnu_mod_CFLAGS = $(COMMON_CFLAGS) +xnu_mod_LDFLAGS = $(COMMON_LDFLAGS) +xnu_mod_ASFLAGS = $(COMMON_ASFLAGS) + +include $(srcdir)/conf/i386.mk +include $(srcdir)/conf/common.mk diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index 47a2e41e5..200621280 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -1,169 +1,5 @@ # -*- makefile -*- -COMMON_ASFLAGS = -nostdinc -fno-builtin -m64 -COMMON_CFLAGS = -fno-builtin -m64 -COMMON_LDFLAGS = -melf_x86_64 -nostdlib +COMMON_LDFLAGS = -melf_x86_64 -# Used by various components. These rules need to precede them. -script/lexer.c_DEPENDENCIES = grub_script.tab.h - -# Utilities. -bin_UTILITIES = grub-mkimage - -# For grub-mkimage. -grub_mkimage_SOURCES = gnulib/progname.c util/i386/efi/grub-mkimage.c \ - util/misc.c util/resolve.c - -# For grub-setup. -#grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c \ -# util/misc.c util/getroot.c kern/device.c kern/disk.c \ -# kern/err.c kern/misc.c fs/fat.c fs/ext2.c fs/xfs.c fs/affs.c \ -# fs/sfs.c kern/parser.c kern/partition.c partmap/msdos.c \ -# fs/ufs.c fs/ufs2.c fs/minix.c fs/hfs.c fs/jfs.c fs/hfsplus.c kern/file.c \ -# kern/fs.c kern/env.c fs/fshelp.c - -# Scripts. -sbin_SCRIPTS = grub-install - -# For grub-install. -grub_install_SOURCES = util/i386/efi/grub-install.in - -# Modules. -pkglib_MODULES = kernel.img chain.mod appleldr.mod \ - halt.mod reboot.mod linux.mod pci.mod lspci.mod \ - datetime.mod date.mod datehook.mod loadbios.mod \ - fixvideo.mod mmap.mod acpi.mod ata.mod - -# For kernel.img. -kernel_img_EXPORTS = no -kernel_img_SOURCES = kern/x86_64/efi/startup.S kern/x86_64/efi/callwrap.S \ - kern/main.c kern/device.c \ - kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ - kern/misc.c kern/mm.c kern/reader.c kern/term.c \ - kern/rescue_parser.c kern/rescue_reader.c \ - kern/$(target_cpu)/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \ - kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \ - kern/time.c kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ - kern/i386/tsc.c kern/i386/pit.c \ - kern/generic/millisleep.c kern/generic/rtc_get_time_ms.c \ - term/efi/console.c disk/efi/efidisk.c -kernel_img_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ - env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ - partition.h msdos_partition.h reader.h symbol.h term.h time.h types.h \ - efi/efi.h efi/time.h efi/disk.h machine/loader.h i386/pit.h list.h \ - handler.h command.h i18n.h -kernel_img_CFLAGS = $(COMMON_CFLAGS) -kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -kernel_img_LDFLAGS = $(COMMON_LDFLAGS) - -MOSTLYCLEANFILES += symlist.c -MOSTLYCLEANFILES += symlist.c kernel_syms.lst -DEFSYMFILES += kernel_syms.lst - -symlist.c: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h gensymlist.sh - /bin/sh gensymlist.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) - -kernel_syms.lst: $(addprefix include/grub/,$(kernel_img_HEADERS)) config.h genkernsyms.sh - /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) - -# For boot.mod. -pkglib_MODULES += boot.mod -boot_mod_SOURCES = commands/boot.c lib/i386/pc/biosnum.c -boot_mod_CFLAGS = $(COMMON_CFLAGS) -boot_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For acpi.mod. -acpi_mod_SOURCES = commands/acpi.c commands/efi/acpi.c -acpi_mod_CFLAGS = $(COMMON_CFLAGS) -acpi_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For ata.mod -ata_mod_SOURCES = disk/ata.c -ata_mod_CFLAGS = $(COMMON_CFLAGS) -ata_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For mmap.mod. -mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \ - mmap/efi/mmap.c -mmap_mod_CFLAGS = $(COMMON_CFLAGS) -mmap_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For chain.mod. -chain_mod_SOURCES = loader/efi/chainloader.c -chain_mod_CFLAGS = $(COMMON_CFLAGS) -chain_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For appleldr.mod. -appleldr_mod_SOURCES = loader/efi/appleloader.c -appleldr_mod_CFLAGS = $(COMMON_CFLAGS) -appleldr_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For linux.mod. -linux_mod_SOURCES = loader/i386/efi/linux.c loader/i386/linux_trampoline.S -linux_mod_CFLAGS = $(COMMON_CFLAGS) -linux_mod_ASFLAGS = $(COMMON_ASFLAGS) -linux_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For halt.mod. -halt_mod_SOURCES = commands/halt.c -halt_mod_CFLAGS = $(COMMON_CFLAGS) -halt_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For reboot.mod. -reboot_mod_SOURCES = commands/reboot.c -reboot_mod_CFLAGS = $(COMMON_CFLAGS) -reboot_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For pci.mod -pci_mod_SOURCES = bus/pci.c -pci_mod_CFLAGS = $(COMMON_CFLAGS) -pci_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For lspci.mod -lspci_mod_SOURCES = commands/lspci.c -lspci_mod_CFLAGS = $(COMMON_CFLAGS) -lspci_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For datetime.mod -datetime_mod_SOURCES = lib/efi/datetime.c -datetime_mod_CFLAGS = $(COMMON_CFLAGS) -datetime_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For date.mod -date_mod_SOURCES = commands/date.c -date_mod_CFLAGS = $(COMMON_CFLAGS) -date_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For datehook.mod -datehook_mod_SOURCES = hook/datehook.c -datehook_mod_CFLAGS = $(COMMON_CFLAGS) -datehook_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For loadbios.mod -loadbios_mod_SOURCES = commands/efi/loadbios.c -loadbios_mod_CFLAGS = $(COMMON_CFLAGS) -loadbios_mod_LDFLAGS = $(COMMON_LDFLAGS) - -# For fixvideo.mod -fixvideo_mod_SOURCES = commands/efi/fixvideo.c -fixvideo_mod_CFLAGS = $(COMMON_CFLAGS) -fixvideo_mod_LDFLAGS = $(COMMON_LDFLAGS) - -pkglib_MODULES += efi_uga.mod -efi_uga_mod_SOURCES = video/efi_uga.c -efi_uga_mod_CFLAGS = $(COMMON_CFLAGS) -efi_uga_mod_LDFLAGS = $(COMMON_LDFLAGS) - -pkglib_MODULES += efi_gop.mod -efi_gop_mod_SOURCES = video/efi_gop.c -efi_gop_mod_CFLAGS = $(COMMON_CFLAGS) -efi_gop_mod_LDFLAGS = $(COMMON_LDFLAGS) - -pkglib_MODULES += xnu.mod -xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/i386/efi/xnu.c\ - loader/macho.c loader/xnu.c loader/i386/xnu_helper.S -xnu_mod_CFLAGS = $(COMMON_CFLAGS) -xnu_mod_LDFLAGS = $(COMMON_LDFLAGS) -xnu_mod_ASFLAGS = $(COMMON_ASFLAGS) - -include $(srcdir)/conf/common.mk +include $(srcdir)/conf/x86-efi.mk diff --git a/config.rpath b/config.rpath new file mode 100755 index 000000000..85c2f209b --- /dev/null +++ b/config.rpath @@ -0,0 +1,672 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2008 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit , 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's _LT_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + darwin*) + case $cc_basename in + xlc*) + wl='-Wl,' + ;; + esac + ;; + mingw* | cygwin* | pw32* | os2* | cegcc*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + newsos6) + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + ecc*) + wl='-Wl,' + ;; + icc* | ifort*) + wl='-Wl,' + ;; + lf95*) + wl='-Wl,' + ;; + pgcc | pgf77 | pgf90) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + rdos*) + ;; + solaris*) + wl='-Wl,' + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + wl='-Wl,' + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's _LT_LINKER_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we cannot use + # them. + ld_shlibs=no + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32* | cegcc*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + interix[3-9]*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if test "$GCC" = yes ; then + : + else + case $cc_basename in + xlc*) + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd1*) + ld_shlibs=no + ;; + freebsd2.2*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + freebsd2*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. +# Unlike libtool.m4, here we don't care about _all_ names of the library, but +# only about the one the linker finds when passed -lNAME. This is the last +# element of library_names_spec in libtool.m4, or possibly two of them if the +# linker has special search rules. +library_names_spec= # the last element of library_names_spec in libtool.m4 +libname_spec='lib$name' +case "$host_os" in + aix3*) + library_names_spec='$libname.a' + ;; + aix[4-9]*) + library_names_spec='$libname$shrext' + ;; + amigaos*) + library_names_spec='$libname.a' + ;; + beos*) + library_names_spec='$libname$shrext' + ;; + bsdi[45]*) + library_names_spec='$libname$shrext' + ;; + cygwin* | mingw* | pw32* | cegcc*) + shrext=.dll + library_names_spec='$libname.dll.a $libname.lib' + ;; + darwin* | rhapsody*) + shrext=.dylib + library_names_spec='$libname$shrext' + ;; + dgux*) + library_names_spec='$libname$shrext' + ;; + freebsd1*) + ;; + freebsd* | dragonfly*) + case "$host_os" in + freebsd[123]*) + library_names_spec='$libname$shrext$versuffix' ;; + *) + library_names_spec='$libname$shrext' ;; + esac + ;; + gnu*) + library_names_spec='$libname$shrext' + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + library_names_spec='$libname$shrext' + ;; + interix[3-9]*) + library_names_spec='$libname$shrext' + ;; + irix5* | irix6* | nonstopux*) + library_names_spec='$libname$shrext' + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux* | k*bsd*-gnu) + library_names_spec='$libname$shrext' + ;; + knetbsd*-gnu) + library_names_spec='$libname$shrext' + ;; + netbsd*) + library_names_spec='$libname$shrext' + ;; + newsos6) + library_names_spec='$libname$shrext' + ;; + nto-qnx*) + library_names_spec='$libname$shrext' + ;; + openbsd*) + library_names_spec='$libname$shrext$versuffix' + ;; + os2*) + libname_spec='$name' + shrext=.dll + library_names_spec='$libname.a' + ;; + osf3* | osf4* | osf5*) + library_names_spec='$libname$shrext' + ;; + rdos*) + ;; + solaris*) + library_names_spec='$libname$shrext' + ;; + sunos4*) + library_names_spec='$libname$shrext$versuffix' + ;; + sysv4 | sysv4.3*) + library_names_spec='$libname$shrext' + ;; + sysv4*MP*) + library_names_spec='$libname$shrext' + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + library_names_spec='$libname$shrext' + ;; + uts4*) + library_names_spec='$libname$shrext' + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' < +int va_arg_func (int fixed, va_list args);]], [[]])], + [grub_cv_cc_isystem=yes], + [grub_cv_cc_isystem=no]) + CPPFLAGS="$SAVED_CPPFLAGS" +]) + +if test x"$grub_cv_cc_isystem" = xyes ; then + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -nostdinc -isystem `$TARGET_CC -print-file-name=include`" +fi +fi # Restore the flags. CC="$tmp_CC" @@ -526,6 +601,18 @@ AC_ARG_ENABLE([grub-emu-usb], [AS_HELP_STRING([--enable-grub-emu-usb], [build and install the `grub-emu' debugging utility with USB support (default=guessed)])]) +AC_ARG_ENABLE([grub-emu-sdl], + [AS_HELP_STRING([--enable-grub-emu-sdl], + [build and install the `grub-emu' debugging utility with SDL support (default=guessed)])]) + +AC_ARG_ENABLE([grub-emu-pci], + [AS_HELP_STRING([--enable-grub-emu-pci], + [build and install the `grub-emu' debugging utility with PCI support (potentially dangerous) (default=no)])]) + +AC_ARG_ENABLE([grub-emu-modules], + [AS_HELP_STRING([--enable-grub-emu-modules], + [Support module loading in `grub-emu' debugging utility (default=no)])]) + if test "$platform" = emu; then missing_ncurses= [# Check for curses libraries.] @@ -544,9 +631,27 @@ if test x"$missing_ncurses" = xtrue ; then AC_MSG_ERROR([grub-emu can't be compiled without ncurses]) fi +if test x"$enable_grub_emu_modules" = xyes ; then + TARGET_NO_MODULES=no +else + TARGET_NO_MODULES=yes +fi +AC_SUBST(TARGET_NO_MODULES) + +if test "$TARGET_NO_MODULES" = yes ; then + # Do not convert modules, otherwise linkage may fail (Cygwin only). + # FIXME: Should be checked above before TARGET_OBJ2ELF is set first. + TARGET_OBJ2ELF= +fi + if test x"$enable_grub_emu_usb" = xno ; then grub_emu_usb_excuse="explicitly disabled" fi + +if test x"$enable_grub_emu_pci" = xyes ; then + grub_emu_usb_excuse="conflicts with PCI support" +fi + [if [ x"$grub_emu_usb_excuse" = x ]; then # Check for libusb libraries.] AC_CHECK_LIB([usb], [usb_claim_interface], [LIBUSB="-lusb"], @@ -566,7 +671,62 @@ enable_grub_emu_usb=yes else enable_grub_emu_usb=no fi + +if test x"$enable_grub_emu_sdl" = xno ; then + grub_emu_sdl_excuse="explicitely disabled" +fi +[if [ x"$grub_emu_sdl_excuse" = x ]; then + # Check for libSDL libraries.] +AC_CHECK_LIB([SDL], [SDL_Init], [LIBSDL="-lSDL"], + [grub_emu_sdl_excuse=["libSDL libraries are required to build \`grub-emu' with SDL support"]]) + AC_SUBST([LIBSDL]) +[fi] + +[if [ x"$grub_emu_sdl_excuse" = x ]; then + # Check for headers.] + AC_CHECK_HEADERS([SDL/SDL.h], [], + [grub_emu_sdl_excuse=["libSDL header file is required to build \`grub-emu' with SDL support"]]) +[fi] + +if test x"enable_grub_emu_sdl" = xyes && test x"$grub_emu_sdl_excuse" != x ; then + AC_MSG_ERROR([SDL support for grub-emu was explicitely requested but can't be compiled]) +fi +if test x"$grub_emu_sdl_excuse" = x ; then +enable_grub_emu_sdl=yes +else +enable_grub_emu_sdl=no +fi + +if test x"$enable_grub_emu_pci" != xyes ; then + grub_emu_pci_excuse="not enabled" +fi + +if test x"$enable_grub_emu_usb" = xyes ; then + grub_emu_pci_excuse="conflicts with USB support" +fi + +[if [ x"$grub_emu_pci_excuse" = x ]; then + # Check for libpci libraries.] + AC_CHECK_LIB([pciaccess], [pci_system_init], [LIBPCIACCESS="-lpciaccess"], + [grub_emu_pci_excuse=["need libpciaccess library"]]) + AC_SUBST([LIBPCIACCESS]) +[fi] +[if [ x"$grub_emu_pci_excuse" = x ]; then + # Check for headers.] + AC_CHECK_HEADERS([pci/pci.h], [], + [grub_emu_pci_excuse=["need libpciaccess headers"]]) +[fi] + +if test x"$grub_emu_pci_excuse" = x ; then +enable_grub_emu_pci=yes +else + +enable_grub_emu_pci=no +fi + +AC_SUBST([enable_grub_emu_sdl]) AC_SUBST([enable_grub_emu_usb]) +AC_SUBST([enable_grub_emu_pci]) fi AC_ARG_ENABLE([grub-fstest], @@ -598,6 +758,16 @@ if test x"$grub_mkfont_excuse" = x ; then freetype_cflags=`freetype-config --cflags` freetype_libs=`freetype-config --libs` fi + +if test x"$grub_mkfont_excuse" = x ; then + # Check for freetype libraries. + SAVED_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $freetype_cflags" + AC_CHECK_HEADERS([ft2build.h], [], + [grub_mkfont_excuse=["need freetype2 headers"]]) + CPPFLAGS="$SAVED_CPPFLAGS" +fi + if test x"$enable_grub_mkfont" = xyes && test x"$grub_mkfont_excuse" != x ; then AC_MSG_ERROR([grub-mkfont was explicitly requested but can't be compiled]) fi @@ -610,6 +780,22 @@ AC_SUBST([enable_grub_mkfont]) AC_SUBST([freetype_cflags]) AC_SUBST([freetype_libs]) +AC_ARG_ENABLE([device-mapper], + [AS_HELP_STRING([--enable-device-mapper], + [enable Linux device-mapper support (default=guessed)])]) +if test x"$enable_device_mapper" = xno ; then + device_mapper_excuse="explicitly disabled" +fi + +if test x"$device_mapper_excuse" = x ; then + # Check for device-mapper library. + AC_CHECK_LIB([devmapper], [dm_task_create], + [LDFLAGS="$LDFLAGS -ldevmapper" + AC_DEFINE([HAVE_DEVICE_MAPPER], [1], + [Define to 1 if you have the devmapper library.])], + [device_mapper_excuse="need devmapper library"]) +fi + AC_SUBST(ASFLAGS) # Output files. @@ -641,6 +827,21 @@ echo USB support for grub-emu: Yes else echo USB support for grub-emu: No "($grub_emu_usb_excuse)" fi +if [ x"$grub_emu_sdl_excuse" = x ]; then +echo SDL support for grub-emu: Yes +else +echo SDL support for grub-emu: No "($grub_emu_sdl_excuse)" +fi +if [ x"$grub_emu_pci_excuse" = x ]; then +echo PCI support for grub-emu: Yes +else +echo PCI support for grub-emu: No "($grub_emu_pci_excuse)" +fi +if [ x"$TARGET_NO_MODULES" = xno ]; then +echo Module support for grub-emu: Yes +else +echo Module support for grub-emu: No +fi fi if [ x"$enable_mm_debug" = xyes ]; then echo With memory debugging: Yes diff --git a/disk/ata.c b/disk/ata.c index 11489828f..687ed9378 100644 --- a/disk/ata.c +++ b/disk/ata.c @@ -26,8 +26,8 @@ #include /* At the moment, only two IDE ports are supported. */ -static const int grub_ata_ioaddress[] = { 0x1f0, 0x170 }; -static const int grub_ata_ioaddress2[] = { 0x3f6, 0x376 }; +static const grub_port_t grub_ata_ioaddress[] = { 0x1f0, 0x170 }; +static const grub_port_t grub_ata_ioaddress2[] = { 0x3f6, 0x376 }; static struct grub_ata_device *grub_ata_devices; @@ -281,7 +281,7 @@ grub_ata_identify (struct grub_ata_device *dev) else /* Other Error. */ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, - "device can not be identified"); + "device cannot be identified"); } grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE); @@ -347,8 +347,8 @@ grub_ata_device_initialize (int port, int device, int addr, int addr2) /* Setup the device information. */ dev->port = port; dev->device = device; - dev->ioaddress = addr; - dev->ioaddress2 = addr2; + dev->ioaddress = addr + GRUB_MACHINE_PCI_IO_BASE; + dev->ioaddress2 = addr2 + GRUB_MACHINE_PCI_IO_BASE; dev->next = NULL; grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4); @@ -388,8 +388,8 @@ grub_ata_device_initialize (int port, int device, int addr, int addr2) } static int NESTED_FUNC_ATTR -grub_ata_pciinit (int bus, int device, int func, - grub_pci_id_t pciid __attribute__((unused))) +grub_ata_pciinit (grub_pci_device_t dev, + grub_pci_id_t pciid) { static int compat_use[2] = { 0 }; grub_pci_address_t addr; @@ -400,19 +400,34 @@ grub_ata_pciinit (int bus, int device, int func, int regb; int i; static int controller = 0; + int cs5536 = 0; + int nports = 2; /* Read class. */ - addr = grub_pci_make_address (bus, device, func, 2); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); class = grub_pci_read (addr); + /* AMD CS5536 Southbridge. */ + if (pciid == 0x208f1022) + { + cs5536 = 1; + nports = 1; + } + /* Check if this class ID matches that of a PCI IDE Controller. */ - if (class >> 16 != 0x0101) + if (!cs5536 && (class >> 16 != 0x0101)) return 0; - for (i = 0; i < 2; i++) + for (i = 0; i < nports; i++) { /* Set to 0 when the channel operated in compatibility mode. */ - int compat = (class >> (8 + 2 * i)) & 1; + int compat; + + /* We don't support non-compatibility mode for CS5536. */ + if (cs5536) + compat = 0; + else + compat = (class >> (8 + 2 * i)) & 1; rega = 0; regb = 0; @@ -429,9 +444,12 @@ grub_ata_pciinit (int bus, int device, int func, { /* Read the BARs, which either contain a mmapped IO address or the IO port address. */ - addr = grub_pci_make_address (bus, device, func, 4 + 2 * i); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES + + sizeof (grub_uint64_t) * i); bar1 = grub_pci_read (addr); - addr = grub_pci_make_address (bus, device, func, 5 + 2 * i); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES + + sizeof (grub_uint64_t) * i + + sizeof (grub_uint32_t)); bar2 = grub_pci_read (addr); /* Check if the BARs describe an IO region. */ @@ -444,7 +462,8 @@ grub_ata_pciinit (int bus, int device, int func, grub_dprintf ("ata", "PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n", - bus, device, func, compat, rega, regb); + grub_pci_get_bus (dev), grub_pci_get_device (dev), + grub_pci_get_function (dev), compat, rega, regb); if (rega && regb) { @@ -484,7 +503,6 @@ grub_ata_initialize (void) return 0; } - static void grub_ata_setlba (struct grub_ata_device *dev, grub_disk_addr_t sector, grub_size_t size) @@ -519,7 +537,7 @@ grub_ata_setaddress (struct grub_ata_device *dev, || cylinder > dev->cylinders || head > dev->heads) return grub_error (GRUB_ERR_OUT_OF_RANGE, - "sector %d can not be addressed " + "sector %d cannot be addressed " "using CHS addressing", sector); grub_ata_regset (dev, GRUB_ATA_REG_DISK, (dev->device << 4) | head); @@ -647,12 +665,14 @@ grub_ata_iterate (int (*hook) (const char *name)) for (dev = grub_ata_devices; dev; dev = dev->next) { - char devname[5]; - grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device); + char devname[10]; if (dev->atapi) continue; + grub_snprintf (devname, sizeof (devname), + "ata%d", dev->port * 2 + dev->device); + if (hook (devname)) return 1; } @@ -667,14 +687,15 @@ grub_ata_open (const char *name, grub_disk_t disk) for (dev = grub_ata_devices; dev; dev = dev->next) { - char devname[5]; - grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device); + char devname[10]; + grub_snprintf (devname, sizeof (devname), + "ata%d", dev->port * 2 + dev->device); if (grub_strcmp (name, devname) == 0) break; } if (! dev) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device"); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); if (dev->atapi) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk"); @@ -734,8 +755,9 @@ grub_atapi_iterate (int (*hook) (const char *name, int luns)) for (dev = grub_ata_devices; dev; dev = dev->next) { - char devname[7]; - grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device); + char devname[10]; + grub_snprintf (devname, sizeof (devname), + "ata%d", dev->port * 2 + dev->device); if (! dev->atapi) continue; @@ -774,7 +796,7 @@ grub_atapi_read (struct grub_scsi *scsi, /* Count of last transfer may be uneven. */ if (! (0 < cnt && cnt <= size - nread && (! (cnt & 1) || cnt == size - nread))) - return grub_error (GRUB_ERR_READ_ERROR, "Invalid ATAPI transfer count"); + return grub_error (GRUB_ERR_READ_ERROR, "invalid ATAPI transfer count"); /* Read the data. */ grub_ata_pio_read (dev, buf + nread, cnt); @@ -807,8 +829,9 @@ grub_atapi_open (const char *name, struct grub_scsi *scsi) for (dev = grub_ata_devices; dev; dev = dev->next) { - char devname[7]; - grub_sprintf (devname, "ata%d", dev->port * 2 + dev->device); + char devname[10]; + grub_snprintf (devname, sizeof (devname), + "ata%d", dev->port * 2 + dev->device); if (!grub_strcmp (devname, name)) { @@ -820,7 +843,7 @@ grub_atapi_open (const char *name, struct grub_scsi *scsi) grub_dprintf ("ata", "opening ATAPI dev `%s'\n", name); if (! devfnd) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such ATAPI device"); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device"); scsi->data = devfnd; diff --git a/disk/ata_pthru.c b/disk/ata_pthru.c index 70d4f3a78..f52725a49 100644 --- a/disk/ata_pthru.c +++ b/disk/ata_pthru.c @@ -30,7 +30,7 @@ grub_ata_pass_through (grub_disk_t disk, { if (disk->dev->id != GRUB_DISK_DEVICE_ATA_ID) return grub_error (GRUB_ERR_BAD_DEVICE, - "Device not accessed via ata.mod"); + "device not accessed via ata.mod"); struct grub_ata_device *dev = (struct grub_ata_device *) disk->data; diff --git a/disk/dmraid_nvidia.c b/disk/dmraid_nvidia.c index 84dfad8c4..c4e3922cf 100644 --- a/disk/dmraid_nvidia.c +++ b/disk/dmraid_nvidia.c @@ -1,7 +1,7 @@ /* dmraid_nvidia.c - module to handle Nvidia fakeraid. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009 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 @@ -107,7 +107,7 @@ grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) if (sb.version != NV_VERSION) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unknown version: %d.%d", sb.version); + "unknown version: %d.%d", sb.version); switch (sb.array.raid_level) { @@ -129,7 +129,7 @@ grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) default: return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unsupported RAID level: %d", sb.array.raid_level); + "unsupported RAID level: %d", sb.array.raid_level); } array->number = 0; diff --git a/disk/efi/efidisk.c b/disk/efi/efidisk.c index de848594a..f9c6f3153 100644 --- a/disk/efi/efidisk.c +++ b/disk/efi/efidisk.c @@ -440,7 +440,7 @@ grub_efidisk_iterate (int (*hook) (const char *name)) for (d = fd_devices, count = 0; d; d = d->next, count++) { - grub_sprintf (buf, "fd%d", count); + grub_snprintf (buf, sizeof (buf), "fd%d", count); grub_dprintf ("efidisk", "iterating %s\n", buf); if (hook (buf)) return 1; @@ -448,7 +448,7 @@ grub_efidisk_iterate (int (*hook) (const char *name)) for (d = hd_devices, count = 0; d; d = d->next, count++) { - grub_sprintf (buf, "hd%d", count); + grub_snprintf (buf, sizeof (buf), "hd%d", count); grub_dprintf ("efidisk", "iterating %s\n", buf); if (hook (buf)) return 1; @@ -456,7 +456,7 @@ grub_efidisk_iterate (int (*hook) (const char *name)) for (d = cd_devices, count = 0; d; d = d->next, count++) { - grub_sprintf (buf, "cd%d", count); + grub_snprintf (buf, sizeof (buf), "cd%d", count); grub_dprintf ("efidisk", "iterating %s\n", buf); if (hook (buf)) return 1; @@ -805,18 +805,10 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) return 0; } - device_name = grub_malloc (grub_strlen (parent->name) + 1 - + grub_strlen (partition_name) + 1); - if (! device_name) - { - grub_free (partition_name); - grub_disk_close (parent); - return 0; - } - - grub_sprintf (device_name, "%s,%s", parent->name, partition_name); + device_name = grub_xasprintf ("%s,%s", parent->name, partition_name); grub_free (partition_name); grub_disk_close (parent); + return device_name; } else @@ -833,7 +825,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) if (! disk) return 1; - if (disk->id == GRUB_DISK_DEVICE_EFIDISK_ID) + if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID) { struct grub_efidisk_data *d; diff --git a/disk/fs_file.c b/disk/fs_file.c deleted file mode 100644 index e09568250..000000000 --- a/disk/fs_file.c +++ /dev/null @@ -1,136 +0,0 @@ -/* fs_file.c - Access partition by a file it contains. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 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 . - */ - -#include -#include -#include -#include -#include -#include - -static grub_device_t -search_fs_file (const char *key, unsigned long *count) -{ - char *filename = NULL; - grub_device_t ret = NULL; - *count = 0; - - auto int iterate_device (const char *name); - int iterate_device (const char *name) - { - int len; - grub_file_t file; - - (*count)++; - - len = grub_strlen (name) + 2 + grub_strlen (key) + 1; - filename = grub_realloc (filename, len); - if (! filename) - return 1; - - grub_sprintf (filename, "(%s)%s", name, key); - file = grub_file_open (filename); - if (file) - { - grub_file_close (file); - ret = grub_device_open (name); - return 1; - } - - grub_errno = GRUB_ERR_NONE; - return 0; - } - - grub_device_iterate (iterate_device); - grub_free (filename); - - return ret; -} - -static grub_err_t -grub_fs_file_open (const char *name, grub_disk_t disk) -{ - grub_device_t dev; - - if (grub_strncmp (name, "FILE=", sizeof ("FILE=") - 1)) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a FILE virtual volume"); - - dev = search_fs_file (name + sizeof ("FILE=") - 1, &disk->id); - if (! dev) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file found"); - - disk->total_sectors = dev->disk->total_sectors; - disk->has_partitions = 0; - if (dev->disk->partition) - { - disk->partition = grub_malloc (sizeof (*disk->partition)); - if (disk->partition) - grub_memcpy (disk->partition, dev->disk->partition, - sizeof (*disk->partition)); - } - else - disk->partition = NULL; - - disk->data = dev; - - return GRUB_ERR_NONE; -} - -static void -grub_fs_file_close (grub_disk_t disk) -{ - grub_device_t parent = disk->data; - grub_device_close (parent); -} - -static grub_err_t -grub_fs_file_read (grub_disk_t disk, grub_disk_addr_t sector, - grub_size_t size, char *buf) -{ - grub_device_t parent = disk->data; - return parent->disk->dev->read (parent->disk, sector, size, buf); -} - -static grub_err_t -grub_fs_file_write (grub_disk_t disk, grub_disk_addr_t sector, - grub_size_t size, const char *buf) -{ - grub_device_t parent = disk->data; - return parent->disk->dev->write (parent->disk, sector, size, buf); -} - -static struct grub_disk_dev grub_fs_file_dev = { - .name = "fs_file", - .id = GRUB_DISK_DEVICE_FILE_ID, - .open = grub_fs_file_open, - .close = grub_fs_file_close, - .read = grub_fs_file_read, - .write = grub_fs_file_write, - .next = 0 -}; - -GRUB_MOD_INIT (fs_file) -{ - grub_disk_dev_register (&grub_fs_file_dev); -} - -GRUB_MOD_FINI (fs_file) -{ - grub_disk_dev_unregister (&grub_fs_file_dev); -} diff --git a/disk/fs_uuid.c b/disk/fs_uuid.c deleted file mode 100644 index 6901dbacf..000000000 --- a/disk/fs_uuid.c +++ /dev/null @@ -1,149 +0,0 @@ -/* fs_uuid.c - Access disks by their filesystem UUID. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007,2008 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 . - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -static grub_device_t -search_fs_uuid (const char *key, unsigned long *count) -{ - *count = 0; - grub_device_t ret = NULL; - - auto int iterate_device (const char *name); - int iterate_device (const char *name) - { - grub_device_t dev; - - dev = grub_device_open (name); - if (dev) - { - grub_fs_t fs; - - fs = grub_fs_probe (dev); - if (fs && fs->uuid) - { - char *uuid; - - (fs->uuid) (dev, &uuid); - if (grub_errno == GRUB_ERR_NONE && uuid) - { - (*count)++; - - if (grub_strcasecmp (uuid, key) == 0) - { - ret = dev; - grub_free (uuid); - return 1; - } - grub_free (uuid); - } - } - - grub_device_close (dev); - } - - grub_errno = GRUB_ERR_NONE; - return 0; - } - - grub_device_iterate (iterate_device); - - return ret; -} - -static grub_err_t -grub_fs_uuid_open (const char *name, grub_disk_t disk) -{ - grub_device_t dev; - - if (grub_strncmp (name, "UUID=", sizeof ("UUID=")-1)) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a UUID virtual volume"); - - dev = search_fs_uuid (name + sizeof ("UUID=") - 1, &disk->id); - if (! dev) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching UUID found"); - - disk->total_sectors = dev->disk->total_sectors; - disk->has_partitions = 0; - if (dev->disk->partition) - { - disk->partition = grub_malloc (sizeof (*disk->partition)); - if (disk->partition) - grub_memcpy (disk->partition, dev->disk->partition, - sizeof (*disk->partition)); - } - else - disk->partition = NULL; - - disk->data = dev; - - return GRUB_ERR_NONE; -} - -static void -grub_fs_uuid_close (grub_disk_t disk __attribute((unused))) -{ - grub_device_t parent = disk->data; - grub_device_close (parent); -} - -static grub_err_t -grub_fs_uuid_read (grub_disk_t disk, grub_disk_addr_t sector, - grub_size_t size, char *buf) -{ - grub_device_t parent = disk->data; - return parent->disk->dev->read (parent->disk, sector, size, buf); -} - -static grub_err_t -grub_fs_uuid_write (grub_disk_t disk, grub_disk_addr_t sector, - grub_size_t size, const char *buf) -{ - grub_device_t parent = disk->data; - return parent->disk->dev->write (parent->disk, sector, size, buf); -} - -static struct grub_disk_dev grub_fs_uuid_dev = - { - .name = "fs_uuid", - .id = GRUB_DISK_DEVICE_UUID_ID, - .open = grub_fs_uuid_open, - .close = grub_fs_uuid_close, - .read = grub_fs_uuid_read, - .write = grub_fs_uuid_write, - .next = 0 - }; - -GRUB_MOD_INIT(fs_uuid) -{ - grub_disk_dev_register (&grub_fs_uuid_dev); -} - -GRUB_MOD_FINI(fs_uuid) -{ - grub_disk_dev_unregister (&grub_fs_uuid_dev); -} diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c index 0a6137fad..94d0e3708 100644 --- a/disk/i386/pc/biosdisk.c +++ b/disk/i386/pc/biosdisk.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,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 @@ -56,7 +56,8 @@ grub_biosdisk_call_hook (int (*hook) (const char *name), int drive) { char name[10]; - grub_sprintf (name, (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80)); + grub_snprintf (name, sizeof (name), + (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80)); return hook (name); } @@ -169,7 +170,7 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) else { grub_free (data); - return grub_error (GRUB_ERR_BAD_DEVICE, "cannot get C/H/S values"); + return grub_error (GRUB_ERR_BAD_DEVICE, "%s cannot get C/H/S values", disk->name); } } @@ -222,7 +223,7 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk, if (cmd) return grub_error (GRUB_ERR_WRITE_ERROR, "can\'t write to cdrom"); - dap->blocks = (dap->blocks + 3) >> 2; + dap->blocks = ALIGN_UP (dap->blocks, 4) >> 2; dap->block >>= 2; for (i = 0; i < GRUB_BIOSDISK_CDROM_RETRY_COUNT; i++) @@ -252,7 +253,7 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk, 1024 /* cylinders */ * 256 /* heads */ * 63 /* spt */) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "out of disk"); + return grub_error (GRUB_ERR_OUT_OF_RANGE, "%s out of disk", disk->name); soff = ((grub_uint32_t) sector) % data->sectors + 1; head = ((grub_uint32_t) sector) / data->sectors; @@ -260,7 +261,7 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk, coff = head / data->heads; if (coff >= data->cylinders) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "out of disk"); + return grub_error (GRUB_ERR_OUT_OF_RANGE, "%s out of disk", disk->name); if (grub_biosdisk_rw_standard (cmd + 0x02, data->drive, coff, hoff, soff, size, segment)) @@ -268,9 +269,9 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk, switch (cmd) { case GRUB_BIOSDISK_READ: - return grub_error (GRUB_ERR_READ_ERROR, "biosdisk read error"); + return grub_error (GRUB_ERR_READ_ERROR, "%s read error", disk->name); case GRUB_BIOSDISK_WRITE: - return grub_error (GRUB_ERR_WRITE_ERROR, "biosdisk write error"); + return grub_error (GRUB_ERR_WRITE_ERROR, "%s write error", disk->name); } } } @@ -306,8 +307,17 @@ grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, while (size) { grub_size_t len; + grub_size_t cdoff = 0; len = get_safe_sectors (sector, data->sectors); + + if (data->flags & GRUB_BIOSDISK_FLAG_CDROM) + { + cdoff = (sector & 3) << GRUB_DISK_SECTOR_BITS; + len = ALIGN_UP (sector + len, 4) - (sector & ~3); + sector &= ~3; + } + if (len > size) len = size; @@ -315,7 +325,7 @@ grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, GRUB_MEMORY_MACHINE_SCRATCH_SEG)) return grub_errno; - grub_memcpy (buf, (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, + grub_memcpy (buf, (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + cdoff), len << GRUB_DISK_SECTOR_BITS); buf += len << GRUB_DISK_SECTOR_BITS; sector += len; @@ -331,6 +341,9 @@ grub_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector, { struct grub_biosdisk_data *data = disk->data; + if (data->flags & GRUB_BIOSDISK_FLAG_CDROM) + return grub_error (GRUB_ERR_IO, "can't write to CDROM"); + while (size) { grub_size_t len; diff --git a/disk/ieee1275/nand.c b/disk/ieee1275/nand.c index 37427f884..df2ee81f3 100644 --- a/disk/ieee1275/nand.c +++ b/disk/ieee1275/nand.c @@ -1,7 +1,7 @@ /* nand.c - NAND flash disk access. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 @@ -67,7 +67,7 @@ grub_nand_open (const char *name, grub_disk_t disk) } args; if (! grub_strstr (name, "nand")) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Not a nand device"); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a NAND device"); data = grub_malloc (sizeof (*data)); if (! data) @@ -76,7 +76,7 @@ grub_nand_open (const char *name, grub_disk_t disk) grub_ieee1275_open (name, &dev_ihandle); if (! dev_ihandle) { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device"); + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); goto fail; } @@ -89,7 +89,7 @@ grub_nand_open (const char *name, grub_disk_t disk) if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.result)) { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't get block size"); + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't get block size"); goto fail; } @@ -102,7 +102,7 @@ grub_nand_open (const char *name, grub_disk_t disk) if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.result)) { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't get disk size"); + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't get disk size"); goto fail; } @@ -172,7 +172,7 @@ grub_nand_read (grub_disk_t disk, grub_disk_addr_t sector, args.result = 1; if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.result)) - return grub_error (GRUB_ERR_READ_ERROR, "Read error"); + return grub_error (GRUB_ERR_READ_ERROR, "read error"); ofs = 0; size -= len; diff --git a/disk/ieee1275/ofdisk.c b/disk/ieee1275/ofdisk.c index a33d729e3..e5a4a67fa 100644 --- a/disk/ieee1275/ofdisk.c +++ b/disk/ieee1275/ofdisk.c @@ -1,7 +1,7 @@ /* ofdisk.c - Open Firmware disk access. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2004,2006,2007,2008,2009 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 @@ -118,7 +118,7 @@ grub_ofdisk_iterate (int (*hook) (const char *name)) static char * compute_dev_path (const char *name) { - char *devpath = grub_malloc (grub_strlen (name) + 2); + char *devpath = grub_malloc (grub_strlen (name) + 3); char *p, c; if (!devpath) @@ -172,35 +172,35 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) grub_dprintf ("disk", "Opening `%s'.\n", op->devpath); - grub_ieee1275_open (op->devpath, &dev_ihandle); - if (! dev_ihandle) - { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device"); - goto fail; - } - - grub_dprintf ("disk", "Opened `%s' as handle %p.\n", op->devpath, - (void *) (unsigned long) dev_ihandle); - if (grub_ieee1275_finddevice (op->devpath, &dev)) { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't read device properties"); + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read device properties"); goto fail; } if (grub_ieee1275_get_property (dev, "device_type", prop, sizeof (prop), &actual)) { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't read the device type"); + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type"); goto fail; } if (grub_strcmp (prop, "block")) { - grub_error (GRUB_ERR_BAD_DEVICE, "Not a block device"); + grub_error (GRUB_ERR_BAD_DEVICE, "not a block device"); goto fail; } + grub_ieee1275_open (op->devpath, &dev_ihandle); + if (! dev_ihandle) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); + goto fail; + } + + grub_dprintf ("disk", "Opened `%s' as handle %p.\n", op->devpath, + (void *) (unsigned long) dev_ihandle); + /* XXX: There is no property to read the number of blocks. There should be a property `#blocks', but it is not there. Perhaps it is possible to use seek for this. */ @@ -234,22 +234,18 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, grub_ssize_t status, actual; unsigned long long pos; - grub_dprintf ("disk", - "Reading handle %p: sector 0x%llx, size 0x%lx, buf %p.\n", - (void *) disk->data, (long long) sector, (long) size, buf); - pos = sector * 512UL; grub_ieee1275_seek ((grub_ieee1275_ihandle_t) (unsigned long) disk->data, - (int) (pos >> 32), (int) pos & 0xFFFFFFFFUL, &status); + pos, &status); if (status < 0) return grub_error (GRUB_ERR_READ_ERROR, - "Seek error, can't seek block %llu", + "seek error, can't seek block %llu", (long long) sector); grub_ieee1275_read ((grub_ieee1275_ihandle_t) (unsigned long) disk->data, buf, size * 512UL, &actual); - if (actual != actual) - return grub_error (GRUB_ERR_READ_ERROR, "Read error on block: %llu", + if (actual != (grub_ssize_t) (size * 512UL)) + return grub_error (GRUB_ERR_READ_ERROR, "read error on block: %llu", (long long) sector); return 0; diff --git a/disk/loopback.c b/disk/loopback.c index 29805182e..1b525e05f 100644 --- a/disk/loopback.c +++ b/disk/loopback.c @@ -23,6 +23,7 @@ #include #include #include +#include struct grub_loopback { @@ -36,8 +37,8 @@ static struct grub_loopback *loopback_list; static const struct grub_arg_option options[] = { - {"delete", 'd', 0, "delete the loopback device entry", 0, 0}, - {"partitions", 'p', 0, "simulate a hard drive with partitions", 0, 0}, + {"delete", 'd', 0, N_("Delete the loopback device entry."), 0, 0}, + {"partitions", 'p', 0, N_("Simulate a hard drive with partitions."), 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -56,7 +57,7 @@ delete_loopback (const char *name) break; if (! dev) - return grub_error (GRUB_ERR_BAD_DEVICE, "Device not found"); + return grub_error (GRUB_ERR_BAD_DEVICE, "device not found"); /* Remove the device from the list. */ *prev = dev->next; @@ -167,7 +168,7 @@ grub_loopback_open (const char *name, grub_disk_t disk) break; if (! dev) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device"); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); file = grub_file_open (dev->filename); if (! file) @@ -241,16 +242,16 @@ static struct grub_disk_dev grub_loopback_dev = static grub_extcmd_t cmd; -GRUB_MOD_INIT(loop) +GRUB_MOD_INIT(loopback) { cmd = grub_register_extcmd ("loopback", grub_cmd_loopback, GRUB_COMMAND_FLAG_BOTH, - "loopback [-d|-p] DEVICENAME FILE", - "Make a device of a file.", options); + N_("[-d|-p] DEVICENAME FILE."), + N_("Make a device of a file."), options); grub_disk_dev_register (&grub_loopback_dev); } -GRUB_MOD_FINI(loop) +GRUB_MOD_FINI(loopback) { grub_unregister_extcmd (cmd); grub_disk_dev_unregister (&grub_loopback_dev); diff --git a/disk/lvm.c b/disk/lvm.c index 126b49439..7dde40920 100644 --- a/disk/lvm.c +++ b/disk/lvm.c @@ -1,7 +1,7 @@ /* lvm.c - module to read Logical Volumes. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009 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 @@ -24,6 +24,10 @@ #include #include +#ifdef GRUB_UTIL +#include +#endif + static struct grub_lvm_vg *vg_list; static int lv_count; @@ -68,6 +72,9 @@ grub_lvm_memberlist (grub_disk_t disk) if (lv->vg->pvs) for (pv = lv->vg->pvs; pv; pv = pv->next) { + if (!pv->disk) + grub_util_error ("Couldn't find PV %s. Check your device.map", + pv->name); tmp = grub_malloc (sizeof (*tmp)); tmp->disk = pv->disk; tmp->next = list; @@ -95,7 +102,7 @@ grub_lvm_open (const char *name, grub_disk_t disk) } if (! lv) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Unknown LVM device %s", name); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown LVM device %s", name); disk->has_partitions = 0; disk->id = lv->number; @@ -188,7 +195,7 @@ grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector, size << GRUB_DISK_SECTOR_BITS, buf); else err = grub_error (GRUB_ERR_UNKNOWN_DEVICE, - "Physical volume %s not found", pv->name); + "physical volume %s not found", pv->name); return err; } @@ -263,7 +270,7 @@ grub_lvm_scan_device (const char *name) if (dlocn->offset) { grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "We don't support multiple LVM data areas"); + "we don't support multiple LVM data areas"); goto fail; } @@ -290,7 +297,7 @@ grub_lvm_scan_device (const char *name) || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION)) { grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unknown LVM metadata header"); + "unknown LVM metadata header"); goto fail2; } diff --git a/disk/mdraid_linux.c b/disk/mdraid_linux.c index 29a21b4c7..306c66a8b 100644 --- a/disk/mdraid_linux.c +++ b/disk/mdraid_linux.c @@ -181,7 +181,7 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array) /* FIXME: Also support version 1.0. */ if (sb.major_version != 0 || sb.minor_version != 90) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unsupported RAID version: %d.%d", + "unsupported RAID version: %d.%d", sb.major_version, sb.minor_version); /* FIXME: Check the checksum. */ @@ -193,7 +193,7 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array) if (sb.level != 0 && sb.level != 1 && sb.level != 4 && sb.level != 5 && sb.level != 6 && sb.level != 10) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unsupported RAID level: %d", sb.level); + "unsupported RAID level: %d", sb.level); array->number = sb.md_minor; array->level = sb.level; diff --git a/disk/memdisk.c b/disk/memdisk.c index 4a0470837..2e8885020 100644 --- a/disk/memdisk.c +++ b/disk/memdisk.c @@ -23,7 +23,6 @@ #include #include #include -#include static char *memdisk_addr; static grub_off_t memdisk_size = 0; diff --git a/disk/raid.c b/disk/raid.c index c720fb36c..2d544afdc 100644 --- a/disk/raid.c +++ b/disk/raid.c @@ -1,7 +1,7 @@ /* raid.c - module to read RAID arrays. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009 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 @@ -123,7 +123,7 @@ grub_raid_open (const char *name, grub_disk_t disk) } if (!array) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Unknown RAID device %s", + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s", name); disk->has_partitions = 1; @@ -265,7 +265,7 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, } else err = grub_error (GRUB_ERR_READ_ERROR, - "disk missing."); + "disk missing"); k++; if (k == array->total_devs) @@ -556,7 +556,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, } } - array->name = grub_malloc (13); + array->name = grub_xasprintf ("md%d", array->number); if (! array->name) { grub_free (array->uuid); @@ -565,8 +565,6 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, return grub_errno; } - grub_sprintf (array->name, "md%d", array->number); - grub_dprintf ("raid", "Found array %s (%s)\n", array->name, scanner_name); diff --git a/disk/raid6_recover.c b/disk/raid6_recover.c index 7bbf8eaef..550968ceb 100644 --- a/disk/raid6_recover.c +++ b/disk/raid6_recover.c @@ -1,7 +1,7 @@ /* raid6_recover.c - module to recover from faulty RAID6 arrays. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009 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 @@ -157,7 +157,7 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p, if (! array->device[q]) { - grub_error (GRUB_ERR_READ_ERROR, "Not enough disk to restore"); + grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore"); goto quit; } @@ -176,7 +176,7 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p, if ((! array->device[p]) || (! array->device[q])) { - grub_error (GRUB_ERR_READ_ERROR, "Not enough disk to restore"); + grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore"); goto quit; } diff --git a/disk/scsi.c b/disk/scsi.c index d0e248511..eba237287 100644 --- a/disk/scsi.c +++ b/disk/scsi.c @@ -1,7 +1,7 @@ /* scsi.c - scsi support. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 @@ -197,7 +197,6 @@ grub_scsi_iterate (int (*hook) (const char *name)) int scsi_iterate (const char *name, int luns) { - char sname[40]; int i; /* In case of a single LUN, just return `usbX'. */ @@ -208,8 +207,14 @@ grub_scsi_iterate (int (*hook) (const char *name)) distinguish it. */ for (i = 0; i < luns; i++) { - grub_sprintf (sname, "%s%c", name, 'a' + i); - if (hook (sname)) + char *sname; + int ret; + sname = grub_xasprintf ("%s%c", name, 'a' + i); + if (!sname) + return 1; + ret = hook (sname); + grub_free (sname); + if (ret) return 1; } return 0; @@ -337,14 +342,14 @@ grub_scsi_read (grub_disk_t disk, grub_disk_addr_t sector, unsigned spb = scsi->blocksize >> GRUB_DISK_SECTOR_BITS; if (! (spb != 0 && (scsi->blocksize & GRUB_DISK_SECTOR_SIZE) == 0)) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unsupported SCSI block size"); + "unsupported SCSI block size"); grub_uint32_t sector_mod = 0; sector = grub_divmod64 (sector, spb, §or_mod); if (! (sector_mod == 0 && size % spb == 0)) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unaligned SCSI read not supported"); + "unaligned SCSI read not supported"); size /= spb; } diff --git a/disk/usbms.c b/disk/usbms.c index 51e886520..8554b224f 100644 --- a/disk/usbms.c +++ b/disk/usbms.c @@ -200,11 +200,15 @@ grub_usbms_iterate (int (*hook) (const char *name, int luns)) for (p = grub_usbms_dev_list; p; p = p->next) { - char devname[20]; - grub_sprintf (devname, "usb%d", cnt); + char *devname; + devname = grub_xasprintf ("usb%d", cnt); if (hook (devname, p->luns)) - return 1; + { + grub_free (devname); + return 1; + } + grub_free (devname); cnt++; } diff --git a/docs/grub.texi b/docs/grub.texi index 4fa44462e..704f8b2a3 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -1126,6 +1126,7 @@ you forget a command, you can run the command @command{help} * insmod:: Insert a module * keystatus:: Check key modifier status * ls:: List devices or files +* play:: Play a tune * reboot:: Reboot your computer * set:: Set an environment variable * unset:: Unset an environment variable @@ -1364,6 +1365,25 @@ name syntax}), then list the contents of that directory. @end deffn +@node play +@subsection play + +@deffn Command play file | tempo [pitch1 duration1] [pitch2 duration2] ... +Plays a tune + +If the argument is a file name (@pxref{File name syntax}), play the tune +recorded in it. The file format is first the tempo as an unsigned 32bit +little-endian number, then pairs of unsigned 16bit little-endian numbers for +pitch and duration pairs. + +If the arguments are a series of numbers, play the inline tune. + +The tempo is the base for all note durations. 60 gives a 1-second base, 120 +gives a half-second base, etc. Pitches are Hz. Set pitch to 0 to produce +a rest. +@end deffn + + @node reboot @subsection reboot diff --git a/efiemu/main.c b/efiemu/main.c index b5608e666..b197a8b2c 100644 --- a/efiemu/main.c +++ b/efiemu/main.c @@ -31,6 +31,7 @@ #include #include #include +#include /* System table. Two version depending on mode */ grub_efi_system_table32_t *grub_efiemu_system_table32 = 0; @@ -39,6 +40,7 @@ grub_efi_system_table64_t *grub_efiemu_system_table64 = 0; static struct grub_efiemu_prepare_hook *efiemu_prepare_hooks = 0; /* Linked list of configuration tables */ static struct grub_efiemu_configuration_table *efiemu_config_tables = 0; +static int prepared = 0; /* Free all allocated space */ grub_err_t @@ -70,6 +72,8 @@ grub_efiemu_unload (void) } efiemu_prepare_hooks = 0; + prepared = 0; + return GRUB_ERR_NONE; } @@ -211,7 +215,7 @@ grub_efiemu_load_file (const char *filename) { grub_file_close (file); grub_efiemu_unload (); - return grub_error (grub_errno, "Couldn't init memory management"); + return grub_error (grub_errno, "couldn't init memory management"); } grub_dprintf ("efiemu", "mm initialized\n"); @@ -252,18 +256,17 @@ grub_efiemu_autocore (void) suffix = grub_efiemu_get_default_core_name (); - filename = grub_malloc (grub_strlen (prefix) + grub_strlen (suffix) + 2); + filename = grub_xasprintf ("%s/%s", prefix, suffix); if (! filename) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't allocate temporary space"); - grub_sprintf (filename, "%s/%s", prefix, suffix); err = grub_efiemu_load_file (filename); grub_free (filename); if (err) return err; -#ifndef GRUB_UTIL +#ifndef GRUB_MACHINE_EMU err = grub_machine_efiemu_init_tables (); if (err) return err; @@ -277,14 +280,19 @@ grub_efiemu_prepare (void) { grub_err_t err; + if (prepared) + return GRUB_ERR_NONE; + grub_dprintf ("efiemu", "Preparing %d-bit efiemu\n", 8 * grub_efiemu_sizeof_uintn_t ()); err = grub_efiemu_autocore (); - /* Create NVRAM if not yet done. */ + /* Create NVRAM. */ grub_efiemu_pnvram (); + prepared = 1; + if (grub_efiemu_sizeof_uintn_t () == 4) return grub_efiemu_prepare32 (efiemu_prepare_hooks, efiemu_config_tables); else @@ -306,7 +314,7 @@ grub_cmd_efiemu_load (grub_command_t cmd __attribute__ ((unused)), err = grub_efiemu_load_file (args[0]); if (err) return err; -#ifndef GRUB_UTIL +#ifndef GRUB_MACHINE_EMU err = grub_machine_efiemu_init_tables (); if (err) return err; @@ -316,23 +324,19 @@ grub_cmd_efiemu_load (grub_command_t cmd __attribute__ ((unused)), static grub_command_t cmd_loadcore, cmd_prepare, cmd_unload; -void -grub_efiemu_pnvram_cmd_register (void); - GRUB_MOD_INIT(efiemu) { cmd_loadcore = grub_register_command ("efiemu_loadcore", grub_cmd_efiemu_load, - "efiemu_loadcore FILE", - "Load and initialize EFI emulator"); + N_("FILE"), + N_("Load and initialize EFI emulator.")); cmd_prepare = grub_register_command ("efiemu_prepare", grub_cmd_efiemu_prepare, - "efiemu_prepare", - "Finalize loading of EFI emulator"); + 0, + N_("Finalize loading of EFI emulator.")); cmd_unload = grub_register_command ("efiemu_unload", grub_cmd_efiemu_unload, - "efiemu_unload", - "Unload EFI emulator"); - grub_efiemu_pnvram_cmd_register (); + 0, + N_("Unload EFI emulator.")); } GRUB_MOD_FINI(efiemu) @@ -340,5 +344,4 @@ GRUB_MOD_FINI(efiemu) grub_unregister_command (cmd_loadcore); grub_unregister_command (cmd_prepare); grub_unregister_command (cmd_unload); - grub_efiemu_pnvram_cmd_unregister (); } diff --git a/efiemu/mm.c b/efiemu/mm.c index 8b0322942..4b293606f 100644 --- a/efiemu/mm.c +++ b/efiemu/mm.c @@ -67,7 +67,7 @@ grub_efiemu_add_to_mmap (grub_uint64_t start, grub_uint64_t size, * sizeof (grub_efi_memory_descriptor_t)); if (!efiemu_mmap) return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Not enough space for memory map"); + "not enough space for memory map"); } /* Fill slot*/ @@ -281,7 +281,7 @@ grub_efiemu_mmap_init (void) // the place for memory used by efiemu itself mmap_reserved_size = GRUB_EFI_MAX_MEMORY_TYPE + 1; -#ifndef GRUB_UTIL +#ifndef GRUB_MACHINE_EMU grub_machine_mmap_iterate (bounds_hook); #endif @@ -394,7 +394,7 @@ grub_efiemu_mmap_fill (void) } } -#ifndef GRUB_UTIL +#ifndef GRUB_MACHINE_EMU grub_machine_mmap_iterate (fill_hook); #endif @@ -622,7 +622,7 @@ grub_efiemu_mm_do_alloc (void) if (!efiemu_mmap) { grub_efiemu_unload (); - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Couldn't initialize mmap"); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't initialize mmap"); } if ((err = efiemu_alloc_requests ())) diff --git a/efiemu/pnvram.c b/efiemu/pnvram.c index 04ad6e284..e58fce84e 100644 --- a/efiemu/pnvram.c +++ b/efiemu/pnvram.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -34,62 +35,184 @@ static int timezone_handle = 0; static int accuracy_handle = 0; static int daylight_handle = 0; -/* Temporary place */ -static grub_uint8_t *nvram; static grub_size_t nvramsize; -static grub_uint32_t high_monotonic_count; -static grub_int16_t timezone; -static grub_uint8_t daylight; -static grub_uint32_t accuracy; - -static const struct grub_arg_option options[] = { - {"size", 's', 0, "number of bytes to reserve for pseudo NVRAM", 0, - ARG_TYPE_INT}, - {"high-monotonic-count", 'm', 0, - "Initial value of high monotonic count", 0, ARG_TYPE_INT}, - {"timezone", 't', 0, - "Timezone, offset in minutes from GMT", 0, ARG_TYPE_INT}, - {"accuracy", 'a', 0, - "Accuracy of clock, in 1e-12 units", 0, ARG_TYPE_INT}, - {"daylight", 'd', 0, - "Daylight value, as per EFI specifications", 0, ARG_TYPE_INT}, - {0, 0, 0, 0, 0, 0} -}; /* Parse signed value */ static int -grub_strtosl (char *arg, char **end, int base) +grub_strtosl (const char *arg, char **end, int base) { if (arg[0] == '-') return -grub_strtoul (arg + 1, end, base); return grub_strtoul (arg, end, base); } +static inline int +hextoval (char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'z') + return c - 'a' + 10; + if (c >= 'A' && c <= 'Z') + return c - 'A' + 10; + return 0; +} + +static inline grub_err_t +unescape (char *in, char *out, char *outmax, int *len) +{ + char *ptr, *dptr; + dptr = out; + for (ptr = in; *ptr && dptr < outmax; ) + if (*ptr == '%' && ptr[1] && ptr[2]) + { + *dptr = (hextoval (ptr[1]) << 4) | (hextoval (ptr[2])); + ptr += 3; + dptr++; + } + else + { + *dptr = *ptr; + ptr++; + dptr++; + } + if (dptr == outmax) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "too many NVRAM variables for reserved variable space." + " Try increasing EfiEmu.pnvram.size"); + *len = dptr - out; + return 0; +} + /* Export stuff for efiemu */ static grub_err_t nvram_set (void * data __attribute__ ((unused))) { + const char *env; /* Take definitive pointers */ - grub_uint8_t *nvram_def = grub_efiemu_mm_obtain_request (nvram_handle); + char *nvram = grub_efiemu_mm_obtain_request (nvram_handle); grub_uint32_t *nvramsize_def = grub_efiemu_mm_obtain_request (nvramsize_handle); - grub_uint32_t *high_monotonic_count_def + grub_uint32_t *high_monotonic_count = grub_efiemu_mm_obtain_request (high_monotonic_count_handle); - grub_int16_t *timezone_def + grub_int16_t *timezone = grub_efiemu_mm_obtain_request (timezone_handle); - grub_uint8_t *daylight_def + grub_uint8_t *daylight = grub_efiemu_mm_obtain_request (daylight_handle); - grub_uint32_t *accuracy_def + grub_uint32_t *accuracy = grub_efiemu_mm_obtain_request (accuracy_handle); + char *nvramptr; + + auto int iterate_env (struct grub_env_var *var); + int iterate_env (struct grub_env_var *var) + { + char *guid, *attr, *name, *varname; + struct efi_variable *efivar; + int len = 0; + int i; + grub_uint64_t guidcomp; + + if (grub_memcmp (var->name, "EfiEmu.pnvram.", + sizeof ("EfiEmu.pnvram.") - 1) != 0) + return 0; + + guid = var->name + sizeof ("EfiEmu.pnvram.") - 1; + + attr = grub_strchr (guid, '.'); + if (!attr) + return 0; + attr++; + + name = grub_strchr (attr, '.'); + if (!name) + return 0; + name++; + + efivar = (struct efi_variable *) nvramptr; + if (nvramptr - nvram + sizeof (struct efi_variable) > nvramsize) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, + "too many NVRAM variables for reserved variable space." + " Try increasing EfiEmu.pnvram.size"); + return 1; + } + + nvramptr += sizeof (struct efi_variable); + + efivar->guid.data1 = grub_cpu_to_le32 (grub_strtoul (guid, &guid, 16)); + if (*guid != '-') + return 0; + guid++; + + efivar->guid.data2 = grub_cpu_to_le16 (grub_strtoul (guid, &guid, 16)); + if (*guid != '-') + return 0; + guid++; + + efivar->guid.data3 = grub_cpu_to_le16 (grub_strtoul (guid, &guid, 16)); + if (*guid != '-') + return 0; + guid++; + + guidcomp = grub_strtoull (guid, 0, 16); + for (i = 0; i < 8; i++) + efivar->guid.data4[i] = (guidcomp >> (56 - 8 * i)) & 0xff; + + efivar->attributes = grub_strtoull (attr, 0, 16); + + varname = grub_malloc (grub_strlen (name) + 1); + if (! varname) + return 1; + + if (unescape (name, varname, varname + grub_strlen (name) + 1, &len)) + return 1; + + len = grub_utf8_to_utf16 ((grub_uint16_t *) nvramptr, + (nvramsize - (nvramptr - nvram)) / 2, + (grub_uint8_t *) varname, len, NULL); + + if (len < 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "broken UTF-8 in variable name"); + return 1; + } + + nvramptr += 2 * len; + *((grub_uint16_t *) nvramptr) = 0; + nvramptr += 2; + efivar->namelen = 2 * len + 2; + + if (unescape (var->value, nvramptr, nvram + nvramsize, &len)) + { + efivar->namelen = 0; + return 1; + } + + nvramptr += len; + + efivar->size = len; + + return 0; + } /* Copy to definitive loaction */ grub_dprintf ("efiemu", "preparing pnvram\n"); - grub_memcpy (nvram_def, nvram, nvramsize); + + env = grub_env_get ("EfiEmu.pnvram.high_monotonic_count"); + *high_monotonic_count = env ? grub_strtoul (env, 0, 0) : 1; + env = grub_env_get ("EfiEmu.pnvram.timezone"); + *timezone = env ? grub_strtosl (env, 0, 0) : GRUB_EFI_UNSPECIFIED_TIMEZONE; + env = grub_env_get ("EfiEmu.pnvram.accuracy"); + *accuracy = env ? grub_strtoul (env, 0, 0) : 50000000; + env = grub_env_get ("EfiEmu.pnvram.daylight"); + *daylight = env ? grub_strtoul (env, 0, 0) : 0; + + nvramptr = nvram; + grub_memset (nvram, 0, nvramsize); + grub_env_iterate (iterate_env); + if (grub_errno) + return grub_errno; *nvramsize_def = nvramsize; - *high_monotonic_count_def = high_monotonic_count; - *timezone_def = timezone; - *daylight_def = daylight; - *accuracy_def = accuracy; /* Register symbols */ grub_efiemu_register_symbol ("efiemu_variables", nvram_handle, 0); @@ -113,197 +236,27 @@ nvram_unload (void * data __attribute__ ((unused))) grub_efiemu_mm_return_request (timezone_handle); grub_efiemu_mm_return_request (accuracy_handle); grub_efiemu_mm_return_request (daylight_handle); - - grub_free (nvram); - nvram = 0; } -/* Load the variables file It's in format - guid1:attr1:name1:data1; - guid2:attr2:name2:data2; - ... - Where all fields are in hex -*/ -static grub_err_t -read_pnvram (char *filename) -{ - char *buf, *ptr, *ptr2; - grub_file_t file; - grub_size_t size; - grub_uint8_t *nvramptr = nvram; - struct efi_variable *efivar; - grub_size_t guidlen, datalen; - unsigned i, j; - - file = grub_file_open (filename); - if (!file) - return grub_error (GRUB_ERR_BAD_OS, "couldn't read pnvram"); - size = grub_file_size (file); - buf = grub_malloc (size + 1); - if (!buf) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't read pnvram"); - if (grub_file_read (file, buf, size) != (grub_ssize_t) size) - return grub_error (GRUB_ERR_BAD_OS, "couldn't read pnvram"); - buf[size] = 0; - grub_file_close (file); - - for (ptr = buf; *ptr; ) - { - if (grub_isspace (*ptr)) - { - ptr++; - continue; - } - - efivar = (struct efi_variable *) nvramptr; - if (nvramptr - nvram + sizeof (struct efi_variable) > nvramsize) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "file is too large for reserved variable space"); - - nvramptr += sizeof (struct efi_variable); - - /* look ahow long guid field is*/ - guidlen = 0; - for (ptr2 = ptr; (grub_isspace (*ptr2) - || (*ptr2 >= '0' && *ptr2 <= '9') - || (*ptr2 >= 'a' && *ptr2 <= 'f') - || (*ptr2 >= 'A' && *ptr2 <= 'F')); - ptr2++) - if (!grub_isspace (*ptr2)) - guidlen++; - guidlen /= 2; - - /* Read guid */ - if (guidlen != sizeof (efivar->guid)) - { - grub_free (buf); - return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename); - } - for (i = 0; i < 2 * sizeof (efivar->guid); i++) - { - int hex = 0; - while (grub_isspace (*ptr)) - ptr++; - if (*ptr >= '0' && *ptr <= '9') - hex = *ptr - '0'; - if (*ptr >= 'a' && *ptr <= 'f') - hex = *ptr - 'a' + 10; - if (*ptr >= 'A' && *ptr <= 'F') - hex = *ptr - 'A' + 10; - - if (i%2 == 0) - ((grub_uint8_t *)&(efivar->guid))[i/2] = hex << 4; - else - ((grub_uint8_t *)&(efivar->guid))[i/2] |= hex; - ptr++; - } - - while (grub_isspace (*ptr)) - ptr++; - if (*ptr != ':') - { - grub_dprintf ("efiemu", "Not colon\n"); - grub_free (buf); - return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename); - } - ptr++; - while (grub_isspace (*ptr)) - ptr++; - - /* Attributes can be just parsed by existing functions */ - efivar->attributes = grub_strtoul (ptr, &ptr, 16); - - while (grub_isspace (*ptr)) - ptr++; - if (*ptr != ':') - { - grub_dprintf ("efiemu", "Not colon\n"); - grub_free (buf); - return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename); - } - ptr++; - while (grub_isspace (*ptr)) - ptr++; - - /* Read name and value */ - for (j = 0; j < 2; j++) - { - /* Look the length */ - datalen = 0; - for (ptr2 = ptr; *ptr2 && (grub_isspace (*ptr2) - || (*ptr2 >= '0' && *ptr2 <= '9') - || (*ptr2 >= 'a' && *ptr2 <= 'f') - || (*ptr2 >= 'A' && *ptr2 <= 'F')); - ptr2++) - if (!grub_isspace (*ptr2)) - datalen++; - datalen /= 2; - - if (nvramptr - nvram + datalen > nvramsize) - { - grub_free (buf); - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "file is too large for reserved " - " variable space"); - } - - for (i = 0; i < 2 * datalen; i++) - { - int hex = 0; - while (grub_isspace (*ptr)) - ptr++; - if (*ptr >= '0' && *ptr <= '9') - hex = *ptr - '0'; - if (*ptr >= 'a' && *ptr <= 'f') - hex = *ptr - 'a' + 10; - if (*ptr >= 'A' && *ptr <= 'F') - hex = *ptr - 'A' + 10; - - if (i%2 == 0) - nvramptr[i/2] = hex << 4; - else - nvramptr[i/2] |= hex; - ptr++; - } - nvramptr += datalen; - while (grub_isspace (*ptr)) - ptr++; - if (*ptr != (j ? ';' : ':')) - { - grub_free (buf); - grub_dprintf ("efiemu", j?"Not semicolon\n":"Not colon\n"); - return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename); - } - if (j) - efivar->size = datalen; - else - efivar->namelen = datalen; - - ptr++; - } - } - grub_free (buf); - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_efiemu_make_nvram (void) +grub_err_t +grub_efiemu_pnvram (void) { + const char *size; grub_err_t err; - err = grub_efiemu_autocore (); - if (err) - { - grub_free (nvram); - return err; - } + nvramsize = 0; + + size = grub_env_get ("EfiEmu.pnvram.size"); + if (size) + nvramsize = grub_strtoul (size, 0, 0); + + if (!nvramsize) + nvramsize = 2048; err = grub_efiemu_register_prepare_hook (nvram_set, nvram_unload, 0); if (err) - { - grub_free (nvram); - return err; - } + return err; + nvram_handle = grub_efiemu_request_memalign (1, nvramsize, GRUB_EFI_RUNTIME_SERVICES_DATA); @@ -323,78 +276,5 @@ grub_efiemu_make_nvram (void) = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t), GRUB_EFI_RUNTIME_SERVICES_DATA); - grub_efiemu_request_symbols (6); return GRUB_ERR_NONE; } - -grub_err_t -grub_efiemu_pnvram (void) -{ - if (nvram) - return GRUB_ERR_NONE; - - nvramsize = 2048; - high_monotonic_count = 1; - timezone = GRUB_EFI_UNSPECIFIED_TIMEZONE; - accuracy = 50000000; - daylight = 0; - - nvram = grub_zalloc (nvramsize); - if (!nvram) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Couldn't allocate space for temporary pnvram storage"); - - return grub_efiemu_make_nvram (); -} - -static grub_err_t -grub_cmd_efiemu_pnvram (struct grub_extcmd *cmd, - int argc, char **args) -{ - struct grub_arg_list *state = cmd->state; - grub_err_t err; - - if (argc > 1) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one argument expected"); - - nvramsize = state[0].set ? grub_strtoul (state[0].arg, 0, 0) : 2048; - high_monotonic_count = state[1].set ? grub_strtoul (state[1].arg, 0, 0) : 1; - timezone = state[2].set ? grub_strtosl (state[2].arg, 0, 0) - : GRUB_EFI_UNSPECIFIED_TIMEZONE; - accuracy = state[3].set ? grub_strtoul (state[3].arg, 0, 0) : 50000000; - daylight = state[4].set ? grub_strtoul (state[4].arg, 0, 0) : 0; - - nvram = grub_zalloc (nvramsize); - if (!nvram) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Couldn't allocate space for temporary pnvram storage"); - - if (argc == 1 && (err = read_pnvram (args[0]))) - { - grub_free (nvram); - return err; - } - return grub_efiemu_make_nvram (); -} - -static grub_extcmd_t cmd; - -void grub_efiemu_pnvram_cmd_register (void); -void grub_efiemu_pnvram_cmd_unregister (void); - -void -grub_efiemu_pnvram_cmd_register (void) -{ - cmd = grub_register_extcmd ("efiemu_pnvram", grub_cmd_efiemu_pnvram, - GRUB_COMMAND_FLAG_BOTH, - "efiemu_pnvram [FILENAME]", - "Initialise pseudo-NVRAM and load variables " - "from FILE", - options); -} - -void -grub_efiemu_pnvram_cmd_unregister (void) -{ - grub_unregister_extcmd (cmd); -} diff --git a/efiemu/prepare.c b/efiemu/prepare.c index 9e6d46fa1..620260049 100644 --- a/efiemu/prepare.c +++ b/efiemu/prepare.c @@ -36,7 +36,6 @@ SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks, int cntconftables = 0; struct SUFFIX (grub_efiemu_configuration_table) *conftables = 0; - struct SUFFIX (grub_efiemu_runtime_services) *runtime_services; int i; int handle; grub_off_t off; @@ -54,6 +53,7 @@ SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks, /* Switch from phase 1 (counting) to phase 2 (real job) */ grub_efiemu_alloc_syms (); grub_efiemu_mm_do_alloc (); + grub_efiemu_write_sym_markers (); grub_efiemu_system_table32 = 0; grub_efiemu_system_table64 = 0; @@ -81,16 +81,6 @@ SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks, = (struct SUFFIX (grub_efi_system_table) *) ((grub_uint8_t *) grub_efiemu_mm_obtain_request (handle) + off); - /* compute CRC32 of runtime_services */ - if ((err = grub_efiemu_resolve_symbol ("efiemu_runtime_services", - &handle, &off))) - return err; - runtime_services = (struct SUFFIX (grub_efiemu_runtime_services) *) - ((grub_uint8_t *) grub_efiemu_mm_obtain_request (handle) + off); - runtime_services->hdr.crc32 = 0; - runtime_services->hdr.crc32 = grub_getcrc32 - (0, runtime_services, runtime_services->hdr.header_size); - /* Put pointer to the list of configuration tables in system table */ grub_efiemu_write_value (&(SUFFIX (grub_efiemu_system_table)->configuration_table), 0, @@ -113,16 +103,51 @@ SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks, conftables[i].vendor_table = PTR_TO_UINT64 (cur->data); } + err = SUFFIX (grub_efiemu_crc) (); + if (err) + { + grub_efiemu_unload (); + return err; + } + + grub_dprintf ("efiemu","system_table = %p, conftables = %p (%d entries)\n", + SUFFIX (grub_efiemu_system_table), conftables, cntconftables); + + return GRUB_ERR_NONE; +} + +grub_err_t +SUFFIX (grub_efiemu_crc) (void) +{ + grub_err_t err; + int handle; + grub_off_t off; + struct SUFFIX (grub_efiemu_runtime_services) *runtime_services; + + /* compute CRC32 of runtime_services */ + err = grub_efiemu_resolve_symbol ("efiemu_runtime_services", + &handle, &off); + if (err) + return err; + + runtime_services = (struct SUFFIX (grub_efiemu_runtime_services) *) + ((grub_uint8_t *) grub_efiemu_mm_obtain_request (handle) + off); + runtime_services->hdr.crc32 = 0; + runtime_services->hdr.crc32 = grub_getcrc32 + (0, runtime_services, runtime_services->hdr.header_size); + + err = grub_efiemu_resolve_symbol ("efiemu_system_table", &handle, &off); + if (err) + return err; + /* compute CRC32 of system table */ SUFFIX (grub_efiemu_system_table)->hdr.crc32 = 0; SUFFIX (grub_efiemu_system_table)->hdr.crc32 = grub_getcrc32 (0, SUFFIX (grub_efiemu_system_table), SUFFIX (grub_efiemu_system_table)->hdr.header_size); - grub_dprintf ("efiemu","system_table = %p, runtime_services = %p," - " conftables = %p (%d entries)\n", - SUFFIX (grub_efiemu_system_table), runtime_services, - conftables, cntconftables); + grub_dprintf ("efiemu","system_table = %p, runtime_services = %p\n", + SUFFIX (grub_efiemu_system_table), runtime_services); return GRUB_ERR_NONE; } diff --git a/efiemu/runtime/efiemu.c b/efiemu/runtime/efiemu.c index 085e75d0c..73893414a 100644 --- a/efiemu/runtime/efiemu.c +++ b/efiemu/runtime/efiemu.c @@ -111,9 +111,8 @@ static grub_uint8_t loge[1000] = "EFIEMULOG"; static int logn = 9; #define LOG(x) { if (logn<900) loge[logn++]=x; } -static int ptv_relocated = 0; - /* Interface with grub */ +extern grub_uint8_t efiemu_ptv_relocated; struct grub_efi_runtime_services efiemu_runtime_services; struct grub_efi_system_table efiemu_system_table; extern struct grub_efiemu_ptv_rel efiemu_ptv_relloc[]; @@ -343,9 +342,9 @@ grub_efi_status_t EFI_FUNC LOG ('e'); /* Ensure that we are called only once */ - if (ptv_relocated) + if (efiemu_ptv_relocated) return GRUB_EFI_UNSUPPORTED; - ptv_relocated = 1; + efiemu_ptv_relocated = 1; /* Correct addresses using information supplied by grub */ for (cur_relloc = efiemu_ptv_relloc; cur_relloc->size;cur_relloc++) diff --git a/efiemu/symbols.c b/efiemu/symbols.c index ec508d975..4fc546b59 100644 --- a/efiemu/symbols.c +++ b/efiemu/symbols.c @@ -26,6 +26,7 @@ static int ptv_written = 0; static int ptv_alloc = 0; static int ptv_handle = 0; +static int relocated_handle = 0; static int ptv_requested = 0; static struct grub_efiemu_sym *efiemu_syms = 0; @@ -54,6 +55,8 @@ grub_efiemu_free_syms (void) ptv_requested = 0; grub_efiemu_mm_return_request (ptv_handle); ptv_handle = 0; + grub_efiemu_mm_return_request (relocated_handle); + relocated_handle = 0; } /* Announce that the module will need NUM allocators */ @@ -114,10 +117,26 @@ grub_efiemu_alloc_syms (void) ptv_handle = grub_efiemu_request_memalign (1, (ptv_requested + 1) * sizeof (struct grub_efiemu_ptv_rel), GRUB_EFI_RUNTIME_SERVICES_DATA); + relocated_handle = grub_efiemu_request_memalign + (1, sizeof (grub_uint8_t), GRUB_EFI_RUNTIME_SERVICES_DATA); + + grub_efiemu_register_symbol ("efiemu_ptv_relocated", relocated_handle, 0); grub_efiemu_register_symbol ("efiemu_ptv_relloc", ptv_handle, 0); return grub_errno; } +grub_err_t +grub_efiemu_write_sym_markers (void) +{ + struct grub_efiemu_ptv_rel *ptv_rels + = grub_efiemu_mm_obtain_request (ptv_handle); + grub_uint8_t *relocated = grub_efiemu_mm_obtain_request (relocated_handle); + grub_memset (ptv_rels, 0, (ptv_requested + 1) + * sizeof (struct grub_efiemu_ptv_rel)); + *relocated = 0; + return GRUB_ERR_NONE; +} + /* Write value (pointer to memory PLUS_HANDLE) - (pointer to memory MINUS_HANDLE) + VALUE to ADDR assuming that the size SIZE bytes. If PTV_NEEDED is 1 then announce it to runtime that this @@ -186,3 +205,67 @@ grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle, return GRUB_ERR_NONE; } + +grub_err_t +grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version + __attribute__ ((unused)), + grub_efi_memory_descriptor_t *virtual_map) +{ + grub_uint8_t *ptv_relocated; + struct grub_efiemu_ptv_rel *cur_relloc; + struct grub_efiemu_ptv_rel *ptv_rels; + + ptv_relocated = grub_efiemu_mm_obtain_request (relocated_handle); + ptv_rels = grub_efiemu_mm_obtain_request (ptv_handle); + + /* Ensure that we are called only once */ + if (*ptv_relocated) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "EfiEmu is already relocated"); + *ptv_relocated = 1; + + /* Correct addresses using information supplied by grub */ + for (cur_relloc = ptv_rels; cur_relloc->size; cur_relloc++) + { + grub_int64_t corr = 0; + grub_efi_memory_descriptor_t *descptr; + + /* Compute correction */ + for (descptr = virtual_map; + (grub_size_t) ((grub_uint8_t *) descptr + - (grub_uint8_t *) virtual_map) < memory_map_size; + descptr = (grub_efi_memory_descriptor_t *) + ((grub_uint8_t *) descptr + descriptor_size)) + { + if (descptr->type == cur_relloc->plustype) + corr += descptr->virtual_start - descptr->physical_start; + if (descptr->type == cur_relloc->minustype) + corr -= descptr->virtual_start - descptr->physical_start; + } + + /* Apply correction */ + switch (cur_relloc->size) + { + case 8: + *((grub_uint64_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + break; + case 4: + *((grub_uint32_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + break; + case 2: + *((grub_uint16_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + break; + case 1: + *((grub_uint8_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + break; + } + } + + /* Recompute crc32 of system table and runtime services */ + + if (grub_efiemu_sizeof_uintn_t () == 4) + return grub_efiemu_crc32 (); + else + return grub_efiemu_crc64 (); +} diff --git a/font/font.c b/font/font.c index a81291916..9a89cadc5 100644 --- a/font/font.c +++ b/font/font.c @@ -1,7 +1,7 @@ /* font.c - Font API and font file loader. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2003,2005,2006,2007,2008,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 @@ -26,6 +26,11 @@ #include #include #include +#include + +#ifdef USE_ASCII_FAILBACK +#include "ascii.h" +#endif #ifndef FONT_DEBUG #define FONT_DEBUG 0 @@ -43,6 +48,7 @@ struct char_index_entry #define FONT_WEIGHT_NORMAL 100 #define FONT_WEIGHT_BOLD 200 +#define ASCII_BITMAP_SIZE 16 struct grub_font { @@ -58,6 +64,7 @@ struct grub_font short leading; grub_uint32_t num_chars; struct char_index_entry *char_index; + grub_uint16_t *bmp_idx; }; /* Definition of font registry. */ @@ -83,39 +90,25 @@ struct font_file_section int eof; }; -/* Font file format constants. */ -static const char pff2_magic[4] = { 'P', 'F', 'F', '2' }; -static const char section_names_file[4] = { 'F', 'I', 'L', 'E' }; -static const char section_names_font_name[4] = { 'N', 'A', 'M', 'E' }; -static const char section_names_point_size[4] = { 'P', 'T', 'S', 'Z' }; -static const char section_names_weight[4] = { 'W', 'E', 'I', 'G' }; -static const char section_names_max_char_width[4] = { 'M', 'A', 'X', 'W' }; -static const char section_names_max_char_height[4] = { 'M', 'A', 'X', 'H' }; -static const char section_names_ascent[4] = { 'A', 'S', 'C', 'E' }; -static const char section_names_descent[4] = { 'D', 'E', 'S', 'C' }; -static const char section_names_char_index[4] = { 'C', 'H', 'I', 'X' }; -static const char section_names_data[4] = { 'D', 'A', 'T', 'A' }; - /* Replace unknown glyphs with a rounded question mark. */ -static grub_uint8_t unknown_glyph_bitmap[] = -{ - /* 76543210 */ - 0x7C, /* ooooo */ - 0x82, /* o o */ - 0xBA, /* o ooo o */ - 0xAA, /* o o o o */ - 0xAA, /* o o o o */ - 0x8A, /* o o o */ - 0x9A, /* o oo o */ - 0x92, /* o o o */ - 0x92, /* o o o */ - 0x92, /* o o o */ - 0x92, /* o o o */ - 0x82, /* o o */ - 0x92, /* o o o */ - 0x82, /* o o */ - 0x7C, /* ooooo */ - 0x00 /* */ +static grub_uint8_t unknown_glyph_bitmap[] = { + /* 76543210 */ + 0x7C, /* ooooo */ + 0x82, /* o o */ + 0xBA, /* o ooo o */ + 0xAA, /* o o o o */ + 0xAA, /* o o o o */ + 0x8A, /* o o o */ + 0x9A, /* o oo o */ + 0x92, /* o o o */ + 0x92, /* o o o */ + 0x92, /* o o o */ + 0x92, /* o o o */ + 0x82, /* o o */ + 0x92, /* o o o */ + 0x82, /* o o */ + 0x7C, /* ooooo */ + 0x00 /* */ }; /* The "unknown glyph" glyph, used as a last resort. */ @@ -129,6 +122,48 @@ static struct grub_font null_font; /* Flag to ensure module is initialized only once. */ static grub_uint8_t font_loader_initialized; +#ifdef USE_ASCII_FAILBACK +static struct grub_font_glyph *ascii_font_glyph[0x80]; +#endif + +static struct grub_font_glyph * +ascii_glyph_lookup (grub_uint32_t code) +{ +#ifdef USE_ASCII_FAILBACK + static int ascii_failback_initialized = 0; + + if (code >= 0x80) + return unknown_glyph; + + if (ascii_failback_initialized == 0) + { + int current; + for (current = 0; current < 0x80; current++) + { + ascii_font_glyph[current] = + grub_malloc (sizeof (struct grub_font_glyph) + ASCII_BITMAP_SIZE); + + ascii_font_glyph[current]->width = 8; + ascii_font_glyph[current]->height = 16; + ascii_font_glyph[current]->offset_x = 0; + ascii_font_glyph[current]->offset_y = -2; + ascii_font_glyph[current]->device_width = 8; + + grub_memcpy (ascii_font_glyph[current]->bitmap, + &ascii_bitmaps[(0x7f - current) * ASCII_BITMAP_SIZE], + ASCII_BITMAP_SIZE); + } + + ascii_failback_initialized = 1; + } + + return ascii_font_glyph[code]; +#else + (void) code; + return unknown_glyph; +#endif +} + void grub_font_loader_init (void) { @@ -137,9 +172,9 @@ grub_font_loader_init (void) return; /* Make glyph for unknown glyph. */ - unknown_glyph = grub_malloc(sizeof(struct grub_font_glyph) - + sizeof(unknown_glyph_bitmap)); - if (! unknown_glyph) + unknown_glyph = grub_malloc (sizeof (struct grub_font_glyph) + + sizeof (unknown_glyph_bitmap)); + if (!unknown_glyph) return; unknown_glyph->width = 8; @@ -147,13 +182,13 @@ grub_font_loader_init (void) unknown_glyph->offset_x = 0; unknown_glyph->offset_y = -3; unknown_glyph->device_width = 8; - grub_memcpy(unknown_glyph->bitmap, - unknown_glyph_bitmap, sizeof(unknown_glyph_bitmap)); + grub_memcpy (unknown_glyph->bitmap, + unknown_glyph_bitmap, sizeof (unknown_glyph_bitmap)); /* Initialize the null font. */ font_init (&null_font); null_font.name = ""; - null_font.ascent = unknown_glyph->height-3; + null_font.ascent = unknown_glyph->height - 3; null_font.descent = 3; null_font.max_char_width = unknown_glyph->width; null_font.max_char_height = unknown_glyph->height; @@ -180,6 +215,7 @@ font_init (grub_font_t font) font->descent = 0; font->num_chars = 0; font->char_index = 0; + font->bmp_idx = 0; } /* Open the next section in the file. @@ -210,7 +246,7 @@ open_section (grub_file_t file, struct font_file_section *section) else if (retval < 0) { grub_error (GRUB_ERR_BAD_FONT, - "Font format error: can't read section name"); + "font format error: can't read section name"); return 1; } @@ -225,7 +261,7 @@ open_section (grub_file_t file, struct font_file_section *section) else if (retval < 0) { grub_error (GRUB_ERR_BAD_FONT, - "Font format error: can't read section length"); + "font format error: can't read section length"); return 1; } @@ -246,22 +282,22 @@ open_section (grub_file_t file, struct font_file_section *section) grub_errno is set appropriately). */ static int load_font_index (grub_file_t file, grub_uint32_t sect_length, struct - grub_font *font) + grub_font *font) { unsigned i; grub_uint32_t last_code; #if FONT_DEBUG >= 2 - grub_printf("load_font_index(sect_length=%d)\n", sect_length); + grub_printf ("load_font_index(sect_length=%d)\n", sect_length); #endif /* Sanity check: ensure section length is divisible by the entry size. */ if ((sect_length % FONT_CHAR_INDEX_ENTRY_SIZE) != 0) { grub_error (GRUB_ERR_BAD_FONT, - "Font file format error: character index length %d " - "is not a multiple of the entry size %d", - sect_length, FONT_CHAR_INDEX_ENTRY_SIZE); + "font file format error: character index length %d " + "is not a multiple of the entry size %d", + sect_length, FONT_CHAR_INDEX_ENTRY_SIZE); return 1; } @@ -270,12 +306,20 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct /* Allocate the character index array. */ font->char_index = grub_malloc (font->num_chars - * sizeof (struct char_index_entry)); - if (! font->char_index) + * sizeof (struct char_index_entry)); + if (!font->char_index) return 1; + font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t)); + if (!font->bmp_idx) + { + grub_free (font->char_index); + return 1; + } + grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t)); + #if FONT_DEBUG >= 2 - grub_printf("num_chars=%d)\n", font->num_chars); + grub_printf ("num_chars=%d)\n", font->num_chars); #endif last_code = 0; @@ -287,27 +331,30 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct /* Read code point value; convert to native byte order. */ if (grub_file_read (file, &entry->code, 4) != 4) - return 1; + return 1; entry->code = grub_be_to_cpu32 (entry->code); /* Verify that characters are in ascending order. */ if (i != 0 && entry->code <= last_code) - { - grub_error (GRUB_ERR_BAD_FONT, - "Font characters not in ascending order: %u <= %u", - entry->code, last_code); - return 1; - } + { + grub_error (GRUB_ERR_BAD_FONT, + "font characters not in ascending order: %u <= %u", + entry->code, last_code); + return 1; + } + + if (entry->code < 0x10000) + font->bmp_idx[entry->code] = i; last_code = entry->code; /* Read storage flags byte. */ if (grub_file_read (file, &entry->storage_flags, 1) != 1) - return 1; + return 1; /* Read glyph data offset; convert to native byte order. */ if (grub_file_read (file, &entry->offset, 4) != 4) - return 1; + return 1; entry->offset = grub_be_to_cpu32 (entry->offset); /* No glyph loaded. Will be loaded on demand and cached thereafter. */ @@ -316,7 +363,7 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct #if FONT_DEBUG >= 5 /* Print the 1st 10 characters. */ if (i < 10) - grub_printf("c=%d o=%d\n", entry->code, entry->offset); + grub_printf ("c=%d o=%d\n", entry->code, entry->offset); #endif } @@ -332,7 +379,7 @@ read_section_as_string (struct font_file_section *section) grub_ssize_t ret; str = grub_malloc (section->length + 1); - if (! str) + if (!str) return 0; ret = grub_file_read (section->file, str, section->length); @@ -350,18 +397,18 @@ read_section_as_string (struct font_file_section *section) which is stored into *VALUE. Returns 0 upon success, nonzero upon failure. */ static int -read_section_as_short (struct font_file_section *section, grub_int16_t *value) +read_section_as_short (struct font_file_section *section, + grub_int16_t * value) { grub_uint16_t raw_value; if (section->length != 2) { grub_error (GRUB_ERR_BAD_FONT, - "Font file format error: section %c%c%c%c length " - "is %d but should be 2", - section->name[0], section->name[1], - section->name[2], section->name[3], - section->length); + "font file format error: section %c%c%c%c length " + "is %d but should be 2", + section->name[0], section->name[1], + section->name[2], section->name[3], section->length); return 1; } if (grub_file_read (section->file, &raw_value, 2) != 2) @@ -382,7 +429,7 @@ grub_font_load (const char *filename) grub_font_t font = 0; #if FONT_DEBUG >= 1 - grub_printf("add_font(%s)\n", filename); + grub_printf ("add_font(%s)\n", filename); #endif file = grub_buffile_open (filename, 1024); @@ -390,7 +437,7 @@ grub_font_load (const char *filename) goto fail; #if FONT_DEBUG >= 3 - grub_printf("file opened\n"); + grub_printf ("file opened\n"); #endif /* Read the FILE section. It indicates the file format. */ @@ -398,144 +445,166 @@ grub_font_load (const char *filename) goto fail; #if FONT_DEBUG >= 3 - grub_printf("opened FILE section\n"); + grub_printf ("opened FILE section\n"); #endif - if (grub_memcmp (section.name, section_names_file, 4) != 0) + if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FILE, + sizeof (FONT_FORMAT_SECTION_NAMES_FILE) - 1) != 0) { grub_error (GRUB_ERR_BAD_FONT, - "Font file format error: 1st section must be FILE"); + "font file format error: 1st section must be FILE"); goto fail; } #if FONT_DEBUG >= 3 - grub_printf("section name ok\n"); + grub_printf ("section name ok\n"); #endif if (section.length != 4) { grub_error (GRUB_ERR_BAD_FONT, - "Font file format error (file type ID length is %d " - "but should be 4)", section.length); + "font file format error (file type ID length is %d " + "but should be 4)", section.length); goto fail; } #if FONT_DEBUG >= 3 - grub_printf("section length ok\n"); + grub_printf ("section length ok\n"); #endif /* Check the file format type code. */ if (grub_file_read (file, magic, 4) != 4) goto fail; #if FONT_DEBUG >= 3 - grub_printf("read magic ok\n"); + grub_printf ("read magic ok\n"); #endif - if (grub_memcmp (magic, pff2_magic, 4) != 0) + if (grub_memcmp (magic, FONT_FORMAT_PFF2_MAGIC, 4) != 0) { - grub_error (GRUB_ERR_BAD_FONT, "Invalid font magic %x %x %x %x", - magic[0], magic[1], magic[2], magic[3]); + grub_error (GRUB_ERR_BAD_FONT, "invalid font magic %x %x %x %x", + magic[0], magic[1], magic[2], magic[3]); goto fail; } #if FONT_DEBUG >= 3 - grub_printf("compare magic ok\n"); + grub_printf ("compare magic ok\n"); #endif /* Allocate the font object. */ font = (grub_font_t) grub_malloc (sizeof (struct grub_font)); - if (! font) + if (!font) goto fail; font_init (font); font->file = file; #if FONT_DEBUG >= 3 - grub_printf("allocate font ok; loading font info\n"); + grub_printf ("allocate font ok; loading font info\n"); #endif /* Load the font information. */ while (1) { if (open_section (file, §ion) != 0) - { - if (section.eof) - break; /* Done reading the font file. */ - else - goto fail; - } + { + if (section.eof) + break; /* Done reading the font file. */ + else + goto fail; + } #if FONT_DEBUG >= 2 - grub_printf("opened section %c%c%c%c ok\n", - section.name[0], section.name[1], - section.name[2], section.name[3]); + grub_printf ("opened section %c%c%c%c ok\n", + section.name[0], section.name[1], + section.name[2], section.name[3]); #endif - if (grub_memcmp (section.name, section_names_font_name, 4) == 0) - { - font->name = read_section_as_string (§ion); - if (!font->name) - goto fail; - } - else if (grub_memcmp (section.name, section_names_point_size, 4) == 0) - { - if (read_section_as_short (§ion, &font->point_size) != 0) - goto fail; - } - else if (grub_memcmp (section.name, section_names_weight, 4) == 0) - { - char *wt; - wt = read_section_as_string (§ion); - if (!wt) - continue; - /* Convert the weight string 'normal' or 'bold' into a number. */ - if (grub_strcmp (wt, "normal") == 0) - font->weight = FONT_WEIGHT_NORMAL; - else if (grub_strcmp (wt, "bold") == 0) - font->weight = FONT_WEIGHT_BOLD; - grub_free (wt); - } - else if (grub_memcmp (section.name, section_names_max_char_width, 4) == 0) - { - if (read_section_as_short (§ion, &font->max_char_width) != 0) - goto fail; - } - else if (grub_memcmp (section.name, section_names_max_char_height, 4) == 0) - { - if (read_section_as_short (§ion, &font->max_char_height) != 0) - goto fail; - } - else if (grub_memcmp (section.name, section_names_ascent, 4) == 0) - { - if (read_section_as_short (§ion, &font->ascent) != 0) - goto fail; - } - else if (grub_memcmp (section.name, section_names_descent, 4) == 0) - { - if (read_section_as_short (§ion, &font->descent) != 0) - goto fail; - } - else if (grub_memcmp (section.name, section_names_char_index, 4) == 0) - { - if (load_font_index (file, section.length, font) != 0) - goto fail; - } - else if (grub_memcmp (section.name, section_names_data, 4) == 0) - { - /* When the DATA section marker is reached, we stop reading. */ - break; - } + if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FONT_NAME, + sizeof (FONT_FORMAT_SECTION_NAMES_FONT_NAME) - 1) == 0) + { + font->name = read_section_as_string (§ion); + if (!font->name) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_POINT_SIZE, + sizeof (FONT_FORMAT_SECTION_NAMES_POINT_SIZE) - + 1) == 0) + { + if (read_section_as_short (§ion, &font->point_size) != 0) + goto fail; + } + else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_WEIGHT, + sizeof (FONT_FORMAT_SECTION_NAMES_WEIGHT) - 1) + == 0) + { + char *wt; + wt = read_section_as_string (§ion); + if (!wt) + continue; + /* Convert the weight string 'normal' or 'bold' into a number. */ + if (grub_strcmp (wt, "normal") == 0) + font->weight = FONT_WEIGHT_NORMAL; + else if (grub_strcmp (wt, "bold") == 0) + font->weight = FONT_WEIGHT_BOLD; + grub_free (wt); + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH, + sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH) + - 1) == 0) + { + if (read_section_as_short (§ion, &font->max_char_width) != 0) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT, + sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT) + - 1) == 0) + { + if (read_section_as_short (§ion, &font->max_char_height) != 0) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_ASCENT, + sizeof (FONT_FORMAT_SECTION_NAMES_ASCENT) - 1) + == 0) + { + if (read_section_as_short (§ion, &font->ascent) != 0) + goto fail; + } + else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DESCENT, + sizeof (FONT_FORMAT_SECTION_NAMES_DESCENT) - 1) + == 0) + { + if (read_section_as_short (§ion, &font->descent) != 0) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_CHAR_INDEX, + sizeof (FONT_FORMAT_SECTION_NAMES_CHAR_INDEX) - + 1) == 0) + { + if (load_font_index (file, section.length, font) != 0) + goto fail; + } + else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DATA, + sizeof (FONT_FORMAT_SECTION_NAMES_DATA) - 1) == 0) + { + /* When the DATA section marker is reached, we stop reading. */ + break; + } else - { - /* Unhandled section type, simply skip past it. */ + { + /* Unhandled section type, simply skip past it. */ #if FONT_DEBUG >= 3 - grub_printf("Unhandled section type, skipping.\n"); + grub_printf ("Unhandled section type, skipping.\n"); #endif - grub_off_t section_end = grub_file_tell (file) + section.length; - if ((int) grub_file_seek (file, section_end) == -1) - goto fail; - } + grub_off_t section_end = grub_file_tell (file) + section.length; + if ((int) grub_file_seek (file, section_end) == -1) + goto fail; + } } - if (! font->name) + if (!font->name) { grub_printf ("Note: Font has no name.\n"); font->name = grub_strdup ("Unknown"); @@ -543,22 +612,19 @@ grub_font_load (const char *filename) #if FONT_DEBUG >= 1 grub_printf ("Loaded font `%s'.\n" - "Ascent=%d Descent=%d MaxW=%d MaxH=%d Number of characters=%d.\n", - font->name, - font->ascent, font->descent, - font->max_char_width, font->max_char_height, - font->num_chars); + "Ascent=%d Descent=%d MaxW=%d MaxH=%d Number of characters=%d.\n", + font->name, + font->ascent, font->descent, + font->max_char_width, font->max_char_height, font->num_chars); #endif if (font->max_char_width == 0 || font->max_char_height == 0 || font->num_chars == 0 - || font->char_index == 0 - || font->ascent == 0 - || font->descent == 0) + || font->char_index == 0 || font->ascent == 0 || font->descent == 0) { grub_error (GRUB_ERR_BAD_FONT, - "Invalid font file: missing some required data."); + "invalid font file: missing some required data"); goto fail; } @@ -594,7 +660,7 @@ read_be_int16 (grub_file_t file, grub_int16_t * value) /* Return a pointer to the character index entry for the glyph corresponding to the codepoint CODE in the font FONT. If not found, return zero. */ -static struct char_index_entry * +static inline struct char_index_entry * find_glyph (const grub_font_t font, grub_uint32_t code) { struct char_index_entry *table; @@ -602,23 +668,32 @@ find_glyph (const grub_font_t font, grub_uint32_t code) grub_size_t hi; grub_size_t mid; - /* Do a binary search in `char_index', which is ordered by code point. */ table = font->char_index; + + /* Use BMP index if possible. */ + if (code < 0x10000 && font->bmp_idx) + { + if (font->bmp_idx[code] == 0xffff) + return 0; + return &table[font->bmp_idx[code]]; + } + + /* Do a binary search in `char_index', which is ordered by code point. */ lo = 0; hi = font->num_chars - 1; - if (! table) + if (!table) return 0; while (lo <= hi) { mid = lo + (hi - lo) / 2; if (code < table[mid].code) - hi = mid - 1; + hi = mid - 1; else if (code > table[mid].code) - lo = mid + 1; + lo = mid + 1; else - return &table[mid]; + return &table[mid]; } return 0; @@ -644,12 +719,12 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) int len; if (index_entry->glyph) - /* Return cached glyph. */ - return index_entry->glyph; + /* Return cached glyph. */ + return index_entry->glyph; - if (! font->file) - /* No open file, can't load any glyphs. */ - return 0; + if (!font->file) + /* No open file, can't load any glyphs. */ + return 0; /* Make sure we can find glyphs for error messages. Push active error message to error stack and reset error message. */ @@ -658,23 +733,23 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) grub_file_seek (font->file, index_entry->offset); /* Read the glyph width, height, and baseline. */ - if (read_be_uint16(font->file, &width) != 0 - || read_be_uint16(font->file, &height) != 0 - || read_be_int16(font->file, &xoff) != 0 - || read_be_int16(font->file, &yoff) != 0 - || read_be_int16(font->file, &dwidth) != 0) - { - remove_font (font); - return 0; - } + if (read_be_uint16 (font->file, &width) != 0 + || read_be_uint16 (font->file, &height) != 0 + || read_be_int16 (font->file, &xoff) != 0 + || read_be_int16 (font->file, &yoff) != 0 + || read_be_int16 (font->file, &dwidth) != 0) + { + remove_font (font); + return 0; + } len = (width * height + 7) / 8; glyph = grub_malloc (sizeof (struct grub_font_glyph) + len); - if (! glyph) - { - remove_font (font); - return 0; - } + if (!glyph) + { + remove_font (font); + return 0; + } glyph->font = font; glyph->width = width; @@ -685,13 +760,13 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) /* Don't try to read empty bitmaps (e.g., space characters). */ if (len != 0) - { - if (grub_file_read (font->file, glyph->bitmap, len) != len) - { - remove_font (font); - return 0; - } - } + { + if (grub_file_read (font->file, glyph->bitmap, len) != len) + { + remove_font (font); + return 0; + } + } /* Restore old error message. */ grub_error_pop (); @@ -715,7 +790,7 @@ free_font (grub_font_t font) if (font) { if (font->file) - grub_file_close (font->file); + grub_file_close (font->file); grub_free (font->name); grub_free (font->family); grub_free (font->char_index); @@ -732,7 +807,7 @@ register_font (grub_font_t font) struct grub_font_node *node = 0; node = grub_malloc (sizeof (struct grub_font_node)); - if (! node) + if (!node) return 1; node->value = font; @@ -750,18 +825,17 @@ remove_font (grub_font_t font) struct grub_font_node **nextp, *cur; for (nextp = &grub_font_list, cur = *nextp; - cur; - nextp = &cur->next, cur = cur->next) + cur; nextp = &cur->next, cur = cur->next) { if (cur->value == font) - { - *nextp = cur->next; + { + *nextp = cur->next; - /* Free the node, but not the font itself. */ - grub_free (cur); + /* Free the node, but not the font itself. */ + grub_free (cur); - return; - } + return; + } } } @@ -778,7 +852,7 @@ grub_font_get (const char *font_name) { grub_font_t font = node->value; if (grub_strcmp (font->name, font_name) == 0) - return font; + return font; } /* If no font by that name is found, return the first font in the list @@ -790,7 +864,7 @@ grub_font_get (const char *font_name) return &null_font; } -/* Get the full name of the font. For instance, "Helvetica Bold 12". */ +/* Get the full name of the font. */ const char * grub_font_get_name (grub_font_t font) { @@ -855,7 +929,7 @@ grub_font_get_string_width (grub_font_t font, const char *str) const grub_uint8_t *ptr; for (ptr = (const grub_uint8_t *) str, width = 0; - grub_utf8_to_ucs4 (&code, 1, ptr, -1, &ptr) > 0; ) + grub_utf8_to_ucs4 (&code, 1, ptr, -1, &ptr) > 0;) { glyph = grub_font_get_glyph_with_fallback (font, code); width += glyph->device_width; @@ -865,15 +939,18 @@ grub_font_get_string_width (grub_font_t font, const char *str) } /* Get the glyph for FONT corresponding to the Unicode code point CODE. - Returns a pointer to an glyph indicating there is no glyph available - if CODE does not exist in the font. The glyphs are cached once loaded. */ + Returns the ASCII glyph for the code if no other fonts are available. + The glyphs are cached once loaded. */ struct grub_font_glyph * grub_font_get_glyph (grub_font_t font, grub_uint32_t code) { - struct grub_font_glyph *glyph; - glyph = grub_font_get_glyph_internal (font, code); + struct grub_font_glyph *glyph = 0; + if (font) + glyph = grub_font_get_glyph_internal (font, code); if (glyph == 0) - glyph = unknown_glyph; + { + glyph = ascii_glyph_lookup (code); + } return glyph; } @@ -886,7 +963,7 @@ grub_font_get_glyph (grub_font_t font, grub_uint32_t code) sizes are used so that tiny 8 point glyphs are not mixed into a string of 24 point text unless there is no other choice. */ static int -get_font_diversity(grub_font_t a, grub_font_t b) +get_font_diversity (grub_font_t a, grub_font_t b) { int d; @@ -936,7 +1013,7 @@ grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code) /* First try to get the glyph from the specified font. */ glyph = grub_font_get_glyph_internal (font, code); if (glyph) - return glyph; + return glyph; } /* Otherwise, search all loaded fonts for the glyph and use the one from @@ -953,23 +1030,23 @@ grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code) glyph = grub_font_get_glyph_internal (curfont, code); if (glyph) - { - int d; + { + int d; - d = get_font_diversity (curfont, font); - if (d < best_diversity) - { - best_diversity = d; - best_glyph = glyph; - } - } + d = get_font_diversity (curfont, font); + if (d < best_diversity) + { + best_diversity = d; + best_glyph = glyph; + } + } } if (best_glyph) return best_glyph; else - /* Glyph not available in any font. Return unknown glyph. */ - return unknown_glyph; + /* Glyph not available in any font. Return ASCII failback. */ + return ascii_glyph_lookup (code); } @@ -977,9 +1054,8 @@ grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code) baseline of the character, while the x coordinate designates the left side location of the character. */ grub_err_t -grub_font_draw_glyph (struct grub_font_glyph *glyph, - grub_video_color_t color, - int left_x, int baseline_y) +grub_font_draw_glyph (struct grub_font_glyph * glyph, + grub_video_color_t color, int left_x, int baseline_y) { struct grub_video_bitmap glyph_bitmap; @@ -990,8 +1066,7 @@ grub_font_draw_glyph (struct grub_font_glyph *glyph, glyph_bitmap.mode_info.width = glyph->width; glyph_bitmap.mode_info.height = glyph->height; glyph_bitmap.mode_info.mode_type = - (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) - | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP; + (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP; glyph_bitmap.mode_info.blit_format = GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED; glyph_bitmap.mode_info.bpp = 1; @@ -1006,11 +1081,11 @@ grub_font_draw_glyph (struct grub_font_glyph *glyph, glyph_bitmap.mode_info.bg_green = 0; glyph_bitmap.mode_info.bg_blue = 0; glyph_bitmap.mode_info.bg_alpha = 0; - grub_video_unmap_color(color, - &glyph_bitmap.mode_info.fg_red, - &glyph_bitmap.mode_info.fg_green, - &glyph_bitmap.mode_info.fg_blue, - &glyph_bitmap.mode_info.fg_alpha); + grub_video_unmap_color (color, + &glyph_bitmap.mode_info.fg_red, + &glyph_bitmap.mode_info.fg_green, + &glyph_bitmap.mode_info.fg_blue, + &glyph_bitmap.mode_info.fg_alpha); glyph_bitmap.data = glyph->bitmap; int bitmap_left = left_x + glyph->offset_x; @@ -1018,9 +1093,8 @@ grub_font_draw_glyph (struct grub_font_glyph *glyph, int bitmap_top = bitmap_bottom - glyph->height; return grub_video_blit_bitmap (&glyph_bitmap, GRUB_VIDEO_BLIT_BLEND, - bitmap_left, bitmap_top, - 0, 0, - glyph->width, glyph->height); + bitmap_left, bitmap_top, + 0, 0, glyph->width, glyph->height); } /* Draw a UTF-8 string of text on the current video render target. @@ -1030,8 +1104,7 @@ grub_font_draw_glyph (struct grub_font_glyph *glyph, a glyph from another loaded font may be used instead. */ grub_err_t grub_font_draw_string (const char *str, grub_font_t font, - grub_video_color_t color, - int left_x, int baseline_y) + grub_video_color_t color, int left_x, int baseline_y) { int x; struct grub_font_glyph *glyph; @@ -1039,15 +1112,13 @@ grub_font_draw_string (const char *str, grub_font_t font, const grub_uint8_t *ptr; for (ptr = (const grub_uint8_t *) str, x = left_x; - grub_utf8_to_ucs4 (&code, 1, ptr, -1, &ptr) > 0; ) + grub_utf8_to_ucs4 (&code, 1, ptr, -1, &ptr) > 0;) { glyph = grub_font_get_glyph_with_fallback (font, code); - if (grub_font_draw_glyph (glyph, color, x, baseline_y) - != GRUB_ERR_NONE) - return grub_errno; + if (grub_font_draw_glyph (glyph, color, x, baseline_y) != GRUB_ERR_NONE) + return grub_errno; x += glyph->device_width; } return GRUB_ERR_NONE; } - diff --git a/font/font_cmd.c b/font/font_cmd.c index 0402b8d77..8b00dd8b9 100644 --- a/font/font_cmd.c +++ b/font/font_cmd.c @@ -21,6 +21,7 @@ #include #include #include +#include static grub_err_t loadfont_command (grub_command_t cmd __attribute__ ((unused)), @@ -56,20 +57,20 @@ lsfonts_command (grub_command_t cmd __attribute__ ((unused)), static grub_command_t cmd_loadfont, cmd_lsfonts; -GRUB_MOD_INIT(font_manager) +GRUB_MOD_INIT(font) { grub_font_loader_init (); cmd_loadfont = grub_register_command ("loadfont", loadfont_command, - "loadfont FILE...", - "Specify one or more font files to load."); + N_("FILE..."), + N_("Specify one or more font files to load.")); cmd_lsfonts = grub_register_command ("lsfonts", lsfonts_command, - 0, "List the loaded fonts."); + 0, N_("List the loaded fonts.")); } -GRUB_MOD_FINI(font_manager) +GRUB_MOD_FINI(font) { /* TODO: Determine way to free allocated resources. Warning: possible pointer references could be in use. */ diff --git a/fs/affs.c b/fs/affs.c index cfe7d579b..3dc80752d 100644 --- a/fs/affs.c +++ b/fs/affs.c @@ -1,7 +1,7 @@ /* affs.c - Amiga Fast FileSystem. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2005,2006,2007,2008,2009 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 @@ -182,14 +182,14 @@ grub_affs_mount (grub_disk_t disk) /* Make sure this is an affs filesystem. */ if (grub_strncmp ((char *) (data->bblock.type), "DOS", 3)) { - grub_error (GRUB_ERR_BAD_FS, "not an affs filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an AFFS filesystem"); goto fail; } /* Test if the filesystem is a OFS filesystem. */ if (! (data->bblock.flags & GRUB_AFFS_FLAG_FFS)) { - grub_error (GRUB_ERR_BAD_FS, "ofs not yet supported"); + grub_error (GRUB_ERR_BAD_FS, "OFS not yet supported"); goto fail; } @@ -231,7 +231,7 @@ grub_affs_mount (grub_disk_t disk) } if (-checksum != checksumr) { - grub_error (GRUB_ERR_BAD_FS, "affs blocksize could not be determined"); + grub_error (GRUB_ERR_BAD_FS, "AFFS blocksize couldn't be determined"); goto fail; } blocksize++; @@ -248,7 +248,7 @@ grub_affs_mount (grub_disk_t disk) fail: if (grub_errno == GRUB_ERR_OUT_OF_RANGE) - grub_error (GRUB_ERR_BAD_FS, "not an affs filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an AFFS filesystem"); grub_free (data); grub_free (rootblock); diff --git a/fs/cpio.c b/fs/cpio.c index 3f3a3d1a0..c087b4f90 100644 --- a/fs/cpio.c +++ b/fs/cpio.c @@ -1,7 +1,7 @@ /* cpio.c - cpio and tar filesystem. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2007,2008,2009 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -88,7 +88,7 @@ grub_cpio_find_file (struct grub_cpio_data *data, char **name, return grub_errno; if (hd.magic != MAGIC_BCPIO) - return grub_error (GRUB_ERR_BAD_FS, "Invalid cpio archive"); + return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive"); data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2; @@ -130,7 +130,7 @@ grub_cpio_find_file (struct grub_cpio_data *data, char **name, } if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1)) - return grub_error (GRUB_ERR_BAD_FS, "Invalid tar archive"); + return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive"); if ((*name = grub_strdup (hd.name)) == NULL) return grub_errno; @@ -280,8 +280,10 @@ grub_cpio_open (grub_file_t file, const char *name) /* Compare NAME and FN by hand in order to cope with duplicate slashes. */ - i = 1; + i = 0; j = 0; + while (name[i] == '/') + i++; while (1) { if (name[i] != fn[j]) @@ -290,13 +292,16 @@ grub_cpio_open (grub_file_t file, const char *name) if (name[i] == '\0') break; - if (name[i] == '/' && name[i+1] == '/') + while (name[i] == '/' && name[i+1] == '/') i++; i++; j++; } + if (name[i] != fn[j]) + goto no_match; + file->data = data; file->size = data->size; grub_free (fn); diff --git a/fs/ext2.c b/fs/ext2.c index e7a20a43b..f2fec828a 100644 --- a/fs/ext2.c +++ b/fs/ext2.c @@ -1,7 +1,7 @@ /* ext2.c - Second Extended filesystem */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2007,2008,2009 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 @@ -436,7 +436,8 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) grub_uint32_t indir[blksz / 4]; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (inode->blocks.indir_block) + ((grub_disk_addr_t) + grub_le_to_cpu32 (inode->blocks.indir_block)) << log2_blksz, 0, blksz, indir)) return grub_errno; @@ -452,13 +453,15 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) grub_uint32_t indir[blksz / 4]; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (inode->blocks.double_indir_block) + ((grub_disk_addr_t) + grub_le_to_cpu32 (inode->blocks.double_indir_block)) << log2_blksz, 0, blksz, indir)) return grub_errno; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (indir[rblock / perblock]) + ((grub_disk_addr_t) + grub_le_to_cpu32 (indir[rblock / perblock])) << log2_blksz, 0, blksz, indir)) return grub_errno; @@ -875,12 +878,15 @@ grub_ext2_uuid (grub_device_t device, char **uuid) data = grub_ext2_mount (disk); if (data) { - *uuid = grub_malloc (40 + sizeof ('\0')); - grub_sprintf (*uuid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", - grub_be_to_cpu16 (data->sblock.uuid[0]), grub_be_to_cpu16 (data->sblock.uuid[1]), - grub_be_to_cpu16 (data->sblock.uuid[2]), grub_be_to_cpu16 (data->sblock.uuid[3]), - grub_be_to_cpu16 (data->sblock.uuid[4]), grub_be_to_cpu16 (data->sblock.uuid[5]), - grub_be_to_cpu16 (data->sblock.uuid[6]), grub_be_to_cpu16 (data->sblock.uuid[7])); + *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + grub_be_to_cpu16 (data->sblock.uuid[0]), + grub_be_to_cpu16 (data->sblock.uuid[1]), + grub_be_to_cpu16 (data->sblock.uuid[2]), + grub_be_to_cpu16 (data->sblock.uuid[3]), + grub_be_to_cpu16 (data->sblock.uuid[4]), + grub_be_to_cpu16 (data->sblock.uuid[5]), + grub_be_to_cpu16 (data->sblock.uuid[6]), + grub_be_to_cpu16 (data->sblock.uuid[7])); } else *uuid = NULL; diff --git a/fs/fat.c b/fs/fat.c index e7f01629e..89050943c 100644 --- a/fs/fat.c +++ b/fs/fat.c @@ -25,6 +25,7 @@ #include #include #include +#include #define GRUB_FAT_DIR_ENTRY_SIZE 32 @@ -337,7 +338,7 @@ grub_fat_mount (grub_disk_t disk) fail: grub_free (data); - grub_error (GRUB_ERR_BAD_FS, "not a fat filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a FAT filesystem"); return 0; } @@ -591,6 +592,7 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data, } grub_free (filename); + grub_free (unibuf); return grub_errno; } @@ -832,9 +834,9 @@ grub_fat_uuid (grub_device_t device, char **uuid) data = grub_fat_mount (disk); if (data) { - *uuid = grub_malloc (sizeof ("xxxx-xxxx")); - grub_sprintf (*uuid, "%04x-%04x", (grub_uint16_t) (data->uuid >> 16), - (grub_uint16_t) data->uuid); + *uuid = grub_xasprintf ("%04x-%04x", + (grub_uint16_t) (data->uuid >> 16), + (grub_uint16_t) data->uuid); } else *uuid = NULL; diff --git a/fs/hfs.c b/fs/hfs.c index 5062b5f71..cef856326 100644 --- a/fs/hfs.c +++ b/fs/hfs.c @@ -1,7 +1,7 @@ /* hfs.c - HFS. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2004,2005,2006,2007,2008,2009 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 @@ -365,7 +365,7 @@ grub_hfs_mount (grub_disk_t disk) if (grub_hfs_find_node (data, (char *) &key, data->cat_root, 0, (char *) &dir, sizeof (dir)) == 0) { - grub_error (GRUB_ERR_BAD_FS, "can not find the hfs root directory"); + grub_error (GRUB_ERR_BAD_FS, "cannot find the HFS root directory"); goto fail; } @@ -379,7 +379,7 @@ grub_hfs_mount (grub_disk_t disk) grub_free (data); if (grub_errno == GRUB_ERR_OUT_OF_RANGE) - grub_error (GRUB_ERR_BAD_FS, "not a hfs filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a HFS filesystem"); return 0; } @@ -1072,6 +1072,30 @@ grub_hfs_label (grub_device_t device, char **label) return grub_errno; } +static grub_err_t +grub_hfs_uuid (grub_device_t device, char **uuid) +{ + struct grub_hfs_data *data; + + grub_dl_ref (my_mod); + + data = grub_hfs_mount (device->disk); + if (data && data->sblock.num_serial != 0) + { + *uuid = grub_xasprintf ("%016llx", + (unsigned long long) + grub_be_to_cpu64 (data->sblock.num_serial)); + } + else + *uuid = NULL; + + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; +} + static struct grub_fs grub_hfs_fs = @@ -1082,6 +1106,7 @@ static struct grub_fs grub_hfs_fs = .read = grub_hfs_read, .close = grub_hfs_close, .label = grub_hfs_label, + .uuid = grub_hfs_uuid, .next = 0 }; diff --git a/fs/hfsplus.c b/fs/hfsplus.c index b306e8d6a..bcb8e9584 100644 --- a/fs/hfsplus.c +++ b/fs/hfsplus.c @@ -28,6 +28,7 @@ #include #include #include +#include #define GRUB_HFSPLUS_MAGIC 0x482B #define GRUB_HFSPLUSX_MAGIC 0x4858 @@ -501,7 +502,7 @@ grub_hfsplus_mount (grub_disk_t disk) fail: if (grub_errno == GRUB_ERR_OUT_OF_RANGE) - grub_error (GRUB_ERR_BAD_FS, "not a hfsplus filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a HFS+ filesystem"); grub_free (data); return 0; @@ -652,7 +653,7 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree, btree->nodesize, (char *) node) <= 0) { grub_free (node); - return grub_error (GRUB_ERR_BAD_FS, "Couldn't read i-node."); + return grub_error (GRUB_ERR_BAD_FS, "couldn't read i-node"); } nodedesc = (struct grub_hfsplus_btnode *) node; @@ -994,10 +995,9 @@ grub_hfsplus_uuid (grub_device_t device, char **uuid) data = grub_hfsplus_mount (disk); if (data) { - *uuid = grub_malloc (16 + sizeof ('\0')); - grub_sprintf (*uuid, "%016llx", - (unsigned long long) - grub_be_to_cpu64 (data->volheader.num_serial)); + *uuid = grub_xasprintf ("%016llx", + (unsigned long long) + grub_be_to_cpu64 (data->volheader.num_serial)); } else *uuid = NULL; diff --git a/fs/i386/pc/pxe.c b/fs/i386/pc/pxe.c index 6c41d4298..82d8ee583 100644 --- a/fs/i386/pc/pxe.c +++ b/fs/i386/pc/pxe.c @@ -1,7 +1,7 @@ /* pxe.c - Driver to provide access to the pxe filesystem */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -33,11 +34,17 @@ #define SEGOFS(x) ((SEGMENT(x) << 16) + OFFSET(x)) #define LINEAR(x) (void *) (((x >> 16) <<4) + (x & 0xFFFF)) +struct grub_pxe_disk_data +{ + grub_uint32_t server_ip; + grub_uint32_t gateway_ip; +}; + struct grub_pxenv *grub_pxe_pxenv; -grub_uint32_t grub_pxe_your_ip; -grub_uint32_t grub_pxe_server_ip; -grub_uint32_t grub_pxe_gateway_ip; -int grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE; +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; +static unsigned grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE; static grub_file_t curr_file = 0; @@ -56,24 +63,83 @@ grub_pxe_iterate (int (*hook) (const char *name)) return 0; } +static grub_err_t +parse_ip (const char *val, grub_uint32_t *ip, const char **rest) +{ + grub_uint32_t newip = 0; + unsigned long t; + int i; + const char *ptr = val; + + for (i = 0; i < 4; i++) + { + t = grub_strtoul (ptr, (char **) &ptr, 0); + if (grub_errno) + return grub_errno; + if (t & ~0xff) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP."); + newip >>= 8; + newip |= (t << 24); + if (i != 3 && *ptr != '.') + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP."); + ptr++; + } + *ip = newip; + if (rest) + *rest = ptr - 1; + return 0; +} + static grub_err_t grub_pxe_open (const char *name, grub_disk_t disk) { - if (grub_strcmp (name, "pxe")) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a pxe disk"); + struct grub_pxe_disk_data *data; + + if (grub_strcmp (name, "pxe") != 0 + && grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a pxe disk"); + + data = grub_malloc (sizeof (*data)); + if (!data) + return grub_errno; + + if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) + { + const char *ptr; + grub_err_t err; + + ptr = name + sizeof ("pxe:") - 1; + err = parse_ip (ptr, &(data->server_ip), &ptr); + if (err) + return err; + if (*ptr == ':') + { + err = parse_ip (ptr + 1, &(data->server_ip), 0); + if (err) + return err; + } + else + data->gateway_ip = grub_pxe_default_gateway_ip; + } + else + { + data->server_ip = grub_pxe_default_server_ip; + data->gateway_ip = grub_pxe_default_gateway_ip; + } disk->total_sectors = 0; - disk->id = (unsigned long) "pxe"; + disk->id = (unsigned long) data; disk->has_partitions = 0; - disk->data = 0; + disk->data = data; return GRUB_ERR_NONE; } static void -grub_pxe_close (grub_disk_t disk __attribute((unused))) +grub_pxe_close (grub_disk_t disk) { + grub_free (disk->data); } static grub_err_t @@ -107,10 +173,15 @@ static struct grub_disk_dev grub_pxe_dev = }; static grub_err_t -grub_pxefs_dir (grub_device_t device UNUSED, const char *path UNUSED, +grub_pxefs_dir (grub_device_t device, + const char *path __attribute__ ((unused)), int (*hook) (const char *filename, - const struct grub_dirhook_info *info) UNUSED) + const struct grub_dirhook_info *info) + __attribute__ ((unused))) { + if (device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID) + return grub_error (GRUB_ERR_IO, "not a pxe disk"); + return GRUB_ERR_NONE; } @@ -123,16 +194,20 @@ grub_pxefs_open (struct grub_file *file, const char *name) struct grub_pxenv_tftp_open c2; } c; struct grub_pxe_data *data; + struct grub_pxe_disk_data *disk_data = file->device->disk->data; grub_file_t file_int, bufio; + if (file->device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID) + return grub_error (GRUB_ERR_IO, "not a pxe disk"); + if (curr_file != 0) { grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c.c2); curr_file = 0; } - c.c1.server_ip = grub_pxe_server_ip; - c.c1.gateway_ip = grub_pxe_gateway_ip; + c.c1.server_ip = disk_data->server_ip; + c.c1.gateway_ip = disk_data->gateway_ip; grub_strcpy ((char *)&c.c1.filename[0], name); grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1); if (c.c1.status) @@ -182,6 +257,7 @@ grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_pxenv_tftp_read c; struct grub_pxe_data *data; + struct grub_pxe_disk_data *disk_data = file->device->disk->data; grub_uint32_t pn, r; data = file->data; @@ -201,8 +277,8 @@ grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len) if (curr_file != 0) grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o); - o.server_ip = grub_pxe_server_ip; - o.gateway_ip = grub_pxe_gateway_ip; + o.server_ip = disk_data->server_ip; + 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; @@ -270,6 +346,100 @@ static struct grub_fs grub_pxefs_fs = .next = 0 }; +static char * +grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)), + const char *val __attribute__ ((unused))) +{ + return NULL; +} + +static void +set_mac_env (grub_uint8_t *mac_addr, grub_size_t mac_len) +{ + char buf[(sizeof ("XX:") - 1) * mac_len + 1]; + char *ptr = buf; + unsigned i; + + for (i = 0; i < mac_len; i++) + { + grub_snprintf (ptr, sizeof (buf) - (ptr - buf), + "%02x:", mac_addr[i] & 0xff); + ptr += (sizeof ("XX:") - 1); + } + if (mac_len) + *(ptr - 1) = 0; + else + buf[0] = 0; + + grub_env_set ("net_pxe_mac", buf); + /* XXX: Is it possible to change MAC in PXE? */ + grub_register_variable_hook ("net_pxe_mac", 0, grub_env_write_readonly); +} + +static void +set_env_limn_ro (const char *varname, char *value, grub_size_t len) +{ + char c; + c = value[len]; + value[len] = 0; + grub_env_set (varname, value); + value[len] = c; + grub_register_variable_hook (varname, 0, grub_env_write_readonly); +} + +static void +parse_dhcp_vendor (void *vend, int limit) +{ + grub_uint8_t *ptr, *ptr0; + + ptr = ptr0 = vend; + + if (grub_be_to_cpu32 (*(grub_uint32_t *) ptr) != 0x63825363) + return; + ptr = ptr + sizeof (grub_uint32_t); + while (ptr - ptr0 < limit) + { + grub_uint8_t tagtype; + grub_uint8_t taglength; + + tagtype = *ptr++; + + /* Pad tag. */ + if (tagtype == 0) + continue; + + /* End tag. */ + if (tagtype == 0xff) + return; + + taglength = *ptr++; + + switch (tagtype) + { + case 12: + set_env_limn_ro ("net_pxe_hostname", (char *) ptr, taglength); + break; + + case 15: + set_env_limn_ro ("net_pxe_domain", (char *) ptr, taglength); + break; + + case 17: + set_env_limn_ro ("net_pxe_rootpath", (char *) ptr, taglength); + break; + + case 18: + set_env_limn_ro ("net_pxe_extensionspath", (char *) ptr, taglength); + break; + + /* If you need any other options please contact GRUB + developpement team. */ + } + + ptr += taglength; + } +} + static void grub_pxe_detect (void) { @@ -291,9 +461,15 @@ grub_pxe_detect (void) bp = LINEAR (ci.buffer); grub_pxe_your_ip = bp->your_ip; - grub_pxe_server_ip = bp->server_ip; - grub_pxe_gateway_ip = bp->gateway_ip; - + grub_pxe_default_server_ip = bp->server_ip; + grub_pxe_default_gateway_ip = bp->gateway_ip; + set_mac_env (bp->mac_addr, bp->hw_len < sizeof (bp->mac_addr) ? bp->hw_len + : sizeof (bp->mac_addr)); + set_env_limn_ro ("net_pxe_boot_file", (char *) bp->boot_file, + sizeof (bp->boot_file)); + set_env_limn_ro ("net_pxe_dhcp_server_name", (char *) bp->server_name, + sizeof (bp->server_name)); + parse_dhcp_vendor (&bp->vendor, sizeof (bp->vendor)); grub_pxe_pxenv = pxenv; } @@ -309,11 +485,105 @@ grub_pxe_unload (void) } } +static void +set_ip_env (char *varname, grub_uint32_t ip) +{ + char buf[sizeof ("XXX.XXX.XXX.XXX")]; + + grub_snprintf (buf, sizeof (buf), "%d.%d.%d.%d", (ip & 0xff), + (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff); + grub_env_set (varname, buf); +} + +static char * +write_ip_env (grub_uint32_t *ip, const char *val) +{ + char *buf; + grub_err_t err; + grub_uint32_t newip; + + err = parse_ip (val, &newip, 0); + if (err) + return 0; + + /* Normalize the IP. */ + buf = grub_xasprintf ("%d.%d.%d.%d", (newip & 0xff), (newip >> 8) & 0xff, + (newip >> 16) & 0xff, (newip >> 24) & 0xff); + if (!buf) + return 0; + + *ip = newip; + + return buf; +} + +static char * +grub_env_write_pxe_default_server (struct grub_env_var *var + __attribute__ ((unused)), + const char *val) +{ + return write_ip_env (&grub_pxe_default_server_ip, val); +} + +static char * +grub_env_write_pxe_default_gateway (struct grub_env_var *var + __attribute__ ((unused)), + const char *val) +{ + return write_ip_env (&grub_pxe_default_gateway_ip, val); +} + +static char * +grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ ((unused)), + const char *val) +{ + unsigned size; + char *buf; + + size = grub_strtoul (val, 0, 0); + if (grub_errno) + return 0; + + if (size < GRUB_PXE_MIN_BLKSIZE) + size = GRUB_PXE_MIN_BLKSIZE; + else if (size > GRUB_PXE_MAX_BLKSIZE) + size = GRUB_PXE_MAX_BLKSIZE; + + buf = grub_xasprintf ("%d", size); + if (!buf) + return 0; + + grub_pxe_blksize = size; + + return buf; +} + + GRUB_MOD_INIT(pxe) { grub_pxe_detect (); if (grub_pxe_pxenv) { + char *buf; + + buf = grub_xasprintf ("%d", grub_pxe_blksize); + if (buf) + grub_env_set ("pxe_blksize", buf); + grub_free (buf); + + set_ip_env ("pxe_default_server", grub_pxe_default_server_ip); + set_ip_env ("pxe_default_gateway", grub_pxe_default_gateway_ip); + set_ip_env ("net_pxe_ip", grub_pxe_your_ip); + grub_register_variable_hook ("pxe_default_server", 0, + grub_env_write_pxe_default_server); + grub_register_variable_hook ("pxe_default_gateway", 0, + grub_env_write_pxe_default_gateway); + + /* XXX: Is it possible to change IP in PXE? */ + grub_register_variable_hook ("net_pxe_ip", 0, + grub_env_write_readonly); + grub_register_variable_hook ("pxe_blksize", 0, + grub_env_write_pxe_blocksize); grub_disk_dev_register (&grub_pxe_dev); grub_fs_register (&grub_pxefs_fs); } diff --git a/fs/iso9660.c b/fs/iso9660.c index 9b7ce765b..6dc465f25 100644 --- a/fs/iso9660.c +++ b/fs/iso9660.c @@ -2,7 +2,7 @@ SUSP, Rock Ridge. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2004,2005,2006,2007,2008,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 @@ -26,6 +26,7 @@ #include #include #include +#include #define GRUB_ISO9660_FSTYPE_DIR 0040000 #define GRUB_ISO9660_FSTYPE_REG 0100000 @@ -135,7 +136,6 @@ struct grub_iso9660_data struct grub_iso9660_primary_voldesc voldesc; grub_disk_t disk; unsigned int first_sector; - unsigned int length; int rockridge; int susp_skip; int joliet; @@ -279,13 +279,13 @@ grub_iso9660_mount (grub_disk_t disk) sizeof (struct grub_iso9660_primary_voldesc), (char *) &voldesc)) { - grub_error (GRUB_ERR_BAD_FS, "not a iso9660 filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); goto fail; } if (grub_strncmp ((char *) voldesc.voldesc.magic, "CD001", 5) != 0) { - grub_error (GRUB_ERR_BAD_FS, "not a iso9660 filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); goto fail; } @@ -314,7 +314,7 @@ grub_iso9660_mount (grub_disk_t disk) << GRUB_ISO9660_LOG2_BLKSZ), 0, sizeof (rootdir), (char *) &rootdir)) { - grub_error (GRUB_ERR_BAD_FS, "not a iso9660 filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); goto fail; } @@ -330,7 +330,7 @@ grub_iso9660_mount (grub_disk_t disk) << GRUB_ISO9660_LOG2_BLKSZ), sua_pos, sua_size, sua)) { - grub_error (GRUB_ERR_BAD_FS, "not a iso9660 filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); goto fail; } @@ -629,12 +629,16 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir, if (dir->data->joliet) { - char *oldname; + char *oldname, *semicolon; oldname = filename; filename = grub_iso9660_convert_string ((grub_uint16_t *) oldname, dirent.namelen >> 1); + semicolon = grub_strrchr (filename, ';'); + if (semicolon) + *semicolon = '\0'; + if (filename_alloc) grub_free (oldname); @@ -743,7 +747,6 @@ grub_iso9660_open (struct grub_file *file, const char *name) goto fail; data->first_sector = foundnode->blk; - data->length = foundnode->size; file->data = data; file->size = foundnode->size; @@ -772,7 +775,10 @@ grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len) data->first_sector << GRUB_ISO9660_LOG2_BLKSZ, file->offset, len, buf); - data->disk->read_hook = 0; + data->disk->read_hook = NULL; + + if (grub_errno) + return -1; return len; } @@ -831,21 +837,28 @@ grub_iso9660_uuid (grub_device_t device, char **uuid) && ! data->voldesc.modified.second[0] && ! data->voldesc.modified.second[1] && ! data->voldesc.modified.hundredth[0] && ! data->voldesc.modified.hundredth[1]) { - grub_error (GRUB_ERR_BAD_NUMBER, "No creation date in filesystem to generate UUID."); + grub_error (GRUB_ERR_BAD_NUMBER, "no creation date in filesystem to generate UUID"); *uuid = NULL; } else { - *uuid = grub_malloc (sizeof ("YYYY-MM-DD-HH-mm-ss-hh")); - grub_sprintf (*uuid, "%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c", - data->voldesc.modified.year[0], data->voldesc.modified.year[1], - data->voldesc.modified.year[2], data->voldesc.modified.year[3], - data->voldesc.modified.month[0], data->voldesc.modified.month[1], - data->voldesc.modified.day[0], data->voldesc.modified.day[1], - data->voldesc.modified.hour[0], data->voldesc.modified.hour[1], - data->voldesc.modified.minute[0], data->voldesc.modified.minute[1], - data->voldesc.modified.second[0], data->voldesc.modified.second[1], - data->voldesc.modified.hundredth[0], data->voldesc.modified.hundredth[1]); + *uuid = grub_xasprintf ("%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c", + data->voldesc.modified.year[0], + data->voldesc.modified.year[1], + data->voldesc.modified.year[2], + data->voldesc.modified.year[3], + data->voldesc.modified.month[0], + data->voldesc.modified.month[1], + data->voldesc.modified.day[0], + data->voldesc.modified.day[1], + data->voldesc.modified.hour[0], + data->voldesc.modified.hour[1], + data->voldesc.modified.minute[0], + data->voldesc.modified.minute[1], + data->voldesc.modified.second[0], + data->voldesc.modified.second[1], + data->voldesc.modified.hundredth[0], + data->voldesc.modified.hundredth[1]); } } else diff --git a/fs/jfs.c b/fs/jfs.c index b73f9bdd4..c9839a22f 100644 --- a/fs/jfs.c +++ b/fs/jfs.c @@ -24,6 +24,7 @@ #include #include #include +#include #define GRUB_JFS_MAX_SYMLNK_CNT 8 #define GRUB_JFS_FILETYPE_MASK 0170000 @@ -343,7 +344,7 @@ grub_jfs_mount (grub_disk_t disk) if (grub_strncmp ((char *) (data->sblock.magic), "JFS1", 4)) { - grub_error (GRUB_ERR_BAD_FS, "not a jfs filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a JFS filesystem"); goto fail; } @@ -362,7 +363,7 @@ grub_jfs_mount (grub_disk_t disk) grub_free (data); if (grub_errno == GRUB_ERR_OUT_OF_RANGE) - grub_error (GRUB_ERR_BAD_FS, "not a jfs filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a JFS filesystem"); return 0; } @@ -714,7 +715,7 @@ grub_jfs_lookup_symlink (struct grub_jfs_data *data, int ino) grub_jfs_find_file (data, symlink); if (grub_errno) - grub_error (grub_errno, "Can not follow symlink `%s'.", symlink); + grub_error (grub_errno, "cannot follow symlink `%s'", symlink); return grub_errno; } @@ -841,17 +842,16 @@ grub_jfs_uuid (grub_device_t device, char **uuid) data = grub_jfs_mount (disk); if (data) { - *uuid = grub_malloc (40 + sizeof ('\0')); - - grub_sprintf (*uuid, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - data->sblock.uuid[0], data->sblock.uuid[1], - data->sblock.uuid[2], data->sblock.uuid[3], - data->sblock.uuid[4], data->sblock.uuid[5], - data->sblock.uuid[6], data->sblock.uuid[7], - data->sblock.uuid[8], data->sblock.uuid[9], - data->sblock.uuid[10], data->sblock.uuid[11], - data->sblock.uuid[12], data->sblock.uuid[13], - data->sblock.uuid[14], data->sblock.uuid[15]); + *uuid = grub_xasprintf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x%02x%02x%02x%02x", + data->sblock.uuid[0], data->sblock.uuid[1], + data->sblock.uuid[2], data->sblock.uuid[3], + data->sblock.uuid[4], data->sblock.uuid[5], + data->sblock.uuid[6], data->sblock.uuid[7], + data->sblock.uuid[8], data->sblock.uuid[9], + data->sblock.uuid[10], data->sblock.uuid[11], + data->sblock.uuid[12], data->sblock.uuid[13], + data->sblock.uuid[14], data->sblock.uuid[15]); } else *uuid = NULL; diff --git a/fs/minix.c b/fs/minix.c index 08eb60729..a856e38c4 100644 --- a/fs/minix.c +++ b/fs/minix.c @@ -311,7 +311,7 @@ grub_minix_lookup_symlink (struct grub_minix_data *data, int ino) grub_minix_find_file (data, symlink); if (grub_errno) - grub_error (grub_errno, "Can not follow symlink `%s'.", symlink); + grub_error (grub_errno, "cannot follow symlink `%s'", symlink); return grub_errno; } diff --git a/fs/nilfs2.c b/fs/nilfs2.c new file mode 100644 index 000000000..7e0415d12 --- /dev/null +++ b/fs/nilfs2.c @@ -0,0 +1,1133 @@ +/* + * nilfs2.c - New Implementation of Log filesystem + * + * Written by Jiro SEKIBA + * + * Copyright (C) 2003,2004,2005,2007,2008,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 . + */ + + +/* Filetype information as used in inodes. */ +#define FILETYPE_INO_MASK 0170000 +#define FILETYPE_INO_REG 0100000 +#define FILETYPE_INO_DIRECTORY 0040000 +#define FILETYPE_INO_SYMLINK 0120000 + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NILFS_INODE_BMAP_SIZE 7 + +#define NILFS_SUPORT_REV 2 + +/* Magic value used to identify an nilfs2 filesystem. */ +#define NILFS2_SUPER_MAGIC 0x3434 +/* nilfs btree node flag. */ +#define NILFS_BTREE_NODE_ROOT 0x01 + +/* nilfs btree node level. */ +#define NILFS_BTREE_LEVEL_DATA 0 +#define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1) +#define NILFS_BTREE_LEVEL_MAX 14 + +struct grub_nilfs2_inode +{ + grub_uint64_t i_blocks; + grub_uint64_t i_size; + grub_uint64_t i_ctime; + grub_uint64_t i_mtime; + grub_uint32_t i_ctime_nsec; + grub_uint32_t i_mtime_nsec; + grub_uint32_t i_uid; + grub_uint32_t i_gid; + grub_uint16_t i_mode; + grub_uint16_t i_links_count; + grub_uint32_t i_flags; + grub_uint64_t i_bmap[NILFS_INODE_BMAP_SIZE]; +#define i_device_code i_bmap[0] + grub_uint64_t i_xattr; + grub_uint32_t i_generation; + grub_uint32_t i_pad; +}; + +struct grub_nilfs2_super_root +{ + grub_uint32_t sr_sum; + grub_uint16_t sr_bytes; + grub_uint16_t sr_flags; + grub_uint64_t sr_nongc_ctime; + struct grub_nilfs2_inode sr_dat; + struct grub_nilfs2_inode sr_cpfile; + struct grub_nilfs2_inode sr_sufile; +}; + +struct grub_nilfs2_super_block +{ + grub_uint32_t s_rev_level; + grub_uint16_t s_minor_rev_level; + grub_uint16_t s_magic; + grub_uint16_t s_bytes; + grub_uint16_t s_flags; + grub_uint32_t s_crc_seed; + grub_uint32_t s_sum; + grub_uint32_t s_log_block_size; + grub_uint64_t s_nsegments; + grub_uint64_t s_dev_size; + grub_uint64_t s_first_data_block; + grub_uint32_t s_blocks_per_segment; + grub_uint32_t s_r_segments_percentage; + grub_uint64_t s_last_cno; + grub_uint64_t s_last_pseg; + grub_uint64_t s_last_seq; + grub_uint64_t s_free_blocks_count; + grub_uint64_t s_ctime; + grub_uint64_t s_mtime; + grub_uint64_t s_wtime; + grub_uint16_t s_mnt_count; + grub_uint16_t s_max_mnt_count; + grub_uint16_t s_state; + grub_uint16_t s_errors; + grub_uint64_t s_lastcheck; + grub_uint32_t s_checkinterval; + grub_uint32_t s_creator_os; + grub_uint16_t s_def_resuid; + grub_uint16_t s_def_resgid; + grub_uint32_t s_first_ino; + grub_uint16_t s_inode_size; + grub_uint16_t s_dat_entry_size; + grub_uint16_t s_checkpoint_size; + grub_uint16_t s_segment_usage_size; + grub_uint8_t s_uuid[16]; + char s_volume_name[16]; + char s_last_mounted[64]; + grub_uint32_t s_c_interval; + grub_uint32_t s_c_block_max; + grub_uint32_t s_reserved[192]; +}; + +struct grub_nilfs2_dir_entry +{ + grub_uint64_t inode; + grub_uint16_t rec_len; + grub_uint8_t name_len; + grub_uint8_t file_type; +#if 0 /* followed by file name. */ + char name[NILFS_NAME_LEN]; + char pad; +#endif +} __attribute__ ((packed)); + +enum +{ + NILFS_FT_UNKNOWN, + NILFS_FT_REG_FILE, + NILFS_FT_DIR, + NILFS_FT_CHRDEV, + NILFS_FT_BLKDEV, + NILFS_FT_FIFO, + NILFS_FT_SOCK, + NILFS_FT_SYMLINK, + NILFS_FT_MAX +}; + +struct grub_nilfs2_finfo +{ + grub_uint64_t fi_ino; + grub_uint64_t fi_cno; + grub_uint32_t fi_nblocks; + grub_uint32_t fi_ndatablk; +}; + +struct grub_nilfs2_binfo_v +{ + grub_uint64_t bi_vblocknr; + grub_uint64_t bi_blkoff; +}; + +struct grub_nilfs2_binfo_dat +{ + grub_uint64_t bi_blkoff; + grub_uint8_t bi_level; + grub_uint8_t bi_pad[7]; +}; + +union grub_nilfs2_binfo +{ + struct grub_nilfs2_binfo_v bi_v; + struct grub_nilfs2_binfo_dat bi_dat; +}; + +struct grub_nilfs2_segment_summary +{ + grub_uint32_t ss_datasum; + grub_uint32_t ss_sumsum; + grub_uint32_t ss_magic; + grub_uint16_t ss_bytes; + grub_uint16_t ss_flags; + grub_uint64_t ss_seq; + grub_uint64_t ss_create; + grub_uint64_t ss_next; + grub_uint32_t ss_nblocks; + grub_uint32_t ss_nfinfo; + grub_uint32_t ss_sumbytes; + grub_uint32_t ss_pad; +}; + +struct grub_nilfs2_btree_node +{ + grub_uint8_t bn_flags; + grub_uint8_t bn_level; + grub_uint16_t bn_nchildren; + grub_uint32_t bn_pad; +}; + +struct grub_nilfs2_palloc_group_desc +{ + grub_uint32_t pg_nfrees; +}; + +struct grub_nilfs2_dat_entry +{ + grub_uint64_t de_blocknr; + grub_uint64_t de_start; + grub_uint64_t de_end; + grub_uint64_t de_rsv; +}; + +struct grub_nilfs2_snapshot_list +{ + grub_uint64_t ssl_next; + grub_uint64_t ssl_prev; +}; + +struct grub_nilfs2_cpfile_header +{ + grub_uint64_t ch_ncheckpoints; + grub_uint64_t ch_nsnapshots; + struct grub_nilfs2_snapshot_list ch_snapshot_list; +}; + +struct grub_nilfs2_checkpoint +{ + grub_uint32_t cp_flags; + grub_uint32_t cp_checkpoints_count; + struct grub_nilfs2_snapshot_list cp_snapshot_list; + grub_uint64_t cp_cno; + grub_uint64_t cp_create; + grub_uint64_t cp_nblk_inc; + grub_uint64_t cp_inodes_count; + grub_uint64_t cp_blocks_count; + struct grub_nilfs2_inode cp_ifile_inode; +}; + + +#define NILFS_BMAP_LARGE 0x1 +#define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(grub_uint64_t)) + +/* nilfs extra padding for nonroot btree node. */ +#define NILFS_BTREE_NODE_EXTRA_PAD_SIZE (sizeof(grub_uint64_t)) +#define NILFS_BTREE_ROOT_SIZE NILFS_BMAP_SIZE +#define NILFS_BTREE_ROOT_NCHILDREN_MAX \ + ((NILFS_BTREE_ROOT_SIZE - sizeof(struct nilfs_btree_node)) / \ + (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) ) + + +struct grub_fshelp_node +{ + struct grub_nilfs2_data *data; + struct grub_nilfs2_inode inode; + grub_uint64_t ino; + int inode_read; +}; + +struct grub_nilfs2_data +{ + struct grub_nilfs2_super_block sblock; + struct grub_nilfs2_super_root sroot; + struct grub_nilfs2_inode ifile; + grub_disk_t disk; + struct grub_nilfs2_inode *inode; + struct grub_fshelp_node diropen; +}; + +/* Log2 size of nilfs2 block in 512 blocks. */ +#define LOG2_NILFS2_BLOCK_SIZE(data) \ + (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 1) + +/* Log2 size of nilfs2 block in bytes. */ +#define LOG2_BLOCK_SIZE(data) \ + (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 10) + +/* The size of an nilfs2 block in bytes. */ +#define NILFS2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE (data)) + +static grub_uint64_t +grub_nilfs2_dat_translate (struct grub_nilfs2_data *data, grub_uint64_t key); +static grub_dl_t my_mod; + + + +static inline unsigned long +grub_nilfs2_palloc_entries_per_group (struct grub_nilfs2_data *data) +{ + return 1UL << (LOG2_BLOCK_SIZE (data) + 3); +} + +static inline grub_uint64_t +grub_nilfs2_palloc_group (struct grub_nilfs2_data *data, + grub_uint64_t nr, grub_uint32_t * offset) +{ + return grub_divmod64 (nr, grub_nilfs2_palloc_entries_per_group (data), + offset); +} + +static inline grub_uint32_t +grub_nilfs2_palloc_groups_per_desc_block (struct grub_nilfs2_data *data) +{ + return NILFS2_BLOCK_SIZE (data) / + sizeof (struct grub_nilfs2_palloc_group_desc); +} + +static inline grub_uint32_t +grub_nilfs2_entries_per_block (struct grub_nilfs2_data *data, + unsigned long entry_size) +{ + return NILFS2_BLOCK_SIZE (data) / entry_size; +} + + +static inline grub_uint32_t +grub_nilfs2_blocks_per_group (struct grub_nilfs2_data *data, + unsigned long entry_size) +{ + return grub_div_roundup (grub_nilfs2_palloc_entries_per_group (data), + grub_nilfs2_entries_per_block (data, + entry_size)) + 1; +} + +static inline grub_uint32_t +grub_nilfs2_blocks_per_desc_block (struct grub_nilfs2_data *data, + unsigned long entry_size) +{ + return grub_nilfs2_palloc_groups_per_desc_block (data) * + grub_nilfs2_blocks_per_group (data, entry_size) + 1; +} + +static inline grub_uint32_t +grub_nilfs2_palloc_desc_block_offset (struct grub_nilfs2_data *data, + unsigned long group, + unsigned long entry_size) +{ + grub_uint32_t desc_block = + group / grub_nilfs2_palloc_groups_per_desc_block (data); + return desc_block * grub_nilfs2_blocks_per_desc_block (data, entry_size); +} + +static inline grub_uint32_t +grub_nilfs2_palloc_bitmap_block_offset (struct grub_nilfs2_data *data, + unsigned long group, + unsigned long entry_size) +{ + unsigned long desc_offset = group % + grub_nilfs2_palloc_groups_per_desc_block (data); + + return grub_nilfs2_palloc_desc_block_offset (data, group, entry_size) + 1 + + desc_offset * grub_nilfs2_blocks_per_group (data, entry_size); +} + +static inline grub_uint32_t +grub_nilfs2_palloc_entry_offset (struct grub_nilfs2_data *data, + grub_uint64_t nr, unsigned long entry_size) +{ + unsigned long group; + grub_uint32_t group_offset; + + group = grub_nilfs2_palloc_group (data, nr, &group_offset); + + return grub_nilfs2_palloc_bitmap_block_offset (data, group, + entry_size) + 1 + + group_offset / grub_nilfs2_entries_per_block (data, entry_size); + +} + +static inline struct grub_nilfs2_btree_node * +grub_nilfs2_btree_get_root (struct grub_nilfs2_inode *inode) +{ + return (struct grub_nilfs2_btree_node *) &inode->i_bmap[0]; +} + +static inline int +grub_nilfs2_btree_get_level (struct grub_nilfs2_btree_node *node) +{ + return node->bn_level; +} + +static inline grub_uint64_t * +grub_nilfs2_btree_node_dkeys (struct grub_nilfs2_btree_node *node) +{ + return (grub_uint64_t *) ((char *) (node + 1) + + ((node->bn_flags & NILFS_BTREE_NODE_ROOT) ? + 0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE)); +} + +static inline grub_uint64_t +grub_nilfs2_btree_node_get_key (struct grub_nilfs2_btree_node *node, + int index) +{ + return grub_le_to_cpu64 (*(grub_nilfs2_btree_node_dkeys (node) + index)); +} + +static inline int +grub_nilfs2_btree_node_lookup (struct grub_nilfs2_btree_node *node, + grub_uint64_t key, int *indexp) +{ + grub_uint64_t nkey; + int index, low, high, s; + + low = 0; + high = grub_le_to_cpu16 (node->bn_nchildren) - 1; + index = 0; + s = 0; + while (low <= high) + { + index = (low + high) / 2; + nkey = grub_nilfs2_btree_node_get_key (node, index); + if (nkey == key) + { + *indexp = index; + return 1; + } + else if (nkey < key) + { + low = index + 1; + s = -1; + } + else + { + high = index - 1; + s = 1; + } + } + + if (node->bn_level > NILFS_BTREE_LEVEL_NODE_MIN) + { + if (s > 0 && index > 0) + index--; + } + else if (s < 0) + index++; + + *indexp = index; + return s == 0; +} + +static inline int +grub_nilfs2_btree_node_nchildren_max (struct grub_nilfs2_data *data, + struct grub_nilfs2_btree_node *node) +{ + int node_children_max = ((NILFS2_BLOCK_SIZE (data) - + sizeof (struct grub_nilfs2_btree_node) - + NILFS_BTREE_NODE_EXTRA_PAD_SIZE) / + (sizeof (grub_uint64_t) + sizeof (grub_uint64_t))); + + return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max; +} + +static inline grub_uint64_t * +grub_nilfs2_btree_node_dptrs (struct grub_nilfs2_data *data, + struct grub_nilfs2_btree_node *node) +{ + return (grub_uint64_t *) (grub_nilfs2_btree_node_dkeys (node) + + grub_nilfs2_btree_node_nchildren_max (data, + node)); +} + +static inline grub_uint64_t +grub_nilfs2_btree_node_get_ptr (struct grub_nilfs2_data *data, + struct grub_nilfs2_btree_node *node, + int index) +{ + return + grub_le_to_cpu64 (*(grub_nilfs2_btree_node_dptrs (data, node) + index)); +} + +static inline int +grub_nilfs2_btree_get_nonroot_node (struct grub_nilfs2_data *data, + grub_uint64_t ptr, void *block) +{ + grub_disk_t disk = data->disk; + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data)); + + return grub_disk_read (disk, ptr * nilfs2_block_count, 0, + NILFS2_BLOCK_SIZE (data), block); +} + +static grub_uint64_t +grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, + struct grub_nilfs2_inode *inode, + grub_uint64_t key, int need_translate) +{ + struct grub_nilfs2_btree_node *node; + unsigned char block[NILFS2_BLOCK_SIZE (data)]; + grub_uint64_t ptr; + int level, found, index; + + node = grub_nilfs2_btree_get_root (inode); + level = grub_nilfs2_btree_get_level (node); + + found = grub_nilfs2_btree_node_lookup (node, key, &index); + ptr = grub_nilfs2_btree_node_get_ptr (data, node, index); + if (need_translate) + ptr = grub_nilfs2_dat_translate (data, ptr); + + for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--) + { + grub_nilfs2_btree_get_nonroot_node (data, ptr, block); + if (grub_errno) + { + return -1; + } + node = (struct grub_nilfs2_btree_node *) block; + + if (node->bn_level != level) + { + grub_error (GRUB_ERR_BAD_FS, "btree level mismatch\n"); + return -1; + } + + if (!found) + found = grub_nilfs2_btree_node_lookup (node, key, &index); + else + index = 0; + + if (index < grub_nilfs2_btree_node_nchildren_max (data, node)) + { + ptr = grub_nilfs2_btree_node_get_ptr (data, node, index); + if (need_translate) + ptr = grub_nilfs2_dat_translate (data, ptr); + } + else + { + grub_error (GRUB_ERR_BAD_FS, "btree corruption\n"); + return -1; + } + } + + if (!found) + return -1; + + return ptr; +} + +static inline grub_uint64_t +grub_nilfs2_direct_lookup (struct grub_nilfs2_inode *inode, grub_uint64_t key) +{ + return grub_le_to_cpu64 (inode->i_bmap[1 + key]); +} + +static inline grub_uint64_t +grub_nilfs2_bmap_lookup (struct grub_nilfs2_data *data, + struct grub_nilfs2_inode *inode, + grub_uint64_t key, int need_translate) +{ + struct grub_nilfs2_btree_node *root = grub_nilfs2_btree_get_root (inode); + if (root->bn_flags & NILFS_BMAP_LARGE) + return grub_nilfs2_btree_lookup (data, inode, key, need_translate); + else + { + grub_uint64_t ptr; + ptr = grub_nilfs2_direct_lookup (inode, key); + if (need_translate) + ptr = grub_nilfs2_dat_translate (data, ptr); + return ptr; + } +} + +static grub_uint64_t +grub_nilfs2_dat_translate (struct grub_nilfs2_data *data, grub_uint64_t key) +{ + struct grub_nilfs2_dat_entry entry; + grub_disk_t disk = data->disk; + grub_uint64_t pptr; + grub_uint32_t blockno, offset; + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data)); + + blockno = grub_nilfs2_palloc_entry_offset (data, key, + sizeof (struct + grub_nilfs2_dat_entry)); + + grub_divmod64 (key * sizeof (struct grub_nilfs2_dat_entry), + NILFS2_BLOCK_SIZE (data), &offset); + + pptr = grub_nilfs2_bmap_lookup (data, &data->sroot.sr_dat, blockno, 0); + if (pptr == (grub_uint64_t) - 1) + { + grub_error (GRUB_ERR_BAD_FS, "btree lookup failure"); + return -1; + } + + grub_disk_read (disk, pptr * nilfs2_block_count, offset, + sizeof (struct grub_nilfs2_dat_entry), &entry); + + return grub_le_to_cpu64 (entry.de_blocknr); +} + + +static grub_disk_addr_t +grub_nilfs2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) +{ + struct grub_nilfs2_data *data = node->data; + struct grub_nilfs2_inode *inode = &node->inode; + grub_uint64_t pptr = -1; + + pptr = grub_nilfs2_bmap_lookup (data, inode, fileblock, 1); + if (pptr == (grub_uint64_t) - 1) + { + grub_error (GRUB_ERR_BAD_FS, "btree lookup failure"); + return -1; + } + + return pptr; +} + +/* Read LEN bytes from the file described by DATA starting with byte + POS. Return the amount of read bytes in READ. */ +static grub_ssize_t +grub_nilfs2_read_file (grub_fshelp_node_t node, + void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t + sector, + unsigned offset, + unsigned length), + int pos, grub_size_t len, char *buf) +{ + return grub_fshelp_read_file (node->data->disk, node, read_hook, + pos, len, buf, grub_nilfs2_read_block, + grub_le_to_cpu64 (node->inode.i_size), + LOG2_NILFS2_BLOCK_SIZE (node->data)); + +} + +static grub_err_t +grub_nilfs2_read_checkpoint (struct grub_nilfs2_data *data, + grub_uint64_t cpno, + struct grub_nilfs2_checkpoint *cpp) +{ + grub_uint64_t blockno; + grub_uint32_t offset; + grub_uint64_t pptr; + grub_disk_t disk = data->disk; + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data)); + + /* Assume sizeof(struct grub_nilfs2_cpfile_header) < + sizeof(struct grub_nilfs2_checkpoint). + */ + blockno = grub_divmod64 (cpno, NILFS2_BLOCK_SIZE (data) / + sizeof (struct grub_nilfs2_checkpoint), &offset); + + pptr = grub_nilfs2_bmap_lookup (data, &data->sroot.sr_cpfile, blockno, 1); + if (pptr == (grub_uint64_t) - 1) + { + return grub_error (GRUB_ERR_BAD_FS, "btree lookup failure"); + } + + return grub_disk_read (disk, pptr * nilfs2_block_count, + offset * sizeof (struct grub_nilfs2_checkpoint), + sizeof (struct grub_nilfs2_checkpoint), cpp); +} + +static inline grub_err_t +grub_nilfs2_read_last_checkpoint (struct grub_nilfs2_data *data, + struct grub_nilfs2_checkpoint *cpp) +{ + return grub_nilfs2_read_checkpoint (data, + grub_le_to_cpu64 (data-> + sblock.s_last_cno), + cpp); +} + +/* Read the inode INO for the file described by DATA into INODE. */ +static grub_err_t +grub_nilfs2_read_inode (struct grub_nilfs2_data *data, + grub_uint64_t ino, struct grub_nilfs2_inode *inodep) +{ + grub_uint64_t blockno; + unsigned int offset; + grub_uint64_t pptr; + grub_disk_t disk = data->disk; + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data)); + + blockno = grub_nilfs2_palloc_entry_offset (data, ino, + sizeof (struct + grub_nilfs2_inode)); + + grub_divmod64 (sizeof (struct grub_nilfs2_inode) * ino, + NILFS2_BLOCK_SIZE (data), &offset); + pptr = grub_nilfs2_bmap_lookup (data, &data->ifile, blockno, 1); + if (pptr == (grub_uint64_t) - 1) + { + return grub_error (GRUB_ERR_BAD_FS, "btree lookup failure"); + } + + return grub_disk_read (disk, pptr * nilfs2_block_count, offset, + sizeof (struct grub_nilfs2_inode), inodep); +} + +static int +grub_nilfs2_valid_sb (struct grub_nilfs2_super_block *sbp) +{ + if (grub_le_to_cpu16 (sbp->s_magic) != NILFS2_SUPER_MAGIC) + return 0; + + if (grub_le_to_cpu32 (sbp->s_rev_level) != NILFS_SUPORT_REV) + return 0; + + return 1; +} + +static struct grub_nilfs2_data * +grub_nilfs2_mount (grub_disk_t disk) +{ + struct grub_nilfs2_data *data; + struct grub_nilfs2_segment_summary ss; + struct grub_nilfs2_checkpoint last_checkpoint; + grub_uint64_t last_pseg; + grub_uint32_t nblocks; + unsigned int nilfs2_block_count; + + data = grub_malloc (sizeof (struct grub_nilfs2_data)); + if (!data) + return 0; + + /* Read the superblock. */ + grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_nilfs2_super_block), + &data->sblock); + if (grub_errno) + goto fail; + + /* Make sure this is an nilfs2 filesystem. */ + if (!grub_nilfs2_valid_sb (&data->sblock)) + { + grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem"); + goto fail; + } + + nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data)); + + /* Read the last segment summary. */ + last_pseg = grub_le_to_cpu64 (data->sblock.s_last_pseg); + grub_disk_read (disk, last_pseg * nilfs2_block_count, 0, + sizeof (struct grub_nilfs2_segment_summary), &ss); + + if (grub_errno) + goto fail; + + /* Read the super root block. */ + nblocks = grub_le_to_cpu32 (ss.ss_nblocks); + grub_disk_read (disk, (last_pseg + (nblocks - 1)) * nilfs2_block_count, 0, + sizeof (struct grub_nilfs2_super_root), &data->sroot); + + if (grub_errno) + goto fail; + + data->disk = disk; + + grub_nilfs2_read_last_checkpoint (data, &last_checkpoint); + + if (grub_errno) + goto fail; + + grub_memcpy (&data->ifile, &last_checkpoint.cp_ifile_inode, + sizeof (struct grub_nilfs2_inode)); + + data->diropen.data = data; + data->diropen.ino = 2; + data->diropen.inode_read = 1; + data->inode = &data->diropen.inode; + + grub_nilfs2_read_inode (data, 2, data->inode); + + return data; + +fail: + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem"); + + grub_free (data); + return 0; +} + +static char * +grub_nilfs2_read_symlink (grub_fshelp_node_t node) +{ + char *symlink; + struct grub_fshelp_node *diro = node; + + if (!diro->inode_read) + { + grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode); + if (grub_errno) + return 0; + } + + symlink = grub_malloc (grub_le_to_cpu64 (diro->inode.i_size) + 1); + if (!symlink) + return 0; + + grub_nilfs2_read_file (diro, 0, 0, + grub_le_to_cpu64 (diro->inode.i_size), symlink); + if (grub_errno) + { + grub_free (symlink); + return 0; + } + + symlink[grub_le_to_cpu64 (diro->inode.i_size)] = '\0'; + return symlink; +} + +static int +grub_nilfs2_iterate_dir (grub_fshelp_node_t dir, + int NESTED_FUNC_ATTR + (*hook) (const char *filename, + enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node)) +{ + unsigned int fpos = 0; + struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir; + + if (!diro->inode_read) + { + grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode); + if (grub_errno) + return 0; + } + + /* Iterate files. */ + while (fpos < grub_le_to_cpu64 (diro->inode.i_size)) + { + struct grub_nilfs2_dir_entry dirent; + + grub_nilfs2_read_file (diro, 0, fpos, + sizeof (struct grub_nilfs2_dir_entry), + (char *) &dirent); + if (grub_errno) + return 0; + + if (dirent.rec_len == 0) + return 0; + + if (dirent.name_len != 0) + { + char filename[dirent.name_len + 1]; + struct grub_fshelp_node *fdiro; + enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN; + + grub_nilfs2_read_file (diro, 0, + fpos + sizeof (struct grub_nilfs2_dir_entry), + dirent.name_len, filename); + if (grub_errno) + return 0; + + fdiro = grub_malloc (sizeof (struct grub_fshelp_node)); + if (!fdiro) + return 0; + + fdiro->data = diro->data; + fdiro->ino = grub_le_to_cpu64 (dirent.inode); + + filename[dirent.name_len] = '\0'; + + if (dirent.file_type != NILFS_FT_UNKNOWN) + { + fdiro->inode_read = 0; + + if (dirent.file_type == NILFS_FT_DIR) + type = GRUB_FSHELP_DIR; + else if (dirent.file_type == NILFS_FT_SYMLINK) + type = GRUB_FSHELP_SYMLINK; + else if (dirent.file_type == NILFS_FT_REG_FILE) + type = GRUB_FSHELP_REG; + } + else + { + /* The filetype can not be read from the dirent, read + the inode to get more information. */ + grub_nilfs2_read_inode (diro->data, + grub_le_to_cpu64 (dirent.inode), + &fdiro->inode); + if (grub_errno) + { + grub_free (fdiro); + return 0; + } + + fdiro->inode_read = 1; + + if ((grub_le_to_cpu16 (fdiro->inode.i_mode) + & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY) + type = GRUB_FSHELP_DIR; + else if ((grub_le_to_cpu16 (fdiro->inode.i_mode) + & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK) + type = GRUB_FSHELP_SYMLINK; + else if ((grub_le_to_cpu16 (fdiro->inode.i_mode) + & FILETYPE_INO_MASK) == FILETYPE_INO_REG) + type = GRUB_FSHELP_REG; + } + + if (hook (filename, type, fdiro)) + return 1; + } + + fpos += grub_le_to_cpu16 (dirent.rec_len); + } + + return 0; +} + +/* Open a file named NAME and initialize FILE. */ +static grub_err_t +grub_nilfs2_open (struct grub_file *file, const char *name) +{ + struct grub_nilfs2_data *data = NULL; + struct grub_fshelp_node *fdiro = 0; + + grub_dl_ref (my_mod); + + data = grub_nilfs2_mount (file->device->disk); + if (!data) + goto fail; + + grub_fshelp_find_file (name, &data->diropen, &fdiro, + grub_nilfs2_iterate_dir, grub_nilfs2_read_symlink, + GRUB_FSHELP_REG); + if (grub_errno) + goto fail; + + if (!fdiro->inode_read) + { + grub_nilfs2_read_inode (data, fdiro->ino, &fdiro->inode); + if (grub_errno) + goto fail; + } + + grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_nilfs2_inode)); + grub_free (fdiro); + + file->size = grub_le_to_cpu64 (data->inode->i_size); + file->data = data; + file->offset = 0; + + return 0; + +fail: + if (fdiro != &data->diropen) + grub_free (fdiro); + grub_free (data); + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static grub_err_t +grub_nilfs2_close (grub_file_t file) +{ + grub_free (file->data); + + grub_dl_unref (my_mod); + + return GRUB_ERR_NONE; +} + +/* Read LEN bytes data from FILE into BUF. */ +static grub_ssize_t +grub_nilfs2_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_nilfs2_data *data = (struct grub_nilfs2_data *) file->data; + + return grub_nilfs2_read_file (&data->diropen, file->read_hook, + file->offset, len, buf); +} + +static grub_err_t +grub_nilfs2_dir (grub_device_t device, const char *path, + int (*hook) (const char *filename, + const struct grub_dirhook_info * info)) +{ + struct grub_nilfs2_data *data = 0; + struct grub_fshelp_node *fdiro = 0; + + auto int NESTED_FUNC_ATTR iterate (const char *filename, + enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node); + + int NESTED_FUNC_ATTR iterate (const char *filename, + enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node) + { + struct grub_dirhook_info info; + grub_memset (&info, 0, sizeof (info)); + if (!node->inode_read) + { + grub_nilfs2_read_inode (data, node->ino, &node->inode); + if (!grub_errno) + node->inode_read = 1; + grub_errno = GRUB_ERR_NONE; + } + if (node->inode_read) + { + info.mtimeset = 1; + info.mtime = grub_le_to_cpu64 (node->inode.i_mtime); + } + + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + grub_free (node); + return hook (filename, &info); + } + + grub_dl_ref (my_mod); + + data = grub_nilfs2_mount (device->disk); + if (!data) + goto fail; + + grub_fshelp_find_file (path, &data->diropen, &fdiro, + grub_nilfs2_iterate_dir, grub_nilfs2_read_symlink, + GRUB_FSHELP_DIR); + if (grub_errno) + goto fail; + + grub_nilfs2_iterate_dir (fdiro, iterate); + +fail: + if (fdiro != &data->diropen) + grub_free (fdiro); + grub_free (data); + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static grub_err_t +grub_nilfs2_label (grub_device_t device, char **label) +{ + struct grub_nilfs2_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_nilfs2_mount (disk); + if (data) + *label = grub_strndup (data->sblock.s_volume_name, 14); + else + *label = NULL; + + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; +} + +static grub_err_t +grub_nilfs2_uuid (grub_device_t device, char **uuid) +{ + struct grub_nilfs2_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_nilfs2_mount (disk); + if (data) + { + *uuid = + grub_xasprintf + ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%0x-%02x%02x%02x%02x%02x%02x", + data->sblock.s_uuid[0], data->sblock.s_uuid[1], + data->sblock.s_uuid[2], data->sblock.s_uuid[3], + data->sblock.s_uuid[4], data->sblock.s_uuid[5], + data->sblock.s_uuid[6], data->sblock.s_uuid[7], + data->sblock.s_uuid[8], data->sblock.s_uuid[9], + data->sblock.s_uuid[10], data->sblock.s_uuid[11], + data->sblock.s_uuid[12], data->sblock.s_uuid[13], + data->sblock.s_uuid[14], data->sblock.s_uuid[15]); + } + else + *uuid = NULL; + + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; +} + +/* Get mtime. */ +static grub_err_t +grub_nilfs2_mtime (grub_device_t device, grub_int32_t * tm) +{ + struct grub_nilfs2_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_nilfs2_mount (disk); + if (!data) + *tm = 0; + else + *tm = (grub_int32_t) grub_le_to_cpu64 (data->sblock.s_mtime); + + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; +} + + + +static struct grub_fs grub_nilfs2_fs = { + .name = "nilfs2", + .dir = grub_nilfs2_dir, + .open = grub_nilfs2_open, + .read = grub_nilfs2_read, + .close = grub_nilfs2_close, + .label = grub_nilfs2_label, + .uuid = grub_nilfs2_uuid, + .mtime = grub_nilfs2_mtime, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, +#endif + .next = 0 +}; + +GRUB_MOD_INIT (nilfs2) +{ + grub_fs_register (&grub_nilfs2_fs); + my_mod = mod; +} + +GRUB_MOD_FINI (nilfs2) +{ + grub_fs_unregister (&grub_nilfs2_fs); +} diff --git a/fs/ntfs.c b/fs/ntfs.c index c780887c6..dd041e23a 100644 --- a/fs/ntfs.c +++ b/fs/ntfs.c @@ -1,7 +1,7 @@ /* ntfs.c - NTFS filesystem */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2007,2008,2009 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +24,7 @@ #include #include #include +#include static grub_dl_t my_mod; @@ -41,7 +42,7 @@ fixup (struct grub_ntfs_data *data, char *buf, int len, char *magic) ss = u16at (buf, 6) - 1; if (ss * (int) data->blocksize != len * GRUB_DISK_SECTOR_SIZE) - return grub_error (GRUB_ERR_BAD_FS, "Size not match", + return grub_error (GRUB_ERR_BAD_FS, "size not match", ss * (int) data->blocksize, len * GRUB_DISK_SECTOR_SIZE); pu = buf + u16at (buf, 4); @@ -52,7 +53,7 @@ fixup (struct grub_ntfs_data *data, char *buf, int len, char *magic) buf += data->blocksize; pu += 2; if (u16at (buf, 0) != us) - return grub_error (GRUB_ERR_BAD_FS, "Fixup signature not match"); + return grub_error (GRUB_ERR_BAD_FS, "fixup signature not match"); v16at (buf, 0) = v16at (pu, 0); ss--; } @@ -146,7 +147,7 @@ find_attr (struct grub_ntfs_attr *at, unsigned char attr) new_pos += u16at (new_pos, 4); } grub_error (GRUB_ERR_BAD_FS, - "Can\'t find 0x%X in attribute list", + "can\'t find 0x%X in attribute list", (unsigned char) *at->attr_cur); return NULL; } @@ -185,7 +186,7 @@ find_attr (struct grub_ntfs_attr *at, unsigned char attr) if (read_data (at, pa, at->edat_buf, 0, n, 0, 0)) { grub_error (GRUB_ERR_BAD_FS, - "Fail to read non-resident attribute list"); + "fail to read non-resident attribute list"); return NULL; } at->attr_nxt = at->edat_buf; @@ -314,7 +315,7 @@ retry: goto retry; } } - return grub_error (GRUB_ERR_BAD_FS, "Run list overflown"); + return grub_error (GRUB_ERR_BAD_FS, "run list overflown"); } run = read_run_data (run + 1, c1, &val, 0); /* length of current VCN */ ctx->curr_vcn = ctx->next_vcn; @@ -368,7 +369,7 @@ read_data (struct grub_ntfs_attr *at, char *pa, char *dest, if (pa[8] == 0) { if (ofs + len > u32at (pa, 0x10)) - return grub_error (GRUB_ERR_BAD_FS, "Read out of range"); + return grub_error (GRUB_ERR_BAD_FS, "read out of range"); grub_memcpy (dest, pa + u32at (pa, 0x14) + ofs, len); return 0; } @@ -382,7 +383,7 @@ read_data (struct grub_ntfs_attr *at, char *pa, char *dest, if (ctx->flags & RF_COMP) { if (!cached) - return grub_error (GRUB_ERR_BAD_FS, "Attribute can\'t be compressed"); + return grub_error (GRUB_ERR_BAD_FS, "attribute can\'t be compressed"); if (at->sbuf) { @@ -501,7 +502,7 @@ read_attr (struct grub_ntfs_attr *at, char *dest, grub_disk_addr_t ofs, else ret = (grub_errno) ? grub_errno : grub_error (GRUB_ERR_BAD_FS, - "Attribute not found"); + "attribute not found"); at->attr_cur = save_cur; return ret; } @@ -512,7 +513,7 @@ read_mft (struct grub_ntfs_data *data, char *buf, grub_uint32_t mftno) if (read_attr (&data->mmft.attr, buf, mftno * ((grub_disk_addr_t) data->mft_size << BLK_SHR), data->mft_size << BLK_SHR, 0, 0)) - return grub_error (GRUB_ERR_BAD_FS, "Read MFT 0x%X fails", mftno); + return grub_error (GRUB_ERR_BAD_FS, "read MFT 0x%X fails", mftno); return fixup (data, buf, data->mft_size, "FILE"); } @@ -540,7 +541,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint32_t mftno) pa = locate_attr (&mft->attr, mft, AT_DATA); if (pa == NULL) - return grub_error (GRUB_ERR_BAD_FS, "No $DATA in MFT 0x%X", mftno); + return grub_error (GRUB_ERR_BAD_FS, "no $DATA in MFT 0x%X", mftno); if (!pa[8]) mft->size = u32at (pa, 0x10); @@ -663,7 +664,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, { if ((cur_pos = find_attr (at, AT_INDEX_ROOT)) == NULL) { - grub_error (GRUB_ERR_BAD_FS, "No $INDEX_ROOT"); + grub_error (GRUB_ERR_BAD_FS, "no $INDEX_ROOT"); goto done; } @@ -716,7 +717,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, if (read_data (at, cur_pos, bmp, 0, bitmap_len, 0, 0)) { grub_error (GRUB_ERR_BAD_FS, - "Fails to read non-resident $BITMAP"); + "fails to read non-resident $BITMAP"); goto done; } bitmap_len = u32at (cur_pos, 0x30); @@ -1071,8 +1072,7 @@ grub_ntfs_uuid (grub_device_t device, char **uuid) data = grub_ntfs_mount (disk); if (data) { - *uuid = grub_malloc (16 + sizeof ('\0')); - grub_sprintf (*uuid, "%016llx", (unsigned long long) data->uuid); + *uuid = grub_xasprintf ("%016llx", (unsigned long long) data->uuid); } else *uuid = NULL; diff --git a/fs/ntfscomp.c b/fs/ntfscomp.c index 6bb33ffb1..c29979edc 100644 --- a/fs/ntfscomp.c +++ b/fs/ntfscomp.c @@ -28,7 +28,7 @@ static grub_err_t decomp_nextvcn (struct grub_ntfs_comp *cc) { if (cc->comp_head >= cc->comp_tail) - return grub_error (GRUB_ERR_BAD_FS, "Compression block overflown"); + return grub_error (GRUB_ERR_BAD_FS, "compression block overflown"); if (grub_disk_read (cc->disk, (cc->comp_table[cc->comp_head][1] - @@ -87,7 +87,7 @@ decomp_block (struct grub_ntfs_comp *cc, char *dest) { if (copied > COM_LEN) return grub_error (GRUB_ERR_BAD_FS, - "Compression block too large"); + "compression block too large"); if (!bits) { @@ -112,7 +112,7 @@ decomp_block (struct grub_ntfs_comp *cc, char *dest) if (!copied) { - grub_error (GRUB_ERR_BAD_FS, "Context window empty"); + grub_error (GRUB_ERR_BAD_FS, "nontext window empty"); return 0; } @@ -150,7 +150,7 @@ decomp_block (struct grub_ntfs_comp *cc, char *dest) { if (cnt != COM_LEN) return grub_error (GRUB_ERR_BAD_FS, - "Invalid compression block size"); + "invalid compression block size"); } } @@ -187,7 +187,7 @@ read_block (struct grub_ntfs_rlst *ctx, char *buf, int num) { if (ctx->comp.comp_head != ctx->comp.comp_tail) - return grub_error (GRUB_ERR_BAD_FS, "Invalid compression block"); + return grub_error (GRUB_ERR_BAD_FS, "invalid compression block"); ctx->comp.comp_head = ctx->comp.comp_tail = 0; ctx->comp.cbuf_vcn = ctx->target_vcn; ctx->comp.cbuf_ofs = (ctx->comp.spc << BLK_SHR); diff --git a/fs/reiserfs.c b/fs/reiserfs.c index fb4f1bc59..5acd339c5 100644 --- a/fs/reiserfs.c +++ b/fs/reiserfs.c @@ -62,7 +62,7 @@ static grub_dl_t my_mod; -#define assert(boolean) real_assert (boolean, __FILE__, __LINE__) +#define assert(boolean) real_assert (boolean, GRUB_FILE, __LINE__) static inline void real_assert (int boolean, const char *file, const int line) { @@ -691,7 +691,7 @@ grub_reiserfs_mount (grub_disk_t disk) if (grub_memcmp (data->superblock.magic_string, REISERFS_MAGIC_STRING, sizeof (REISERFS_MAGIC_STRING) - 1)) { - grub_error (GRUB_ERR_BAD_FS, "not a reiserfs filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a ReiserFS filesystem"); goto fail; } data->disk = disk; @@ -700,7 +700,7 @@ grub_reiserfs_mount (grub_disk_t disk) fail: /* Disk is too small to contain a ReiserFS. */ if (grub_errno == GRUB_ERR_OUT_OF_RANGE) - grub_error (GRUB_ERR_BAD_FS, "not a reiserfs filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a ReiserFS filesystem"); grub_free (data); return 0; @@ -998,7 +998,7 @@ grub_reiserfs_open (struct grub_file *file, const char *name) goto fail; if (root.block_number == 0) { - grub_error (GRUB_ERR_BAD_FS, "Unable to find root item"); + grub_error (GRUB_ERR_BAD_FS, "unable to find root item"); goto fail; /* Should never happen since checked at mount. */ } grub_fshelp_find_file (name, &root, &found, @@ -1014,7 +1014,7 @@ grub_reiserfs_open (struct grub_file *file, const char *name) goto fail; if (info.block_number == 0) { - grub_error (GRUB_ERR_BAD_FS, "Unable to find searched item"); + grub_error (GRUB_ERR_BAD_FS, "unable to find searched item"); goto fail; } entry_version = grub_le_to_cpu16 (info.header.version); @@ -1189,7 +1189,8 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) (unsigned long long) (current_position - initial_position), (unsigned long) len); return current_position - initial_position; -/* + +#if 0 switch (found.type) { case GRUB_REISERFS_DIRECT: @@ -1232,7 +1233,8 @@ grub_reiserfs_read (grub_file_t file, char *buf, grub_size_t len) goto fail; } - return read_length;*/ + return read_length; +#endif fail: grub_free (indirect_block_ptr); @@ -1289,7 +1291,7 @@ grub_reiserfs_dir (grub_device_t device, const char *path, goto fail; if (root.block_number == 0) { - grub_error(GRUB_ERR_BAD_FS, "Root not found"); + grub_error(GRUB_ERR_BAD_FS, "root not found"); goto fail; } grub_fshelp_find_file (path, &root, &found, grub_reiserfs_iterate_dir, @@ -1335,12 +1337,15 @@ grub_reiserfs_uuid (grub_device_t device, char **uuid) data = grub_reiserfs_mount (disk); if (data) { - *uuid = grub_malloc (sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")); - grub_sprintf (*uuid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", - grub_be_to_cpu16 (data->superblock.uuid[0]), grub_be_to_cpu16 (data->superblock.uuid[1]), - grub_be_to_cpu16 (data->superblock.uuid[2]), grub_be_to_cpu16 (data->superblock.uuid[3]), - grub_be_to_cpu16 (data->superblock.uuid[4]), grub_be_to_cpu16 (data->superblock.uuid[5]), - grub_be_to_cpu16 (data->superblock.uuid[6]), grub_be_to_cpu16 (data->superblock.uuid[7])); + *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + grub_be_to_cpu16 (data->superblock.uuid[0]), + grub_be_to_cpu16 (data->superblock.uuid[1]), + grub_be_to_cpu16 (data->superblock.uuid[2]), + grub_be_to_cpu16 (data->superblock.uuid[3]), + grub_be_to_cpu16 (data->superblock.uuid[4]), + grub_be_to_cpu16 (data->superblock.uuid[5]), + grub_be_to_cpu16 (data->superblock.uuid[6]), + grub_be_to_cpu16 (data->superblock.uuid[7])); } else *uuid = NULL; diff --git a/fs/sfs.c b/fs/sfs.c index ec59b73ca..68f8b3a6e 100644 --- a/fs/sfs.c +++ b/fs/sfs.c @@ -1,7 +1,7 @@ /* sfs.c - Amiga Smart FileSystem. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2005,2006,2007,2008,2009 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 @@ -279,7 +279,7 @@ grub_sfs_mount (grub_disk_t disk) /* Make sure this is a sfs filesystem. */ if (grub_strncmp ((char *) (data->rblock.header.magic), "SFS", 4)) { - grub_error (GRUB_ERR_BAD_FS, "not a sfs filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a SFS filesystem"); goto fail; } @@ -307,7 +307,7 @@ grub_sfs_mount (grub_disk_t disk) fail: if (grub_errno == GRUB_ERR_OUT_OF_RANGE) - grub_error (GRUB_ERR_BAD_FS, "not an sfs filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an SFS filesystem"); grub_free (data); grub_free (rootobjc_data); diff --git a/fs/udf.c b/fs/udf.c index 9dfe431f6..ad109bed9 100644 --- a/fs/udf.c +++ b/fs/udf.c @@ -1,7 +1,7 @@ /* udf.c - Universal Disk Format filesystem. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 @@ -25,6 +25,7 @@ #include #include #include +#include #define GRUB_UDF_MAX_PDS 2 #define GRUB_UDF_MAX_PMS 6 @@ -525,7 +526,7 @@ grub_udf_mount (grub_disk_t disk) if (grub_disk_read (disk, block << GRUB_UDF_LOG2_BLKSZ, 0, sizeof (struct grub_udf_vrs), &vrs)) { - grub_error (GRUB_ERR_BAD_FS, "not an udf filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); goto fail; } @@ -539,7 +540,7 @@ grub_udf_mount (grub_disk_t disk) (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_CDW02, 5)) && (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_TEA01, 5))) { - grub_error (GRUB_ERR_BAD_FS, "not an udf filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); goto fail; } } @@ -552,7 +553,7 @@ grub_udf_mount (grub_disk_t disk) if (grub_disk_read (disk, *sblklist << GRUB_UDF_LOG2_BLKSZ, 0, sizeof (struct grub_udf_avdp), &avdp)) { - grub_error (GRUB_ERR_BAD_FS, "not an udf filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); goto fail; } @@ -565,7 +566,7 @@ grub_udf_mount (grub_disk_t disk) sblklist++; if (*sblklist == 0) { - grub_error (GRUB_ERR_BAD_FS, "not an udf filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); goto fail; } } @@ -579,7 +580,7 @@ grub_udf_mount (grub_disk_t disk) if (grub_disk_read (disk, block << GRUB_UDF_LOG2_BLKSZ, 0, sizeof (struct grub_udf_tag), &tag)) { - grub_error (GRUB_ERR_BAD_FS, "not an udf filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); goto fail; } @@ -596,7 +597,7 @@ grub_udf_mount (grub_disk_t disk) sizeof (struct grub_udf_pd), &data->pds[data->npd])) { - grub_error (GRUB_ERR_BAD_FS, "not an udf filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); goto fail; } @@ -612,7 +613,7 @@ grub_udf_mount (grub_disk_t disk) sizeof (struct grub_udf_lvd), &data->lvd)) { - grub_error (GRUB_ERR_BAD_FS, "not an udf filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); goto fail; } @@ -675,7 +676,7 @@ grub_udf_mount (grub_disk_t disk) if (grub_disk_read (disk, block << GRUB_UDF_LOG2_BLKSZ, 0, sizeof (struct grub_udf_fileset), &root_fs)) { - grub_error (GRUB_ERR_BAD_FS, "not an udf filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); goto fail; } @@ -745,19 +746,41 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir, else { enum grub_fshelp_filetype type; - char filename[dirent.file_ident_length + 1]; + grub_uint8_t raw[dirent.file_ident_length]; + grub_uint16_t utf16[dirent.file_ident_length - 1]; + grub_uint8_t filename[dirent.file_ident_length * 2]; + grub_size_t utf16len = 0; type = ((dirent.characteristics & GRUB_UDF_FID_CHAR_DIRECTORY) ? (GRUB_FSHELP_DIR) : (GRUB_FSHELP_REG)); if ((grub_udf_read_file (dir, 0, offset, - dirent.file_ident_length, filename)) + dirent.file_ident_length, + (char *) raw)) != dirent.file_ident_length) return 0; - filename[dirent.file_ident_length] = 0; - if (hook (&filename[1], type, child)) - return 1; + if (raw[0] == 8) + { + unsigned i; + utf16len = dirent.file_ident_length - 1; + for (i = 0; i < utf16len; i++) + utf16[i] = raw[i + 1]; + } + if (raw[0] == 16) + { + unsigned i; + utf16len = (dirent.file_ident_length - 1) / 2; + for (i = 0; i < utf16len; i++) + utf16[i] = (raw[2 * i + 1] << 8) | raw[2*i + 2]; + } + if (raw[0] == 8 || raw[0] == 16) + { + *grub_utf16_to_utf8 (filename, utf16, utf16len) = '\0'; + + if (hook ((char *) filename, type, child)) + return 1; + } } /* Align to dword boundary. */ diff --git a/fs/ufs.c b/fs/ufs.c index c94ad9922..40cf068e6 100644 --- a/fs/ufs.c +++ b/fs/ufs.c @@ -1,7 +1,7 @@ /* ufs.c - Unix File System */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2004,2005,2007,2008,2009 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 @@ -415,7 +415,7 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino) grub_ufs_find_file (data, symlink); if (grub_errno) - grub_error (grub_errno, "Can not follow symlink `%s'.", symlink); + grub_error (grub_errno, "cannot follow symlink `%s'", symlink); return grub_errno; } @@ -732,12 +732,9 @@ grub_ufs_uuid (grub_device_t device, char **uuid) data = grub_ufs_mount (disk); if (data && (data->sblock.uuidhi != 0 || data->sblock.uuidlow != 0)) - { - *uuid = grub_malloc (16 + sizeof ('\0')); - grub_sprintf (*uuid, "%08x%08x", - (unsigned) grub_le_to_cpu32 (data->sblock.uuidhi), - (unsigned) grub_le_to_cpu32 (data->sblock.uuidlow)); - } + *uuid = grub_xasprintf ("%08x%08x", + (unsigned) grub_le_to_cpu32 (data->sblock.uuidhi), + (unsigned) grub_le_to_cpu32 (data->sblock.uuidlow)); else *uuid = NULL; diff --git a/fs/xfs.c b/fs/xfs.c index 1b18bef3b..9dffe31d1 100644 --- a/fs/xfs.c +++ b/fs/xfs.c @@ -1,7 +1,7 @@ /* xfs.c - XFS. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2005,2006,2007,2008,2009 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 @@ -222,7 +222,7 @@ grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino, return grub_errno; if (grub_strncmp ((char *) inode->magic, "IN", 2)) - return grub_error (GRUB_ERR_BAD_FS, "not a correct XFS inode.\n"); + return grub_error (GRUB_ERR_BAD_FS, "not a correct XFS inode"); return 0; } @@ -273,7 +273,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) if (grub_strncmp ((char *) leaf->magic, "BMAP", 4)) { grub_free (leaf); - grub_error (GRUB_ERR_BAD_FS, "not a correct XFS BMAP node.\n"); + grub_error (GRUB_ERR_BAD_FS, "not a correct XFS BMAP node"); return 0; } @@ -290,7 +290,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) else { grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "xfs does not support inode format %d yet", + "XFS does not support inode format %d yet", node->inode.format); return 0; } @@ -567,7 +567,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, default: grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "xfs does not support inode format %d yet", + "XFS does not support inode format %d yet", diro->inode.format); } return 0; @@ -590,7 +590,7 @@ grub_xfs_mount (grub_disk_t disk) if (grub_strncmp ((char *) (data->sblock.magic), "XFSB", 4)) { - grub_error (GRUB_ERR_BAD_FS, "not a xfs filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not a XFS filesystem"); goto fail; } @@ -617,7 +617,7 @@ grub_xfs_mount (grub_disk_t disk) fail: if (grub_errno == GRUB_ERR_OUT_OF_RANGE) - grub_error (GRUB_ERR_BAD_FS, "not an xfs filesystem"); + grub_error (GRUB_ERR_BAD_FS, "not an XFS filesystem"); grub_free (data); @@ -777,12 +777,15 @@ grub_xfs_uuid (grub_device_t device, char **uuid) data = grub_xfs_mount (disk); if (data) { - *uuid = grub_malloc (sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")); - grub_sprintf (*uuid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", - grub_be_to_cpu16 (data->sblock.uuid[0]), grub_be_to_cpu16 (data->sblock.uuid[1]), - grub_be_to_cpu16 (data->sblock.uuid[2]), grub_be_to_cpu16 (data->sblock.uuid[3]), - grub_be_to_cpu16 (data->sblock.uuid[4]), grub_be_to_cpu16 (data->sblock.uuid[5]), - grub_be_to_cpu16 (data->sblock.uuid[6]), grub_be_to_cpu16 (data->sblock.uuid[7])); + *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + grub_be_to_cpu16 (data->sblock.uuid[0]), + grub_be_to_cpu16 (data->sblock.uuid[1]), + grub_be_to_cpu16 (data->sblock.uuid[2]), + grub_be_to_cpu16 (data->sblock.uuid[3]), + grub_be_to_cpu16 (data->sblock.uuid[4]), + grub_be_to_cpu16 (data->sblock.uuid[5]), + grub_be_to_cpu16 (data->sblock.uuid[6]), + grub_be_to_cpu16 (data->sblock.uuid[7])); } else *uuid = NULL; diff --git a/gencmdlist.sh b/gencmdlist.sh index 7f2549099..ed5965f07 100644 --- a/gencmdlist.sh +++ b/gencmdlist.sh @@ -1,6 +1,6 @@ #! /bin/sh # -# Copyright (C) 2005 Free Software Foundation, Inc. +# Copyright (C) 2005,2009 Free Software Foundation, Inc. # # This gensymlist.sh is free software; the author # gives unlimited permission to copy and/or distribute it, diff --git a/gendistlist.sh b/gendistlist.sh old mode 100644 new mode 100755 index 36685a092..102c0c11c --- a/gendistlist.sh +++ b/gendistlist.sh @@ -19,6 +19,7 @@ EXTRA_DISTFILES="AUTHORS COPYING ChangeLog DISTLIST INSTALL NEWS README \ gendistlist.sh genfslist.sh genhandlerlist.sh geninit.sh \ geninitheader.sh genkernsyms.sh.in genmk.rb genmoddep.awk \ genmodsrc.sh genpartmaplist.sh genparttoollist.sh \ + genvideolist.sh \ gensymlist.sh.in install-sh mkinstalldirs stamp-h.in" DISTDIRS="boot bus commands conf disk docs efiemu font fs hello hook include io \ @@ -35,7 +36,7 @@ dir=`dirname $0` cd $dir for dir in $DISTDIRS; do - for d in `find $dir -type d -not -name .svn -not -name .bzr | sort`; do + for d in `find $dir -type d ! -name .svn ! -name .bzr | sort`; do find $d -maxdepth 1 -name '*.[chSy]' -o -name '*.mk' -o -name '*.rmk' \ -o -name '*.rb' -o -name '*.in' -o -name '*.tex' -o -name '*.texi' \ -o -name '*.info' -o -name 'grub.cfg' -o -name 'README' \ diff --git a/genemuinit.sh b/genemuinit.sh new file mode 100644 index 000000000..45c15ecb9 --- /dev/null +++ b/genemuinit.sh @@ -0,0 +1,72 @@ +#! /bin/sh +# +# Copyright (C) 2002,2005,2007 Free Software Foundation, Inc. +# +# This gensymlist.sh is free software; the author +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +nm="$1" +shift + +cat <. + */ + +#include "grub_emu_init.h" + +EOF + +cat < /dev/null; then + echo "grub_${line}_init ();" | sed 's,\.mod,,g;' + fi +done + +cat < /dev/null; then + echo "grub_${line}_fini ();" | sed 's,\.mod,,g;' + fi +done + +cat <. + */ + +EOF + +cat < /dev/null; then + echo "void grub_${line}_init (void);" | sed 's,\.mod,,g;' + fi + if ${nm} --defined-only -P -p ${line} | grep grub_mod_fini > /dev/null; then + echo "void grub_${line}_fini (void);" | sed 's,\.mod,,g;' + fi +done diff --git a/genhandlerlist.sh b/genhandlerlist.sh index 6446a98ff..e4cb0d9de 100644 --- a/genhandlerlist.sh +++ b/genhandlerlist.sh @@ -16,8 +16,4 @@ module=$1 grep -v "^#" | sed -n \ - -e "/grub_parser_register *( *\"/{s/.*( *\"\([^\"]*\)\".*/parser.\1: $module/;p;}" \ - -e "/grub_reader_register *( *\"/{s/.*( *\"\([^\"]*\)\".*/reader.\1: $module/;p;}" \ - -e "/grub_term_register_input *( *\"/{s/.*( *\"\([^\"]*\)\".*/terminal_input.\1: $module/;p;}" \ - -e "/grub_term_register_output *( *\"/{s/.*( *\"\([^\"]*\)\".*/terminal_output.\1: $module/;p;}" \ - -e "/grub_menu_viewer_register *( *\"/{s/.*( *\"\([^\"]*\)\".*/menu_viewer.\1: $module/;p;}" + -e "/grub_parser_register *( *\"/{s/.*( *\"\([^\"]*\)\".*/parser.\1: $module/;p;}" diff --git a/genkernsyms.sh.in b/genkernsyms.sh.in index b2f3f7af9..c5c63b2d5 100644 --- a/genkernsyms.sh.in +++ b/genkernsyms.sh.in @@ -14,7 +14,7 @@ ### The configure script will replace these variables. : ${srcdir=@srcdir@} -: ${CC=@CC@} +: ${CC=@TARGET_CC@} u= grep "^#define HAVE_ASM_USCORE" config.h >/dev/null 2>&1 && u="_" diff --git a/genmk.rb b/genmk.rb index 50bf88fe1..e62dbd4f6 100644 --- a/genmk.rb +++ b/genmk.rb @@ -1,6 +1,6 @@ #! /usr/bin/ruby -w # -# Copyright (C) 2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc. +# Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. # # This genmk.rb is free software; the author # gives unlimited permission to copy and/or distribute it, @@ -68,7 +68,7 @@ MOSTLYCLEAN_IMAGE_TARGETS += mostlyclean-image-#{@name}.#{@rule_count} ifneq ($(TARGET_APPLE_CC),1) #{@name}: #{exe} - $(OBJCOPY) -O $(#{prefix}_FORMAT) --strip-unneeded -R .note -R .comment -R .note.gnu.build-id $< $@ + $(OBJCOPY) -O $(#{prefix}_FORMAT) --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .reginfo -R .rel.dyn $< $@ else ifneq (#{exe},kernel.exec) #{@name}: #{exe} ./grub-macho2img @@ -91,7 +91,7 @@ endif dir = File.dirname(src) "#{obj}: #{src} $(#{src}_DEPENDENCIES) - $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -MD -c -o $@ $< + $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -DGRUB_FILE=\\\"#{src}\\\" -MD -c -o $@ $< -include #{dep} " @@ -132,45 +132,50 @@ clean-module-#{@name}.#{@rule_count}: CLEAN_MODULE_TARGETS += clean-module-#{@name}.#{@rule_count} -ifneq ($(#{prefix}_EXPORTS),no) clean-module-#{@name}-symbol.#{@rule_count}: rm -f #{defsym} CLEAN_MODULE_TARGETS += clean-module-#{@name}-symbol.#{@rule_count} DEFSYMFILES += #{defsym} -endif mostlyclean-module-#{@name}.#{@rule_count}: rm -f #{deps_str} MOSTLYCLEAN_MODULE_TARGETS += mostlyclean-module-#{@name}.#{@rule_count} UNDSYMFILES += #{undsym} +ifeq ($(TARGET_NO_MODULES), yes) +#{@name}: #{pre_obj} $(TARGET_OBJ2ELF) + -rm -f $@ + $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ #{pre_obj} + if test ! -z \"$(TARGET_OBJ2ELF)\"; then ./$(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi + if test x$(TARGET_NO_STRIP) != xyes ; then $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@; fi +else ifneq ($(TARGET_APPLE_CC),1) #{@name}: #{pre_obj} #{mod_obj} $(TARGET_OBJ2ELF) -rm -f $@ $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ #{pre_obj} #{mod_obj} if test ! -z \"$(TARGET_OBJ2ELF)\"; then ./$(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi - $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@ + if test x$(TARGET_NO_STRIP) != xyes ; then $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@; fi else #{@name}: #{pre_obj} #{mod_obj} $(TARGET_OBJ2ELF) -rm -f $@ -rm -f $@.bin $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@.bin #{pre_obj} #{mod_obj} - $(OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -wd1106 -nu -nd $@.bin $@ + $(OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -wd1106 -ew2030 -ew2050 -nu -nd $@.bin $@ -rm -f $@.bin endif +endif #{pre_obj}: $(#{prefix}_DEPENDENCIES) #{objs_str} -rm -f $@ $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ #{objs_str} #{mod_obj}: #{mod_src} - $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(#{prefix}_CFLAGS) -c -o $@ $< + $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(#{prefix}_CFLAGS) -DGRUB_FILE=\\\"#{mod_src}\\\" -c -o $@ $< #{mod_src}: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh sh $(srcdir)/genmodsrc.sh '#{mod_name}' $< > $@ || (rm -f $@; exit 1) -ifneq ($(#{prefix}_EXPORTS),no) ifneq ($(TARGET_APPLE_CC),1) #{defsym}: #{pre_obj} $(NM) -g --defined-only -P -p $< | sed 's/^\\([^ ]*\\).*/\\1 #{mod_name}/' > $@ @@ -178,7 +183,6 @@ else #{defsym}: #{pre_obj} $(NM) -g -P -p $< | grep -E '^[a-zA-Z0-9_]* [TDS]' | sed 's/^\\([^ ]*\\).*/\\1 #{mod_name}/' > $@ endif -endif #{undsym}: #{pre_obj} echo '#{mod_name}' > $@ @@ -192,18 +196,20 @@ endif fs = 'fs-' + obj.suffix('lst') partmap = 'partmap-' + obj.suffix('lst') handler = 'handler-' + obj.suffix('lst') + terminal = 'terminal-' + obj.suffix('lst') parttool = 'parttool-' + obj.suffix('lst') + video = 'video-' + obj.suffix('lst') dep = deps[i] flag = if /\.c$/ =~ src then 'CFLAGS' else 'ASFLAGS' end extra_flags = if /\.S$/ =~ src then '-DASM_FILE=1' else '' end dir = File.dirname(src) "#{obj}: #{src} $(#{src}_DEPENDENCIES) - $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -MD -c -o $@ $< + $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -DGRUB_FILE=\\\"#{src}\\\" -MD -c -o $@ $< -include #{dep} clean-module-#{extra_target}.#{@rule_count}: - rm -f #{command} #{fs} #{partmap} #{handler} #{parttool} + rm -f #{command} #{fs} #{partmap} #{handler} #{parttool} #{video} #{terminal} CLEAN_MODULE_TARGETS += clean-module-#{extra_target}.#{@rule_count} @@ -212,6 +218,8 @@ FSFILES += #{fs} PARTTOOLFILES += #{parttool} PARTMAPFILES += #{partmap} HANDLERFILES += #{handler} +TERMINALFILES += #{terminal} +VIDEOFILES += #{video} #{command}: #{src} $(#{src}_DEPENDENCIES) gencmdlist.sh set -e; \ @@ -238,6 +246,16 @@ HANDLERFILES += #{handler} $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \ | sh $(srcdir)/genhandlerlist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1) +#{terminal}: #{src} $(#{src}_DEPENDENCIES) genterminallist.sh + set -e; \ + $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \ + | sh $(srcdir)/genterminallist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1) + +#{video}: #{src} $(#{src}_DEPENDENCIES) genvideolist.sh + set -e; \ + $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \ + | sh $(srcdir)/genvideolist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1) + " end.join('') end @@ -289,7 +307,7 @@ MOSTLYCLEAN_UTILITY_TARGETS += mostlyclean-utility-#{@name}.#{@rule_count} dir = File.dirname(src) "#{obj}: #{src} $(#{src}_DEPENDENCIES) - $(CC) -I#{dir} -I$(srcdir)/#{dir} $(CPPFLAGS) $(CFLAGS) -DGRUB_UTIL=1 $(#{prefix}_CFLAGS) -MD -c -o $@ $< + $(CC) -I#{dir} -I$(srcdir)/#{dir} $(CPPFLAGS) $(CFLAGS) -DGRUB_UTIL=1 $(#{prefix}_CFLAGS) -DGRUB_FILE=\\\"#{src}\\\" -MD -c -o $@ $< -include #{dep} " @@ -304,21 +322,32 @@ class Program end attr_reader :dir, :name + def print_tail() + prefix = @name.to_var + print "CLEANFILES += #{@name} $(#{prefix}_OBJECTS) +ifeq ($(#{prefix}_RELOCATABLE),yes) +#{@name}: $(#{prefix}_DEPENDENCIES) $(#{prefix}_OBJECTS) + $(TARGET_CC) -Wl,-r,-d -o $@ $(#{prefix}_OBJECTS) $(TARGET_LDFLAGS) $(#{prefix}_LDFLAGS) + if test x$(TARGET_NO_STRIP) != xyes ; then $(STRIP) --strip-unneeded -K start -R .note -R .comment $@; fi +else +#{@name}: $(#{prefix}_DEPENDENCIES) $(#{prefix}_OBJECTS) + $(TARGET_CC) -o $@ $(#{prefix}_OBJECTS) $(TARGET_LDFLAGS) $(#{prefix}_LDFLAGS) + if test x$(TARGET_NO_STRIP) != xyes ; then $(STRIP) -R .rel.dyn -R .reginfo -R .note -R .comment $@; fi +endif + +" + end + def rule(sources) prefix = @name.to_var objs = sources.collect do |src| raise "unknown source file `#{src}'" if /\.[cS]$/ !~ src prefix + '-' + src.to_obj end - objs_str = objs.join(' '); deps = objs.collect {|obj| obj.suffix('d')} deps_str = deps.join(' '); - "CLEANFILES += #{@name} #{objs_str} -MOSTLYCLEANFILES += #{deps_str} - -#{@name}: $(#{prefix}_DEPENDENCIES) #{objs_str} - $(TARGET_CC) -o $@ #{objs_str} $(TARGET_LDFLAGS) $(#{prefix}_LDFLAGS) + "MOSTLYCLEANFILES += #{deps_str} " + objs.collect_with_index do |obj, i| src = sources[i] @@ -329,9 +358,11 @@ MOSTLYCLEANFILES += #{deps_str} dir = File.dirname(src) "#{obj}: #{src} $(#{src}_DEPENDENCIES) - $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -MD -c -o $@ $< + $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -DGRUB_FILE=\\\"#{src}\\\" -MD -c -o $@ $< + -include #{dep} +#{prefix}_OBJECTS += #{obj} " end.join('') end @@ -356,7 +387,7 @@ class Script "CLEANFILES += #{@name} #{@name}: #{src} $(#{src}_DEPENDENCIES) config.status - ./config.status --file=#{name}:#{src} + ./config.status --file=-:#{src} | sed -e 's,@pkglib_DATA@,$(pkglib_DATA),g' > $@ chmod +x $@ " @@ -440,4 +471,5 @@ while l = gets end utils.each {|util| util.print_tail()} +programs.each {|program| program.print_tail()} diff --git a/genmoddep.awk b/genmoddep.awk index f7f085e99..48419a091 100644 --- a/genmoddep.awk +++ b/genmoddep.awk @@ -29,16 +29,15 @@ FNR == 1 { if ($1 in symtab) { modtab[module] = modtab[module] " " symtab[$1]; } - else { + else if ($1 != "__gnu_local_gp") { printf "%s in %s is not defined\n", $1, module >"/dev/stderr"; error++; - exit; } } # Output the result. END { - if (error == 1) + if (error >= 1) exit 1; for (mod in modtab) { diff --git a/gensymlist.sh.in b/gensymlist.sh.in index 27fc5e61a..3c3ddfa6c 100644 --- a/gensymlist.sh.in +++ b/gensymlist.sh.in @@ -14,7 +14,7 @@ ### The configure script will replace these variables. : ${srcdir=@srcdir@} -: ${CC=@CC@} +: ${CC=@TARGET_CC@} cat <. */ +#include EOF for i in $*; do diff --git a/genterminallist.sh b/genterminallist.sh new file mode 100644 index 000000000..60f5b9105 --- /dev/null +++ b/genterminallist.sh @@ -0,0 +1,20 @@ +#! /bin/sh +# +# Copyright (C) 2009,2010 Free Software Foundation, Inc. +# +# This script is free software; the author +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Read source code from stdin and detect command names. + +module=$1 + +grep -v "^#" | sed -n \ + -e "/grub_term_register_input *( *\"/{s/.*( *\"\([^\"]*\)\".*/i\1: $module/;p;}" \ + -e "/grub_term_register_output *( *\"/{s/.*( *\"\([^\"]*\)\".*/o\1: $module/;p;}" \ diff --git a/gentrigtables.c b/gentrigtables.c new file mode 100644 index 000000000..772cd6224 --- /dev/null +++ b/gentrigtables.c @@ -0,0 +1,48 @@ +/* Generate trigonometric function tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008, 2009 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 . + */ + +#define _GNU_SOURCE 1 + +#include +#include +#include + +int +main () +{ + int i; + + printf ("#include \n"); + +#define TAB(op) \ + printf ("grub_int16_t grub_trig_" #op "tab[] =\n{"); \ + for (i = 0; i < GRUB_TRIG_ANGLE_MAX; i++) \ + { \ + double x = i * 2 * M_PI / GRUB_TRIG_ANGLE_MAX; \ + if (i % 10 == 0) \ + printf ("\n "); \ + printf ("%d,", (int) (round (op (x) * GRUB_TRIG_FRACTION_SCALE))); \ + } \ + printf ("\n};\n") + + TAB(sin); + TAB(cos); + + return 0; +} diff --git a/genvideolist.sh b/genvideolist.sh new file mode 100644 index 000000000..b208fa25c --- /dev/null +++ b/genvideolist.sh @@ -0,0 +1,26 @@ +#! /bin/sh +# +# Copyright (C) 2005,2008,2009 Free Software Foundation, Inc. +# +# This script is free software; the author +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Read source code from stdin and detect partmap names. + +module=$1 + +# Ignore video.mod. +if test $module = video; then + exit +fi + +# For now, this emits only a module name, if the module registers a partition map. +if grep -v "^#" | grep '^ *grub_video_register' >/dev/null 2>&1; then + echo $module +fi diff --git a/gettext/gettext.c b/gettext/gettext.c index 65db73a78..0aa8decbd 100644 --- a/gettext/gettext.c +++ b/gettext/gettext.c @@ -29,8 +29,8 @@ #include #include -/* - .mo file information from: +/* + .mo file information from: http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html . */ @@ -148,14 +148,24 @@ grub_gettext_translate (const char *orig) struct grub_gettext_msg *cur; + /* Make sure we can use grub_gettext_translate for error messages. Push + active error message to error stack and reset error message. */ + grub_error_push (); + cur = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_gettext_msg_list), orig); if (cur) - return cur->translated; + { + grub_error_pop (); + return cur->translated; + } if (fd_mo == 0) - return orig; + { + grub_error_pop (); + return orig; + } min = 0; max = grub_gettext_max; @@ -205,6 +215,7 @@ grub_gettext_translate (const char *orig) grub_errno = GRUB_ERR_NONE; } + grub_error_pop (); return ret; } @@ -243,7 +254,7 @@ grub_mofile_open (const char *filename) if (version != 0) { grub_error (GRUB_ERR_BAD_FILE_TYPE, - "mo: invalid mo version in file: %s\n", filename); + "mo: invalid mo version in file: %s", filename); fd_mo = 0; return 0; } @@ -268,21 +279,19 @@ grub_gettext_init_ext (const char *lang) /* mo_file e.g.: /boot/grub/locale/ca.mo */ - mo_file = - grub_malloc (grub_strlen (locale_dir) + grub_strlen ("/") + - grub_strlen (lang) + grub_strlen (".mo") + 1); - - /* Warning: if changing some paths in the below line, change the grub_malloc - contents below. */ - - grub_sprintf (mo_file, "%s/%s.mo", locale_dir, lang); + mo_file = grub_xasprintf ("%s/%s.mo", locale_dir, lang); + if (!mo_file) + return; fd_mo = grub_mofile_open (mo_file); /* Will try adding .gz as well. */ if (fd_mo == NULL) { - grub_sprintf (mo_file, "%s.gz", mo_file); + grub_free (mo_file); + mo_file = grub_xasprintf ("%s.gz", mo_file); + if (!mo_file) + return; fd_mo = grub_mofile_open (mo_file); } @@ -298,7 +307,7 @@ grub_gettext_init_ext (const char *lang) } static void -grub_gettext_delete_list () +grub_gettext_delete_list (void) { struct grub_gettext_msg *item; @@ -308,7 +317,7 @@ grub_gettext_delete_list () char *original = (char *) ((struct grub_gettext_msg *) item)->name; grub_free (original); - // Don't delete the translated message because could be in use. + /* Don't delete the translated message because could be in use. */ } } @@ -347,8 +356,8 @@ GRUB_MOD_INIT (gettext) grub_gettext_init_ext (lang); grub_register_command_p1 ("gettext", grub_cmd_translate, - "gettext STRING", - "Translates the string with the current settings."); + N_("STRING"), + N_("Translates the string with the current settings.")); /* Reload .mo file information if lang changes. */ grub_register_variable_hook ("lang", NULL, grub_gettext_env_write_lang); diff --git a/gfxmenu/gfxmenu.c b/gfxmenu/gfxmenu.c new file mode 100644 index 000000000..a2e765156 --- /dev/null +++ b/gfxmenu/gfxmenu.c @@ -0,0 +1,144 @@ +/* gfxmenu.c - Graphical menu interface controller. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +grub_gfxmenu_view_t cached_view; + +static void +grub_gfxmenu_viewer_fini (void *data __attribute__ ((unused))) +{ +} + +/* FIXME: Previously 't' changed to text menu is it necessary? */ +static grub_err_t +grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) +{ + grub_gfxmenu_view_t view = NULL; + const char *theme_path; + struct grub_menu_viewer *instance; + grub_err_t err; + struct grub_video_mode_info mode_info; + + theme_path = grub_env_get ("theme"); + if (! theme_path) + { + grub_error_push (); + grub_gfxterm_fullscreen (); + grub_error_pop (); + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified"); + } + + instance = grub_zalloc (sizeof (*instance)); + if (!instance) + { + grub_error_push (); + grub_gfxterm_fullscreen (); + grub_error_pop (); + return grub_errno; + } + + err = grub_video_get_info (&mode_info); + if (err) + { + grub_error_push (); + grub_gfxterm_fullscreen (); + grub_error_pop (); + return err; + } + + if (!cached_view || grub_strcmp (cached_view->theme_path, theme_path) != 0 + || cached_view->screen.width != mode_info.width + || cached_view->screen.height != mode_info.height) + { + grub_free (cached_view); + /* Create the view. */ + cached_view = grub_gfxmenu_view_new (theme_path, mode_info.width, + mode_info.height); + } + + if (! cached_view) + { + grub_free (instance); + grub_error_push (); + grub_gfxterm_fullscreen (); + grub_error_pop (); + return grub_errno; + } + + view = cached_view; + + view->double_repaint = (mode_info.mode_type + & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) + && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); + view->selected = entry; + view->menu = menu; + view->nested = nested; + view->first_timeout = -1; + + grub_gfxmenu_view_draw (view); + + instance->data = view; + instance->set_chosen_entry = grub_gfxmenu_set_chosen_entry; + instance->fini = grub_gfxmenu_viewer_fini; + instance->print_timeout = grub_gfxmenu_print_timeout; + instance->clear_timeout = grub_gfxmenu_clear_timeout; + + grub_menu_register_viewer (instance); + + return GRUB_ERR_NONE; +} + +GRUB_MOD_INIT (gfxmenu) +{ + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_gfxmenu_try_hook && grub_strcmp (term->name, "gfxterm") == 0) + { + grub_gfxterm_fullscreen (); + break; + } + + grub_gfxmenu_try_hook = grub_gfxmenu_try; +} + +GRUB_MOD_FINI (gfxmenu) +{ + grub_gfxmenu_view_destroy (cached_view); + grub_gfxmenu_try_hook = NULL; +} diff --git a/gfxmenu/gui_box.c b/gfxmenu/gui_box.c new file mode 100644 index 000000000..38b15f96d --- /dev/null +++ b/gfxmenu/gui_box.c @@ -0,0 +1,412 @@ +/* gui_box.c - GUI container that stack components. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include +#include + +struct component_node +{ + grub_gui_component_t component; + struct component_node *next; + struct component_node *prev; +}; + +typedef struct grub_gui_box *grub_gui_box_t; + +typedef void (*layout_func_t) (grub_gui_box_t self, int modify_layout, + unsigned *minimal_width, + unsigned *minimal_height); + +struct grub_gui_box +{ + struct grub_gui_container container; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + + /* Doubly linked list of components with dummy head & tail nodes. */ + struct component_node chead; + struct component_node ctail; + + /* The layout function: differs for vertical and horizontal boxes. */ + layout_func_t layout_func; +}; + +static void +box_destroy (void *vself) +{ + grub_gui_box_t self = vself; + struct component_node *cur; + struct component_node *next; + for (cur = self->chead.next; cur != &self->ctail; cur = next) + { + /* Copy the 'next' pointer, since we need it for the next iteration, + and we're going to free the memory it is stored in. */ + next = cur->next; + /* Destroy the child component. */ + cur->component->ops->destroy (cur->component); + /* Free the linked list node. */ + grub_free (cur); + } + grub_free (self); +} + +static const char * +box_get_id (void *vself) +{ + grub_gui_box_t self = vself; + return self->id; +} + +static int +box_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return (grub_strcmp (type, "component") == 0 + || grub_strcmp (type, "container") == 0); +} + +static void +layout_horizontally (grub_gui_box_t self, int modify_layout, + unsigned *min_width, unsigned *min_height) +{ + /* Start at the left (chead) and set the x coordinates as we go right. */ + /* All components have their width set to the box's width. */ + + struct component_node *cur; + unsigned w = 0, mwfrac = 0, h = 0, x = 0; + grub_fixed_signed_t wfrac = 0; + int bogus_frac = 0; + + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { + grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; + + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); + + if (c->h > (signed) h) + h = c->h; + if (mh > h) + h = mh; + wfrac += c->wfrac; + w += c->w; + if (mw - c->w > 0) + mwfrac += mw - c->w; + } + if (wfrac > GRUB_FIXED_1 || (w > 0 && wfrac == GRUB_FIXED_1)) + bogus_frac = 1; + + if (min_width) + { + if (wfrac < GRUB_FIXED_1) + *min_width = grub_fixed_sfs_divide (w, GRUB_FIXED_1 - wfrac); + else + *min_width = w; + if (*min_width < w + mwfrac) + *min_width = w + mwfrac; + } + if (min_height) + *min_height = h; + + if (!modify_layout) + return; + + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { + grub_video_rect_t r; + grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; + + r.x = x; + r.y = 0; + r.height = h; + + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); + + r.width = c->w; + if (!bogus_frac) + r.width += grub_fixed_sfs_multiply (self->bounds.width, c->wfrac); + + if (r.width < mw) + r.width = mw; + + c->ops->set_bounds (c, &r); + + x += r.width; + } +} + +static void +layout_vertically (grub_gui_box_t self, int modify_layout, + unsigned *min_width, unsigned *min_height) +{ + /* Start at the top (chead) and set the y coordinates as we go rdown. */ + /* All components have their height set to the box's height. */ + + struct component_node *cur; + unsigned h = 0, mhfrac = 0, w = 0, y = 0; + grub_fixed_signed_t hfrac = 0; + int bogus_frac = 0; + + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { + grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; + + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); + + if (c->w > (signed) w) + w = c->w; + if (mw > w) + w = mw; + hfrac += c->hfrac; + h += c->h; + if (mh - c->h > 0) + mhfrac += mh - c->h; + } + if (hfrac > GRUB_FIXED_1 || (h > 0 && hfrac == GRUB_FIXED_1)) + bogus_frac = 1; + + if (min_height) + { + if (hfrac < GRUB_FIXED_1) + *min_height = grub_fixed_sfs_divide (h, GRUB_FIXED_1 - hfrac); + else + *min_height = h; + if (*min_height < h + mhfrac) + *min_height = h + mhfrac; + } + if (min_width) + *min_width = w; + + if (!modify_layout) + return; + + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { + grub_video_rect_t r; + grub_gui_component_t c = cur->component; + unsigned mw = 0, mh = 0; + + r.x = 0; + r.y = y; + r.width = w; + + if (c->ops->get_minimal_size) + c->ops->get_minimal_size (c, &mw, &mh); + + r.height = c->h; + if (!bogus_frac) + r.height += grub_fixed_sfs_multiply (self->bounds.height, c->hfrac); + + if (r.height < mh) + r.height = mh; + + c->ops->set_bounds (c, &r); + + y += r.height; + } +} + +static void +box_paint (void *vself, const grub_video_rect_t *region) +{ + grub_gui_box_t self = vself; + struct component_node *cur; + grub_video_rect_t vpsave; + + grub_gui_set_viewport (&self->bounds, &vpsave); + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { + grub_gui_component_t comp = cur->component; + comp->ops->paint (comp, region); + } + grub_gui_restore_viewport (&vpsave); +} + +static void +box_set_parent (void *vself, grub_gui_container_t parent) +{ + grub_gui_box_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +box_get_parent (void *vself) +{ + grub_gui_box_t self = vself; + return self->parent; +} + +static void +box_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + grub_gui_box_t self = vself; + self->bounds = *bounds; + self->layout_func (self, 1, 0, 0); /* Relayout the children. */ +} + +static void +box_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + grub_gui_box_t self = vself; + *bounds = self->bounds; +} + +/* The box's preferred size is based on the preferred sizes + of its children. */ +static void +box_get_minimal_size (void *vself, unsigned *width, unsigned *height) +{ + grub_gui_box_t self = vself; + self->layout_func (self, 0, width, height); /* Just calculate the size. */ +} + +static grub_err_t +box_set_property (void *vself, const char *name, const char *value) +{ + grub_gui_box_t self = vself; + if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + { + self->id = grub_strdup (value); + if (! self->id) + return grub_errno; + } + else + self->id = 0; + } + + return grub_errno; +} + +static void +box_add (void *vself, grub_gui_component_t comp) +{ + grub_gui_box_t self = vself; + struct component_node *node; + node = grub_malloc (sizeof (*node)); + if (! node) + return; /* Note: probably should handle the error. */ + node->component = comp; + /* Insert the node before the tail. */ + node->prev = self->ctail.prev; + node->prev->next = node; + node->next = &self->ctail; + node->next->prev = node; + + comp->ops->set_parent (comp, (grub_gui_container_t) self); + self->layout_func (self, 1, 0, 0); /* Relayout the children. */ +} + +static void +box_remove (void *vself, grub_gui_component_t comp) +{ + grub_gui_box_t self = vself; + struct component_node *cur; + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + { + if (cur->component == comp) + { + /* Unlink 'cur' from the list. */ + cur->prev->next = cur->next; + cur->next->prev = cur->prev; + /* Free the node's memory (but don't destroy the component). */ + grub_free (cur); + /* Must not loop again, since 'cur' would be dereferenced! */ + return; + } + } +} + +static void +box_iterate_children (void *vself, + grub_gui_component_callback cb, void *userdata) +{ + grub_gui_box_t self = vself; + struct component_node *cur; + for (cur = self->chead.next; cur != &self->ctail; cur = cur->next) + cb (cur->component, userdata); +} + +static struct grub_gui_component_ops box_comp_ops = + { + .destroy = box_destroy, + .get_id = box_get_id, + .is_instance = box_is_instance, + .paint = box_paint, + .set_parent = box_set_parent, + .get_parent = box_get_parent, + .set_bounds = box_set_bounds, + .get_bounds = box_get_bounds, + .get_minimal_size = box_get_minimal_size, + .set_property = box_set_property + }; + +static struct grub_gui_container_ops box_ops = +{ + .add = box_add, + .remove = box_remove, + .iterate_children = box_iterate_children +}; + +/* Box constructor. Specify the appropriate layout function to create + a horizontal or vertical stacking box. */ +static grub_gui_box_t +box_new (layout_func_t layout_func) +{ + grub_gui_box_t box; + box = grub_zalloc (sizeof (*box)); + if (! box) + return 0; + box->container.ops = &box_ops; + box->container.component.ops = &box_comp_ops; + box->chead.next = &box->ctail; + box->ctail.prev = &box->chead; + box->layout_func = layout_func; + return box; +} + +/* Create a new container that stacks its child components horizontally, + from left to right. Each child get a width corresponding to its + preferred width. The height of each child is set the maximum of the + preferred heights of all children. */ +grub_gui_container_t +grub_gui_hbox_new (void) +{ + return (grub_gui_container_t) box_new (layout_horizontally); +} + +/* Create a new container that stacks its child components verticallyj, + from top to bottom. Each child get a height corresponding to its + preferred height. The width of each child is set the maximum of the + preferred widths of all children. */ +grub_gui_container_t +grub_gui_vbox_new (void) +{ + return (grub_gui_container_t) box_new (layout_vertically); +} diff --git a/gfxmenu/gui_canvas.c b/gfxmenu/gui_canvas.c new file mode 100644 index 000000000..b3919c2d3 --- /dev/null +++ b/gfxmenu/gui_canvas.c @@ -0,0 +1,267 @@ +/* gui_canvas.c - GUI container allowing manually placed components. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include +#include + +/* TODO Add layering so that components can be properly overlaid. */ + +struct component_node +{ + grub_gui_component_t component; + struct component_node *next; +}; + +struct grub_gui_canvas +{ + struct grub_gui_container container; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + /* Component list (dummy head node). */ + struct component_node components; +}; + +typedef struct grub_gui_canvas *grub_gui_canvas_t; + +static void +canvas_destroy (void *vself) +{ + grub_gui_canvas_t self = vself; + struct component_node *cur; + struct component_node *next; + for (cur = self->components.next; cur; cur = next) + { + /* Copy the 'next' pointer, since we need it for the next iteration, + and we're going to free the memory it is stored in. */ + next = cur->next; + /* Destroy the child component. */ + cur->component->ops->destroy (cur->component); + /* Free the linked list node. */ + grub_free (cur); + } + grub_free (self); +} + +static const char * +canvas_get_id (void *vself) +{ + grub_gui_canvas_t self = vself; + return self->id; +} + +static int +canvas_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return (grub_strcmp (type, "component") == 0 + || grub_strcmp (type, "container") == 0); +} + +static void +canvas_paint (void *vself, const grub_video_rect_t *region) +{ + grub_gui_canvas_t self = vself; + struct component_node *cur; + grub_video_rect_t vpsave; + + grub_gui_set_viewport (&self->bounds, &vpsave); + for (cur = self->components.next; cur; cur = cur->next) + { + grub_video_rect_t r; + grub_gui_component_t comp; + signed x, y, w, h; + + comp = cur->component; + + w = grub_fixed_sfs_multiply (self->bounds.width, comp->wfrac) + comp->w; + h = grub_fixed_sfs_multiply (self->bounds.height, comp->hfrac) + comp->h; + x = grub_fixed_sfs_multiply (self->bounds.width, comp->xfrac) + comp->x; + y = grub_fixed_sfs_multiply (self->bounds.height, comp->yfrac) + comp->y; + + if (comp->ops->get_minimal_size) + { + unsigned mw; + unsigned mh; + comp->ops->get_minimal_size (comp, &mw, &mh); + if (w < (signed) mw) + w = mw; + if (h < (signed) mh) + h = mh; + } + + /* Sanity checks. */ + if (w <= 0) + w = 32; + if (h <= 0) + h = 32; + + if (x >= (signed) self->bounds.width) + x = self->bounds.width - 32; + if (y >= (signed) self->bounds.height) + y = self->bounds.height - 32; + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + if (x + w >= (signed) self->bounds.width) + w = self->bounds.width - x; + if (y + h >= (signed) self->bounds.height) + h = self->bounds.height - y; + + r.x = x; + r.y = y; + r.width = w; + r.height = h; + comp->ops->set_bounds (comp, &r); + + /* Paint the child. */ + if (grub_video_have_common_points (region, &r)) + comp->ops->paint (comp, region); + } + grub_gui_restore_viewport (&vpsave); +} + +static void +canvas_set_parent (void *vself, grub_gui_container_t parent) +{ + grub_gui_canvas_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +canvas_get_parent (void *vself) +{ + grub_gui_canvas_t self = vself; + return self->parent; +} + +static void +canvas_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + grub_gui_canvas_t self = vself; + self->bounds = *bounds; +} + +static void +canvas_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + grub_gui_canvas_t self = vself; + *bounds = self->bounds; +} + +static grub_err_t +canvas_set_property (void *vself, const char *name, const char *value) +{ + grub_gui_canvas_t self = vself; + if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + { + self->id = grub_strdup (value); + if (! self->id) + return grub_errno; + } + else + self->id = 0; + } + return grub_errno; +} + +static void +canvas_add (void *vself, grub_gui_component_t comp) +{ + grub_gui_canvas_t self = vself; + struct component_node *node; + node = grub_malloc (sizeof (*node)); + if (! node) + return; /* Note: probably should handle the error. */ + node->component = comp; + node->next = self->components.next; + self->components.next = node; + comp->ops->set_parent (comp, (grub_gui_container_t) self); +} + +static void +canvas_remove (void *vself, grub_gui_component_t comp) +{ + grub_gui_canvas_t self = vself; + struct component_node *cur; + struct component_node *prev; + prev = &self->components; + for (cur = self->components.next; cur; prev = cur, cur = cur->next) + { + if (cur->component == comp) + { + /* Unlink 'cur' from the list. */ + prev->next = cur->next; + /* Free the node's memory (but don't destroy the component). */ + grub_free (cur); + /* Must not loop again, since 'cur' would be dereferenced! */ + return; + } + } +} + +static void +canvas_iterate_children (void *vself, + grub_gui_component_callback cb, void *userdata) +{ + grub_gui_canvas_t self = vself; + struct component_node *cur; + for (cur = self->components.next; cur; cur = cur->next) + cb (cur->component, userdata); +} + +static struct grub_gui_component_ops canvas_comp_ops = +{ + .destroy = canvas_destroy, + .get_id = canvas_get_id, + .is_instance = canvas_is_instance, + .paint = canvas_paint, + .set_parent = canvas_set_parent, + .get_parent = canvas_get_parent, + .set_bounds = canvas_set_bounds, + .get_bounds = canvas_get_bounds, + .set_property = canvas_set_property +}; + +static struct grub_gui_container_ops canvas_ops = +{ + .add = canvas_add, + .remove = canvas_remove, + .iterate_children = canvas_iterate_children +}; + +grub_gui_container_t +grub_gui_canvas_new (void) +{ + grub_gui_canvas_t canvas; + canvas = grub_zalloc (sizeof (*canvas)); + if (! canvas) + return 0; + canvas->container.ops = &canvas_ops; + canvas->container.component.ops = &canvas_comp_ops; + return (grub_gui_container_t) canvas; +} diff --git a/gfxmenu/gui_circular_progress.c b/gfxmenu/gui_circular_progress.c new file mode 100644 index 000000000..098ae1c92 --- /dev/null +++ b/gfxmenu/gui_circular_progress.c @@ -0,0 +1,308 @@ +/* gui_circular_process.c - GUI circular progress indicator component. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct grub_gui_circular_progress +{ + struct grub_gui_progress progress; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int visible; + int start; + int end; + int value; + int num_ticks; + int start_angle; + int ticks_disappear; + char *theme_dir; + int need_to_load_pixmaps; + char *center_file; + char *tick_file; + struct grub_video_bitmap *center_bitmap; + struct grub_video_bitmap *tick_bitmap; +}; + +typedef struct grub_gui_circular_progress *circular_progress_t; + +static void +circprog_destroy (void *vself) +{ + circular_progress_t self = vself; + grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self); + grub_free (self); +} + +static const char * +circprog_get_id (void *vself) +{ + circular_progress_t self = vself; + return self->id; +} + +static int +circprog_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return grub_strcmp (type, "component") == 0; +} + +static struct grub_video_bitmap * +load_bitmap (const char *dir, const char *file) +{ + struct grub_video_bitmap *bitmap; + char *abspath; + + /* Check arguments. */ + if (! dir || ! file) + return 0; + + /* Resolve to an absolute path. */ + abspath = grub_resolve_relative_path (dir, file); + if (! abspath) + return 0; + + /* Load the image. */ + grub_errno = GRUB_ERR_NONE; + grub_video_bitmap_load (&bitmap, abspath); + grub_errno = GRUB_ERR_NONE; + + grub_free (abspath); + return bitmap; +} + +static int +check_pixmaps (circular_progress_t self) +{ + if (self->need_to_load_pixmaps) + { + if (self->center_bitmap) + grub_video_bitmap_destroy (self->center_bitmap); + self->center_bitmap = load_bitmap (self->theme_dir, self->center_file); + self->tick_bitmap = load_bitmap (self->theme_dir, self->tick_file); + self->need_to_load_pixmaps = 0; + } + + return (self->center_bitmap != 0 && self->tick_bitmap != 0); +} + +static void +circprog_paint (void *vself, const grub_video_rect_t *region) +{ + circular_progress_t self = vself; + + if (! self->visible) + return; + + if (!grub_video_have_common_points (region, &self->bounds)) + return; + + if (! check_pixmaps (self)) + return; + + grub_video_rect_t vpsave; + grub_gui_set_viewport (&self->bounds, &vpsave); + + int width = self->bounds.width; + int height = self->bounds.height; + int center_width = grub_video_bitmap_get_width (self->center_bitmap); + int center_height = grub_video_bitmap_get_height (self->center_bitmap); + int tick_width = grub_video_bitmap_get_width (self->tick_bitmap); + int tick_height = grub_video_bitmap_get_height (self->tick_bitmap); + grub_video_blit_bitmap (self->center_bitmap, GRUB_VIDEO_BLIT_BLEND, + (width - center_width) / 2, + (height - center_height) / 2, 0, 0, + center_width, center_height); + + int radius = width / 2 - tick_width / 2 - 1; + int nticks; + int tick_begin; + int tick_end; + if (self->end == self->start) + nticks = 0; + else + nticks = (self->num_ticks + * (self->value - self->start) + / (self->end - self->start)); + /* Do ticks appear or disappear as the value approached the end? */ + if (self->ticks_disappear) + { + tick_begin = nticks; + tick_end = self->num_ticks - 1; + } + else + { + tick_begin = 0; + tick_end = nticks - 1; + } + + int i; + for (i = tick_begin; i < tick_end; i++) + { + int x; + int y; + int angle; + + /* Calculate the location of the tick. */ + angle = self->start_angle + i * GRUB_TRIG_ANGLE_MAX / self->num_ticks; + x = width / 2 + (grub_cos (angle) * radius / GRUB_TRIG_FRACTION_SCALE); + y = height / 2 + (grub_sin (angle) * radius / GRUB_TRIG_FRACTION_SCALE); + + /* Adjust (x,y) so the tick is centered. */ + x -= tick_width / 2; + y -= tick_height / 2; + + /* Draw the tick. */ + grub_video_blit_bitmap (self->tick_bitmap, GRUB_VIDEO_BLIT_BLEND, + x, y, 0, 0, tick_width, tick_height); + } + + grub_gui_restore_viewport (&vpsave); +} + +static void +circprog_set_parent (void *vself, grub_gui_container_t parent) +{ + circular_progress_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +circprog_get_parent (void *vself) +{ + circular_progress_t self = vself; + return self->parent; +} + +static void +circprog_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + circular_progress_t self = vself; + self->bounds = *bounds; +} + +static void +circprog_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + circular_progress_t self = vself; + *bounds = self->bounds; +} + +static void +circprog_set_state (void *vself, int visible, int start, + int current, int end) +{ + circular_progress_t self = vself; + self->visible = visible; + self->start = start; + self->value = current; + self->end = end; +} + +static grub_err_t +circprog_set_property (void *vself, const char *name, const char *value) +{ + circular_progress_t self = vself; + if (grub_strcmp (name, "num_ticks") == 0) + { + self->num_ticks = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "start_angle") == 0) + { + self->start_angle = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "ticks_disappear") == 0) + { + self->ticks_disappear = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "center_bitmap") == 0) + { + self->need_to_load_pixmaps = 1; + grub_free (self->center_file); + self->center_file = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "tick_bitmap") == 0) + { + self->need_to_load_pixmaps = 1; + grub_free (self->tick_file); + self->tick_file = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "theme_dir") == 0) + { + self->need_to_load_pixmaps = 1; + grub_free (self->theme_dir); + self->theme_dir = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "id") == 0) + { + grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self); + grub_free (self->id); + if (value) + self->id = grub_strdup (value); + else + self->id = 0; + if (self->id && grub_strcmp (self->id, GRUB_GFXMENU_TIMEOUT_COMPONENT_ID) + == 0) + grub_gfxmenu_timeout_register ((grub_gui_component_t) self, + circprog_set_state); + } + return grub_errno; +} + +static struct grub_gui_component_ops circprog_ops = +{ + .destroy = circprog_destroy, + .get_id = circprog_get_id, + .is_instance = circprog_is_instance, + .paint = circprog_paint, + .set_parent = circprog_set_parent, + .get_parent = circprog_get_parent, + .set_bounds = circprog_set_bounds, + .get_bounds = circprog_get_bounds, + .set_property = circprog_set_property +}; + +static struct grub_gui_progress_ops circprog_prog_ops = + { + .set_state = circprog_set_state + }; + +grub_gui_component_t +grub_gui_circular_progress_new (void) +{ + circular_progress_t self; + self = grub_zalloc (sizeof (*self)); + if (! self) + return 0; + self->progress.ops = &circprog_prog_ops; + self->progress.component.ops = &circprog_ops; + self->visible = 1; + self->num_ticks = 64; + self->start_angle = -64; + + return (grub_gui_component_t) self; +} diff --git a/gfxmenu/gui_image.c b/gfxmenu/gui_image.c new file mode 100644 index 000000000..3988f4ba8 --- /dev/null +++ b/gfxmenu/gui_image.c @@ -0,0 +1,269 @@ +/* gui_image.c - GUI component to display an image. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include + +struct grub_gui_image +{ + struct grub_gui_component component; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + char *theme_dir; + struct grub_video_bitmap *raw_bitmap; + struct grub_video_bitmap *bitmap; +}; + +typedef struct grub_gui_image *grub_gui_image_t; + +static void +image_destroy (void *vself) +{ + grub_gui_image_t self = vself; + + /* Free the scaled bitmap, unless it's a reference to the raw bitmap. */ + if (self->bitmap && (self->bitmap != self->raw_bitmap)) + grub_video_bitmap_destroy (self->bitmap); + if (self->raw_bitmap) + grub_video_bitmap_destroy (self->raw_bitmap); + + grub_free (self); +} + +static const char * +image_get_id (void *vself) +{ + grub_gui_image_t self = vself; + return self->id; +} + +static int +image_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return grub_strcmp (type, "component") == 0; +} + +static void +image_paint (void *vself, const grub_video_rect_t *region) +{ + grub_gui_image_t self = vself; + grub_video_rect_t vpsave; + + if (! self->bitmap) + return; + if (!grub_video_have_common_points (region, &self->bounds)) + return; + + grub_gui_set_viewport (&self->bounds, &vpsave); + grub_video_blit_bitmap (self->bitmap, GRUB_VIDEO_BLIT_BLEND, + 0, 0, 0, 0, + grub_video_bitmap_get_width (self->bitmap), + grub_video_bitmap_get_height (self->bitmap)); + grub_gui_restore_viewport (&vpsave); +} + +static void +image_set_parent (void *vself, grub_gui_container_t parent) +{ + grub_gui_image_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +image_get_parent (void *vself) +{ + grub_gui_image_t self = vself; + return self->parent; +} + +static grub_err_t +rescale_image (grub_gui_image_t self) +{ + if (! self->raw_bitmap) + { + if (self->bitmap) + { + grub_video_bitmap_destroy (self->bitmap); + self->bitmap = 0; + } + return grub_errno; + } + + unsigned width = self->bounds.width; + unsigned height = self->bounds.height; + + if (self->bitmap + && (grub_video_bitmap_get_width (self->bitmap) == width) + && (grub_video_bitmap_get_height (self->bitmap) == height)) + { + /* Nothing to do; already the right size. */ + return grub_errno; + } + + /* Free any old scaled bitmap, + *unless* it's a reference to the raw bitmap. */ + if (self->bitmap && (self->bitmap != self->raw_bitmap)) + grub_video_bitmap_destroy (self->bitmap); + + self->bitmap = 0; + + /* Create a scaled bitmap, unless the requested size is the same + as the raw size -- in that case a reference is made. */ + if (grub_video_bitmap_get_width (self->raw_bitmap) == width + && grub_video_bitmap_get_height (self->raw_bitmap) == height) + { + self->bitmap = self->raw_bitmap; + return grub_errno; + } + + /* Don't scale to an invalid size. */ + if (width == 0 || height == 0) + return grub_errno; + + /* Create the scaled bitmap. */ + grub_video_bitmap_create_scaled (&self->bitmap, + width, + height, + self->raw_bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + if (grub_errno != GRUB_ERR_NONE) + { + grub_error_push (); + grub_error (grub_errno, "failed to scale bitmap for image component"); + } + return grub_errno; +} + +static void +image_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + grub_gui_image_t self = vself; + self->bounds = *bounds; + rescale_image (self); +} + +static void +image_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + grub_gui_image_t self = vself; + *bounds = self->bounds; +} + +/* FIXME: inform rendering system it's not forced minimum. */ +static void +image_get_minimal_size (void *vself, unsigned *width, unsigned *height) +{ + grub_gui_image_t self = vself; + + if (self->raw_bitmap) + { + *width = grub_video_bitmap_get_width (self->raw_bitmap); + *height = grub_video_bitmap_get_height (self->raw_bitmap); + } + else + { + *width = 0; + *height = 0; + } +} + +static grub_err_t +load_image (grub_gui_image_t self, const char *path) +{ + struct grub_video_bitmap *bitmap; + if (grub_video_bitmap_load (&bitmap, path) != GRUB_ERR_NONE) + return grub_errno; + + if (self->bitmap && (self->bitmap != self->raw_bitmap)) + grub_video_bitmap_destroy (self->bitmap); + if (self->raw_bitmap) + grub_video_bitmap_destroy (self->raw_bitmap); + + self->raw_bitmap = bitmap; + return rescale_image (self); +} + +static grub_err_t +image_set_property (void *vself, const char *name, const char *value) +{ + grub_gui_image_t self = vself; + if (grub_strcmp (name, "theme_dir") == 0) + { + grub_free (self->theme_dir); + self->theme_dir = grub_strdup (value); + } + else if (grub_strcmp (name, "file") == 0) + { + char *absvalue; + grub_err_t err; + + /* Resolve to an absolute path. */ + if (! self->theme_dir) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unspecified theme_dir"); + absvalue = grub_resolve_relative_path (self->theme_dir, value); + if (! absvalue) + return grub_errno; + + err = load_image (self, absvalue); + grub_free (absvalue); + + return err; + } + else if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + self->id = grub_strdup (value); + else + self->id = 0; + } + return grub_errno; +} + +static struct grub_gui_component_ops image_ops = +{ + .destroy = image_destroy, + .get_id = image_get_id, + .is_instance = image_is_instance, + .paint = image_paint, + .set_parent = image_set_parent, + .get_parent = image_get_parent, + .set_bounds = image_set_bounds, + .get_bounds = image_get_bounds, + .get_minimal_size = image_get_minimal_size, + .set_property = image_set_property +}; + +grub_gui_component_t +grub_gui_image_new (void) +{ + grub_gui_image_t image; + image = grub_zalloc (sizeof (*image)); + if (! image) + return 0; + image->component.ops = &image_ops; + return (grub_gui_component_t) image; +} + diff --git a/gfxmenu/gui_label.c b/gfxmenu/gui_label.c new file mode 100644 index 000000000..15a352f84 --- /dev/null +++ b/gfxmenu/gui_label.c @@ -0,0 +1,254 @@ +/* gui_label.c - GUI component to display a line of text. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include +#include +#include + +static const char *align_options[] = +{ + "left", + "center", + "right", + 0 +}; + +enum align_mode { + align_left, + align_center, + align_right +}; + +struct grub_gui_label +{ + struct grub_gui_component comp; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int visible; + char *text; + char *template; + grub_font_t font; + grub_gui_color_t color; + int value; + enum align_mode align; +}; + +typedef struct grub_gui_label *grub_gui_label_t; + +static void +label_destroy (void *vself) +{ + grub_gui_label_t self = vself; + grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self); + grub_free (self->text); + grub_free (self->template); + grub_free (self); +} + +static const char * +label_get_id (void *vself) +{ + grub_gui_label_t self = vself; + return self->id; +} + +static int +label_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return grub_strcmp (type, "component") == 0; +} + +static void +label_paint (void *vself, const grub_video_rect_t *region) +{ + grub_gui_label_t self = vself; + + if (! self->visible) + return; + + if (!grub_video_have_common_points (region, &self->bounds)) + return; + + /* Calculate the starting x coordinate. */ + int left_x; + if (self->align == align_left) + left_x = 0; + else if (self->align == align_center) + left_x = ((self->bounds.width + - grub_font_get_string_width (self->font, self->text)) + ) / 2; + else if (self->align == align_right) + left_x = (self->bounds.width + - grub_font_get_string_width (self->font, self->text)); + else + return; /* Invalid alignment. */ + + grub_video_rect_t vpsave; + grub_gui_set_viewport (&self->bounds, &vpsave); + grub_font_draw_string (self->text, + self->font, + grub_gui_map_color (self->color), + left_x, + grub_font_get_ascent (self->font)); + grub_gui_restore_viewport (&vpsave); +} + +static void +label_set_parent (void *vself, grub_gui_container_t parent) +{ + grub_gui_label_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +label_get_parent (void *vself) +{ + grub_gui_label_t self = vself; + return self->parent; +} + +static void +label_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + grub_gui_label_t self = vself; + self->bounds = *bounds; +} + +static void +label_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + grub_gui_label_t self = vself; + *bounds = self->bounds; +} + +static void +label_get_minimal_size (void *vself, unsigned *width, unsigned *height) +{ + grub_gui_label_t self = vself; + *width = grub_font_get_string_width (self->font, self->text); + *height = (grub_font_get_ascent (self->font) + + grub_font_get_descent (self->font)); +} + +static void +label_set_state (void *vself, int visible, int start __attribute__ ((unused)), + int current, int end __attribute__ ((unused))) +{ + grub_gui_label_t self = vself; + self->value = -current; + self->visible = visible; + grub_free (self->text); + self->text = grub_xasprintf (self->template ? : "%d", self->value); +} + +static grub_err_t +label_set_property (void *vself, const char *name, const char *value) +{ + grub_gui_label_t self = vself; + if (grub_strcmp (name, "text") == 0) + { + grub_free (self->text); + grub_free (self->template); + if (! value) + { + self->template = NULL; + self->text = grub_strdup (""); + } + else + { + self->template = grub_strdup (value); + self->text = grub_xasprintf (value, self->value); + } + } + else if (grub_strcmp (name, "font") == 0) + { + self->font = grub_font_get (value); + } + else if (grub_strcmp (name, "color") == 0) + { + grub_gui_parse_color (value, &self->color); + } + else if (grub_strcmp (name, "align") == 0) + { + int i; + for (i = 0; align_options[i]; i++) + { + if (grub_strcmp (align_options[i], value) == 0) + { + self->align = i; /* Set the alignment mode. */ + break; + } + } + } + else if (grub_strcmp (name, "visible") == 0) + { + self->visible = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "id") == 0) + { + grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self); + grub_free (self->id); + if (value) + self->id = grub_strdup (value); + else + self->id = 0; + if (self->id && grub_strcmp (self->id, GRUB_GFXMENU_TIMEOUT_COMPONENT_ID) + == 0) + grub_gfxmenu_timeout_register ((grub_gui_component_t) self, + label_set_state); + } + return GRUB_ERR_NONE; +} + +static struct grub_gui_component_ops label_ops = +{ + .destroy = label_destroy, + .get_id = label_get_id, + .is_instance = label_is_instance, + .paint = label_paint, + .set_parent = label_set_parent, + .get_parent = label_get_parent, + .set_bounds = label_set_bounds, + .get_bounds = label_get_bounds, + .get_minimal_size = label_get_minimal_size, + .set_property = label_set_property +}; + +grub_gui_component_t +grub_gui_label_new (void) +{ + grub_gui_label_t label; + label = grub_zalloc (sizeof (*label)); + if (! label) + return 0; + label->comp.ops = &label_ops; + label->visible = 1; + label->text = grub_strdup (""); + label->font = grub_font_get ("Unknown Regular 16"); + label->color.red = 0; + label->color.green = 0; + label->color.blue = 0; + label->color.alpha = 255; + label->align = align_left; + return (grub_gui_component_t) label; +} diff --git a/gfxmenu/gui_list.c b/gfxmenu/gui_list.c new file mode 100644 index 000000000..0d771413f --- /dev/null +++ b/gfxmenu/gui_list.c @@ -0,0 +1,612 @@ +/* gui_list.c - GUI component to display a selectable list of items. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include + +struct grub_gui_list_impl +{ + struct grub_gui_list list; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int visible; + + int icon_width; + int icon_height; + int item_height; + int item_padding; + int item_icon_space; + int item_spacing; + grub_font_t item_font; + grub_font_t selected_item_font; + grub_gui_color_t item_color; + int selected_item_color_set; + grub_gui_color_t selected_item_color; + + int draw_scrollbar; + int need_to_recreate_scrollbar; + char *scrollbar_frame_pattern; + char *scrollbar_thumb_pattern; + grub_gfxmenu_box_t scrollbar_frame; + grub_gfxmenu_box_t scrollbar_thumb; + int scrollbar_width; + + int first_shown_index; + + int need_to_recreate_boxes; + char *theme_dir; + char *menu_box_pattern; + char *selected_item_box_pattern; + grub_gfxmenu_box_t menu_box; + grub_gfxmenu_box_t selected_item_box; + + grub_gfxmenu_icon_manager_t icon_manager; + + grub_gfxmenu_view_t view; +}; + +typedef struct grub_gui_list_impl *list_impl_t; + +static void +list_destroy (void *vself) +{ + list_impl_t self = vself; + + grub_free (self->theme_dir); + grub_free (self->menu_box_pattern); + grub_free (self->selected_item_box_pattern); + if (self->menu_box) + self->menu_box->destroy (self->menu_box); + if (self->selected_item_box) + self->selected_item_box->destroy (self->selected_item_box); + if (self->icon_manager) + grub_gfxmenu_icon_manager_destroy (self->icon_manager); + + grub_free (self); +} + +static int +get_num_shown_items (list_impl_t self) +{ + int boxpad = self->item_padding; + int item_vspace = self->item_spacing; + int item_height = self->item_height; + + grub_gfxmenu_box_t box = self->menu_box; + int box_top_pad = box->get_top_pad (box); + int box_bottom_pad = box->get_bottom_pad (box); + + return (self->bounds.height + item_vspace - 2 * boxpad + - box_top_pad - box_bottom_pad) / (item_height + item_vspace); +} + +static int +check_boxes (list_impl_t self) +{ + if (self->need_to_recreate_boxes) + { + grub_gui_recreate_box (&self->menu_box, + self->menu_box_pattern, + self->theme_dir); + + grub_gui_recreate_box (&self->selected_item_box, + self->selected_item_box_pattern, + self->theme_dir); + + self->need_to_recreate_boxes = 0; + } + + return (self->menu_box != 0 && self->selected_item_box != 0); +} + +static int +check_scrollbar (list_impl_t self) +{ + if (self->need_to_recreate_scrollbar) + { + grub_gui_recreate_box (&self->scrollbar_frame, + self->scrollbar_frame_pattern, + self->theme_dir); + + grub_gui_recreate_box (&self->scrollbar_thumb, + self->scrollbar_thumb_pattern, + self->theme_dir); + + self->need_to_recreate_scrollbar = 0; + } + + return (self->scrollbar_frame != 0 && self->scrollbar_thumb != 0); +} + +static const char * +list_get_id (void *vself) +{ + list_impl_t self = vself; + return self->id; +} + +static int +list_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return (grub_strcmp (type, "component") == 0 + || grub_strcmp (type, "list") == 0); +} + +static struct grub_video_bitmap * +get_item_icon (list_impl_t self, int item_index) +{ + grub_menu_entry_t entry; + entry = grub_menu_get_entry (self->view->menu, item_index); + if (! entry) + return 0; + + return grub_gfxmenu_icon_manager_get_icon (self->icon_manager, entry); +} + +static void +make_selected_item_visible (list_impl_t self) +{ + int selected_index = self->view->selected; + if (selected_index < 0) + return; /* No item is selected. */ + int num_shown_items = get_num_shown_items (self); + int last_shown_index = self->first_shown_index + (num_shown_items - 1); + if (selected_index < self->first_shown_index) + self->first_shown_index = selected_index; + else if (selected_index > last_shown_index) + self->first_shown_index = selected_index - (num_shown_items - 1); +} + +/* Draw a scrollbar on the menu. */ +static void +draw_scrollbar (list_impl_t self, + int value, int extent, int min, int max, + int rightx, int topy, int height) +{ + grub_gfxmenu_box_t frame = self->scrollbar_frame; + grub_gfxmenu_box_t thumb = self->scrollbar_thumb; + int frame_vertical_pad = (frame->get_top_pad (frame) + + frame->get_bottom_pad (frame)); + int frame_horizontal_pad = (frame->get_left_pad (frame) + + frame->get_right_pad (frame)); + int tracktop = topy + frame->get_top_pad (frame); + int tracklen = height - frame_vertical_pad; + frame->set_content_size (frame, self->scrollbar_width, tracklen); + int thumby = tracktop + tracklen * (value - min) / (max - min); + int thumbheight = tracklen * extent / (max - min) + 1; + thumb->set_content_size (thumb, + self->scrollbar_width - frame_horizontal_pad, + thumbheight - (thumb->get_top_pad (thumb) + + thumb->get_bottom_pad (thumb))); + frame->draw (frame, + rightx - (self->scrollbar_width + frame_horizontal_pad), + topy); + thumb->draw (thumb, + rightx - (self->scrollbar_width - frame->get_right_pad (frame)), + thumby); +} + +/* Draw the list of items. */ +static void +draw_menu (list_impl_t self, int width, int drawing_scrollbar, + int num_shown_items) +{ + if (! self->menu_box || ! self->selected_item_box) + return; + + int boxpad = self->item_padding; + int icon_text_space = self->item_icon_space; + int item_vspace = self->item_spacing; + + int ascent = grub_font_get_ascent (self->item_font); + int descent = grub_font_get_descent (self->item_font); + int item_height = self->item_height; + + make_selected_item_visible (self); + + int scrollbar_h_space = drawing_scrollbar ? self->scrollbar_width : 0; + + grub_gfxmenu_box_t selbox = self->selected_item_box; + int sel_leftpad = selbox->get_left_pad (selbox); + int item_top = boxpad; + int item_left = boxpad + sel_leftpad; + int menu_index; + int visible_index; + + for (visible_index = 0, menu_index = self->first_shown_index; + visible_index < num_shown_items && menu_index < self->view->menu->size; + visible_index++, menu_index++) + { + int is_selected = (menu_index == self->view->selected); + + if (is_selected) + { + int sel_toppad = selbox->get_top_pad (selbox); + selbox->set_content_size (selbox, + (width - 2 * boxpad + - scrollbar_h_space), + item_height); + selbox->draw (selbox, + item_left - sel_leftpad, + item_top - sel_toppad); + } + + struct grub_video_bitmap *icon; + if ((icon = get_item_icon (self, menu_index)) != 0) + grub_video_blit_bitmap (icon, GRUB_VIDEO_BLIT_BLEND, + item_left, + item_top + (item_height - self->icon_height) / 2, + 0, 0, self->icon_width, self->icon_height); + + const char *item_title = + grub_menu_get_entry (self->view->menu, menu_index)->title; + grub_font_t font = + (is_selected && self->selected_item_font + ? self->selected_item_font + : self->item_font); + grub_gui_color_t text_color = + ((is_selected && self->selected_item_color_set) + ? self->selected_item_color + : self->item_color); + grub_font_draw_string (item_title, + font, + grub_gui_map_color (text_color), + item_left + self->icon_width + icon_text_space, + (item_top + (item_height - (ascent + descent)) + / 2 + ascent)); + + item_top += item_height + item_vspace; + } +} + +static void +list_paint (void *vself, const grub_video_rect_t *region) +{ + list_impl_t self = vself; + grub_video_rect_t vpsave; + + if (! self->visible) + return; + if (!grub_video_have_common_points (region, &self->bounds)) + return; + + check_boxes (self); + + if (! self->menu_box || ! self->selected_item_box) + return; + + grub_gui_set_viewport (&self->bounds, &vpsave); + { + grub_gfxmenu_box_t box = self->menu_box; + int box_left_pad = box->get_left_pad (box); + int box_top_pad = box->get_top_pad (box); + int box_right_pad = box->get_right_pad (box); + int box_bottom_pad = box->get_bottom_pad (box); + grub_video_rect_t vpsave2, content_rect; + int num_shown_items = get_num_shown_items (self); + int drawing_scrollbar = (self->draw_scrollbar + && (num_shown_items < self->view->menu->size) + && check_scrollbar (self)); + + content_rect.x = box_left_pad; + content_rect.y = box_top_pad; + content_rect.width = self->bounds.width - box_left_pad - box_right_pad; + content_rect.height = self->bounds.height - box_top_pad - box_bottom_pad; + + box->set_content_size (box, content_rect.width, content_rect.height); + + box->draw (box, 0, 0); + + grub_gui_set_viewport (&content_rect, &vpsave2); + draw_menu (self, content_rect.width, drawing_scrollbar, num_shown_items); + grub_gui_restore_viewport (&vpsave2); + + if (drawing_scrollbar) + draw_scrollbar (self, + self->first_shown_index, num_shown_items, + 0, self->view->menu->size, + self->bounds.width - box_right_pad + + self->scrollbar_width, + box_top_pad + self->item_padding, + self->bounds.height - box_top_pad - box_bottom_pad); + } + + grub_gui_restore_viewport (&vpsave); +} + +static void +list_set_parent (void *vself, grub_gui_container_t parent) +{ + list_impl_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +list_get_parent (void *vself) +{ + list_impl_t self = vself; + return self->parent; +} + +static void +list_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + list_impl_t self = vself; + self->bounds = *bounds; +} + +static void +list_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + list_impl_t self = vself; + *bounds = self->bounds; +} + +static void +list_get_minimal_size (void *vself, unsigned *width, unsigned *height) +{ + list_impl_t self = vself; + + if (check_boxes (self)) + { + int boxpad = self->item_padding; + int item_vspace = self->item_spacing; + int item_height = self->item_height; + int num_items = 3; + + grub_gfxmenu_box_t box = self->menu_box; + int box_left_pad = box->get_left_pad (box); + int box_top_pad = box->get_top_pad (box); + int box_right_pad = box->get_right_pad (box); + int box_bottom_pad = box->get_bottom_pad (box); + unsigned width_s; + + *width = grub_font_get_string_width (self->item_font, "Typical OS"); + width_s = grub_font_get_string_width (self->selected_item_font, + "Typical OS"); + if (*width < width_s) + *width = width_s; + + *width += 2 * boxpad + box_left_pad + box_right_pad; + + /* Set the menu box height to fit the items. */ + *height = (item_height * num_items + + item_vspace * (num_items - 1) + + 2 * boxpad + + box_top_pad + box_bottom_pad); + } + else + { + *width = 0; + *height = 0; + } +} + +static grub_err_t +list_set_property (void *vself, const char *name, const char *value) +{ + list_impl_t self = vself; + if (grub_strcmp (name, "item_font") == 0) + { + self->item_font = grub_font_get (value); + } + else if (grub_strcmp (name, "selected_item_font") == 0) + { + if (! value || grub_strcmp (value, "inherit") == 0) + self->selected_item_font = 0; + else + self->selected_item_font = grub_font_get (value); + } + else if (grub_strcmp (name, "item_color") == 0) + { + grub_gui_parse_color (value, &self->item_color); + } + else if (grub_strcmp (name, "selected_item_color") == 0) + { + if (! value || grub_strcmp (value, "inherit") == 0) + { + self->selected_item_color_set = 0; + } + else + { + if (grub_gui_parse_color (value, &self->selected_item_color) + == GRUB_ERR_NONE) + self->selected_item_color_set = 1; + } + } + else if (grub_strcmp (name, "icon_width") == 0) + { + self->icon_width = grub_strtol (value, 0, 10); + grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager, + self->icon_width, + self->icon_height); + } + else if (grub_strcmp (name, "icon_height") == 0) + { + self->icon_height = grub_strtol (value, 0, 10); + grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager, + self->icon_width, + self->icon_height); + } + else if (grub_strcmp (name, "item_height") == 0) + { + self->item_height = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "item_padding") == 0) + { + self->item_padding = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "item_icon_space") == 0) + { + self->item_icon_space = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "item_spacing") == 0) + { + self->item_spacing = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "visible") == 0) + { + self->visible = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "menu_pixmap_style") == 0) + { + self->need_to_recreate_boxes = 1; + grub_free (self->menu_box_pattern); + self->menu_box_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "selected_item_pixmap_style") == 0) + { + self->need_to_recreate_boxes = 1; + grub_free (self->selected_item_box_pattern); + self->selected_item_box_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "scrollbar_frame") == 0) + { + self->need_to_recreate_scrollbar = 1; + grub_free (self->scrollbar_frame_pattern); + self->scrollbar_frame_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "scrollbar_thumb") == 0) + { + self->need_to_recreate_scrollbar = 1; + grub_free (self->scrollbar_thumb_pattern); + self->scrollbar_thumb_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "scrollbar_width") == 0) + { + self->scrollbar_width = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "scrollbar") == 0) + { + self->draw_scrollbar = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "theme_dir") == 0) + { + self->need_to_recreate_boxes = 1; + grub_free (self->theme_dir); + self->theme_dir = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + self->id = grub_strdup (value); + else + self->id = 0; + } + return grub_errno; +} + +/* Set necessary information that the gfxmenu view provides. */ +static void +list_set_view_info (void *vself, + grub_gfxmenu_view_t view) +{ + list_impl_t self = vself; + grub_gfxmenu_icon_manager_set_theme_path (self->icon_manager, + view->theme_path); + self->view = view; +} + +static struct grub_gui_component_ops list_comp_ops = + { + .destroy = list_destroy, + .get_id = list_get_id, + .is_instance = list_is_instance, + .paint = list_paint, + .set_parent = list_set_parent, + .get_parent = list_get_parent, + .set_bounds = list_set_bounds, + .get_bounds = list_get_bounds, + .get_minimal_size = list_get_minimal_size, + .set_property = list_set_property + }; + +static struct grub_gui_list_ops list_ops = +{ + .set_view_info = list_set_view_info +}; + +grub_gui_component_t +grub_gui_list_new (void) +{ + list_impl_t self; + grub_font_t default_font; + grub_gui_color_t default_fg_color; + grub_gui_color_t default_bg_color; + + self = grub_zalloc (sizeof (*self)); + if (! self) + return 0; + + self->list.ops = &list_ops; + self->list.component.ops = &list_comp_ops; + + self->visible = 1; + + default_font = grub_font_get ("Unknown Regular 16"); + default_fg_color = grub_gui_color_rgb (0, 0, 0); + default_bg_color = grub_gui_color_rgb (255, 255, 255); + + self->icon_width = 32; + self->icon_height = 32; + self->item_height = 42; + self->item_padding = 14; + self->item_icon_space = 4; + self->item_spacing = 16; + self->item_font = default_font; + self->selected_item_font = 0; /* Default to using the item_font. */ + self->item_color = default_fg_color; + self->selected_item_color_set = 0; /* Default to using the item_color. */ + self->selected_item_color = default_fg_color; + + self->draw_scrollbar = 1; + self->need_to_recreate_scrollbar = 1; + self->scrollbar_frame = 0; + self->scrollbar_thumb = 0; + self->scrollbar_frame_pattern = 0; + self->scrollbar_thumb_pattern = 0; + self->scrollbar_width = 16; + + self->first_shown_index = 0; + + self->need_to_recreate_boxes = 0; + self->theme_dir = 0; + self->menu_box_pattern = 0; + self->selected_item_box_pattern = 0; + self->menu_box = grub_gfxmenu_create_box (0, 0); + self->selected_item_box = grub_gfxmenu_create_box (0, 0); + + self->icon_manager = grub_gfxmenu_icon_manager_new (); + if (! self->icon_manager) + { + self->list.component.ops->destroy (self); + return 0; + } + grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager, + self->icon_width, + self->icon_height); + return (grub_gui_component_t) self; +} diff --git a/gfxmenu/gui_progress_bar.c b/gfxmenu/gui_progress_bar.c new file mode 100644 index 000000000..e1b31794f --- /dev/null +++ b/gfxmenu/gui_progress_bar.c @@ -0,0 +1,391 @@ +/* gui_progress_bar.c - GUI progress bar component. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct grub_gui_progress_bar +{ + struct grub_gui_progress progress; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int visible; + int start; + int end; + int value; + int show_text; + char *template; + grub_font_t font; + grub_gui_color_t text_color; + grub_gui_color_t border_color; + grub_gui_color_t bg_color; + grub_gui_color_t fg_color; + + char *theme_dir; + int need_to_recreate_pixmaps; + int pixmapbar_available; + char *bar_pattern; + char *highlight_pattern; + grub_gfxmenu_box_t bar_box; + grub_gfxmenu_box_t highlight_box; +}; + +typedef struct grub_gui_progress_bar *grub_gui_progress_bar_t; + +static void +progress_bar_destroy (void *vself) +{ + grub_gui_progress_bar_t self = vself; + grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self); + grub_free (self); +} + +static const char * +progress_bar_get_id (void *vself) +{ + grub_gui_progress_bar_t self = vself; + return self->id; +} + +static int +progress_bar_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return grub_strcmp (type, "component") == 0; +} + +static int +check_pixmaps (grub_gui_progress_bar_t self) +{ + if (!self->pixmapbar_available) + return 0; + if (self->need_to_recreate_pixmaps) + { + grub_gui_recreate_box (&self->bar_box, + self->bar_pattern, + self->theme_dir); + + grub_gui_recreate_box (&self->highlight_box, + self->highlight_pattern, + self->theme_dir); + + self->need_to_recreate_pixmaps = 0; + } + + return (self->bar_box != 0 && self->highlight_box != 0); +} + +static void +draw_filled_rect_bar (grub_gui_progress_bar_t self) +{ + /* Set the progress bar's frame. */ + grub_video_rect_t f; + f.x = 1; + f.y = 1; + f.width = self->bounds.width - 2; + f.height = self->bounds.height - 2; + + /* Border. */ + grub_video_fill_rect (grub_gui_map_color (self->border_color), + f.x - 1, f.y - 1, + f.width + 2, f.height + 2); + + /* Bar background. */ + int barwidth = (f.width + * (self->value - self->start) + / (self->end - self->start)); + grub_video_fill_rect (grub_gui_map_color (self->bg_color), + f.x + barwidth, f.y, + f.width - barwidth, f.height); + + /* Bar foreground. */ + grub_video_fill_rect (grub_gui_map_color (self->fg_color), + f.x, f.y, + barwidth, f.height); +} + +static void +draw_pixmap_bar (grub_gui_progress_bar_t self) +{ + grub_gfxmenu_box_t bar = self->bar_box; + grub_gfxmenu_box_t hl = self->highlight_box; + int w = self->bounds.width; + int h = self->bounds.height; + int bar_l_pad = bar->get_left_pad (bar); + int bar_r_pad = bar->get_right_pad (bar); + int bar_t_pad = bar->get_top_pad (bar); + int bar_b_pad = bar->get_bottom_pad (bar); + int bar_h_pad = bar_l_pad + bar_r_pad; + int bar_v_pad = bar_t_pad + bar_b_pad; + int tracklen = w - bar_h_pad; + int trackheight = h - bar_v_pad; + int barwidth; + + bar->set_content_size (bar, tracklen, trackheight); + + barwidth = (tracklen * (self->value - self->start) + / (self->end - self->start)); + + hl->set_content_size (hl, barwidth, h - bar_v_pad); + + bar->draw (bar, 0, 0); + hl->draw (hl, bar_l_pad, bar_t_pad); +} + +static void +draw_text (grub_gui_progress_bar_t self) +{ + if (self->template) + { + grub_font_t font = self->font; + grub_video_color_t text_color = grub_gui_map_color (self->text_color); + int width = self->bounds.width; + int height = self->bounds.height; + char *text; + text = grub_xasprintf (self->template, + self->value > 0 ? self->value : -self->value); + if (!text) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return; + } + /* Center the text. */ + int text_width = grub_font_get_string_width (font, text); + int x = (width - text_width) / 2; + int y = ((height - grub_font_get_descent (font)) / 2 + + grub_font_get_ascent (font) / 2); + grub_font_draw_string (text, font, text_color, x, y); + } +} + +static void +progress_bar_paint (void *vself, const grub_video_rect_t *region) +{ + grub_gui_progress_bar_t self = vself; + grub_video_rect_t vpsave; + + if (! self->visible) + return; + if (!grub_video_have_common_points (region, &self->bounds)) + return; + + if (self->end == self->start) + return; + + grub_gui_set_viewport (&self->bounds, &vpsave); + + if (check_pixmaps (self)) + draw_pixmap_bar (self); + else + draw_filled_rect_bar (self); + + draw_text (self); + + grub_gui_restore_viewport (&vpsave); +} + +static void +progress_bar_set_parent (void *vself, grub_gui_container_t parent) +{ + grub_gui_progress_bar_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +progress_bar_get_parent (void *vself) +{ + grub_gui_progress_bar_t self = vself; + return self->parent; +} + +static void +progress_bar_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + grub_gui_progress_bar_t self = vself; + self->bounds = *bounds; +} + +static void +progress_bar_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + grub_gui_progress_bar_t self = vself; + *bounds = self->bounds; +} + +static void +progress_bar_get_minimal_size (void *vself, + unsigned *width, unsigned *height) +{ + unsigned text_width = 0, text_height = 0; + grub_gui_progress_bar_t self = vself; + + if (self->template) + { + text_width = grub_font_get_string_width (self->font, self->template); + text_width += grub_font_get_string_width (self->font, "XXXXXXXXXX"); + text_height = grub_font_get_descent (self->font) + + grub_font_get_ascent (self->font); + } + *width = 200; + if (*width < text_width) + *width = text_width; + *height = 28; + if (*height < text_height) + *height = text_height; +} + +static void +progress_bar_set_state (void *vself, int visible, int start, + int current, int end) +{ + grub_gui_progress_bar_t self = vself; + self->visible = visible; + self->start = start; + self->value = current; + self->end = end; +} + +static grub_err_t +progress_bar_set_property (void *vself, const char *name, const char *value) +{ + grub_gui_progress_bar_t self = vself; + if (grub_strcmp (name, "text") == 0) + { + grub_free (self->template); + if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_LONG@") == 0) + value + = _("The highlighted entry will be executed automatically in %ds."); + else if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_MIDDLE@") == 0) + /* TRANSLATORS: 's' stands for seconds. + It's a standalone timeout notification. + Please use the short form in your language. */ + value = _("%ds remaining."); + else if (grub_strcmp (value, "@TIMEOUT_NOTIFICATION_SHORT@") == 0) + /* TRANSLATORS: 's' stands for seconds. + It's a standalone timeout notification. + Please use the shortest form available in you language. */ + value = _("%ds"); + + self->template = grub_strdup (value); + } + else if (grub_strcmp (name, "font") == 0) + { + self->font = grub_font_get (value); + } + else if (grub_strcmp (name, "text_color") == 0) + { + grub_gui_parse_color (value, &self->text_color); + } + else if (grub_strcmp (name, "border_color") == 0) + { + grub_gui_parse_color (value, &self->border_color); + } + else if (grub_strcmp (name, "bg_color") == 0) + { + grub_gui_parse_color (value, &self->bg_color); + } + else if (grub_strcmp (name, "fg_color") == 0) + { + grub_gui_parse_color (value, &self->fg_color); + } + else if (grub_strcmp (name, "bar_style") == 0) + { + self->need_to_recreate_pixmaps = 1; + self->pixmapbar_available = 1; + grub_free (self->bar_pattern); + self->bar_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "highlight_style") == 0) + { + self->need_to_recreate_pixmaps = 1; + self->pixmapbar_available = 1; + grub_free (self->highlight_pattern); + self->highlight_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "theme_dir") == 0) + { + self->need_to_recreate_pixmaps = 1; + grub_free (self->theme_dir); + self->theme_dir = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "id") == 0) + { + grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self); + grub_free (self->id); + if (value) + self->id = grub_strdup (value); + else + self->id = 0; + /* if (self->id && grub_strcmp (self->id, GRUB_GFXMENU_TIMEOUT_COMPONENT_ID) + == 0)*/ + grub_gfxmenu_timeout_register ((grub_gui_component_t) self, + progress_bar_set_state); + } + return grub_errno; +} + +static struct grub_gui_component_ops progress_bar_ops = +{ + .destroy = progress_bar_destroy, + .get_id = progress_bar_get_id, + .is_instance = progress_bar_is_instance, + .paint = progress_bar_paint, + .set_parent = progress_bar_set_parent, + .get_parent = progress_bar_get_parent, + .set_bounds = progress_bar_set_bounds, + .get_bounds = progress_bar_get_bounds, + .get_minimal_size = progress_bar_get_minimal_size, + .set_property = progress_bar_set_property +}; + +static struct grub_gui_progress_ops progress_bar_pb_ops = + { + .set_state = progress_bar_set_state + }; + +grub_gui_component_t +grub_gui_progress_bar_new (void) +{ + grub_gui_progress_bar_t self; + self = grub_zalloc (sizeof (*self)); + if (! self) + return 0; + + self->progress.ops = &progress_bar_pb_ops; + self->progress.component.ops = &progress_bar_ops; + self->visible = 1; + self->font = grub_font_get ("Unknown Regular 16"); + grub_gui_color_t black = { .red = 0, .green = 0, .blue = 0, .alpha = 255 }; + grub_gui_color_t gray = { .red = 128, .green = 128, .blue = 128, .alpha = 255 }; + grub_gui_color_t lightgray = { .red = 200, .green = 200, .blue = 200, .alpha = 255 }; + self->text_color = black; + self->border_color = black; + self->bg_color = gray; + self->fg_color = lightgray; + + return (grub_gui_component_t) self; +} diff --git a/gfxmenu/gui_string_util.c b/gfxmenu/gui_string_util.c new file mode 100644 index 000000000..8c51e396a --- /dev/null +++ b/gfxmenu/gui_string_util.c @@ -0,0 +1,327 @@ +/* gui_string_util.c - String utilities used by the GUI system. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include +#include + +/* Create a new NUL-terminated string on the heap as a substring of BUF. + The range of buf included is the half-open interval [START,END). + The index START is inclusive, END is exclusive. */ +char * +grub_new_substring (const char *buf, + grub_size_t start, grub_size_t end) +{ + if (end < start) + return 0; + grub_size_t len = end - start; + char *s = grub_malloc (len + 1); + if (! s) + return 0; + grub_memcpy (s, buf + start, len); + s[len] = '\0'; + return s; +} + +/* Eliminate "." and ".." path elements from PATH. A new heap-allocated + string is returned. */ +static char * +canonicalize_path (const char *path) +{ + int i; + const char *p; + char *newpath = 0; + + /* Count the path components in path. */ + int components = 1; + for (p = path; *p; p++) + if (*p == '/') + components++; + + char **path_array = grub_malloc (components * sizeof (*path_array)); + if (! path_array) + return 0; + + /* Initialize array elements to NULL pointers; in case once of the + allocations fails, the cleanup code can just call grub_free() for all + pointers in the array. */ + for (i = 0; i < components; i++) + path_array[i] = 0; + + /* Parse the path into path_array. */ + p = path; + for (i = 0; i < components && p; i++) + { + /* Find the end of the path element. */ + const char *end = grub_strchr (p, '/'); + if (!end) + end = p + grub_strlen (p); + + /* Copy the element. */ + path_array[i] = grub_new_substring (p, 0, end - p); + if (! path_array[i]) + goto cleanup; + + /* Advance p to point to the start of the next element, or NULL. */ + if (*end) + p = end + 1; + else + p = 0; + } + + /* Eliminate '.' and '..' elements from the path array. */ + int newpath_length = 0; + for (i = components - 1; i >= 0; --i) + { + if (! grub_strcmp (path_array[i], ".")) + { + grub_free (path_array[i]); + path_array[i] = 0; + } + else if (! grub_strcmp (path_array[i], "..") + && i > 0) + { + /* Delete the '..' and the prior path element. */ + grub_free (path_array[i]); + path_array[i] = 0; + --i; + grub_free (path_array[i]); + path_array[i] = 0; + } + else + { + newpath_length += grub_strlen (path_array[i]) + 1; + } + } + + /* Construct a new path string. */ + newpath = grub_malloc (newpath_length + 1); + if (! newpath) + goto cleanup; + + newpath[0] = '\0'; + char *newpath_end = newpath; + int first = 1; + for (i = 0; i < components; i++) + { + char *element = path_array[i]; + if (element) + { + /* For all components but the first, prefix with a slash. */ + if (! first) + newpath_end = grub_stpcpy (newpath_end, "/"); + newpath_end = grub_stpcpy (newpath_end, element); + first = 0; + } + } + +cleanup: + for (i = 0; i < components; i++) + grub_free (path_array[i]); + grub_free (path_array); + + return newpath; +} + +/* Return a new heap-allocated string representing to absolute path + to the file referred to by PATH. If PATH is an absolute path, then + the returned path is a copy of PATH. If PATH is a relative path, then + BASE is with PATH used to construct the absolute path. */ +char * +grub_resolve_relative_path (const char *base, const char *path) +{ + char *abspath; + char *canonpath; + char *p; + grub_size_t l; + + /* If PATH is an absolute path, then just use it as is. */ + if (path[0] == '/' || path[0] == '(') + return canonicalize_path (path); + + abspath = grub_malloc (grub_strlen (base) + grub_strlen (path) + 3); + if (! abspath) + return 0; + + /* Concatenate BASE and PATH. */ + p = grub_stpcpy (abspath, base); + l = grub_strlen (abspath); + if (l == 0 || abspath[l-1] != '/') + { + *p = '/'; + p++; + *p = 0; + } + grub_stpcpy (p, path); + + canonpath = canonicalize_path (abspath); + if (! canonpath) + return abspath; + + grub_free (abspath); + return canonpath; +} + +/* Get the path of the directory where the file at FILE_PATH is located. + FILE_PATH should refer to a file, not a directory. The returned path + includes a trailing slash. + This does not handle GRUB "(hd0,0)" paths properly yet since it only + looks at slashes. */ +char * +grub_get_dirname (const char *file_path) +{ + int i; + int last_slash; + + last_slash = -1; + for (i = grub_strlen (file_path) - 1; i >= 0; --i) + { + if (file_path[i] == '/') + { + last_slash = i; + break; + } + } + if (last_slash == -1) + return grub_strdup ("/"); + + return grub_new_substring (file_path, 0, last_slash + 1); +} + +static __inline int +my_isxdigit (char c) +{ + return ((c >= '0' && c <= '9') + || (c >= 'a' && c <= 'f') + || (c >= 'A' && c <= 'F')); +} + +static int +parse_hex_color_component (const char *s, unsigned start, unsigned end) +{ + unsigned len; + char buf[3]; + + len = end - start; + /* Check the limits so we don't overrun the buffer. */ + if (len < 1 || len > 2) + return 0; + + if (len == 1) + { + buf[0] = s[start]; /* Get the first and only hex digit. */ + buf[1] = buf[0]; /* Duplicate the hex digit. */ + } + else if (len == 2) + { + buf[0] = s[start]; + buf[1] = s[start + 1]; + } + + buf[2] = '\0'; + + return grub_strtoul (buf, 0, 16); +} + +/* Parse a color string of the form "r, g, b", "#RGB", "#RGBA", + "#RRGGBB", or "#RRGGBBAA". */ +grub_err_t +grub_gui_parse_color (const char *s, grub_gui_color_t *color) +{ + grub_gui_color_t c; + + /* Skip whitespace. */ + while (*s && grub_isspace (*s)) + s++; + + if (*s == '#') + { + /* HTML-style. Number if hex digits: + [6] #RRGGBB [3] #RGB + [8] #RRGGBBAA [4] #RGBA */ + + s++; /* Skip the '#'. */ + /* Count the hexits to determine the format. */ + int hexits = 0; + const char *end = s; + while (my_isxdigit (*end)) + { + end++; + hexits++; + } + + /* Parse the color components based on the format. */ + if (hexits == 3 || hexits == 4) + { + c.red = parse_hex_color_component (s, 0, 1); + c.green = parse_hex_color_component (s, 1, 2); + c.blue = parse_hex_color_component (s, 2, 3); + if (hexits == 4) + c.alpha = parse_hex_color_component (s, 3, 4); + else + c.alpha = 255; + } + else if (hexits == 6 || hexits == 8) + { + c.red = parse_hex_color_component (s, 0, 2); + c.green = parse_hex_color_component (s, 2, 4); + c.blue = parse_hex_color_component (s, 4, 6); + if (hexits == 8) + c.alpha = parse_hex_color_component (s, 6, 8); + else + c.alpha = 255; + } + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "invalid HTML-type color string `%s'", s); + } + else if (grub_isdigit (*s)) + { + /* Comma separated decimal values. */ + c.red = grub_strtoul (s, 0, 0); + if ((s = grub_strchr (s, ',')) == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "missing 1st comma separator in color `%s'", s); + s++; + c.green = grub_strtoul (s, 0, 0); + if ((s = grub_strchr (s, ',')) == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "missing 2nd comma separator in color `%s'", s); + s++; + c.blue = grub_strtoul (s, 0, 0); + if ((s = grub_strchr (s, ',')) == 0) + c.alpha = 255; + else + { + s++; + c.alpha = grub_strtoul (s, 0, 0); + } + } + else + { + if (! grub_gui_get_named_color (s, &c)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "invalid named color `%s'", s); + } + + if (grub_errno == GRUB_ERR_NONE) + *color = c; + return grub_errno; +} diff --git a/gfxmenu/gui_util.c b/gfxmenu/gui_util.c new file mode 100644 index 000000000..eba7bb39e --- /dev/null +++ b/gfxmenu/gui_util.c @@ -0,0 +1,101 @@ +/* gui_util.c - GUI utility functions. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 . + */ + +#include +#include +#include +#include + + +struct find_by_id_state +{ + const char *match_id; + grub_gui_component_callback match_callback; + void *match_userdata; +}; + +static void +find_by_id_recursively (grub_gui_component_t component, void *userdata) +{ + struct find_by_id_state *state; + const char *id; + + state = (struct find_by_id_state *) userdata; + id = component->ops->get_id (component); + if (id && grub_strcmp (id, state->match_id) == 0) + state->match_callback (component, state->match_userdata); + + if (component->ops->is_instance (component, "container")) + { + grub_gui_container_t container; + container = (grub_gui_container_t) component; + container->ops->iterate_children (container, + find_by_id_recursively, + state); + } +} + +void +grub_gui_find_by_id (grub_gui_component_t root, + const char *id, + grub_gui_component_callback cb, + void *userdata) +{ + struct find_by_id_state state; + state.match_id = id; + state.match_callback = cb; + state.match_userdata = userdata; + find_by_id_recursively (root, &state); +} + + +struct iterate_recursively_state +{ + grub_gui_component_callback callback; + void *userdata; +}; + +static +void iterate_recursively_cb (grub_gui_component_t component, void *userdata) +{ + struct iterate_recursively_state *state; + + state = (struct iterate_recursively_state *) userdata; + state->callback (component, state->userdata); + + if (component->ops->is_instance (component, "container")) + { + grub_gui_container_t container; + container = (grub_gui_container_t) component; + container->ops->iterate_children (container, + iterate_recursively_cb, + state); + } +} + +void +grub_gui_iterate_recursively (grub_gui_component_t root, + grub_gui_component_callback cb, + void *userdata) +{ + struct iterate_recursively_state state; + state.callback = cb; + state.userdata = userdata; + iterate_recursively_cb (root, &state); +} diff --git a/gfxmenu/icon_manager.c b/gfxmenu/icon_manager.c new file mode 100644 index 000000000..0c304ede0 --- /dev/null +++ b/gfxmenu/icon_manager.c @@ -0,0 +1,263 @@ +/* icon_manager.c - gfxmenu icon manager. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Currently hard coded to '.png' extension. */ +static const char icon_extension[] = ".png"; + +typedef struct icon_entry +{ + char *class_name; + struct grub_video_bitmap *bitmap; + struct icon_entry *next; +} *icon_entry_t; + +struct grub_gfxmenu_icon_manager +{ + char *theme_path; + int icon_width; + int icon_height; + + /* Icon cache: linked list w/ dummy head node. */ + struct icon_entry cache; +}; + + +/* Create a new icon manager and return a point to it. */ +grub_gfxmenu_icon_manager_t +grub_gfxmenu_icon_manager_new (void) +{ + grub_gfxmenu_icon_manager_t mgr; + mgr = grub_malloc (sizeof (*mgr)); + if (! mgr) + return 0; + + mgr->theme_path = 0; + mgr->icon_width = 0; + mgr->icon_height = 0; + + /* Initialize the dummy head node. */ + mgr->cache.class_name = 0; + mgr->cache.bitmap = 0; + mgr->cache.next = 0; + + return mgr; +} + +/* Destroy the icon manager MGR, freeing all resources used by it. + +Note: Any bitmaps returned by grub_gfxmenu_icon_manager_get_icon() +are destroyed and must not be used by the caller after this function +is called. */ +void +grub_gfxmenu_icon_manager_destroy (grub_gfxmenu_icon_manager_t mgr) +{ + grub_gfxmenu_icon_manager_clear_cache (mgr); + grub_free (mgr->theme_path); + grub_free (mgr); +} + +/* Clear the icon cache. */ +void +grub_gfxmenu_icon_manager_clear_cache (grub_gfxmenu_icon_manager_t mgr) +{ + icon_entry_t cur; + icon_entry_t next; + for (cur = mgr->cache.next; cur; cur = next) + { + next = cur->next; + grub_free (cur->class_name); + grub_video_bitmap_destroy (cur->bitmap); + grub_free (cur); + } + mgr->cache.next = 0; +} + +/* Set the theme path. If the theme path is changed, the icon cache + is cleared. */ +void +grub_gfxmenu_icon_manager_set_theme_path (grub_gfxmenu_icon_manager_t mgr, + const char *path) +{ + /* Clear the cache if the theme path has changed. */ + if (((mgr->theme_path == 0) != (path == 0)) + || (grub_strcmp (mgr->theme_path, path) != 0)) + grub_gfxmenu_icon_manager_clear_cache (mgr); + + grub_free (mgr->theme_path); + mgr->theme_path = path ? grub_strdup (path) : 0; +} + +/* Set the icon size. When icons are requested from the icon manager, + they are scaled to this size before being returned. If the size is + changed, the icon cache is cleared. */ +void +grub_gfxmenu_icon_manager_set_icon_size (grub_gfxmenu_icon_manager_t mgr, + int width, int height) +{ + /* If the width or height is changed, we must clear the cache, since the + scaled bitmaps are stored in the cache. */ + if (width != mgr->icon_width || height != mgr->icon_height) + grub_gfxmenu_icon_manager_clear_cache (mgr); + + mgr->icon_width = width; + mgr->icon_height = height; +} + +/* Try to load an icon for the specified CLASS_NAME in the directory DIR. + Returns 0 if the icon could not be loaded, or returns a pointer to a new + bitmap if it was successful. */ +static struct grub_video_bitmap * +try_loading_icon (grub_gfxmenu_icon_manager_t mgr, + const char *dir, const char *class_name) +{ + char *path; + int l; + + path = grub_malloc (grub_strlen (dir) + grub_strlen (class_name) + + grub_strlen (icon_extension) + 3); + if (! path) + return 0; + + grub_strcpy (path, dir); + l = grub_strlen (path); + if (path[l-1] != '/') + { + path[l] = '/'; + path[l+1] = 0; + } + grub_strcat (path, class_name); + grub_strcat (path, icon_extension); + + struct grub_video_bitmap *raw_bitmap; + grub_video_bitmap_load (&raw_bitmap, path); + grub_free (path); + grub_errno = GRUB_ERR_NONE; /* Critical to clear the error!! */ + if (! raw_bitmap) + return 0; + + struct grub_video_bitmap *scaled_bitmap; + grub_video_bitmap_create_scaled (&scaled_bitmap, + mgr->icon_width, mgr->icon_height, + raw_bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + grub_video_bitmap_destroy (raw_bitmap); + if (! scaled_bitmap) + { + grub_error_push (); + grub_error (grub_errno, "failed to scale icon"); + return 0; + } + + return scaled_bitmap; +} + +/* Get the icon for the specified class CLASS_NAME. If an icon for + CLASS_NAME already exists in the cache, then a reference to the cached + bitmap is returned. If it is not cached, then it is loaded and cached. + If no icon could be could for CLASS_NAME, then 0 is returned. */ +static struct grub_video_bitmap * +get_icon_by_class (grub_gfxmenu_icon_manager_t mgr, const char *class_name) +{ + /* First check the icon cache. */ + icon_entry_t entry; + for (entry = mgr->cache.next; entry; entry = entry->next) + { + if (grub_strcmp (entry->class_name, class_name) == 0) + return entry->bitmap; + } + + if (! mgr->theme_path) + return 0; + + /* Otherwise, we search for an icon to load. */ + char *theme_dir = grub_get_dirname (mgr->theme_path); + char *icons_dir; + struct grub_video_bitmap *icon; + icon = 0; + /* First try the theme's own icons, from "grub/themes/NAME/icons/" */ + icons_dir = grub_resolve_relative_path (theme_dir, "icons/"); + if (icons_dir) + { + icon = try_loading_icon (mgr, icons_dir, class_name); + grub_free (icons_dir); + } + + grub_free (theme_dir); + if (! icon) + { + const char *icondir; + + icondir = grub_env_get ("icondir"); + if (icondir) + icon = try_loading_icon (mgr, icondir, class_name); + } + + /* No icon was found. */ + /* This should probably be noted in the cache, so that a search is not + performed each time an icon for CLASS_NAME is requested. */ + if (! icon) + return 0; + + /* Insert a new cache entry for this icon. */ + entry = grub_malloc (sizeof (*entry)); + if (! entry) + { + grub_video_bitmap_destroy (icon); + return 0; + } + entry->class_name = grub_strdup (class_name); + entry->bitmap = icon; + entry->next = mgr->cache.next; + mgr->cache.next = entry; /* Link it into the cache. */ + return entry->bitmap; +} + +/* Get the best available icon for ENTRY. Beginning with the first class + listed in the menu entry and proceeding forward, an icon for each class + is searched for. The first icon found is returned. The returned icon + is scaled to the size specified by + grub_gfxmenu_icon_manager_set_icon_size(). + + Note: Bitmaps returned by this function are destroyed when the + icon manager is destroyed. + */ +struct grub_video_bitmap * +grub_gfxmenu_icon_manager_get_icon (grub_gfxmenu_icon_manager_t mgr, + grub_menu_entry_t entry) +{ + struct grub_menu_entry_class *c; + struct grub_video_bitmap *icon; + + /* Try each class in succession. */ + icon = 0; + for (c = entry->classes->next; c && ! icon; c = c->next) + icon = get_icon_by_class (mgr, c->name); + return icon; +} diff --git a/gfxmenu/model.c b/gfxmenu/model.c new file mode 100644 index 000000000..e69de29bb diff --git a/gfxmenu/named_colors.c b/gfxmenu/named_colors.c new file mode 100644 index 000000000..eedbc47fb --- /dev/null +++ b/gfxmenu/named_colors.c @@ -0,0 +1,209 @@ +/* named_colors.c - Named color values. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 . + */ + +#include +#include +#include +#include + +struct named_color +{ + const char *name; + grub_gui_color_t color; +}; + +/* + Named color list generated from the list of SVG color keywords from + , + processed through the following Perl command: + perl -ne 'chomp;split;print "{ \"$_[0]\", RGB_COLOR($_[2]) },\n"' + */ + +#define RGB_COLOR(r,g,b) {.red = r, .green = g, .blue = b, .alpha = 255} + +static struct named_color named_colors[] = +{ + { "aliceblue", RGB_COLOR(240,248,255) }, + { "antiquewhite", RGB_COLOR(250,235,215) }, + { "aqua", RGB_COLOR(0,255,255) }, + { "aquamarine", RGB_COLOR(127,255,212) }, + { "azure", RGB_COLOR(240,255,255) }, + { "beige", RGB_COLOR(245,245,220) }, + { "bisque", RGB_COLOR(255,228,196) }, + { "black", RGB_COLOR(0,0,0) }, + { "blanchedalmond", RGB_COLOR(255,235,205) }, + { "blue", RGB_COLOR(0,0,255) }, + { "blueviolet", RGB_COLOR(138,43,226) }, + { "brown", RGB_COLOR(165,42,42) }, + { "burlywood", RGB_COLOR(222,184,135) }, + { "cadetblue", RGB_COLOR(95,158,160) }, + { "chartreuse", RGB_COLOR(127,255,0) }, + { "chocolate", RGB_COLOR(210,105,30) }, + { "coral", RGB_COLOR(255,127,80) }, + { "cornflowerblue", RGB_COLOR(100,149,237) }, + { "cornsilk", RGB_COLOR(255,248,220) }, + { "crimson", RGB_COLOR(220,20,60) }, + { "cyan", RGB_COLOR(0,255,255) }, + { "darkblue", RGB_COLOR(0,0,139) }, + { "darkcyan", RGB_COLOR(0,139,139) }, + { "darkgoldenrod", RGB_COLOR(184,134,11) }, + { "darkgray", RGB_COLOR(169,169,169) }, + { "darkgreen", RGB_COLOR(0,100,0) }, + { "darkgrey", RGB_COLOR(169,169,169) }, + { "darkkhaki", RGB_COLOR(189,183,107) }, + { "darkmagenta", RGB_COLOR(139,0,139) }, + { "darkolivegreen", RGB_COLOR(85,107,47) }, + { "darkorange", RGB_COLOR(255,140,0) }, + { "darkorchid", RGB_COLOR(153,50,204) }, + { "darkred", RGB_COLOR(139,0,0) }, + { "darksalmon", RGB_COLOR(233,150,122) }, + { "darkseagreen", RGB_COLOR(143,188,143) }, + { "darkslateblue", RGB_COLOR(72,61,139) }, + { "darkslategray", RGB_COLOR(47,79,79) }, + { "darkslategrey", RGB_COLOR(47,79,79) }, + { "darkturquoise", RGB_COLOR(0,206,209) }, + { "darkviolet", RGB_COLOR(148,0,211) }, + { "deeppink", RGB_COLOR(255,20,147) }, + { "deepskyblue", RGB_COLOR(0,191,255) }, + { "dimgray", RGB_COLOR(105,105,105) }, + { "dimgrey", RGB_COLOR(105,105,105) }, + { "dodgerblue", RGB_COLOR(30,144,255) }, + { "firebrick", RGB_COLOR(178,34,34) }, + { "floralwhite", RGB_COLOR(255,250,240) }, + { "forestgreen", RGB_COLOR(34,139,34) }, + { "fuchsia", RGB_COLOR(255,0,255) }, + { "gainsboro", RGB_COLOR(220,220,220) }, + { "ghostwhite", RGB_COLOR(248,248,255) }, + { "gold", RGB_COLOR(255,215,0) }, + { "goldenrod", RGB_COLOR(218,165,32) }, + { "gray", RGB_COLOR(128,128,128) }, + { "green", RGB_COLOR(0,128,0) }, + { "greenyellow", RGB_COLOR(173,255,47) }, + { "grey", RGB_COLOR(128,128,128) }, + { "honeydew", RGB_COLOR(240,255,240) }, + { "hotpink", RGB_COLOR(255,105,180) }, + { "indianred", RGB_COLOR(205,92,92) }, + { "indigo", RGB_COLOR(75,0,130) }, + { "ivory", RGB_COLOR(255,255,240) }, + { "khaki", RGB_COLOR(240,230,140) }, + { "lavender", RGB_COLOR(230,230,250) }, + { "lavenderblush", RGB_COLOR(255,240,245) }, + { "lawngreen", RGB_COLOR(124,252,0) }, + { "lemonchiffon", RGB_COLOR(255,250,205) }, + { "lightblue", RGB_COLOR(173,216,230) }, + { "lightcoral", RGB_COLOR(240,128,128) }, + { "lightcyan", RGB_COLOR(224,255,255) }, + { "lightgoldenrodyellow", RGB_COLOR(250,250,210) }, + { "lightgray", RGB_COLOR(211,211,211) }, + { "lightgreen", RGB_COLOR(144,238,144) }, + { "lightgrey", RGB_COLOR(211,211,211) }, + { "lightpink", RGB_COLOR(255,182,193) }, + { "lightsalmon", RGB_COLOR(255,160,122) }, + { "lightseagreen", RGB_COLOR(32,178,170) }, + { "lightskyblue", RGB_COLOR(135,206,250) }, + { "lightslategray", RGB_COLOR(119,136,153) }, + { "lightslategrey", RGB_COLOR(119,136,153) }, + { "lightsteelblue", RGB_COLOR(176,196,222) }, + { "lightyellow", RGB_COLOR(255,255,224) }, + { "lime", RGB_COLOR(0,255,0) }, + { "limegreen", RGB_COLOR(50,205,50) }, + { "linen", RGB_COLOR(250,240,230) }, + { "magenta", RGB_COLOR(255,0,255) }, + { "maroon", RGB_COLOR(128,0,0) }, + { "mediumaquamarine", RGB_COLOR(102,205,170) }, + { "mediumblue", RGB_COLOR(0,0,205) }, + { "mediumorchid", RGB_COLOR(186,85,211) }, + { "mediumpurple", RGB_COLOR(147,112,219) }, + { "mediumseagreen", RGB_COLOR(60,179,113) }, + { "mediumslateblue", RGB_COLOR(123,104,238) }, + { "mediumspringgreen", RGB_COLOR(0,250,154) }, + { "mediumturquoise", RGB_COLOR(72,209,204) }, + { "mediumvioletred", RGB_COLOR(199,21,133) }, + { "midnightblue", RGB_COLOR(25,25,112) }, + { "mintcream", RGB_COLOR(245,255,250) }, + { "mistyrose", RGB_COLOR(255,228,225) }, + { "moccasin", RGB_COLOR(255,228,181) }, + { "navajowhite", RGB_COLOR(255,222,173) }, + { "navy", RGB_COLOR(0,0,128) }, + { "oldlace", RGB_COLOR(253,245,230) }, + { "olive", RGB_COLOR(128,128,0) }, + { "olivedrab", RGB_COLOR(107,142,35) }, + { "orange", RGB_COLOR(255,165,0) }, + { "orangered", RGB_COLOR(255,69,0) }, + { "orchid", RGB_COLOR(218,112,214) }, + { "palegoldenrod", RGB_COLOR(238,232,170) }, + { "palegreen", RGB_COLOR(152,251,152) }, + { "paleturquoise", RGB_COLOR(175,238,238) }, + { "palevioletred", RGB_COLOR(219,112,147) }, + { "papayawhip", RGB_COLOR(255,239,213) }, + { "peachpuff", RGB_COLOR(255,218,185) }, + { "peru", RGB_COLOR(205,133,63) }, + { "pink", RGB_COLOR(255,192,203) }, + { "plum", RGB_COLOR(221,160,221) }, + { "powderblue", RGB_COLOR(176,224,230) }, + { "purple", RGB_COLOR(128,0,128) }, + { "red", RGB_COLOR(255,0,0) }, + { "rosybrown", RGB_COLOR(188,143,143) }, + { "royalblue", RGB_COLOR(65,105,225) }, + { "saddlebrown", RGB_COLOR(139,69,19) }, + { "salmon", RGB_COLOR(250,128,114) }, + { "sandybrown", RGB_COLOR(244,164,96) }, + { "seagreen", RGB_COLOR(46,139,87) }, + { "seashell", RGB_COLOR(255,245,238) }, + { "sienna", RGB_COLOR(160,82,45) }, + { "silver", RGB_COLOR(192,192,192) }, + { "skyblue", RGB_COLOR(135,206,235) }, + { "slateblue", RGB_COLOR(106,90,205) }, + { "slategray", RGB_COLOR(112,128,144) }, + { "slategrey", RGB_COLOR(112,128,144) }, + { "snow", RGB_COLOR(255,250,250) }, + { "springgreen", RGB_COLOR(0,255,127) }, + { "steelblue", RGB_COLOR(70,130,180) }, + { "tan", RGB_COLOR(210,180,140) }, + { "teal", RGB_COLOR(0,128,128) }, + { "thistle", RGB_COLOR(216,191,216) }, + { "tomato", RGB_COLOR(255,99,71) }, + { "turquoise", RGB_COLOR(64,224,208) }, + { "violet", RGB_COLOR(238,130,238) }, + { "wheat", RGB_COLOR(245,222,179) }, + { "white", RGB_COLOR(255,255,255) }, + { "whitesmoke", RGB_COLOR(245,245,245) }, + { "yellow", RGB_COLOR(255,255,0) }, + { "yellowgreen", RGB_COLOR(154,205,50) }, + { 0, { 0, 0, 0, 0 } } /* Terminator. */ +}; + +/* Get the color named NAME. If the color was found, returns 1 and + stores the color into *COLOR. If the color was not found, returns 0 and + does not modify *COLOR. */ +int +grub_gui_get_named_color (const char *name, + grub_gui_color_t *color) +{ + int i; + for (i = 0; named_colors[i].name; i++) + { + if (grub_strcmp (named_colors[i].name, name) == 0) + { + *color = named_colors[i].color; + return 1; + } + } + return 0; +} diff --git a/gfxmenu/theme_loader.c b/gfxmenu/theme_loader.c new file mode 100644 index 000000000..3854c6c53 --- /dev/null +++ b/gfxmenu/theme_loader.c @@ -0,0 +1,723 @@ +/* theme_loader.c - Theme file loader for gfxmenu. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Construct a new box widget using ABSPATTERN to find the pixmap files for + it, storing the new box instance at *BOXPTR. + PATTERN should be of the form: "(hd0,0)/somewhere/style*.png". + The '*' then gets substituted with the various pixmap names that the + box uses. */ +static grub_err_t +recreate_box_absolute (grub_gfxmenu_box_t *boxptr, const char *abspattern) +{ + char *prefix; + char *suffix; + char *star; + grub_gfxmenu_box_t box; + + star = grub_strchr (abspattern, '*'); + if (! star) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "missing `*' in box pixmap pattern `%s'", abspattern); + + /* Prefix: Get the part before the '*'. */ + prefix = grub_malloc (star - abspattern + 1); + if (! prefix) + return grub_errno; + + grub_memcpy (prefix, abspattern, star - abspattern); + prefix[star - abspattern] = '\0'; + + /* Suffix: Everything after the '*' is the suffix. */ + suffix = star + 1; + + box = grub_gfxmenu_create_box (prefix, suffix); + grub_free (prefix); + if (! box) + return grub_errno; + + if (*boxptr) + (*boxptr)->destroy (*boxptr); + *boxptr = box; + return grub_errno; +} + + +/* Construct a new box widget using PATTERN to find the pixmap files for it, + storing the new widget at *BOXPTR. PATTERN should be of the form: + "somewhere/style*.png". The '*' then gets substituted with the various + pixmap names that the widget uses. + + Important! The value of *BOXPTR must be initialized! It must either + (1) Be 0 (a NULL pointer), or + (2) Be a pointer to a valid 'grub_gfxmenu_box_t' instance. + In this case, the previous instance is destroyed. */ +grub_err_t +grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr, + const char *pattern, const char *theme_dir) +{ + char *abspattern; + + /* Check arguments. */ + if (! pattern) + { + /* If no pixmap pattern is given, then just create an empty box. */ + if (*boxptr) + (*boxptr)->destroy (*boxptr); + *boxptr = grub_gfxmenu_create_box (0, 0); + return grub_errno; + } + + if (! theme_dir) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "styled box missing theme directory"); + + /* Resolve to an absolute path. */ + abspattern = grub_resolve_relative_path (theme_dir, pattern); + if (! abspattern) + return grub_errno; + + /* Create the box. */ + recreate_box_absolute (boxptr, abspattern); + grub_free (abspattern); + return grub_errno; +} + +/* Set the specified property NAME on the view to the given string VALUE. + The caller is responsible for the lifetimes of NAME and VALUE. */ +static grub_err_t +theme_set_string (grub_gfxmenu_view_t view, + const char *name, + const char *value, + const char *theme_dir, + const char *filename, + int line_num, + int col_num) +{ + if (! grub_strcmp ("title-font", name)) + view->title_font = grub_font_get (value); + else if (! grub_strcmp ("message-font", name)) + view->message_font = grub_font_get (value); + else if (! grub_strcmp ("terminal-font", name)) + { + grub_free (view->terminal_font_name); + view->terminal_font_name = grub_strdup (value); + if (! view->terminal_font_name) + return grub_errno; + } + else if (! grub_strcmp ("title-color", name)) + grub_gui_parse_color (value, &view->title_color); + else if (! grub_strcmp ("message-color", name)) + grub_gui_parse_color (value, &view->message_color); + else if (! grub_strcmp ("message-bg-color", name)) + grub_gui_parse_color (value, &view->message_bg_color); + else if (! grub_strcmp ("desktop-image", name)) + { + struct grub_video_bitmap *raw_bitmap; + struct grub_video_bitmap *scaled_bitmap; + char *path; + path = grub_resolve_relative_path (theme_dir, value); + if (! path) + return grub_errno; + if (grub_video_bitmap_load (&raw_bitmap, path) != GRUB_ERR_NONE) + { + grub_free (path); + return grub_errno; + } + grub_free(path); + grub_video_bitmap_create_scaled (&scaled_bitmap, + view->screen.width, + view->screen.height, + raw_bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + grub_video_bitmap_destroy (raw_bitmap); + if (! scaled_bitmap) + { + grub_error_push (); + return grub_error (grub_errno, "error scaling desktop image"); + } + + grub_video_bitmap_destroy (view->desktop_image); + view->desktop_image = scaled_bitmap; + } + else if (! grub_strcmp ("desktop-color", name)) + grub_gui_parse_color (value, &view->desktop_color); + else if (! grub_strcmp ("terminal-box", name)) + { + grub_err_t err; + err = grub_gui_recreate_box (&view->terminal_box, value, theme_dir); + if (err != GRUB_ERR_NONE) + return err; + } + else if (! grub_strcmp ("title-text", name)) + { + grub_free (view->title_text); + view->title_text = grub_strdup (value); + if (! view->title_text) + return grub_errno; + } + else + { + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "%s:%d:%d unknown property `%s'", + filename, line_num, col_num, name); + } + return grub_errno; +} + +struct parsebuf +{ + char *buf; + int pos; + int len; + int line_num; + int col_num; + const char *filename; + char *theme_dir; + grub_gfxmenu_view_t view; +}; + +static int +has_more (struct parsebuf *p) +{ + return p->pos < p->len; +} + +static int +read_char (struct parsebuf *p) +{ + if (has_more (p)) + { + char c; + c = p->buf[p->pos++]; + if (c == '\n') + { + p->line_num++; + p->col_num = 1; + } + else + { + p->col_num++; + } + return c; + } + else + return -1; +} + +static int +peek_char (struct parsebuf *p) +{ + if (has_more (p)) + return p->buf[p->pos]; + else + return -1; +} + +static int +is_whitespace (char c) +{ + return (c == ' ' + || c == '\t' + || c == '\r' + || c == '\n' + || c == '\f'); +} + +static void +skip_whitespace (struct parsebuf *p) +{ + while (has_more (p) && is_whitespace(peek_char (p))) + read_char (p); +} + +static void +advance_to_next_line (struct parsebuf *p) +{ + int c; + + /* Eat characters up to the newline. */ + do + { + c = read_char (p); + } + while (c != -1 && c != '\n'); +} + +static int +is_identifier_char (int c) +{ + return (c != -1 + && (grub_isalpha(c) + || grub_isdigit(c) + || c == '_' + || c == '-')); +} + +static char * +read_identifier (struct parsebuf *p) +{ + /* Index of the first character of the identifier in p->buf. */ + int start; + /* Next index after the last character of the identifer in p->buf. */ + int end; + + skip_whitespace (p); + + /* Capture the start of the identifier. */ + start = p->pos; + + /* Scan for the end. */ + while (is_identifier_char (peek_char (p))) + read_char (p); + end = p->pos; + + if (end - start < 1) + return 0; + + return grub_new_substring (p->buf, start, end); +} + +static char * +read_expression (struct parsebuf *p) +{ + int start; + int end; + + skip_whitespace (p); + if (peek_char (p) == '"') + { + /* Read as a quoted string. + The quotation marks are not included in the expression value. */ + /* Skip opening quotation mark. */ + read_char (p); + start = p->pos; + while (has_more (p) && peek_char (p) != '"') + read_char (p); + end = p->pos; + /* Skip the terminating quotation mark. */ + read_char (p); + } + else if (peek_char (p) == '(') + { + /* Read as a parenthesized string -- for tuples/coordinates. */ + /* The parentheses are included in the expression value. */ + int c; + + start = p->pos; + do + { + c = read_char (p); + } + while (c != -1 && c != ')'); + end = p->pos; + } + else if (has_more (p)) + { + /* Read as a single word -- for numeric values or words without + whitespace. */ + start = p->pos; + while (has_more (p) && ! is_whitespace (peek_char (p))) + read_char (p); + end = p->pos; + } + else + { + /* The end of the theme file has been reached. */ + grub_error (GRUB_ERR_IO, "%s:%d:%d expression expected in theme file", + p->filename, p->line_num, p->col_num); + return 0; + } + + return grub_new_substring (p->buf, start, end); +} + +static grub_err_t +parse_proportional_spec (char *value, signed *abs, grub_fixed_signed_t *prop) +{ + signed num; + char *ptr; + int sig = 0; + *abs = 0; + *prop = 0; + ptr = value; + while (*ptr) + { + sig = 0; + + while (*ptr == '-' || *ptr == '+') + { + if (*ptr == '-') + sig = !sig; + ptr++; + } + + num = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + if (sig) + num = -num; + if (*ptr == '%') + { + *prop += grub_fixed_fsf_divide (grub_signed_to_fixed (num), 100); + ptr++; + } + else + *abs += num; + } + return GRUB_ERR_NONE; +} + + +/* Read a GUI object specification from the theme file. + Any components created will be added to the GUI container PARENT. */ +static grub_err_t +read_object (struct parsebuf *p, grub_gui_container_t parent) +{ + grub_video_rect_t bounds; + + char *name; + name = read_identifier (p); + if (! name) + goto cleanup; + + grub_gui_component_t component = 0; + if (grub_strcmp (name, "label") == 0) + { + component = grub_gui_label_new (); + } + else if (grub_strcmp (name, "image") == 0) + { + component = grub_gui_image_new (); + } + else if (grub_strcmp (name, "vbox") == 0) + { + component = (grub_gui_component_t) grub_gui_vbox_new (); + } + else if (grub_strcmp (name, "hbox") == 0) + { + component = (grub_gui_component_t) grub_gui_hbox_new (); + } + else if (grub_strcmp (name, "canvas") == 0) + { + component = (grub_gui_component_t) grub_gui_canvas_new (); + } + else if (grub_strcmp (name, "progress_bar") == 0) + { + component = grub_gui_progress_bar_new (); + } + else if (grub_strcmp (name, "circular_progress") == 0) + { + component = grub_gui_circular_progress_new (); + } + else if (grub_strcmp (name, "boot_menu") == 0) + { + component = grub_gui_list_new (); + } + else + { + /* Unknown type. */ + grub_error (GRUB_ERR_IO, "%s:%d:%d unknown object type `%s'", + p->filename, p->line_num, p->col_num, name); + goto cleanup; + } + + if (! component) + goto cleanup; + + /* Inform the component about the theme so it can find its resources. */ + component->ops->set_property (component, "theme_dir", p->theme_dir); + component->ops->set_property (component, "theme_path", p->filename); + + /* Add the component as a child of PARENT. */ + bounds.x = 0; + bounds.y = 0; + bounds.width = -1; + bounds.height = -1; + component->ops->set_bounds (component, &bounds); + parent->ops->add (parent, component); + + skip_whitespace (p); + if (read_char (p) != '{') + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d expected `{' after object type name `%s'", + p->filename, p->line_num, p->col_num, name); + goto cleanup; + } + + while (has_more (p)) + { + skip_whitespace (p); + + /* Check whether the end has been encountered. */ + if (peek_char (p) == '}') + { + /* Skip the closing brace. */ + read_char (p); + break; + } + + if (peek_char (p) == '#') + { + /* Skip comments. */ + advance_to_next_line (p); + continue; + } + + if (peek_char (p) == '+') + { + /* Skip the '+'. */ + read_char (p); + + /* Check whether this component is a container. */ + if (component->ops->is_instance (component, "container")) + { + /* Read the sub-object recursively and add it as a child. */ + if (read_object (p, (grub_gui_container_t) component) != 0) + goto cleanup; + /* After reading the sub-object, resume parsing, expecting + another property assignment or sub-object definition. */ + continue; + } + else + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d attempted to add object to non-container", + p->filename, p->line_num, p->col_num); + goto cleanup; + } + } + + char *property; + property = read_identifier (p); + if (! property) + { + grub_error (GRUB_ERR_IO, "%s:%d:%d identifier expected in theme file", + p->filename, p->line_num, p->col_num); + goto cleanup; + } + + skip_whitespace (p); + if (read_char (p) != '=') + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d expected `=' after property name `%s'", + p->filename, p->line_num, p->col_num, property); + grub_free (property); + goto cleanup; + } + skip_whitespace (p); + + char *value; + value = read_expression (p); + if (! value) + { + grub_free (property); + goto cleanup; + } + + /* Handle the property value. */ + if (grub_strcmp (property, "left") == 0) + parse_proportional_spec (value, &component->x, &component->xfrac); + else if (grub_strcmp (property, "top") == 0) + parse_proportional_spec (value, &component->y, &component->yfrac); + else if (grub_strcmp (property, "width") == 0) + parse_proportional_spec (value, &component->w, &component->wfrac); + else if (grub_strcmp (property, "height") == 0) + parse_proportional_spec (value, &component->h, &component->hfrac); + else + /* General property handling. */ + component->ops->set_property (component, property, value); + + grub_free (value); + grub_free (property); + if (grub_errno != GRUB_ERR_NONE) + goto cleanup; + } + +cleanup: + grub_free (name); + return grub_errno; +} + +static grub_err_t +read_property (struct parsebuf *p) +{ + char *name; + + /* Read the property name. */ + name = read_identifier (p); + if (! name) + { + advance_to_next_line (p); + return grub_errno; + } + + /* Skip whitespace before separator. */ + skip_whitespace (p); + + /* Read separator. */ + if (read_char (p) != ':') + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d missing separator after property name `%s'", + p->filename, p->line_num, p->col_num, name); + goto done; + } + + /* Skip whitespace after separator. */ + skip_whitespace (p); + + /* Get the value based on its type. */ + if (peek_char (p) == '"') + { + /* String value (e.g., '"My string"'). */ + char *value = read_expression (p); + if (! value) + { + grub_error (GRUB_ERR_IO, "%s:%d:%d missing property value", + p->filename, p->line_num, p->col_num); + goto done; + } + /* If theme_set_string results in an error, grub_errno will be returned + below. */ + theme_set_string (p->view, name, value, p->theme_dir, + p->filename, p->line_num, p->col_num); + grub_free (value); + } + else + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d property value invalid; " + "enclose literal values in quotes (\")", + p->filename, p->line_num, p->col_num); + goto done; + } + +done: + grub_free (name); + return grub_errno; +} + +/* Set properties on the view based on settings from the specified + theme file. */ +grub_err_t +grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) +{ + grub_file_t file; + struct parsebuf p; + + p.view = view; + p.theme_dir = grub_get_dirname (theme_path); + + file = grub_file_open (theme_path); + if (! file) + { + grub_free (p.theme_dir); + return grub_errno; + } + + p.len = grub_file_size (file); + p.buf = grub_malloc (p.len); + p.pos = 0; + p.line_num = 1; + p.col_num = 1; + p.filename = theme_path; + if (! p.buf) + { + grub_file_close (file); + grub_free (p.theme_dir); + return grub_errno; + } + if (grub_file_read (file, p.buf, p.len) != p.len) + { + grub_free (p.buf); + grub_file_close (file); + grub_free (p.theme_dir); + return grub_errno; + } + + if (view->canvas) + view->canvas->component.ops->destroy (view->canvas); + + view->canvas = grub_gui_canvas_new (); + ((grub_gui_component_t) view->canvas) + ->ops->set_bounds ((grub_gui_component_t) view->canvas, + &view->screen); + + while (has_more (&p)) + { + /* Skip comments (lines beginning with #). */ + if (peek_char (&p) == '#') + { + advance_to_next_line (&p); + continue; + } + + /* Find the first non-whitespace character. */ + skip_whitespace (&p); + + /* Handle the content. */ + if (peek_char (&p) == '+') + { + /* Skip the '+'. */ + read_char (&p); + read_object (&p, view->canvas); + } + else + { + read_property (&p); + } + + if (grub_errno != GRUB_ERR_NONE) + goto fail; + } + + /* Set the new theme path. */ + grub_free (view->theme_path); + view->theme_path = grub_strdup (theme_path); + goto cleanup; + +fail: + if (view->canvas) + { + view->canvas->component.ops->destroy (view->canvas); + view->canvas = 0; + } + +cleanup: + grub_free (p.buf); + grub_file_close (file); + grub_free (p.theme_dir); + return grub_errno; +} diff --git a/gfxmenu/view.c b/gfxmenu/view.c new file mode 100644 index 000000000..9a5671cdd --- /dev/null +++ b/gfxmenu/view.c @@ -0,0 +1,453 @@ +/* view.c - Graphical menu interface MVC view. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +init_terminal (grub_gfxmenu_view_t view); +static grub_video_rect_t term_rect; +static grub_gfxmenu_view_t term_view; + +/* Create a new view object, loading the theme specified by THEME_PATH and + associating MODEL with the view. */ +grub_gfxmenu_view_t +grub_gfxmenu_view_new (const char *theme_path, + int width, int height) +{ + grub_gfxmenu_view_t view; + grub_font_t default_font; + grub_gui_color_t default_fg_color; + grub_gui_color_t default_bg_color; + + view = grub_malloc (sizeof (*view)); + if (! view) + return 0; + + view->screen.x = 0; + view->screen.y = 0; + view->screen.width = width; + view->screen.height = height; + + default_font = grub_font_get ("Unknown Regular 16"); + default_fg_color = grub_gui_color_rgb (0, 0, 0); + default_bg_color = grub_gui_color_rgb (255, 255, 255); + + view->canvas = 0; + + view->title_font = default_font; + view->message_font = default_font; + view->terminal_font_name = grub_strdup ("Fixed 10"); + view->title_color = default_fg_color; + view->message_color = default_bg_color; + view->message_bg_color = default_fg_color; + view->desktop_image = 0; + view->desktop_color = default_bg_color; + view->terminal_box = grub_gfxmenu_create_box (0, 0); + view->title_text = grub_strdup ("GRUB Boot Menu"); + view->progress_message_text = 0; + view->theme_path = 0; + + /* Set the timeout bar's frame. */ + view->progress_message_frame.width = view->screen.width * 4 / 5; + view->progress_message_frame.height = 50; + view->progress_message_frame.x = view->screen.x + + (view->screen.width - view->progress_message_frame.width) / 2; + view->progress_message_frame.y = view->screen.y + + view->screen.height - 90 - 20 - view->progress_message_frame.height; + + if (grub_gfxmenu_view_load_theme (view, theme_path) != 0) + { + grub_gfxmenu_view_destroy (view); + return 0; + } + + return view; +} + +/* Destroy the view object. All used memory is freed. */ +void +grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view) +{ + if (!view) + return; + grub_video_bitmap_destroy (view->desktop_image); + if (view->terminal_box) + view->terminal_box->destroy (view->terminal_box); + grub_free (view->terminal_font_name); + grub_free (view->title_text); + grub_free (view->progress_message_text); + grub_free (view->theme_path); + if (view->canvas) + view->canvas->component.ops->destroy (view->canvas); + grub_free (view); +} + +static void +redraw_background (grub_gfxmenu_view_t view, + const grub_video_rect_t *bounds) +{ + if (view->desktop_image) + { + struct grub_video_bitmap *img = view->desktop_image; + grub_video_blit_bitmap (img, GRUB_VIDEO_BLIT_REPLACE, + bounds->x, bounds->y, + bounds->x - view->screen.x, + bounds->y - view->screen.y, + bounds->width, bounds->height); + } + else + { + grub_video_fill_rect (grub_gui_map_color (view->desktop_color), + bounds->x, bounds->y, + bounds->width, bounds->height); + } +} + +static void +draw_title (grub_gfxmenu_view_t view) +{ + if (! view->title_text) + return; + + /* Center the title. */ + int title_width = grub_font_get_string_width (view->title_font, + view->title_text); + int x = (view->screen.width - title_width) / 2; + int y = 40 + grub_font_get_ascent (view->title_font); + grub_font_draw_string (view->title_text, + view->title_font, + grub_gui_map_color (view->title_color), + x, y); +} + +struct progress_value_data +{ + int visible; + int start; + int end; + int value; +}; + +struct grub_gfxmenu_timeout_notify *grub_gfxmenu_timeout_notifications; + +static void +update_timeouts (int visible, int start, int value, int end) +{ + struct grub_gfxmenu_timeout_notify *cur; + + for (cur = grub_gfxmenu_timeout_notifications; cur; cur = cur->next) + cur->set_state (cur->self, visible, start, value, end); +} + +static void +redraw_timeouts (struct grub_gfxmenu_view *view) +{ + struct grub_gfxmenu_timeout_notify *cur; + + for (cur = grub_gfxmenu_timeout_notifications; cur; cur = cur->next) + { + grub_video_rect_t bounds; + cur->self->ops->get_bounds (cur->self, &bounds); + grub_gfxmenu_view_redraw (view, &bounds); + } +} + +void +grub_gfxmenu_print_timeout (int timeout, void *data) +{ + struct grub_gfxmenu_view *view = data; + + if (view->first_timeout == -1) + view->first_timeout = timeout; + + update_timeouts (1, -(view->first_timeout + 1), -timeout, 0); + redraw_timeouts (view); + grub_video_swap_buffers (); + if (view->double_repaint) + redraw_timeouts (view); +} + +void +grub_gfxmenu_clear_timeout (void *data) +{ + struct grub_gfxmenu_view *view = data; + + update_timeouts (0, 1, 0, 0); + redraw_timeouts (view); + grub_video_swap_buffers (); + if (view->double_repaint) + redraw_timeouts (view); +} + +static void +update_menu_visit (grub_gui_component_t component, + void *userdata) +{ + grub_gfxmenu_view_t view; + view = userdata; + if (component->ops->is_instance (component, "list")) + { + grub_gui_list_t list = (grub_gui_list_t) component; + list->ops->set_view_info (list, view); + } +} + +/* Update any boot menu components with the current menu model and + theme path. */ +static void +update_menu_components (grub_gfxmenu_view_t view) +{ + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + update_menu_visit, view); +} + +static void +draw_message (grub_gfxmenu_view_t view) +{ + char *text = view->progress_message_text; + grub_video_rect_t f = view->progress_message_frame; + if (! text) + return; + + grub_font_t font = view->message_font; + grub_video_color_t color = grub_gui_map_color (view->message_color); + + /* Border. */ + grub_video_fill_rect (color, + f.x-1, f.y-1, f.width+2, f.height+2); + /* Fill. */ + grub_video_fill_rect (grub_gui_map_color (view->message_bg_color), + f.x, f.y, f.width, f.height); + + /* Center the text. */ + int text_width = grub_font_get_string_width (font, text); + int x = f.x + (f.width - text_width) / 2; + int y = (f.y + (f.height - grub_font_get_descent (font)) / 2 + + grub_font_get_ascent (font) / 2); + grub_font_draw_string (text, font, color, x, y); +} + +void +grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, + const grub_video_rect_t *region) +{ + if (grub_video_have_common_points (&term_rect, region)) + grub_gfxterm_schedule_repaint (); + + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + + redraw_background (view, region); + if (view->canvas) + view->canvas->component.ops->paint (view->canvas, region); + draw_title (view); + if (grub_video_have_common_points (&view->progress_message_frame, region)) + draw_message (view); +} + +void +grub_gfxmenu_view_draw (grub_gfxmenu_view_t view) +{ + init_terminal (view); + + /* Clear the screen; there may be garbage left over in video memory. */ + grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), + view->screen.x, view->screen.y, + view->screen.width, view->screen.height); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), + view->screen.x, view->screen.y, + view->screen.width, view->screen.height); + + update_menu_components (view); + + grub_gfxmenu_view_redraw (view, &view->screen); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_gfxmenu_view_redraw (view, &view->screen); +} + +static void +redraw_menu_visit (grub_gui_component_t component, + void *userdata) +{ + grub_gfxmenu_view_t view; + view = userdata; + if (component->ops->is_instance (component, "list")) + { + grub_gui_list_t list; + grub_video_rect_t bounds; + + list = (grub_gui_list_t) component; + component->ops->get_bounds (component, &bounds); + grub_gfxmenu_view_redraw (view, &bounds); + } +} + +void +grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view) +{ + update_menu_components (view); + + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + redraw_menu_visit, view); + grub_video_swap_buffers (); + if (view->double_repaint) + { + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + redraw_menu_visit, view); + } +} + +void +grub_gfxmenu_set_chosen_entry (int entry, void *data) +{ + grub_gfxmenu_view_t view = data; + + view->selected = entry; + grub_gfxmenu_redraw_menu (view); +} + +static void +grub_gfxmenu_draw_terminal_box (void) +{ + grub_gfxmenu_box_t term_box; + + term_box = term_view->terminal_box; + if (!term_box) + return; + + term_box->set_content_size (term_box, term_rect.width, + term_rect.height); + + term_box->draw (term_box, + term_rect.x - term_box->get_left_pad (term_box), + term_rect.y - term_box->get_top_pad (term_box)); + grub_video_swap_buffers (); + if (term_view->double_repaint) + term_box->draw (term_box, + term_rect.x - term_box->get_left_pad (term_box), + term_rect.y - term_box->get_top_pad (term_box)); +} + +static void +init_terminal (grub_gfxmenu_view_t view) +{ + term_rect.width = view->screen.width * 7 / 10; + term_rect.height = view->screen.height * 7 / 10; + + term_rect.x = view->screen.x + view->screen.width * (10 - 7) / 10 / 2; + term_rect.y = view->screen.y + view->screen.height * (10 - 7) / 10 / 2; + + term_view = view; + + /* Note: currently there is no API for changing the gfxterm font + on the fly, so whatever font the initially loaded theme specifies + will be permanent. */ + grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, term_rect.x, + term_rect.y, + term_rect.width, term_rect.height, + view->double_repaint, view->terminal_font_name, 3); + grub_gfxterm_decorator_hook = grub_gfxmenu_draw_terminal_box; +} + +/* FIXME: previously notifications were displayed in special case. + Is it necessary? + */ +#if 0 +/* Sets MESSAGE as the progress message for the view. + MESSAGE can be 0, in which case no message is displayed. */ +static void +set_progress_message (grub_gfxmenu_view_t view, const char *message) +{ + grub_free (view->progress_message_text); + if (message) + view->progress_message_text = grub_strdup (message); + else + view->progress_message_text = 0; +} + +static void +notify_booting (grub_menu_entry_t entry, void *userdata) +{ + grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata; + + char *s = grub_malloc (100 + grub_strlen (entry->title)); + if (!s) + return; + + grub_sprintf (s, "Booting '%s'", entry->title); + set_progress_message (view, s); + grub_free (s); + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); +} + +static void +notify_fallback (grub_menu_entry_t entry, void *userdata) +{ + grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata; + + char *s = grub_malloc (100 + grub_strlen (entry->title)); + if (!s) + return; + + grub_sprintf (s, "Falling back to '%s'", entry->title); + set_progress_message (view, s); + grub_free (s); + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); +} + +static void +notify_execution_failure (void *userdata __attribute__ ((unused))) +{ +} + + +static struct grub_menu_execute_callback execute_callback = +{ + .notify_booting = notify_booting, + .notify_fallback = notify_fallback, + .notify_failure = notify_execution_failure +}; + +#endif diff --git a/gfxmenu/widget-box.c b/gfxmenu/widget-box.c new file mode 100644 index 000000000..079fd66d4 --- /dev/null +++ b/gfxmenu/widget-box.c @@ -0,0 +1,313 @@ +/* widget_box.c - Pixmap-stylized box widget. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +enum box_pixmaps +{ + BOX_PIXMAP_NW, BOX_PIXMAP_NE, BOX_PIXMAP_SE, BOX_PIXMAP_SW, + BOX_PIXMAP_N, BOX_PIXMAP_E, BOX_PIXMAP_S, BOX_PIXMAP_W, + BOX_PIXMAP_CENTER +}; + +static const char *box_pixmap_names[] = { + /* Corners: */ + "nw", "ne", "se", "sw", + /* Sides: */ + "n", "e", "s", "w", + /* Center: */ + "c" +}; + +#define BOX_NUM_PIXMAPS (sizeof(box_pixmap_names)/sizeof(*box_pixmap_names)) + +static int +get_height (struct grub_video_bitmap *bitmap) +{ + if (bitmap) + return grub_video_bitmap_get_height (bitmap); + else + return 0; +} + +static int +get_width (struct grub_video_bitmap *bitmap) +{ + if (bitmap) + return grub_video_bitmap_get_width (bitmap); + else + return 0; +} + +static void +blit (grub_gfxmenu_box_t self, int pixmap_index, int x, int y) +{ + struct grub_video_bitmap *bitmap; + bitmap = self->scaled_pixmaps[pixmap_index]; + if (! bitmap) + return; + grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_BLEND, + x, y, 0, 0, + grub_video_bitmap_get_width (bitmap), + grub_video_bitmap_get_height (bitmap)); +} + +static void +draw (grub_gfxmenu_box_t self, int x, int y) +{ + int height_n; + int height_s; + int height_e; + int height_w; + int width_n; + int width_s; + int width_e; + int width_w; + + height_n = get_height (self->scaled_pixmaps[BOX_PIXMAP_N]); + height_s = get_height (self->scaled_pixmaps[BOX_PIXMAP_S]); + height_e = get_height (self->scaled_pixmaps[BOX_PIXMAP_E]); + height_w = get_height (self->scaled_pixmaps[BOX_PIXMAP_W]); + width_n = get_width (self->scaled_pixmaps[BOX_PIXMAP_N]); + width_s = get_width (self->scaled_pixmaps[BOX_PIXMAP_S]); + width_e = get_width (self->scaled_pixmaps[BOX_PIXMAP_E]); + width_w = get_width (self->scaled_pixmaps[BOX_PIXMAP_W]); + + /* Draw sides. */ + blit (self, BOX_PIXMAP_N, x + width_w, y); + blit (self, BOX_PIXMAP_S, x + width_w, y + height_n + self->content_height); + blit (self, BOX_PIXMAP_E, x + width_w + self->content_width, y + height_n); + blit (self, BOX_PIXMAP_W, x, y + height_n); + + /* Draw corners. */ + blit (self, BOX_PIXMAP_NW, x, y); + blit (self, BOX_PIXMAP_NE, x + width_w + self->content_width, y); + blit (self, BOX_PIXMAP_SE, + x + width_w + self->content_width, + y + height_n + self->content_height); + blit (self, BOX_PIXMAP_SW, x, y + height_n + self->content_height); + + /* Draw center. */ + blit (self, BOX_PIXMAP_CENTER, x + width_w, y + height_n); +} + +static grub_err_t +scale_pixmap (grub_gfxmenu_box_t self, int i, int w, int h) +{ + struct grub_video_bitmap **scaled = &self->scaled_pixmaps[i]; + struct grub_video_bitmap *raw = self->raw_pixmaps[i]; + + if (raw == 0) + return grub_errno; + + if (w == -1) + w = grub_video_bitmap_get_width (raw); + if (h == -1) + h = grub_video_bitmap_get_height (raw); + + if (*scaled == 0 + || ((int) grub_video_bitmap_get_width (*scaled) != w) + || ((int) grub_video_bitmap_get_height (*scaled) != h)) + { + if (*scaled) + { + grub_video_bitmap_destroy (*scaled); + *scaled = 0; + } + + /* Don't try to create a bitmap with a zero dimension. */ + if (w != 0 && h != 0) + grub_video_bitmap_create_scaled (scaled, w, h, raw, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + if (grub_errno != GRUB_ERR_NONE) + { + grub_error_push (); + grub_error (grub_errno, + "failed to scale bitmap for styled box pixmap #%d", i); + } + } + + return grub_errno; +} + +static void +set_content_size (grub_gfxmenu_box_t self, + int width, int height) +{ + self->content_width = width; + self->content_height = height; + + /* Resize sides to match the width and height. */ + /* It is assumed that the corners width/height match the adjacent sides. */ + + /* Resize N and S sides to match width. */ + if (scale_pixmap(self, BOX_PIXMAP_N, width, -1) != GRUB_ERR_NONE) + return; + if (scale_pixmap(self, BOX_PIXMAP_S, width, -1) != GRUB_ERR_NONE) + return; + + /* Resize E and W sides to match height. */ + if (scale_pixmap(self, BOX_PIXMAP_E, -1, height) != GRUB_ERR_NONE) + return; + if (scale_pixmap(self, BOX_PIXMAP_W, -1, height) != GRUB_ERR_NONE) + return; + + /* Don't scale the corners--they are assumed to match the sides. */ + if (scale_pixmap(self, BOX_PIXMAP_NW, -1, -1) != GRUB_ERR_NONE) + return; + if (scale_pixmap(self, BOX_PIXMAP_SW, -1, -1) != GRUB_ERR_NONE) + return; + if (scale_pixmap(self, BOX_PIXMAP_NE, -1, -1) != GRUB_ERR_NONE) + return; + if (scale_pixmap(self, BOX_PIXMAP_SE, -1, -1) != GRUB_ERR_NONE) + return; + + /* Scale the center area. */ + if (scale_pixmap(self, BOX_PIXMAP_CENTER, width, height) != GRUB_ERR_NONE) + return; +} + +static int +get_left_pad (grub_gfxmenu_box_t self) +{ + return get_width (self->raw_pixmaps[BOX_PIXMAP_W]); +} + +static int +get_top_pad (grub_gfxmenu_box_t self) +{ + return get_height (self->raw_pixmaps[BOX_PIXMAP_N]); +} + +static int +get_right_pad (grub_gfxmenu_box_t self) +{ + return get_width (self->raw_pixmaps[BOX_PIXMAP_E]); +} + +static int +get_bottom_pad (grub_gfxmenu_box_t self) +{ + return get_height (self->raw_pixmaps[BOX_PIXMAP_S]); +} + +static void +destroy (grub_gfxmenu_box_t self) +{ + unsigned i; + for (i = 0; i < BOX_NUM_PIXMAPS; i++) + { + if (self->raw_pixmaps[i]) + grub_video_bitmap_destroy(self->raw_pixmaps[i]); + self->raw_pixmaps[i] = 0; + + if (self->scaled_pixmaps[i]) + grub_video_bitmap_destroy(self->scaled_pixmaps[i]); + self->scaled_pixmaps[i] = 0; + } + grub_free (self->raw_pixmaps); + self->raw_pixmaps = 0; + grub_free (self->scaled_pixmaps); + self->scaled_pixmaps = 0; + + /* Free self: must be the last step! */ + grub_free (self); +} + + +/* Create a new box. If PIXMAPS_PREFIX and PIXMAPS_SUFFIX are both non-null, + then an attempt is made to load the north, south, east, west, northwest, + northeast, southeast, southwest, and center pixmaps. + If either PIXMAPS_PREFIX or PIXMAPS_SUFFIX is 0, then no pixmaps are + loaded, and the box has zero-width borders and is drawn transparent. */ +grub_gfxmenu_box_t +grub_gfxmenu_create_box (const char *pixmaps_prefix, + const char *pixmaps_suffix) +{ + unsigned i; + grub_gfxmenu_box_t box; + + box = (grub_gfxmenu_box_t) grub_malloc (sizeof (*box)); + if (! box) + return 0; + + box->content_width = 0; + box->content_height = 0; + box->raw_pixmaps = + (struct grub_video_bitmap **) + grub_malloc (BOX_NUM_PIXMAPS * sizeof (struct grub_video_bitmap *)); + box->scaled_pixmaps = + (struct grub_video_bitmap **) + grub_malloc (BOX_NUM_PIXMAPS * sizeof (struct grub_video_bitmap *)); + + /* Initialize all pixmap pointers to NULL so that proper destruction can + be performed if an error is encountered partway through construction. */ + for (i = 0; i < BOX_NUM_PIXMAPS; i++) + box->raw_pixmaps[i] = 0; + for (i = 0; i < BOX_NUM_PIXMAPS; i++) + box->scaled_pixmaps[i] = 0; + + /* Load the pixmaps. */ + for (i = 0; i < BOX_NUM_PIXMAPS; i++) + { + if (pixmaps_prefix && pixmaps_suffix) + { + char *path; + char *path_end; + + path = grub_malloc (grub_strlen (pixmaps_prefix) + + grub_strlen (box_pixmap_names[i]) + + grub_strlen (pixmaps_suffix) + + 1); + if (! path) + goto fail_and_destroy; + + /* Construct the specific path for this pixmap. */ + path_end = grub_stpcpy (path, pixmaps_prefix); + path_end = grub_stpcpy (path_end, box_pixmap_names[i]); + path_end = grub_stpcpy (path_end, pixmaps_suffix); + + grub_video_bitmap_load (&box->raw_pixmaps[i], path); + grub_free (path); + + /* Ignore missing pixmaps. */ + grub_errno = GRUB_ERR_NONE; + } + } + + box->draw = draw; + box->set_content_size = set_content_size; + box->get_left_pad = get_left_pad; + box->get_top_pad = get_top_pad; + box->get_right_pad = get_right_pad; + box->get_bottom_pad = get_bottom_pad; + box->destroy = destroy; + return box; + +fail_and_destroy: + destroy (box); + return 0; +} diff --git a/gnulib/alloca.h b/gnulib/alloca.h index 5d16e08b7..107534e98 100644 --- a/gnulib/alloca.h +++ b/gnulib/alloca.h @@ -1,7 +1,7 @@ /* Memory allocation on the stack. - Copyright (C) 1995, 1999, 2001-2004, 2006-2008 Free Software - Foundation, Inc. + Copyright (C) 1995, 1999, 2001-2004, 2006-2010 Free Software Foundation, + Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published diff --git a/gnulib/argp-ba.c b/gnulib/argp-ba.c new file mode 100644 index 000000000..95feabb86 --- /dev/null +++ b/gnulib/argp-ba.c @@ -0,0 +1,34 @@ +/* Default definition for ARGP_PROGRAM_BUG_ADDRESS. + Copyright (C) 1996, 1997, 1999, 2009, 2010 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +/* If set by the user program, it should point to string that is the + bug-reporting address for the program. It will be printed by argp_help if + the ARGP_HELP_BUG_ADDR flag is set (as it is by various standard help + messages), embedded in a sentence that says something like `Report bugs to + ADDR.'. */ +const char *argp_program_bug_address +/* This variable should be zero-initialized. On most systems, putting it into + BSS is sufficient. Not so on MacOS X 10.3 and 10.4, see + + . */ +#if defined __ELF__ + /* On ELF systems, variables in BSS behave well. */ +#else + = (const char *) 0 +#endif + ; diff --git a/gnulib/argp-eexst.c b/gnulib/argp-eexst.c new file mode 100644 index 000000000..115a8cd5d --- /dev/null +++ b/gnulib/argp-eexst.c @@ -0,0 +1,30 @@ +/* Default definition for ARGP_ERR_EXIT_STATUS + Copyright (C) 1997, 2009, 2010 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "argp.h" + +/* The exit status that argp will use when exiting due to a parsing error. + If not defined or set by the user program, this defaults to EX_USAGE from + . */ +error_t argp_err_exit_status = EX_USAGE; diff --git a/gnulib/argp-fmtstream.c b/gnulib/argp-fmtstream.c new file mode 100644 index 000000000..70bbebc21 --- /dev/null +++ b/gnulib/argp-fmtstream.c @@ -0,0 +1,435 @@ +/* Word-wrapping and line-truncating streams + Copyright (C) 1997-1999, 2001-2003, 2005, 2009-2010 Free Software + Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +/* This package emulates glibc `line_wrap_stream' semantics for systems that + don't have that. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "argp-fmtstream.h" +#include "argp-namefrob.h" + +#ifndef ARGP_FMTSTREAM_USE_LINEWRAP + +#ifndef isblank +#define isblank(ch) ((ch)==' ' || (ch)=='\t') +#endif + +#if defined _LIBC && defined USE_IN_LIBIO +# include +# include +# define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a) +#endif + +#define INIT_BUF_SIZE 200 +#define PRINTF_SIZE_GUESS 150 + +/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines + written on it with LMARGIN spaces and limits them to RMARGIN columns + total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by + replacing the whitespace before them with a newline and WMARGIN spaces. + Otherwise, chars beyond RMARGIN are simply dropped until a newline. + Returns NULL if there was an error. */ +argp_fmtstream_t +__argp_make_fmtstream (FILE *stream, + size_t lmargin, size_t rmargin, ssize_t wmargin) +{ + argp_fmtstream_t fs; + + fs = (struct argp_fmtstream *) malloc (sizeof (struct argp_fmtstream)); + if (fs != NULL) + { + fs->stream = stream; + + fs->lmargin = lmargin; + fs->rmargin = rmargin; + fs->wmargin = wmargin; + fs->point_col = 0; + fs->point_offs = 0; + + fs->buf = (char *) malloc (INIT_BUF_SIZE); + if (! fs->buf) + { + free (fs); + fs = 0; + } + else + { + fs->p = fs->buf; + fs->end = fs->buf + INIT_BUF_SIZE; + } + } + + return fs; +} +#if 0 +/* Not exported. */ +#ifdef weak_alias +weak_alias (__argp_make_fmtstream, argp_make_fmtstream) +#endif +#endif + +/* Flush FS to its stream, and free it (but don't close the stream). */ +void +__argp_fmtstream_free (argp_fmtstream_t fs) +{ + __argp_fmtstream_update (fs); + if (fs->p > fs->buf) + { +#ifdef USE_IN_LIBIO + __fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf); +#else + fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream); +#endif + } + free (fs->buf); + free (fs); +} +#if 0 +/* Not exported. */ +#ifdef weak_alias +weak_alias (__argp_fmtstream_free, argp_fmtstream_free) +#endif +#endif + +/* Process FS's buffer so that line wrapping is done from POINT_OFFS to the + end of its buffer. This code is mostly from glibc stdio/linewrap.c. */ +void +__argp_fmtstream_update (argp_fmtstream_t fs) +{ + char *buf, *nl; + size_t len; + + /* Scan the buffer for newlines. */ + buf = fs->buf + fs->point_offs; + while (buf < fs->p) + { + size_t r; + + if (fs->point_col == 0 && fs->lmargin != 0) + { + /* We are starting a new line. Print spaces to the left margin. */ + const size_t pad = fs->lmargin; + if (fs->p + pad < fs->end) + { + /* We can fit in them in the buffer by moving the + buffer text up and filling in the beginning. */ + memmove (buf + pad, buf, fs->p - buf); + fs->p += pad; /* Compensate for bigger buffer. */ + memset (buf, ' ', pad); /* Fill in the spaces. */ + buf += pad; /* Don't bother searching them. */ + } + else + { + /* No buffer space for spaces. Must flush. */ + size_t i; + for (i = 0; i < pad; i++) + { +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + putwc_unlocked (L' ', fs->stream); + else +#endif + putc_unlocked (' ', fs->stream); + } + } + fs->point_col = pad; + } + + len = fs->p - buf; + nl = memchr (buf, '\n', len); + + if (fs->point_col < 0) + fs->point_col = 0; + + if (!nl) + { + /* The buffer ends in a partial line. */ + + if (fs->point_col + len < fs->rmargin) + { + /* The remaining buffer text is a partial line and fits + within the maximum line width. Advance point for the + characters to be written and stop scanning. */ + fs->point_col += len; + break; + } + else + /* Set the end-of-line pointer for the code below to + the end of the buffer. */ + nl = fs->p; + } + else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin) + { + /* The buffer contains a full line that fits within the maximum + line width. Reset point and scan the next line. */ + fs->point_col = 0; + buf = nl + 1; + continue; + } + + /* This line is too long. */ + r = fs->rmargin - 1; + + if (fs->wmargin < 0) + { + /* Truncate the line by overwriting the excess with the + newline and anything after it in the buffer. */ + if (nl < fs->p) + { + memmove (buf + (r - fs->point_col), nl, fs->p - nl); + fs->p -= buf + (r - fs->point_col) - nl; + /* Reset point for the next line and start scanning it. */ + fs->point_col = 0; + buf += r + 1; /* Skip full line plus \n. */ + } + else + { + /* The buffer ends with a partial line that is beyond the + maximum line width. Advance point for the characters + written, and discard those past the max from the buffer. */ + fs->point_col += len; + fs->p -= fs->point_col - r; + break; + } + } + else + { + /* Do word wrap. Go to the column just past the maximum line + width and scan back for the beginning of the word there. + Then insert a line break. */ + + char *p, *nextline; + int i; + + p = buf + (r + 1 - fs->point_col); + while (p >= buf && !isblank ((unsigned char) *p)) + --p; + nextline = p + 1; /* This will begin the next line. */ + + if (nextline > buf) + { + /* Swallow separating blanks. */ + if (p >= buf) + do + --p; + while (p >= buf && isblank ((unsigned char) *p)); + nl = p + 1; /* The newline will replace the first blank. */ + } + else + { + /* A single word that is greater than the maximum line width. + Oh well. Put it on an overlong line by itself. */ + p = buf + (r + 1 - fs->point_col); + /* Find the end of the long word. */ + if (p < nl) + do + ++p; + while (p < nl && !isblank ((unsigned char) *p)); + if (p == nl) + { + /* It already ends a line. No fussing required. */ + fs->point_col = 0; + buf = nl + 1; + continue; + } + /* We will move the newline to replace the first blank. */ + nl = p; + /* Swallow separating blanks. */ + do + ++p; + while (isblank ((unsigned char) *p)); + /* The next line will start here. */ + nextline = p; + } + + /* Note: There are a bunch of tests below for + NEXTLINE == BUF + LEN + 1; this case is where NL happens to fall + at the end of the buffer, and NEXTLINE is in fact empty (and so + we need not be careful to maintain its contents). */ + + if ((nextline == buf + len + 1 + ? fs->end - nl < fs->wmargin + 1 + : nextline - (nl + 1) < fs->wmargin) + && fs->p > nextline) + { + /* The margin needs more blanks than we removed. */ + if (fs->end - fs->p > fs->wmargin + 1) + /* Make some space for them. */ + { + size_t mv = fs->p - nextline; + memmove (nl + 1 + fs->wmargin, nextline, mv); + nextline = nl + 1 + fs->wmargin; + len = nextline + mv - buf; + *nl++ = '\n'; + } + else + /* Output the first line so we can use the space. */ + { +#ifdef _LIBC + __fxprintf (fs->stream, "%.*s\n", + (int) (nl - fs->buf), fs->buf); +#else + if (nl > fs->buf) + fwrite_unlocked (fs->buf, 1, nl - fs->buf, fs->stream); + putc_unlocked ('\n', fs->stream); +#endif + + len += buf - fs->buf; + nl = buf = fs->buf; + } + } + else + /* We can fit the newline and blanks in before + the next word. */ + *nl++ = '\n'; + + if (nextline - nl >= fs->wmargin + || (nextline == buf + len + 1 && fs->end - nextline >= fs->wmargin)) + /* Add blanks up to the wrap margin column. */ + for (i = 0; i < fs->wmargin; ++i) + *nl++ = ' '; + else + for (i = 0; i < fs->wmargin; ++i) +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + putwc_unlocked (L' ', fs->stream); + else +#endif + putc_unlocked (' ', fs->stream); + + /* Copy the tail of the original buffer into the current buffer + position. */ + if (nl < nextline) + memmove (nl, nextline, buf + len - nextline); + len -= nextline - buf; + + /* Continue the scan on the remaining lines in the buffer. */ + buf = nl; + + /* Restore bufp to include all the remaining text. */ + fs->p = nl + len; + + /* Reset the counter of what has been output this line. If wmargin + is 0, we want to avoid the lmargin getting added, so we set + point_col to a magic value of -1 in that case. */ + fs->point_col = fs->wmargin ? fs->wmargin : -1; + } + } + + /* Remember that we've scanned as far as the end of the buffer. */ + fs->point_offs = fs->p - fs->buf; +} + +/* Ensure that FS has space for AMOUNT more bytes in its buffer, either by + growing the buffer, or by flushing it. True is returned iff we succeed. */ +int +__argp_fmtstream_ensure (struct argp_fmtstream *fs, size_t amount) +{ + if ((size_t) (fs->end - fs->p) < amount) + { + ssize_t wrote; + + /* Flush FS's buffer. */ + __argp_fmtstream_update (fs); + +#ifdef _LIBC + __fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf); + wrote = fs->p - fs->buf; +#else + wrote = fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream); +#endif + if (wrote == fs->p - fs->buf) + { + fs->p = fs->buf; + fs->point_offs = 0; + } + else + { + fs->p -= wrote; + fs->point_offs -= wrote; + memmove (fs->buf, fs->buf + wrote, fs->p - fs->buf); + return 0; + } + + if ((size_t) (fs->end - fs->buf) < amount) + /* Gotta grow the buffer. */ + { + size_t old_size = fs->end - fs->buf; + size_t new_size = old_size + amount; + char *new_buf; + + if (new_size < old_size || ! (new_buf = realloc (fs->buf, new_size))) + { + __set_errno (ENOMEM); + return 0; + } + + fs->buf = new_buf; + fs->end = new_buf + new_size; + fs->p = fs->buf; + } + } + + return 1; +} + +ssize_t +__argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...) +{ + int out; + size_t avail; + size_t size_guess = PRINTF_SIZE_GUESS; /* How much space to reserve. */ + + do + { + va_list args; + + if (! __argp_fmtstream_ensure (fs, size_guess)) + return -1; + + va_start (args, fmt); + avail = fs->end - fs->p; + out = __vsnprintf (fs->p, avail, fmt, args); + va_end (args); + if ((size_t) out >= avail) + size_guess = out + 1; + } + while ((size_t) out >= avail); + + fs->p += out; + + return out; +} +#if 0 +/* Not exported. */ +#ifdef weak_alias +weak_alias (__argp_fmtstream_printf, argp_fmtstream_printf) +#endif +#endif + +#endif /* !ARGP_FMTSTREAM_USE_LINEWRAP */ diff --git a/gnulib/argp-fmtstream.h b/gnulib/argp-fmtstream.h new file mode 100644 index 000000000..b913d1b25 --- /dev/null +++ b/gnulib/argp-fmtstream.h @@ -0,0 +1,354 @@ +/* Word-wrapping and line-truncating streams. + Copyright (C) 1997, 2006-2010 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +/* This package emulates glibc `line_wrap_stream' semantics for systems that + don't have that. If the system does have it, it is just a wrapper for + that. This header file is only used internally while compiling argp, and + shouldn't be installed. */ + +#ifndef _ARGP_FMTSTREAM_H +#define _ARGP_FMTSTREAM_H + +#include +#include +#include + +#ifndef __attribute__ +/* The __attribute__ feature is available in gcc versions 2.5 and later. + The __-protected variants of the attributes 'format' and 'printf' are + accepted by gcc versions 2.6.4 (effectively 2.7) and later. + We enable __attribute__ only if these are supported too, because + gnulib and libintl do '#define printf __printf__' when they override + the 'printf' function. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __attribute__(Spec) /* empty */ +# endif +#endif + +#if (_LIBC - 0 && !defined (USE_IN_LIBIO)) \ + || (defined (__GNU_LIBRARY__) && defined (HAVE_LINEWRAP_H)) +/* line_wrap_stream is available, so use that. */ +#define ARGP_FMTSTREAM_USE_LINEWRAP +#endif + +#ifdef ARGP_FMTSTREAM_USE_LINEWRAP +/* Just be a simple wrapper for line_wrap_stream; the semantics are + *slightly* different, as line_wrap_stream doesn't actually make a new + object, it just modifies the given stream (reversibly) to do + line-wrapping. Since we control who uses this code, it doesn't matter. */ + +#include + +typedef FILE *argp_fmtstream_t; + +#define argp_make_fmtstream line_wrap_stream +#define __argp_make_fmtstream line_wrap_stream +#define argp_fmtstream_free line_unwrap_stream +#define __argp_fmtstream_free line_unwrap_stream + +#define __argp_fmtstream_putc(fs,ch) putc(ch,fs) +#define argp_fmtstream_putc(fs,ch) putc(ch,fs) +#define __argp_fmtstream_puts(fs,str) fputs(str,fs) +#define argp_fmtstream_puts(fs,str) fputs(str,fs) +#define __argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs) +#define argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs) +#define __argp_fmtstream_printf fprintf +#define argp_fmtstream_printf fprintf + +#define __argp_fmtstream_lmargin line_wrap_lmargin +#define argp_fmtstream_lmargin line_wrap_lmargin +#define __argp_fmtstream_set_lmargin line_wrap_set_lmargin +#define argp_fmtstream_set_lmargin line_wrap_set_lmargin +#define __argp_fmtstream_rmargin line_wrap_rmargin +#define argp_fmtstream_rmargin line_wrap_rmargin +#define __argp_fmtstream_set_rmargin line_wrap_set_rmargin +#define argp_fmtstream_set_rmargin line_wrap_set_rmargin +#define __argp_fmtstream_wmargin line_wrap_wmargin +#define argp_fmtstream_wmargin line_wrap_wmargin +#define __argp_fmtstream_set_wmargin line_wrap_set_wmargin +#define argp_fmtstream_set_wmargin line_wrap_set_wmargin +#define __argp_fmtstream_point line_wrap_point +#define argp_fmtstream_point line_wrap_point + +#else /* !ARGP_FMTSTREAM_USE_LINEWRAP */ +/* Guess we have to define our own version. */ + +struct argp_fmtstream +{ + FILE *stream; /* The stream we're outputting to. */ + + size_t lmargin, rmargin; /* Left and right margins. */ + ssize_t wmargin; /* Margin to wrap to, or -1 to truncate. */ + + /* Point in buffer to which we've processed for wrapping, but not output. */ + size_t point_offs; + /* Output column at POINT_OFFS, or -1 meaning 0 but don't add lmargin. */ + ssize_t point_col; + + char *buf; /* Output buffer. */ + char *p; /* Current end of text in BUF. */ + char *end; /* Absolute end of BUF. */ +}; + +typedef struct argp_fmtstream *argp_fmtstream_t; + +/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines + written on it with LMARGIN spaces and limits them to RMARGIN columns + total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by + replacing the whitespace before them with a newline and WMARGIN spaces. + Otherwise, chars beyond RMARGIN are simply dropped until a newline. + Returns NULL if there was an error. */ +extern argp_fmtstream_t __argp_make_fmtstream (FILE *__stream, + size_t __lmargin, + size_t __rmargin, + ssize_t __wmargin); +extern argp_fmtstream_t argp_make_fmtstream (FILE *__stream, + size_t __lmargin, + size_t __rmargin, + ssize_t __wmargin); + +/* Flush __FS to its stream, and free it (but don't close the stream). */ +extern void __argp_fmtstream_free (argp_fmtstream_t __fs); +extern void argp_fmtstream_free (argp_fmtstream_t __fs); + +extern ssize_t __argp_fmtstream_printf (argp_fmtstream_t __fs, + const char *__fmt, ...) + __attribute__ ((__format__ (printf, 2, 3))); +extern ssize_t argp_fmtstream_printf (argp_fmtstream_t __fs, + const char *__fmt, ...) + __attribute__ ((__format__ (printf, 2, 3))); + +#if _LIBC || !defined __OPTIMIZE__ +extern int __argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch); +extern int argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch); + +extern int __argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str); +extern int argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str); + +extern size_t __argp_fmtstream_write (argp_fmtstream_t __fs, + const char *__str, size_t __len); +extern size_t argp_fmtstream_write (argp_fmtstream_t __fs, + const char *__str, size_t __len); +#endif + +/* Access macros for various bits of state. */ +#define argp_fmtstream_lmargin(__fs) ((__fs)->lmargin) +#define argp_fmtstream_rmargin(__fs) ((__fs)->rmargin) +#define argp_fmtstream_wmargin(__fs) ((__fs)->wmargin) +#define __argp_fmtstream_lmargin argp_fmtstream_lmargin +#define __argp_fmtstream_rmargin argp_fmtstream_rmargin +#define __argp_fmtstream_wmargin argp_fmtstream_wmargin + +#if _LIBC || !defined __OPTIMIZE__ +/* Set __FS's left margin to LMARGIN and return the old value. */ +extern size_t argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, + size_t __lmargin); +extern size_t __argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, + size_t __lmargin); + +/* Set __FS's right margin to __RMARGIN and return the old value. */ +extern size_t argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, + size_t __rmargin); +extern size_t __argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, + size_t __rmargin); + +/* Set __FS's wrap margin to __WMARGIN and return the old value. */ +extern size_t argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, + size_t __wmargin); +extern size_t __argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, + size_t __wmargin); + +/* Return the column number of the current output point in __FS. */ +extern size_t argp_fmtstream_point (argp_fmtstream_t __fs); +extern size_t __argp_fmtstream_point (argp_fmtstream_t __fs); +#endif + +/* Internal routines. */ +extern void _argp_fmtstream_update (argp_fmtstream_t __fs); +extern void __argp_fmtstream_update (argp_fmtstream_t __fs); +extern int _argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount); +extern int __argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount); + +#ifdef __OPTIMIZE__ +/* Inline versions of above routines. */ + +#if !_LIBC +#define __argp_fmtstream_putc argp_fmtstream_putc +#define __argp_fmtstream_puts argp_fmtstream_puts +#define __argp_fmtstream_write argp_fmtstream_write +#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin +#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin +#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin +#define __argp_fmtstream_point argp_fmtstream_point +#define __argp_fmtstream_update _argp_fmtstream_update +#define __argp_fmtstream_ensure _argp_fmtstream_ensure +#endif + +#ifndef ARGP_FS_EI +# ifdef __GNUC__ + /* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99 + inline semantics, unless -fgnu89-inline is used. It defines a macro + __GNUC_STDC_INLINE__ to indicate this situation or a macro + __GNUC_GNU_INLINE__ to indicate the opposite situation. + + GCC 4.2 with -std=c99 or -std=gnu99 implements the GNU C inline + semantics but warns, unless -fgnu89-inline is used: + warning: C99 inline functions are not supported; using GNU89 + warning: to disable this warning use -fgnu89-inline or the gnu_inline function attribute + It defines a macro __GNUC_GNU_INLINE__ to indicate this situation. + + Whereas Apple GCC 4.0.1 build 5479 without -std=c99 or -std=gnu99 + implements the GNU C inline semantics and defines the macro + __GNUC_GNU_INLINE__, but it does not warn and does not support + __attribute__ ((__gnu_inline__)). + + All in all, these are the possible combinations. For every compiler, + we need to choose ARGP_FS_EI so that the corresponding table cell + contains an "ok". + + \ ARGP_FS_EI inline extern extern + \ inline inline + CC \ __attribute__ + ((gnu_inline)) + + gcc 4.3.0 error ok ok + gcc 4.3.0 -std=gnu99 -fgnu89-inline error ok ok + gcc 4.3.0 -std=gnu99 ok error ok + + gcc 4.2.2 error ok ok + gcc 4.2.2 -std=gnu99 -fgnu89-inline error ok ok + gcc 4.2.2 -std=gnu99 error warning ok + + gcc 4.1.2 error ok warning + gcc 4.1.2 -std=gnu99 error ok warning + + Apple gcc 4.0.1 error ok warning + Apple gcc 4.0.1 -std=gnu99 ok error warning + */ +# if defined __GNUC_STDC_INLINE__ +# define ARGP_FS_EI inline +# elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) +# define ARGP_FS_EI extern inline __attribute__ ((__gnu_inline__)) +# else +# define ARGP_FS_EI extern inline +# endif +# else + /* With other compilers, assume the ISO C99 meaning of 'inline', if + the compiler supports 'inline' at all. */ +# define ARGP_FS_EI inline +# endif +#endif + +ARGP_FS_EI size_t +__argp_fmtstream_write (argp_fmtstream_t __fs, + const char *__str, size_t __len) +{ + if (__fs->p + __len <= __fs->end || __argp_fmtstream_ensure (__fs, __len)) + { + memcpy (__fs->p, __str, __len); + __fs->p += __len; + return __len; + } + else + return 0; +} + +ARGP_FS_EI int +__argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str) +{ + size_t __len = strlen (__str); + if (__len) + { + size_t __wrote = __argp_fmtstream_write (__fs, __str, __len); + return __wrote == __len ? 0 : -1; + } + else + return 0; +} + +ARGP_FS_EI int +__argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch) +{ + if (__fs->p < __fs->end || __argp_fmtstream_ensure (__fs, 1)) + return *__fs->p++ = __ch; + else + return EOF; +} + +/* Set __FS's left margin to __LMARGIN and return the old value. */ +ARGP_FS_EI size_t +__argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, size_t __lmargin) +{ + size_t __old; + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + __old = __fs->lmargin; + __fs->lmargin = __lmargin; + return __old; +} + +/* Set __FS's right margin to __RMARGIN and return the old value. */ +ARGP_FS_EI size_t +__argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, size_t __rmargin) +{ + size_t __old; + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + __old = __fs->rmargin; + __fs->rmargin = __rmargin; + return __old; +} + +/* Set FS's wrap margin to __WMARGIN and return the old value. */ +ARGP_FS_EI size_t +__argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin) +{ + size_t __old; + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + __old = __fs->wmargin; + __fs->wmargin = __wmargin; + return __old; +} + +/* Return the column number of the current output point in __FS. */ +ARGP_FS_EI size_t +__argp_fmtstream_point (argp_fmtstream_t __fs) +{ + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + return __fs->point_col >= 0 ? __fs->point_col : 0; +} + +#if !_LIBC +#undef __argp_fmtstream_putc +#undef __argp_fmtstream_puts +#undef __argp_fmtstream_write +#undef __argp_fmtstream_set_lmargin +#undef __argp_fmtstream_set_rmargin +#undef __argp_fmtstream_set_wmargin +#undef __argp_fmtstream_point +#undef __argp_fmtstream_update +#undef __argp_fmtstream_ensure +#endif + +#endif /* __OPTIMIZE__ */ + +#endif /* ARGP_FMTSTREAM_USE_LINEWRAP */ + +#endif /* argp-fmtstream.h */ diff --git a/gnulib/argp-fs-xinl.c b/gnulib/argp-fs-xinl.c new file mode 100644 index 000000000..2c683f914 --- /dev/null +++ b/gnulib/argp-fs-xinl.c @@ -0,0 +1,42 @@ +/* Real definitions for extern inline functions in argp-fmtstream.h + Copyright (C) 1997, 2003, 2004, 2009, 2010 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#define ARGP_FS_EI +#undef __OPTIMIZE__ +#define __OPTIMIZE__ 1 +#include "argp-fmtstream.h" + +#if 0 +/* Not exported. */ +/* Add weak aliases. */ +#if _LIBC - 0 && !defined (ARGP_FMTSTREAM_USE_LINEWRAP) && defined (weak_alias) + +weak_alias (__argp_fmtstream_putc, argp_fmtstream_putc) +weak_alias (__argp_fmtstream_puts, argp_fmtstream_puts) +weak_alias (__argp_fmtstream_write, argp_fmtstream_write) +weak_alias (__argp_fmtstream_set_lmargin, argp_fmtstream_set_lmargin) +weak_alias (__argp_fmtstream_set_rmargin, argp_fmtstream_set_rmargin) +weak_alias (__argp_fmtstream_set_wmargin, argp_fmtstream_set_wmargin) +weak_alias (__argp_fmtstream_point, argp_fmtstream_point) + +#endif +#endif diff --git a/gnulib/argp-help.c b/gnulib/argp-help.c new file mode 100644 index 000000000..5b6d950be --- /dev/null +++ b/gnulib/argp-help.c @@ -0,0 +1,1951 @@ +/* Hierarchial argument parsing help output + Copyright (C) 1995-2005, 2007, 2009-2010 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef USE_IN_LIBIO +# include +#endif + +#ifdef _LIBC +# include +# undef dgettext +# define dgettext(domain, msgid) \ + INTUSE(__dcgettext) (domain, msgid, LC_MESSAGES) +#else +# include "gettext.h" +#endif + +#include "argp.h" +#include "argp-fmtstream.h" +#include "argp-namefrob.h" + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +/* User-selectable (using an environment variable) formatting parameters. + + These may be specified in an environment variable called `ARGP_HELP_FMT', + with a contents like: VAR1=VAL1,VAR2=VAL2,BOOLVAR2,no-BOOLVAR2 + Where VALn must be a positive integer. The list of variables is in the + UPARAM_NAMES vector, below. */ + +/* Default parameters. */ +#define DUP_ARGS 0 /* True if option argument can be duplicated. */ +#define DUP_ARGS_NOTE 1 /* True to print a note about duplicate args. */ +#define SHORT_OPT_COL 2 /* column in which short options start */ +#define LONG_OPT_COL 6 /* column in which long options start */ +#define DOC_OPT_COL 2 /* column in which doc options start */ +#define OPT_DOC_COL 29 /* column in which option text starts */ +#define HEADER_COL 1 /* column in which group headers are printed */ +#define USAGE_INDENT 12 /* indentation of wrapped usage lines */ +#define RMARGIN 79 /* right margin used for wrapping */ + +/* User-selectable (using an environment variable) formatting parameters. + They must all be of type `int' for the parsing code to work. */ +struct uparams +{ + /* If true, arguments for an option are shown with both short and long + options, even when a given option has both, e.g. `-x ARG, --longx=ARG'. + If false, then if an option has both, the argument is only shown with + the long one, e.g., `-x, --longx=ARG', and a message indicating that + this really means both is printed below the options. */ + int dup_args; + + /* This is true if when DUP_ARGS is false, and some duplicate arguments have + been suppressed, an explanatory message should be printed. */ + int dup_args_note; + + /* Various output columns. */ + int short_opt_col; /* column in which short options start */ + int long_opt_col; /* column in which long options start */ + int doc_opt_col; /* column in which doc options start */ + int opt_doc_col; /* column in which option text starts */ + int header_col; /* column in which group headers are printed */ + int usage_indent; /* indentation of wrapped usage lines */ + int rmargin; /* right margin used for wrapping */ + + int valid; /* True when the values in here are valid. */ +}; + +/* This is a global variable, as user options are only ever read once. */ +static struct uparams uparams = { + DUP_ARGS, DUP_ARGS_NOTE, + SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL, + USAGE_INDENT, RMARGIN, + 0 +}; + +/* A particular uparam, and what the user name is. */ +struct uparam_name +{ + const char *name; /* User name. */ + int is_bool; /* Whether it's `boolean'. */ + size_t uparams_offs; /* Location of the (int) field in UPARAMS. */ +}; + +/* The name-field mappings we know about. */ +static const struct uparam_name uparam_names[] = +{ + { "dup-args", 1, offsetof (struct uparams, dup_args) }, + { "dup-args-note", 1, offsetof (struct uparams, dup_args_note) }, + { "short-opt-col", 0, offsetof (struct uparams, short_opt_col) }, + { "long-opt-col", 0, offsetof (struct uparams, long_opt_col) }, + { "doc-opt-col", 0, offsetof (struct uparams, doc_opt_col) }, + { "opt-doc-col", 0, offsetof (struct uparams, opt_doc_col) }, + { "header-col", 0, offsetof (struct uparams, header_col) }, + { "usage-indent", 0, offsetof (struct uparams, usage_indent) }, + { "rmargin", 0, offsetof (struct uparams, rmargin) }, + { 0 } +}; + +static void +validate_uparams (const struct argp_state *state, struct uparams *upptr) +{ + const struct uparam_name *up; + + for (up = uparam_names; up->name; up++) + { + if (up->is_bool + || up->uparams_offs == offsetof (struct uparams, rmargin)) + continue; + if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin) + { + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "\ +ARGP_HELP_FMT: %s value is less than or equal to %s"), + "rmargin", up->name); + return; + } + } + uparams = *upptr; + uparams.valid = 1; +} + +/* Read user options from the environment, and fill in UPARAMS appropiately. */ +static void +fill_in_uparams (const struct argp_state *state) +{ + const char *var = getenv ("ARGP_HELP_FMT"); + struct uparams new_params = uparams; + +#define SKIPWS(p) do { while (isspace ((unsigned char) *p)) p++; } while (0); + + if (var) + { + /* Parse var. */ + while (*var) + { + SKIPWS (var); + + if (isalpha ((unsigned char) *var)) + { + size_t var_len; + const struct uparam_name *un; + int unspec = 0, val = 0; + const char *arg = var; + + while (isalnum ((unsigned char) *arg) || *arg == '-' || *arg == '_') + arg++; + var_len = arg - var; + + SKIPWS (arg); + + if (*arg == '\0' || *arg == ',') + unspec = 1; + else if (*arg == '=') + { + arg++; + SKIPWS (arg); + } + + if (unspec) + { + if (var[0] == 'n' && var[1] == 'o' && var[2] == '-') + { + val = 0; + var += 3; + var_len -= 3; + } + else + val = 1; + } + else if (isdigit ((unsigned char) *arg)) + { + val = atoi (arg); + while (isdigit ((unsigned char) *arg)) + arg++; + SKIPWS (arg); + } + + for (un = uparam_names; un->name; un++) + if (strlen (un->name) == var_len + && strncmp (var, un->name, var_len) == 0) + { + if (unspec && !un->is_bool) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "\ +%.*s: ARGP_HELP_FMT parameter requires a value"), + (int) var_len, var); + else if (val < 0) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "\ +%.*s: ARGP_HELP_FMT parameter must be positive"), + (int) var_len, var); + else + *(int *)((char *)&new_params + un->uparams_offs) = val; + break; + } + if (! un->name) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, "\ +%.*s: Unknown ARGP_HELP_FMT parameter"), + (int) var_len, var); + + var = arg; + if (*var == ',') + var++; + } + else if (*var) + { + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "Garbage in ARGP_HELP_FMT: %s"), var); + break; + } + } + validate_uparams (state, &new_params); + } +} + +/* Returns true if OPT hasn't been marked invisible. Visibility only affects + whether OPT is displayed or used in sorting, not option shadowing. */ +#define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN)) + +/* Returns true if OPT is an alias for an earlier option. */ +#define oalias(opt) ((opt)->flags & OPTION_ALIAS) + +/* Returns true if OPT is an documentation-only entry. */ +#define odoc(opt) ((opt)->flags & OPTION_DOC) + +/* Returns true if OPT should not be translated */ +#define onotrans(opt) ((opt)->flags & OPTION_NO_TRANS) + +/* Returns true if OPT is the end-of-list marker for a list of options. */ +#define oend(opt) __option_is_end (opt) + +/* Returns true if OPT has a short option. */ +#define oshort(opt) __option_is_short (opt) + +/* + The help format for a particular option is like: + + -xARG, -yARG, --long1=ARG, --long2=ARG Documentation... + + Where ARG will be omitted if there's no argument, for this option, or + will be surrounded by "[" and "]" appropiately if the argument is + optional. The documentation string is word-wrapped appropiately, and if + the list of options is long enough, it will be started on a separate line. + If there are no short options for a given option, the first long option is + indented slighly in a way that's supposed to make most long options appear + to be in a separate column. + + For example, the following output (from ps): + + -p PID, --pid=PID List the process PID + --pgrp=PGRP List processes in the process group PGRP + -P, -x, --no-parent Include processes without parents + -Q, --all-fields Don't elide unusable fields (normally if there's + some reason ps can't print a field for any + process, it's removed from the output entirely) + -r, --reverse, --gratuitously-long-reverse-option + Reverse the order of any sort + --session[=SID] Add the processes from the session SID (which + defaults to the sid of the current process) + + Here are some more options: + -f ZOT, --foonly=ZOT Glork a foonly + -z, --zaza Snit a zar + + -?, --help Give this help list + --usage Give a short usage message + -V, --version Print program version + + The struct argp_option array for the above could look like: + + { + {"pid", 'p', "PID", 0, "List the process PID"}, + {"pgrp", OPT_PGRP, "PGRP", 0, "List processes in the process group PGRP"}, + {"no-parent", 'P', 0, 0, "Include processes without parents"}, + {0, 'x', 0, OPTION_ALIAS}, + {"all-fields",'Q', 0, 0, "Don't elide unusable fields (normally" + " if there's some reason ps can't" + " print a field for any process, it's" + " removed from the output entirely)" }, + {"reverse", 'r', 0, 0, "Reverse the order of any sort"}, + {"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS}, + {"session", OPT_SESS, "SID", OPTION_ARG_OPTIONAL, + "Add the processes from the session" + " SID (which defaults to the sid of" + " the current process)" }, + + {0,0,0,0, "Here are some more options:"}, + {"foonly", 'f', "ZOT", 0, "Glork a foonly"}, + {"zaza", 'z', 0, 0, "Snit a zar"}, + + {0} + } + + Note that the last three options are automatically supplied by argp_parse, + unless you tell it not to with ARGP_NO_HELP. + +*/ + +/* Returns true if CH occurs between BEG and END. */ +static int +find_char (char ch, char *beg, char *end) +{ + while (beg < end) + if (*beg == ch) + return 1; + else + beg++; + return 0; +} + +struct hol_cluster; /* fwd decl */ + +struct hol_entry +{ + /* First option. */ + const struct argp_option *opt; + /* Number of options (including aliases). */ + unsigned num; + + /* A pointers into the HOL's short_options field, to the first short option + letter for this entry. The order of the characters following this point + corresponds to the order of options pointed to by OPT, and there are at + most NUM. A short option recorded in a option following OPT is only + valid if it occurs in the right place in SHORT_OPTIONS (otherwise it's + probably been shadowed by some other entry). */ + char *short_options; + + /* Entries are sorted by their group first, in the order: + 1, 2, ..., n, 0, -m, ..., -2, -1 + and then alphabetically within each group. The default is 0. */ + int group; + + /* The cluster of options this entry belongs to, or 0 if none. */ + struct hol_cluster *cluster; + + /* The argp from which this option came. */ + const struct argp *argp; + + /* Position in the array */ + unsigned ord; +}; + +/* A cluster of entries to reflect the argp tree structure. */ +struct hol_cluster +{ + /* A descriptive header printed before options in this cluster. */ + const char *header; + + /* Used to order clusters within the same group with the same parent, + according to the order in which they occurred in the parent argp's child + list. */ + int index; + + /* How to sort this cluster with respect to options and other clusters at the + same depth (clusters always follow options in the same group). */ + int group; + + /* The cluster to which this cluster belongs, or 0 if it's at the base + level. */ + struct hol_cluster *parent; + + /* The argp from which this cluster is (eventually) derived. */ + const struct argp *argp; + + /* The distance this cluster is from the root. */ + int depth; + + /* Clusters in a given hol are kept in a linked list, to make freeing them + possible. */ + struct hol_cluster *next; +}; + +/* A list of options for help. */ +struct hol +{ + /* An array of hol_entry's. */ + struct hol_entry *entries; + /* The number of entries in this hol. If this field is zero, the others + are undefined. */ + unsigned num_entries; + + /* A string containing all short options in this HOL. Each entry contains + pointers into this string, so the order can't be messed with blindly. */ + char *short_options; + + /* Clusters of entries in this hol. */ + struct hol_cluster *clusters; +}; + +/* Create a struct hol from the options in ARGP. CLUSTER is the + hol_cluster in which these entries occur, or 0, if at the root. */ +static struct hol * +make_hol (const struct argp *argp, struct hol_cluster *cluster) +{ + char *so; + const struct argp_option *o; + const struct argp_option *opts = argp->options; + struct hol_entry *entry; + unsigned num_short_options = 0; + struct hol *hol = malloc (sizeof (struct hol)); + + assert (hol); + + hol->num_entries = 0; + hol->clusters = 0; + + if (opts) + { + int cur_group = 0; + + /* The first option must not be an alias. */ + assert (! oalias (opts)); + + /* Calculate the space needed. */ + for (o = opts; ! oend (o); o++) + { + if (! oalias (o)) + hol->num_entries++; + if (oshort (o)) + num_short_options++; /* This is an upper bound. */ + } + + hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries); + hol->short_options = malloc (num_short_options + 1); + + assert (hol->entries && hol->short_options); + if (SIZE_MAX <= UINT_MAX) + assert (hol->num_entries <= SIZE_MAX / sizeof (struct hol_entry)); + + /* Fill in the entries. */ + so = hol->short_options; + for (o = opts, entry = hol->entries; ! oend (o); entry++) + { + entry->opt = o; + entry->num = 0; + entry->short_options = so; + entry->group = cur_group = + o->group + ? o->group + : ((!o->name && !o->key) + ? cur_group + 1 + : cur_group); + entry->cluster = cluster; + entry->argp = argp; + + do + { + entry->num++; + if (oshort (o) && ! find_char (o->key, hol->short_options, so)) + /* O has a valid short option which hasn't already been used.*/ + *so++ = o->key; + o++; + } + while (! oend (o) && oalias (o)); + } + *so = '\0'; /* null terminated so we can find the length */ + } + + return hol; +} + +/* Add a new cluster to HOL, with the given GROUP and HEADER (taken from the + associated argp child list entry), INDEX, and PARENT, and return a pointer + to it. ARGP is the argp that this cluster results from. */ +static struct hol_cluster * +hol_add_cluster (struct hol *hol, int group, const char *header, int index, + struct hol_cluster *parent, const struct argp *argp) +{ + struct hol_cluster *cl = malloc (sizeof (struct hol_cluster)); + if (cl) + { + cl->group = group; + cl->header = header; + + cl->index = index; + cl->parent = parent; + cl->argp = argp; + cl->depth = parent ? parent->depth + 1 : 0; + + cl->next = hol->clusters; + hol->clusters = cl; + } + return cl; +} + +/* Free HOL and any resources it uses. */ +static void +hol_free (struct hol *hol) +{ + struct hol_cluster *cl = hol->clusters; + + while (cl) + { + struct hol_cluster *next = cl->next; + free (cl); + cl = next; + } + + if (hol->num_entries > 0) + { + free (hol->entries); + free (hol->short_options); + } + + free (hol); +} + +static int +hol_entry_short_iterate (const struct hol_entry *entry, + int (*func)(const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie), + const char *domain, void *cookie) +{ + unsigned nopts; + int val = 0; + const struct argp_option *opt, *real = entry->opt; + char *so = entry->short_options; + + for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--) + if (oshort (opt) && *so == opt->key) + { + if (!oalias (opt)) + real = opt; + if (ovisible (opt)) + val = (*func)(opt, real, domain, cookie); + so++; + } + + return val; +} + +static inline int +__attribute__ ((always_inline)) +hol_entry_long_iterate (const struct hol_entry *entry, + int (*func)(const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie), + const char *domain, void *cookie) +{ + unsigned nopts; + int val = 0; + const struct argp_option *opt, *real = entry->opt; + + for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--) + if (opt->name) + { + if (!oalias (opt)) + real = opt; + if (ovisible (opt)) + val = (*func)(opt, real, domain, cookie); + } + + return val; +} + +/* Iterator that returns true for the first short option. */ +static int +until_short (const struct argp_option *opt, const struct argp_option *real, + const char *domain, void *cookie) +{ + return oshort (opt) ? opt->key : 0; +} + +/* Returns the first valid short option in ENTRY, or 0 if there is none. */ +static char +hol_entry_first_short (const struct hol_entry *entry) +{ + return hol_entry_short_iterate (entry, until_short, + entry->argp->argp_domain, 0); +} + +/* Returns the first valid long option in ENTRY, or 0 if there is none. */ +static const char * +hol_entry_first_long (const struct hol_entry *entry) +{ + const struct argp_option *opt; + unsigned num; + for (opt = entry->opt, num = entry->num; num > 0; opt++, num--) + if (opt->name && ovisible (opt)) + return opt->name; + return 0; +} + +/* Returns the entry in HOL with the long option name NAME, or 0 if there is + none. */ +static struct hol_entry * +hol_find_entry (struct hol *hol, const char *name) +{ + struct hol_entry *entry = hol->entries; + unsigned num_entries = hol->num_entries; + + while (num_entries-- > 0) + { + const struct argp_option *opt = entry->opt; + unsigned num_opts = entry->num; + + while (num_opts-- > 0) + if (opt->name && ovisible (opt) && strcmp (opt->name, name) == 0) + return entry; + else + opt++; + + entry++; + } + + return 0; +} + +/* If an entry with the long option NAME occurs in HOL, set it's special + sort position to GROUP. */ +static void +hol_set_group (struct hol *hol, const char *name, int group) +{ + struct hol_entry *entry = hol_find_entry (hol, name); + if (entry) + entry->group = group; +} + +/* Order by group: 0, 1, 2, ..., n, -m, ..., -2, -1. + EQ is what to return if GROUP1 and GROUP2 are the same. */ +static int +group_cmp (int group1, int group2, int eq) +{ + if (group1 == group2) + return eq; + else if ((group1 < 0 && group2 < 0) || (group1 >= 0 && group2 >= 0)) + return group1 - group2; + else + return group2 - group1; +} + +/* Compare clusters CL1 & CL2 by the order that they should appear in + output. */ +static int +hol_cluster_cmp (const struct hol_cluster *cl1, const struct hol_cluster *cl2) +{ + /* If one cluster is deeper than the other, use its ancestor at the same + level, so that finding the common ancestor is straightforward. + + clN->depth > 0 means that clN->parent != NULL (see hol_add_cluster) */ + while (cl1->depth > cl2->depth) + cl1 = cl1->parent; + while (cl2->depth > cl1->depth) + cl2 = cl2->parent; + + /* Now reduce both clusters to their ancestors at the point where both have + a common parent; these can be directly compared. */ + while (cl1->parent != cl2->parent) + cl1 = cl1->parent, cl2 = cl2->parent; + + return group_cmp (cl1->group, cl2->group, cl2->index - cl1->index); +} + +/* Return the ancestor of CL that's just below the root (i.e., has a parent + of 0). */ +static struct hol_cluster * +hol_cluster_base (struct hol_cluster *cl) +{ + while (cl->parent) + cl = cl->parent; + return cl; +} + +/* Return true if CL1 is a child of CL2. */ +static int +hol_cluster_is_child (const struct hol_cluster *cl1, + const struct hol_cluster *cl2) +{ + while (cl1 && cl1 != cl2) + cl1 = cl1->parent; + return cl1 == cl2; +} + +/* Given the name of a OPTION_DOC option, modifies NAME to start at the tail + that should be used for comparisons, and returns true iff it should be + treated as a non-option. */ +static int +canon_doc_option (const char **name) +{ + int non_opt; + + if (!*name) + non_opt = 1; + else + { + /* Skip initial whitespace. */ + while (isspace ((unsigned char) **name)) + (*name)++; + /* Decide whether this looks like an option (leading `-') or not. */ + non_opt = (**name != '-'); + /* Skip until part of name used for sorting. */ + while (**name && !isalnum ((unsigned char) **name)) + (*name)++; + } + return non_opt; +} + +#define HOL_ENTRY_PTRCMP(a,b) ((a)->ord < (b)->ord ? -1 : 1) + +/* Order ENTRY1 & ENTRY2 by the order which they should appear in a help + listing. */ +static int +hol_entry_cmp (const struct hol_entry *entry1, + const struct hol_entry *entry2) +{ + /* The group numbers by which the entries should be ordered; if either is + in a cluster, then this is just the group within the cluster. */ + int group1 = entry1->group, group2 = entry2->group; + int rc; + + if (entry1->cluster != entry2->cluster) + { + /* The entries are not within the same cluster, so we can't compare them + directly, we have to use the appropiate clustering level too. */ + if (! entry1->cluster) + /* ENTRY1 is at the `base level', not in a cluster, so we have to + compare it's group number with that of the base cluster in which + ENTRY2 resides. Note that if they're in the same group, the + clustered option always comes laster. */ + return group_cmp (group1, hol_cluster_base (entry2->cluster)->group, -1); + else if (! entry2->cluster) + /* Likewise, but ENTRY2's not in a cluster. */ + return group_cmp (hol_cluster_base (entry1->cluster)->group, group2, 1); + else + /* Both entries are in clusters, we can just compare the clusters. */ + return (rc = hol_cluster_cmp (entry1->cluster, entry2->cluster)) ? + rc : HOL_ENTRY_PTRCMP (entry1, entry2); + } + else if (group1 == group2) + /* The entries are both in the same cluster and group, so compare them + alphabetically. */ + { + int short1 = hol_entry_first_short (entry1); + int short2 = hol_entry_first_short (entry2); + int doc1 = odoc (entry1->opt); + int doc2 = odoc (entry2->opt); + const char *long1 = hol_entry_first_long (entry1); + const char *long2 = hol_entry_first_long (entry2); + + if (doc1) + doc1 = canon_doc_option (&long1); + if (doc2) + doc2 = canon_doc_option (&long2); + + if (doc1 != doc2) + /* `documentation' options always follow normal options (or + documentation options that *look* like normal options). */ + return doc1 - doc2; + else if (!short1 && !short2 && long1 && long2) + /* Only long options. */ + return (rc = __strcasecmp (long1, long2)) ? + rc : HOL_ENTRY_PTRCMP (entry1, entry2); + else + /* Compare short/short, long/short, short/long, using the first + character of long options. Entries without *any* valid + options (such as options with OPTION_HIDDEN set) will be put + first, but as they're not displayed, it doesn't matter where + they are. */ + { + unsigned char first1 = short1 ? short1 : long1 ? *long1 : 0; + unsigned char first2 = short2 ? short2 : long2 ? *long2 : 0; + /* Use tolower, not _tolower, since only the former is + guaranteed to work on something already lower case. */ + int lower_cmp = tolower (first1) - tolower (first2); + /* Compare ignoring case, except when the options are both the + same letter, in which case lower-case always comes first. */ + return lower_cmp ? lower_cmp : + (rc = first2 - first1) ? + rc : HOL_ENTRY_PTRCMP (entry1, entry2); + } + } + else + /* Within the same cluster, but not the same group, so just compare + groups. */ + return group_cmp (group1, group2, HOL_ENTRY_PTRCMP (entry1, entry2)); +} + +/* Version of hol_entry_cmp with correct signature for qsort. */ +static int +hol_entry_qcmp (const void *entry1_v, const void *entry2_v) +{ + return hol_entry_cmp (entry1_v, entry2_v); +} + +/* Sort HOL by group and alphabetically by option name (with short options + taking precedence over long). Since the sorting is for display purposes + only, the shadowing of options isn't effected. */ +static void +hol_sort (struct hol *hol) +{ + if (hol->num_entries > 0) + { + unsigned i; + struct hol_entry *e; + for (i = 0, e = hol->entries; i < hol->num_entries; i++, e++) + e->ord = i; + qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry), + hol_entry_qcmp); + } +} + +/* Append MORE to HOL, destroying MORE in the process. Options in HOL shadow + any in MORE with the same name. */ +static void +hol_append (struct hol *hol, struct hol *more) +{ + struct hol_cluster **cl_end = &hol->clusters; + + /* Steal MORE's cluster list, and add it to the end of HOL's. */ + while (*cl_end) + cl_end = &(*cl_end)->next; + *cl_end = more->clusters; + more->clusters = 0; + + /* Merge entries. */ + if (more->num_entries > 0) + { + if (hol->num_entries == 0) + { + hol->num_entries = more->num_entries; + hol->entries = more->entries; + hol->short_options = more->short_options; + more->num_entries = 0; /* Mark MORE's fields as invalid. */ + } + else + /* Append the entries in MORE to those in HOL, taking care to only add + non-shadowed SHORT_OPTIONS values. */ + { + unsigned left; + char *so, *more_so; + struct hol_entry *e; + unsigned num_entries = hol->num_entries + more->num_entries; + struct hol_entry *entries = + malloc (num_entries * sizeof (struct hol_entry)); + unsigned hol_so_len = strlen (hol->short_options); + char *short_options = + malloc (hol_so_len + strlen (more->short_options) + 1); + + assert (entries && short_options); + if (SIZE_MAX <= UINT_MAX) + assert (num_entries <= SIZE_MAX / sizeof (struct hol_entry)); + + __mempcpy (__mempcpy (entries, hol->entries, + hol->num_entries * sizeof (struct hol_entry)), + more->entries, + more->num_entries * sizeof (struct hol_entry)); + + __mempcpy (short_options, hol->short_options, hol_so_len); + + /* Fix up the short options pointers from HOL. */ + for (e = entries, left = hol->num_entries; left > 0; e++, left--) + e->short_options += (short_options - hol->short_options); + + /* Now add the short options from MORE, fixing up its entries + too. */ + so = short_options + hol_so_len; + more_so = more->short_options; + for (left = more->num_entries; left > 0; e++, left--) + { + int opts_left; + const struct argp_option *opt; + + e->short_options = so; + + for (opts_left = e->num, opt = e->opt; opts_left; opt++, opts_left--) + { + int ch = *more_so; + if (oshort (opt) && ch == opt->key) + /* The next short option in MORE_SO, CH, is from OPT. */ + { + if (! find_char (ch, short_options, + short_options + hol_so_len)) + /* The short option CH isn't shadowed by HOL's options, + so add it to the sum. */ + *so++ = ch; + more_so++; + } + } + } + + *so = '\0'; + + free (hol->entries); + free (hol->short_options); + + hol->entries = entries; + hol->num_entries = num_entries; + hol->short_options = short_options; + } + } + + hol_free (more); +} + +/* Inserts enough spaces to make sure STREAM is at column COL. */ +static void +indent_to (argp_fmtstream_t stream, unsigned col) +{ + int needed = col - __argp_fmtstream_point (stream); + while (needed-- > 0) + __argp_fmtstream_putc (stream, ' '); +} + +/* Output to STREAM either a space, or a newline if there isn't room for at + least ENSURE characters before the right margin. */ +static void +space (argp_fmtstream_t stream, size_t ensure) +{ + if (__argp_fmtstream_point (stream) + ensure + >= __argp_fmtstream_rmargin (stream)) + __argp_fmtstream_putc (stream, '\n'); + else + __argp_fmtstream_putc (stream, ' '); +} + +/* If the option REAL has an argument, we print it in using the printf + format REQ_FMT or OPT_FMT depending on whether it's a required or + optional argument. */ +static void +arg (const struct argp_option *real, const char *req_fmt, const char *opt_fmt, + const char *domain, argp_fmtstream_t stream) +{ + if (real->arg) + { + if (real->flags & OPTION_ARG_OPTIONAL) + __argp_fmtstream_printf (stream, opt_fmt, + dgettext (domain, real->arg)); + else + __argp_fmtstream_printf (stream, req_fmt, + dgettext (domain, real->arg)); + } +} + +/* Helper functions for hol_entry_help. */ + +/* State used during the execution of hol_help. */ +struct hol_help_state +{ + /* PREV_ENTRY should contain the previous entry printed, or 0. */ + struct hol_entry *prev_entry; + + /* If an entry is in a different group from the previous one, and SEP_GROUPS + is true, then a blank line will be printed before any output. */ + int sep_groups; + + /* True if a duplicate option argument was suppressed (only ever set if + UPARAMS.dup_args is false). */ + int suppressed_dup_arg; +}; + +/* Some state used while printing a help entry (used to communicate with + helper functions). See the doc for hol_entry_help for more info, as most + of the fields are copied from its arguments. */ +struct pentry_state +{ + const struct hol_entry *entry; + argp_fmtstream_t stream; + struct hol_help_state *hhstate; + + /* True if nothing's been printed so far. */ + int first; + + /* If non-zero, the state that was used to print this help. */ + const struct argp_state *state; +}; + +/* If a user doc filter should be applied to DOC, do so. */ +static const char * +filter_doc (const char *doc, int key, const struct argp *argp, + const struct argp_state *state) +{ + if (argp->help_filter) + /* We must apply a user filter to this output. */ + { + void *input = __argp_input (argp, state); + return (*argp->help_filter) (key, doc, input); + } + else + /* No filter. */ + return doc; +} + +/* Prints STR as a header line, with the margin lines set appropiately, and + notes the fact that groups should be separated with a blank line. ARGP is + the argp that should dictate any user doc filtering to take place. Note + that the previous wrap margin isn't restored, but the left margin is reset + to 0. */ +static void +print_header (const char *str, const struct argp *argp, + struct pentry_state *pest) +{ + const char *tstr = dgettext (argp->argp_domain, str); + const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_HEADER, argp, pest->state); + + if (fstr) + { + if (*fstr) + { + if (pest->hhstate->prev_entry) + /* Precede with a blank line. */ + __argp_fmtstream_putc (pest->stream, '\n'); + indent_to (pest->stream, uparams.header_col); + __argp_fmtstream_set_lmargin (pest->stream, uparams.header_col); + __argp_fmtstream_set_wmargin (pest->stream, uparams.header_col); + __argp_fmtstream_puts (pest->stream, fstr); + __argp_fmtstream_set_lmargin (pest->stream, 0); + __argp_fmtstream_putc (pest->stream, '\n'); + } + + pest->hhstate->sep_groups = 1; /* Separate subsequent groups. */ + } + + if (fstr != tstr) + free ((char *) fstr); +} + +/* Inserts a comma if this isn't the first item on the line, and then makes + sure we're at least to column COL. If this *is* the first item on a line, + prints any pending whitespace/headers that should precede this line. Also + clears FIRST. */ +static void +comma (unsigned col, struct pentry_state *pest) +{ + if (pest->first) + { + const struct hol_entry *pe = pest->hhstate->prev_entry; + const struct hol_cluster *cl = pest->entry->cluster; + + if (pest->hhstate->sep_groups && pe && pest->entry->group != pe->group) + __argp_fmtstream_putc (pest->stream, '\n'); + + if (cl && cl->header && *cl->header + && (!pe + || (pe->cluster != cl + && !hol_cluster_is_child (pe->cluster, cl)))) + /* If we're changing clusters, then this must be the start of the + ENTRY's cluster unless that is an ancestor of the previous one + (in which case we had just popped into a sub-cluster for a bit). + If so, then print the cluster's header line. */ + { + int old_wm = __argp_fmtstream_wmargin (pest->stream); + print_header (cl->header, cl->argp, pest); + __argp_fmtstream_set_wmargin (pest->stream, old_wm); + } + + pest->first = 0; + } + else + __argp_fmtstream_puts (pest->stream, ", "); + + indent_to (pest->stream, col); +} + +/* Print help for ENTRY to STREAM. */ +static void +hol_entry_help (struct hol_entry *entry, const struct argp_state *state, + argp_fmtstream_t stream, struct hol_help_state *hhstate) +{ + unsigned num; + const struct argp_option *real = entry->opt, *opt; + char *so = entry->short_options; + int have_long_opt = 0; /* We have any long options. */ + /* Saved margins. */ + int old_lm = __argp_fmtstream_set_lmargin (stream, 0); + int old_wm = __argp_fmtstream_wmargin (stream); + /* PEST is a state block holding some of our variables that we'd like to + share with helper functions. */ + struct pentry_state pest; + + pest.entry = entry; + pest.stream = stream; + pest.hhstate = hhstate; + pest.first = 1; + pest.state = state; + + if (! odoc (real)) + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (opt->name && ovisible (opt)) + { + have_long_opt = 1; + break; + } + + /* First emit short options. */ + __argp_fmtstream_set_wmargin (stream, uparams.short_opt_col); /* For truly bizarre cases. */ + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (oshort (opt) && opt->key == *so) + /* OPT has a valid (non shadowed) short option. */ + { + if (ovisible (opt)) + { + comma (uparams.short_opt_col, &pest); + __argp_fmtstream_putc (stream, '-'); + __argp_fmtstream_putc (stream, *so); + if (!have_long_opt || uparams.dup_args) + arg (real, " %s", "[%s]", state->root_argp->argp_domain, stream); + else if (real->arg) + hhstate->suppressed_dup_arg = 1; + } + so++; + } + + /* Now, long options. */ + if (odoc (real)) + /* A `documentation' option. */ + { + __argp_fmtstream_set_wmargin (stream, uparams.doc_opt_col); + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (opt->name && *opt->name && ovisible (opt)) + { + comma (uparams.doc_opt_col, &pest); + /* Calling dgettext here isn't quite right, since sorting will + have been done on the original; but documentation options + should be pretty rare anyway... */ + __argp_fmtstream_puts (stream, + onotrans (opt) ? + opt->name : + dgettext (state->root_argp->argp_domain, + opt->name)); + } + } + else + /* A real long option. */ + { + int first_long_opt = 1; + + __argp_fmtstream_set_wmargin (stream, uparams.long_opt_col); + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (opt->name && ovisible (opt)) + { + comma (uparams.long_opt_col, &pest); + __argp_fmtstream_printf (stream, "--%s", opt->name); + if (first_long_opt || uparams.dup_args) + arg (real, "=%s", "[=%s]", state->root_argp->argp_domain, + stream); + else if (real->arg) + hhstate->suppressed_dup_arg = 1; + } + } + + /* Next, documentation strings. */ + __argp_fmtstream_set_lmargin (stream, 0); + + if (pest.first) + { + /* Didn't print any switches, what's up? */ + if (!oshort (real) && !real->name) + /* This is a group header, print it nicely. */ + print_header (real->doc, entry->argp, &pest); + else + /* Just a totally shadowed option or null header; print nothing. */ + goto cleanup; /* Just return, after cleaning up. */ + } + else + { + const char *tstr = real->doc ? dgettext (state->root_argp->argp_domain, + real->doc) : 0; + const char *fstr = filter_doc (tstr, real->key, entry->argp, state); + if (fstr && *fstr) + { + unsigned int col = __argp_fmtstream_point (stream); + + __argp_fmtstream_set_lmargin (stream, uparams.opt_doc_col); + __argp_fmtstream_set_wmargin (stream, uparams.opt_doc_col); + + if (col > (unsigned int) (uparams.opt_doc_col + 3)) + __argp_fmtstream_putc (stream, '\n'); + else if (col >= (unsigned int) uparams.opt_doc_col) + __argp_fmtstream_puts (stream, " "); + else + indent_to (stream, uparams.opt_doc_col); + + __argp_fmtstream_puts (stream, fstr); + } + if (fstr && fstr != tstr) + free ((char *) fstr); + + /* Reset the left margin. */ + __argp_fmtstream_set_lmargin (stream, 0); + __argp_fmtstream_putc (stream, '\n'); + } + + hhstate->prev_entry = entry; + +cleanup: + __argp_fmtstream_set_lmargin (stream, old_lm); + __argp_fmtstream_set_wmargin (stream, old_wm); +} + +/* Output a long help message about the options in HOL to STREAM. */ +static void +hol_help (struct hol *hol, const struct argp_state *state, + argp_fmtstream_t stream) +{ + unsigned num; + struct hol_entry *entry; + struct hol_help_state hhstate = { 0, 0, 0 }; + + for (entry = hol->entries, num = hol->num_entries; num > 0; entry++, num--) + hol_entry_help (entry, state, stream, &hhstate); + + if (hhstate.suppressed_dup_arg && uparams.dup_args_note) + { + const char *tstr = dgettext (state->root_argp->argp_domain, "\ +Mandatory or optional arguments to long options are also mandatory or \ +optional for any corresponding short options."); + const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE, + state ? state->root_argp : 0, state); + if (fstr && *fstr) + { + __argp_fmtstream_putc (stream, '\n'); + __argp_fmtstream_puts (stream, fstr); + __argp_fmtstream_putc (stream, '\n'); + } + if (fstr && fstr != tstr) + free ((char *) fstr); + } +} + +/* Helper functions for hol_usage. */ + +/* If OPT is a short option without an arg, append its key to the string + pointer pointer to by COOKIE, and advance the pointer. */ +static int +add_argless_short_opt (const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie) +{ + char **snao_end = cookie; + if (!(opt->arg || real->arg) + && !((opt->flags | real->flags) & OPTION_NO_USAGE)) + *(*snao_end)++ = opt->key; + return 0; +} + +/* If OPT is a short option with an arg, output a usage entry for it to the + stream pointed at by COOKIE. */ +static int +usage_argful_short_opt (const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie) +{ + argp_fmtstream_t stream = cookie; + const char *arg = opt->arg; + int flags = opt->flags | real->flags; + + if (! arg) + arg = real->arg; + + if (arg && !(flags & OPTION_NO_USAGE)) + { + arg = dgettext (domain, arg); + + if (flags & OPTION_ARG_OPTIONAL) + __argp_fmtstream_printf (stream, " [-%c[%s]]", opt->key, arg); + else + { + /* Manually do line wrapping so that it (probably) won't + get wrapped at the embedded space. */ + space (stream, 6 + strlen (arg)); + __argp_fmtstream_printf (stream, "[-%c %s]", opt->key, arg); + } + } + + return 0; +} + +/* Output a usage entry for the long option opt to the stream pointed at by + COOKIE. */ +static int +usage_long_opt (const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie) +{ + argp_fmtstream_t stream = cookie; + const char *arg = opt->arg; + int flags = opt->flags | real->flags; + + if (! arg) + arg = real->arg; + + if (! (flags & OPTION_NO_USAGE) && !odoc (opt)) + { + if (arg) + { + arg = dgettext (domain, arg); + if (flags & OPTION_ARG_OPTIONAL) + __argp_fmtstream_printf (stream, " [--%s[=%s]]", opt->name, arg); + else + __argp_fmtstream_printf (stream, " [--%s=%s]", opt->name, arg); + } + else + __argp_fmtstream_printf (stream, " [--%s]", opt->name); + } + + return 0; +} + +/* Print a short usage description for the arguments in HOL to STREAM. */ +static void +hol_usage (struct hol *hol, argp_fmtstream_t stream) +{ + if (hol->num_entries > 0) + { + unsigned nentries; + struct hol_entry *entry; + char *short_no_arg_opts = alloca (strlen (hol->short_options) + 1); + char *snao_end = short_no_arg_opts; + + /* First we put a list of short options without arguments. */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) + hol_entry_short_iterate (entry, add_argless_short_opt, + entry->argp->argp_domain, &snao_end); + if (snao_end > short_no_arg_opts) + { + *snao_end++ = 0; + __argp_fmtstream_printf (stream, " [-%s]", short_no_arg_opts); + } + + /* Now a list of short options *with* arguments. */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) + hol_entry_short_iterate (entry, usage_argful_short_opt, + entry->argp->argp_domain, stream); + + /* Finally, a list of long options (whew!). */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) + hol_entry_long_iterate (entry, usage_long_opt, + entry->argp->argp_domain, stream); + } +} + +/* Make a HOL containing all levels of options in ARGP. CLUSTER is the + cluster in which ARGP's entries should be clustered, or 0. */ +static struct hol * +argp_hol (const struct argp *argp, struct hol_cluster *cluster) +{ + const struct argp_child *child = argp->children; + struct hol *hol = make_hol (argp, cluster); + if (child) + while (child->argp) + { + struct hol_cluster *child_cluster = + ((child->group || child->header) + /* Put CHILD->argp within its own cluster. */ + ? hol_add_cluster (hol, child->group, child->header, + child - argp->children, cluster, argp) + /* Just merge it into the parent's cluster. */ + : cluster); + hol_append (hol, argp_hol (child->argp, child_cluster)) ; + child++; + } + return hol; +} + +/* Calculate how many different levels with alternative args strings exist in + ARGP. */ +static size_t +argp_args_levels (const struct argp *argp) +{ + size_t levels = 0; + const struct argp_child *child = argp->children; + + if (argp->args_doc && strchr (argp->args_doc, '\n')) + levels++; + + if (child) + while (child->argp) + levels += argp_args_levels ((child++)->argp); + + return levels; +} + +/* Print all the non-option args documented in ARGP to STREAM. Any output is + preceded by a space. LEVELS is a pointer to a byte vector the length + returned by argp_args_levels; it should be initialized to zero, and + updated by this routine for the next call if ADVANCE is true. True is + returned as long as there are more patterns to output. */ +static int +argp_args_usage (const struct argp *argp, const struct argp_state *state, + char **levels, int advance, argp_fmtstream_t stream) +{ + char *our_level = *levels; + int multiple = 0; + const struct argp_child *child = argp->children; + const char *tdoc = dgettext (argp->argp_domain, argp->args_doc), *nl = 0; + const char *fdoc = filter_doc (tdoc, ARGP_KEY_HELP_ARGS_DOC, argp, state); + + if (fdoc) + { + const char *cp = fdoc; + nl = __strchrnul (cp, '\n'); + if (*nl != '\0') + /* This is a `multi-level' args doc; advance to the correct position + as determined by our state in LEVELS, and update LEVELS. */ + { + int i; + multiple = 1; + for (i = 0; i < *our_level; i++) + cp = nl + 1, nl = __strchrnul (cp, '\n'); + (*levels)++; + } + + /* Manually do line wrapping so that it (probably) won't get wrapped at + any embedded spaces. */ + space (stream, 1 + nl - cp); + + __argp_fmtstream_write (stream, cp, nl - cp); + } + if (fdoc && fdoc != tdoc) + free ((char *)fdoc); /* Free user's modified doc string. */ + + if (child) + while (child->argp) + advance = !argp_args_usage ((child++)->argp, state, levels, advance, stream); + + if (advance && multiple) + { + /* Need to increment our level. */ + if (*nl) + /* There's more we can do here. */ + { + (*our_level)++; + advance = 0; /* Our parent shouldn't advance also. */ + } + else if (*our_level > 0) + /* We had multiple levels, but used them up; reset to zero. */ + *our_level = 0; + } + + return !advance; +} + +/* Print the documentation for ARGP to STREAM; if POST is false, then + everything preceeding a `\v' character in the documentation strings (or + the whole string, for those with none) is printed, otherwise, everything + following the `\v' character (nothing for strings without). Each separate + bit of documentation is separated a blank line, and if PRE_BLANK is true, + then the first is as well. If FIRST_ONLY is true, only the first + occurrence is output. Returns true if anything was output. */ +static int +argp_doc (const struct argp *argp, const struct argp_state *state, + int post, int pre_blank, int first_only, + argp_fmtstream_t stream) +{ + const char *text; + const char *inp_text; + size_t inp_text_len = 0; + const char *trans_text; + void *input = 0; + int anything = 0; + const struct argp_child *child = argp->children; + + if (argp->doc) + { + char *vt = strchr (argp->doc, '\v'); + if (vt) + { + if (post) + inp_text = vt + 1; + else + { + inp_text_len = vt - argp->doc; + inp_text = __strndup (argp->doc, inp_text_len); + } + } + else + inp_text = post ? 0 : argp->doc; + trans_text = inp_text ? dgettext (argp->argp_domain, inp_text) : NULL; + } + else + trans_text = inp_text = 0; + + if (argp->help_filter) + /* We have to filter the doc strings. */ + { + input = __argp_input (argp, state); + text = + (*argp->help_filter) (post + ? ARGP_KEY_HELP_POST_DOC + : ARGP_KEY_HELP_PRE_DOC, + trans_text, input); + } + else + text = (const char *) trans_text; + + if (text) + { + if (pre_blank) + __argp_fmtstream_putc (stream, '\n'); + + __argp_fmtstream_puts (stream, text); + + if (__argp_fmtstream_point (stream) > __argp_fmtstream_lmargin (stream)) + __argp_fmtstream_putc (stream, '\n'); + + anything = 1; + } + + if (text && text != trans_text) + free ((char *) text); /* Free TEXT returned from the help filter. */ + + if (inp_text && inp_text_len) + free ((char *) inp_text); /* We copied INP_TEXT, so free it now. */ + + if (post && argp->help_filter) + /* Now see if we have to output a ARGP_KEY_HELP_EXTRA text. */ + { + text = (*argp->help_filter) (ARGP_KEY_HELP_EXTRA, 0, input); + if (text) + { + if (anything || pre_blank) + __argp_fmtstream_putc (stream, '\n'); + __argp_fmtstream_puts (stream, text); + free ((char *) text); + if (__argp_fmtstream_point (stream) + > __argp_fmtstream_lmargin (stream)) + __argp_fmtstream_putc (stream, '\n'); + anything = 1; + } + } + + if (child) + while (child->argp && !(first_only && anything)) + anything |= + argp_doc ((child++)->argp, state, + post, anything || pre_blank, first_only, + stream); + + return anything; +} + +/* Output a usage message for ARGP to STREAM. If called from + argp_state_help, STATE is the relevent parsing state. FLAGS are from the + set ARGP_HELP_*. NAME is what to use wherever a `program name' is + needed. */ +static void +_help (const struct argp *argp, const struct argp_state *state, FILE *stream, + unsigned flags, char *name) +{ + int anything = 0; /* Whether we've output anything. */ + struct hol *hol = 0; + argp_fmtstream_t fs; + + if (! stream) + return; + +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __flockfile (stream); +#endif + + if (! uparams.valid) + fill_in_uparams (state); + + fs = __argp_make_fmtstream (stream, 0, uparams.rmargin, 0); + if (! fs) + { +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __funlockfile (stream); +#endif + return; + } + + if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG)) + { + hol = argp_hol (argp, 0); + + /* If present, these options always come last. */ + hol_set_group (hol, "help", -1); + hol_set_group (hol, "version", -1); + + hol_sort (hol); + } + + if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE)) + /* Print a short `Usage:' message. */ + { + int first_pattern = 1, more_patterns; + size_t num_pattern_levels = argp_args_levels (argp); + char *pattern_levels = alloca (num_pattern_levels); + + memset (pattern_levels, 0, num_pattern_levels); + + do + { + int old_lm; + int old_wm = __argp_fmtstream_set_wmargin (fs, uparams.usage_indent); + char *levels = pattern_levels; + + if (first_pattern) + __argp_fmtstream_printf (fs, "%s %s", + dgettext (argp->argp_domain, "Usage:"), + name); + else + __argp_fmtstream_printf (fs, "%s %s", + dgettext (argp->argp_domain, " or: "), + name); + + /* We set the lmargin as well as the wmargin, because hol_usage + manually wraps options with newline to avoid annoying breaks. */ + old_lm = __argp_fmtstream_set_lmargin (fs, uparams.usage_indent); + + if (flags & ARGP_HELP_SHORT_USAGE) + /* Just show where the options go. */ + { + if (hol->num_entries > 0) + __argp_fmtstream_puts (fs, dgettext (argp->argp_domain, + " [OPTION...]")); + } + else + /* Actually print the options. */ + { + hol_usage (hol, fs); + flags |= ARGP_HELP_SHORT_USAGE; /* But only do so once. */ + } + + more_patterns = argp_args_usage (argp, state, &levels, 1, fs); + + __argp_fmtstream_set_wmargin (fs, old_wm); + __argp_fmtstream_set_lmargin (fs, old_lm); + + __argp_fmtstream_putc (fs, '\n'); + anything = 1; + + first_pattern = 0; + } + while (more_patterns); + } + + if (flags & ARGP_HELP_PRE_DOC) + anything |= argp_doc (argp, state, 0, 0, 1, fs); + + if (flags & ARGP_HELP_SEE) + { + __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, "\ +Try `%s --help' or `%s --usage' for more information.\n"), + name, name); + anything = 1; + } + + if (flags & ARGP_HELP_LONG) + /* Print a long, detailed help message. */ + { + /* Print info about all the options. */ + if (hol->num_entries > 0) + { + if (anything) + __argp_fmtstream_putc (fs, '\n'); + hol_help (hol, state, fs); + anything = 1; + } + } + + if (flags & ARGP_HELP_POST_DOC) + /* Print any documentation strings at the end. */ + anything |= argp_doc (argp, state, 1, anything, 0, fs); + + if ((flags & ARGP_HELP_BUG_ADDR) && argp_program_bug_address) + { + if (anything) + __argp_fmtstream_putc (fs, '\n'); + __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, + "Report bugs to %s.\n"), + argp_program_bug_address); + anything = 1; + } + +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __funlockfile (stream); +#endif + + if (hol) + hol_free (hol); + + __argp_fmtstream_free (fs); +} + +/* Output a usage message for ARGP to STREAM. FLAGS are from the set + ARGP_HELP_*. NAME is what to use wherever a `program name' is needed. */ +void __argp_help (const struct argp *argp, FILE *stream, + unsigned flags, char *name) +{ + struct argp_state state; + memset (&state, 0, sizeof state); + state.root_argp = argp; + _help (argp, &state, stream, flags, name); +} +#ifdef weak_alias +weak_alias (__argp_help, argp_help) +#endif + +#if ! (defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME) +char * +__argp_short_program_name (void) +{ +# if HAVE_DECL_PROGRAM_INVOCATION_NAME + return __argp_base_name (program_invocation_name); +# else + /* FIXME: What now? Miles suggests that it is better to use NULL, + but currently the value is passed on directly to fputs_unlocked, + so that requires more changes. */ +# if __GNUC__ +# warning No reasonable value to return +# endif /* __GNUC__ */ + return ""; +# endif +} +#endif + +/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are + from the set ARGP_HELP_*. */ +void +__argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags) +{ + if ((!state || ! (state->flags & ARGP_NO_ERRS)) && stream) + { + if (state && (state->flags & ARGP_LONG_ONLY)) + flags |= ARGP_HELP_LONG_ONLY; + + _help (state ? state->root_argp : 0, state, stream, flags, + state ? state->name : __argp_short_program_name ()); + + if (!state || ! (state->flags & ARGP_NO_EXIT)) + { + if (flags & ARGP_HELP_EXIT_ERR) + exit (argp_err_exit_status); + if (flags & ARGP_HELP_EXIT_OK) + exit (0); + } + } +} +#ifdef weak_alias +weak_alias (__argp_state_help, argp_state_help) +#endif + +/* If appropriate, print the printf string FMT and following args, preceded + by the program name and `:', to stderr, and followed by a `Try ... --help' + message, then exit (1). */ +void +__argp_error (const struct argp_state *state, const char *fmt, ...) +{ + if (!state || !(state->flags & ARGP_NO_ERRS)) + { + FILE *stream = state ? state->err_stream : stderr; + + if (stream) + { + va_list ap; + +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __flockfile (stream); +#endif + + va_start (ap, fmt); + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + { + char *buf; + + if (__asprintf (&buf, fmt, ap) < 0) + buf = NULL; + + __fwprintf (stream, L"%s: %s\n", + state ? state->name : __argp_short_program_name (), + buf); + + free (buf); + } + else +#endif + { + fputs_unlocked (state + ? state->name : __argp_short_program_name (), + stream); + putc_unlocked (':', stream); + putc_unlocked (' ', stream); + + vfprintf (stream, fmt, ap); + + putc_unlocked ('\n', stream); + } + + __argp_state_help (state, stream, ARGP_HELP_STD_ERR); + + va_end (ap); + +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __funlockfile (stream); +#endif + } + } +} +#ifdef weak_alias +weak_alias (__argp_error, argp_error) +#endif + +/* Similar to the standard gnu error-reporting function error(), but will + respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print + to STATE->err_stream. This is useful for argument parsing code that is + shared between program startup (when exiting is desired) and runtime + option parsing (when typically an error code is returned instead). The + difference between this function and argp_error is that the latter is for + *parsing errors*, and the former is for other problems that occur during + parsing but don't reflect a (syntactic) problem with the input. */ +void +__argp_failure (const struct argp_state *state, int status, int errnum, + const char *fmt, ...) +{ + if (!state || !(state->flags & ARGP_NO_ERRS)) + { + FILE *stream = state ? state->err_stream : stderr; + + if (stream) + { +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __flockfile (stream); +#endif + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + __fwprintf (stream, L"%s", + state ? state->name : __argp_short_program_name ()); + else +#endif + fputs_unlocked (state + ? state->name : __argp_short_program_name (), + stream); + + if (fmt) + { + va_list ap; + + va_start (ap, fmt); +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + { + char *buf; + + if (__asprintf (&buf, fmt, ap) < 0) + buf = NULL; + + __fwprintf (stream, L": %s", buf); + + free (buf); + } + else +#endif + { + putc_unlocked (':', stream); + putc_unlocked (' ', stream); + + vfprintf (stream, fmt, ap); + } + + va_end (ap); + } + + if (errnum) + { + char buf[200]; + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + __fwprintf (stream, L": %s", + __strerror_r (errnum, buf, sizeof (buf))); + else +#endif + { + char const *s = NULL; + putc_unlocked (':', stream); + putc_unlocked (' ', stream); +#if _LIBC || (HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P) + s = __strerror_r (errnum, buf, sizeof buf); +#elif HAVE_DECL_STRERROR_R + if (__strerror_r (errnum, buf, sizeof buf) == 0) + s = buf; +#endif +#if !_LIBC + if (! s && ! (s = strerror (errnum))) + s = dgettext (state->root_argp->argp_domain, + "Unknown system error"); +#endif + fputs (s, stream); + } + } + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + putwc_unlocked (L'\n', stream); + else +#endif + putc_unlocked ('\n', stream); + +#if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE) + __funlockfile (stream); +#endif + + if (status && (!state || !(state->flags & ARGP_NO_EXIT))) + exit (status); + } + } +} +#ifdef weak_alias +weak_alias (__argp_failure, argp_failure) +#endif diff --git a/gnulib/argp-namefrob.h b/gnulib/argp-namefrob.h new file mode 100644 index 000000000..24581a626 --- /dev/null +++ b/gnulib/argp-namefrob.h @@ -0,0 +1,157 @@ +/* Name frobnication for compiling argp outside of glibc + Copyright (C) 1997, 2003, 2007, 2009, 2010 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +#if !_LIBC +/* This code is written for inclusion in gnu-libc, and uses names in the + namespace reserved for libc. If we're not compiling in libc, define those + names to be the normal ones instead. */ + +/* argp-parse functions */ +#undef __argp_parse +#define __argp_parse argp_parse +#undef __option_is_end +#define __option_is_end _option_is_end +#undef __option_is_short +#define __option_is_short _option_is_short +#undef __argp_input +#define __argp_input _argp_input + +/* argp-help functions */ +#undef __argp_help +#define __argp_help argp_help +#undef __argp_error +#define __argp_error argp_error +#undef __argp_failure +#define __argp_failure argp_failure +#undef __argp_state_help +#define __argp_state_help argp_state_help +#undef __argp_usage +#define __argp_usage argp_usage + +/* argp-fmtstream functions */ +#undef __argp_make_fmtstream +#define __argp_make_fmtstream argp_make_fmtstream +#undef __argp_fmtstream_free +#define __argp_fmtstream_free argp_fmtstream_free +#undef __argp_fmtstream_putc +#define __argp_fmtstream_putc argp_fmtstream_putc +#undef __argp_fmtstream_puts +#define __argp_fmtstream_puts argp_fmtstream_puts +#undef __argp_fmtstream_write +#define __argp_fmtstream_write argp_fmtstream_write +#undef __argp_fmtstream_printf +#define __argp_fmtstream_printf argp_fmtstream_printf +#undef __argp_fmtstream_set_lmargin +#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin +#undef __argp_fmtstream_set_rmargin +#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin +#undef __argp_fmtstream_set_wmargin +#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin +#undef __argp_fmtstream_point +#define __argp_fmtstream_point argp_fmtstream_point +#undef __argp_fmtstream_update +#define __argp_fmtstream_update _argp_fmtstream_update +#undef __argp_fmtstream_ensure +#define __argp_fmtstream_ensure _argp_fmtstream_ensure +#undef __argp_fmtstream_lmargin +#define __argp_fmtstream_lmargin argp_fmtstream_lmargin +#undef __argp_fmtstream_rmargin +#define __argp_fmtstream_rmargin argp_fmtstream_rmargin +#undef __argp_fmtstream_wmargin +#define __argp_fmtstream_wmargin argp_fmtstream_wmargin + +/* normal libc functions we call */ +#undef __flockfile +#define __flockfile flockfile +#undef __funlockfile +#define __funlockfile funlockfile +#undef __mempcpy +#define __mempcpy mempcpy +#undef __sleep +#define __sleep sleep +#undef __strcasecmp +#define __strcasecmp strcasecmp +#undef __strchrnul +#define __strchrnul strchrnul +#undef __strerror_r +#define __strerror_r strerror_r +#undef __strndup +#define __strndup strndup +#undef __vsnprintf +#define __vsnprintf vsnprintf + +#if defined(HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED +# define clearerr_unlocked(x) clearerr (x) +#endif +#if defined(HAVE_DECL_FEOF_UNLOCKED) && !HAVE_DECL_FEOF_UNLOCKED +# define feof_unlocked(x) feof (x) +# endif +#if defined(HAVE_DECL_FERROR_UNLOCKED) && !HAVE_DECL_FERROR_UNLOCKED +# define ferror_unlocked(x) ferror (x) +# endif +#if defined(HAVE_DECL_FFLUSH_UNLOCKED) && !HAVE_DECL_FFLUSH_UNLOCKED +# define fflush_unlocked(x) fflush (x) +# endif +#if defined(HAVE_DECL_FGETS_UNLOCKED) && !HAVE_DECL_FGETS_UNLOCKED +# define fgets_unlocked(x,y,z) fgets (x,y,z) +# endif +#if defined(HAVE_DECL_FPUTC_UNLOCKED) && !HAVE_DECL_FPUTC_UNLOCKED +# define fputc_unlocked(x,y) fputc (x,y) +# endif +#if defined(HAVE_DECL_FPUTS_UNLOCKED) && !HAVE_DECL_FPUTS_UNLOCKED +# define fputs_unlocked(x,y) fputs (x,y) +# endif +#if defined(HAVE_DECL_FREAD_UNLOCKED) && !HAVE_DECL_FREAD_UNLOCKED +# define fread_unlocked(w,x,y,z) fread (w,x,y,z) +# endif +#if defined(HAVE_DECL_FWRITE_UNLOCKED) && !HAVE_DECL_FWRITE_UNLOCKED +# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z) +# endif +#if defined(HAVE_DECL_GETC_UNLOCKED) && !HAVE_DECL_GETC_UNLOCKED +# define getc_unlocked(x) getc (x) +# endif +#if defined(HAVE_DECL_GETCHAR_UNLOCKED) && !HAVE_DECL_GETCHAR_UNLOCKED +# define getchar_unlocked() getchar () +# endif +#if defined(HAVE_DECL_PUTC_UNLOCKED) && !HAVE_DECL_PUTC_UNLOCKED +# define putc_unlocked(x,y) putc (x,y) +# endif +#if defined(HAVE_DECL_PUTCHAR_UNLOCKED) && !HAVE_DECL_PUTCHAR_UNLOCKED +# define putchar_unlocked(x) putchar (x) +# endif + +#endif /* !_LIBC */ + +#ifndef __set_errno +#define __set_errno(e) (errno = (e)) +#endif + +#if defined GNULIB_ARGP_DISABLE_DIRNAME +# define __argp_base_name(arg) arg +#elif defined GNULIB_ARGP_EXTERN_BASENAME +extern char *__argp_base_name (const char *arg); +#else +# include "dirname.h" +# define __argp_base_name last_component +#endif + +#if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME +# define __argp_short_program_name() (program_invocation_short_name) +#else +extern char *__argp_short_program_name (void); +#endif diff --git a/gnulib/argp-parse.c b/gnulib/argp-parse.c new file mode 100644 index 000000000..a1cbf884e --- /dev/null +++ b/gnulib/argp-parse.c @@ -0,0 +1,952 @@ +/* Hierarchial argument parsing, layered over getopt + Copyright (C) 1995-2000, 2002-2004, 2009-2010 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _LIBC +# include +# undef dgettext +# define dgettext(domain, msgid) \ + INTUSE(__dcgettext) (domain, msgid, LC_MESSAGES) +#else +# include "gettext.h" +#endif +#define N_(msgid) msgid + +#include "argp.h" +#include "argp-namefrob.h" + +#define alignof(type) offsetof (struct { char c; type x; }, x) +#define alignto(n, d) ((((n) + (d) - 1) / (d)) * (d)) + +/* Getopt return values. */ +#define KEY_END (-1) /* The end of the options. */ +#define KEY_ARG 1 /* A non-option argument. */ +#define KEY_ERR '?' /* An error parsing the options. */ + +/* The meta-argument used to prevent any further arguments being interpreted + as options. */ +#define QUOTE "--" + +/* The number of bits we steal in a long-option value for our own use. */ +#define GROUP_BITS CHAR_BIT + +/* The number of bits available for the user value. */ +#define USER_BITS ((sizeof ((struct option *)0)->val * CHAR_BIT) - GROUP_BITS) +#define USER_MASK ((1 << USER_BITS) - 1) + +/* EZ alias for ARGP_ERR_UNKNOWN. */ +#define EBADKEY ARGP_ERR_UNKNOWN + +/* Default options. */ + +/* When argp is given the --HANG switch, _ARGP_HANG is set and argp will sleep + for one second intervals, decrementing _ARGP_HANG until it's zero. Thus + you can force the program to continue by attaching a debugger and setting + it to 0 yourself. */ +static volatile int _argp_hang; + +#define OPT_PROGNAME -2 +#define OPT_USAGE -3 +#define OPT_HANG -4 + +static const struct argp_option argp_default_options[] = +{ + {"help", '?', 0, 0, N_("give this help list"), -1}, + {"usage", OPT_USAGE, 0, 0, N_("give a short usage message"), 0}, + {"program-name",OPT_PROGNAME,N_("NAME"), OPTION_HIDDEN, N_("set the program name"), 0}, + {"HANG", OPT_HANG, N_("SECS"), OPTION_ARG_OPTIONAL | OPTION_HIDDEN, + N_("hang for SECS seconds (default 3600)"), 0}, + {NULL, 0, 0, 0, NULL, 0} +}; + +static error_t +argp_default_parser (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case '?': + __argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP); + break; + case OPT_USAGE: + __argp_state_help (state, state->out_stream, + ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); + break; + + case OPT_PROGNAME: /* Set the program name. */ +#if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_NAME + program_invocation_name = arg; +#endif + /* [Note that some systems only have PROGRAM_INVOCATION_SHORT_NAME (aka + __PROGNAME), in which case, PROGRAM_INVOCATION_NAME is just defined + to be that, so we have to be a bit careful here.] */ + + /* Update what we use for messages. */ + state->name = __argp_base_name (arg); + +#if defined _LIBC || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME + program_invocation_short_name = state->name; +#endif + + if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS)) + == ARGP_PARSE_ARGV0) + /* Update what getopt uses too. */ + state->argv[0] = arg; + + break; + + case OPT_HANG: + _argp_hang = atoi (arg ? arg : "3600"); + while (_argp_hang-- > 0) + __sleep (1); + break; + + default: + return EBADKEY; + } + return 0; +} + +static const struct argp argp_default_argp = + {argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL, "libc"}; + + +static const struct argp_option argp_version_options[] = +{ + {"version", 'V', 0, 0, N_("print program version"), -1}, + {NULL, 0, 0, 0, NULL, 0} +}; + +static error_t +argp_version_parser (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'V': + if (argp_program_version_hook) + (*argp_program_version_hook) (state->out_stream, state); + else if (argp_program_version) + fprintf (state->out_stream, "%s\n", argp_program_version); + else + __argp_error (state, dgettext (state->root_argp->argp_domain, + "(PROGRAM ERROR) No version known!?")); + if (! (state->flags & ARGP_NO_EXIT)) + exit (0); + break; + default: + return EBADKEY; + } + return 0; +} + +static const struct argp argp_version_argp = + {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL, "libc"}; + +/* Returns the offset into the getopt long options array LONG_OPTIONS of a + long option with called NAME, or -1 if none is found. Passing NULL as + NAME will return the number of options. */ +static int +find_long_option (struct option *long_options, const char *name) +{ + struct option *l = long_options; + while (l->name != NULL) + if (name != NULL && strcmp (l->name, name) == 0) + return l - long_options; + else + l++; + if (name == NULL) + return l - long_options; + else + return -1; +} + + +/* The state of a `group' during parsing. Each group corresponds to a + particular argp structure from the tree of such descending from the top + level argp passed to argp_parse. */ +struct group +{ + /* This group's parsing function. */ + argp_parser_t parser; + + /* Which argp this group is from. */ + const struct argp *argp; + + /* Points to the point in SHORT_OPTS corresponding to the end of the short + options for this group. We use it to determine from which group a + particular short options is from. */ + char *short_end; + + /* The number of non-option args sucessfully handled by this parser. */ + unsigned args_processed; + + /* This group's parser's parent's group. */ + struct group *parent; + unsigned parent_index; /* And the our position in the parent. */ + + /* These fields are swapped into and out of the state structure when + calling this group's parser. */ + void *input, **child_inputs; + void *hook; +}; + +/* Call GROUP's parser with KEY and ARG, swapping any group-specific info + from STATE before calling, and back into state afterwards. If GROUP has + no parser, EBADKEY is returned. */ +static error_t +group_parse (struct group *group, struct argp_state *state, int key, char *arg) +{ + if (group->parser) + { + error_t err; + state->hook = group->hook; + state->input = group->input; + state->child_inputs = group->child_inputs; + state->arg_num = group->args_processed; + err = (*group->parser)(key, arg, state); + group->hook = state->hook; + return err; + } + else + return EBADKEY; +} + +struct parser +{ + const struct argp *argp; + + /* SHORT_OPTS is the getopt short options string for the union of all the + groups of options. */ + char *short_opts; + /* LONG_OPTS is the array of getop long option structures for the union of + all the groups of options. */ + struct option *long_opts; + /* OPT_DATA is the getopt data used for the re-entrant getopt. */ + struct _getopt_data opt_data; + + /* States of the various parsing groups. */ + struct group *groups; + /* The end of the GROUPS array. */ + struct group *egroup; + /* An vector containing storage for the CHILD_INPUTS field in all groups. */ + void **child_inputs; + + /* True if we think using getopt is still useful; if false, then + remaining arguments are just passed verbatim with ARGP_KEY_ARG. This is + cleared whenever getopt returns KEY_END, but may be set again if the user + moves the next argument pointer backwards. */ + int try_getopt; + + /* State block supplied to parsing routines. */ + struct argp_state state; + + /* Memory used by this parser. */ + void *storage; +}; + +/* The next usable entries in the various parser tables being filled in by + convert_options. */ +struct parser_convert_state +{ + struct parser *parser; + char *short_end; + struct option *long_end; + void **child_inputs_end; +}; + +/* Converts all options in ARGP (which is put in GROUP) and ancestors + into getopt options stored in SHORT_OPTS and LONG_OPTS; SHORT_END and + CVT->LONG_END are the points at which new options are added. Returns the + next unused group entry. CVT holds state used during the conversion. */ +static struct group * +convert_options (const struct argp *argp, + struct group *parent, unsigned parent_index, + struct group *group, struct parser_convert_state *cvt) +{ + /* REAL is the most recent non-alias value of OPT. */ + const struct argp_option *real = argp->options; + const struct argp_child *children = argp->children; + + if (real || argp->parser) + { + const struct argp_option *opt; + + if (real) + for (opt = real; !__option_is_end (opt); opt++) + { + if (! (opt->flags & OPTION_ALIAS)) + /* OPT isn't an alias, so we can use values from it. */ + real = opt; + + if (! (real->flags & OPTION_DOC)) + /* A real option (not just documentation). */ + { + if (__option_is_short (opt)) + /* OPT can be used as a short option. */ + { + *cvt->short_end++ = opt->key; + if (real->arg) + { + *cvt->short_end++ = ':'; + if (real->flags & OPTION_ARG_OPTIONAL) + *cvt->short_end++ = ':'; + } + *cvt->short_end = '\0'; /* keep 0 terminated */ + } + + if (opt->name + && find_long_option (cvt->parser->long_opts, opt->name) < 0) + /* OPT can be used as a long option. */ + { + cvt->long_end->name = opt->name; + cvt->long_end->has_arg = + (real->arg + ? (real->flags & OPTION_ARG_OPTIONAL + ? optional_argument + : required_argument) + : no_argument); + cvt->long_end->flag = 0; + /* we add a disambiguating code to all the user's + values (which is removed before we actually call + the function to parse the value); this means that + the user loses use of the high 8 bits in all his + values (the sign of the lower bits is preserved + however)... */ + cvt->long_end->val = + ((opt->key ? opt->key : real->key) & USER_MASK) + + (((group - cvt->parser->groups) + 1) << USER_BITS); + + /* Keep the LONG_OPTS list terminated. */ + (++cvt->long_end)->name = NULL; + } + } + } + + group->parser = argp->parser; + group->argp = argp; + group->short_end = cvt->short_end; + group->args_processed = 0; + group->parent = parent; + group->parent_index = parent_index; + group->input = 0; + group->hook = 0; + group->child_inputs = 0; + + if (children) + /* Assign GROUP's CHILD_INPUTS field some space from + CVT->child_inputs_end.*/ + { + unsigned num_children = 0; + while (children[num_children].argp) + num_children++; + group->child_inputs = cvt->child_inputs_end; + cvt->child_inputs_end += num_children; + } + + parent = group++; + } + else + parent = 0; + + if (children) + { + unsigned index = 0; + while (children->argp) + group = + convert_options (children++->argp, parent, index++, group, cvt); + } + + return group; +} + +/* Find the merged set of getopt options, with keys appropiately prefixed. */ +static void +parser_convert (struct parser *parser, const struct argp *argp, int flags) +{ + struct parser_convert_state cvt; + + cvt.parser = parser; + cvt.short_end = parser->short_opts; + cvt.long_end = parser->long_opts; + cvt.child_inputs_end = parser->child_inputs; + + if (flags & ARGP_IN_ORDER) + *cvt.short_end++ = '-'; + else if (flags & ARGP_NO_ARGS) + *cvt.short_end++ = '+'; + *cvt.short_end = '\0'; + + cvt.long_end->name = NULL; + + parser->argp = argp; + + if (argp) + parser->egroup = convert_options (argp, 0, 0, parser->groups, &cvt); + else + parser->egroup = parser->groups; /* No parsers at all! */ +} + +/* Lengths of various parser fields which we will allocated. */ +struct parser_sizes +{ + size_t short_len; /* Getopt short options string. */ + size_t long_len; /* Getopt long options vector. */ + size_t num_groups; /* Group structures we allocate. */ + size_t num_child_inputs; /* Child input slots. */ +}; + +/* For ARGP, increments the NUM_GROUPS field in SZS by the total number of + argp structures descended from it, and the SHORT_LEN & LONG_LEN fields by + the maximum lengths of the resulting merged getopt short options string and + long-options array, respectively. */ +static void +calc_sizes (const struct argp *argp, struct parser_sizes *szs) +{ + const struct argp_child *child = argp->children; + const struct argp_option *opt = argp->options; + + if (opt || argp->parser) + { + szs->num_groups++; + if (opt) + { + int num_opts = 0; + while (!__option_is_end (opt++)) + num_opts++; + szs->short_len += num_opts * 3; /* opt + up to 2 `:'s */ + szs->long_len += num_opts; + } + } + + if (child) + while (child->argp) + { + calc_sizes ((child++)->argp, szs); + szs->num_child_inputs++; + } +} + +/* Initializes PARSER to parse ARGP in a manner described by FLAGS. */ +static error_t +parser_init (struct parser *parser, const struct argp *argp, + int argc, char **argv, int flags, void *input) +{ + error_t err = 0; + struct group *group; + struct parser_sizes szs; + struct _getopt_data opt_data = _GETOPT_DATA_INITIALIZER; + char *storage; + size_t glen, gsum; + size_t clen, csum; + size_t llen, lsum; + size_t slen, ssum; + + szs.short_len = (flags & ARGP_NO_ARGS) ? 0 : 1; + szs.long_len = 0; + szs.num_groups = 0; + szs.num_child_inputs = 0; + + if (argp) + calc_sizes (argp, &szs); + + /* Lengths of the various bits of storage used by PARSER. */ + glen = (szs.num_groups + 1) * sizeof (struct group); + clen = szs.num_child_inputs * sizeof (void *); + llen = (szs.long_len + 1) * sizeof (struct option); + slen = szs.short_len + 1; + + /* Sums of previous lengths, properly aligned. There's no need to + align gsum, since struct group is aligned at least as strictly as + void * (since it contains a void * member). And there's no need + to align lsum, since struct option is aligned at least as + strictly as char. */ + gsum = glen; + csum = alignto (gsum + clen, alignof (struct option)); + lsum = csum + llen; + ssum = lsum + slen; + + parser->storage = malloc (ssum); + if (! parser->storage) + return ENOMEM; + + storage = parser->storage; + parser->groups = parser->storage; + parser->child_inputs = (void **) (storage + gsum); + parser->long_opts = (struct option *) (storage + csum); + parser->short_opts = storage + lsum; + parser->opt_data = opt_data; + + memset (parser->child_inputs, 0, clen); + parser_convert (parser, argp, flags); + + memset (&parser->state, 0, sizeof (struct argp_state)); + parser->state.root_argp = parser->argp; + parser->state.argc = argc; + parser->state.argv = argv; + parser->state.flags = flags; + parser->state.err_stream = stderr; + parser->state.out_stream = stdout; + parser->state.next = 0; /* Tell getopt to initialize. */ + parser->state.pstate = parser; + + parser->try_getopt = 1; + + /* Call each parser for the first time, giving it a chance to propagate + values to child parsers. */ + if (parser->groups < parser->egroup) + parser->groups->input = input; + for (group = parser->groups; + group < parser->egroup && (!err || err == EBADKEY); + group++) + { + if (group->parent) + /* If a child parser, get the initial input value from the parent. */ + group->input = group->parent->child_inputs[group->parent_index]; + + if (!group->parser + && group->argp->children && group->argp->children->argp) + /* For the special case where no parsing function is supplied for an + argp, propagate its input to its first child, if any (this just + makes very simple wrapper argps more convenient). */ + group->child_inputs[0] = group->input; + + err = group_parse (group, &parser->state, ARGP_KEY_INIT, 0); + } + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + + if (err) + return err; + + if (parser->state.flags & ARGP_NO_ERRS) + { + parser->opt_data.opterr = 0; + if (parser->state.flags & ARGP_PARSE_ARGV0) + /* getopt always skips ARGV[0], so we have to fake it out. As long + as OPTERR is 0, then it shouldn't actually try to access it. */ + parser->state.argv--, parser->state.argc++; + } + else + parser->opt_data.opterr = 1; /* Print error messages. */ + + if (parser->state.argv == argv && argv[0]) + /* There's an argv[0]; use it for messages. */ + parser->state.name = __argp_base_name (argv[0]); + else + parser->state.name = __argp_short_program_name (); + + return 0; +} + +/* Free any storage consumed by PARSER (but not PARSER itself). */ +static error_t +parser_finalize (struct parser *parser, + error_t err, int arg_ebadkey, int *end_index) +{ + struct group *group; + + if (err == EBADKEY && arg_ebadkey) + /* Suppress errors generated by unparsed arguments. */ + err = 0; + + if (! err) + { + if (parser->state.next == parser->state.argc) + /* We successfully parsed all arguments! Call all the parsers again, + just a few more times... */ + { + for (group = parser->groups; + group < parser->egroup && (!err || err==EBADKEY); + group++) + if (group->args_processed == 0) + err = group_parse (group, &parser->state, ARGP_KEY_NO_ARGS, 0); + for (group = parser->egroup - 1; + group >= parser->groups && (!err || err==EBADKEY); + group--) + err = group_parse (group, &parser->state, ARGP_KEY_END, 0); + + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + + /* Tell the user that all arguments are parsed. */ + if (end_index) + *end_index = parser->state.next; + } + else if (end_index) + /* Return any remaining arguments to the user. */ + *end_index = parser->state.next; + else + /* No way to return the remaining arguments, they must be bogus. */ + { + if (!(parser->state.flags & ARGP_NO_ERRS) + && parser->state.err_stream) + fprintf (parser->state.err_stream, + dgettext (parser->argp->argp_domain, + "%s: Too many arguments\n"), + parser->state.name); + err = EBADKEY; + } + } + + /* Okay, we're all done, with either an error or success; call the parsers + to indicate which one. */ + + if (err) + { + /* Maybe print an error message. */ + if (err == EBADKEY) + /* An appropriate message describing what the error was should have + been printed earlier. */ + __argp_state_help (&parser->state, parser->state.err_stream, + ARGP_HELP_STD_ERR); + + /* Since we didn't exit, give each parser an error indication. */ + for (group = parser->groups; group < parser->egroup; group++) + group_parse (group, &parser->state, ARGP_KEY_ERROR, 0); + } + else + /* Notify parsers of success, and propagate back values from parsers. */ + { + /* We pass over the groups in reverse order so that child groups are + given a chance to do there processing before passing back a value to + the parent. */ + for (group = parser->egroup - 1 + ; group >= parser->groups && (!err || err == EBADKEY) + ; group--) + err = group_parse (group, &parser->state, ARGP_KEY_SUCCESS, 0); + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + } + + /* Call parsers once more, to do any final cleanup. Errors are ignored. */ + for (group = parser->egroup - 1; group >= parser->groups; group--) + group_parse (group, &parser->state, ARGP_KEY_FINI, 0); + + if (err == EBADKEY) + err = EINVAL; + + free (parser->storage); + + return err; +} + +/* Call the user parsers to parse the non-option argument VAL, at the current + position, returning any error. The state NEXT pointer is assumed to have + been adjusted (by getopt) to point after this argument; this function will + adjust it correctly to reflect however many args actually end up being + consumed. */ +static error_t +parser_parse_arg (struct parser *parser, char *val) +{ + /* Save the starting value of NEXT, first adjusting it so that the arg + we're parsing is again the front of the arg vector. */ + int index = --parser->state.next; + error_t err = EBADKEY; + struct group *group; + int key = 0; /* Which of ARGP_KEY_ARG[S] we used. */ + + /* Try to parse the argument in each parser. */ + for (group = parser->groups + ; group < parser->egroup && err == EBADKEY + ; group++) + { + parser->state.next++; /* For ARGP_KEY_ARG, consume the arg. */ + key = ARGP_KEY_ARG; + err = group_parse (group, &parser->state, key, val); + + if (err == EBADKEY) + /* This parser doesn't like ARGP_KEY_ARG; try ARGP_KEY_ARGS instead. */ + { + parser->state.next--; /* For ARGP_KEY_ARGS, put back the arg. */ + key = ARGP_KEY_ARGS; + err = group_parse (group, &parser->state, key, 0); + } + } + + if (! err) + { + if (key == ARGP_KEY_ARGS) + /* The default for ARGP_KEY_ARGS is to assume that if NEXT isn't + changed by the user, *all* arguments should be considered + consumed. */ + parser->state.next = parser->state.argc; + + if (parser->state.next > index) + /* Remember that we successfully processed a non-option + argument -- but only if the user hasn't gotten tricky and set + the clock back. */ + (--group)->args_processed += (parser->state.next - index); + else + /* The user wants to reparse some args, give getopt another try. */ + parser->try_getopt = 1; + } + + return err; +} + +/* Call the user parsers to parse the option OPT, with argument VAL, at the + current position, returning any error. */ +static error_t +parser_parse_opt (struct parser *parser, int opt, char *val) +{ + /* The group key encoded in the high bits; 0 for short opts or + group_number + 1 for long opts. */ + int group_key = opt >> USER_BITS; + error_t err = EBADKEY; + + if (group_key == 0) + /* A short option. By comparing OPT's position in SHORT_OPTS to the + various starting positions in each group's SHORT_END field, we can + determine which group OPT came from. */ + { + struct group *group; + char *short_index = strchr (parser->short_opts, opt); + + if (short_index) + for (group = parser->groups; group < parser->egroup; group++) + if (group->short_end > short_index) + { + err = group_parse (group, &parser->state, opt, + parser->opt_data.optarg); + break; + } + } + else + /* A long option. We use shifts instead of masking for extracting + the user value in order to preserve the sign. */ + err = + group_parse (&parser->groups[group_key - 1], &parser->state, + (opt << GROUP_BITS) >> GROUP_BITS, + parser->opt_data.optarg); + + if (err == EBADKEY) + /* At least currently, an option not recognized is an error in the + parser, because we pre-compute which parser is supposed to deal + with each option. */ + { + static const char bad_key_err[] = + N_("(PROGRAM ERROR) Option should have been recognized!?"); + if (group_key == 0) + __argp_error (&parser->state, "-%c: %s", opt, + dgettext (parser->argp->argp_domain, bad_key_err)); + else + { + struct option *long_opt = parser->long_opts; + while (long_opt->val != opt && long_opt->name) + long_opt++; + __argp_error (&parser->state, "--%s: %s", + long_opt->name ? long_opt->name : "???", + dgettext (parser->argp->argp_domain, bad_key_err)); + } + } + + return err; +} + +/* Parse the next argument in PARSER (as indicated by PARSER->state.next). + Any error from the parsers is returned, and *ARGP_EBADKEY indicates + whether a value of EBADKEY is due to an unrecognized argument (which is + generally not fatal). */ +static error_t +parser_parse_next (struct parser *parser, int *arg_ebadkey) +{ + int opt; + error_t err = 0; + + if (parser->state.quoted && parser->state.next < parser->state.quoted) + /* The next argument pointer has been moved to before the quoted + region, so pretend we never saw the quoting `--', and give getopt + another chance. If the user hasn't removed it, getopt will just + process it again. */ + parser->state.quoted = 0; + + if (parser->try_getopt && !parser->state.quoted) + /* Give getopt a chance to parse this. */ + { + /* Put it back in OPTIND for getopt. */ + parser->opt_data.optind = parser->state.next; + /* Distinguish KEY_ERR from a real option. */ + parser->opt_data.optopt = KEY_END; + if (parser->state.flags & ARGP_LONG_ONLY) + opt = _getopt_long_only_r (parser->state.argc, parser->state.argv, + parser->short_opts, parser->long_opts, 0, + &parser->opt_data); + else + opt = _getopt_long_r (parser->state.argc, parser->state.argv, + parser->short_opts, parser->long_opts, 0, + &parser->opt_data); + /* And see what getopt did. */ + parser->state.next = parser->opt_data.optind; + + if (opt == KEY_END) + /* Getopt says there are no more options, so stop using + getopt; we'll continue if necessary on our own. */ + { + parser->try_getopt = 0; + if (parser->state.next > 1 + && strcmp (parser->state.argv[parser->state.next - 1], QUOTE) + == 0) + /* Not only is this the end of the options, but it's a + `quoted' region, which may have args that *look* like + options, so we definitely shouldn't try to use getopt past + here, whatever happens. */ + parser->state.quoted = parser->state.next; + } + else if (opt == KEY_ERR && parser->opt_data.optopt != KEY_END) + /* KEY_ERR can have the same value as a valid user short + option, but in the case of a real error, getopt sets OPTOPT + to the offending character, which can never be KEY_END. */ + { + *arg_ebadkey = 0; + return EBADKEY; + } + } + else + opt = KEY_END; + + if (opt == KEY_END) + { + /* We're past what getopt considers the options. */ + if (parser->state.next >= parser->state.argc + || (parser->state.flags & ARGP_NO_ARGS)) + /* Indicate that we're done. */ + { + *arg_ebadkey = 1; + return EBADKEY; + } + else + /* A non-option arg; simulate what getopt might have done. */ + { + opt = KEY_ARG; + parser->opt_data.optarg = parser->state.argv[parser->state.next++]; + } + } + + if (opt == KEY_ARG) + /* A non-option argument; try each parser in turn. */ + err = parser_parse_arg (parser, parser->opt_data.optarg); + else + err = parser_parse_opt (parser, opt, parser->opt_data.optarg); + + if (err == EBADKEY) + *arg_ebadkey = (opt == KEY_END || opt == KEY_ARG); + + return err; +} + +/* Parse the options strings in ARGC & ARGV according to the argp in ARGP. + FLAGS is one of the ARGP_ flags above. If END_INDEX is non-NULL, the + index in ARGV of the first unparsed option is returned in it. If an + unknown option is present, EINVAL is returned; if some parser routine + returned a non-zero value, it is returned; otherwise 0 is returned. */ +error_t +__argp_parse (const struct argp *argp, int argc, char **argv, unsigned flags, + int *end_index, void *input) +{ + error_t err; + struct parser parser; + + /* If true, then err == EBADKEY is a result of a non-option argument failing + to be parsed (which in some cases isn't actually an error). */ + int arg_ebadkey = 0; + +#ifndef _LIBC + if (!(flags & ARGP_PARSE_ARGV0)) + { +#ifdef HAVE_DECL_PROGRAM_INVOCATION_NAME + if (!program_invocation_name) + program_invocation_name = argv[0]; +#endif +#ifdef HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME + if (!program_invocation_short_name) + program_invocation_short_name = __argp_base_name (argv[0]); +#endif + } +#endif + + if (! (flags & ARGP_NO_HELP)) + /* Add our own options. */ + { + struct argp_child *child = alloca (4 * sizeof (struct argp_child)); + struct argp *top_argp = alloca (sizeof (struct argp)); + + /* TOP_ARGP has no options, it just serves to group the user & default + argps. */ + memset (top_argp, 0, sizeof (*top_argp)); + top_argp->children = child; + + memset (child, 0, 4 * sizeof (struct argp_child)); + + if (argp) + (child++)->argp = argp; + (child++)->argp = &argp_default_argp; + if (argp_program_version || argp_program_version_hook) + (child++)->argp = &argp_version_argp; + child->argp = 0; + + argp = top_argp; + } + + /* Construct a parser for these arguments. */ + err = parser_init (&parser, argp, argc, argv, flags, input); + + if (! err) + /* Parse! */ + { + while (! err) + err = parser_parse_next (&parser, &arg_ebadkey); + err = parser_finalize (&parser, err, arg_ebadkey, end_index); + } + + return err; +} +#ifdef weak_alias +weak_alias (__argp_parse, argp_parse) +#endif + +/* Return the input field for ARGP in the parser corresponding to STATE; used + by the help routines. */ +void * +__argp_input (const struct argp *argp, const struct argp_state *state) +{ + if (state) + { + struct group *group; + struct parser *parser = state->pstate; + + for (group = parser->groups; group < parser->egroup; group++) + if (group->argp == argp) + return group->input; + } + + return 0; +} +#ifdef weak_alias +weak_alias (__argp_input, _argp_input) +#endif diff --git a/gnulib/argp-pin.c b/gnulib/argp-pin.c new file mode 100644 index 000000000..eda4d958e --- /dev/null +++ b/gnulib/argp-pin.c @@ -0,0 +1,27 @@ +/* Full and short program names for argp module + Copyright (C) 2005, 2009, 2010 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME +char *program_invocation_short_name = 0; +#endif +#ifndef HAVE_PROGRAM_INVOCATION_NAME +char *program_invocation_name = 0; +#endif + diff --git a/gnulib/argp-pv.c b/gnulib/argp-pv.c new file mode 100644 index 000000000..e3227d322 --- /dev/null +++ b/gnulib/argp-pv.c @@ -0,0 +1,34 @@ +/* Default definition for ARGP_PROGRAM_VERSION. + Copyright (C) 1996, 1997, 1999, 2006, 2009, 2010 Free Software Foundation, + Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +/* If set by the user program to a non-zero value, then a default option + --version is added (unless the ARGP_NO_HELP flag is used), which will + print this string followed by a newline and exit (unless the + ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ +const char *argp_program_version +/* This variable should be zero-initialized. On most systems, putting it into + BSS is sufficient. Not so on MacOS X 10.3 and 10.4, see + + . */ +#if defined __ELF__ + /* On ELF systems, variables in BSS behave well. */ +#else + = (const char *) 0 +#endif + ; diff --git a/gnulib/argp-pvh.c b/gnulib/argp-pvh.c new file mode 100644 index 000000000..fb98fc21c --- /dev/null +++ b/gnulib/argp-pvh.c @@ -0,0 +1,31 @@ +/* Default definition for ARGP_PROGRAM_VERSION_HOOK. + Copyright (C) 1996, 1997, 1999, 2004, 2009, 2010 Free Software Foundation, + Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "argp.h" + +/* If set by the user program to a non-zero value, then a default option + --version is added (unless the ARGP_NO_HELP flag is used), which calls + this function with a stream to print the version to and a pointer to the + current parsing state, and then exits (unless the ARGP_NO_EXIT flag is + used). This variable takes precedent over ARGP_PROGRAM_VERSION. */ +void (*argp_program_version_hook) (FILE *stream, struct argp_state *state) = NULL; diff --git a/gnulib/argp-version-etc.c b/gnulib/argp-version-etc.c new file mode 100644 index 000000000..f500a8f56 --- /dev/null +++ b/gnulib/argp-version-etc.c @@ -0,0 +1,38 @@ +/* Version hook for Argp. + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program. If not, see . */ + +#include +#include +#include +#include + +static const char *program_canonical_name; +static const char * const *program_authors; + +static void +version_etc_hook (FILE *stream, struct argp_state *state) +{ + version_etc_ar (stream, program_canonical_name, PACKAGE_NAME, VERSION, + program_authors); +} + +void +argp_version_setup (const char *name, const char * const *authors) +{ + argp_program_version_hook = version_etc_hook; + program_canonical_name = name; + program_authors = authors; +} diff --git a/gnulib/argp-version-etc.h b/gnulib/argp-version-etc.h new file mode 100644 index 000000000..7c12c0181 --- /dev/null +++ b/gnulib/argp-version-etc.h @@ -0,0 +1,40 @@ +/* Version hook for Argp. + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program. If not, see . */ + +#ifndef _ARGP_VERSION_ETC_H +#define _ARGP_VERSION_ETC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Setup standard display of the version information for the `--version' + option. NAME is the canonical program name, and AUTHORS is a NULL- + terminated array of author names. At least one author name must be + given. + + If NAME is NULL, the package name (as given by the PACKAGE macro) + is asumed to be the name of the program. + + This function is intended to be called before argp_parse(). +*/ +extern void argp_version_setup (const char *name, const char * const *authors); + +#ifdef __cplusplus +} +#endif + +#endif /* _ARGP_VERSION_ETC_H */ diff --git a/gnulib/argp-xinl.c b/gnulib/argp-xinl.c new file mode 100644 index 000000000..6e7e20bba --- /dev/null +++ b/gnulib/argp-xinl.c @@ -0,0 +1,42 @@ +/* Real definitions for extern inline functions in argp.h + Copyright (C) 1997, 1998, 2004, 2009, 2010 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined _LIBC || defined HAVE_FEATURES_H +# include +#endif + +#ifndef __USE_EXTERN_INLINES +# define __USE_EXTERN_INLINES 1 +#endif +#define ARGP_EI +#undef __OPTIMIZE__ +#define __OPTIMIZE__ 1 +#include "argp.h" + +/* Add weak aliases. */ +#if _LIBC - 0 && defined (weak_alias) + +weak_alias (__argp_usage, argp_usage) +weak_alias (__option_is_short, _option_is_short) +weak_alias (__option_is_end, _option_is_end) + +#endif diff --git a/gnulib/argp.h b/gnulib/argp.h new file mode 100644 index 000000000..3667224a9 --- /dev/null +++ b/gnulib/argp.h @@ -0,0 +1,645 @@ +/* Hierarchial argument parsing, layered over getopt. + Copyright (C) 1995-1999, 2003-2010 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + This program 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. + + This program 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 this program. If not, see . */ + +#ifndef _ARGP_H +#define _ARGP_H + +#include +#include +#include +#include + +#define __need_error_t +#include + +#ifndef __THROW +# define __THROW +#endif +#ifndef __NTH +# define __NTH(fct) fct __THROW +#endif + +#ifndef __attribute__ +/* The __attribute__ feature is available in gcc versions 2.5 and later. + The __-protected variants of the attributes 'format' and 'printf' are + accepted by gcc versions 2.6.4 (effectively 2.7) and later. + We enable __attribute__ only if these are supported too, because + gnulib and libintl do '#define printf __printf__' when they override + the 'printf' function. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __attribute__(Spec) /* empty */ +# endif +#endif + +/* GCC 2.95 and later have "__restrict"; C99 compilers have + "restrict", and "configure" may have defined "restrict". + Other compilers use __restrict, __restrict__, and _Restrict, and + 'configure' might #define 'restrict' to those words. */ +#ifndef __restrict +# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) +# if 199901L <= __STDC_VERSION__ +# define __restrict restrict +# else +# define __restrict +# endif +# endif +#endif + +#ifndef __error_t_defined +typedef int error_t; +# define __error_t_defined +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* A description of a particular option. A pointer to an array of + these is passed in the OPTIONS field of an argp structure. Each option + entry can correspond to one long option and/or one short option; more + names for the same option can be added by following an entry in an option + array with options having the OPTION_ALIAS flag set. */ +struct argp_option +{ + /* The long option name. For more than one name for the same option, you + can use following options with the OPTION_ALIAS flag set. */ + const char *name; + + /* What key is returned for this option. If > 0 and printable, then it's + also accepted as a short option. */ + int key; + + /* If non-NULL, this is the name of the argument associated with this + option, which is required unless the OPTION_ARG_OPTIONAL flag is set. */ + const char *arg; + + /* OPTION_ flags. */ + int flags; + + /* The doc string for this option. If both NAME and KEY are 0, This string + will be printed outdented from the normal option column, making it + useful as a group header (it will be the first thing printed in its + group); in this usage, it's conventional to end the string with a `:'. + + Write the initial value as N_("TEXT") if you want xgettext to collect + it into a POT file. */ + const char *doc; + + /* The group this option is in. In a long help message, options are sorted + alphabetically within each group, and the groups presented in the order + 0, 1, 2, ..., n, -m, ..., -2, -1. Every entry in an options array with + if this field 0 will inherit the group number of the previous entry, or + zero if it's the first one, unless its a group header (NAME and KEY both + 0), in which case, the previous entry + 1 is the default. Automagic + options such as --help are put into group -1. */ + int group; +}; + +/* The argument associated with this option is optional. */ +#define OPTION_ARG_OPTIONAL 0x1 + +/* This option isn't displayed in any help messages. */ +#define OPTION_HIDDEN 0x2 + +/* This option is an alias for the closest previous non-alias option. This + means that it will be displayed in the same help entry, and will inherit + fields other than NAME and KEY from the aliased option. */ +#define OPTION_ALIAS 0x4 + +/* This option isn't actually an option (and so should be ignored by the + actual option parser), but rather an arbitrary piece of documentation that + should be displayed in much the same manner as the options. If this flag + is set, then the option NAME field is displayed unmodified (e.g., no `--' + prefix is added) at the left-margin (where a *short* option would normally + be displayed), and the documentation string in the normal place. The NAME + field will be translated using gettext, unless OPTION_NO_TRANS is set (see + below). For purposes of sorting, any leading whitespace and punctuation is + ignored, except that if the first non-whitespace character is not `-', this + entry is displayed after all options (and OPTION_DOC entries with a leading + `-') in the same group. */ +#define OPTION_DOC 0x8 + +/* This option shouldn't be included in `long' usage messages (but is still + included in help messages). This is mainly intended for options that are + completely documented in an argp's ARGS_DOC field, in which case including + the option in the generic usage list would be redundant. For instance, + if ARGS_DOC is "FOO BAR\n-x BLAH", and the `-x' option's purpose is to + distinguish these two cases, -x should probably be marked + OPTION_NO_USAGE. */ +#define OPTION_NO_USAGE 0x10 + +/* Valid only in conjunction with OPTION_DOC. This option disables translation + of option name. */ +#define OPTION_NO_TRANS 0x20 + + +struct argp; /* fwd declare this type */ +struct argp_state; /* " */ +struct argp_child; /* " */ + +/* The type of a pointer to an argp parsing function. */ +typedef error_t (*argp_parser_t) (int key, char *arg, + struct argp_state *state); + +/* What to return for unrecognized keys. For special ARGP_KEY_ keys, such + returns will simply be ignored. For user keys, this error will be turned + into EINVAL (if the call to argp_parse is such that errors are propagated + back to the user instead of exiting); returning EINVAL itself would result + in an immediate stop to parsing in *all* cases. */ +#define ARGP_ERR_UNKNOWN E2BIG /* Hurd should never need E2BIG. XXX */ + +/* Special values for the KEY argument to an argument parsing function. + ARGP_ERR_UNKNOWN should be returned if they aren't understood. + + The sequence of keys to a parsing function is either (where each + uppercased word should be prefixed by `ARGP_KEY_' and opt is a user key): + + INIT opt... NO_ARGS END SUCCESS -- No non-option arguments at all + or INIT (opt | ARG)... END SUCCESS -- All non-option args parsed + or INIT (opt | ARG)... SUCCESS -- Some non-option arg unrecognized + + The third case is where every parser returned ARGP_KEY_UNKNOWN for an + argument, in which case parsing stops at that argument (returning the + unparsed arguments to the caller of argp_parse if requested, or stopping + with an error message if not). + + If an error occurs (either detected by argp, or because the parsing + function returned an error value), then the parser is called with + ARGP_KEY_ERROR, and no further calls are made. */ + +/* This is not an option at all, but rather a command line argument. If a + parser receiving this key returns success, the fact is recorded, and the + ARGP_KEY_NO_ARGS case won't be used. HOWEVER, if while processing the + argument, a parser function decrements the NEXT field of the state it's + passed, the option won't be considered processed; this is to allow you to + actually modify the argument (perhaps into an option), and have it + processed again. */ +#define ARGP_KEY_ARG 0 +/* There are remaining arguments not parsed by any parser, which may be found + starting at (STATE->argv + STATE->next). If success is returned, but + STATE->next left untouched, it's assumed that all arguments were consume, + otherwise, the parser should adjust STATE->next to reflect any arguments + consumed. */ +#define ARGP_KEY_ARGS 0x1000006 +/* There are no more command line arguments at all. */ +#define ARGP_KEY_END 0x1000001 +/* Because it's common to want to do some special processing if there aren't + any non-option args, user parsers are called with this key if they didn't + successfully process any non-option arguments. Called just before + ARGP_KEY_END (where more general validity checks on previously parsed + arguments can take place). */ +#define ARGP_KEY_NO_ARGS 0x1000002 +/* Passed in before any parsing is done. Afterwards, the values of each + element of the CHILD_INPUT field, if any, in the state structure is + copied to each child's state to be the initial value of the INPUT field. */ +#define ARGP_KEY_INIT 0x1000003 +/* Use after all other keys, including SUCCESS & END. */ +#define ARGP_KEY_FINI 0x1000007 +/* Passed in when parsing has successfully been completed (even if there are + still arguments remaining). */ +#define ARGP_KEY_SUCCESS 0x1000004 +/* Passed in if an error occurs. */ +#define ARGP_KEY_ERROR 0x1000005 + +/* An argp structure contains a set of options declarations, a function to + deal with parsing one, documentation string, a possible vector of child + argp's, and perhaps a function to filter help output. When actually + parsing options, getopt is called with the union of all the argp + structures chained together through their CHILD pointers, with conflicts + being resolved in favor of the first occurrence in the chain. */ +struct argp +{ + /* An array of argp_option structures, terminated by an entry with both + NAME and KEY having a value of 0. */ + const struct argp_option *options; + + /* What to do with an option from this structure. KEY is the key + associated with the option, and ARG is any associated argument (NULL if + none was supplied). If KEY isn't understood, ARGP_ERR_UNKNOWN should be + returned. If a non-zero, non-ARGP_ERR_UNKNOWN value is returned, then + parsing is stopped immediately, and that value is returned from + argp_parse(). For special (non-user-supplied) values of KEY, see the + ARGP_KEY_ definitions below. */ + argp_parser_t parser; + + /* A string describing what other arguments are wanted by this program. It + is only used by argp_usage to print the `Usage:' message. If it + contains newlines, the strings separated by them are considered + alternative usage patterns, and printed on separate lines (lines after + the first are prefix by ` or: ' instead of `Usage:'). */ + const char *args_doc; + + /* If non-NULL, a string containing extra text to be printed before and + after the options in a long help message (separated by a vertical tab + `\v' character). + Write the initial value as N_("BEFORE-TEXT") "\v" N_("AFTER-TEXT") if + you want xgettext to collect the two pieces of text into a POT file. */ + const char *doc; + + /* A vector of argp_children structures, terminated by a member with a 0 + argp field, pointing to child argps should be parsed with this one. Any + conflicts are resolved in favor of this argp, or early argps in the + CHILDREN list. This field is useful if you use libraries that supply + their own argp structure, which you want to use in conjunction with your + own. */ + const struct argp_child *children; + + /* If non-zero, this should be a function to filter the output of help + messages. KEY is either a key from an option, in which case TEXT is + that option's help text, or a special key from the ARGP_KEY_HELP_ + defines, below, describing which other help text TEXT is. The function + should return either TEXT, if it should be used as-is, a replacement + string, which should be malloced, and will be freed by argp, or NULL, + meaning `print nothing'. The value for TEXT is *after* any translation + has been done, so if any of the replacement text also needs translation, + that should be done by the filter function. INPUT is either the input + supplied to argp_parse, or NULL, if argp_help was called directly. */ + char *(*help_filter) (int __key, const char *__text, void *__input); + + /* If non-zero the strings used in the argp library are translated using + the domain described by this string. Otherwise the currently installed + default domain is used. */ + const char *argp_domain; +}; + +/* Possible KEY arguments to a help filter function. */ +#define ARGP_KEY_HELP_PRE_DOC 0x2000001 /* Help text preceeding options. */ +#define ARGP_KEY_HELP_POST_DOC 0x2000002 /* Help text following options. */ +#define ARGP_KEY_HELP_HEADER 0x2000003 /* Option header string. */ +#define ARGP_KEY_HELP_EXTRA 0x2000004 /* After all other documentation; + TEXT is NULL for this key. */ +/* Explanatory note emitted when duplicate option arguments have been + suppressed. */ +#define ARGP_KEY_HELP_DUP_ARGS_NOTE 0x2000005 +#define ARGP_KEY_HELP_ARGS_DOC 0x2000006 /* Argument doc string. */ + +/* When an argp has a non-zero CHILDREN field, it should point to a vector of + argp_child structures, each of which describes a subsidiary argp. */ +struct argp_child +{ + /* The child parser. */ + const struct argp *argp; + + /* Flags for this child. */ + int flags; + + /* If non-zero, an optional header to be printed in help output before the + child options. As a side-effect, a non-zero value forces the child + options to be grouped together; to achieve this effect without actually + printing a header string, use a value of "". */ + const char *header; + + /* Where to group the child options relative to the other (`consolidated') + options in the parent argp; the values are the same as the GROUP field + in argp_option structs, but all child-groupings follow parent options at + a particular group level. If both this field and HEADER are zero, then + they aren't grouped at all, but rather merged with the parent options + (merging the child's grouping levels with the parents). */ + int group; +}; + +/* Parsing state. This is provided to parsing functions called by argp, + which may examine and, as noted, modify fields. */ +struct argp_state +{ + /* The top level ARGP being parsed. */ + const struct argp *root_argp; + + /* The argument vector being parsed. May be modified. */ + int argc; + char **argv; + + /* The index in ARGV of the next arg that to be parsed. May be modified. */ + int next; + + /* The flags supplied to argp_parse. May be modified. */ + unsigned flags; + + /* While calling a parsing function with a key of ARGP_KEY_ARG, this is the + number of the current arg, starting at zero, and incremented after each + such call returns. At all other times, this is the number of such + arguments that have been processed. */ + unsigned arg_num; + + /* If non-zero, the index in ARGV of the first argument following a special + `--' argument (which prevents anything following being interpreted as an + option). Only set once argument parsing has proceeded past this point. */ + int quoted; + + /* An arbitrary pointer passed in from the user. */ + void *input; + /* Values to pass to child parsers. This vector will be the same length as + the number of children for the current parser. */ + void **child_inputs; + + /* For the parser's use. Initialized to 0. */ + void *hook; + + /* The name used when printing messages. This is initialized to ARGV[0], + or PROGRAM_INVOCATION_NAME if that is unavailable. */ + char *name; + + /* Streams used when argp prints something. */ + FILE *err_stream; /* For errors; initialized to stderr. */ + FILE *out_stream; /* For information; initialized to stdout. */ + + void *pstate; /* Private, for use by argp. */ +}; + +/* Flags for argp_parse (note that the defaults are those that are + convenient for program command line parsing): */ + +/* Don't ignore the first element of ARGV. Normally (and always unless + ARGP_NO_ERRS is set) the first element of the argument vector is + skipped for option parsing purposes, as it corresponds to the program name + in a command line. */ +#define ARGP_PARSE_ARGV0 0x01 + +/* Don't print error messages for unknown options to stderr; unless this flag + is set, ARGP_PARSE_ARGV0 is ignored, as ARGV[0] is used as the program + name in the error messages. This flag implies ARGP_NO_EXIT (on the + assumption that silent exiting upon errors is bad behaviour). */ +#define ARGP_NO_ERRS 0x02 + +/* Don't parse any non-option args. Normally non-option args are parsed by + calling the parse functions with a key of ARGP_KEY_ARG, and the actual arg + as the value. Since it's impossible to know which parse function wants to + handle it, each one is called in turn, until one returns 0 or an error + other than ARGP_ERR_UNKNOWN; if an argument is handled by no one, the + argp_parse returns prematurely (but with a return value of 0). If all + args have been parsed without error, all parsing functions are called one + last time with a key of ARGP_KEY_END. This flag needn't normally be set, + as the normal behavior is to stop parsing as soon as some argument can't + be handled. */ +#define ARGP_NO_ARGS 0x04 + +/* Parse options and arguments in the same order they occur on the command + line -- normally they're rearranged so that all options come first. */ +#define ARGP_IN_ORDER 0x08 + +/* Don't provide the standard long option --help, which causes usage and + option help information to be output to stdout, and exit (0) called. */ +#define ARGP_NO_HELP 0x10 + +/* Don't exit on errors (they may still result in error messages). */ +#define ARGP_NO_EXIT 0x20 + +/* Use the gnu getopt `long-only' rules for parsing arguments. */ +#define ARGP_LONG_ONLY 0x40 + +/* Turns off any message-printing/exiting options. */ +#define ARGP_SILENT (ARGP_NO_EXIT | ARGP_NO_ERRS | ARGP_NO_HELP) + +/* Parse the options strings in ARGC & ARGV according to the options in ARGP. + FLAGS is one of the ARGP_ flags above. If ARG_INDEX is non-NULL, the + index in ARGV of the first unparsed option is returned in it. If an + unknown option is present, ARGP_ERR_UNKNOWN is returned; if some parser + routine returned a non-zero value, it is returned; otherwise 0 is + returned. This function may also call exit unless the ARGP_NO_HELP flag + is set. INPUT is a pointer to a value to be passed in to the parser. */ +extern error_t argp_parse (const struct argp *__restrict __argp, + int /*argc*/, char **__restrict /*argv*/, + unsigned __flags, int *__restrict __arg_index, + void *__restrict __input); +extern error_t __argp_parse (const struct argp *__restrict __argp, + int /*argc*/, char **__restrict /*argv*/, + unsigned __flags, int *__restrict __arg_index, + void *__restrict __input); + +/* Global variables. */ + +/* GNULIB makes sure both program_invocation_name and + program_invocation_short_name are available */ +#ifdef GNULIB_PROGRAM_INVOCATION_NAME +extern char *program_invocation_name; +# undef HAVE_DECL_PROGRAM_INVOCATION_NAME +# define HAVE_DECL_PROGRAM_INVOCATION_NAME 1 +#endif + +#ifdef GNULIB_PROGRAM_INVOCATION_SHORT_NAME +extern char *program_invocation_short_name; +# undef HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME +# define HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME 1 +#endif + +/* If defined or set by the user program to a non-zero value, then a default + option --version is added (unless the ARGP_NO_HELP flag is used), which + will print this string followed by a newline and exit (unless the + ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ +extern const char *argp_program_version; + +/* If defined or set by the user program to a non-zero value, then a default + option --version is added (unless the ARGP_NO_HELP flag is used), which + calls this function with a stream to print the version to and a pointer to + the current parsing state, and then exits (unless the ARGP_NO_EXIT flag is + used). This variable takes precedent over ARGP_PROGRAM_VERSION. */ +extern void (*argp_program_version_hook) (FILE *__restrict __stream, + struct argp_state *__restrict + __state); + +/* If defined or set by the user program, it should point to string that is + the bug-reporting address for the program. It will be printed by + argp_help if the ARGP_HELP_BUG_ADDR flag is set (as it is by various + standard help messages), embedded in a sentence that says something like + `Report bugs to ADDR.'. */ +extern const char *argp_program_bug_address; + +/* The exit status that argp will use when exiting due to a parsing error. + If not defined or set by the user program, this defaults to EX_USAGE from + . */ +extern error_t argp_err_exit_status; + +/* Flags for argp_help. */ +#define ARGP_HELP_USAGE 0x01 /* a Usage: message. */ +#define ARGP_HELP_SHORT_USAGE 0x02 /* " but don't actually print options. */ +#define ARGP_HELP_SEE 0x04 /* a `Try ... for more help' message. */ +#define ARGP_HELP_LONG 0x08 /* a long help message. */ +#define ARGP_HELP_PRE_DOC 0x10 /* doc string preceding long help. */ +#define ARGP_HELP_POST_DOC 0x20 /* doc string following long help. */ +#define ARGP_HELP_DOC (ARGP_HELP_PRE_DOC | ARGP_HELP_POST_DOC) +#define ARGP_HELP_BUG_ADDR 0x40 /* bug report address */ +#define ARGP_HELP_LONG_ONLY 0x80 /* modify output appropriately to + reflect ARGP_LONG_ONLY mode. */ + +/* These ARGP_HELP flags are only understood by argp_state_help. */ +#define ARGP_HELP_EXIT_ERR 0x100 /* Call exit(1) instead of returning. */ +#define ARGP_HELP_EXIT_OK 0x200 /* Call exit(0) instead of returning. */ + +/* The standard thing to do after a program command line parsing error, if an + error message has already been printed. */ +#define ARGP_HELP_STD_ERR \ + (ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) +/* The standard thing to do after a program command line parsing error, if no + more specific error message has been printed. */ +#define ARGP_HELP_STD_USAGE \ + (ARGP_HELP_SHORT_USAGE | ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) +/* The standard thing to do in response to a --help option. */ +#define ARGP_HELP_STD_HELP \ + (ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_EXIT_OK \ + | ARGP_HELP_DOC | ARGP_HELP_BUG_ADDR) + +/* Output a usage message for ARGP to STREAM. FLAGS are from the set + ARGP_HELP_*. */ +extern void argp_help (const struct argp *__restrict __argp, + FILE *__restrict __stream, + unsigned __flags, char *__restrict __name); +extern void __argp_help (const struct argp *__restrict __argp, + FILE *__restrict __stream, unsigned __flags, + char *__name); + +/* The following routines are intended to be called from within an argp + parsing routine (thus taking an argp_state structure as the first + argument). They may or may not print an error message and exit, depending + on the flags in STATE -- in any case, the caller should be prepared for + them *not* to exit, and should return an appropiate error after calling + them. [argp_usage & argp_error should probably be called argp_state_..., + but they're used often enough that they should be short] */ + +/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are + from the set ARGP_HELP_*. */ +extern void argp_state_help (const struct argp_state *__restrict __state, + FILE *__restrict __stream, + unsigned int __flags); +extern void __argp_state_help (const struct argp_state *__restrict __state, + FILE *__restrict __stream, + unsigned int __flags); + +#if _LIBC || !defined __USE_EXTERN_INLINES +/* Possibly output the standard usage message for ARGP to stderr and exit. */ +extern void argp_usage (const struct argp_state *__state); +extern void __argp_usage (const struct argp_state *__state); +#endif + +/* If appropriate, print the printf string FMT and following args, preceded + by the program name and `:', to stderr, and followed by a `Try ... --help' + message, then exit (1). */ +extern void argp_error (const struct argp_state *__restrict __state, + const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +extern void __argp_error (const struct argp_state *__restrict __state, + const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); + +/* Similar to the standard gnu error-reporting function error(), but will + respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print + to STATE->err_stream. This is useful for argument parsing code that is + shared between program startup (when exiting is desired) and runtime + option parsing (when typically an error code is returned instead). The + difference between this function and argp_error is that the latter is for + *parsing errors*, and the former is for other problems that occur during + parsing but don't reflect a (syntactic) problem with the input. */ +extern void argp_failure (const struct argp_state *__restrict __state, + int __status, int __errnum, + const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); +extern void __argp_failure (const struct argp_state *__restrict __state, + int __status, int __errnum, + const char *__restrict __fmt, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); + +#if _LIBC || !defined __USE_EXTERN_INLINES +/* Returns true if the option OPT is a valid short option. */ +extern int _option_is_short (const struct argp_option *__opt) __THROW; +extern int __option_is_short (const struct argp_option *__opt) __THROW; + +/* Returns true if the option OPT is in fact the last (unused) entry in an + options array. */ +extern int _option_is_end (const struct argp_option *__opt) __THROW; +extern int __option_is_end (const struct argp_option *__opt) __THROW; +#endif + +/* Return the input field for ARGP in the parser corresponding to STATE; used + by the help routines. */ +extern void *_argp_input (const struct argp *__restrict __argp, + const struct argp_state *__restrict __state) + __THROW; +extern void *__argp_input (const struct argp *__restrict __argp, + const struct argp_state *__restrict __state) + __THROW; + +#ifdef __USE_EXTERN_INLINES + +# if !_LIBC +# define __argp_usage argp_usage +# define __argp_state_help argp_state_help +# define __option_is_short _option_is_short +# define __option_is_end _option_is_end +# endif + +# ifndef ARGP_EI +# ifdef __GNUC__ + /* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99 + inline semantics, unless -fgnu89-inline is used. It defines a macro + __GNUC_STDC_INLINE__ to indicate this situation or a macro + __GNUC_GNU_INLINE__ to indicate the opposite situation. + GCC 4.2 with -std=c99 or -std=gnu99 implements the GNU C inline + semantics but warns, unless -fgnu89-inline is used: + warning: C99 inline functions are not supported; using GNU89 + warning: to disable this warning use -fgnu89-inline or the gnu_inline function attribute + It defines a macro __GNUC_GNU_INLINE__ to indicate this situation. */ +# if defined __GNUC_STDC_INLINE__ +# define ARGP_EI __inline__ +# elif defined __GNUC_GNU_INLINE__ +# define ARGP_EI extern __inline__ __attribute__ ((__gnu_inline__)) +# else +# define ARGP_EI extern __inline__ +# endif +# else + /* With other compilers, assume the ISO C99 meaning of 'inline', if + the compiler supports 'inline' at all. */ +# define ARGP_EI inline +# endif +# endif + +ARGP_EI void +__argp_usage (const struct argp_state *__state) +{ + __argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE); +} + +ARGP_EI int +__NTH (__option_is_short (const struct argp_option *__opt)) +{ + if (__opt->flags & OPTION_DOC) + return 0; + else + { + int __key = __opt->key; + return __key > 0 && __key <= UCHAR_MAX && isprint (__key); + } +} + +ARGP_EI int +__NTH (__option_is_end (const struct argp_option *__opt)) +{ + return !__opt->key && !__opt->name && !__opt->doc && !__opt->group; +} + +# if !_LIBC +# undef __argp_usage +# undef __argp_state_help +# undef __option_is_short +# undef __option_is_end +# endif +#endif /* Use extern inlines. */ + +#ifdef __cplusplus +} +#endif + +#endif /* argp.h */ diff --git a/gnulib/error.c b/gnulib/error.c index af2287b27..c79e8d42c 100644 --- a/gnulib/error.c +++ b/gnulib/error.c @@ -1,5 +1,5 @@ /* Error handler for noninteractive utilities - Copyright (C) 1990-1998, 2000-2007, 2009 Free Software Foundation, Inc. + Copyright (C) 1990-1998, 2000-2007, 2009-2010 Free Software Foundation, Inc. This file is part of the GNU C Library. This program is free software: you can redistribute it and/or modify @@ -70,8 +70,8 @@ unsigned int error_message_count; extern void __error (int status, int errnum, const char *message, ...) __attribute__ ((__format__ (__printf__, 3, 4))); extern void __error_at_line (int status, int errnum, const char *file_name, - unsigned int line_number, const char *message, - ...) + unsigned int line_number, const char *message, + ...) __attribute__ ((__format__ (__printf__, 5, 6)));; # define error __error # define error_at_line __error_at_line @@ -86,6 +86,7 @@ extern void __error_at_line (int status, int errnum, const char *file_name, #else /* not _LIBC */ # include +# include # if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P # ifndef HAVE_DECL_STRERROR_R @@ -100,8 +101,33 @@ extern char *program_name; # if HAVE_STRERROR_R || defined strerror_r # define __strerror_r strerror_r -# endif /* HAVE_STRERROR_R || defined strerror_r */ -#endif /* not _LIBC */ +# endif /* HAVE_STRERROR_R || defined strerror_r */ +#endif /* not _LIBC */ + +static inline void +flush_stdout (void) +{ +#if !_LIBC && defined F_GETFL + int stdout_fd; + +# if GNULIB_FREOPEN_SAFER + /* Use of gnulib's freopen-safer module normally ensures that + fileno (stdout) == 1 + whenever stdout is open. */ + stdout_fd = STDOUT_FILENO; +# else + /* POSIX states that fileno (stdout) after fclose is unspecified. But in + practice it is not a problem, because stdout is statically allocated and + the fd of a FILE stream is stored as a field in its allocated memory. */ + stdout_fd = fileno (stdout); +# endif + /* POSIX states that fflush (stdout) after fclose is unspecified; it + is safe in glibc, but not on all other platforms. fflush (NULL) + is always defined, but too draconian. */ + if (0 <= stdout_fd && 0 <= fcntl (stdout_fd, F_GETFL)) +#endif + fflush (stdout); +} static void print_errno_message (int errnum) @@ -149,58 +175,58 @@ error_tail (int status, int errnum, const char *message, va_list args) bool use_malloc = false; while (1) - { - if (__libc_use_alloca (len * sizeof (wchar_t))) - wmessage = (wchar_t *) alloca (len * sizeof (wchar_t)); - else - { - if (!use_malloc) - wmessage = NULL; + { + if (__libc_use_alloca (len * sizeof (wchar_t))) + wmessage = (wchar_t *) alloca (len * sizeof (wchar_t)); + else + { + if (!use_malloc) + wmessage = NULL; - wchar_t *p = (wchar_t *) realloc (wmessage, - len * sizeof (wchar_t)); - if (p == NULL) - { - free (wmessage); - fputws_unlocked (L"out of memory\n", stderr); - return; - } - wmessage = p; - use_malloc = true; - } + wchar_t *p = (wchar_t *) realloc (wmessage, + len * sizeof (wchar_t)); + if (p == NULL) + { + free (wmessage); + fputws_unlocked (L"out of memory\n", stderr); + return; + } + wmessage = p; + use_malloc = true; + } - memset (&st, '\0', sizeof (st)); - tmp = message; + memset (&st, '\0', sizeof (st)); + tmp = message; - res = mbsrtowcs (wmessage, &tmp, len, &st); - if (res != len) - break; + res = mbsrtowcs (wmessage, &tmp, len, &st); + if (res != len) + break; - if (__builtin_expect (len >= SIZE_MAX / 2, 0)) - { - /* This really should not happen if everything is fine. */ - res = (size_t) -1; - break; - } + if (__builtin_expect (len >= SIZE_MAX / 2, 0)) + { + /* This really should not happen if everything is fine. */ + res = (size_t) -1; + break; + } - len *= 2; - } + len *= 2; + } if (res == (size_t) -1) - { - /* The string cannot be converted. */ - if (use_malloc) - { - free (wmessage); - use_malloc = false; - } - wmessage = (wchar_t *) L"???"; - } + { + /* The string cannot be converted. */ + if (use_malloc) + { + free (wmessage); + use_malloc = false; + } + wmessage = (wchar_t *) L"???"; + } __vfwprintf (stderr, wmessage, args); if (use_malloc) - free (wmessage); + free (wmessage); } else #endif @@ -235,16 +261,10 @@ error (int status, int errnum, const char *message, ...) cancellation. Therefore disable cancellation for now. */ int state = PTHREAD_CANCEL_ENABLE; __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), - 0); + 0); #endif -#if !_LIBC && defined F_GETFL - /* POSIX states that fflush (stdout) after fclose is unspecified; it - is safe in glibc, but not on all other platforms. fflush (NULL) - is always defined, but too draconian. */ - if (0 <= fcntl (1, F_GETFL)) -#endif - fflush (stdout); + flush_stdout (); #ifdef _LIBC _IO_flockfile (stderr); #endif @@ -276,7 +296,7 @@ int error_one_per_line; void error_at_line (int status, int errnum, const char *file_name, - unsigned int line_number, const char *message, ...) + unsigned int line_number, const char *message, ...) { va_list args; @@ -286,10 +306,10 @@ error_at_line (int status, int errnum, const char *file_name, static unsigned int old_line_number; if (old_line_number == line_number - && (file_name == old_file_name - || strcmp (old_file_name, file_name) == 0)) - /* Simply return and print nothing. */ - return; + && (file_name == old_file_name + || strcmp (old_file_name, file_name) == 0)) + /* Simply return and print nothing. */ + return; old_file_name = file_name; old_line_number = line_number; @@ -300,16 +320,10 @@ error_at_line (int status, int errnum, const char *file_name, cancellation. Therefore disable cancellation for now. */ int state = PTHREAD_CANCEL_ENABLE; __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), - 0); + 0); #endif -#if !_LIBC && defined F_GETFL - /* POSIX states that fflush (stdout) after fclose is unspecified; it - is safe in glibc, but not on all other platforms. fflush (NULL) - is always defined, but too draconian. */ - if (0 <= fcntl (1, F_GETFL)) -#endif - fflush (stdout); + flush_stdout (); #ifdef _LIBC _IO_flockfile (stderr); #endif @@ -326,10 +340,10 @@ error_at_line (int status, int errnum, const char *file_name, #if _LIBC __fxprintf (NULL, file_name != NULL ? "%s:%d: " : " ", - file_name, line_number); + file_name, line_number); #else fprintf (stderr, file_name != NULL ? "%s:%d: " : " ", - file_name, line_number); + file_name, line_number); #endif va_start (args, message); diff --git a/gnulib/error.h b/gnulib/error.h index 6d4968114..9deef02d2 100644 --- a/gnulib/error.h +++ b/gnulib/error.h @@ -1,5 +1,6 @@ /* Declaration for error-reporting function - Copyright (C) 1995, 1996, 1997, 2003, 2006, 2008 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1997, 2003, 2006, 2008, 2009, 2010 Free Software + Foundation, Inc. This file is part of the GNU C Library. This program is free software: you can redistribute it and/or modify @@ -19,19 +20,18 @@ #define _ERROR_H 1 #ifndef __attribute__ -/* This feature is available in gcc versions 2.5 and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) -# define __attribute__(Spec) /* empty */ -# endif -/* The __-protected variants of `format' and `printf' attributes - are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +/* The __attribute__ feature is available in gcc versions 2.5 and later. + The __-protected variants of the attributes 'format' and 'printf' are + accepted by gcc versions 2.6.4 (effectively 2.7) and later. + We enable __attribute__ only if these are supported too, because + gnulib and libintl do '#define printf __printf__' when they override + the 'printf' function. */ # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) -# define __format__ format -# define __printf__ printf +# define __attribute__(Spec) /* empty */ # endif #endif -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -43,7 +43,7 @@ extern void error (int __status, int __errnum, const char *__format, ...) __attribute__ ((__format__ (__printf__, 3, 4))); extern void error_at_line (int __status, int __errnum, const char *__fname, - unsigned int __lineno, const char *__format, ...) + unsigned int __lineno, const char *__format, ...) __attribute__ ((__format__ (__printf__, 5, 6))); /* If NULL, error will flush stdout, then print on stderr the program @@ -58,7 +58,7 @@ extern unsigned int error_message_count; variable controls whether this mode is selected or not. */ extern int error_one_per_line; -#ifdef __cplusplus +#ifdef __cplusplus } #endif diff --git a/gnulib/fnmatch.c b/gnulib/fnmatch.c index 48bc8b5d2..f15dbb806 100644 --- a/gnulib/fnmatch.c +++ b/gnulib/fnmatch.c @@ -1,5 +1,5 @@ -/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007 - Free Software Foundation, Inc. +/* Copyright (C) 1991, 1992, 1993, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ /* Enable GNU extensions in fnmatch.h. */ #ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 +# define _GNU_SOURCE 1 #endif #if ! defined __builtin_expect && __GNUC__ < 3 @@ -89,7 +89,7 @@ extern int fnmatch (const char *pattern, const char *string, int flags); # define isblank(c) ((c) == ' ' || (c) == '\t') # endif -# define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) +# define STREQ(s1, s2) (strcmp (s1, s2) == 0) # if defined _LIBC || WIDE_CHAR_SUPPORT /* The GNU C library provides support for user-defined character classes @@ -109,25 +109,25 @@ extern int fnmatch (const char *pattern, const char *string, int flags); # endif # ifdef _LIBC -# define ISWCTYPE(WC, WT) __iswctype (WC, WT) +# define ISWCTYPE(WC, WT) __iswctype (WC, WT) # else -# define ISWCTYPE(WC, WT) iswctype (WC, WT) +# define ISWCTYPE(WC, WT) iswctype (WC, WT) # endif # if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC /* In this case we are implementing the multibyte character handling. */ -# define HANDLE_MULTIBYTE 1 +# define HANDLE_MULTIBYTE 1 # endif # else # define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ -# define IS_CHAR_CLASS(string) \ - (STREQ (string, "alpha") || STREQ (string, "upper") \ - || STREQ (string, "lower") || STREQ (string, "digit") \ - || STREQ (string, "alnum") || STREQ (string, "xdigit") \ - || STREQ (string, "space") || STREQ (string, "print") \ - || STREQ (string, "punct") || STREQ (string, "graph") \ +# define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ || STREQ (string, "cntrl") || STREQ (string, "blank")) # endif @@ -145,17 +145,17 @@ static int posixly_correct; /* Note that this evaluates C many times. */ # define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c)) -# define CHAR char -# define UCHAR unsigned char -# define INT int -# define FCT internal_fnmatch -# define EXT ext_match -# define END end_pattern -# define L_(CS) CS +# define CHAR char +# define UCHAR unsigned char +# define INT int +# define FCT internal_fnmatch +# define EXT ext_match +# define END end_pattern +# define L_(CS) CS # ifdef _LIBC -# define BTOWC(C) __btowc (C) +# define BTOWC(C) __btowc (C) # else -# define BTOWC(C) btowc (C) +# define BTOWC(C) btowc (C) # endif # define STRLEN(S) strlen (S) # define STRCAT(D, S) strcat (D, S) @@ -175,14 +175,14 @@ static int posixly_correct; # if HANDLE_MULTIBYTE # define FOLD(c) ((flags & FNM_CASEFOLD) ? towlower (c) : (c)) -# define CHAR wchar_t -# define UCHAR wint_t -# define INT wint_t -# define FCT internal_fnwmatch -# define EXT ext_wmatch -# define END end_wpattern -# define L_(CS) L##CS -# define BTOWC(C) (C) +# define CHAR wchar_t +# define UCHAR wint_t +# define INT wint_t +# define FCT internal_fnwmatch +# define EXT ext_wmatch +# define END end_wpattern +# define L_(CS) L##CS +# define BTOWC(C) (C) # ifdef _LIBC # define STRLEN(S) __wcslen (S) # define STRCAT(D, S) __wcscat (D, S) @@ -218,40 +218,40 @@ is_char_class (const wchar_t *wcs) /* Test for a printable character from the portable character set. */ # ifdef _LIBC if (*wcs < 0x20 || *wcs > 0x7e - || *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60) - return (wctype_t) 0; + || *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60) + return (wctype_t) 0; # else switch (*wcs) - { - case L' ': case L'!': case L'"': case L'#': case L'%': - case L'&': case L'\'': case L'(': case L')': case L'*': - case L'+': case L',': case L'-': case L'.': case L'/': - case L'0': case L'1': case L'2': case L'3': case L'4': - case L'5': case L'6': case L'7': case L'8': case L'9': - case L':': case L';': case L'<': case L'=': case L'>': - case L'?': - case L'A': case L'B': case L'C': case L'D': case L'E': - case L'F': case L'G': case L'H': case L'I': case L'J': - case L'K': case L'L': case L'M': case L'N': case L'O': - case L'P': case L'Q': case L'R': case L'S': case L'T': - case L'U': case L'V': case L'W': case L'X': case L'Y': - case L'Z': - case L'[': case L'\\': case L']': case L'^': case L'_': - case L'a': case L'b': case L'c': case L'd': case L'e': - case L'f': case L'g': case L'h': case L'i': case L'j': - case L'k': case L'l': case L'm': case L'n': case L'o': - case L'p': case L'q': case L'r': case L's': case L't': - case L'u': case L'v': case L'w': case L'x': case L'y': - case L'z': case L'{': case L'|': case L'}': case L'~': - break; - default: - return (wctype_t) 0; - } + { + case L' ': case L'!': case L'"': case L'#': case L'%': + case L'&': case L'\'': case L'(': case L')': case L'*': + case L'+': case L',': case L'-': case L'.': case L'/': + case L'0': case L'1': case L'2': case L'3': case L'4': + case L'5': case L'6': case L'7': case L'8': case L'9': + case L':': case L';': case L'<': case L'=': case L'>': + case L'?': + case L'A': case L'B': case L'C': case L'D': case L'E': + case L'F': case L'G': case L'H': case L'I': case L'J': + case L'K': case L'L': case L'M': case L'N': case L'O': + case L'P': case L'Q': case L'R': case L'S': case L'T': + case L'U': case L'V': case L'W': case L'X': case L'Y': + case L'Z': + case L'[': case L'\\': case L']': case L'^': case L'_': + case L'a': case L'b': case L'c': case L'd': case L'e': + case L'f': case L'g': case L'h': case L'i': case L'j': + case L'k': case L'l': case L'm': case L'n': case L'o': + case L'p': case L'q': case L'r': case L's': case L't': + case L'u': case L'v': case L'w': case L'x': case L'y': + case L'z': case L'{': case L'|': case L'}': case L'~': + break; + default: + return (wctype_t) 0; + } # endif /* Avoid overrunning the buffer. */ if (cp == s + CHAR_CLASS_MAX_LENGTH) - return (wctype_t) 0; + return (wctype_t) 0; *cp++ = (char) *wcs++; } @@ -287,58 +287,58 @@ fnmatch (const char *pattern, const char *string, int flags) int res; /* Calculate the size needed to convert the strings to - wide characters. */ + wide characters. */ memset (&ps, '\0', sizeof (ps)); patsize = mbsrtowcs (NULL, &pattern, 0, &ps) + 1; if (__builtin_expect (patsize != 0, 1)) - { - assert (mbsinit (&ps)); - strsize = mbsrtowcs (NULL, &string, 0, &ps) + 1; - if (__builtin_expect (strsize != 0, 1)) - { - assert (mbsinit (&ps)); - totsize = patsize + strsize; - if (__builtin_expect (! (patsize <= totsize - && totsize <= SIZE_MAX / sizeof (wchar_t)), - 0)) - { - errno = ENOMEM; - return -1; - } + { + assert (mbsinit (&ps)); + strsize = mbsrtowcs (NULL, &string, 0, &ps) + 1; + if (__builtin_expect (strsize != 0, 1)) + { + assert (mbsinit (&ps)); + totsize = patsize + strsize; + if (__builtin_expect (! (patsize <= totsize + && totsize <= SIZE_MAX / sizeof (wchar_t)), + 0)) + { + errno = ENOMEM; + return -1; + } - /* Allocate room for the wide characters. */ - if (__builtin_expect (totsize < ALLOCA_LIMIT, 1)) - wpattern = (wchar_t *) alloca (totsize * sizeof (wchar_t)); - else - { - wpattern = malloc (totsize * sizeof (wchar_t)); - if (__builtin_expect (! wpattern, 0)) - { - errno = ENOMEM; - return -1; - } - } - wstring = wpattern + patsize; + /* Allocate room for the wide characters. */ + if (__builtin_expect (totsize < ALLOCA_LIMIT, 1)) + wpattern = (wchar_t *) alloca (totsize * sizeof (wchar_t)); + else + { + wpattern = malloc (totsize * sizeof (wchar_t)); + if (__builtin_expect (! wpattern, 0)) + { + errno = ENOMEM; + return -1; + } + } + wstring = wpattern + patsize; - /* Convert the strings into wide characters. */ - mbsrtowcs (wpattern, &pattern, patsize, &ps); - assert (mbsinit (&ps)); - mbsrtowcs (wstring, &string, strsize, &ps); + /* Convert the strings into wide characters. */ + mbsrtowcs (wpattern, &pattern, patsize, &ps); + assert (mbsinit (&ps)); + mbsrtowcs (wstring, &string, strsize, &ps); - res = internal_fnwmatch (wpattern, wstring, wstring + strsize - 1, - flags & FNM_PERIOD, flags); + res = internal_fnwmatch (wpattern, wstring, wstring + strsize - 1, + flags & FNM_PERIOD, flags); - if (__builtin_expect (! (totsize < ALLOCA_LIMIT), 0)) - free (wpattern); - return res; - } - } + if (__builtin_expect (! (totsize < ALLOCA_LIMIT), 0)) + free (wpattern); + return res; + } + } } # endif /* HANDLE_MULTIBYTE */ return internal_fnmatch (pattern, string, string + strlen (string), - flags & FNM_PERIOD, flags); + flags & FNM_PERIOD, flags); } # ifdef _LIBC @@ -351,4 +351,4 @@ compat_symbol (libc, __fnmatch_old, fnmatch, GLIBC_2_0); libc_hidden_ver (__fnmatch, fnmatch) # endif -#endif /* _LIBC or not __GNU_LIBRARY__. */ +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/gnulib/fnmatch_loop.c b/gnulib/fnmatch_loop.c index c2182ffb0..8cd444404 100644 --- a/gnulib/fnmatch_loop.c +++ b/gnulib/fnmatch_loop.c @@ -1,5 +1,5 @@ -/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006 - Free Software Foundation, Inc. +/* Copyright (C) 1991, 1992, 1993, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2006, 2009, 2010 Free Software Foundation, Inc. This file is part of the GNU C Library. This program is free software; you can redistribute it and/or modify @@ -19,7 +19,7 @@ /* Match STRING against the file name pattern PATTERN, returning zero if it matches, nonzero if not. */ static int EXT (INT opt, const CHAR *pattern, const CHAR *string, - const CHAR *string_end, bool no_leading_period, int flags) + const CHAR *string_end, bool no_leading_period, int flags) internal_function; static const CHAR *END (const CHAR *patternp) internal_function; @@ -46,310 +46,310 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, c = FOLD (c); switch (c) - { - case L_('?'): - if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') - { - int res; + { + case L_('?'): + if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') + { + int res; - res = EXT (c, p, n, string_end, no_leading_period, - flags); - if (res != -1) - return res; - } + res = EXT (c, p, n, string_end, no_leading_period, + flags); + if (res != -1) + return res; + } - if (n == string_end) - return FNM_NOMATCH; - else if (*n == L_('/') && (flags & FNM_FILE_NAME)) - return FNM_NOMATCH; - else if (*n == L_('.') && no_leading_period) - return FNM_NOMATCH; - break; + if (n == string_end) + return FNM_NOMATCH; + else if (*n == L_('/') && (flags & FNM_FILE_NAME)) + return FNM_NOMATCH; + else if (*n == L_('.') && no_leading_period) + return FNM_NOMATCH; + break; - case L_('\\'): - if (!(flags & FNM_NOESCAPE)) - { - c = *p++; - if (c == L_('\0')) - /* Trailing \ loses. */ - return FNM_NOMATCH; - c = FOLD (c); - } - if (n == string_end || FOLD ((UCHAR) *n) != c) - return FNM_NOMATCH; - break; + case L_('\\'): + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + if (c == L_('\0')) + /* Trailing \ loses. */ + return FNM_NOMATCH; + c = FOLD (c); + } + if (n == string_end || FOLD ((UCHAR) *n) != c) + return FNM_NOMATCH; + break; - case L_('*'): - if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') - { - int res; + case L_('*'): + if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') + { + int res; - res = EXT (c, p, n, string_end, no_leading_period, - flags); - if (res != -1) - return res; - } + res = EXT (c, p, n, string_end, no_leading_period, + flags); + if (res != -1) + return res; + } - if (n != string_end && *n == L_('.') && no_leading_period) - return FNM_NOMATCH; + if (n != string_end && *n == L_('.') && no_leading_period) + return FNM_NOMATCH; - for (c = *p++; c == L_('?') || c == L_('*'); c = *p++) - { - if (*p == L_('(') && (flags & FNM_EXTMATCH) != 0) - { - const CHAR *endp = END (p); - if (endp != p) - { - /* This is a pattern. Skip over it. */ - p = endp; - continue; - } - } + for (c = *p++; c == L_('?') || c == L_('*'); c = *p++) + { + if (*p == L_('(') && (flags & FNM_EXTMATCH) != 0) + { + const CHAR *endp = END (p); + if (endp != p) + { + /* This is a pattern. Skip over it. */ + p = endp; + continue; + } + } - if (c == L_('?')) - { - /* A ? needs to match one character. */ - if (n == string_end) - /* There isn't another character; no match. */ - return FNM_NOMATCH; - else if (*n == L_('/') - && __builtin_expect (flags & FNM_FILE_NAME, 0)) - /* A slash does not match a wildcard under - FNM_FILE_NAME. */ - return FNM_NOMATCH; - else - /* One character of the string is consumed in matching - this ? wildcard, so *??? won't match if there are - less than three characters. */ - ++n; - } - } + if (c == L_('?')) + { + /* A ? needs to match one character. */ + if (n == string_end) + /* There isn't another character; no match. */ + return FNM_NOMATCH; + else if (*n == L_('/') + && __builtin_expect (flags & FNM_FILE_NAME, 0)) + /* A slash does not match a wildcard under + FNM_FILE_NAME. */ + return FNM_NOMATCH; + else + /* One character of the string is consumed in matching + this ? wildcard, so *??? won't match if there are + less than three characters. */ + ++n; + } + } - if (c == L_('\0')) - /* The wildcard(s) is/are the last element of the pattern. - If the name is a file name and contains another slash - this means it cannot match, unless the FNM_LEADING_DIR - flag is set. */ - { - int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH; + if (c == L_('\0')) + /* The wildcard(s) is/are the last element of the pattern. + If the name is a file name and contains another slash + this means it cannot match, unless the FNM_LEADING_DIR + flag is set. */ + { + int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH; - if (flags & FNM_FILE_NAME) - { - if (flags & FNM_LEADING_DIR) - result = 0; - else - { - if (MEMCHR (n, L_('/'), string_end - n) == NULL) - result = 0; - } - } + if (flags & FNM_FILE_NAME) + { + if (flags & FNM_LEADING_DIR) + result = 0; + else + { + if (MEMCHR (n, L_('/'), string_end - n) == NULL) + result = 0; + } + } - return result; - } - else - { - const CHAR *endp; + return result; + } + else + { + const CHAR *endp; - endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L_('/') : L_('\0'), - string_end - n); - if (endp == NULL) - endp = string_end; + endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L_('/') : L_('\0'), + string_end - n); + if (endp == NULL) + endp = string_end; - if (c == L_('[') - || (__builtin_expect (flags & FNM_EXTMATCH, 0) != 0 - && (c == L_('@') || c == L_('+') || c == L_('!')) - && *p == L_('('))) - { - int flags2 = ((flags & FNM_FILE_NAME) - ? flags : (flags & ~FNM_PERIOD)); - bool no_leading_period2 = no_leading_period; + if (c == L_('[') + || (__builtin_expect (flags & FNM_EXTMATCH, 0) != 0 + && (c == L_('@') || c == L_('+') || c == L_('!')) + && *p == L_('('))) + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + bool no_leading_period2 = no_leading_period; - for (--p; n < endp; ++n, no_leading_period2 = false) - if (FCT (p, n, string_end, no_leading_period2, flags2) - == 0) - return 0; - } - else if (c == L_('/') && (flags & FNM_FILE_NAME)) - { - while (n < string_end && *n != L_('/')) - ++n; - if (n < string_end && *n == L_('/') - && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags) - == 0)) - return 0; - } - else - { - int flags2 = ((flags & FNM_FILE_NAME) - ? flags : (flags & ~FNM_PERIOD)); - int no_leading_period2 = no_leading_period; + for (--p; n < endp; ++n, no_leading_period2 = false) + if (FCT (p, n, string_end, no_leading_period2, flags2) + == 0) + return 0; + } + else if (c == L_('/') && (flags & FNM_FILE_NAME)) + { + while (n < string_end && *n != L_('/')) + ++n; + if (n < string_end && *n == L_('/') + && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags) + == 0)) + return 0; + } + else + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + int no_leading_period2 = no_leading_period; - if (c == L_('\\') && !(flags & FNM_NOESCAPE)) - c = *p; - c = FOLD (c); - for (--p; n < endp; ++n, no_leading_period2 = false) - if (FOLD ((UCHAR) *n) == c - && (FCT (p, n, string_end, no_leading_period2, flags2) - == 0)) - return 0; - } - } + if (c == L_('\\') && !(flags & FNM_NOESCAPE)) + c = *p; + c = FOLD (c); + for (--p; n < endp; ++n, no_leading_period2 = false) + if (FOLD ((UCHAR) *n) == c + && (FCT (p, n, string_end, no_leading_period2, flags2) + == 0)) + return 0; + } + } - /* If we come here no match is possible with the wildcard. */ - return FNM_NOMATCH; + /* If we come here no match is possible with the wildcard. */ + return FNM_NOMATCH; - case L_('['): - { - /* Nonzero if the sense of the character class is inverted. */ - register bool not; - CHAR cold; - UCHAR fn; + case L_('['): + { + /* Nonzero if the sense of the character class is inverted. */ + register bool not; + CHAR cold; + UCHAR fn; - if (posixly_correct == 0) - posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; - if (n == string_end) - return FNM_NOMATCH; + if (n == string_end) + return FNM_NOMATCH; - if (*n == L_('.') && no_leading_period) - return FNM_NOMATCH; + if (*n == L_('.') && no_leading_period) + return FNM_NOMATCH; - if (*n == L_('/') && (flags & FNM_FILE_NAME)) - /* `/' cannot be matched. */ - return FNM_NOMATCH; + if (*n == L_('/') && (flags & FNM_FILE_NAME)) + /* `/' cannot be matched. */ + return FNM_NOMATCH; - not = (*p == L_('!') || (posixly_correct < 0 && *p == L_('^'))); - if (not) - ++p; + not = (*p == L_('!') || (posixly_correct < 0 && *p == L_('^'))); + if (not) + ++p; - fn = FOLD ((UCHAR) *n); + fn = FOLD ((UCHAR) *n); - c = *p++; - for (;;) - { - if (!(flags & FNM_NOESCAPE) && c == L_('\\')) - { - if (*p == L_('\0')) - return FNM_NOMATCH; - c = FOLD ((UCHAR) *p); - ++p; + c = *p++; + for (;;) + { + if (!(flags & FNM_NOESCAPE) && c == L_('\\')) + { + if (*p == L_('\0')) + return FNM_NOMATCH; + c = FOLD ((UCHAR) *p); + ++p; - goto normal_bracket; - } - else if (c == L_('[') && *p == L_(':')) - { - /* Leave room for the null. */ - CHAR str[CHAR_CLASS_MAX_LENGTH + 1]; - size_t c1 = 0; + goto normal_bracket; + } + else if (c == L_('[') && *p == L_(':')) + { + /* Leave room for the null. */ + CHAR str[CHAR_CLASS_MAX_LENGTH + 1]; + size_t c1 = 0; #if defined _LIBC || WIDE_CHAR_SUPPORT - wctype_t wt; + wctype_t wt; #endif - const CHAR *startp = p; + const CHAR *startp = p; - for (;;) - { - if (c1 == CHAR_CLASS_MAX_LENGTH) - /* The name is too long and therefore the pattern - is ill-formed. */ - return FNM_NOMATCH; + for (;;) + { + if (c1 == CHAR_CLASS_MAX_LENGTH) + /* The name is too long and therefore the pattern + is ill-formed. */ + return FNM_NOMATCH; - c = *++p; - if (c == L_(':') && p[1] == L_(']')) - { - p += 2; - break; - } - if (c < L_('a') || c >= L_('z')) - { - /* This cannot possibly be a character class name. - Match it as a normal range. */ - p = startp; - c = L_('['); - goto normal_bracket; - } - str[c1++] = c; - } - str[c1] = L_('\0'); + c = *++p; + if (c == L_(':') && p[1] == L_(']')) + { + p += 2; + break; + } + if (c < L_('a') || c >= L_('z')) + { + /* This cannot possibly be a character class name. + Match it as a normal range. */ + p = startp; + c = L_('['); + goto normal_bracket; + } + str[c1++] = c; + } + str[c1] = L_('\0'); #if defined _LIBC || WIDE_CHAR_SUPPORT - wt = IS_CHAR_CLASS (str); - if (wt == 0) - /* Invalid character class name. */ - return FNM_NOMATCH; + wt = IS_CHAR_CLASS (str); + if (wt == 0) + /* Invalid character class name. */ + return FNM_NOMATCH; # if defined _LIBC && ! WIDE_CHAR_VERSION - /* The following code is glibc specific but does - there a good job in speeding up the code since - we can avoid the btowc() call. */ - if (_ISCTYPE ((UCHAR) *n, wt)) - goto matched; + /* The following code is glibc specific but does + there a good job in speeding up the code since + we can avoid the btowc() call. */ + if (_ISCTYPE ((UCHAR) *n, wt)) + goto matched; # else - if (ISWCTYPE (BTOWC ((UCHAR) *n), wt)) - goto matched; + if (ISWCTYPE (BTOWC ((UCHAR) *n), wt)) + goto matched; # endif #else - if ((STREQ (str, L_("alnum")) && isalnum ((UCHAR) *n)) - || (STREQ (str, L_("alpha")) && isalpha ((UCHAR) *n)) - || (STREQ (str, L_("blank")) && isblank ((UCHAR) *n)) - || (STREQ (str, L_("cntrl")) && iscntrl ((UCHAR) *n)) - || (STREQ (str, L_("digit")) && isdigit ((UCHAR) *n)) - || (STREQ (str, L_("graph")) && isgraph ((UCHAR) *n)) - || (STREQ (str, L_("lower")) && islower ((UCHAR) *n)) - || (STREQ (str, L_("print")) && isprint ((UCHAR) *n)) - || (STREQ (str, L_("punct")) && ispunct ((UCHAR) *n)) - || (STREQ (str, L_("space")) && isspace ((UCHAR) *n)) - || (STREQ (str, L_("upper")) && isupper ((UCHAR) *n)) - || (STREQ (str, L_("xdigit")) && isxdigit ((UCHAR) *n))) - goto matched; + if ((STREQ (str, L_("alnum")) && isalnum ((UCHAR) *n)) + || (STREQ (str, L_("alpha")) && isalpha ((UCHAR) *n)) + || (STREQ (str, L_("blank")) && isblank ((UCHAR) *n)) + || (STREQ (str, L_("cntrl")) && iscntrl ((UCHAR) *n)) + || (STREQ (str, L_("digit")) && isdigit ((UCHAR) *n)) + || (STREQ (str, L_("graph")) && isgraph ((UCHAR) *n)) + || (STREQ (str, L_("lower")) && islower ((UCHAR) *n)) + || (STREQ (str, L_("print")) && isprint ((UCHAR) *n)) + || (STREQ (str, L_("punct")) && ispunct ((UCHAR) *n)) + || (STREQ (str, L_("space")) && isspace ((UCHAR) *n)) + || (STREQ (str, L_("upper")) && isupper ((UCHAR) *n)) + || (STREQ (str, L_("xdigit")) && isxdigit ((UCHAR) *n))) + goto matched; #endif - c = *p++; - } + c = *p++; + } #ifdef _LIBC - else if (c == L_('[') && *p == L_('=')) - { - UCHAR str[1]; - uint32_t nrules = - _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - const CHAR *startp = p; + else if (c == L_('[') && *p == L_('=')) + { + UCHAR str[1]; + uint32_t nrules = + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + const CHAR *startp = p; - c = *++p; - if (c == L_('\0')) - { - p = startp; - c = L_('['); - goto normal_bracket; - } - str[0] = c; + c = *++p; + if (c == L_('\0')) + { + p = startp; + c = L_('['); + goto normal_bracket; + } + str[0] = c; - c = *++p; - if (c != L_('=') || p[1] != L_(']')) - { - p = startp; - c = L_('['); - goto normal_bracket; - } - p += 2; + c = *++p; + if (c != L_('=') || p[1] != L_(']')) + { + p = startp; + c = L_('['); + goto normal_bracket; + } + p += 2; - if (nrules == 0) - { - if ((UCHAR) *n == str[0]) - goto matched; - } - else - { - const int32_t *table; + if (nrules == 0) + { + if ((UCHAR) *n == str[0]) + goto matched; + } + else + { + const int32_t *table; # if WIDE_CHAR_VERSION - const int32_t *weights; - const int32_t *extra; + const int32_t *weights; + const int32_t *extra; # else - const unsigned char *weights; - const unsigned char *extra; + const unsigned char *weights; + const unsigned char *extra; # endif - const int32_t *indirect; - int32_t idx; - const UCHAR *cp = (const UCHAR *) str; + const int32_t *indirect; + int32_t idx; + const UCHAR *cp = (const UCHAR *) str; - /* This #include defines a local function! */ + /* This #include defines a local function! */ # if WIDE_CHAR_VERSION # include # else @@ -357,605 +357,610 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, # endif # if WIDE_CHAR_VERSION - table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC); - weights = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC); - extra = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC); - indirect = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC); + table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC); + weights = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC); + extra = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC); + indirect = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC); # else - table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); - weights = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); - indirect = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); + table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); + weights = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); + indirect = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); # endif - idx = findidx (&cp); - if (idx != 0) - { - /* We found a table entry. Now see whether the - character we are currently at has the same - equivalance class value. */ - int len = weights[idx]; - int32_t idx2; - const UCHAR *np = (const UCHAR *) n; + idx = findidx (&cp); + if (idx != 0) + { + /* We found a table entry. Now see whether the + character we are currently at has the same + equivalance class value. */ + int len = weights[idx & 0xffffff]; + int32_t idx2; + const UCHAR *np = (const UCHAR *) n; - idx2 = findidx (&np); - if (idx2 != 0 && len == weights[idx2]) - { - int cnt = 0; + idx2 = findidx (&np); + if (idx2 != 0 + && (idx >> 24) == (idx2 >> 24) + && len == weights[idx2 & 0xffffff]) + { + int cnt = 0; - while (cnt < len - && (weights[idx + 1 + cnt] - == weights[idx2 + 1 + cnt])) - ++cnt; + idx &= 0xffffff; + idx2 &= 0xffffff; - if (cnt == len) - goto matched; - } - } - } + while (cnt < len + && (weights[idx + 1 + cnt] + == weights[idx2 + 1 + cnt])) + ++cnt; - c = *p++; - } + if (cnt == len) + goto matched; + } + } + } + + c = *p++; + } #endif - else if (c == L_('\0')) - /* [ (unterminated) loses. */ - return FNM_NOMATCH; - else - { - bool is_range = false; + else if (c == L_('\0')) + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + else + { + bool is_range = false; #ifdef _LIBC - bool is_seqval = false; + bool is_seqval = false; - if (c == L_('[') && *p == L_('.')) - { - uint32_t nrules = - _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - const CHAR *startp = p; - size_t c1 = 0; + if (c == L_('[') && *p == L_('.')) + { + uint32_t nrules = + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + const CHAR *startp = p; + size_t c1 = 0; - while (1) - { - c = *++p; - if (c == L_('.') && p[1] == L_(']')) - { - p += 2; - break; - } - if (c == '\0') - return FNM_NOMATCH; - ++c1; - } + while (1) + { + c = *++p; + if (c == L_('.') && p[1] == L_(']')) + { + p += 2; + break; + } + if (c == '\0') + return FNM_NOMATCH; + ++c1; + } - /* We have to handling the symbols differently in - ranges since then the collation sequence is - important. */ - is_range = *p == L_('-') && p[1] != L_('\0'); + /* We have to handling the symbols differently in + ranges since then the collation sequence is + important. */ + is_range = *p == L_('-') && p[1] != L_('\0'); - if (nrules == 0) - { - /* There are no names defined in the collation - data. Therefore we only accept the trivial - names consisting of the character itself. */ - if (c1 != 1) - return FNM_NOMATCH; + if (nrules == 0) + { + /* There are no names defined in the collation + data. Therefore we only accept the trivial + names consisting of the character itself. */ + if (c1 != 1) + return FNM_NOMATCH; - if (!is_range && *n == startp[1]) - goto matched; + if (!is_range && *n == startp[1]) + goto matched; - cold = startp[1]; - c = *p++; - } - else - { - int32_t table_size; - const int32_t *symb_table; + cold = startp[1]; + c = *p++; + } + else + { + int32_t table_size; + const int32_t *symb_table; # ifdef WIDE_CHAR_VERSION - char str[c1]; - size_t strcnt; + char str[c1]; + size_t strcnt; # else # define str (startp + 1) # endif - const unsigned char *extra; - int32_t idx; - int32_t elem; - int32_t second; - int32_t hash; + const unsigned char *extra; + int32_t idx; + int32_t elem; + int32_t second; + int32_t hash; # ifdef WIDE_CHAR_VERSION - /* We have to convert the name to a single-byte - string. This is possible since the names - consist of ASCII characters and the internal - representation is UCS4. */ - for (strcnt = 0; strcnt < c1; ++strcnt) - str[strcnt] = startp[1 + strcnt]; + /* We have to convert the name to a single-byte + string. This is possible since the names + consist of ASCII characters and the internal + representation is UCS4. */ + for (strcnt = 0; strcnt < c1; ++strcnt) + str[strcnt] = startp[1 + strcnt]; # endif - table_size = - _NL_CURRENT_WORD (LC_COLLATE, - _NL_COLLATE_SYMB_HASH_SIZEMB); - symb_table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_TABLEMB); - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_EXTRAMB); + table_size = + _NL_CURRENT_WORD (LC_COLLATE, + _NL_COLLATE_SYMB_HASH_SIZEMB); + symb_table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_TABLEMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_EXTRAMB); - /* Locate the character in the hashing table. */ - hash = elem_hash (str, c1); + /* Locate the character in the hashing table. */ + hash = elem_hash (str, c1); - idx = 0; - elem = hash % table_size; - if (symb_table[2 * elem] != 0) - { - second = hash % (table_size - 2) + 1; + idx = 0; + elem = hash % table_size; + if (symb_table[2 * elem] != 0) + { + second = hash % (table_size - 2) + 1; - do - { - /* First compare the hashing value. */ - if (symb_table[2 * elem] == hash - && (c1 - == extra[symb_table[2 * elem + 1]]) - && memcmp (str, - &extra[symb_table[2 * elem - + 1] - + 1], c1) == 0) - { - /* Yep, this is the entry. */ - idx = symb_table[2 * elem + 1]; - idx += 1 + extra[idx]; - break; - } + do + { + /* First compare the hashing value. */ + if (symb_table[2 * elem] == hash + && (c1 + == extra[symb_table[2 * elem + 1]]) + && memcmp (str, + &extra[symb_table[2 * elem + + 1] + + 1], c1) == 0) + { + /* Yep, this is the entry. */ + idx = symb_table[2 * elem + 1]; + idx += 1 + extra[idx]; + break; + } - /* Next entry. */ - elem += second; - } - while (symb_table[2 * elem] != 0); - } + /* Next entry. */ + elem += second; + } + while (symb_table[2 * elem] != 0); + } - if (symb_table[2 * elem] != 0) - { - /* Compare the byte sequence but only if - this is not part of a range. */ + if (symb_table[2 * elem] != 0) + { + /* Compare the byte sequence but only if + this is not part of a range. */ # ifdef WIDE_CHAR_VERSION - int32_t *wextra; + int32_t *wextra; - idx += 1 + extra[idx]; - /* Adjust for the alignment. */ - idx = (idx + 3) & ~3; + idx += 1 + extra[idx]; + /* Adjust for the alignment. */ + idx = (idx + 3) & ~3; - wextra = (int32_t *) &extra[idx + 4]; + wextra = (int32_t *) &extra[idx + 4]; # endif - if (! is_range) - { + if (! is_range) + { # ifdef WIDE_CHAR_VERSION - for (c1 = 0; - (int32_t) c1 < wextra[idx]; - ++c1) - if (n[c1] != wextra[1 + c1]) - break; + for (c1 = 0; + (int32_t) c1 < wextra[idx]; + ++c1) + if (n[c1] != wextra[1 + c1]) + break; - if ((int32_t) c1 == wextra[idx]) - goto matched; + if ((int32_t) c1 == wextra[idx]) + goto matched; # else - for (c1 = 0; c1 < extra[idx]; ++c1) - if (n[c1] != extra[1 + c1]) - break; + for (c1 = 0; c1 < extra[idx]; ++c1) + if (n[c1] != extra[1 + c1]) + break; - if (c1 == extra[idx]) - goto matched; + if (c1 == extra[idx]) + goto matched; # endif - } + } - /* Get the collation sequence value. */ - is_seqval = true; + /* Get the collation sequence value. */ + is_seqval = true; # ifdef WIDE_CHAR_VERSION - cold = wextra[1 + wextra[idx]]; + cold = wextra[1 + wextra[idx]]; # else - /* Adjust for the alignment. */ - idx += 1 + extra[idx]; - idx = (idx + 3) & ~4; - cold = *((int32_t *) &extra[idx]); + /* Adjust for the alignment. */ + idx += 1 + extra[idx]; + idx = (idx + 3) & ~4; + cold = *((int32_t *) &extra[idx]); # endif - c = *p++; - } - else if (c1 == 1) - { - /* No valid character. Match it as a - single byte. */ - if (!is_range && *n == str[0]) - goto matched; + c = *p++; + } + else if (c1 == 1) + { + /* No valid character. Match it as a + single byte. */ + if (!is_range && *n == str[0]) + goto matched; - cold = str[0]; - c = *p++; - } - else - return FNM_NOMATCH; - } - } - else + cold = str[0]; + c = *p++; + } + else + return FNM_NOMATCH; + } + } + else # undef str #endif - { - c = FOLD (c); - normal_bracket: + { + c = FOLD (c); + normal_bracket: - /* We have to handling the symbols differently in - ranges since then the collation sequence is - important. */ - is_range = (*p == L_('-') && p[1] != L_('\0') - && p[1] != L_(']')); + /* We have to handling the symbols differently in + ranges since then the collation sequence is + important. */ + is_range = (*p == L_('-') && p[1] != L_('\0') + && p[1] != L_(']')); - if (!is_range && c == fn) - goto matched; + if (!is_range && c == fn) + goto matched; #if _LIBC - /* This is needed if we goto normal_bracket; from - outside of is_seqval's scope. */ - is_seqval = false; + /* This is needed if we goto normal_bracket; from + outside of is_seqval's scope. */ + is_seqval = false; #endif - cold = c; - c = *p++; - } + cold = c; + c = *p++; + } - if (c == L_('-') && *p != L_(']')) - { + if (c == L_('-') && *p != L_(']')) + { #if _LIBC - /* We have to find the collation sequence - value for C. Collation sequence is nothing - we can regularly access. The sequence - value is defined by the order in which the - definitions of the collation values for the - various characters appear in the source - file. A strange concept, nowhere - documented. */ - uint32_t fcollseq; - uint32_t lcollseq; - UCHAR cend = *p++; + /* We have to find the collation sequence + value for C. Collation sequence is nothing + we can regularly access. The sequence + value is defined by the order in which the + definitions of the collation values for the + various characters appear in the source + file. A strange concept, nowhere + documented. */ + uint32_t fcollseq; + uint32_t lcollseq; + UCHAR cend = *p++; # ifdef WIDE_CHAR_VERSION - /* Search in the `names' array for the characters. */ - fcollseq = __collseq_table_lookup (collseq, fn); - if (fcollseq == ~((uint32_t) 0)) - /* XXX We don't know anything about the character - we are supposed to match. This means we are - failing. */ - goto range_not_matched; + /* Search in the `names' array for the characters. */ + fcollseq = __collseq_table_lookup (collseq, fn); + if (fcollseq == ~((uint32_t) 0)) + /* XXX We don't know anything about the character + we are supposed to match. This means we are + failing. */ + goto range_not_matched; - if (is_seqval) - lcollseq = cold; - else - lcollseq = __collseq_table_lookup (collseq, cold); + if (is_seqval) + lcollseq = cold; + else + lcollseq = __collseq_table_lookup (collseq, cold); # else - fcollseq = collseq[fn]; - lcollseq = is_seqval ? cold : collseq[(UCHAR) cold]; + fcollseq = collseq[fn]; + lcollseq = is_seqval ? cold : collseq[(UCHAR) cold]; # endif - is_seqval = false; - if (cend == L_('[') && *p == L_('.')) - { - uint32_t nrules = - _NL_CURRENT_WORD (LC_COLLATE, - _NL_COLLATE_NRULES); - const CHAR *startp = p; - size_t c1 = 0; + is_seqval = false; + if (cend == L_('[') && *p == L_('.')) + { + uint32_t nrules = + _NL_CURRENT_WORD (LC_COLLATE, + _NL_COLLATE_NRULES); + const CHAR *startp = p; + size_t c1 = 0; - while (1) - { - c = *++p; - if (c == L_('.') && p[1] == L_(']')) - { - p += 2; - break; - } - if (c == '\0') - return FNM_NOMATCH; - ++c1; - } + while (1) + { + c = *++p; + if (c == L_('.') && p[1] == L_(']')) + { + p += 2; + break; + } + if (c == '\0') + return FNM_NOMATCH; + ++c1; + } - if (nrules == 0) - { - /* There are no names defined in the - collation data. Therefore we only - accept the trivial names consisting - of the character itself. */ - if (c1 != 1) - return FNM_NOMATCH; + if (nrules == 0) + { + /* There are no names defined in the + collation data. Therefore we only + accept the trivial names consisting + of the character itself. */ + if (c1 != 1) + return FNM_NOMATCH; - cend = startp[1]; - } - else - { - int32_t table_size; - const int32_t *symb_table; + cend = startp[1]; + } + else + { + int32_t table_size; + const int32_t *symb_table; # ifdef WIDE_CHAR_VERSION - char str[c1]; - size_t strcnt; + char str[c1]; + size_t strcnt; # else # define str (startp + 1) # endif - const unsigned char *extra; - int32_t idx; - int32_t elem; - int32_t second; - int32_t hash; + const unsigned char *extra; + int32_t idx; + int32_t elem; + int32_t second; + int32_t hash; # ifdef WIDE_CHAR_VERSION - /* We have to convert the name to a single-byte - string. This is possible since the names - consist of ASCII characters and the internal - representation is UCS4. */ - for (strcnt = 0; strcnt < c1; ++strcnt) - str[strcnt] = startp[1 + strcnt]; + /* We have to convert the name to a single-byte + string. This is possible since the names + consist of ASCII characters and the internal + representation is UCS4. */ + for (strcnt = 0; strcnt < c1; ++strcnt) + str[strcnt] = startp[1 + strcnt]; # endif - table_size = - _NL_CURRENT_WORD (LC_COLLATE, - _NL_COLLATE_SYMB_HASH_SIZEMB); - symb_table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_TABLEMB); - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_EXTRAMB); + table_size = + _NL_CURRENT_WORD (LC_COLLATE, + _NL_COLLATE_SYMB_HASH_SIZEMB); + symb_table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_TABLEMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_EXTRAMB); - /* Locate the character in the hashing + /* Locate the character in the hashing table. */ - hash = elem_hash (str, c1); + hash = elem_hash (str, c1); - idx = 0; - elem = hash % table_size; - if (symb_table[2 * elem] != 0) - { - second = hash % (table_size - 2) + 1; + idx = 0; + elem = hash % table_size; + if (symb_table[2 * elem] != 0) + { + second = hash % (table_size - 2) + 1; - do - { - /* First compare the hashing value. */ - if (symb_table[2 * elem] == hash - && (c1 - == extra[symb_table[2 * elem + 1]]) - && memcmp (str, - &extra[symb_table[2 * elem + 1] - + 1], c1) == 0) - { - /* Yep, this is the entry. */ - idx = symb_table[2 * elem + 1]; - idx += 1 + extra[idx]; - break; - } + do + { + /* First compare the hashing value. */ + if (symb_table[2 * elem] == hash + && (c1 + == extra[symb_table[2 * elem + 1]]) + && memcmp (str, + &extra[symb_table[2 * elem + 1] + + 1], c1) == 0) + { + /* Yep, this is the entry. */ + idx = symb_table[2 * elem + 1]; + idx += 1 + extra[idx]; + break; + } - /* Next entry. */ - elem += second; - } - while (symb_table[2 * elem] != 0); - } + /* Next entry. */ + elem += second; + } + while (symb_table[2 * elem] != 0); + } - if (symb_table[2 * elem] != 0) - { - /* Compare the byte sequence but only if - this is not part of a range. */ + if (symb_table[2 * elem] != 0) + { + /* Compare the byte sequence but only if + this is not part of a range. */ # ifdef WIDE_CHAR_VERSION - int32_t *wextra; + int32_t *wextra; - idx += 1 + extra[idx]; - /* Adjust for the alignment. */ - idx = (idx + 3) & ~4; + idx += 1 + extra[idx]; + /* Adjust for the alignment. */ + idx = (idx + 3) & ~4; - wextra = (int32_t *) &extra[idx + 4]; + wextra = (int32_t *) &extra[idx + 4]; # endif - /* Get the collation sequence value. */ - is_seqval = true; + /* Get the collation sequence value. */ + is_seqval = true; # ifdef WIDE_CHAR_VERSION - cend = wextra[1 + wextra[idx]]; + cend = wextra[1 + wextra[idx]]; # else - /* Adjust for the alignment. */ - idx += 1 + extra[idx]; - idx = (idx + 3) & ~4; - cend = *((int32_t *) &extra[idx]); + /* Adjust for the alignment. */ + idx += 1 + extra[idx]; + idx = (idx + 3) & ~4; + cend = *((int32_t *) &extra[idx]); # endif - } - else if (symb_table[2 * elem] != 0 && c1 == 1) - { - cend = str[0]; - c = *p++; - } - else - return FNM_NOMATCH; - } + } + else if (symb_table[2 * elem] != 0 && c1 == 1) + { + cend = str[0]; + c = *p++; + } + else + return FNM_NOMATCH; + } # undef str - } - else - { - if (!(flags & FNM_NOESCAPE) && cend == L_('\\')) - cend = *p++; - if (cend == L_('\0')) - return FNM_NOMATCH; - cend = FOLD (cend); - } + } + else + { + if (!(flags & FNM_NOESCAPE) && cend == L_('\\')) + cend = *p++; + if (cend == L_('\0')) + return FNM_NOMATCH; + cend = FOLD (cend); + } - /* XXX It is not entirely clear to me how to handle - characters which are not mentioned in the - collation specification. */ - if ( + /* XXX It is not entirely clear to me how to handle + characters which are not mentioned in the + collation specification. */ + if ( # ifdef WIDE_CHAR_VERSION - lcollseq == 0xffffffff || + lcollseq == 0xffffffff || # endif - lcollseq <= fcollseq) - { - /* We have to look at the upper bound. */ - uint32_t hcollseq; + lcollseq <= fcollseq) + { + /* We have to look at the upper bound. */ + uint32_t hcollseq; - if (is_seqval) - hcollseq = cend; - else - { + if (is_seqval) + hcollseq = cend; + else + { # ifdef WIDE_CHAR_VERSION - hcollseq = - __collseq_table_lookup (collseq, cend); - if (hcollseq == ~((uint32_t) 0)) - { - /* Hum, no information about the upper - bound. The matching succeeds if the - lower bound is matched exactly. */ - if (lcollseq != fcollseq) - goto range_not_matched; + hcollseq = + __collseq_table_lookup (collseq, cend); + if (hcollseq == ~((uint32_t) 0)) + { + /* Hum, no information about the upper + bound. The matching succeeds if the + lower bound is matched exactly. */ + if (lcollseq != fcollseq) + goto range_not_matched; - goto matched; - } + goto matched; + } # else - hcollseq = collseq[cend]; + hcollseq = collseq[cend]; # endif - } + } - if (lcollseq <= hcollseq && fcollseq <= hcollseq) - goto matched; - } + if (lcollseq <= hcollseq && fcollseq <= hcollseq) + goto matched; + } # ifdef WIDE_CHAR_VERSION - range_not_matched: + range_not_matched: # endif #else - /* We use a boring value comparison of the character - values. This is better than comparing using - `strcoll' since the latter would have surprising - and sometimes fatal consequences. */ - UCHAR cend = *p++; + /* We use a boring value comparison of the character + values. This is better than comparing using + `strcoll' since the latter would have surprising + and sometimes fatal consequences. */ + UCHAR cend = *p++; - if (!(flags & FNM_NOESCAPE) && cend == L_('\\')) - cend = *p++; - if (cend == L_('\0')) - return FNM_NOMATCH; + if (!(flags & FNM_NOESCAPE) && cend == L_('\\')) + cend = *p++; + if (cend == L_('\0')) + return FNM_NOMATCH; - /* It is a range. */ - if (cold <= fn && fn <= cend) - goto matched; + /* It is a range. */ + if (cold <= fn && fn <= cend) + goto matched; #endif - c = *p++; - } - } + c = *p++; + } + } - if (c == L_(']')) - break; - } + if (c == L_(']')) + break; + } - if (!not) - return FNM_NOMATCH; - break; + if (!not) + return FNM_NOMATCH; + break; - matched: - /* Skip the rest of the [...] that already matched. */ - do - { - ignore_next: - c = *p++; + matched: + /* Skip the rest of the [...] that already matched. */ + do + { + ignore_next: + c = *p++; - if (c == L_('\0')) - /* [... (unterminated) loses. */ - return FNM_NOMATCH; + if (c == L_('\0')) + /* [... (unterminated) loses. */ + return FNM_NOMATCH; - if (!(flags & FNM_NOESCAPE) && c == L_('\\')) - { - if (*p == L_('\0')) - return FNM_NOMATCH; - /* XXX 1003.2d11 is unclear if this is right. */ - ++p; - } - else if (c == L_('[') && *p == L_(':')) - { - int c1 = 0; - const CHAR *startp = p; + if (!(flags & FNM_NOESCAPE) && c == L_('\\')) + { + if (*p == L_('\0')) + return FNM_NOMATCH; + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + else if (c == L_('[') && *p == L_(':')) + { + int c1 = 0; + const CHAR *startp = p; - while (1) - { - c = *++p; - if (++c1 == CHAR_CLASS_MAX_LENGTH) - return FNM_NOMATCH; + while (1) + { + c = *++p; + if (++c1 == CHAR_CLASS_MAX_LENGTH) + return FNM_NOMATCH; - if (*p == L_(':') && p[1] == L_(']')) - break; + if (*p == L_(':') && p[1] == L_(']')) + break; - if (c < L_('a') || c >= L_('z')) - { - p = startp; - goto ignore_next; - } - } - p += 2; - c = *p++; - } - else if (c == L_('[') && *p == L_('=')) - { - c = *++p; - if (c == L_('\0')) - return FNM_NOMATCH; - c = *++p; - if (c != L_('=') || p[1] != L_(']')) - return FNM_NOMATCH; - p += 2; - c = *p++; - } - else if (c == L_('[') && *p == L_('.')) - { - ++p; - while (1) - { - c = *++p; - if (c == '\0') - return FNM_NOMATCH; + if (c < L_('a') || c >= L_('z')) + { + p = startp; + goto ignore_next; + } + } + p += 2; + c = *p++; + } + else if (c == L_('[') && *p == L_('=')) + { + c = *++p; + if (c == L_('\0')) + return FNM_NOMATCH; + c = *++p; + if (c != L_('=') || p[1] != L_(']')) + return FNM_NOMATCH; + p += 2; + c = *p++; + } + else if (c == L_('[') && *p == L_('.')) + { + ++p; + while (1) + { + c = *++p; + if (c == '\0') + return FNM_NOMATCH; - if (*p == L_('.') && p[1] == L_(']')) - break; - } - p += 2; - c = *p++; - } - } - while (c != L_(']')); - if (not) - return FNM_NOMATCH; - } - break; + if (*p == L_('.') && p[1] == L_(']')) + break; + } + p += 2; + c = *p++; + } + } + while (c != L_(']')); + if (not) + return FNM_NOMATCH; + } + break; - case L_('+'): - case L_('@'): - case L_('!'): - if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') - { - int res; + case L_('+'): + case L_('@'): + case L_('!'): + if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') + { + int res; - res = EXT (c, p, n, string_end, no_leading_period, flags); - if (res != -1) - return res; - } - goto normal_match; + res = EXT (c, p, n, string_end, no_leading_period, flags); + if (res != -1) + return res; + } + goto normal_match; - case L_('/'): - if (NO_LEADING_PERIOD (flags)) - { - if (n == string_end || c != (UCHAR) *n) - return FNM_NOMATCH; + case L_('/'): + if (NO_LEADING_PERIOD (flags)) + { + if (n == string_end || c != (UCHAR) *n) + return FNM_NOMATCH; - new_no_leading_period = true; - break; - } - /* FALLTHROUGH */ - default: - normal_match: - if (n == string_end || c != FOLD ((UCHAR) *n)) - return FNM_NOMATCH; - } + new_no_leading_period = true; + break; + } + /* FALLTHROUGH */ + default: + normal_match: + if (n == string_end || c != FOLD ((UCHAR) *n)) + return FNM_NOMATCH; + } no_leading_period = new_no_leading_period; ++n; @@ -984,25 +989,25 @@ END (const CHAR *pattern) return pattern; else if (*p == L_('[')) { - /* Handle brackets special. */ - if (posixly_correct == 0) - posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; + /* Handle brackets special. */ + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; - /* Skip the not sign. We have to recognize it because of a possibly - following ']'. */ - if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^'))) - ++p; - /* A leading ']' is recognized as such. */ - if (*p == L_(']')) - ++p; - /* Skip over all characters of the list. */ - while (*p != L_(']')) - if (*p++ == L_('\0')) - /* This is no valid pattern. */ - return pattern; + /* Skip the not sign. We have to recognize it because of a possibly + following ']'. */ + if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^'))) + ++p; + /* A leading ']' is recognized as such. */ + if (*p == L_(']')) + ++p; + /* Skip over all characters of the list. */ + while (*p != L_(']')) + if (*p++ == L_('\0')) + /* This is no valid pattern. */ + return pattern; } else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@') - || *p == L_('!')) && p[1] == L_('(')) + || *p == L_('!')) && p[1] == L_('(')) p = END (p + 1); else if (*p == L_(')')) break; @@ -1037,64 +1042,63 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, return -1; else if (*p == L_('[')) { - /* Handle brackets special. */ - if (posixly_correct == 0) - posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; + /* Handle brackets special. */ + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; - /* Skip the not sign. We have to recognize it because of a possibly - following ']'. */ - if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^'))) - ++p; - /* A leading ']' is recognized as such. */ - if (*p == L_(']')) - ++p; - /* Skip over all characters of the list. */ - while (*p != L_(']')) - if (*p++ == L_('\0')) - /* This is no valid pattern. */ - return -1; + /* Skip the not sign. We have to recognize it because of a possibly + following ']'. */ + if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^'))) + ++p; + /* A leading ']' is recognized as such. */ + if (*p == L_(']')) + ++p; + /* Skip over all characters of the list. */ + while (*p != L_(']')) + if (*p++ == L_('\0')) + /* This is no valid pattern. */ + return -1; } else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@') - || *p == L_('!')) && p[1] == L_('(')) + || *p == L_('!')) && p[1] == L_('(')) /* Remember the nesting level. */ ++level; else if (*p == L_(')')) { - if (level-- == 0) - { - /* This means we found the end of the pattern. */ + if (level-- == 0) + { + /* This means we found the end of the pattern. */ #define NEW_PATTERN \ - struct patternlist *newp; \ - size_t plen; \ - size_t plensize; \ - size_t newpsize; \ - \ - assert (p > startp); \ - plen = (opt == L_('?') || opt == L_('@') \ - ? pattern_len \ - : (unsigned) (p - startp) + 1); \ - plensize = plen * sizeof (CHAR); \ - newpsize = offsetof (struct patternlist, str) + plensize; \ - if ((size_t) -1 / sizeof (CHAR) < plen \ - || newpsize < offsetof (struct patternlist, str) \ - || ALLOCA_LIMIT <= newpsize) \ - return -1; \ - newp = (struct patternlist *) alloca (newpsize); \ - *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L_('\0'); \ - newp->next = NULL; \ - *lastp = newp; \ - lastp = &newp->next - NEW_PATTERN; - break; - } + struct patternlist *newp; \ + size_t plen; \ + size_t plensize; \ + size_t newpsize; \ + \ + plen = (opt == L_('?') || opt == L_('@') \ + ? pattern_len \ + : p - startp + 1UL); \ + plensize = plen * sizeof (CHAR); \ + newpsize = offsetof (struct patternlist, str) + plensize; \ + if ((size_t) -1 / sizeof (CHAR) < plen \ + || newpsize < offsetof (struct patternlist, str) \ + || ALLOCA_LIMIT <= newpsize) \ + return -1; \ + newp = (struct patternlist *) alloca (newpsize); \ + *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L_('\0'); \ + newp->next = NULL; \ + *lastp = newp; \ + lastp = &newp->next + NEW_PATTERN; + break; + } } else if (*p == L_('|')) { - if (level == 0) - { - NEW_PATTERN; - startp = p + 1; - } + if (level == 0) + { + NEW_PATTERN; + startp = p + 1; + } } assert (list != NULL); assert (p[-1] == L_(')')); @@ -1104,36 +1108,36 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, { case L_('*'): if (FCT (p, string, string_end, no_leading_period, flags) == 0) - return 0; + return 0; /* FALLTHROUGH */ case L_('+'): do - { - for (rs = string; rs <= string_end; ++rs) - /* First match the prefix with the current pattern with the - current pattern. */ - if (FCT (list->str, string, rs, no_leading_period, - flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0 - /* This was successful. Now match the rest with the rest - of the pattern. */ - && (FCT (p, rs, string_end, - rs == string - ? no_leading_period - : rs[-1] == '/' && NO_LEADING_PERIOD (flags), - flags & FNM_FILE_NAME - ? flags : flags & ~FNM_PERIOD) == 0 - /* This didn't work. Try the whole pattern. */ - || (rs != string - && FCT (pattern - 1, rs, string_end, - rs == string - ? no_leading_period - : rs[-1] == '/' && NO_LEADING_PERIOD (flags), - flags & FNM_FILE_NAME - ? flags : flags & ~FNM_PERIOD) == 0))) - /* It worked. Signal success. */ - return 0; - } + { + for (rs = string; rs <= string_end; ++rs) + /* First match the prefix with the current pattern with the + current pattern. */ + if (FCT (list->str, string, rs, no_leading_period, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0 + /* This was successful. Now match the rest with the rest + of the pattern. */ + && (FCT (p, rs, string_end, + rs == string + ? no_leading_period + : rs[-1] == '/' && NO_LEADING_PERIOD (flags), + flags & FNM_FILE_NAME + ? flags : flags & ~FNM_PERIOD) == 0 + /* This didn't work. Try the whole pattern. */ + || (rs != string + && FCT (pattern - 1, rs, string_end, + rs == string + ? no_leading_period + : rs[-1] == '/' && NO_LEADING_PERIOD (flags), + flags & FNM_FILE_NAME + ? flags : flags & ~FNM_PERIOD) == 0))) + /* It worked. Signal success. */ + return 0; + } while ((list = list->next) != NULL); /* None of the patterns lead to a match. */ @@ -1141,20 +1145,20 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, case L_('?'): if (FCT (p, string, string_end, no_leading_period, flags) == 0) - return 0; + return 0; /* FALLTHROUGH */ case L_('@'): do - /* I cannot believe it but `strcat' is actually acceptable - here. Match the entire string with the prefix from the - pattern list and the rest of the pattern following the - pattern list. */ - if (FCT (STRCAT (list->str, p), string, string_end, - no_leading_period, - flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0) - /* It worked. Signal success. */ - return 0; + /* I cannot believe it but `strcat' is actually acceptable + here. Match the entire string with the prefix from the + pattern list and the rest of the pattern following the + pattern list. */ + if (FCT (STRCAT (list->str, p), string, string_end, + no_leading_period, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0) + /* It worked. Signal success. */ + return 0; while ((list = list->next) != NULL); /* None of the patterns lead to a match. */ @@ -1162,28 +1166,28 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, case L_('!'): for (rs = string; rs <= string_end; ++rs) - { - struct patternlist *runp; + { + struct patternlist *runp; - for (runp = list; runp != NULL; runp = runp->next) - if (FCT (runp->str, string, rs, no_leading_period, - flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0) - break; + for (runp = list; runp != NULL; runp = runp->next) + if (FCT (runp->str, string, rs, no_leading_period, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0) + break; - /* If none of the patterns matched see whether the rest does. */ - if (runp == NULL - && (FCT (p, rs, string_end, - rs == string - ? no_leading_period - : rs[-1] == '/' && NO_LEADING_PERIOD (flags), - flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) - == 0)) - /* This is successful. */ - return 0; - } + /* If none of the patterns matched see whether the rest does. */ + if (runp == NULL + && (FCT (p, rs, string_end, + rs == string + ? no_leading_period + : rs[-1] == '/' && NO_LEADING_PERIOD (flags), + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) + == 0)) + /* This is successful. */ + return 0; + } /* None of the patterns together with the rest of the pattern - lead to a match. */ + lead to a match. */ return FNM_NOMATCH; default: diff --git a/gnulib/getdelim.c b/gnulib/getdelim.c new file mode 100644 index 000000000..c0240900c --- /dev/null +++ b/gnulib/getdelim.c @@ -0,0 +1,137 @@ +/* getdelim.c --- Implementation of replacement getdelim function. + Copyright (C) 1994, 1996, 1997, 1998, 2001, 2003, 2005, 2006, 2007, 2008, + 2009, 2010 Free Software Foundation, Inc. + + This program 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 2, or (at + your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +/* Ported from glibc by Simon Josefsson. */ + +#include + +/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc + optimizes away the lineptr == NULL || n == NULL || fp == NULL tests below. */ +#define _GL_ARG_NONNULL(params) + +#include + +#include +#include +#include +#include + +#ifndef SSIZE_MAX +# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) +#endif + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +# define getc_maybe_unlocked(fp) getc(fp) +#elif !HAVE_FLOCKFILE || !HAVE_FUNLOCKFILE || !HAVE_DECL_GETC_UNLOCKED +# undef flockfile +# undef funlockfile +# define flockfile(x) ((void) 0) +# define funlockfile(x) ((void) 0) +# define getc_maybe_unlocked(fp) getc(fp) +#else +# define getc_maybe_unlocked(fp) getc_unlocked(fp) +#endif + +/* Read up to (and including) a DELIMITER from FP into *LINEPTR (and + NUL-terminate it). *LINEPTR is a pointer returned from malloc (or + NULL), pointing to *N characters of space. It is realloc'ed as + necessary. Returns the number of characters read (not including + the null terminator), or -1 on error or EOF. */ + +ssize_t +getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp) +{ + ssize_t result; + size_t cur_len = 0; + + if (lineptr == NULL || n == NULL || fp == NULL) + { + errno = EINVAL; + return -1; + } + + flockfile (fp); + + if (*lineptr == NULL || *n == 0) + { + char *new_lineptr; + *n = 120; + new_lineptr = (char *) realloc (*lineptr, *n); + if (new_lineptr == NULL) + { + result = -1; + goto unlock_return; + } + *lineptr = new_lineptr; + } + + for (;;) + { + int i; + + i = getc_maybe_unlocked (fp); + if (i == EOF) + { + result = -1; + break; + } + + /* Make enough space for len+1 (for final NUL) bytes. */ + if (cur_len + 1 >= *n) + { + size_t needed_max = + SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX; + size_t needed = 2 * *n + 1; /* Be generous. */ + char *new_lineptr; + + if (needed_max < needed) + needed = needed_max; + if (cur_len + 1 >= needed) + { + result = -1; + errno = EOVERFLOW; + goto unlock_return; + } + + new_lineptr = (char *) realloc (*lineptr, needed); + if (new_lineptr == NULL) + { + result = -1; + goto unlock_return; + } + + *lineptr = new_lineptr; + *n = needed; + } + + (*lineptr)[cur_len] = i; + cur_len++; + + if (i == delimiter) + break; + } + (*lineptr)[cur_len] = '\0'; + result = cur_len ? cur_len : result; + + unlock_return: + funlockfile (fp); /* doesn't set errno */ + + return result; +} diff --git a/gnulib/getline.c b/gnulib/getline.c new file mode 100644 index 000000000..6cf187be2 --- /dev/null +++ b/gnulib/getline.c @@ -0,0 +1,30 @@ +/* getline.c --- Implementation of replacement getline function. + Copyright (C) 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. + + This program 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 2, or (at + your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +/* Written by Simon Josefsson. */ + +#include + +#include +#include + +ssize_t +getline (char **lineptr, size_t *n, FILE *stream) +{ + return getdelim (lineptr, n, '\n', stream); +} diff --git a/gnulib/getopt.c b/gnulib/getopt.c index f1e6d1f7c..aaabc8d19 100644 --- a/gnulib/getopt.c +++ b/gnulib/getopt.c @@ -1,9 +1,9 @@ /* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what + NOTE: getopt is part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! - Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001,2002,2003,2004,2006,2008 - Free Software Foundation, Inc. + Copyright (C) 1987-1996, 1998-2004, 2006, 2008-2010 Free Software + Foundation, Inc. This file is part of the GNU C Library. This program is free software: you can redistribute it and/or modify @@ -41,12 +41,9 @@ # include #endif -#ifndef attribute_hidden -# define attribute_hidden -#endif - -/* Unlike standard Unix `getopt', functions like `getopt_long' - let the user intersperse the options with the other arguments. +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. As `getopt_long' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus @@ -54,7 +51,7 @@ Using `getopt' or setting the environment variable POSIXLY_CORRECT disables permutation. - Then the application's behavior is completely standard. + Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ @@ -121,18 +118,18 @@ extern char *__getopt_nonoption_flags; # ifdef USE_NONOPTION_FLAGS # define SWAP_FLAGS(ch1, ch2) \ - if (d->__nonoption_flags_len > 0) \ - { \ - char __tmp = __getopt_nonoption_flags[ch1]; \ - __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ - __getopt_nonoption_flags[ch2] = __tmp; \ + if (d->__nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ } # else # define SWAP_FLAGS(ch1, ch2) # endif -#else /* !_LIBC */ +#else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) -#endif /* _LIBC */ +#endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) @@ -163,57 +160,57 @@ exchange (char **argv, struct _getopt_data *d) if (d->__nonoption_flags_len > 0 && top >= d->__nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and - presents new arguments. */ + presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) - d->__nonoption_flags_len = d->__nonoption_flags_max_len = 0; + d->__nonoption_flags_len = d->__nonoption_flags_max_len = 0; else - { - memset (__mempcpy (new_str, __getopt_nonoption_flags, - d->__nonoption_flags_max_len), - '\0', top + 1 - d->__nonoption_flags_max_len); - d->__nonoption_flags_max_len = top + 1; - __getopt_nonoption_flags = new_str; - } + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + d->__nonoption_flags_max_len), + '\0', top + 1 - d->__nonoption_flags_max_len); + d->__nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - SWAP_FLAGS (bottom + i, middle + i); - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } } /* Update records for the slots the non-options now occupy. */ @@ -225,8 +222,9 @@ exchange (char **argv, struct _getopt_data *d) /* Initialize the internal data when the first call is made. */ static const char * -_getopt_initialize (int argc, char **argv, const char *optstring, - int posixly_correct, struct _getopt_data *d) +_getopt_initialize (int argc _GL_UNUSED, + char **argv _GL_UNUSED, const char *optstring, + struct _getopt_data *d, int posixly_correct) { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped @@ -260,25 +258,25 @@ _getopt_initialize (int argc, char **argv, const char *optstring, && argc == __libc_argc && argv == __libc_argv) { if (d->__nonoption_flags_max_len == 0) - { - if (__getopt_nonoption_flags == NULL - || __getopt_nonoption_flags[0] == '\0') - d->__nonoption_flags_max_len = -1; - else - { - const char *orig_str = __getopt_nonoption_flags; - int len = d->__nonoption_flags_max_len = strlen (orig_str); - if (d->__nonoption_flags_max_len < argc) - d->__nonoption_flags_max_len = argc; - __getopt_nonoption_flags = - (char *) malloc (d->__nonoption_flags_max_len); - if (__getopt_nonoption_flags == NULL) - d->__nonoption_flags_max_len = -1; - else - memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), - '\0', d->__nonoption_flags_max_len - len); - } - } + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + d->__nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = d->__nonoption_flags_max_len = strlen (orig_str); + if (d->__nonoption_flags_max_len < argc) + d->__nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (d->__nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + d->__nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', d->__nonoption_flags_max_len - len); + } + } d->__nonoption_flags_len = d->__nonoption_flags_max_len; } else @@ -330,6 +328,10 @@ _getopt_initialize (int argc, char **argv, const char *optstring, `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. @@ -338,15 +340,12 @@ _getopt_initialize (int argc, char **argv, const char *optstring, recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. - - If POSIXLY_CORRECT is nonzero, behave as if the POSIXLY_CORRECT - environment variable were set. */ + long-named options. */ int _getopt_internal_r (int argc, char **argv, const char *optstring, - const struct option *longopts, int *longind, - int long_only, int posixly_correct, struct _getopt_data *d) + const struct option *longopts, int *longind, + int long_only, struct _getopt_data *d, int posixly_correct) { int print_errors = d->opterr; if (optstring[0] == ':') @@ -360,9 +359,9 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, if (d->optind == 0 || !d->__initialized) { if (d->optind == 0) - d->optind = 1; /* Don't scan ARGV[0], the program name. */ - optstring = _getopt_initialize (argc, argv, optstring, - posixly_correct, d); + d->optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring, d, + posixly_correct); d->__initialized = 1; } @@ -372,8 +371,8 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, is only used when the used in the GNU libc. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS # define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0' \ - || (d->optind < d->__nonoption_flags_len \ - && __getopt_nonoption_flags[d->optind] == '1')) + || (d->optind < d->__nonoption_flags_len \ + && __getopt_nonoption_flags[d->optind] == '1')) #else # define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0') #endif @@ -383,78 +382,78 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been - moved back by the user (who may also have changed the arguments). */ + moved back by the user (who may also have changed the arguments). */ if (d->__last_nonopt > d->optind) - d->__last_nonopt = d->optind; + d->__last_nonopt = d->optind; if (d->__first_nonopt > d->optind) - d->__first_nonopt = d->optind; + d->__first_nonopt = d->optind; if (d->__ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ - if (d->__first_nonopt != d->__last_nonopt - && d->__last_nonopt != d->optind) - exchange ((char **) argv, d); - else if (d->__last_nonopt != d->optind) - d->__first_nonopt = d->optind; + if (d->__first_nonopt != d->__last_nonopt + && d->__last_nonopt != d->optind) + exchange ((char **) argv, d); + else if (d->__last_nonopt != d->optind) + d->__first_nonopt = d->optind; - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ - while (d->optind < argc && NONOPTION_P) - d->optind++; - d->__last_nonopt = d->optind; - } + while (d->optind < argc && NONOPTION_P) + d->optind++; + d->__last_nonopt = d->optind; + } /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ if (d->optind != argc && !strcmp (argv[d->optind], "--")) - { - d->optind++; + { + d->optind++; - if (d->__first_nonopt != d->__last_nonopt - && d->__last_nonopt != d->optind) - exchange ((char **) argv, d); - else if (d->__first_nonopt == d->__last_nonopt) - d->__first_nonopt = d->optind; - d->__last_nonopt = argc; + if (d->__first_nonopt != d->__last_nonopt + && d->__last_nonopt != d->optind) + exchange ((char **) argv, d); + else if (d->__first_nonopt == d->__last_nonopt) + d->__first_nonopt = d->optind; + d->__last_nonopt = argc; - d->optind = argc; - } + d->optind = argc; + } /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ + and back over any non-options that we skipped and permuted. */ if (d->optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (d->__first_nonopt != d->__last_nonopt) - d->optind = d->__first_nonopt; - return -1; - } + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (d->__first_nonopt != d->__last_nonopt) + d->optind = d->__first_nonopt; + return -1; + } /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ + either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) - { - if (d->__ordering == REQUIRE_ORDER) - return -1; - d->optarg = argv[d->optind++]; - return 1; - } + { + if (d->__ordering == REQUIRE_ORDER) + return -1; + d->optarg = argv[d->optind++]; + return 1; + } /* We have found another option-ARGV-element. - Skip the initial punctuation. */ + Skip the initial punctuation. */ d->__nextchar = (argv[d->optind] + 1 - + (longopts != NULL && argv[d->optind][1] == '-')); + + (longopts != NULL && argv[d->optind][1] == '-')); } /* Decode the current option-ARGV-element. */ @@ -474,8 +473,8 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, if (longopts != NULL && (argv[d->optind][1] == '-' - || (long_only && (argv[d->optind][2] - || !strchr (optstring, argv[d->optind][1]))))) + || (long_only && (argv[d->optind][2] + || !strchr (optstring, argv[d->optind][1]))))) { char *nameend; const struct option *p; @@ -486,251 +485,251 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, int option_index; for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; + /* Do nothing. */ ; /* Test all long options for either exact match - or abbreviated matches. */ + or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) - { - if ((unsigned int) (nameend - d->__nextchar) - == (unsigned int) strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else if (long_only - || pfound->has_arg != p->has_arg - || pfound->flag != p->flag - || pfound->val != p->val) - /* Second or later nonexact match found. */ - ambig = 1; - } + if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) + { + if ((unsigned int) (nameend - d->__nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else if (long_only + || pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } if (ambig && !exact) - { - if (print_errors) - { + { + if (print_errors) + { #if defined _LIBC && defined USE_IN_LIBIO - char *buf; + char *buf; - if (__asprintf (&buf, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[d->optind]) >= 0) - { - _IO_flockfile (stderr); + if (__asprintf (&buf, _("%s: option '%s' is ambiguous\n"), + argv[0], argv[d->optind]) >= 0) + { + _IO_flockfile (stderr); - int old_flags2 = ((_IO_FILE *) stderr)->_flags2; - ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - __fxprintf (NULL, "%s", buf); + __fxprintf (NULL, "%s", buf); - ((_IO_FILE *) stderr)->_flags2 = old_flags2; - _IO_funlockfile (stderr); + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); - free (buf); - } + free (buf); + } #else - fprintf (stderr, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[d->optind]); + fprintf (stderr, _("%s: option '%s' is ambiguous\n"), + argv[0], argv[d->optind]); #endif - } - d->__nextchar += strlen (d->__nextchar); - d->optind++; - d->optopt = 0; - return '?'; - } + } + d->__nextchar += strlen (d->__nextchar); + d->optind++; + d->optopt = 0; + return '?'; + } if (pfound != NULL) - { - option_index = indfound; - d->optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - d->optarg = nameend + 1; - else - { - if (print_errors) - { + { + option_index = indfound; + d->optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { #if defined _LIBC && defined USE_IN_LIBIO - char *buf; - int n; + char *buf; + int n; #endif - if (argv[d->optind - 1][1] == '-') - { - /* --option */ + if (argv[d->optind - 1][1] == '-') + { + /* --option */ #if defined _LIBC && defined USE_IN_LIBIO - n = __asprintf (&buf, _("\ -%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); + n = __asprintf (&buf, _("\ +%s: option '--%s' doesn't allow an argument\n"), + argv[0], pfound->name); #else - fprintf (stderr, _("\ -%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); + fprintf (stderr, _("\ +%s: option '--%s' doesn't allow an argument\n"), + argv[0], pfound->name); #endif - } - else - { - /* +option or -option */ + } + else + { + /* +option or -option */ #if defined _LIBC && defined USE_IN_LIBIO - n = __asprintf (&buf, _("\ -%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[d->optind - 1][0], - pfound->name); + n = __asprintf (&buf, _("\ +%s: option '%c%s' doesn't allow an argument\n"), + argv[0], argv[d->optind - 1][0], + pfound->name); #else - fprintf (stderr, _("\ -%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[d->optind - 1][0], - pfound->name); + fprintf (stderr, _("\ +%s: option '%c%s' doesn't allow an argument\n"), + argv[0], argv[d->optind - 1][0], + pfound->name); #endif - } + } #if defined _LIBC && defined USE_IN_LIBIO - if (n >= 0) - { - _IO_flockfile (stderr); + if (n >= 0) + { + _IO_flockfile (stderr); - int old_flags2 = ((_IO_FILE *) stderr)->_flags2; - ((_IO_FILE *) stderr)->_flags2 - |= _IO_FLAGS2_NOTCANCEL; + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; - __fxprintf (NULL, "%s", buf); + __fxprintf (NULL, "%s", buf); - ((_IO_FILE *) stderr)->_flags2 = old_flags2; - _IO_funlockfile (stderr); + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); - free (buf); - } + free (buf); + } #endif - } + } - d->__nextchar += strlen (d->__nextchar); + d->__nextchar += strlen (d->__nextchar); - d->optopt = pfound->val; - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (d->optind < argc) - d->optarg = argv[d->optind++]; - else - { - if (print_errors) - { + d->optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { #if defined _LIBC && defined USE_IN_LIBIO - char *buf; + char *buf; - if (__asprintf (&buf, _("\ -%s: option `%s' requires an argument\n"), - argv[0], argv[d->optind - 1]) >= 0) - { - _IO_flockfile (stderr); + if (__asprintf (&buf, _("\ +%s: option '%s' requires an argument\n"), + argv[0], argv[d->optind - 1]) >= 0) + { + _IO_flockfile (stderr); - int old_flags2 = ((_IO_FILE *) stderr)->_flags2; - ((_IO_FILE *) stderr)->_flags2 - |= _IO_FLAGS2_NOTCANCEL; + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; - __fxprintf (NULL, "%s", buf); + __fxprintf (NULL, "%s", buf); - ((_IO_FILE *) stderr)->_flags2 = old_flags2; - _IO_funlockfile (stderr); + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); - free (buf); - } + free (buf); + } #else - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[d->optind - 1]); + fprintf (stderr, + _("%s: option '%s' requires an argument\n"), + argv[0], argv[d->optind - 1]); #endif - } - d->__nextchar += strlen (d->__nextchar); - d->optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; - } - } - d->__nextchar += strlen (d->__nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } + } + d->__nextchar += strlen (d->__nextchar); + d->optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + d->__nextchar += strlen (d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ if (!long_only || argv[d->optind][1] == '-' - || strchr (optstring, *d->__nextchar) == NULL) - { - if (print_errors) - { + || strchr (optstring, *d->__nextchar) == NULL) + { + if (print_errors) + { #if defined _LIBC && defined USE_IN_LIBIO - char *buf; - int n; + char *buf; + int n; #endif - if (argv[d->optind][1] == '-') - { - /* --option */ + if (argv[d->optind][1] == '-') + { + /* --option */ #if defined _LIBC && defined USE_IN_LIBIO - n = __asprintf (&buf, _("%s: unrecognized option `--%s'\n"), - argv[0], d->__nextchar); + n = __asprintf (&buf, _("%s: unrecognized option '--%s'\n"), + argv[0], d->__nextchar); #else - fprintf (stderr, _("%s: unrecognized option `--%s'\n"), - argv[0], d->__nextchar); + fprintf (stderr, _("%s: unrecognized option '--%s'\n"), + argv[0], d->__nextchar); #endif - } - else - { - /* +option or -option */ + } + else + { + /* +option or -option */ #if defined _LIBC && defined USE_IN_LIBIO - n = __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[d->optind][0], d->__nextchar); + n = __asprintf (&buf, _("%s: unrecognized option '%c%s'\n"), + argv[0], argv[d->optind][0], d->__nextchar); #else - fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[d->optind][0], d->__nextchar); + fprintf (stderr, _("%s: unrecognized option '%c%s'\n"), + argv[0], argv[d->optind][0], d->__nextchar); #endif - } + } #if defined _LIBC && defined USE_IN_LIBIO - if (n >= 0) - { - _IO_flockfile (stderr); + if (n >= 0) + { + _IO_flockfile (stderr); - int old_flags2 = ((_IO_FILE *) stderr)->_flags2; - ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - __fxprintf (NULL, "%s", buf); + __fxprintf (NULL, "%s", buf); - ((_IO_FILE *) stderr)->_flags2 = old_flags2; - _IO_funlockfile (stderr); + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); - free (buf); - } + free (buf); + } #endif - } - d->__nextchar = (char *) ""; - d->optind++; - d->optopt = 0; - return '?'; - } + } + d->__nextchar = (char *) ""; + d->optind++; + d->optopt = 0; + return '?'; + } } /* Look at and handle the next short option-character. */ @@ -745,335 +744,321 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, if (temp == NULL || c == ':') { - if (print_errors) - { + if (print_errors) + { #if defined _LIBC && defined USE_IN_LIBIO - char *buf; - int n; + char *buf; + int n; #endif - if (d->__posixly_correct) - { - /* 1003.2 specifies the format of this message. */ #if defined _LIBC && defined USE_IN_LIBIO - n = __asprintf (&buf, _("%s: illegal option -- %c\n"), - argv[0], c); + n = __asprintf (&buf, _("%s: invalid option -- '%c'\n"), + argv[0], c); #else - fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); + fprintf (stderr, _("%s: invalid option -- '%c'\n"), argv[0], c); #endif - } - else - { -#if defined _LIBC && defined USE_IN_LIBIO - n = __asprintf (&buf, _("%s: invalid option -- %c\n"), - argv[0], c); -#else - fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); -#endif - } #if defined _LIBC && defined USE_IN_LIBIO - if (n >= 0) - { - _IO_flockfile (stderr); + if (n >= 0) + { + _IO_flockfile (stderr); - int old_flags2 = ((_IO_FILE *) stderr)->_flags2; - ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - __fxprintf (NULL, "%s", buf); + __fxprintf (NULL, "%s", buf); - ((_IO_FILE *) stderr)->_flags2 = old_flags2; - _IO_funlockfile (stderr); + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); - free (buf); - } + free (buf); + } #endif - } - d->optopt = c; - return '?'; + } + d->optopt = c; + return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = 0; - int option_index; + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; - /* This is an option that requires an argument. */ - if (*d->__nextchar != '\0') - { - d->optarg = d->__nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - d->optind++; - } - else if (d->optind == argc) - { - if (print_errors) - { - /* 1003.2 specifies the format of this message. */ + /* This is an option that requires an argument. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { #if defined _LIBC && defined USE_IN_LIBIO - char *buf; + char *buf; - if (__asprintf (&buf, - _("%s: option requires an argument -- %c\n"), - argv[0], c) >= 0) - { - _IO_flockfile (stderr); + if (__asprintf (&buf, + _("%s: option requires an argument -- '%c'\n"), + argv[0], c) >= 0) + { + _IO_flockfile (stderr); - int old_flags2 = ((_IO_FILE *) stderr)->_flags2; - ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - __fxprintf (NULL, "%s", buf); + __fxprintf (NULL, "%s", buf); - ((_IO_FILE *) stderr)->_flags2 = old_flags2; - _IO_funlockfile (stderr); + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); - free (buf); - } + free (buf); + } #else - fprintf (stderr, _("%s: option requires an argument -- %c\n"), - argv[0], c); + fprintf (stderr, + _("%s: option requires an argument -- '%c'\n"), + argv[0], c); #endif - } - d->optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - return c; - } - else - /* We already incremented `d->optind' once; - increment it again when taking next ARGV-elt as argument. */ - d->optarg = argv[d->optind++]; + } + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `d->optind' once; + increment it again when taking next ARGV-elt as argument. */ + d->optarg = argv[d->optind++]; - /* optarg is now the argument, see if it's in the - table of longopts. */ + /* optarg is now the argument, see if it's in the + table of longopts. */ - for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; - nameend++) - /* Do nothing. */ ; + for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; + nameend++) + /* Do nothing. */ ; - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) - { - if ((unsigned int) (nameend - d->__nextchar) == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) - { - if (print_errors) - { + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) + { + if ((unsigned int) (nameend - d->__nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + { #if defined _LIBC && defined USE_IN_LIBIO - char *buf; + char *buf; - if (__asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[d->optind]) >= 0) - { - _IO_flockfile (stderr); + if (__asprintf (&buf, _("%s: option '-W %s' is ambiguous\n"), + argv[0], argv[d->optind]) >= 0) + { + _IO_flockfile (stderr); - int old_flags2 = ((_IO_FILE *) stderr)->_flags2; - ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - __fxprintf (NULL, "%s", buf); + __fxprintf (NULL, "%s", buf); - ((_IO_FILE *) stderr)->_flags2 = old_flags2; - _IO_funlockfile (stderr); + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); - free (buf); - } + free (buf); + } #else - fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[d->optind]); + fprintf (stderr, _("%s: option '-W %s' is ambiguous\n"), + argv[0], argv[d->optind]); #endif - } - d->__nextchar += strlen (d->__nextchar); - d->optind++; - return '?'; - } - if (pfound != NULL) - { - option_index = indfound; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - d->optarg = nameend + 1; - else - { - if (print_errors) - { + } + d->__nextchar += strlen (d->__nextchar); + d->optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { #if defined _LIBC && defined USE_IN_LIBIO - char *buf; + char *buf; - if (__asprintf (&buf, _("\ -%s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name) >= 0) - { - _IO_flockfile (stderr); + if (__asprintf (&buf, _("\ +%s: option '-W %s' doesn't allow an argument\n"), + argv[0], pfound->name) >= 0) + { + _IO_flockfile (stderr); - int old_flags2 = ((_IO_FILE *) stderr)->_flags2; - ((_IO_FILE *) stderr)->_flags2 - |= _IO_FLAGS2_NOTCANCEL; + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; - __fxprintf (NULL, "%s", buf); + __fxprintf (NULL, "%s", buf); - ((_IO_FILE *) stderr)->_flags2 = old_flags2; - _IO_funlockfile (stderr); + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); - free (buf); - } + free (buf); + } #else - fprintf (stderr, _("\ -%s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); + fprintf (stderr, _("\ +%s: option '-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); #endif - } + } - d->__nextchar += strlen (d->__nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (d->optind < argc) - d->optarg = argv[d->optind++]; - else - { - if (print_errors) - { + d->__nextchar += strlen (d->__nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { #if defined _LIBC && defined USE_IN_LIBIO - char *buf; + char *buf; - if (__asprintf (&buf, _("\ -%s: option `%s' requires an argument\n"), - argv[0], argv[d->optind - 1]) >= 0) - { - _IO_flockfile (stderr); + if (__asprintf (&buf, _("\ +%s: option '%s' requires an argument\n"), + argv[0], argv[d->optind - 1]) >= 0) + { + _IO_flockfile (stderr); - int old_flags2 = ((_IO_FILE *) stderr)->_flags2; - ((_IO_FILE *) stderr)->_flags2 - |= _IO_FLAGS2_NOTCANCEL; + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 + |= _IO_FLAGS2_NOTCANCEL; - __fxprintf (NULL, "%s", buf); + __fxprintf (NULL, "%s", buf); - ((_IO_FILE *) stderr)->_flags2 = old_flags2; - _IO_funlockfile (stderr); + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); - free (buf); - } + free (buf); + } #else - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[d->optind - 1]); + fprintf (stderr, + _("%s: option '%s' requires an argument\n"), + argv[0], argv[d->optind - 1]); #endif - } - d->__nextchar += strlen (d->__nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - d->__nextchar += strlen (d->__nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - d->__nextchar = NULL; - return 'W'; /* Let the application handle it. */ + } + d->__nextchar += strlen (d->__nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + d->__nextchar += strlen (d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + d->__nextchar = NULL; + return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*d->__nextchar != '\0') - { - d->optarg = d->__nextchar; - d->optind++; - } - else - d->optarg = NULL; - d->__nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*d->__nextchar != '\0') - { - d->optarg = d->__nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - d->optind++; - } - else if (d->optind == argc) - { - if (print_errors) - { - /* 1003.2 specifies the format of this message. */ + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + d->optind++; + } + else + d->optarg = NULL; + d->__nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { #if defined _LIBC && defined USE_IN_LIBIO - char *buf; + char *buf; - if (__asprintf (&buf, _("\ -%s: option requires an argument -- %c\n"), - argv[0], c) >= 0) - { - _IO_flockfile (stderr); + if (__asprintf (&buf, _("\ +%s: option requires an argument -- '%c'\n"), + argv[0], c) >= 0) + { + _IO_flockfile (stderr); - int old_flags2 = ((_IO_FILE *) stderr)->_flags2; - ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; + int old_flags2 = ((_IO_FILE *) stderr)->_flags2; + ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; - __fxprintf (NULL, "%s", buf); + __fxprintf (NULL, "%s", buf); - ((_IO_FILE *) stderr)->_flags2 = old_flags2; - _IO_funlockfile (stderr); + ((_IO_FILE *) stderr)->_flags2 = old_flags2; + _IO_funlockfile (stderr); - free (buf); - } + free (buf); + } #else - fprintf (stderr, - _("%s: option requires an argument -- %c\n"), - argv[0], c); + fprintf (stderr, + _("%s: option requires an argument -- '%c'\n"), + argv[0], c); #endif - } - d->optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - d->optarg = argv[d->optind++]; - d->__nextchar = NULL; - } + } + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + d->optarg = argv[d->optind++]; + d->__nextchar = NULL; + } } return c; } @@ -1081,16 +1066,17 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, int _getopt_internal (int argc, char **argv, const char *optstring, - const struct option *longopts, int *longind, - int long_only, int posixly_correct) + const struct option *longopts, int *longind, int long_only, + int posixly_correct) { int result; getopt_data.optind = optind; getopt_data.opterr = opterr; - result = _getopt_internal_r (argc, argv, optstring, longopts, longind, - long_only, posixly_correct, &getopt_data); + result = _getopt_internal_r (argc, argv, optstring, longopts, + longind, long_only, &getopt_data, + posixly_correct); optind = getopt_data.optind; optarg = getopt_data.optarg; @@ -1110,10 +1096,23 @@ enum { POSIXLY_CORRECT = 1 }; int getopt (int argc, char *const *argv, const char *optstring) { - return _getopt_internal (argc, (char **) argv, optstring, NULL, NULL, 0, - POSIXLY_CORRECT); + return _getopt_internal (argc, (char **) argv, optstring, + (const struct option *) 0, + (int *) 0, + 0, POSIXLY_CORRECT); } +#ifdef _LIBC +int +__posix_getopt (int argc, char *const *argv, const char *optstring) +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0, 1); +} +#endif + #ifdef TEST @@ -1132,51 +1131,51 @@ main (int argc, char **argv) c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) - break; + break; switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; - case 'a': - printf ("option a\n"); - break; + case 'a': + printf ("option a\n"); + break; - case 'b': - printf ("option b\n"); - break; + case 'b': + printf ("option b\n"); + break; - case 'c': - printf ("option c with value `%s'\n", optarg); - break; + case 'c': + printf ("option c with value '%s'\n", optarg); + break; - case '?': - break; + case '?': + break; - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) - printf ("%s ", argv[optind++]); + printf ("%s ", argv[optind++]); printf ("\n"); } diff --git a/gnulib/getopt1.c b/gnulib/getopt1.c index d6a3ecf4e..046d69f94 100644 --- a/gnulib/getopt1.c +++ b/gnulib/getopt1.c @@ -1,6 +1,6 @@ /* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98,2004,2006 - Free Software Foundation, Inc. + Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, + 1998, 2004, 2006, 2009, 2010 Free Software Foundation, Inc. This file is part of the GNU C Library. This program is free software: you can redistribute it and/or modify @@ -32,25 +32,25 @@ #include #endif -#ifndef NULL +#ifndef NULL #define NULL 0 #endif int getopt_long (int argc, char *__getopt_argv_const *argv, const char *options, - const struct option *long_options, int *opt_index) + const struct option *long_options, int *opt_index) { return _getopt_internal (argc, (char **) argv, options, long_options, - opt_index, 0, 0); + opt_index, 0, 0); } int _getopt_long_r (int argc, char **argv, const char *options, - const struct option *long_options, int *opt_index, - struct _getopt_data *d) + const struct option *long_options, int *opt_index, + struct _getopt_data *d) { return _getopt_internal_r (argc, argv, options, long_options, opt_index, - 0, 0, d); + 0, d, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. @@ -60,20 +60,20 @@ _getopt_long_r (int argc, char **argv, const char *options, int getopt_long_only (int argc, char *__getopt_argv_const *argv, - const char *options, - const struct option *long_options, int *opt_index) + const char *options, + const struct option *long_options, int *opt_index) { return _getopt_internal (argc, (char **) argv, options, long_options, - opt_index, 1, 0); + opt_index, 1, 0); } int _getopt_long_only_r (int argc, char **argv, const char *options, - const struct option *long_options, int *opt_index, - struct _getopt_data *d) + const struct option *long_options, int *opt_index, + struct _getopt_data *d) { return _getopt_internal_r (argc, argv, options, long_options, opt_index, - 1, 0, d); + 1, d, 0); } @@ -91,76 +91,76 @@ main (int argc, char **argv) { int this_option_optind = optind ? optind : 1; int option_index = 0; - static struct option long_options[] = + static const struct option long_options[] = { - {"add", 1, 0, 0}, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", - long_options, &option_index); + long_options, &option_index); if (c == -1) - break; + break; switch (c) - { - case 0: - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; - case 'a': - printf ("option a\n"); - break; + case 'a': + printf ("option a\n"); + break; - case 'b': - printf ("option b\n"); - break; + case 'b': + printf ("option b\n"); + break; - case 'c': - printf ("option c with value `%s'\n", optarg); - break; + case 'c': + printf ("option c with value `%s'\n", optarg); + break; - case 'd': - printf ("option d with value `%s'\n", optarg); - break; + case 'd': + printf ("option d with value `%s'\n", optarg); + break; - case '?': - break; + case '?': + break; - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) - printf ("%s ", argv[optind++]); + printf ("%s ", argv[optind++]); printf ("\n"); } diff --git a/gnulib/getopt_int.h b/gnulib/getopt_int.h index 3c6628bb9..169def5b2 100644 --- a/gnulib/getopt_int.h +++ b/gnulib/getopt_int.h @@ -1,6 +1,6 @@ /* Internal declarations for getopt. - Copyright (C) 1989-1994,1996-1999,2001,2003,2004 - Free Software Foundation, Inc. + Copyright (C) 1989-1994, 1996-1999, 2001, 2003-2004, 2009-2010 Free Software + Foundation, Inc. This file is part of the GNU C Library. This program is free software: you can redistribute it and/or modify @@ -17,12 +17,14 @@ along with this program. If not, see . */ #ifndef _GETOPT_INT_H -#define _GETOPT_INT_H 1 +#define _GETOPT_INT_H 1 + +#include extern int _getopt_internal (int ___argc, char **___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind, - int __long_only, int __posixly_correct); + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only, int __posixly_correct); /* Reentrant versions which can handle parsing multiple argument @@ -108,23 +110,23 @@ struct _getopt_data /* The initializer is necessary to set OPTIND and OPTERR to their default values and to clear the initialization flag. */ -#define _GETOPT_DATA_INITIALIZER { 1, 1 } +#define _GETOPT_DATA_INITIALIZER { 1, 1 } extern int _getopt_internal_r (int ___argc, char **___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind, - int __long_only, int __posixly_correct, - struct _getopt_data *__data); + const char *__shortopts, + const struct option *__longopts, int *__longind, + int __long_only, struct _getopt_data *__data, + int __posixly_correct); extern int _getopt_long_r (int ___argc, char **___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind, - struct _getopt_data *__data); + const char *__shortopts, + const struct option *__longopts, int *__longind, + struct _getopt_data *__data); extern int _getopt_long_only_r (int ___argc, char **___argv, - const char *__shortopts, - const struct option *__longopts, - int *__longind, - struct _getopt_data *__data); + const char *__shortopts, + const struct option *__longopts, + int *__longind, + struct _getopt_data *__data); #endif /* getopt_int.h */ diff --git a/gnulib/gettext.h b/gnulib/gettext.h index 9d76ec9af..6a069c448 100644 --- a/gnulib/gettext.h +++ b/gnulib/gettext.h @@ -1,5 +1,6 @@ /* Convenience header for conditional use of GNU . - Copyright (C) 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2010 Free Software + Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -63,21 +64,30 @@ for invalid uses of the value returned from these functions. On pre-ANSI systems without 'const', the config.h file is supposed to contain "#define const". */ +# undef gettext # define gettext(Msgid) ((const char *) (Msgid)) +# undef dgettext # define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) +# undef dcgettext # define dcgettext(Domainname, Msgid, Category) \ ((void) (Category), dgettext (Domainname, Msgid)) +# undef ngettext # define ngettext(Msgid1, Msgid2, N) \ ((N) == 1 \ ? ((void) (Msgid2), (const char *) (Msgid1)) \ : ((void) (Msgid1), (const char *) (Msgid2))) +# undef dngettext # define dngettext(Domainname, Msgid1, Msgid2, N) \ ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) +# undef dcngettext # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ - ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N)) + ((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N)) +# undef textdomain # define textdomain(Domainname) ((const char *) (Domainname)) +# undef bindtextdomain # define bindtextdomain(Domainname, Dirname) \ ((void) (Domainname), (const char *) (Dirname)) +# undef bind_textdomain_codeset # define bind_textdomain_codeset(Domainname, Codeset) \ ((void) (Domainname), (const char *) (Codeset)) @@ -131,8 +141,8 @@ inline #endif static const char * pgettext_aux (const char *domain, - const char *msg_ctxt_id, const char *msgid, - int category) + const char *msg_ctxt_id, const char *msgid, + int category) { const char *translation = dcgettext (domain, msg_ctxt_id, category); if (translation == msg_ctxt_id) @@ -150,9 +160,9 @@ inline #endif static const char * npgettext_aux (const char *domain, - const char *msg_ctxt_id, const char *msgid, - const char *msgid_plural, unsigned long int n, - int category) + const char *msg_ctxt_id, const char *msgid, + const char *msgid_plural, unsigned long int n, + int category) { const char *translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); @@ -190,8 +200,8 @@ inline #endif static const char * dcpgettext_expr (const char *domain, - const char *msgctxt, const char *msgid, - int category) + const char *msgctxt, const char *msgid, + int category) { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; @@ -213,10 +223,10 @@ dcpgettext_expr (const char *domain, translation = dcgettext (domain, msg_ctxt_id, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) - free (msg_ctxt_id); + free (msg_ctxt_id); #endif if (translation != msg_ctxt_id) - return translation; + return translation; } return msgid; } @@ -235,9 +245,9 @@ inline #endif static const char * dcnpgettext_expr (const char *domain, - const char *msgctxt, const char *msgid, - const char *msgid_plural, unsigned long int n, - int category) + const char *msgctxt, const char *msgid, + const char *msgid_plural, unsigned long int n, + int category) { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; @@ -259,10 +269,10 @@ dcnpgettext_expr (const char *domain, translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) - free (msg_ctxt_id); + free (msg_ctxt_id); #endif if (!(translation == msg_ctxt_id || translation == msgid_plural)) - return translation; + return translation; } return (n == 1 ? msgid : msgid_plural); } diff --git a/gnulib/progname.c b/gnulib/progname.c index bfa374a52..1415e6a55 100644 --- a/gnulib/progname.c +++ b/gnulib/progname.c @@ -1,6 +1,6 @@ /* Program name management. - Copyright (C) 2001-2003, 2005-2009 Free Software Foundation, Inc. - Written by Bruno Haible , 2001. + Copyright (C) 2001-2003, 2005-2010 Free Software Foundation, Inc. + Written by Bruno Haible , 2001. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,6 +23,8 @@ #include "progname.h" #include /* get program_invocation_name declaration */ +#include +#include #include @@ -30,7 +32,9 @@ To be initialized by main(). */ const char *program_name = NULL; -/* Set program_name, based on argv[0]. */ +/* Set program_name, based on argv[0]. + argv0 must be a string allocated with indefinite extent, and must not be + modified after this call. */ void set_program_name (const char *argv0) { @@ -42,20 +46,30 @@ set_program_name (const char *argv0) const char *slash; const char *base; + /* Sanity check. POSIX requires the invoking process to pass a non-NULL + argv[0]. */ + if (argv0 == NULL) + { + /* It's a bug in the invoking program. Help diagnosing it. */ + fputs ("A NULL argv[0] was passed through an exec system call.\n", + stderr); + abort (); + } + slash = strrchr (argv0, '/'); base = (slash != NULL ? slash + 1 : argv0); if (base - argv0 >= 7 && strncmp (base - 7, "/.libs/", 7) == 0) { argv0 = base; if (strncmp (base, "lt-", 3) == 0) - { - argv0 = base + 3; - /* On glibc systems, remove the "lt-" prefix from the variable - program_invocation_short_name. */ + { + argv0 = base + 3; + /* On glibc systems, remove the "lt-" prefix from the variable + program_invocation_short_name. */ #if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME - program_invocation_short_name = (char *) argv0; + program_invocation_short_name = (char *) argv0; #endif - } + } } /* But don't strip off a leading / in general, because when the user diff --git a/gnulib/progname.h b/gnulib/progname.h index 82615c6bc..5ba303bd0 100644 --- a/gnulib/progname.h +++ b/gnulib/progname.h @@ -1,6 +1,6 @@ /* Program name management. - Copyright (C) 2001-2004, 2006 Free Software Foundation, Inc. - Written by Bruno Haible , 2001. + Copyright (C) 2001-2004, 2006, 2009-2010 Free Software Foundation, Inc. + Written by Bruno Haible , 2001. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,7 +31,9 @@ extern "C" { /* String containing name the program is called with. */ extern const char *program_name; -/* Set program_name, based on argv[0]. */ +/* Set program_name, based on argv[0]. + argv0 must be a string allocated with indefinite extent, and must not be + modified after this call. */ extern void set_program_name (const char *argv0); #if ENABLE_RELOCATABLE @@ -39,8 +41,8 @@ extern void set_program_name (const char *argv0); /* Set program_name, based on argv[0], and original installation prefix and directory, for relocatability. */ extern void set_program_name_and_installdir (const char *argv0, - const char *orig_installprefix, - const char *orig_installdir); + const char *orig_installprefix, + const char *orig_installdir); #undef set_program_name #define set_program_name(ARG0) \ set_program_name_and_installdir (ARG0, INSTALLPREFIX, INSTALLDIR) diff --git a/gnulib/regcomp.c b/gnulib/regcomp.c new file mode 100644 index 000000000..7eff56925 --- /dev/null +++ b/gnulib/regcomp.c @@ -0,0 +1,3877 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free + Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + This program 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 2, or (at your option) + any later version. + + This program 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 this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, + size_t length, reg_syntax_t syntax); +static void re_compile_fastmap_iter (regex_t *bufp, + const re_dfastate_t *init_state, + char *fastmap); +static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len); +#ifdef RE_ENABLE_I18N +static void free_charset (re_charset_t *cset); +#endif /* RE_ENABLE_I18N */ +static void free_workarea_compile (regex_t *preg); +static reg_errcode_t create_initial_state (re_dfa_t *dfa); +#ifdef RE_ENABLE_I18N +static void optimize_utf8 (re_dfa_t *dfa); +#endif +static reg_errcode_t analyze (regex_t *preg); +static reg_errcode_t preorder (bin_tree_t *root, + reg_errcode_t (fn (void *, bin_tree_t *)), + void *extra); +static reg_errcode_t postorder (bin_tree_t *root, + reg_errcode_t (fn (void *, bin_tree_t *)), + void *extra); +static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node); +static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node); +static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg, + bin_tree_t *node); +static reg_errcode_t calc_first (void *extra, bin_tree_t *node); +static reg_errcode_t calc_next (void *extra, bin_tree_t *node); +static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node); +static Idx duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int constraint); +static Idx search_duplicated_node (const re_dfa_t *dfa, Idx org_node, + unsigned int constraint); +static reg_errcode_t calc_eclosure (re_dfa_t *dfa); +static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, + Idx node, bool root); +static reg_errcode_t calc_inveclosure (re_dfa_t *dfa); +static Idx fetch_number (re_string_t *input, re_token_t *token, + reg_syntax_t syntax); +static int peek_token (re_token_t *token, re_string_t *input, + reg_syntax_t syntax) internal_function; +static bin_tree_t *parse (re_string_t *regexp, regex_t *preg, + reg_syntax_t syntax, reg_errcode_t *err); +static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg, + re_token_t *token, reg_syntax_t syntax, + Idx nest, reg_errcode_t *err); +static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg, + re_token_t *token, reg_syntax_t syntax, + Idx nest, reg_errcode_t *err); +static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg, + re_token_t *token, reg_syntax_t syntax, + Idx nest, reg_errcode_t *err); +static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg, + re_token_t *token, reg_syntax_t syntax, + Idx nest, reg_errcode_t *err); +static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp, + re_dfa_t *dfa, re_token_t *token, + reg_syntax_t syntax, reg_errcode_t *err); +static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, + re_token_t *token, reg_syntax_t syntax, + reg_errcode_t *err); +static reg_errcode_t parse_bracket_element (bracket_elem_t *elem, + re_string_t *regexp, + re_token_t *token, int token_len, + re_dfa_t *dfa, + reg_syntax_t syntax, + bool accept_hyphen); +static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem, + re_string_t *regexp, + re_token_t *token); +#ifdef RE_ENABLE_I18N +static reg_errcode_t build_equiv_class (bitset_t sbcset, + re_charset_t *mbcset, + Idx *equiv_class_alloc, + const unsigned char *name); +static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans, + bitset_t sbcset, + re_charset_t *mbcset, + Idx *char_class_alloc, + const unsigned char *class_name, + reg_syntax_t syntax); +#else /* not RE_ENABLE_I18N */ +static reg_errcode_t build_equiv_class (bitset_t sbcset, + const unsigned char *name); +static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans, + bitset_t sbcset, + const unsigned char *class_name, + reg_syntax_t syntax); +#endif /* not RE_ENABLE_I18N */ +static bin_tree_t *build_charclass_op (re_dfa_t *dfa, + RE_TRANSLATE_TYPE trans, + const unsigned char *class_name, + const unsigned char *extra, + bool non_match, reg_errcode_t *err); +static bin_tree_t *create_tree (re_dfa_t *dfa, + bin_tree_t *left, bin_tree_t *right, + re_token_type_t type); +static bin_tree_t *create_token_tree (re_dfa_t *dfa, + bin_tree_t *left, bin_tree_t *right, + const re_token_t *token); +static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa); +static void free_token (re_token_t *node); +static reg_errcode_t free_tree (void *extra, bin_tree_t *node); +static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node); + +/* This table gives an error message for each of the error codes listed + in regex.h. Obviously the order here has to be same as there. + POSIX doesn't require that we do anything for REG_NOERROR, + but why not be nice? */ + +static const char __re_error_msgid[] = + { +#define REG_NOERROR_IDX 0 + gettext_noop ("Success") /* REG_NOERROR */ + "\0" +#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") + gettext_noop ("No match") /* REG_NOMATCH */ + "\0" +#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") + gettext_noop ("Invalid regular expression") /* REG_BADPAT */ + "\0" +#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") + gettext_noop ("Invalid collation character") /* REG_ECOLLATE */ + "\0" +#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") + gettext_noop ("Invalid character class name") /* REG_ECTYPE */ + "\0" +#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") + gettext_noop ("Trailing backslash") /* REG_EESCAPE */ + "\0" +#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") + gettext_noop ("Invalid back reference") /* REG_ESUBREG */ + "\0" +#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") + gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */ + "\0" +#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^") + gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ + "\0" +#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") + gettext_noop ("Unmatched \\{") /* REG_EBRACE */ + "\0" +#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") + gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ + "\0" +#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") + gettext_noop ("Invalid range end") /* REG_ERANGE */ + "\0" +#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") + gettext_noop ("Memory exhausted") /* REG_ESPACE */ + "\0" +#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") + gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ + "\0" +#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") + gettext_noop ("Premature end of regular expression") /* REG_EEND */ + "\0" +#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") + gettext_noop ("Regular expression too big") /* REG_ESIZE */ + "\0" +#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") + gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ + }; + +static const size_t __re_error_msgid_idx[] = + { + REG_NOERROR_IDX, + REG_NOMATCH_IDX, + REG_BADPAT_IDX, + REG_ECOLLATE_IDX, + REG_ECTYPE_IDX, + REG_EESCAPE_IDX, + REG_ESUBREG_IDX, + REG_EBRACK_IDX, + REG_EPAREN_IDX, + REG_EBRACE_IDX, + REG_BADBR_IDX, + REG_ERANGE_IDX, + REG_ESPACE_IDX, + REG_BADRPT_IDX, + REG_EEND_IDX, + REG_ESIZE_IDX, + REG_ERPAREN_IDX + }; + +/* Entry points for GNU code. */ + +/* re_compile_pattern is the GNU regular expression compiler: it + compiles PATTERN (of length LENGTH) and puts the result in BUFP. + Returns 0 if the pattern was valid, otherwise an error string. + + Assumes the `allocated' (and perhaps `buffer') and `translate' fields + are set in BUFP on entry. */ + +#ifdef _LIBC +const char * +re_compile_pattern (pattern, length, bufp) + const char *pattern; + size_t length; + struct re_pattern_buffer *bufp; +#else /* size_t might promote */ +const char * +re_compile_pattern (const char *pattern, size_t length, + struct re_pattern_buffer *bufp) +#endif +{ + reg_errcode_t ret; + + /* And GNU code determines whether or not to get register information + by passing null for the REGS argument to re_match, etc., not by + setting no_sub, unless RE_NO_SUB is set. */ + bufp->no_sub = !!(re_syntax_options & RE_NO_SUB); + + /* Match anchors at newline. */ + bufp->newline_anchor = 1; + + ret = re_compile_internal (bufp, pattern, length, re_syntax_options); + + if (!ret) + return NULL; + return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); +} +#ifdef _LIBC +weak_alias (__re_compile_pattern, re_compile_pattern) +#endif + +/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can + also be assigned to arbitrarily: each pattern buffer stores its own + syntax, so it can be changed between regex compilations. */ +/* This has no initializer because initialized variables in Emacs + become read-only after dumping. */ +reg_syntax_t re_syntax_options; + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit mask comprised of the various bits + defined in regex.h. We return the old syntax. */ + +reg_syntax_t +re_set_syntax (syntax) + reg_syntax_t syntax; +{ + reg_syntax_t ret = re_syntax_options; + + re_syntax_options = syntax; + return ret; +} +#ifdef _LIBC +weak_alias (__re_set_syntax, re_set_syntax) +#endif + +int +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; + char *fastmap = bufp->fastmap; + + memset (fastmap, '\0', sizeof (char) * SBC_MAX); + re_compile_fastmap_iter (bufp, dfa->init_state, fastmap); + if (dfa->init_state != dfa->init_state_word) + re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap); + if (dfa->init_state != dfa->init_state_nl) + re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap); + if (dfa->init_state != dfa->init_state_begbuf) + re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap); + bufp->fastmap_accurate = 1; + return 0; +} +#ifdef _LIBC +weak_alias (__re_compile_fastmap, re_compile_fastmap) +#endif + +static inline void +__attribute ((always_inline)) +re_set_fastmap (char *fastmap, bool icase, int ch) +{ + fastmap[ch] = 1; + if (icase) + fastmap[tolower (ch)] = 1; +} + +/* Helper function for re_compile_fastmap. + Compile fastmap for the initial_state INIT_STATE. */ + +static void +re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, + char *fastmap) +{ + re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; + Idx node_cnt; + bool icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE)); + for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) + { + Idx node = init_state->nodes.elems[node_cnt]; + re_token_type_t type = dfa->nodes[node].type; + + if (type == CHARACTER) + { + re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c); +#ifdef RE_ENABLE_I18N + if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) + { + unsigned char buf[MB_LEN_MAX]; + unsigned char *p; + wchar_t wc; + mbstate_t state; + + p = buf; + *p++ = dfa->nodes[node].opr.c; + while (++node < dfa->nodes_len + && dfa->nodes[node].type == CHARACTER + && dfa->nodes[node].mb_partial) + *p++ = dfa->nodes[node].opr.c; + memset (&state, '\0', sizeof (state)); + if (__mbrtowc (&wc, (const char *) buf, p - buf, + &state) == p - buf + && (__wcrtomb ((char *) buf, towlower (wc), &state) + != (size_t) -1)) + re_set_fastmap (fastmap, false, buf[0]); + } +#endif + } + else if (type == SIMPLE_BRACKET) + { + int i, ch; + for (i = 0, ch = 0; i < BITSET_WORDS; ++i) + { + int j; + bitset_word_t w = dfa->nodes[node].opr.sbcset[i]; + for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) + if (w & ((bitset_word_t) 1 << j)) + re_set_fastmap (fastmap, icase, ch); + } + } +#ifdef RE_ENABLE_I18N + else if (type == COMPLEX_BRACKET) + { + re_charset_t *cset = dfa->nodes[node].opr.mbcset; + Idx i; + +# ifdef _LIBC + /* See if we have to try all bytes which start multiple collation + elements. + e.g. In da_DK, we want to catch 'a' since "aa" is a valid + collation element, and don't catch 'b' since 'b' is + the only collation element which starts from 'b' (and + it is caught by SIMPLE_BRACKET). */ + if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0 + && (cset->ncoll_syms || cset->nranges)) + { + const int32_t *table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); + for (i = 0; i < SBC_MAX; ++i) + if (table[i] < 0) + re_set_fastmap (fastmap, icase, i); + } +# endif /* _LIBC */ + + /* See if we have to start the match at all multibyte characters, + i.e. where we would not find an invalid sequence. This only + applies to multibyte character sets; for single byte character + sets, the SIMPLE_BRACKET again suffices. */ + if (dfa->mb_cur_max > 1 + && (cset->nchar_classes || cset->non_match || cset->nranges +# ifdef _LIBC + || cset->nequiv_classes +# endif /* _LIBC */ + )) + { + unsigned char c = 0; + do + { + mbstate_t mbs; + memset (&mbs, 0, sizeof (mbs)); + if (__mbrtowc (NULL, (char *) &c, 1, &mbs) == (size_t) -2) + re_set_fastmap (fastmap, false, (int) c); + } + while (++c != 0); + } + + else + { + /* ... Else catch all bytes which can start the mbchars. */ + for (i = 0; i < cset->nmbchars; ++i) + { + char buf[256]; + mbstate_t state; + memset (&state, '\0', sizeof (state)); + if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1) + re_set_fastmap (fastmap, icase, *(unsigned char *) buf); + if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) + { + if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state) + != (size_t) -1) + re_set_fastmap (fastmap, false, *(unsigned char *) buf); + } + } + } + } +#endif /* RE_ENABLE_I18N */ + else if (type == OP_PERIOD +#ifdef RE_ENABLE_I18N + || type == OP_UTF8_PERIOD +#endif /* RE_ENABLE_I18N */ + || type == END_OF_RE) + { + memset (fastmap, '\1', sizeof (char) * SBC_MAX); + if (type == END_OF_RE) + bufp->can_be_null = 1; + return; + } + } +} + +/* Entry point for POSIX code. */ +/* regcomp takes a regular expression as a string and compiles it. + + PREG is a regex_t *. We do not expect any fields to be initialized, + since POSIX says we shouldn't. Thus, we set + + `buffer' to the compiled pattern; + `used' to the length of the compiled pattern; + `syntax' to RE_SYNTAX_POSIX_EXTENDED if the + REG_EXTENDED bit in CFLAGS is set; otherwise, to + RE_SYNTAX_POSIX_BASIC; + `newline_anchor' to REG_NEWLINE being set in CFLAGS; + `fastmap' to an allocated space for the fastmap; + `fastmap_accurate' to zero; + `re_nsub' to the number of subexpressions in PATTERN. + + PATTERN is the address of the pattern string. + + CFLAGS is a series of bits which affect compilation. + + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we + use POSIX basic syntax. + + If REG_NEWLINE is set, then . and [^...] don't match newline. + Also, regexec will try a match beginning after every newline. + + If REG_ICASE is set, then we considers upper- and lowercase + versions of letters to be equivalent when matching. + + If REG_NOSUB is set, then when PREG is passed to regexec, that + routine will report only success or failure, and nothing about the + registers. + + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + the return codes and their meanings.) */ + +int +regcomp (preg, pattern, cflags) + regex_t *_Restrict_ preg; + const char *_Restrict_ pattern; + int cflags; +{ + reg_errcode_t ret; + reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED + : RE_SYNTAX_POSIX_BASIC); + + preg->buffer = NULL; + preg->allocated = 0; + preg->used = 0; + + /* Try to allocate space for the fastmap. */ + preg->fastmap = re_malloc (char, SBC_MAX); + if (BE (preg->fastmap == NULL, 0)) + return REG_ESPACE; + + syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0; + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (cflags & REG_NEWLINE) + { /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + /* It also changes the matching behavior. */ + preg->newline_anchor = 1; + } + else + preg->newline_anchor = 0; + preg->no_sub = !!(cflags & REG_NOSUB); + preg->translate = NULL; + + ret = re_compile_internal (preg, pattern, strlen (pattern), syntax); + + /* POSIX doesn't distinguish between an unmatched open-group and an + unmatched close-group: both are REG_EPAREN. */ + if (ret == REG_ERPAREN) + ret = REG_EPAREN; + + /* We have already checked preg->fastmap != NULL. */ + if (BE (ret == REG_NOERROR, 1)) + /* Compute the fastmap now, since regexec cannot modify the pattern + buffer. This function never fails in this implementation. */ + (void) re_compile_fastmap (preg); + else + { + /* Some error occurred while compiling the expression. */ + re_free (preg->fastmap); + preg->fastmap = NULL; + } + + return (int) ret; +} +#ifdef _LIBC +weak_alias (__regcomp, regcomp) +#endif + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +#ifdef _LIBC +size_t +regerror (errcode, preg, errbuf, errbuf_size) + int errcode; + const regex_t *_Restrict_ preg; + char *_Restrict_ errbuf; + size_t errbuf_size; +#else /* size_t might promote */ +size_t +regerror (int errcode, const regex_t *_Restrict_ preg, + char *_Restrict_ errbuf, size_t errbuf_size) +#endif +{ + const char *msg; + size_t msg_size; + + if (BE (errcode < 0 + || errcode >= (int) (sizeof (__re_error_msgid_idx) + / sizeof (__re_error_msgid_idx[0])), 0)) + /* Only error codes returned by the rest of the code should be passed + to this routine. If we are given anything else, or if other regex + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort (); + + msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); + + msg_size = strlen (msg) + 1; /* Includes the null. */ + + if (BE (errbuf_size != 0, 1)) + { + size_t cpy_size = msg_size; + if (BE (msg_size > errbuf_size, 0)) + { + cpy_size = errbuf_size - 1; + errbuf[cpy_size] = '\0'; + } + memcpy (errbuf, msg, cpy_size); + } + + return msg_size; +} +#ifdef _LIBC +weak_alias (__regerror, regerror) +#endif + + +#ifdef RE_ENABLE_I18N +/* This static array is used for the map to single-byte characters when + UTF-8 is used. Otherwise we would allocate memory just to initialize + it the same all the time. UTF-8 is the preferred encoding so this is + a worthwhile optimization. */ +static const bitset_t utf8_sb_map = +{ + /* Set the first 128 bits. */ +# if 4 * BITSET_WORD_BITS < ASCII_CHARS +# error "bitset_word_t is narrower than 32 bits" +# elif 3 * BITSET_WORD_BITS < ASCII_CHARS + BITSET_WORD_MAX, BITSET_WORD_MAX, BITSET_WORD_MAX, +# elif 2 * BITSET_WORD_BITS < ASCII_CHARS + BITSET_WORD_MAX, BITSET_WORD_MAX, +# elif 1 * BITSET_WORD_BITS < ASCII_CHARS + BITSET_WORD_MAX, +# endif + (BITSET_WORD_MAX + >> (SBC_MAX % BITSET_WORD_BITS == 0 + ? 0 + : BITSET_WORD_BITS - SBC_MAX % BITSET_WORD_BITS)) +}; +#endif + + +static void +free_dfa_content (re_dfa_t *dfa) +{ + Idx i, j; + + if (dfa->nodes) + for (i = 0; i < dfa->nodes_len; ++i) + free_token (dfa->nodes + i); + re_free (dfa->nexts); + for (i = 0; i < dfa->nodes_len; ++i) + { + if (dfa->eclosures != NULL) + re_node_set_free (dfa->eclosures + i); + if (dfa->inveclosures != NULL) + re_node_set_free (dfa->inveclosures + i); + if (dfa->edests != NULL) + re_node_set_free (dfa->edests + i); + } + re_free (dfa->edests); + re_free (dfa->eclosures); + re_free (dfa->inveclosures); + re_free (dfa->nodes); + + if (dfa->state_table) + for (i = 0; i <= dfa->state_hash_mask; ++i) + { + struct re_state_table_entry *entry = dfa->state_table + i; + for (j = 0; j < entry->num; ++j) + { + re_dfastate_t *state = entry->array[j]; + free_state (state); + } + re_free (entry->array); + } + re_free (dfa->state_table); +#ifdef RE_ENABLE_I18N + if (dfa->sb_char != utf8_sb_map) + re_free (dfa->sb_char); +#endif + re_free (dfa->subexp_map); +#ifdef DEBUG + re_free (dfa->re_str); +#endif + + re_free (dfa); +} + + +/* Free dynamically allocated space used by PREG. */ + +void +regfree (preg) + regex_t *preg; +{ + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; + if (BE (dfa != NULL, 1)) + free_dfa_content (dfa); + preg->buffer = NULL; + preg->allocated = 0; + + re_free (preg->fastmap); + preg->fastmap = NULL; + + re_free (preg->translate); + preg->translate = NULL; +} +#ifdef _LIBC +weak_alias (__regfree, regfree) +#endif + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them unless specifically requested. */ + +#if defined _REGEX_RE_COMP || defined _LIBC + +/* BSD has one and only one pattern buffer. */ +static struct re_pattern_buffer re_comp_buf; + +char * +# ifdef _LIBC +/* Make these definitions weak in libc, so POSIX programs can redefine + these names if they don't use our functions, and still use + regcomp/regexec above without link errors. */ +weak_function +# endif +re_comp (s) + const char *s; +{ + reg_errcode_t ret; + char *fastmap; + + if (!s) + { + if (!re_comp_buf.buffer) + return gettext ("No previous regular expression"); + return 0; + } + + if (re_comp_buf.buffer) + { + fastmap = re_comp_buf.fastmap; + re_comp_buf.fastmap = NULL; + __regfree (&re_comp_buf); + memset (&re_comp_buf, '\0', sizeof (re_comp_buf)); + re_comp_buf.fastmap = fastmap; + } + + if (re_comp_buf.fastmap == NULL) + { + re_comp_buf.fastmap = (char *) malloc (SBC_MAX); + if (re_comp_buf.fastmap == NULL) + return (char *) gettext (__re_error_msgid + + __re_error_msgid_idx[(int) REG_ESPACE]); + } + + /* Since `re_exec' always passes NULL for the `regs' argument, we + don't need to initialize the pattern buffer fields which affect it. */ + + /* Match anchors at newlines. */ + re_comp_buf.newline_anchor = 1; + + ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options); + + if (!ret) + return NULL; + + /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ + return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); +} + +#ifdef _LIBC +libc_freeres_fn (free_mem) +{ + __regfree (&re_comp_buf); +} +#endif + +#endif /* _REGEX_RE_COMP */ + +/* Internal entry point. + Compile the regular expression PATTERN, whose length is LENGTH. + SYNTAX indicate regular expression's syntax. */ + +static reg_errcode_t +re_compile_internal (regex_t *preg, const char * pattern, size_t length, + reg_syntax_t syntax) +{ + reg_errcode_t err = REG_NOERROR; + re_dfa_t *dfa; + re_string_t regexp; + + /* Initialize the pattern buffer. */ + preg->fastmap_accurate = 0; + preg->syntax = syntax; + preg->not_bol = preg->not_eol = 0; + preg->used = 0; + preg->re_nsub = 0; + preg->can_be_null = 0; + preg->regs_allocated = REGS_UNALLOCATED; + + /* Initialize the dfa. */ + dfa = (re_dfa_t *) preg->buffer; + if (BE (preg->allocated < sizeof (re_dfa_t), 0)) + { + /* If zero allocated, but buffer is non-null, try to realloc + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. If ->buffer is NULL this + is a simple allocation. */ + dfa = re_realloc (preg->buffer, re_dfa_t, 1); + if (dfa == NULL) + return REG_ESPACE; + preg->allocated = sizeof (re_dfa_t); + preg->buffer = (unsigned char *) dfa; + } + preg->used = sizeof (re_dfa_t); + + err = init_dfa (dfa, length); + if (BE (err != REG_NOERROR, 0)) + { + free_dfa_content (dfa); + preg->buffer = NULL; + preg->allocated = 0; + return err; + } +#ifdef DEBUG + /* Note: length+1 will not overflow since it is checked in init_dfa. */ + dfa->re_str = re_malloc (char, length + 1); + strncpy (dfa->re_str, pattern, length + 1); +#endif + + __libc_lock_init (dfa->lock); + + err = re_string_construct (®exp, pattern, length, preg->translate, + (syntax & RE_ICASE) != 0, dfa); + if (BE (err != REG_NOERROR, 0)) + { + re_compile_internal_free_return: + free_workarea_compile (preg); + re_string_destruct (®exp); + free_dfa_content (dfa); + preg->buffer = NULL; + preg->allocated = 0; + return err; + } + + /* Parse the regular expression, and build a structure tree. */ + preg->re_nsub = 0; + dfa->str_tree = parse (®exp, preg, syntax, &err); + if (BE (dfa->str_tree == NULL, 0)) + goto re_compile_internal_free_return; + + /* Analyze the tree and create the nfa. */ + err = analyze (preg); + if (BE (err != REG_NOERROR, 0)) + goto re_compile_internal_free_return; + +#ifdef RE_ENABLE_I18N + /* If possible, do searching in single byte encoding to speed things up. */ + if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL) + optimize_utf8 (dfa); +#endif + + /* Then create the initial state of the dfa. */ + err = create_initial_state (dfa); + + /* Release work areas. */ + free_workarea_compile (preg); + re_string_destruct (®exp); + + if (BE (err != REG_NOERROR, 0)) + { + free_dfa_content (dfa); + preg->buffer = NULL; + preg->allocated = 0; + } + + return err; +} + +/* Initialize DFA. We use the length of the regular expression PAT_LEN + as the initial length of some arrays. */ + +static reg_errcode_t +init_dfa (re_dfa_t *dfa, size_t pat_len) +{ + __re_size_t table_size; +#ifndef _LIBC + char *codeset_name; +#endif +#ifdef RE_ENABLE_I18N + size_t max_i18n_object_size = MAX (sizeof (wchar_t), sizeof (wctype_t)); +#else + size_t max_i18n_object_size = 0; +#endif + size_t max_object_size = + MAX (sizeof (struct re_state_table_entry), + MAX (sizeof (re_token_t), + MAX (sizeof (re_node_set), + MAX (sizeof (regmatch_t), + max_i18n_object_size)))); + + memset (dfa, '\0', sizeof (re_dfa_t)); + + /* Force allocation of str_tree_storage the first time. */ + dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; + + /* Avoid overflows. The extra "/ 2" is for the table_size doubling + calculation below, and for similar doubling calculations + elsewhere. And it's <= rather than <, because some of the + doubling calculations add 1 afterwards. */ + if (BE (SIZE_MAX / max_object_size / 2 <= pat_len, 0)) + return REG_ESPACE; + + dfa->nodes_alloc = pat_len + 1; + dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc); + + /* table_size = 2 ^ ceil(log pat_len) */ + for (table_size = 1; ; table_size <<= 1) + if (table_size > pat_len) + break; + + dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size); + dfa->state_hash_mask = table_size - 1; + + dfa->mb_cur_max = MB_CUR_MAX; +#ifdef _LIBC + if (dfa->mb_cur_max == 6 + && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0) + dfa->is_utf8 = 1; + dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII) + != 0); +#else + codeset_name = nl_langinfo (CODESET); + if (strcasecmp (codeset_name, "UTF-8") == 0 + || strcasecmp (codeset_name, "UTF8") == 0) + dfa->is_utf8 = 1; + + /* We check exhaustively in the loop below if this charset is a + superset of ASCII. */ + dfa->map_notascii = 0; +#endif + +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + { + if (dfa->is_utf8) + dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map; + else + { + int i, j, ch; + + dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); + if (BE (dfa->sb_char == NULL, 0)) + return REG_ESPACE; + + /* Set the bits corresponding to single byte chars. */ + for (i = 0, ch = 0; i < BITSET_WORDS; ++i) + for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) + { + wint_t wch = __btowc (ch); + if (wch != WEOF) + dfa->sb_char[i] |= (bitset_word_t) 1 << j; +# ifndef _LIBC + if (isascii (ch) && wch != ch) + dfa->map_notascii = 1; +# endif + } + } + } +#endif + + if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0)) + return REG_ESPACE; + return REG_NOERROR; +} + +/* Initialize WORD_CHAR table, which indicate which character is + "word". In this case "word" means that it is the word construction + character used by some operators like "\<", "\>", etc. */ + +static void +internal_function +init_word_char (re_dfa_t *dfa) +{ + int i, j, ch; + dfa->word_ops_used = 1; + for (i = 0, ch = 0; i < BITSET_WORDS; ++i) + for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) + if (isalnum (ch) || ch == '_') + dfa->word_char[i] |= (bitset_word_t) 1 << j; +} + +/* Free the work area which are only used while compiling. */ + +static void +free_workarea_compile (regex_t *preg) +{ + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; + bin_tree_storage_t *storage, *next; + for (storage = dfa->str_tree_storage; storage; storage = next) + { + next = storage->next; + re_free (storage); + } + dfa->str_tree_storage = NULL; + dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; + dfa->str_tree = NULL; + re_free (dfa->org_indices); + dfa->org_indices = NULL; +} + +/* Create initial states for all contexts. */ + +static reg_errcode_t +create_initial_state (re_dfa_t *dfa) +{ + Idx first, i; + reg_errcode_t err; + re_node_set init_nodes; + + /* Initial states have the epsilon closure of the node which is + the first node of the regular expression. */ + first = dfa->str_tree->first->node_idx; + dfa->init_node = first; + err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first); + if (BE (err != REG_NOERROR, 0)) + return err; + + /* The back-references which are in initial states can epsilon transit, + since in this case all of the subexpressions can be null. + Then we add epsilon closures of the nodes which are the next nodes of + the back-references. */ + if (dfa->nbackref > 0) + for (i = 0; i < init_nodes.nelem; ++i) + { + Idx node_idx = init_nodes.elems[i]; + re_token_type_t type = dfa->nodes[node_idx].type; + + Idx clexp_idx; + if (type != OP_BACK_REF) + continue; + for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx) + { + re_token_t *clexp_node; + clexp_node = dfa->nodes + init_nodes.elems[clexp_idx]; + if (clexp_node->type == OP_CLOSE_SUBEXP + && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx) + break; + } + if (clexp_idx == init_nodes.nelem) + continue; + + if (type == OP_BACK_REF) + { + Idx dest_idx = dfa->edests[node_idx].elems[0]; + if (!re_node_set_contains (&init_nodes, dest_idx)) + { + reg_errcode_t merge_err + = re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx); + if (merge_err != REG_NOERROR) + return merge_err; + i = 0; + } + } + } + + /* It must be the first time to invoke acquire_state. */ + dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0); + /* We don't check ERR here, since the initial state must not be NULL. */ + if (BE (dfa->init_state == NULL, 0)) + return err; + if (dfa->init_state->has_constraint) + { + dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes, + CONTEXT_WORD); + dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes, + CONTEXT_NEWLINE); + dfa->init_state_begbuf = re_acquire_state_context (&err, dfa, + &init_nodes, + CONTEXT_NEWLINE + | CONTEXT_BEGBUF); + if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL + || dfa->init_state_begbuf == NULL, 0)) + return err; + } + else + dfa->init_state_word = dfa->init_state_nl + = dfa->init_state_begbuf = dfa->init_state; + + re_node_set_free (&init_nodes); + return REG_NOERROR; +} + +#ifdef RE_ENABLE_I18N +/* If it is possible to do searching in single byte encoding instead of UTF-8 + to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change + DFA nodes where needed. */ + +static void +optimize_utf8 (re_dfa_t *dfa) +{ + Idx node; + int i; + bool mb_chars = false; + bool has_period = false; + + for (node = 0; node < dfa->nodes_len; ++node) + switch (dfa->nodes[node].type) + { + case CHARACTER: + if (dfa->nodes[node].opr.c >= ASCII_CHARS) + mb_chars = true; + break; + case ANCHOR: + switch (dfa->nodes[node].opr.ctx_type) + { + case LINE_FIRST: + case LINE_LAST: + case BUF_FIRST: + case BUF_LAST: + break; + default: + /* Word anchors etc. cannot be handled. It's okay to test + opr.ctx_type since constraints (for all DFA nodes) are + created by ORing one or more opr.ctx_type values. */ + return; + } + break; + case OP_PERIOD: + has_period = true; + break; + case OP_BACK_REF: + case OP_ALT: + case END_OF_RE: + case OP_DUP_ASTERISK: + case OP_OPEN_SUBEXP: + case OP_CLOSE_SUBEXP: + break; + case COMPLEX_BRACKET: + return; + case SIMPLE_BRACKET: + /* Just double check. */ + { + int rshift = (ASCII_CHARS % BITSET_WORD_BITS == 0 + ? 0 + : BITSET_WORD_BITS - ASCII_CHARS % BITSET_WORD_BITS); + for (i = ASCII_CHARS / BITSET_WORD_BITS; i < BITSET_WORDS; ++i) + { + if (dfa->nodes[node].opr.sbcset[i] >> rshift != 0) + return; + rshift = 0; + } + } + break; + default: + abort (); + } + + if (mb_chars || has_period) + for (node = 0; node < dfa->nodes_len; ++node) + { + if (dfa->nodes[node].type == CHARACTER + && dfa->nodes[node].opr.c >= ASCII_CHARS) + dfa->nodes[node].mb_partial = 0; + else if (dfa->nodes[node].type == OP_PERIOD) + dfa->nodes[node].type = OP_UTF8_PERIOD; + } + + /* The search can be in single byte locale. */ + dfa->mb_cur_max = 1; + dfa->is_utf8 = 0; + dfa->has_mb_node = dfa->nbackref > 0 || has_period; +} +#endif + +/* Analyze the structure tree, and calculate "first", "next", "edest", + "eclosure", and "inveclosure". */ + +static reg_errcode_t +analyze (regex_t *preg) +{ + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; + reg_errcode_t ret; + + /* Allocate arrays. */ + dfa->nexts = re_malloc (Idx, dfa->nodes_alloc); + dfa->org_indices = re_malloc (Idx, dfa->nodes_alloc); + dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc); + dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc); + if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL + || dfa->eclosures == NULL, 0)) + return REG_ESPACE; + + dfa->subexp_map = re_malloc (Idx, preg->re_nsub); + if (dfa->subexp_map != NULL) + { + Idx i; + for (i = 0; i < preg->re_nsub; i++) + dfa->subexp_map[i] = i; + preorder (dfa->str_tree, optimize_subexps, dfa); + for (i = 0; i < preg->re_nsub; i++) + if (dfa->subexp_map[i] != i) + break; + if (i == preg->re_nsub) + { + free (dfa->subexp_map); + dfa->subexp_map = NULL; + } + } + + ret = postorder (dfa->str_tree, lower_subexps, preg); + if (BE (ret != REG_NOERROR, 0)) + return ret; + ret = postorder (dfa->str_tree, calc_first, dfa); + if (BE (ret != REG_NOERROR, 0)) + return ret; + preorder (dfa->str_tree, calc_next, dfa); + ret = preorder (dfa->str_tree, link_nfa_nodes, dfa); + if (BE (ret != REG_NOERROR, 0)) + return ret; + ret = calc_eclosure (dfa); + if (BE (ret != REG_NOERROR, 0)) + return ret; + + /* We only need this during the prune_impossible_nodes pass in regexec.c; + skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */ + if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match) + || dfa->nbackref) + { + dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len); + if (BE (dfa->inveclosures == NULL, 0)) + return REG_ESPACE; + ret = calc_inveclosure (dfa); + } + + return ret; +} + +/* Our parse trees are very unbalanced, so we cannot use a stack to + implement parse tree visits. Instead, we use parent pointers and + some hairy code in these two functions. */ +static reg_errcode_t +postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), + void *extra) +{ + bin_tree_t *node, *prev; + + for (node = root; ; ) + { + /* Descend down the tree, preferably to the left (or to the right + if that's the only child). */ + while (node->left || node->right) + if (node->left) + node = node->left; + else + node = node->right; + + do + { + reg_errcode_t err = fn (extra, node); + if (BE (err != REG_NOERROR, 0)) + return err; + if (node->parent == NULL) + return REG_NOERROR; + prev = node; + node = node->parent; + } + /* Go up while we have a node that is reached from the right. */ + while (node->right == prev || node->right == NULL); + node = node->right; + } +} + +static reg_errcode_t +preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), + void *extra) +{ + bin_tree_t *node; + + for (node = root; ; ) + { + reg_errcode_t err = fn (extra, node); + if (BE (err != REG_NOERROR, 0)) + return err; + + /* Go to the left node, or up and to the right. */ + if (node->left) + node = node->left; + else + { + bin_tree_t *prev = NULL; + while (node->right == prev || node->right == NULL) + { + prev = node; + node = node->parent; + if (!node) + return REG_NOERROR; + } + node = node->right; + } + } +} + +/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell + re_search_internal to map the inner one's opr.idx to this one's. Adjust + backreferences as well. Requires a preorder visit. */ +static reg_errcode_t +optimize_subexps (void *extra, bin_tree_t *node) +{ + re_dfa_t *dfa = (re_dfa_t *) extra; + + if (node->token.type == OP_BACK_REF && dfa->subexp_map) + { + int idx = node->token.opr.idx; + node->token.opr.idx = dfa->subexp_map[idx]; + dfa->used_bkref_map |= 1 << node->token.opr.idx; + } + + else if (node->token.type == SUBEXP + && node->left && node->left->token.type == SUBEXP) + { + Idx other_idx = node->left->token.opr.idx; + + node->left = node->left->left; + if (node->left) + node->left->parent = node; + + dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx]; + if (other_idx < BITSET_WORD_BITS) + dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx); + } + + return REG_NOERROR; +} + +/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation + of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */ +static reg_errcode_t +lower_subexps (void *extra, bin_tree_t *node) +{ + regex_t *preg = (regex_t *) extra; + reg_errcode_t err = REG_NOERROR; + + if (node->left && node->left->token.type == SUBEXP) + { + node->left = lower_subexp (&err, preg, node->left); + if (node->left) + node->left->parent = node; + } + if (node->right && node->right->token.type == SUBEXP) + { + node->right = lower_subexp (&err, preg, node->right); + if (node->right) + node->right->parent = node; + } + + return err; +} + +static bin_tree_t * +lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node) +{ + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; + bin_tree_t *body = node->left; + bin_tree_t *op, *cls, *tree1, *tree; + + if (preg->no_sub + /* We do not optimize empty subexpressions, because otherwise we may + have bad CONCAT nodes with NULL children. This is obviously not + very common, so we do not lose much. An example that triggers + this case is the sed "script" /\(\)/x. */ + && node->left != NULL + && (node->token.opr.idx >= BITSET_WORD_BITS + || !(dfa->used_bkref_map + & ((bitset_word_t) 1 << node->token.opr.idx)))) + return node->left; + + /* Convert the SUBEXP node to the concatenation of an + OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */ + op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP); + cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP); + tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls; + tree = create_tree (dfa, op, tree1, CONCAT); + if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } + + op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx; + op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp; + return tree; +} + +/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton + nodes. Requires a postorder visit. */ +static reg_errcode_t +calc_first (void *extra, bin_tree_t *node) +{ + re_dfa_t *dfa = (re_dfa_t *) extra; + if (node->token.type == CONCAT) + { + node->first = node->left->first; + node->node_idx = node->left->node_idx; + } + else + { + node->first = node; + node->node_idx = re_dfa_add_node (dfa, node->token); + if (BE (node->node_idx == REG_MISSING, 0)) + return REG_ESPACE; + if (node->token.type == ANCHOR) + dfa->nodes[node->node_idx].constraint = node->token.opr.ctx_type; + } + return REG_NOERROR; +} + +/* Pass 2: compute NEXT on the tree. Preorder visit. */ +static reg_errcode_t +calc_next (void *extra, bin_tree_t *node) +{ + switch (node->token.type) + { + case OP_DUP_ASTERISK: + node->left->next = node; + break; + case CONCAT: + node->left->next = node->right->first; + node->right->next = node->next; + break; + default: + if (node->left) + node->left->next = node->next; + if (node->right) + node->right->next = node->next; + break; + } + return REG_NOERROR; +} + +/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */ +static reg_errcode_t +link_nfa_nodes (void *extra, bin_tree_t *node) +{ + re_dfa_t *dfa = (re_dfa_t *) extra; + Idx idx = node->node_idx; + reg_errcode_t err = REG_NOERROR; + + switch (node->token.type) + { + case CONCAT: + break; + + case END_OF_RE: + assert (node->next == NULL); + break; + + case OP_DUP_ASTERISK: + case OP_ALT: + { + Idx left, right; + dfa->has_plural_match = 1; + if (node->left != NULL) + left = node->left->first->node_idx; + else + left = node->next->node_idx; + if (node->right != NULL) + right = node->right->first->node_idx; + else + right = node->next->node_idx; + assert (REG_VALID_INDEX (left)); + assert (REG_VALID_INDEX (right)); + err = re_node_set_init_2 (dfa->edests + idx, left, right); + } + break; + + case ANCHOR: + case OP_OPEN_SUBEXP: + case OP_CLOSE_SUBEXP: + err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx); + break; + + case OP_BACK_REF: + dfa->nexts[idx] = node->next->node_idx; + if (node->token.type == OP_BACK_REF) + err = re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]); + break; + + default: + assert (!IS_EPSILON_NODE (node->token.type)); + dfa->nexts[idx] = node->next->node_idx; + break; + } + + return err; +} + +/* Duplicate the epsilon closure of the node ROOT_NODE. + Note that duplicated nodes have constraint INIT_CONSTRAINT in addition + to their own constraint. */ + +static reg_errcode_t +internal_function +duplicate_node_closure (re_dfa_t *dfa, Idx top_org_node, Idx top_clone_node, + Idx root_node, unsigned int init_constraint) +{ + Idx org_node, clone_node; + bool ok; + unsigned int constraint = init_constraint; + for (org_node = top_org_node, clone_node = top_clone_node;;) + { + Idx org_dest, clone_dest; + if (dfa->nodes[org_node].type == OP_BACK_REF) + { + /* If the back reference epsilon-transit, its destination must + also have the constraint. Then duplicate the epsilon closure + of the destination of the back reference, and store it in + edests of the back reference. */ + org_dest = dfa->nexts[org_node]; + re_node_set_empty (dfa->edests + clone_node); + clone_dest = duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest == REG_MISSING, 0)) + return REG_ESPACE; + dfa->nexts[clone_node] = dfa->nexts[org_node]; + ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + } + else if (dfa->edests[org_node].nelem == 0) + { + /* In case of the node can't epsilon-transit, don't duplicate the + destination and store the original destination as the + destination of the node. */ + dfa->nexts[clone_node] = dfa->nexts[org_node]; + break; + } + else if (dfa->edests[org_node].nelem == 1) + { + /* In case of the node can epsilon-transit, and it has only one + destination. */ + org_dest = dfa->edests[org_node].elems[0]; + re_node_set_empty (dfa->edests + clone_node); + /* If the node is root_node itself, it means the epsilon closure + has a loop. Then tie it to the destination of the root_node. */ + if (org_node == root_node && clone_node != org_node) + { + ok = re_node_set_insert (dfa->edests + clone_node, org_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + break; + } + /* In case the node has another constraint, append it. */ + constraint |= dfa->nodes[org_node].constraint; + clone_dest = duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest == REG_MISSING, 0)) + return REG_ESPACE; + ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + } + else /* dfa->edests[org_node].nelem == 2 */ + { + /* In case of the node can epsilon-transit, and it has two + destinations. In the bin_tree_t and DFA, that's '|' and '*'. */ + org_dest = dfa->edests[org_node].elems[0]; + re_node_set_empty (dfa->edests + clone_node); + /* Search for a duplicated node which satisfies the constraint. */ + clone_dest = search_duplicated_node (dfa, org_dest, constraint); + if (clone_dest == REG_MISSING) + { + /* There is no such duplicated node, create a new one. */ + reg_errcode_t err; + clone_dest = duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest == REG_MISSING, 0)) + return REG_ESPACE; + ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + err = duplicate_node_closure (dfa, org_dest, clone_dest, + root_node, constraint); + if (BE (err != REG_NOERROR, 0)) + return err; + } + else + { + /* There is a duplicated node which satisfies the constraint, + use it to avoid infinite loop. */ + ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + } + + org_dest = dfa->edests[org_node].elems[1]; + clone_dest = duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest == REG_MISSING, 0)) + return REG_ESPACE; + ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + } + org_node = org_dest; + clone_node = clone_dest; + } + return REG_NOERROR; +} + +/* Search for a node which is duplicated from the node ORG_NODE, and + satisfies the constraint CONSTRAINT. */ + +static Idx +search_duplicated_node (const re_dfa_t *dfa, Idx org_node, + unsigned int constraint) +{ + Idx idx; + for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx) + { + if (org_node == dfa->org_indices[idx] + && constraint == dfa->nodes[idx].constraint) + return idx; /* Found. */ + } + return REG_MISSING; /* Not found. */ +} + +/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT. + Return the index of the new node, or REG_MISSING if insufficient storage is + available. */ + +static Idx +duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int constraint) +{ + Idx dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]); + if (BE (dup_idx != REG_MISSING, 1)) + { + dfa->nodes[dup_idx].constraint = constraint; + dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].constraint; + dfa->nodes[dup_idx].duplicated = 1; + + /* Store the index of the original node. */ + dfa->org_indices[dup_idx] = org_idx; + } + return dup_idx; +} + +static reg_errcode_t +calc_inveclosure (re_dfa_t *dfa) +{ + Idx src, idx; + bool ok; + for (idx = 0; idx < dfa->nodes_len; ++idx) + re_node_set_init_empty (dfa->inveclosures + idx); + + for (src = 0; src < dfa->nodes_len; ++src) + { + Idx *elems = dfa->eclosures[src].elems; + for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx) + { + ok = re_node_set_insert_last (dfa->inveclosures + elems[idx], src); + if (BE (! ok, 0)) + return REG_ESPACE; + } + } + + return REG_NOERROR; +} + +/* Calculate "eclosure" for all the node in DFA. */ + +static reg_errcode_t +calc_eclosure (re_dfa_t *dfa) +{ + Idx node_idx; + bool incomplete; +#ifdef DEBUG + assert (dfa->nodes_len > 0); +#endif + incomplete = false; + /* For each nodes, calculate epsilon closure. */ + for (node_idx = 0; ; ++node_idx) + { + reg_errcode_t err; + re_node_set eclosure_elem; + if (node_idx == dfa->nodes_len) + { + if (!incomplete) + break; + incomplete = false; + node_idx = 0; + } + +#ifdef DEBUG + assert (dfa->eclosures[node_idx].nelem != REG_MISSING); +#endif + + /* If we have already calculated, skip it. */ + if (dfa->eclosures[node_idx].nelem != 0) + continue; + /* Calculate epsilon closure of `node_idx'. */ + err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, true); + if (BE (err != REG_NOERROR, 0)) + return err; + + if (dfa->eclosures[node_idx].nelem == 0) + { + incomplete = true; + re_node_set_free (&eclosure_elem); + } + } + return REG_NOERROR; +} + +/* Calculate epsilon closure of NODE. */ + +static reg_errcode_t +calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root) +{ + reg_errcode_t err; + Idx i; + re_node_set eclosure; + bool ok; + bool incomplete = false; + err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1); + if (BE (err != REG_NOERROR, 0)) + return err; + + /* This indicates that we are calculating this node now. + We reference this value to avoid infinite loop. */ + dfa->eclosures[node].nelem = REG_MISSING; + + /* If the current node has constraints, duplicate all nodes + since they must inherit the constraints. */ + if (dfa->nodes[node].constraint + && dfa->edests[node].nelem + && !dfa->nodes[dfa->edests[node].elems[0]].duplicated) + { + err = duplicate_node_closure (dfa, node, node, node, + dfa->nodes[node].constraint); + if (BE (err != REG_NOERROR, 0)) + return err; + } + + /* Expand each epsilon destination nodes. */ + if (IS_EPSILON_NODE(dfa->nodes[node].type)) + for (i = 0; i < dfa->edests[node].nelem; ++i) + { + re_node_set eclosure_elem; + Idx edest = dfa->edests[node].elems[i]; + /* If calculating the epsilon closure of `edest' is in progress, + return intermediate result. */ + if (dfa->eclosures[edest].nelem == REG_MISSING) + { + incomplete = true; + continue; + } + /* If we haven't calculated the epsilon closure of `edest' yet, + calculate now. Otherwise use calculated epsilon closure. */ + if (dfa->eclosures[edest].nelem == 0) + { + err = calc_eclosure_iter (&eclosure_elem, dfa, edest, false); + if (BE (err != REG_NOERROR, 0)) + return err; + } + else + eclosure_elem = dfa->eclosures[edest]; + /* Merge the epsilon closure of `edest'. */ + err = re_node_set_merge (&eclosure, &eclosure_elem); + if (BE (err != REG_NOERROR, 0)) + return err; + /* If the epsilon closure of `edest' is incomplete, + the epsilon closure of this node is also incomplete. */ + if (dfa->eclosures[edest].nelem == 0) + { + incomplete = true; + re_node_set_free (&eclosure_elem); + } + } + + /* An epsilon closure includes itself. */ + ok = re_node_set_insert (&eclosure, node); + if (BE (! ok, 0)) + return REG_ESPACE; + if (incomplete && !root) + dfa->eclosures[node].nelem = 0; + else + dfa->eclosures[node] = eclosure; + *new_set = eclosure; + return REG_NOERROR; +} + +/* Functions for token which are used in the parser. */ + +/* Fetch a token from INPUT. + We must not use this function inside bracket expressions. */ + +static void +internal_function +fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax) +{ + re_string_skip_bytes (input, peek_token (result, input, syntax)); +} + +/* Peek a token from INPUT, and return the length of the token. + We must not use this function inside bracket expressions. */ + +static int +internal_function +peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax) +{ + unsigned char c; + + if (re_string_eoi (input)) + { + token->type = END_OF_RE; + return 0; + } + + c = re_string_peek_byte (input, 0); + token->opr.c = c; + + token->word_char = 0; +#ifdef RE_ENABLE_I18N + token->mb_partial = 0; + if (input->mb_cur_max > 1 && + !re_string_first_byte (input, re_string_cur_idx (input))) + { + token->type = CHARACTER; + token->mb_partial = 1; + return 1; + } +#endif + if (c == '\\') + { + unsigned char c2; + if (re_string_cur_idx (input) + 1 >= re_string_length (input)) + { + token->type = BACK_SLASH; + return 1; + } + + c2 = re_string_peek_byte_case (input, 1); + token->opr.c = c2; + token->type = CHARACTER; +#ifdef RE_ENABLE_I18N + if (input->mb_cur_max > 1) + { + wint_t wc = re_string_wchar_at (input, + re_string_cur_idx (input) + 1); + token->word_char = IS_WIDE_WORD_CHAR (wc) != 0; + } + else +#endif + token->word_char = IS_WORD_CHAR (c2) != 0; + + switch (c2) + { + case '|': + if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR)) + token->type = OP_ALT; + break; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (!(syntax & RE_NO_BK_REFS)) + { + token->type = OP_BACK_REF; + token->opr.idx = c2 - '1'; + } + break; + case '<': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type = ANCHOR; + token->opr.ctx_type = WORD_FIRST; + } + break; + case '>': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type = ANCHOR; + token->opr.ctx_type = WORD_LAST; + } + break; + case 'b': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type = ANCHOR; + token->opr.ctx_type = WORD_DELIM; + } + break; + case 'B': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type = ANCHOR; + token->opr.ctx_type = NOT_WORD_DELIM; + } + break; + case 'w': + if (!(syntax & RE_NO_GNU_OPS)) + token->type = OP_WORD; + break; + case 'W': + if (!(syntax & RE_NO_GNU_OPS)) + token->type = OP_NOTWORD; + break; + case 's': + if (!(syntax & RE_NO_GNU_OPS)) + token->type = OP_SPACE; + break; + case 'S': + if (!(syntax & RE_NO_GNU_OPS)) + token->type = OP_NOTSPACE; + break; + case '`': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type = ANCHOR; + token->opr.ctx_type = BUF_FIRST; + } + break; + case '\'': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type = ANCHOR; + token->opr.ctx_type = BUF_LAST; + } + break; + case '(': + if (!(syntax & RE_NO_BK_PARENS)) + token->type = OP_OPEN_SUBEXP; + break; + case ')': + if (!(syntax & RE_NO_BK_PARENS)) + token->type = OP_CLOSE_SUBEXP; + break; + case '+': + if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) + token->type = OP_DUP_PLUS; + break; + case '?': + if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) + token->type = OP_DUP_QUESTION; + break; + case '{': + if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) + token->type = OP_OPEN_DUP_NUM; + break; + case '}': + if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) + token->type = OP_CLOSE_DUP_NUM; + break; + default: + break; + } + return 2; + } + + token->type = CHARACTER; +#ifdef RE_ENABLE_I18N + if (input->mb_cur_max > 1) + { + wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input)); + token->word_char = IS_WIDE_WORD_CHAR (wc) != 0; + } + else +#endif + token->word_char = IS_WORD_CHAR (token->opr.c); + + switch (c) + { + case '\n': + if (syntax & RE_NEWLINE_ALT) + token->type = OP_ALT; + break; + case '|': + if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR)) + token->type = OP_ALT; + break; + case '*': + token->type = OP_DUP_ASTERISK; + break; + case '+': + if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) + token->type = OP_DUP_PLUS; + break; + case '?': + if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) + token->type = OP_DUP_QUESTION; + break; + case '{': + if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + token->type = OP_OPEN_DUP_NUM; + break; + case '}': + if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + token->type = OP_CLOSE_DUP_NUM; + break; + case '(': + if (syntax & RE_NO_BK_PARENS) + token->type = OP_OPEN_SUBEXP; + break; + case ')': + if (syntax & RE_NO_BK_PARENS) + token->type = OP_CLOSE_SUBEXP; + break; + case '[': + token->type = OP_OPEN_BRACKET; + break; + case '.': + token->type = OP_PERIOD; + break; + case '^': + if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) && + re_string_cur_idx (input) != 0) + { + char prev = re_string_peek_byte (input, -1); + if (!(syntax & RE_NEWLINE_ALT) || prev != '\n') + break; + } + token->type = ANCHOR; + token->opr.ctx_type = LINE_FIRST; + break; + case '$': + if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && + re_string_cur_idx (input) + 1 != re_string_length (input)) + { + re_token_t next; + re_string_skip_bytes (input, 1); + peek_token (&next, input, syntax); + re_string_skip_bytes (input, -1); + if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP) + break; + } + token->type = ANCHOR; + token->opr.ctx_type = LINE_LAST; + break; + default: + break; + } + return 1; +} + +/* Peek a token from INPUT, and return the length of the token. + We must not use this function out of bracket expressions. */ + +static int +internal_function +peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax) +{ + unsigned char c; + if (re_string_eoi (input)) + { + token->type = END_OF_RE; + return 0; + } + c = re_string_peek_byte (input, 0); + token->opr.c = c; + +#ifdef RE_ENABLE_I18N + if (input->mb_cur_max > 1 && + !re_string_first_byte (input, re_string_cur_idx (input))) + { + token->type = CHARACTER; + return 1; + } +#endif /* RE_ENABLE_I18N */ + + if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) + && re_string_cur_idx (input) + 1 < re_string_length (input)) + { + /* In this case, '\' escape a character. */ + unsigned char c2; + re_string_skip_bytes (input, 1); + c2 = re_string_peek_byte (input, 0); + token->opr.c = c2; + token->type = CHARACTER; + return 1; + } + if (c == '[') /* '[' is a special char in a bracket exps. */ + { + unsigned char c2; + int token_len; + if (re_string_cur_idx (input) + 1 < re_string_length (input)) + c2 = re_string_peek_byte (input, 1); + else + c2 = 0; + token->opr.c = c2; + token_len = 2; + switch (c2) + { + case '.': + token->type = OP_OPEN_COLL_ELEM; + break; + case '=': + token->type = OP_OPEN_EQUIV_CLASS; + break; + case ':': + if (syntax & RE_CHAR_CLASSES) + { + token->type = OP_OPEN_CHAR_CLASS; + break; + } + /* else fall through. */ + default: + token->type = CHARACTER; + token->opr.c = c; + token_len = 1; + break; + } + return token_len; + } + switch (c) + { + case '-': + token->type = OP_CHARSET_RANGE; + break; + case ']': + token->type = OP_CLOSE_BRACKET; + break; + case '^': + token->type = OP_NON_MATCH_LIST; + break; + default: + token->type = CHARACTER; + } + return 1; +} + +/* Functions for parser. */ + +/* Entry point of the parser. + Parse the regular expression REGEXP and return the structure tree. + If an error is occured, ERR is set by error code, and return NULL. + This function build the following tree, from regular expression : + CAT + / \ + / \ + EOR + + CAT means concatenation. + EOR means end of regular expression. */ + +static bin_tree_t * +parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, + reg_errcode_t *err) +{ + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; + bin_tree_t *tree, *eor, *root; + re_token_t current_token; + dfa->syntax = syntax; + fetch_token (¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE); + tree = parse_reg_exp (regexp, preg, ¤t_token, syntax, 0, err); + if (BE (*err != REG_NOERROR && tree == NULL, 0)) + return NULL; + eor = create_tree (dfa, NULL, NULL, END_OF_RE); + if (tree != NULL) + root = create_tree (dfa, tree, eor, CONCAT); + else + root = eor; + if (BE (eor == NULL || root == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } + return root; +} + +/* This function build the following tree, from regular expression + |: + ALT + / \ + / \ + + + ALT means alternative, which represents the operator `|'. */ + +static bin_tree_t * +parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) +{ + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; + bin_tree_t *tree, *branch = NULL; + tree = parse_branch (regexp, preg, token, syntax, nest, err); + if (BE (*err != REG_NOERROR && tree == NULL, 0)) + return NULL; + + while (token->type == OP_ALT) + { + fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); + if (token->type != OP_ALT && token->type != END_OF_RE + && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) + { + branch = parse_branch (regexp, preg, token, syntax, nest, err); + if (BE (*err != REG_NOERROR && branch == NULL, 0)) + return NULL; + } + else + branch = NULL; + tree = create_tree (dfa, tree, branch, OP_ALT); + if (BE (tree == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } + } + return tree; +} + +/* This function build the following tree, from regular expression + : + CAT + / \ + / \ + + + CAT means concatenation. */ + +static bin_tree_t * +parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) +{ + bin_tree_t *tree, *expr; + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; + tree = parse_expression (regexp, preg, token, syntax, nest, err); + if (BE (*err != REG_NOERROR && tree == NULL, 0)) + return NULL; + + while (token->type != OP_ALT && token->type != END_OF_RE + && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) + { + expr = parse_expression (regexp, preg, token, syntax, nest, err); + if (BE (*err != REG_NOERROR && expr == NULL, 0)) + { + return NULL; + } + if (tree != NULL && expr != NULL) + { + tree = create_tree (dfa, tree, expr, CONCAT); + if (tree == NULL) + { + *err = REG_ESPACE; + return NULL; + } + } + else if (tree == NULL) + tree = expr; + /* Otherwise expr == NULL, we don't need to create new tree. */ + } + return tree; +} + +/* This function build the following tree, from regular expression a*: + * + | + a +*/ + +static bin_tree_t * +parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) +{ + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; + bin_tree_t *tree; + switch (token->type) + { + case CHARACTER: + tree = create_token_tree (dfa, NULL, NULL, token); + if (BE (tree == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + { + while (!re_string_eoi (regexp) + && !re_string_first_byte (regexp, re_string_cur_idx (regexp))) + { + bin_tree_t *mbc_remain; + fetch_token (token, regexp, syntax); + mbc_remain = create_token_tree (dfa, NULL, NULL, token); + tree = create_tree (dfa, tree, mbc_remain, CONCAT); + if (BE (mbc_remain == NULL || tree == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } + } + } +#endif + break; + case OP_OPEN_SUBEXP: + tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err); + if (BE (*err != REG_NOERROR && tree == NULL, 0)) + return NULL; + break; + case OP_OPEN_BRACKET: + tree = parse_bracket_exp (regexp, dfa, token, syntax, err); + if (BE (*err != REG_NOERROR && tree == NULL, 0)) + return NULL; + break; + case OP_BACK_REF: + if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1)) + { + *err = REG_ESUBREG; + return NULL; + } + dfa->used_bkref_map |= 1 << token->opr.idx; + tree = create_token_tree (dfa, NULL, NULL, token); + if (BE (tree == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } + ++dfa->nbackref; + dfa->has_mb_node = 1; + break; + case OP_OPEN_DUP_NUM: + if (syntax & RE_CONTEXT_INVALID_DUP) + { + *err = REG_BADRPT; + return NULL; + } + /* FALLTHROUGH */ + case OP_DUP_ASTERISK: + case OP_DUP_PLUS: + case OP_DUP_QUESTION: + if (syntax & RE_CONTEXT_INVALID_OPS) + { + *err = REG_BADRPT; + return NULL; + } + else if (syntax & RE_CONTEXT_INDEP_OPS) + { + fetch_token (token, regexp, syntax); + return parse_expression (regexp, preg, token, syntax, nest, err); + } + /* else fall through */ + case OP_CLOSE_SUBEXP: + if ((token->type == OP_CLOSE_SUBEXP) && + !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)) + { + *err = REG_ERPAREN; + return NULL; + } + /* else fall through */ + case OP_CLOSE_DUP_NUM: + /* We treat it as a normal character. */ + + /* Then we can these characters as normal characters. */ + token->type = CHARACTER; + /* mb_partial and word_char bits should be initialized already + by peek_token. */ + tree = create_token_tree (dfa, NULL, NULL, token); + if (BE (tree == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } + break; + case ANCHOR: + if ((token->opr.ctx_type + & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST)) + && dfa->word_ops_used == 0) + init_word_char (dfa); + if (token->opr.ctx_type == WORD_DELIM + || token->opr.ctx_type == NOT_WORD_DELIM) + { + bin_tree_t *tree_first, *tree_last; + if (token->opr.ctx_type == WORD_DELIM) + { + token->opr.ctx_type = WORD_FIRST; + tree_first = create_token_tree (dfa, NULL, NULL, token); + token->opr.ctx_type = WORD_LAST; + } + else + { + token->opr.ctx_type = INSIDE_WORD; + tree_first = create_token_tree (dfa, NULL, NULL, token); + token->opr.ctx_type = INSIDE_NOTWORD; + } + tree_last = create_token_tree (dfa, NULL, NULL, token); + tree = create_tree (dfa, tree_first, tree_last, OP_ALT); + if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } + } + else + { + tree = create_token_tree (dfa, NULL, NULL, token); + if (BE (tree == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } + } + /* We must return here, since ANCHORs can't be followed + by repetition operators. + eg. RE"^*" is invalid or "", + it must not be "". */ + fetch_token (token, regexp, syntax); + return tree; + case OP_PERIOD: + tree = create_token_tree (dfa, NULL, NULL, token); + if (BE (tree == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } + if (dfa->mb_cur_max > 1) + dfa->has_mb_node = 1; + break; + case OP_WORD: + case OP_NOTWORD: + tree = build_charclass_op (dfa, regexp->trans, + (const unsigned char *) "alnum", + (const unsigned char *) "_", + token->type == OP_NOTWORD, err); + if (BE (*err != REG_NOERROR && tree == NULL, 0)) + return NULL; + break; + case OP_SPACE: + case OP_NOTSPACE: + tree = build_charclass_op (dfa, regexp->trans, + (const unsigned char *) "space", + (const unsigned char *) "", + token->type == OP_NOTSPACE, err); + if (BE (*err != REG_NOERROR && tree == NULL, 0)) + return NULL; + break; + case OP_ALT: + case END_OF_RE: + return NULL; + case BACK_SLASH: + *err = REG_EESCAPE; + return NULL; + default: + /* Must not happen? */ +#ifdef DEBUG + assert (0); +#endif + return NULL; + } + fetch_token (token, regexp, syntax); + + while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS + || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM) + { + tree = parse_dup_op (tree, regexp, dfa, token, syntax, err); + if (BE (*err != REG_NOERROR && tree == NULL, 0)) + return NULL; + /* In BRE consecutive duplications are not allowed. */ + if ((syntax & RE_CONTEXT_INVALID_DUP) + && (token->type == OP_DUP_ASTERISK + || token->type == OP_OPEN_DUP_NUM)) + { + *err = REG_BADRPT; + return NULL; + } + } + + return tree; +} + +/* This function build the following tree, from regular expression + (): + SUBEXP + | + +*/ + +static bin_tree_t * +parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) +{ + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; + bin_tree_t *tree; + size_t cur_nsub; + cur_nsub = preg->re_nsub++; + + fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); + + /* The subexpression may be a null string. */ + if (token->type == OP_CLOSE_SUBEXP) + tree = NULL; + else + { + tree = parse_reg_exp (regexp, preg, token, syntax, nest, err); + if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0)) + *err = REG_EPAREN; + if (BE (*err != REG_NOERROR, 0)) + return NULL; + } + + if (cur_nsub <= '9' - '1') + dfa->completed_bkref_map |= 1 << cur_nsub; + + tree = create_tree (dfa, tree, NULL, SUBEXP); + if (BE (tree == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } + tree->token.opr.idx = cur_nsub; + return tree; +} + +/* This function parse repetition operators like "*", "+", "{1,3}" etc. */ + +static bin_tree_t * +parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa, + re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err) +{ + bin_tree_t *tree = NULL, *old_tree = NULL; + Idx i, start, end, start_idx = re_string_cur_idx (regexp); + re_token_t start_token = *token; + + if (token->type == OP_OPEN_DUP_NUM) + { + end = 0; + start = fetch_number (regexp, token, syntax); + if (start == REG_MISSING) + { + if (token->type == CHARACTER && token->opr.c == ',') + start = 0; /* We treat "{,m}" as "{0,m}". */ + else + { + *err = REG_BADBR; /* {} is invalid. */ + return NULL; + } + } + if (BE (start != REG_ERROR, 1)) + { + /* We treat "{n}" as "{n,n}". */ + end = ((token->type == OP_CLOSE_DUP_NUM) ? start + : ((token->type == CHARACTER && token->opr.c == ',') + ? fetch_number (regexp, token, syntax) : REG_ERROR)); + } + if (BE (start == REG_ERROR || end == REG_ERROR, 0)) + { + /* Invalid sequence. */ + if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) + { + if (token->type == END_OF_RE) + *err = REG_EBRACE; + else + *err = REG_BADBR; + + return NULL; + } + + /* If the syntax bit is set, rollback. */ + re_string_set_index (regexp, start_idx); + *token = start_token; + token->type = CHARACTER; + /* mb_partial and word_char bits should be already initialized by + peek_token. */ + return elem; + } + + if (BE ((end != REG_MISSING && start > end) + || token->type != OP_CLOSE_DUP_NUM, 0)) + { + /* First number greater than second. */ + *err = REG_BADBR; + return NULL; + } + } + else + { + start = (token->type == OP_DUP_PLUS) ? 1 : 0; + end = (token->type == OP_DUP_QUESTION) ? 1 : REG_MISSING; + } + + fetch_token (token, regexp, syntax); + + if (BE (elem == NULL, 0)) + return NULL; + if (BE (start == 0 && end == 0, 0)) + { + postorder (elem, free_tree, NULL); + return NULL; + } + + /* Extract "{n,m}" to "...{0,}". */ + if (BE (start > 0, 0)) + { + tree = elem; + for (i = 2; i <= start; ++i) + { + elem = duplicate_tree (elem, dfa); + tree = create_tree (dfa, tree, elem, CONCAT); + if (BE (elem == NULL || tree == NULL, 0)) + goto parse_dup_op_espace; + } + + if (start == end) + return tree; + + /* Duplicate ELEM before it is marked optional. */ + elem = duplicate_tree (elem, dfa); + old_tree = tree; + } + else + old_tree = NULL; + + if (elem->token.type == SUBEXP) + postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx); + + tree = create_tree (dfa, elem, NULL, + (end == REG_MISSING ? OP_DUP_ASTERISK : OP_ALT)); + if (BE (tree == NULL, 0)) + goto parse_dup_op_espace; + +/* From gnulib's "intprops.h": + True if the arithmetic type T is signed. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + + /* This loop is actually executed only when end != REG_MISSING, + to rewrite {0,n} as ((...?)?)?... We have + already created the start+1-th copy. */ + if (TYPE_SIGNED (Idx) || end != REG_MISSING) + for (i = start + 2; i <= end; ++i) + { + elem = duplicate_tree (elem, dfa); + tree = create_tree (dfa, tree, elem, CONCAT); + if (BE (elem == NULL || tree == NULL, 0)) + goto parse_dup_op_espace; + + tree = create_tree (dfa, tree, NULL, OP_ALT); + if (BE (tree == NULL, 0)) + goto parse_dup_op_espace; + } + + if (old_tree) + tree = create_tree (dfa, old_tree, tree, CONCAT); + + return tree; + + parse_dup_op_espace: + *err = REG_ESPACE; + return NULL; +} + +/* Size of the names for collating symbol/equivalence_class/character_class. + I'm not sure, but maybe enough. */ +#define BRACKET_NAME_BUF_SIZE 32 + +#ifndef _LIBC + /* Local function for parse_bracket_exp only used in case of NOT _LIBC. + Build the range expression which starts from START_ELEM, and ends + at END_ELEM. The result are written to MBCSET and SBCSET. + RANGE_ALLOC is the allocated size of mbcset->range_starts, and + mbcset->range_ends, is a pointer argument sinse we may + update it. */ + +static reg_errcode_t +internal_function +# ifdef RE_ENABLE_I18N +build_range_exp (const reg_syntax_t syntax, + bitset_t sbcset, + re_charset_t *mbcset, + Idx *range_alloc, + const bracket_elem_t *start_elem, + const bracket_elem_t *end_elem) +# else /* not RE_ENABLE_I18N */ +build_range_exp (const reg_syntax_t syntax, + bitset_t sbcset, + const bracket_elem_t *start_elem, + const bracket_elem_t *end_elem) +# endif /* not RE_ENABLE_I18N */ +{ + unsigned int start_ch, end_ch; + /* Equivalence Classes and Character Classes can't be a range start/end. */ + if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS + || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, + 0)) + return REG_ERANGE; + + /* We can handle no multi character collating elements without libc + support. */ + if (BE ((start_elem->type == COLL_SYM + && strlen ((char *) start_elem->opr.name) > 1) + || (end_elem->type == COLL_SYM + && strlen ((char *) end_elem->opr.name) > 1), 0)) + return REG_ECOLLATE; + +# ifdef RE_ENABLE_I18N + { + wchar_t wc; + wint_t start_wc; + wint_t end_wc; + wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; + + start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch + : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] + : 0)); + end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch + : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] + : 0)); + start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM) + ? __btowc (start_ch) : start_elem->opr.wch); + end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM) + ? __btowc (end_ch) : end_elem->opr.wch); + if (start_wc == WEOF || end_wc == WEOF) + return REG_ECOLLATE; + cmp_buf[0] = start_wc; + cmp_buf[4] = end_wc; + + if (BE ((syntax & RE_NO_EMPTY_RANGES) + && wcscoll (cmp_buf, cmp_buf + 4) > 0, 0)) + return REG_ERANGE; + + /* Got valid collation sequence values, add them as a new entry. + However, for !_LIBC we have no collation elements: if the + character set is single byte, the single byte character set + that we build below suffices. parse_bracket_exp passes + no MBCSET if dfa->mb_cur_max == 1. */ + if (mbcset) + { + /* Check the space of the arrays. */ + if (BE (*range_alloc == mbcset->nranges, 0)) + { + /* There is not enough space, need realloc. */ + wchar_t *new_array_start, *new_array_end; + Idx new_nranges; + + /* +1 in case of mbcset->nranges is 0. */ + new_nranges = 2 * mbcset->nranges + 1; + /* Use realloc since mbcset->range_starts and mbcset->range_ends + are NULL if *range_alloc == 0. */ + new_array_start = re_realloc (mbcset->range_starts, wchar_t, + new_nranges); + new_array_end = re_realloc (mbcset->range_ends, wchar_t, + new_nranges); + + if (BE (new_array_start == NULL || new_array_end == NULL, 0)) + return REG_ESPACE; + + mbcset->range_starts = new_array_start; + mbcset->range_ends = new_array_end; + *range_alloc = new_nranges; + } + + mbcset->range_starts[mbcset->nranges] = start_wc; + mbcset->range_ends[mbcset->nranges++] = end_wc; + } + + /* Build the table for single byte characters. */ + for (wc = 0; wc < SBC_MAX; ++wc) + { + cmp_buf[2] = wc; + if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 + && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) + bitset_set (sbcset, wc); + } + } +# else /* not RE_ENABLE_I18N */ + { + unsigned int ch; + start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch + : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] + : 0)); + end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch + : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] + : 0)); + if (start_ch > end_ch) + return REG_ERANGE; + /* Build the table for single byte characters. */ + for (ch = 0; ch < SBC_MAX; ++ch) + if (start_ch <= ch && ch <= end_ch) + bitset_set (sbcset, ch); + } +# endif /* not RE_ENABLE_I18N */ + return REG_NOERROR; +} +#endif /* not _LIBC */ + +#ifndef _LIBC +/* Helper function for parse_bracket_exp only used in case of NOT _LIBC.. + Build the collating element which is represented by NAME. + The result are written to MBCSET and SBCSET. + COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a + pointer argument since we may update it. */ + +static reg_errcode_t +internal_function +build_collating_symbol (bitset_t sbcset, +# ifdef RE_ENABLE_I18N + re_charset_t *mbcset, Idx *coll_sym_alloc, +# endif + const unsigned char *name) +{ + size_t name_len = strlen ((const char *) name); + if (BE (name_len != 1, 0)) + return REG_ECOLLATE; + else + { + bitset_set (sbcset, name[0]); + return REG_NOERROR; + } +} +#endif /* not _LIBC */ + +/* This function parse bracket expression like "[abc]", "[a-c]", + "[[.a-a.]]" etc. */ + +static bin_tree_t * +parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, + reg_syntax_t syntax, reg_errcode_t *err) +{ +#ifdef _LIBC + const unsigned char *collseqmb; + const char *collseqwc; + uint32_t nrules; + int32_t table_size; + const int32_t *symb_table; + const unsigned char *extra; + + /* Local function for parse_bracket_exp used in _LIBC environement. + Seek the collating symbol entry correspondings to NAME. + Return the index of the symbol in the SYMB_TABLE. */ + + auto inline int32_t + __attribute ((always_inline)) + seek_collating_symbol_entry (name, name_len) + const unsigned char *name; + size_t name_len; + { + int32_t hash = elem_hash ((const char *) name, name_len); + int32_t elem = hash % table_size; + if (symb_table[2 * elem] != 0) + { + int32_t second = hash % (table_size - 2) + 1; + + do + { + /* First compare the hashing value. */ + if (symb_table[2 * elem] == hash + /* Compare the length of the name. */ + && name_len == extra[symb_table[2 * elem + 1]] + /* Compare the name. */ + && memcmp (name, &extra[symb_table[2 * elem + 1] + 1], + name_len) == 0) + { + /* Yep, this is the entry. */ + break; + } + + /* Next entry. */ + elem += second; + } + while (symb_table[2 * elem] != 0); + } + return elem; + } + + /* Local function for parse_bracket_exp used in _LIBC environment. + Look up the collation sequence value of BR_ELEM. + Return the value if succeeded, UINT_MAX otherwise. */ + + auto inline unsigned int + __attribute ((always_inline)) + lookup_collation_sequence_value (br_elem) + bracket_elem_t *br_elem; + { + if (br_elem->type == SB_CHAR) + { + /* + if (MB_CUR_MAX == 1) + */ + if (nrules == 0) + return collseqmb[br_elem->opr.ch]; + else + { + wint_t wc = __btowc (br_elem->opr.ch); + return __collseq_table_lookup (collseqwc, wc); + } + } + else if (br_elem->type == MB_CHAR) + { + if (nrules != 0) + return __collseq_table_lookup (collseqwc, br_elem->opr.wch); + } + else if (br_elem->type == COLL_SYM) + { + size_t sym_name_len = strlen ((char *) br_elem->opr.name); + if (nrules != 0) + { + int32_t elem, idx; + elem = seek_collating_symbol_entry (br_elem->opr.name, + sym_name_len); + if (symb_table[2 * elem] != 0) + { + /* We found the entry. */ + idx = symb_table[2 * elem + 1]; + /* Skip the name of collating element name. */ + idx += 1 + extra[idx]; + /* Skip the byte sequence of the collating element. */ + idx += 1 + extra[idx]; + /* Adjust for the alignment. */ + idx = (idx + 3) & ~3; + /* Skip the multibyte collation sequence value. */ + idx += sizeof (unsigned int); + /* Skip the wide char sequence of the collating element. */ + idx += sizeof (unsigned int) * + (1 + *(unsigned int *) (extra + idx)); + /* Return the collation sequence value. */ + return *(unsigned int *) (extra + idx); + } + else if (symb_table[2 * elem] == 0 && sym_name_len == 1) + { + /* No valid character. Match it as a single byte + character. */ + return collseqmb[br_elem->opr.name[0]]; + } + } + else if (sym_name_len == 1) + return collseqmb[br_elem->opr.name[0]]; + } + return UINT_MAX; + } + + /* Local function for parse_bracket_exp used in _LIBC environement. + Build the range expression which starts from START_ELEM, and ends + at END_ELEM. The result are written to MBCSET and SBCSET. + RANGE_ALLOC is the allocated size of mbcset->range_starts, and + mbcset->range_ends, is a pointer argument sinse we may + update it. */ + + auto inline reg_errcode_t + __attribute ((always_inline)) + build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) + re_charset_t *mbcset; + Idx *range_alloc; + bitset_t sbcset; + bracket_elem_t *start_elem, *end_elem; + { + unsigned int ch; + uint32_t start_collseq; + uint32_t end_collseq; + + /* Equivalence Classes and Character Classes can't be a range + start/end. */ + if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS + || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, + 0)) + return REG_ERANGE; + + start_collseq = lookup_collation_sequence_value (start_elem); + end_collseq = lookup_collation_sequence_value (end_elem); + /* Check start/end collation sequence values. */ + if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0)) + return REG_ECOLLATE; + if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0)) + return REG_ERANGE; + + /* Got valid collation sequence values, add them as a new entry. + However, if we have no collation elements, and the character set + is single byte, the single byte character set that we + build below suffices. */ + if (nrules > 0 || dfa->mb_cur_max > 1) + { + /* Check the space of the arrays. */ + if (BE (*range_alloc == mbcset->nranges, 0)) + { + /* There is not enough space, need realloc. */ + uint32_t *new_array_start; + uint32_t *new_array_end; + Idx new_nranges; + + /* +1 in case of mbcset->nranges is 0. */ + new_nranges = 2 * mbcset->nranges + 1; + new_array_start = re_realloc (mbcset->range_starts, uint32_t, + new_nranges); + new_array_end = re_realloc (mbcset->range_ends, uint32_t, + new_nranges); + + if (BE (new_array_start == NULL || new_array_end == NULL, 0)) + return REG_ESPACE; + + mbcset->range_starts = new_array_start; + mbcset->range_ends = new_array_end; + *range_alloc = new_nranges; + } + + mbcset->range_starts[mbcset->nranges] = start_collseq; + mbcset->range_ends[mbcset->nranges++] = end_collseq; + } + + /* Build the table for single byte characters. */ + for (ch = 0; ch < SBC_MAX; ch++) + { + uint32_t ch_collseq; + /* + if (MB_CUR_MAX == 1) + */ + if (nrules == 0) + ch_collseq = collseqmb[ch]; + else + ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch)); + if (start_collseq <= ch_collseq && ch_collseq <= end_collseq) + bitset_set (sbcset, ch); + } + return REG_NOERROR; + } + + /* Local function for parse_bracket_exp used in _LIBC environement. + Build the collating element which is represented by NAME. + The result are written to MBCSET and SBCSET. + COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a + pointer argument sinse we may update it. */ + + auto inline reg_errcode_t + __attribute ((always_inline)) + build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name) + re_charset_t *mbcset; + Idx *coll_sym_alloc; + bitset_t sbcset; + const unsigned char *name; + { + int32_t elem, idx; + size_t name_len = strlen ((const char *) name); + if (nrules != 0) + { + elem = seek_collating_symbol_entry (name, name_len); + if (symb_table[2 * elem] != 0) + { + /* We found the entry. */ + idx = symb_table[2 * elem + 1]; + /* Skip the name of collating element name. */ + idx += 1 + extra[idx]; + } + else if (symb_table[2 * elem] == 0 && name_len == 1) + { + /* No valid character, treat it as a normal + character. */ + bitset_set (sbcset, name[0]); + return REG_NOERROR; + } + else + return REG_ECOLLATE; + + /* Got valid collation sequence, add it as a new entry. */ + /* Check the space of the arrays. */ + if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0)) + { + /* Not enough, realloc it. */ + /* +1 in case of mbcset->ncoll_syms is 0. */ + Idx new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1; + /* Use realloc since mbcset->coll_syms is NULL + if *alloc == 0. */ + int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t, + new_coll_sym_alloc); + if (BE (new_coll_syms == NULL, 0)) + return REG_ESPACE; + mbcset->coll_syms = new_coll_syms; + *coll_sym_alloc = new_coll_sym_alloc; + } + mbcset->coll_syms[mbcset->ncoll_syms++] = idx; + return REG_NOERROR; + } + else + { + if (BE (name_len != 1, 0)) + return REG_ECOLLATE; + else + { + bitset_set (sbcset, name[0]); + return REG_NOERROR; + } + } + } +#endif + + re_token_t br_token; + re_bitset_ptr_t sbcset; +#ifdef RE_ENABLE_I18N + re_charset_t *mbcset; + Idx coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0; + Idx equiv_class_alloc = 0, char_class_alloc = 0; +#endif /* not RE_ENABLE_I18N */ + bool non_match = false; + bin_tree_t *work_tree; + int token_len; + bool first_round = true; +#ifdef _LIBC + collseqmb = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); + nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + if (nrules) + { + /* + if (MB_CUR_MAX > 1) + */ + collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); + table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB); + symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_TABLEMB); + extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_EXTRAMB); + } +#endif + sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); +#ifdef RE_ENABLE_I18N + mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); +#endif /* RE_ENABLE_I18N */ +#ifdef RE_ENABLE_I18N + if (BE (sbcset == NULL || mbcset == NULL, 0)) +#else + if (BE (sbcset == NULL, 0)) +#endif /* RE_ENABLE_I18N */ + { + *err = REG_ESPACE; + return NULL; + } + + token_len = peek_token_bracket (token, regexp, syntax); + if (BE (token->type == END_OF_RE, 0)) + { + *err = REG_BADPAT; + goto parse_bracket_exp_free_return; + } + if (token->type == OP_NON_MATCH_LIST) + { +#ifdef RE_ENABLE_I18N + mbcset->non_match = 1; +#endif /* not RE_ENABLE_I18N */ + non_match = true; + if (syntax & RE_HAT_LISTS_NOT_NEWLINE) + bitset_set (sbcset, '\n'); + re_string_skip_bytes (regexp, token_len); /* Skip a token. */ + token_len = peek_token_bracket (token, regexp, syntax); + if (BE (token->type == END_OF_RE, 0)) + { + *err = REG_BADPAT; + goto parse_bracket_exp_free_return; + } + } + + /* We treat the first ']' as a normal character. */ + if (token->type == OP_CLOSE_BRACKET) + token->type = CHARACTER; + + while (1) + { + bracket_elem_t start_elem, end_elem; + unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE]; + unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE]; + reg_errcode_t ret; + int token_len2 = 0; + bool is_range_exp = false; + re_token_t token2; + + start_elem.opr.name = start_name_buf; + ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa, + syntax, first_round); + if (BE (ret != REG_NOERROR, 0)) + { + *err = ret; + goto parse_bracket_exp_free_return; + } + first_round = false; + + /* Get information about the next token. We need it in any case. */ + token_len = peek_token_bracket (token, regexp, syntax); + + /* Do not check for ranges if we know they are not allowed. */ + if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS) + { + if (BE (token->type == END_OF_RE, 0)) + { + *err = REG_EBRACK; + goto parse_bracket_exp_free_return; + } + if (token->type == OP_CHARSET_RANGE) + { + re_string_skip_bytes (regexp, token_len); /* Skip '-'. */ + token_len2 = peek_token_bracket (&token2, regexp, syntax); + if (BE (token2.type == END_OF_RE, 0)) + { + *err = REG_EBRACK; + goto parse_bracket_exp_free_return; + } + if (token2.type == OP_CLOSE_BRACKET) + { + /* We treat the last '-' as a normal character. */ + re_string_skip_bytes (regexp, -token_len); + token->type = CHARACTER; + } + else + is_range_exp = true; + } + } + + if (is_range_exp == true) + { + end_elem.opr.name = end_name_buf; + ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2, + dfa, syntax, true); + if (BE (ret != REG_NOERROR, 0)) + { + *err = ret; + goto parse_bracket_exp_free_return; + } + + token_len = peek_token_bracket (token, regexp, syntax); + +#ifdef _LIBC + *err = build_range_exp (sbcset, mbcset, &range_alloc, + &start_elem, &end_elem); +#else +# ifdef RE_ENABLE_I18N + *err = build_range_exp (syntax, sbcset, + dfa->mb_cur_max > 1 ? mbcset : NULL, + &range_alloc, &start_elem, &end_elem); +# else + *err = build_range_exp (syntax, sbcset, &start_elem, &end_elem); +# endif +#endif /* RE_ENABLE_I18N */ + if (BE (*err != REG_NOERROR, 0)) + goto parse_bracket_exp_free_return; + } + else + { + switch (start_elem.type) + { + case SB_CHAR: + bitset_set (sbcset, start_elem.opr.ch); + break; +#ifdef RE_ENABLE_I18N + case MB_CHAR: + /* Check whether the array has enough space. */ + if (BE (mbchar_alloc == mbcset->nmbchars, 0)) + { + wchar_t *new_mbchars; + /* Not enough, realloc it. */ + /* +1 in case of mbcset->nmbchars is 0. */ + mbchar_alloc = 2 * mbcset->nmbchars + 1; + /* Use realloc since array is NULL if *alloc == 0. */ + new_mbchars = re_realloc (mbcset->mbchars, wchar_t, + mbchar_alloc); + if (BE (new_mbchars == NULL, 0)) + goto parse_bracket_exp_espace; + mbcset->mbchars = new_mbchars; + } + mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch; + break; +#endif /* RE_ENABLE_I18N */ + case EQUIV_CLASS: + *err = build_equiv_class (sbcset, +#ifdef RE_ENABLE_I18N + mbcset, &equiv_class_alloc, +#endif /* RE_ENABLE_I18N */ + start_elem.opr.name); + if (BE (*err != REG_NOERROR, 0)) + goto parse_bracket_exp_free_return; + break; + case COLL_SYM: + *err = build_collating_symbol (sbcset, +#ifdef RE_ENABLE_I18N + mbcset, &coll_sym_alloc, +#endif /* RE_ENABLE_I18N */ + start_elem.opr.name); + if (BE (*err != REG_NOERROR, 0)) + goto parse_bracket_exp_free_return; + break; + case CHAR_CLASS: + *err = build_charclass (regexp->trans, sbcset, +#ifdef RE_ENABLE_I18N + mbcset, &char_class_alloc, +#endif /* RE_ENABLE_I18N */ + start_elem.opr.name, syntax); + if (BE (*err != REG_NOERROR, 0)) + goto parse_bracket_exp_free_return; + break; + default: + assert (0); + break; + } + } + if (BE (token->type == END_OF_RE, 0)) + { + *err = REG_EBRACK; + goto parse_bracket_exp_free_return; + } + if (token->type == OP_CLOSE_BRACKET) + break; + } + + re_string_skip_bytes (regexp, token_len); /* Skip a token. */ + + /* If it is non-matching list. */ + if (non_match) + bitset_not (sbcset); + +#ifdef RE_ENABLE_I18N + /* Ensure only single byte characters are set. */ + if (dfa->mb_cur_max > 1) + bitset_mask (sbcset, dfa->sb_char); + + if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes + || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes + || mbcset->non_match))) + { + bin_tree_t *mbc_tree; + int sbc_idx; + /* Build a tree for complex bracket. */ + dfa->has_mb_node = 1; + br_token.type = COMPLEX_BRACKET; + br_token.opr.mbcset = mbcset; + mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (mbc_tree == NULL, 0)) + goto parse_bracket_exp_espace; + for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx) + if (sbcset[sbc_idx]) + break; + /* If there are no bits set in sbcset, there is no point + of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */ + if (sbc_idx < BITSET_WORDS) + { + /* Build a tree for simple bracket. */ + br_token.type = SIMPLE_BRACKET; + br_token.opr.sbcset = sbcset; + work_tree = create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (work_tree == NULL, 0)) + goto parse_bracket_exp_espace; + + /* Then join them by ALT node. */ + work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT); + if (BE (work_tree == NULL, 0)) + goto parse_bracket_exp_espace; + } + else + { + re_free (sbcset); + work_tree = mbc_tree; + } + } + else +#endif /* not RE_ENABLE_I18N */ + { +#ifdef RE_ENABLE_I18N + free_charset (mbcset); +#endif + /* Build a tree for simple bracket. */ + br_token.type = SIMPLE_BRACKET; + br_token.opr.sbcset = sbcset; + work_tree = create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (work_tree == NULL, 0)) + goto parse_bracket_exp_espace; + } + return work_tree; + + parse_bracket_exp_espace: + *err = REG_ESPACE; + parse_bracket_exp_free_return: + re_free (sbcset); +#ifdef RE_ENABLE_I18N + free_charset (mbcset); +#endif /* RE_ENABLE_I18N */ + return NULL; +} + +/* Parse an element in the bracket expression. */ + +static reg_errcode_t +parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp, + re_token_t *token, int token_len, re_dfa_t *dfa, + reg_syntax_t syntax, bool accept_hyphen) +{ +#ifdef RE_ENABLE_I18N + int cur_char_size; + cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp)); + if (cur_char_size > 1) + { + elem->type = MB_CHAR; + elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp)); + re_string_skip_bytes (regexp, cur_char_size); + return REG_NOERROR; + } +#endif /* RE_ENABLE_I18N */ + re_string_skip_bytes (regexp, token_len); /* Skip a token. */ + if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS + || token->type == OP_OPEN_EQUIV_CLASS) + return parse_bracket_symbol (elem, regexp, token); + if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen) + { + /* A '-' must only appear as anything but a range indicator before + the closing bracket. Everything else is an error. */ + re_token_t token2; + (void) peek_token_bracket (&token2, regexp, syntax); + if (token2.type != OP_CLOSE_BRACKET) + /* The actual error value is not standardized since this whole + case is undefined. But ERANGE makes good sense. */ + return REG_ERANGE; + } + elem->type = SB_CHAR; + elem->opr.ch = token->opr.c; + return REG_NOERROR; +} + +/* Parse a bracket symbol in the bracket expression. Bracket symbols are + such as [::], [..], and + [==]. */ + +static reg_errcode_t +parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp, + re_token_t *token) +{ + unsigned char ch, delim = token->opr.c; + int i = 0; + if (re_string_eoi(regexp)) + return REG_EBRACK; + for (;; ++i) + { + if (i >= BRACKET_NAME_BUF_SIZE) + return REG_EBRACK; + if (token->type == OP_OPEN_CHAR_CLASS) + ch = re_string_fetch_byte_case (regexp); + else + ch = re_string_fetch_byte (regexp); + if (re_string_eoi(regexp)) + return REG_EBRACK; + if (ch == delim && re_string_peek_byte (regexp, 0) == ']') + break; + elem->opr.name[i] = ch; + } + re_string_skip_bytes (regexp, 1); + elem->opr.name[i] = '\0'; + switch (token->type) + { + case OP_OPEN_COLL_ELEM: + elem->type = COLL_SYM; + break; + case OP_OPEN_EQUIV_CLASS: + elem->type = EQUIV_CLASS; + break; + case OP_OPEN_CHAR_CLASS: + elem->type = CHAR_CLASS; + break; + default: + break; + } + return REG_NOERROR; +} + + /* Helper function for parse_bracket_exp. + Build the equivalence class which is represented by NAME. + The result are written to MBCSET and SBCSET. + EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes, + is a pointer argument sinse we may update it. */ + +static reg_errcode_t +#ifdef RE_ENABLE_I18N +build_equiv_class (bitset_t sbcset, re_charset_t *mbcset, + Idx *equiv_class_alloc, const unsigned char *name) +#else /* not RE_ENABLE_I18N */ +build_equiv_class (bitset_t sbcset, const unsigned char *name) +#endif /* not RE_ENABLE_I18N */ +{ +#ifdef _LIBC + uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + if (nrules != 0) + { + const int32_t *table, *indirect; + const unsigned char *weights, *extra, *cp; + unsigned char char_buf[2]; + int32_t idx1, idx2; + unsigned int ch; + size_t len; + /* This #include defines a local function! */ +# include + /* Calculate the index for equivalence class. */ + cp = name; + table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); + weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_WEIGHTMB); + extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_EXTRAMB); + indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_INDIRECTMB); + idx1 = findidx (&cp); + if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0)) + /* This isn't a valid character. */ + return REG_ECOLLATE; + + /* Build single byte matcing table for this equivalence class. */ + char_buf[1] = (unsigned char) '\0'; + len = weights[idx1 & 0xffffff]; + for (ch = 0; ch < SBC_MAX; ++ch) + { + char_buf[0] = ch; + cp = char_buf; + idx2 = findidx (&cp); +/* + idx2 = table[ch]; +*/ + if (idx2 == 0) + /* This isn't a valid character. */ + continue; + /* Compare only if the length matches and the collation rule + index is the same. */ + if (len == weights[idx2 & 0xffffff] && (idx1 >> 24) == (idx2 >> 24)) + { + int cnt = 0; + + while (cnt <= len && + weights[(idx1 & 0xffffff) + 1 + cnt] + == weights[(idx2 & 0xffffff) + 1 + cnt]) + ++cnt; + + if (cnt > len) + bitset_set (sbcset, ch); + } + } + /* Check whether the array has enough space. */ + if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0)) + { + /* Not enough, realloc it. */ + /* +1 in case of mbcset->nequiv_classes is 0. */ + Idx new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1; + /* Use realloc since the array is NULL if *alloc == 0. */ + int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes, + int32_t, + new_equiv_class_alloc); + if (BE (new_equiv_classes == NULL, 0)) + return REG_ESPACE; + mbcset->equiv_classes = new_equiv_classes; + *equiv_class_alloc = new_equiv_class_alloc; + } + mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1; + } + else +#endif /* _LIBC */ + { + if (BE (strlen ((const char *) name) != 1, 0)) + return REG_ECOLLATE; + bitset_set (sbcset, *name); + } + return REG_NOERROR; +} + + /* Helper function for parse_bracket_exp. + Build the character class which is represented by NAME. + The result are written to MBCSET and SBCSET. + CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes, + is a pointer argument sinse we may update it. */ + +static reg_errcode_t +#ifdef RE_ENABLE_I18N +build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, + re_charset_t *mbcset, Idx *char_class_alloc, + const unsigned char *class_name, reg_syntax_t syntax) +#else /* not RE_ENABLE_I18N */ +build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, + const unsigned char *class_name, reg_syntax_t syntax) +#endif /* not RE_ENABLE_I18N */ +{ + int i; + const char *name = (const char *) class_name; + + /* In case of REG_ICASE "upper" and "lower" match the both of + upper and lower cases. */ + if ((syntax & RE_ICASE) + && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0)) + name = "alpha"; + +#ifdef RE_ENABLE_I18N + /* Check the space of the arrays. */ + if (BE (*char_class_alloc == mbcset->nchar_classes, 0)) + { + /* Not enough, realloc it. */ + /* +1 in case of mbcset->nchar_classes is 0. */ + Idx new_char_class_alloc = 2 * mbcset->nchar_classes + 1; + /* Use realloc since array is NULL if *alloc == 0. */ + wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t, + new_char_class_alloc); + if (BE (new_char_classes == NULL, 0)) + return REG_ESPACE; + mbcset->char_classes = new_char_classes; + *char_class_alloc = new_char_class_alloc; + } + mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name); +#endif /* RE_ENABLE_I18N */ + +#define BUILD_CHARCLASS_LOOP(ctype_func) \ + do { \ + if (BE (trans != NULL, 0)) \ + { \ + for (i = 0; i < SBC_MAX; ++i) \ + if (ctype_func (i)) \ + bitset_set (sbcset, trans[i]); \ + } \ + else \ + { \ + for (i = 0; i < SBC_MAX; ++i) \ + if (ctype_func (i)) \ + bitset_set (sbcset, i); \ + } \ + } while (0) + + if (strcmp (name, "alnum") == 0) + BUILD_CHARCLASS_LOOP (isalnum); + else if (strcmp (name, "cntrl") == 0) + BUILD_CHARCLASS_LOOP (iscntrl); + else if (strcmp (name, "lower") == 0) + BUILD_CHARCLASS_LOOP (islower); + else if (strcmp (name, "space") == 0) + BUILD_CHARCLASS_LOOP (isspace); + else if (strcmp (name, "alpha") == 0) + BUILD_CHARCLASS_LOOP (isalpha); + else if (strcmp (name, "digit") == 0) + BUILD_CHARCLASS_LOOP (isdigit); + else if (strcmp (name, "print") == 0) + BUILD_CHARCLASS_LOOP (isprint); + else if (strcmp (name, "upper") == 0) + BUILD_CHARCLASS_LOOP (isupper); + else if (strcmp (name, "blank") == 0) + BUILD_CHARCLASS_LOOP (isblank); + else if (strcmp (name, "graph") == 0) + BUILD_CHARCLASS_LOOP (isgraph); + else if (strcmp (name, "punct") == 0) + BUILD_CHARCLASS_LOOP (ispunct); + else if (strcmp (name, "xdigit") == 0) + BUILD_CHARCLASS_LOOP (isxdigit); + else + return REG_ECTYPE; + + return REG_NOERROR; +} + +static bin_tree_t * +build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, + const unsigned char *class_name, + const unsigned char *extra, bool non_match, + reg_errcode_t *err) +{ + re_bitset_ptr_t sbcset; +#ifdef RE_ENABLE_I18N + re_charset_t *mbcset; + Idx alloc = 0; +#endif /* not RE_ENABLE_I18N */ + reg_errcode_t ret; + re_token_t br_token; + bin_tree_t *tree; + + sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); +#ifdef RE_ENABLE_I18N + mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); +#endif /* RE_ENABLE_I18N */ + +#ifdef RE_ENABLE_I18N + if (BE (sbcset == NULL || mbcset == NULL, 0)) +#else /* not RE_ENABLE_I18N */ + if (BE (sbcset == NULL, 0)) +#endif /* not RE_ENABLE_I18N */ + { + *err = REG_ESPACE; + return NULL; + } + + if (non_match) + { +#ifdef RE_ENABLE_I18N + mbcset->non_match = 1; +#endif /* not RE_ENABLE_I18N */ + } + + /* We don't care the syntax in this case. */ + ret = build_charclass (trans, sbcset, +#ifdef RE_ENABLE_I18N + mbcset, &alloc, +#endif /* RE_ENABLE_I18N */ + class_name, 0); + + if (BE (ret != REG_NOERROR, 0)) + { + re_free (sbcset); +#ifdef RE_ENABLE_I18N + free_charset (mbcset); +#endif /* RE_ENABLE_I18N */ + *err = ret; + return NULL; + } + /* \w match '_' also. */ + for (; *extra; extra++) + bitset_set (sbcset, *extra); + + /* If it is non-matching list. */ + if (non_match) + bitset_not (sbcset); + +#ifdef RE_ENABLE_I18N + /* Ensure only single byte characters are set. */ + if (dfa->mb_cur_max > 1) + bitset_mask (sbcset, dfa->sb_char); +#endif + + /* Build a tree for simple bracket. */ + br_token.type = SIMPLE_BRACKET; + br_token.opr.sbcset = sbcset; + tree = create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (tree == NULL, 0)) + goto build_word_op_espace; + +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + { + bin_tree_t *mbc_tree; + /* Build a tree for complex bracket. */ + br_token.type = COMPLEX_BRACKET; + br_token.opr.mbcset = mbcset; + dfa->has_mb_node = 1; + mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (mbc_tree == NULL, 0)) + goto build_word_op_espace; + /* Then join them by ALT node. */ + tree = create_tree (dfa, tree, mbc_tree, OP_ALT); + if (BE (mbc_tree != NULL, 1)) + return tree; + } + else + { + free_charset (mbcset); + return tree; + } +#else /* not RE_ENABLE_I18N */ + return tree; +#endif /* not RE_ENABLE_I18N */ + + build_word_op_espace: + re_free (sbcset); +#ifdef RE_ENABLE_I18N + free_charset (mbcset); +#endif /* RE_ENABLE_I18N */ + *err = REG_ESPACE; + return NULL; +} + +/* This is intended for the expressions like "a{1,3}". + Fetch a number from `input', and return the number. + Return REG_MISSING if the number field is empty like "{,1}". + Return REG_ERROR if an error occurred. */ + +static Idx +fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax) +{ + Idx num = REG_MISSING; + unsigned char c; + while (1) + { + fetch_token (token, input, syntax); + c = token->opr.c; + if (BE (token->type == END_OF_RE, 0)) + return REG_ERROR; + if (token->type == OP_CLOSE_DUP_NUM || c == ',') + break; + num = ((token->type != CHARACTER || c < '0' || '9' < c + || num == REG_ERROR) + ? REG_ERROR + : ((num == REG_MISSING) ? c - '0' : num * 10 + c - '0')); + num = (num > RE_DUP_MAX) ? REG_ERROR : num; + } + return num; +} + +#ifdef RE_ENABLE_I18N +static void +free_charset (re_charset_t *cset) +{ + re_free (cset->mbchars); +# ifdef _LIBC + re_free (cset->coll_syms); + re_free (cset->equiv_classes); + re_free (cset->range_starts); + re_free (cset->range_ends); +# endif + re_free (cset->char_classes); + re_free (cset); +} +#endif /* RE_ENABLE_I18N */ + +/* Functions for binary tree operation. */ + +/* Create a tree node. */ + +static bin_tree_t * +create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, + re_token_type_t type) +{ + re_token_t t; + t.type = type; + return create_token_tree (dfa, left, right, &t); +} + +static bin_tree_t * +create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, + const re_token_t *token) +{ + bin_tree_t *tree; + if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0)) + { + bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1); + + if (storage == NULL) + return NULL; + storage->next = dfa->str_tree_storage; + dfa->str_tree_storage = storage; + dfa->str_tree_storage_idx = 0; + } + tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++]; + + tree->parent = NULL; + tree->left = left; + tree->right = right; + tree->token = *token; + tree->token.duplicated = 0; + tree->token.opt_subexp = 0; + tree->first = NULL; + tree->next = NULL; + tree->node_idx = REG_MISSING; + + if (left != NULL) + left->parent = tree; + if (right != NULL) + right->parent = tree; + return tree; +} + +/* Mark the tree SRC as an optional subexpression. + To be called from preorder or postorder. */ + +static reg_errcode_t +mark_opt_subexp (void *extra, bin_tree_t *node) +{ + Idx idx = (Idx) (long) extra; + if (node->token.type == SUBEXP && node->token.opr.idx == idx) + node->token.opt_subexp = 1; + + return REG_NOERROR; +} + +/* Free the allocated memory inside NODE. */ + +static void +free_token (re_token_t *node) +{ +#ifdef RE_ENABLE_I18N + if (node->type == COMPLEX_BRACKET && node->duplicated == 0) + free_charset (node->opr.mbcset); + else +#endif /* RE_ENABLE_I18N */ + if (node->type == SIMPLE_BRACKET && node->duplicated == 0) + re_free (node->opr.sbcset); +} + +/* Worker function for tree walking. Free the allocated memory inside NODE + and its children. */ + +static reg_errcode_t +free_tree (void *extra, bin_tree_t *node) +{ + free_token (&node->token); + return REG_NOERROR; +} + + +/* Duplicate the node SRC, and return new node. This is a preorder + visit similar to the one implemented by the generic visitor, but + we need more infrastructure to maintain two parallel trees --- so, + it's easier to duplicate. */ + +static bin_tree_t * +duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa) +{ + const bin_tree_t *node; + bin_tree_t *dup_root; + bin_tree_t **p_new = &dup_root, *dup_node = root->parent; + + for (node = root; ; ) + { + /* Create a new tree and link it back to the current parent. */ + *p_new = create_token_tree (dfa, NULL, NULL, &node->token); + if (*p_new == NULL) + return NULL; + (*p_new)->parent = dup_node; + (*p_new)->token.duplicated = 1; + dup_node = *p_new; + + /* Go to the left node, or up and to the right. */ + if (node->left) + { + node = node->left; + p_new = &dup_node->left; + } + else + { + const bin_tree_t *prev = NULL; + while (node->right == prev || node->right == NULL) + { + prev = node; + node = node->parent; + dup_node = dup_node->parent; + if (!node) + return dup_root; + } + node = node->right; + p_new = &dup_node->right; + } + } +} diff --git a/gnulib/regex.c b/gnulib/regex.c new file mode 100644 index 000000000..904fe62c8 --- /dev/null +++ b/gnulib/regex.c @@ -0,0 +1,72 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002, 2003, 2005, 2006, 2009, 2010 Free Software Foundation, + Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + This program 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 2, or (at your option) + any later version. + + This program 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 this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include + +/* Make sure noone compiles this code with a C++ compiler. */ +#if defined __cplusplus && defined _LIBC +# error "This is C code, use a C compiler" +#endif + +#ifdef _LIBC +/* We have to keep the namespace clean. */ +# define regfree(preg) __regfree (preg) +# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) +# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) +# define regerror(errcode, preg, errbuf, errbuf_size) \ + __regerror(errcode, preg, errbuf, errbuf_size) +# define re_set_registers(bu, re, nu, st, en) \ + __re_set_registers (bu, re, nu, st, en) +# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ + __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) +# define re_match(bufp, string, size, pos, regs) \ + __re_match (bufp, string, size, pos, regs) +# define re_search(bufp, string, size, startpos, range, regs) \ + __re_search (bufp, string, size, startpos, range, regs) +# define re_compile_pattern(pattern, length, bufp) \ + __re_compile_pattern (pattern, length, bufp) +# define re_set_syntax(syntax) __re_set_syntax (syntax) +# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ + __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) +# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) + +# include "../locale/localeinfo.h" +#endif + +/* On some systems, limits.h sets RE_DUP_MAX to a lower value than + GNU regex allows. Include it before , which correctly + #undefs RE_DUP_MAX and sets it to the right value. */ +#include + +#include +#include "regex_internal.h" + +#include "regex_internal.c" +#include "regcomp.c" +#include "regexec.c" + +/* Binary backward compatibility. */ +#if _LIBC +# include +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3) +link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.") +int re_max_failures = 2000; +# endif +#endif diff --git a/gnulib/regex.h b/gnulib/regex.h new file mode 100644 index 000000000..594d5e6aa --- /dev/null +++ b/gnulib/regex.h @@ -0,0 +1,676 @@ +/* Definitions for data structures and routines for the regular + expression library. + Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993, 1995, 1996, 1997, 1998, + 2000, 2001, 2002, 2003, 2005, 2006, 2009, 2010 Free Software Foundation, + Inc. + This file is part of the GNU C Library. + + This program 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 2, or (at your option) + any later version. + + This program 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 this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _REGEX_H +#define _REGEX_H 1 + +#include + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Define __USE_GNU_REGEX to declare GNU extensions that violate the + POSIX name space rules. */ +#undef __USE_GNU_REGEX +#if (defined _GNU_SOURCE \ + || (!defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE \ + && !defined _XOPEN_SOURCE)) +# define __USE_GNU_REGEX 1 +#endif + +#ifdef _REGEX_LARGE_OFFSETS + +/* Use types and values that are wide enough to represent signed and + unsigned byte offsets in memory. This currently works only when + the regex code is used outside of the GNU C library; it is not yet + supported within glibc itself, and glibc users should not define + _REGEX_LARGE_OFFSETS. */ + +/* The type of the offset of a byte within a string. + For historical reasons POSIX 1003.1-2004 requires that regoff_t be + at least as wide as off_t. However, many common POSIX platforms set + regoff_t to the more-sensible ssize_t and the Open Group has + signalled its intention to change the requirement to be that + regoff_t be at least as wide as ptrdiff_t and ssize_t; see XBD ERN + 60 (2005-08-25). We don't know of any hosts where ssize_t or + ptrdiff_t is wider than ssize_t, so ssize_t is safe. */ +typedef ssize_t regoff_t; + +/* The type of nonnegative object indexes. Traditionally, GNU regex + uses 'int' for these. Code that uses __re_idx_t should work + regardless of whether the type is signed. */ +typedef size_t __re_idx_t; + +/* The type of object sizes. */ +typedef size_t __re_size_t; + +/* The type of object sizes, in places where the traditional code + uses unsigned long int. */ +typedef size_t __re_long_size_t; + +#else + +/* Use types that are binary-compatible with the traditional GNU regex + implementation, which mishandles strings longer than INT_MAX. */ + +typedef int regoff_t; +typedef int __re_idx_t; +typedef unsigned int __re_size_t; +typedef unsigned long int __re_long_size_t; + +#endif + +/* The following two types have to be signed and unsigned integer type + wide enough to hold a value of a pointer. For most ANSI compilers + ptrdiff_t and size_t should be likely OK. Still size of these two + types is 2 for Microsoft C. Ugh... */ +typedef long int s_reg_t; +typedef unsigned long int active_reg_t; + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings are chosen so that Emacs syntax + remains the value 0. The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned long int reg_syntax_t; + +#ifdef __USE_GNU_REGEX + +/* If this bit is not set, then \ inside a bracket expression is literal. + If set, then such a \ quotes the following character. */ +# define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) + +/* If this bit is not set, then + and ? are operators, and \+ and \? are + literals. + If set, then \+ and \? are operators and + and ? are literals. */ +# define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) + +/* If this bit is set, then character classes are supported. They are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +# define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) + +/* If this bit is set, then ^ and $ are always anchors (outside bracket + expressions, of course). + If this bit is not set, then it depends: + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. + + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because + POSIX draft 11.2 says that * etc. in leading positions is undefined. + We already implemented a previous draft which made those constructs + invalid, though, so we haven't changed the code back. */ +# define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) + +/* If this bit is set, then special characters are always special + regardless of where they are in the pattern. + If this bit is not set, then special characters are special only in + some contexts; otherwise they are ordinary. Specifically, + * + ? and intervals are only special when not after the beginning, + open-group, or alternation operator. */ +# define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) + +/* If this bit is set, then *, +, ?, and { cannot be first in an re or + immediately after an alternation or begin-group operator. */ +# define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) + +/* If this bit is set, then . matches newline. + If not set, then it doesn't. */ +# define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) + +/* If this bit is set, then . doesn't match NUL. + If not set, then it does. */ +# define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) + +/* If this bit is set, nonmatching lists [^...] do not match newline. + If not set, they do. */ +# define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) + +/* If this bit is set, either \{...\} or {...} defines an + interval, depending on RE_NO_BK_BRACES. + If not set, \{, \}, {, and } are literals. */ +# define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) + +/* If this bit is set, +, ? and | aren't recognized as operators. + If not set, they are. */ +# define RE_LIMITED_OPS (RE_INTERVALS << 1) + +/* If this bit is set, newline is an alternation operator. + If not set, newline is literal. */ +# define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) + +/* If this bit is set, then `{...}' defines an interval, and \{ and \} + are literals. + If not set, then `\{...\}' defines an interval. */ +# define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) + +/* If this bit is set, (...) defines a group, and \( and \) are literals. + If not set, \(...\) defines a group, and ( and ) are literals. */ +# define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) + +/* If this bit is set, then \ matches . + If not set, then \ is a back-reference. */ +# define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) + +/* If this bit is set, then | is an alternation operator, and \| is literal. + If not set, then \| is an alternation operator, and | is literal. */ +# define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) + +/* If this bit is set, then an ending range point collating higher + than the starting range point, as in [z-a], is invalid. + If not set, then when ending range point collates higher than the + starting range point, the range is ignored. */ +# define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) + +/* If this bit is set, then an unmatched ) is ordinary. + If not set, then an unmatched ) is invalid. */ +# define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) + +/* If this bit is set, succeed as soon as we match the whole pattern, + without further backtracking. */ +# define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) + +/* If this bit is set, do not process the GNU regex operators. + If not set, then the GNU regex operators are recognized. */ +# define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) + +/* If this bit is set, turn on internal regex debugging. + If not set, and debugging was on, turn it off. + This only works if regex.c is compiled -DDEBUG. + We define this bit always, so that all that's needed to turn on + debugging is to recompile regex.c; the calling code can always have + this bit set, and it won't affect anything in the normal case. */ +# define RE_DEBUG (RE_NO_GNU_OPS << 1) + +/* If this bit is set, a syntactically invalid interval is treated as + a string of ordinary characters. For example, the ERE 'a{1' is + treated as 'a\{1'. */ +# define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1) + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +# define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) + +/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only + for ^, because it is difficult to scan the regex backwards to find + whether ^ should be special. */ +# define RE_CARET_ANCHORS_HERE (RE_ICASE << 1) + +/* If this bit is set, then \{ cannot be first in an bre or + immediately after an alternation or begin-group operator. */ +# define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1) + +/* If this bit is set, then no_sub will be set to 1 during + re_compile_pattern. */ +# define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1) + +#endif /* defined __USE_GNU_REGEX */ + +/* This global variable defines the particular regexp syntax to use (for + some interfaces). When a regexp is compiled, the syntax used is + stored in the pattern buffer, so changing this does not affect + already-compiled regexps. */ +extern reg_syntax_t re_syntax_options; + +#ifdef __USE_GNU_REGEX +/* Define combinations of the above bits for the standard possibilities. + (The [[[ comments delimit what gets put into the Texinfo file, so + don't delete them!) */ +/* [[[begin syntaxes]]] */ +# define RE_SYNTAX_EMACS 0 + +# define RE_SYNTAX_AWK \ + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ + | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ + | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) + +# define RE_SYNTAX_GNU_AWK \ + ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \ + & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS \ + | RE_CONTEXT_INVALID_OPS )) + +# define RE_SYNTAX_POSIX_AWK \ + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ + | RE_INTERVALS | RE_NO_GNU_OPS) + +# define RE_SYNTAX_GREP \ + (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ + | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ + | RE_NEWLINE_ALT) + +# define RE_SYNTAX_EGREP \ + (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ + | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ + | RE_NO_BK_VBAR) + +# define RE_SYNTAX_POSIX_EGREP \ + (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \ + | RE_INVALID_INTERVAL_ORD) + +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ +# define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + +# define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + +/* Syntax bits common to both basic and extended POSIX regex syntax. */ +# define _RE_SYNTAX_POSIX_COMMON \ + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ + | RE_INTERVALS | RE_NO_EMPTY_RANGES) + +# define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP) + +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this + isn't minimal, since other operators, such as \`, aren't disabled. */ +# define RE_SYNTAX_POSIX_MINIMAL_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) + +# define RE_SYNTAX_POSIX_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) + +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is + removed and RE_NO_BK_REFS is added. */ +# define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) +/* [[[end syntaxes]]] */ + +#endif /* defined __USE_GNU_REGEX */ + +#ifdef __USE_GNU_REGEX + +/* Maximum number of duplicates an interval can allow. POSIX-conforming + systems might define this in , but we want our + value, so remove any previous define. */ +# ifdef RE_DUP_MAX +# undef RE_DUP_MAX +# endif + +/* RE_DUP_MAX is 2**15 - 1 because an earlier implementation stored + the counter as a 2-byte signed integer. This is no longer true, so + RE_DUP_MAX could be increased to (INT_MAX / 10 - 1), or to + ((SIZE_MAX - 2) / 10 - 1) if _REGEX_LARGE_OFFSETS is defined. + However, there would be a huge performance problem if someone + actually used a pattern like a\{214748363\}, so RE_DUP_MAX retains + its historical value. */ +# define RE_DUP_MAX (0x7fff) + +#endif /* defined __USE_GNU_REGEX */ + + +/* POSIX `cflags' bits (i.e., information for `regcomp'). */ + +/* If this bit is set, then use extended regular expression syntax. + If not set, then use basic regular expression syntax. */ +#define REG_EXTENDED 1 + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define REG_ICASE (1 << 1) + +/* If this bit is set, then anchors do not match at newline + characters in the string. + If not set, then anchors do match at newlines. */ +#define REG_NEWLINE (1 << 2) + +/* If this bit is set, then report only success or fail in regexec. + If not set, then returns differ between not matching and errors. */ +#define REG_NOSUB (1 << 3) + + +/* POSIX `eflags' bits (i.e., information for regexec). */ + +/* If this bit is set, then the beginning-of-line operator doesn't match + the beginning of the string (presumably because it's not the + beginning of a line). + If not set, then the beginning-of-line operator does match the + beginning of the string. */ +#define REG_NOTBOL 1 + +/* Like REG_NOTBOL, except for the end-of-line. */ +#define REG_NOTEOL (1 << 1) + +/* Use PMATCH[0] to delimit the start and end of the search in the + buffer. */ +#define REG_STARTEND (1 << 2) + + +/* If any error codes are removed, changed, or added, update the + `__re_error_msgid' table in regcomp.c. */ + +typedef enum +{ + _REG_ENOSYS = -1, /* This will never happen for this implementation. */ + _REG_NOERROR = 0, /* Success. */ + _REG_NOMATCH, /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ + _REG_BADPAT, /* Invalid pattern. */ + _REG_ECOLLATE, /* Invalid collating element. */ + _REG_ECTYPE, /* Invalid character class name. */ + _REG_EESCAPE, /* Trailing backslash. */ + _REG_ESUBREG, /* Invalid back reference. */ + _REG_EBRACK, /* Unmatched left bracket. */ + _REG_EPAREN, /* Parenthesis imbalance. */ + _REG_EBRACE, /* Unmatched \{. */ + _REG_BADBR, /* Invalid contents of \{\}. */ + _REG_ERANGE, /* Invalid range end. */ + _REG_ESPACE, /* Ran out of memory. */ + _REG_BADRPT, /* No preceding re for repetition op. */ + + /* Error codes we've added. */ + _REG_EEND, /* Premature end. */ + _REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ + _REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ +} reg_errcode_t; + +#ifdef _XOPEN_SOURCE +# define REG_ENOSYS _REG_ENOSYS +#endif +#define REG_NOERROR _REG_NOERROR +#define REG_NOMATCH _REG_NOMATCH +#define REG_BADPAT _REG_BADPAT +#define REG_ECOLLATE _REG_ECOLLATE +#define REG_ECTYPE _REG_ECTYPE +#define REG_EESCAPE _REG_EESCAPE +#define REG_ESUBREG _REG_ESUBREG +#define REG_EBRACK _REG_EBRACK +#define REG_EPAREN _REG_EPAREN +#define REG_EBRACE _REG_EBRACE +#define REG_BADBR _REG_BADBR +#define REG_ERANGE _REG_ERANGE +#define REG_ESPACE _REG_ESPACE +#define REG_BADRPT _REG_BADRPT +#define REG_EEND _REG_EEND +#define REG_ESIZE _REG_ESIZE +#define REG_ERPAREN _REG_ERPAREN + +/* struct re_pattern_buffer normally uses member names like `buffer' + that POSIX does not allow. In POSIX mode these members have names + with leading `re_' (e.g., `re_buffer'). */ +#ifdef __USE_GNU_REGEX +# define _REG_RE_NAME(id) id +# define _REG_RM_NAME(id) id +#else +# define _REG_RE_NAME(id) re_##id +# define _REG_RM_NAME(id) rm_##id +#endif + +/* The user can specify the type of the re_translate member by + defining the macro RE_TRANSLATE_TYPE, which defaults to unsigned + char *. This pollutes the POSIX name space, so in POSIX mode just + use unsigned char *. */ +#ifdef __USE_GNU_REGEX +# ifndef RE_TRANSLATE_TYPE +# define RE_TRANSLATE_TYPE unsigned char * +# endif +# define REG_TRANSLATE_TYPE RE_TRANSLATE_TYPE +#else +# define REG_TRANSLATE_TYPE unsigned char * +#endif + +/* This data structure represents a compiled pattern. Before calling + the pattern compiler, the fields `buffer', `allocated', `fastmap', + `translate', and `no_sub' can be set. After the pattern has been + compiled, the `re_nsub' field is available. All other fields are + private to the regex routines. */ + +struct re_pattern_buffer +{ + /* Space that holds the compiled pattern. It is declared as + `unsigned char *' because its elements are sometimes used as + array indexes. */ + unsigned char *_REG_RE_NAME (buffer); + + /* Number of bytes to which `buffer' points. */ + __re_long_size_t _REG_RE_NAME (allocated); + + /* Number of bytes actually used in `buffer'. */ + __re_long_size_t _REG_RE_NAME (used); + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t _REG_RE_NAME (syntax); + + /* Pointer to a fastmap, if any, otherwise zero. re_search uses the + fastmap, if there is one, to skip over impossible starting points + for matches. */ + char *_REG_RE_NAME (fastmap); + + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation is + applied to a pattern when it is compiled and to a string when it + is matched. */ + REG_TRANSLATE_TYPE _REG_RE_NAME (translate); + + /* Number of subexpressions found by the compiler. */ + size_t re_nsub; + + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see whether or + not we should use the fastmap, so we don't set this absolutely + perfectly; see `re_compile_fastmap' (the `duplicate' case). */ + unsigned int _REG_RE_NAME (can_be_null) : 1; + + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ +#ifdef __USE_GNU_REGEX +# define REGS_UNALLOCATED 0 +# define REGS_REALLOCATE 1 +# define REGS_FIXED 2 +#endif + unsigned int _REG_RE_NAME (regs_allocated) : 2; + + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ + unsigned int _REG_RE_NAME (fastmap_accurate) : 1; + + /* If set, `re_match_2' does not return information about + subexpressions. */ + unsigned int _REG_RE_NAME (no_sub) : 1; + + /* If set, a beginning-of-line anchor doesn't match at the beginning + of the string. */ + unsigned int _REG_RE_NAME (not_bol) : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned int _REG_RE_NAME (not_eol) : 1; + + /* If true, an anchor at a newline matches. */ + unsigned int _REG_RE_NAME (newline_anchor) : 1; + +/* [[[end pattern_buffer]]] */ +}; + +typedef struct re_pattern_buffer regex_t; + +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + __re_size_t _REG_RM_NAME (num_regs); + regoff_t *_REG_RM_NAME (start); + regoff_t *_REG_RM_NAME (end); +}; + + +/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, + `re_match_2' returns information about at least this many registers + the first time a `regs' structure is passed. */ +#if !defined RE_NREGS && defined __USE_GNU_REGEX +# define RE_NREGS 30 +#endif + + +/* POSIX specification for registers. Aside from the different names than + `re_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ +} regmatch_t; + +/* Declarations for routines. */ + +/* Sets the current default syntax to SYNTAX, and return the old syntax. + You can also simply assign to the `re_syntax_options' variable. */ +extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); + +/* Compile the regular expression PATTERN, with length LENGTH + and syntax given by the global `re_syntax_options', into the buffer + BUFFER. Return NULL if successful, and an error string if not. */ +extern const char *re_compile_pattern (const char *__pattern, size_t __length, + struct re_pattern_buffer *__buffer); + + +/* Compile a fastmap for the compiled pattern in BUFFER; used to + accelerate searches. Return 0 if successful and -2 if was an + internal error. */ +extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); + + +/* Search in the string STRING (with length LENGTH) for the pattern + compiled into BUFFER. Start searching at position START, for RANGE + characters. Return the starting position of the match, -1 for no + match, or -2 for an internal error. Also return register + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ +extern regoff_t re_search (struct re_pattern_buffer *__buffer, + const char *__string, __re_idx_t __length, + __re_idx_t __start, regoff_t __range, + struct re_registers *__regs); + + +/* Like `re_search', but search in the concatenation of STRING1 and + STRING2. Also, stop searching at index START + STOP. */ +extern regoff_t re_search_2 (struct re_pattern_buffer *__buffer, + const char *__string1, __re_idx_t __length1, + const char *__string2, __re_idx_t __length2, + __re_idx_t __start, regoff_t __range, + struct re_registers *__regs, + __re_idx_t __stop); + + +/* Like `re_search', but return how many characters in STRING the regexp + in BUFFER matched, starting at position START. */ +extern regoff_t re_match (struct re_pattern_buffer *__buffer, + const char *__string, __re_idx_t __length, + __re_idx_t __start, struct re_registers *__regs); + + +/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ +extern regoff_t re_match_2 (struct re_pattern_buffer *__buffer, + const char *__string1, __re_idx_t __length1, + const char *__string2, __re_idx_t __length2, + __re_idx_t __start, struct re_registers *__regs, + __re_idx_t __stop); + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using BUFFER and REGS will use this memory + for recording register information. STARTS and ENDS must be + allocated with malloc, and must each be at least `NUM_REGS * sizeof + (regoff_t)' bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ +extern void re_set_registers (struct re_pattern_buffer *__buffer, + struct re_registers *__regs, + __re_size_t __num_regs, + regoff_t *__starts, regoff_t *__ends); + +#if defined _REGEX_RE_COMP || defined _LIBC +# ifndef _CRAY +/* 4.2 bsd compatibility. */ +extern char *re_comp (const char *); +extern int re_exec (const char *); +# endif +#endif + +/* GCC 2.95 and later have "__restrict"; C99 compilers have + "restrict", and "configure" may have defined "restrict". + Other compilers use __restrict, __restrict__, and _Restrict, and + 'configure' might #define 'restrict' to those words, so pick a + different name. */ +#ifndef _Restrict_ +# if 199901L <= __STDC_VERSION__ +# define _Restrict_ restrict +# elif 2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__) +# define _Restrict_ __restrict +# else +# define _Restrict_ +# endif +#endif +/* gcc 3.1 and up support the [restrict] syntax. Don't trust + sys/cdefs.h's definition of __restrict_arr, though, as it + mishandles gcc -ansi -pedantic. */ +#ifndef _Restrict_arr_ +# if ((199901L <= __STDC_VERSION__ \ + || ((3 < __GNUC__ || (3 == __GNUC__ && 1 <= __GNUC_MINOR__)) \ + && !__STRICT_ANSI__)) \ + && !defined __GNUG__) +# define _Restrict_arr_ _Restrict_ +# else +# define _Restrict_arr_ +# endif +#endif + +/* POSIX compatibility. */ +extern int regcomp (regex_t *_Restrict_ __preg, + const char *_Restrict_ __pattern, + int __cflags); + +extern int regexec (const regex_t *_Restrict_ __preg, + const char *_Restrict_ __string, size_t __nmatch, + regmatch_t __pmatch[_Restrict_arr_], + int __eflags); + +extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg, + char *_Restrict_ __errbuf, size_t __errbuf_size); + +extern void regfree (regex_t *__preg); + + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* regex.h */ diff --git a/gnulib/regex_internal.c b/gnulib/regex_internal.c new file mode 100644 index 000000000..378b767d8 --- /dev/null +++ b/gnulib/regex_internal.c @@ -0,0 +1,1740 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free + Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + This program 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 2, or (at your option) + any later version. + + This program 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 this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +static void re_string_construct_common (const char *str, Idx len, + re_string_t *pstr, + RE_TRANSLATE_TYPE trans, bool icase, + const re_dfa_t *dfa) internal_function; +static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa, + const re_node_set *nodes, + re_hashval_t hash) internal_function; +static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa, + const re_node_set *nodes, + unsigned int context, + re_hashval_t hash) internal_function; + +/* Functions for string operation. */ + +/* This function allocate the buffers. It is necessary to call + re_string_reconstruct before using the object. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_string_allocate (re_string_t *pstr, const char *str, Idx len, Idx init_len, + RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa) +{ + reg_errcode_t ret; + Idx init_buf_len; + + /* Ensure at least one character fits into the buffers. */ + if (init_len < dfa->mb_cur_max) + init_len = dfa->mb_cur_max; + init_buf_len = (len + 1 < init_len) ? len + 1: init_len; + re_string_construct_common (str, len, pstr, trans, icase, dfa); + + ret = re_string_realloc_buffers (pstr, init_buf_len); + if (BE (ret != REG_NOERROR, 0)) + return ret; + + pstr->word_char = dfa->word_char; + pstr->word_ops_used = dfa->word_ops_used; + pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; + pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len; + pstr->valid_raw_len = pstr->valid_len; + return REG_NOERROR; +} + +/* This function allocate the buffers, and initialize them. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_string_construct (re_string_t *pstr, const char *str, Idx len, + RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa) +{ + reg_errcode_t ret; + memset (pstr, '\0', sizeof (re_string_t)); + re_string_construct_common (str, len, pstr, trans, icase, dfa); + + if (len > 0) + { + ret = re_string_realloc_buffers (pstr, len + 1); + if (BE (ret != REG_NOERROR, 0)) + return ret; + } + pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; + + if (icase) + { +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + { + while (1) + { + ret = build_wcs_upper_buffer (pstr); + if (BE (ret != REG_NOERROR, 0)) + return ret; + if (pstr->valid_raw_len >= len) + break; + if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max) + break; + ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); + if (BE (ret != REG_NOERROR, 0)) + return ret; + } + } + else +#endif /* RE_ENABLE_I18N */ + build_upper_buffer (pstr); + } + else + { +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + build_wcs_buffer (pstr); + else +#endif /* RE_ENABLE_I18N */ + { + if (trans != NULL) + re_string_translate_buffer (pstr); + else + { + pstr->valid_len = pstr->bufs_len; + pstr->valid_raw_len = pstr->bufs_len; + } + } + } + + return REG_NOERROR; +} + +/* Helper functions for re_string_allocate, and re_string_construct. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_string_realloc_buffers (re_string_t *pstr, Idx new_buf_len) +{ +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + { + wint_t *new_wcs; + + /* Avoid overflow. */ + size_t max_object_size = MAX (sizeof (wint_t), sizeof (Idx)); + if (BE (SIZE_MAX / max_object_size < new_buf_len, 0)) + return REG_ESPACE; + + new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len); + if (BE (new_wcs == NULL, 0)) + return REG_ESPACE; + pstr->wcs = new_wcs; + if (pstr->offsets != NULL) + { + Idx *new_offsets = re_realloc (pstr->offsets, Idx, new_buf_len); + if (BE (new_offsets == NULL, 0)) + return REG_ESPACE; + pstr->offsets = new_offsets; + } + } +#endif /* RE_ENABLE_I18N */ + if (pstr->mbs_allocated) + { + unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char, + new_buf_len); + if (BE (new_mbs == NULL, 0)) + return REG_ESPACE; + pstr->mbs = new_mbs; + } + pstr->bufs_len = new_buf_len; + return REG_NOERROR; +} + + +static void +internal_function +re_string_construct_common (const char *str, Idx len, re_string_t *pstr, + RE_TRANSLATE_TYPE trans, bool icase, + const re_dfa_t *dfa) +{ + pstr->raw_mbs = (const unsigned char *) str; + pstr->len = len; + pstr->raw_len = len; + pstr->trans = trans; + pstr->icase = icase; + pstr->mbs_allocated = (trans != NULL || icase); + pstr->mb_cur_max = dfa->mb_cur_max; + pstr->is_utf8 = dfa->is_utf8; + pstr->map_notascii = dfa->map_notascii; + pstr->stop = pstr->len; + pstr->raw_stop = pstr->stop; +} + +#ifdef RE_ENABLE_I18N + +/* Build wide character buffer PSTR->WCS. + If the byte sequence of the string are: + (0), (1), (0), (1), + Then wide character buffer will be: + , WEOF , , WEOF , + We use WEOF for padding, they indicate that the position isn't + a first byte of a multibyte character. + + Note that this function assumes PSTR->VALID_LEN elements are already + built and starts from PSTR->VALID_LEN. */ + +static void +internal_function +build_wcs_buffer (re_string_t *pstr) +{ +#ifdef _LIBC + unsigned char buf[MB_LEN_MAX]; + assert (MB_LEN_MAX >= pstr->mb_cur_max); +#else + unsigned char buf[64]; +#endif + mbstate_t prev_st; + Idx byte_idx, end_idx, remain_len; + size_t mbclen; + + /* Build the buffers from pstr->valid_len to either pstr->len or + pstr->bufs_len. */ + end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; + for (byte_idx = pstr->valid_len; byte_idx < end_idx;) + { + wchar_t wc; + const char *p; + + remain_len = end_idx - byte_idx; + prev_st = pstr->cur_state; + /* Apply the translation if we need. */ + if (BE (pstr->trans != NULL, 0)) + { + int i, ch; + + for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i) + { + ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i]; + buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch]; + } + p = (const char *) buf; + } + else + p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx; + mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state); + if (BE (mbclen == (size_t) -2, 0)) + { + /* The buffer doesn't have enough space, finish to build. */ + pstr->cur_state = prev_st; + break; + } + else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0)) + { + /* We treat these cases as a singlebyte character. */ + mbclen = 1; + wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; + if (BE (pstr->trans != NULL, 0)) + wc = pstr->trans[wc]; + pstr->cur_state = prev_st; + } + + /* Write wide character and padding. */ + pstr->wcs[byte_idx++] = wc; + /* Write paddings. */ + for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) + pstr->wcs[byte_idx++] = WEOF; + } + pstr->valid_len = byte_idx; + pstr->valid_raw_len = byte_idx; +} + +/* Build wide character buffer PSTR->WCS like build_wcs_buffer, + but for REG_ICASE. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +build_wcs_upper_buffer (re_string_t *pstr) +{ + mbstate_t prev_st; + Idx src_idx, byte_idx, end_idx, remain_len; + size_t mbclen; +#ifdef _LIBC + char buf[MB_LEN_MAX]; + assert (MB_LEN_MAX >= pstr->mb_cur_max); +#else + char buf[64]; +#endif + + byte_idx = pstr->valid_len; + end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; + + /* The following optimization assumes that ASCII characters can be + mapped to wide characters with a simple cast. */ + if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed) + { + while (byte_idx < end_idx) + { + wchar_t wc; + + if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]) + && mbsinit (&pstr->cur_state)) + { + /* In case of a singlebyte character. */ + pstr->mbs[byte_idx] + = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]); + /* The next step uses the assumption that wchar_t is encoded + ASCII-safe: all ASCII values can be converted like this. */ + pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx]; + ++byte_idx; + continue; + } + + remain_len = end_idx - byte_idx; + prev_st = pstr->cur_state; + mbclen = __mbrtowc (&wc, + ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx + + byte_idx), remain_len, &pstr->cur_state); + if (BE (mbclen < (size_t) -2, 1)) + { + wchar_t wcu = wc; + if (iswlower (wc)) + { + size_t mbcdlen; + + wcu = towupper (wc); + mbcdlen = wcrtomb (buf, wcu, &prev_st); + if (BE (mbclen == mbcdlen, 1)) + memcpy (pstr->mbs + byte_idx, buf, mbclen); + else + { + src_idx = byte_idx; + goto offsets_needed; + } + } + else + memcpy (pstr->mbs + byte_idx, + pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen); + pstr->wcs[byte_idx++] = wcu; + /* Write paddings. */ + for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) + pstr->wcs[byte_idx++] = WEOF; + } + else if (mbclen == (size_t) -1 || mbclen == 0) + { + /* It is an invalid character or '\0'. Just use the byte. */ + int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; + pstr->mbs[byte_idx] = ch; + /* And also cast it to wide char. */ + pstr->wcs[byte_idx++] = (wchar_t) ch; + if (BE (mbclen == (size_t) -1, 0)) + pstr->cur_state = prev_st; + } + else + { + /* The buffer doesn't have enough space, finish to build. */ + pstr->cur_state = prev_st; + break; + } + } + pstr->valid_len = byte_idx; + pstr->valid_raw_len = byte_idx; + return REG_NOERROR; + } + else + for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;) + { + wchar_t wc; + const char *p; + offsets_needed: + remain_len = end_idx - byte_idx; + prev_st = pstr->cur_state; + if (BE (pstr->trans != NULL, 0)) + { + int i, ch; + + for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i) + { + ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i]; + buf[i] = pstr->trans[ch]; + } + p = (const char *) buf; + } + else + p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx; + mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state); + if (BE (mbclen < (size_t) -2, 1)) + { + wchar_t wcu = wc; + if (iswlower (wc)) + { + size_t mbcdlen; + + wcu = towupper (wc); + mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st); + if (BE (mbclen == mbcdlen, 1)) + memcpy (pstr->mbs + byte_idx, buf, mbclen); + else if (mbcdlen != (size_t) -1) + { + size_t i; + + if (byte_idx + mbcdlen > pstr->bufs_len) + { + pstr->cur_state = prev_st; + break; + } + + if (pstr->offsets == NULL) + { + pstr->offsets = re_malloc (Idx, pstr->bufs_len); + + if (pstr->offsets == NULL) + return REG_ESPACE; + } + if (!pstr->offsets_needed) + { + for (i = 0; i < (size_t) byte_idx; ++i) + pstr->offsets[i] = i; + pstr->offsets_needed = 1; + } + + memcpy (pstr->mbs + byte_idx, buf, mbcdlen); + pstr->wcs[byte_idx] = wcu; + pstr->offsets[byte_idx] = src_idx; + for (i = 1; i < mbcdlen; ++i) + { + pstr->offsets[byte_idx + i] + = src_idx + (i < mbclen ? i : mbclen - 1); + pstr->wcs[byte_idx + i] = WEOF; + } + pstr->len += mbcdlen - mbclen; + if (pstr->raw_stop > src_idx) + pstr->stop += mbcdlen - mbclen; + end_idx = (pstr->bufs_len > pstr->len) + ? pstr->len : pstr->bufs_len; + byte_idx += mbcdlen; + src_idx += mbclen; + continue; + } + else + memcpy (pstr->mbs + byte_idx, p, mbclen); + } + else + memcpy (pstr->mbs + byte_idx, p, mbclen); + + if (BE (pstr->offsets_needed != 0, 0)) + { + size_t i; + for (i = 0; i < mbclen; ++i) + pstr->offsets[byte_idx + i] = src_idx + i; + } + src_idx += mbclen; + + pstr->wcs[byte_idx++] = wcu; + /* Write paddings. */ + for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) + pstr->wcs[byte_idx++] = WEOF; + } + else if (mbclen == (size_t) -1 || mbclen == 0) + { + /* It is an invalid character or '\0'. Just use the byte. */ + int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx]; + + if (BE (pstr->trans != NULL, 0)) + ch = pstr->trans [ch]; + pstr->mbs[byte_idx] = ch; + + if (BE (pstr->offsets_needed != 0, 0)) + pstr->offsets[byte_idx] = src_idx; + ++src_idx; + + /* And also cast it to wide char. */ + pstr->wcs[byte_idx++] = (wchar_t) ch; + if (BE (mbclen == (size_t) -1, 0)) + pstr->cur_state = prev_st; + } + else + { + /* The buffer doesn't have enough space, finish to build. */ + pstr->cur_state = prev_st; + break; + } + } + pstr->valid_len = byte_idx; + pstr->valid_raw_len = src_idx; + return REG_NOERROR; +} + +/* Skip characters until the index becomes greater than NEW_RAW_IDX. + Return the index. */ + +static Idx +internal_function +re_string_skip_chars (re_string_t *pstr, Idx new_raw_idx, wint_t *last_wc) +{ + mbstate_t prev_st; + Idx rawbuf_idx; + size_t mbclen; + wint_t wc = WEOF; + + /* Skip the characters which are not necessary to check. */ + for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len; + rawbuf_idx < new_raw_idx;) + { + wchar_t wc2; + Idx remain_len; + remain_len = pstr->len - rawbuf_idx; + prev_st = pstr->cur_state; + mbclen = __mbrtowc (&wc2, (const char *) pstr->raw_mbs + rawbuf_idx, + remain_len, &pstr->cur_state); + if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0)) + { + /* We treat these cases as a single byte character. */ + if (mbclen == 0 || remain_len == 0) + wc = L'\0'; + else + wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx); + mbclen = 1; + pstr->cur_state = prev_st; + } + else + wc = wc2; + /* Then proceed the next character. */ + rawbuf_idx += mbclen; + } + *last_wc = wc; + return rawbuf_idx; +} +#endif /* RE_ENABLE_I18N */ + +/* Build the buffer PSTR->MBS, and apply the translation if we need. + This function is used in case of REG_ICASE. */ + +static void +internal_function +build_upper_buffer (re_string_t *pstr) +{ + Idx char_idx, end_idx; + end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; + + for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx) + { + int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx]; + if (BE (pstr->trans != NULL, 0)) + ch = pstr->trans[ch]; + if (islower (ch)) + pstr->mbs[char_idx] = toupper (ch); + else + pstr->mbs[char_idx] = ch; + } + pstr->valid_len = char_idx; + pstr->valid_raw_len = char_idx; +} + +/* Apply TRANS to the buffer in PSTR. */ + +static void +internal_function +re_string_translate_buffer (re_string_t *pstr) +{ + Idx buf_idx, end_idx; + end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; + + for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx) + { + int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx]; + pstr->mbs[buf_idx] = pstr->trans[ch]; + } + + pstr->valid_len = buf_idx; + pstr->valid_raw_len = buf_idx; +} + +/* This function re-construct the buffers. + Concretely, convert to wide character in case of pstr->mb_cur_max > 1, + convert to upper case in case of REG_ICASE, apply translation. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_string_reconstruct (re_string_t *pstr, Idx idx, int eflags) +{ + Idx offset; + + if (BE (pstr->raw_mbs_idx <= idx, 0)) + offset = idx - pstr->raw_mbs_idx; + else + { + /* Reset buffer. */ +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); +#endif /* RE_ENABLE_I18N */ + pstr->len = pstr->raw_len; + pstr->stop = pstr->raw_stop; + pstr->valid_len = 0; + pstr->raw_mbs_idx = 0; + pstr->valid_raw_len = 0; + pstr->offsets_needed = 0; + pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF + : CONTEXT_NEWLINE | CONTEXT_BEGBUF); + if (!pstr->mbs_allocated) + pstr->mbs = (unsigned char *) pstr->raw_mbs; + offset = idx; + } + + if (BE (offset != 0, 1)) + { + /* Should the already checked characters be kept? */ + if (BE (offset < pstr->valid_raw_len, 1)) + { + /* Yes, move them to the front of the buffer. */ +#ifdef RE_ENABLE_I18N + if (BE (pstr->offsets_needed, 0)) + { + Idx low = 0, high = pstr->valid_len, mid; + do + { + mid = (high + low) / 2; + if (pstr->offsets[mid] > offset) + high = mid; + else if (pstr->offsets[mid] < offset) + low = mid + 1; + else + break; + } + while (low < high); + if (pstr->offsets[mid] < offset) + ++mid; + pstr->tip_context = re_string_context_at (pstr, mid - 1, + eflags); + /* This can be quite complicated, so handle specially + only the common and easy case where the character with + different length representation of lower and upper + case is present at or after offset. */ + if (pstr->valid_len > offset + && mid == offset && pstr->offsets[mid] == offset) + { + memmove (pstr->wcs, pstr->wcs + offset, + (pstr->valid_len - offset) * sizeof (wint_t)); + memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset); + pstr->valid_len -= offset; + pstr->valid_raw_len -= offset; + for (low = 0; low < pstr->valid_len; low++) + pstr->offsets[low] = pstr->offsets[low + offset] - offset; + } + else + { + /* Otherwise, just find out how long the partial multibyte + character at offset is and fill it with WEOF/255. */ + pstr->len = pstr->raw_len - idx + offset; + pstr->stop = pstr->raw_stop - idx + offset; + pstr->offsets_needed = 0; + while (mid > 0 && pstr->offsets[mid - 1] == offset) + --mid; + while (mid < pstr->valid_len) + if (pstr->wcs[mid] != WEOF) + break; + else + ++mid; + if (mid == pstr->valid_len) + pstr->valid_len = 0; + else + { + pstr->valid_len = pstr->offsets[mid] - offset; + if (pstr->valid_len) + { + for (low = 0; low < pstr->valid_len; ++low) + pstr->wcs[low] = WEOF; + memset (pstr->mbs, 255, pstr->valid_len); + } + } + pstr->valid_raw_len = pstr->valid_len; + } + } + else +#endif + { + pstr->tip_context = re_string_context_at (pstr, offset - 1, + eflags); +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + memmove (pstr->wcs, pstr->wcs + offset, + (pstr->valid_len - offset) * sizeof (wint_t)); +#endif /* RE_ENABLE_I18N */ + if (BE (pstr->mbs_allocated, 0)) + memmove (pstr->mbs, pstr->mbs + offset, + pstr->valid_len - offset); + pstr->valid_len -= offset; + pstr->valid_raw_len -= offset; +#if DEBUG + assert (pstr->valid_len > 0); +#endif + } + } + else + { +#ifdef RE_ENABLE_I18N + /* No, skip all characters until IDX. */ + Idx prev_valid_len = pstr->valid_len; + + if (BE (pstr->offsets_needed, 0)) + { + pstr->len = pstr->raw_len - idx + offset; + pstr->stop = pstr->raw_stop - idx + offset; + pstr->offsets_needed = 0; + } +#endif + pstr->valid_len = 0; +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + { + Idx wcs_idx; + wint_t wc = WEOF; + + if (pstr->is_utf8) + { + const unsigned char *raw, *p, *end; + + /* Special case UTF-8. Multi-byte chars start with any + byte other than 0x80 - 0xbf. */ + raw = pstr->raw_mbs + pstr->raw_mbs_idx; + end = raw + (offset - pstr->mb_cur_max); + if (end < pstr->raw_mbs) + end = pstr->raw_mbs; + p = raw + offset - 1; +#ifdef _LIBC + /* We know the wchar_t encoding is UCS4, so for the simple + case, ASCII characters, skip the conversion step. */ + if (isascii (*p) && BE (pstr->trans == NULL, 1)) + { + memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); + /* pstr->valid_len = 0; */ + wc = (wchar_t) *p; + } + else +#endif + for (; p >= end; --p) + if ((*p & 0xc0) != 0x80) + { + mbstate_t cur_state; + wchar_t wc2; + Idx mlen = raw + pstr->len - p; + unsigned char buf[6]; + size_t mbclen; + + if (BE (pstr->trans != NULL, 0)) + { + int i = mlen < 6 ? mlen : 6; + while (--i >= 0) + buf[i] = pstr->trans[p[i]]; + } + /* XXX Don't use mbrtowc, we know which conversion + to use (UTF-8 -> UCS4). */ + memset (&cur_state, 0, sizeof (cur_state)); + mbclen = __mbrtowc (&wc2, (const char *) p, mlen, + &cur_state); + if (raw + offset - p <= mbclen + && mbclen < (size_t) -2) + { + memset (&pstr->cur_state, '\0', + sizeof (mbstate_t)); + pstr->valid_len = mbclen - (raw + offset - p); + wc = wc2; + } + break; + } + } + + if (wc == WEOF) + pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx; + if (wc == WEOF) + pstr->tip_context + = re_string_context_at (pstr, prev_valid_len - 1, eflags); + else + pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0) + && IS_WIDE_WORD_CHAR (wc)) + ? CONTEXT_WORD + : ((IS_WIDE_NEWLINE (wc) + && pstr->newline_anchor) + ? CONTEXT_NEWLINE : 0)); + if (BE (pstr->valid_len, 0)) + { + for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx) + pstr->wcs[wcs_idx] = WEOF; + if (pstr->mbs_allocated) + memset (pstr->mbs, 255, pstr->valid_len); + } + pstr->valid_raw_len = pstr->valid_len; + } + else +#endif /* RE_ENABLE_I18N */ + { + int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1]; + pstr->valid_raw_len = 0; + if (pstr->trans) + c = pstr->trans[c]; + pstr->tip_context = (bitset_contain (pstr->word_char, c) + ? CONTEXT_WORD + : ((IS_NEWLINE (c) && pstr->newline_anchor) + ? CONTEXT_NEWLINE : 0)); + } + } + if (!BE (pstr->mbs_allocated, 0)) + pstr->mbs += offset; + } + pstr->raw_mbs_idx = idx; + pstr->len -= offset; + pstr->stop -= offset; + + /* Then build the buffers. */ +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + { + if (pstr->icase) + { + reg_errcode_t ret = build_wcs_upper_buffer (pstr); + if (BE (ret != REG_NOERROR, 0)) + return ret; + } + else + build_wcs_buffer (pstr); + } + else +#endif /* RE_ENABLE_I18N */ + if (BE (pstr->mbs_allocated, 0)) + { + if (pstr->icase) + build_upper_buffer (pstr); + else if (pstr->trans != NULL) + re_string_translate_buffer (pstr); + } + else + pstr->valid_len = pstr->len; + + pstr->cur_idx = 0; + return REG_NOERROR; +} + +static unsigned char +internal_function __attribute ((pure)) +re_string_peek_byte_case (const re_string_t *pstr, Idx idx) +{ + int ch; + Idx off; + + /* Handle the common (easiest) cases first. */ + if (BE (!pstr->mbs_allocated, 1)) + return re_string_peek_byte (pstr, idx); + +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1 + && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx)) + return re_string_peek_byte (pstr, idx); +#endif + + off = pstr->cur_idx + idx; +#ifdef RE_ENABLE_I18N + if (pstr->offsets_needed) + off = pstr->offsets[off]; +#endif + + ch = pstr->raw_mbs[pstr->raw_mbs_idx + off]; + +#ifdef RE_ENABLE_I18N + /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I + this function returns CAPITAL LETTER I instead of first byte of + DOTLESS SMALL LETTER I. The latter would confuse the parser, + since peek_byte_case doesn't advance cur_idx in any way. */ + if (pstr->offsets_needed && !isascii (ch)) + return re_string_peek_byte (pstr, idx); +#endif + + return ch; +} + +static unsigned char +internal_function __attribute ((pure)) +re_string_fetch_byte_case (re_string_t *pstr) +{ + if (BE (!pstr->mbs_allocated, 1)) + return re_string_fetch_byte (pstr); + +#ifdef RE_ENABLE_I18N + if (pstr->offsets_needed) + { + Idx off; + int ch; + + /* For tr_TR.UTF-8 [[:islower:]] there is + [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip + in that case the whole multi-byte character and return + the original letter. On the other side, with + [[: DOTLESS SMALL LETTER I return [[:I, as doing + anything else would complicate things too much. */ + + if (!re_string_first_byte (pstr, pstr->cur_idx)) + return re_string_fetch_byte (pstr); + + off = pstr->offsets[pstr->cur_idx]; + ch = pstr->raw_mbs[pstr->raw_mbs_idx + off]; + + if (! isascii (ch)) + return re_string_fetch_byte (pstr); + + re_string_skip_bytes (pstr, + re_string_char_size_at (pstr, pstr->cur_idx)); + return ch; + } +#endif + + return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++]; +} + +static void +internal_function +re_string_destruct (re_string_t *pstr) +{ +#ifdef RE_ENABLE_I18N + re_free (pstr->wcs); + re_free (pstr->offsets); +#endif /* RE_ENABLE_I18N */ + if (pstr->mbs_allocated) + re_free (pstr->mbs); +} + +/* Return the context at IDX in INPUT. */ + +static unsigned int +internal_function +re_string_context_at (const re_string_t *input, Idx idx, int eflags) +{ + int c; + if (BE (! REG_VALID_INDEX (idx), 0)) + /* In this case, we use the value stored in input->tip_context, + since we can't know the character in input->mbs[-1] here. */ + return input->tip_context; + if (BE (idx == input->len, 0)) + return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF + : CONTEXT_NEWLINE | CONTEXT_ENDBUF); +#ifdef RE_ENABLE_I18N + if (input->mb_cur_max > 1) + { + wint_t wc; + Idx wc_idx = idx; + while(input->wcs[wc_idx] == WEOF) + { +#ifdef DEBUG + /* It must not happen. */ + assert (REG_VALID_INDEX (wc_idx)); +#endif + --wc_idx; + if (! REG_VALID_INDEX (wc_idx)) + return input->tip_context; + } + wc = input->wcs[wc_idx]; + if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc)) + return CONTEXT_WORD; + return (IS_WIDE_NEWLINE (wc) && input->newline_anchor + ? CONTEXT_NEWLINE : 0); + } + else +#endif + { + c = re_string_byte_at (input, idx); + if (bitset_contain (input->word_char, c)) + return CONTEXT_WORD; + return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0; + } +} + +/* Functions for set operation. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_node_set_alloc (re_node_set *set, Idx size) +{ + set->alloc = size; + set->nelem = 0; + set->elems = re_malloc (Idx, size); + if (BE (set->elems == NULL, 0)) + return REG_ESPACE; + return REG_NOERROR; +} + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_node_set_init_1 (re_node_set *set, Idx elem) +{ + set->alloc = 1; + set->nelem = 1; + set->elems = re_malloc (Idx, 1); + if (BE (set->elems == NULL, 0)) + { + set->alloc = set->nelem = 0; + return REG_ESPACE; + } + set->elems[0] = elem; + return REG_NOERROR; +} + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_node_set_init_2 (re_node_set *set, Idx elem1, Idx elem2) +{ + set->alloc = 2; + set->elems = re_malloc (Idx, 2); + if (BE (set->elems == NULL, 0)) + return REG_ESPACE; + if (elem1 == elem2) + { + set->nelem = 1; + set->elems[0] = elem1; + } + else + { + set->nelem = 2; + if (elem1 < elem2) + { + set->elems[0] = elem1; + set->elems[1] = elem2; + } + else + { + set->elems[0] = elem2; + set->elems[1] = elem1; + } + } + return REG_NOERROR; +} + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_node_set_init_copy (re_node_set *dest, const re_node_set *src) +{ + dest->nelem = src->nelem; + if (src->nelem > 0) + { + dest->alloc = dest->nelem; + dest->elems = re_malloc (Idx, dest->alloc); + if (BE (dest->elems == NULL, 0)) + { + dest->alloc = dest->nelem = 0; + return REG_ESPACE; + } + memcpy (dest->elems, src->elems, src->nelem * sizeof (Idx)); + } + else + re_node_set_init_empty (dest); + return REG_NOERROR; +} + +/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to + DEST. Return value indicate the error code or REG_NOERROR if succeeded. + Note: We assume dest->elems is NULL, when dest->alloc is 0. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1, + const re_node_set *src2) +{ + Idx i1, i2, is, id, delta, sbase; + if (src1->nelem == 0 || src2->nelem == 0) + return REG_NOERROR; + + /* We need dest->nelem + 2 * elems_in_intersection; this is a + conservative estimate. */ + if (src1->nelem + src2->nelem + dest->nelem > dest->alloc) + { + Idx new_alloc = src1->nelem + src2->nelem + dest->alloc; + Idx *new_elems = re_realloc (dest->elems, Idx, new_alloc); + if (BE (new_elems == NULL, 0)) + return REG_ESPACE; + dest->elems = new_elems; + dest->alloc = new_alloc; + } + + /* Find the items in the intersection of SRC1 and SRC2, and copy + into the top of DEST those that are not already in DEST itself. */ + sbase = dest->nelem + src1->nelem + src2->nelem; + i1 = src1->nelem - 1; + i2 = src2->nelem - 1; + id = dest->nelem - 1; + for (;;) + { + if (src1->elems[i1] == src2->elems[i2]) + { + /* Try to find the item in DEST. Maybe we could binary search? */ + while (REG_VALID_INDEX (id) && dest->elems[id] > src1->elems[i1]) + --id; + + if (! REG_VALID_INDEX (id) || dest->elems[id] != src1->elems[i1]) + dest->elems[--sbase] = src1->elems[i1]; + + if (! REG_VALID_INDEX (--i1) || ! REG_VALID_INDEX (--i2)) + break; + } + + /* Lower the highest of the two items. */ + else if (src1->elems[i1] < src2->elems[i2]) + { + if (! REG_VALID_INDEX (--i2)) + break; + } + else + { + if (! REG_VALID_INDEX (--i1)) + break; + } + } + + id = dest->nelem - 1; + is = dest->nelem + src1->nelem + src2->nelem - 1; + delta = is - sbase + 1; + + /* Now copy. When DELTA becomes zero, the remaining + DEST elements are already in place; this is more or + less the same loop that is in re_node_set_merge. */ + dest->nelem += delta; + if (delta > 0 && REG_VALID_INDEX (id)) + for (;;) + { + if (dest->elems[is] > dest->elems[id]) + { + /* Copy from the top. */ + dest->elems[id + delta--] = dest->elems[is--]; + if (delta == 0) + break; + } + else + { + /* Slide from the bottom. */ + dest->elems[id + delta] = dest->elems[id]; + if (! REG_VALID_INDEX (--id)) + break; + } + } + + /* Copy remaining SRC elements. */ + memcpy (dest->elems, dest->elems + sbase, delta * sizeof (Idx)); + + return REG_NOERROR; +} + +/* Calculate the union set of the sets SRC1 and SRC2. And store it to + DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_node_set_init_union (re_node_set *dest, const re_node_set *src1, + const re_node_set *src2) +{ + Idx i1, i2, id; + if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) + { + dest->alloc = src1->nelem + src2->nelem; + dest->elems = re_malloc (Idx, dest->alloc); + if (BE (dest->elems == NULL, 0)) + return REG_ESPACE; + } + else + { + if (src1 != NULL && src1->nelem > 0) + return re_node_set_init_copy (dest, src1); + else if (src2 != NULL && src2->nelem > 0) + return re_node_set_init_copy (dest, src2); + else + re_node_set_init_empty (dest); + return REG_NOERROR; + } + for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;) + { + if (src1->elems[i1] > src2->elems[i2]) + { + dest->elems[id++] = src2->elems[i2++]; + continue; + } + if (src1->elems[i1] == src2->elems[i2]) + ++i2; + dest->elems[id++] = src1->elems[i1++]; + } + if (i1 < src1->nelem) + { + memcpy (dest->elems + id, src1->elems + i1, + (src1->nelem - i1) * sizeof (Idx)); + id += src1->nelem - i1; + } + else if (i2 < src2->nelem) + { + memcpy (dest->elems + id, src2->elems + i2, + (src2->nelem - i2) * sizeof (Idx)); + id += src2->nelem - i2; + } + dest->nelem = id; + return REG_NOERROR; +} + +/* Calculate the union set of the sets DEST and SRC. And store it to + DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_node_set_merge (re_node_set *dest, const re_node_set *src) +{ + Idx is, id, sbase, delta; + if (src == NULL || src->nelem == 0) + return REG_NOERROR; + if (dest->alloc < 2 * src->nelem + dest->nelem) + { + Idx new_alloc = 2 * (src->nelem + dest->alloc); + Idx *new_buffer = re_realloc (dest->elems, Idx, new_alloc); + if (BE (new_buffer == NULL, 0)) + return REG_ESPACE; + dest->elems = new_buffer; + dest->alloc = new_alloc; + } + + if (BE (dest->nelem == 0, 0)) + { + dest->nelem = src->nelem; + memcpy (dest->elems, src->elems, src->nelem * sizeof (Idx)); + return REG_NOERROR; + } + + /* Copy into the top of DEST the items of SRC that are not + found in DEST. Maybe we could binary search in DEST? */ + for (sbase = dest->nelem + 2 * src->nelem, + is = src->nelem - 1, id = dest->nelem - 1; + REG_VALID_INDEX (is) && REG_VALID_INDEX (id); ) + { + if (dest->elems[id] == src->elems[is]) + is--, id--; + else if (dest->elems[id] < src->elems[is]) + dest->elems[--sbase] = src->elems[is--]; + else /* if (dest->elems[id] > src->elems[is]) */ + --id; + } + + if (REG_VALID_INDEX (is)) + { + /* If DEST is exhausted, the remaining items of SRC must be unique. */ + sbase -= is + 1; + memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (Idx)); + } + + id = dest->nelem - 1; + is = dest->nelem + 2 * src->nelem - 1; + delta = is - sbase + 1; + if (delta == 0) + return REG_NOERROR; + + /* Now copy. When DELTA becomes zero, the remaining + DEST elements are already in place. */ + dest->nelem += delta; + for (;;) + { + if (dest->elems[is] > dest->elems[id]) + { + /* Copy from the top. */ + dest->elems[id + delta--] = dest->elems[is--]; + if (delta == 0) + break; + } + else + { + /* Slide from the bottom. */ + dest->elems[id + delta] = dest->elems[id]; + if (! REG_VALID_INDEX (--id)) + { + /* Copy remaining SRC elements. */ + memcpy (dest->elems, dest->elems + sbase, + delta * sizeof (Idx)); + break; + } + } + } + + return REG_NOERROR; +} + +/* Insert the new element ELEM to the re_node_set* SET. + SET should not already have ELEM. + Return true if successful. */ + +static bool +internal_function __attribute_warn_unused_result__ +re_node_set_insert (re_node_set *set, Idx elem) +{ + Idx idx; + /* In case the set is empty. */ + if (set->alloc == 0) + return BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1); + + if (BE (set->nelem, 0) == 0) + { + /* We already guaranteed above that set->alloc != 0. */ + set->elems[0] = elem; + ++set->nelem; + return true; + } + + /* Realloc if we need. */ + if (set->alloc == set->nelem) + { + Idx *new_elems; + set->alloc = set->alloc * 2; + new_elems = re_realloc (set->elems, Idx, set->alloc); + if (BE (new_elems == NULL, 0)) + return false; + set->elems = new_elems; + } + + /* Move the elements which follows the new element. Test the + first element separately to skip a check in the inner loop. */ + if (elem < set->elems[0]) + { + idx = 0; + for (idx = set->nelem; idx > 0; idx--) + set->elems[idx] = set->elems[idx - 1]; + } + else + { + for (idx = set->nelem; set->elems[idx - 1] > elem; idx--) + set->elems[idx] = set->elems[idx - 1]; + } + + /* Insert the new element. */ + set->elems[idx] = elem; + ++set->nelem; + return true; +} + +/* Insert the new element ELEM to the re_node_set* SET. + SET should not already have any element greater than or equal to ELEM. + Return true if successful. */ + +static bool +internal_function __attribute_warn_unused_result__ +re_node_set_insert_last (re_node_set *set, Idx elem) +{ + /* Realloc if we need. */ + if (set->alloc == set->nelem) + { + Idx *new_elems; + set->alloc = (set->alloc + 1) * 2; + new_elems = re_realloc (set->elems, Idx, set->alloc); + if (BE (new_elems == NULL, 0)) + return false; + set->elems = new_elems; + } + + /* Insert the new element. */ + set->elems[set->nelem++] = elem; + return true; +} + +/* Compare two node sets SET1 and SET2. + Return true if SET1 and SET2 are equivalent. */ + +static bool +internal_function __attribute ((pure)) +re_node_set_compare (const re_node_set *set1, const re_node_set *set2) +{ + Idx i; + if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem) + return false; + for (i = set1->nelem ; REG_VALID_INDEX (--i) ; ) + if (set1->elems[i] != set2->elems[i]) + return false; + return true; +} + +/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */ + +static Idx +internal_function __attribute ((pure)) +re_node_set_contains (const re_node_set *set, Idx elem) +{ + __re_size_t idx, right, mid; + if (! REG_VALID_NONZERO_INDEX (set->nelem)) + return 0; + + /* Binary search the element. */ + idx = 0; + right = set->nelem - 1; + while (idx < right) + { + mid = (idx + right) / 2; + if (set->elems[mid] < elem) + idx = mid + 1; + else + right = mid; + } + return set->elems[idx] == elem ? idx + 1 : 0; +} + +static void +internal_function +re_node_set_remove_at (re_node_set *set, Idx idx) +{ + if (idx < 0 || idx >= set->nelem) + return; + --set->nelem; + for (; idx < set->nelem; idx++) + set->elems[idx] = set->elems[idx + 1]; +} + + +/* Add the token TOKEN to dfa->nodes, and return the index of the token. + Or return REG_MISSING if an error occurred. */ + +static Idx +internal_function +re_dfa_add_node (re_dfa_t *dfa, re_token_t token) +{ + if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0)) + { + size_t new_nodes_alloc = dfa->nodes_alloc * 2; + Idx *new_nexts, *new_indices; + re_node_set *new_edests, *new_eclosures; + re_token_t *new_nodes; + size_t max_object_size = + MAX (sizeof (re_token_t), + MAX (sizeof (re_node_set), + sizeof (Idx))); + + /* Avoid overflows. */ + if (BE (SIZE_MAX / 2 / max_object_size < dfa->nodes_alloc, 0)) + return REG_MISSING; + + new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc); + if (BE (new_nodes == NULL, 0)) + return REG_MISSING; + dfa->nodes = new_nodes; + new_nexts = re_realloc (dfa->nexts, Idx, new_nodes_alloc); + new_indices = re_realloc (dfa->org_indices, Idx, new_nodes_alloc); + new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc); + new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc); + if (BE (new_nexts == NULL || new_indices == NULL + || new_edests == NULL || new_eclosures == NULL, 0)) + return REG_MISSING; + dfa->nexts = new_nexts; + dfa->org_indices = new_indices; + dfa->edests = new_edests; + dfa->eclosures = new_eclosures; + dfa->nodes_alloc = new_nodes_alloc; + } + dfa->nodes[dfa->nodes_len] = token; + dfa->nodes[dfa->nodes_len].constraint = 0; +#ifdef RE_ENABLE_I18N + { + int type = token.type; + dfa->nodes[dfa->nodes_len].accept_mb = + (type == OP_PERIOD && dfa->mb_cur_max > 1) || type == COMPLEX_BRACKET; + } +#endif + dfa->nexts[dfa->nodes_len] = REG_MISSING; + re_node_set_init_empty (dfa->edests + dfa->nodes_len); + re_node_set_init_empty (dfa->eclosures + dfa->nodes_len); + return dfa->nodes_len++; +} + +static inline re_hashval_t +internal_function +calc_state_hash (const re_node_set *nodes, unsigned int context) +{ + re_hashval_t hash = nodes->nelem + context; + Idx i; + for (i = 0 ; i < nodes->nelem ; i++) + hash += nodes->elems[i]; + return hash; +} + +/* Search for the state whose node_set is equivalent to NODES. + Return the pointer to the state, if we found it in the DFA. + Otherwise create the new one and return it. In case of an error + return NULL and set the error code in ERR. + Note: - We assume NULL as the invalid state, then it is possible that + return value is NULL and ERR is REG_NOERROR. + - We never return non-NULL value in case of any errors, it is for + optimization. */ + +static re_dfastate_t * +internal_function __attribute_warn_unused_result__ +re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa, + const re_node_set *nodes) +{ + re_hashval_t hash; + re_dfastate_t *new_state; + struct re_state_table_entry *spot; + Idx i; +#ifdef lint + /* Suppress bogus uninitialized-variable warnings. */ + *err = REG_NOERROR; +#endif + if (BE (nodes->nelem == 0, 0)) + { + *err = REG_NOERROR; + return NULL; + } + hash = calc_state_hash (nodes, 0); + spot = dfa->state_table + (hash & dfa->state_hash_mask); + + for (i = 0 ; i < spot->num ; i++) + { + re_dfastate_t *state = spot->array[i]; + if (hash != state->hash) + continue; + if (re_node_set_compare (&state->nodes, nodes)) + return state; + } + + /* There are no appropriate state in the dfa, create the new one. */ + new_state = create_ci_newstate (dfa, nodes, hash); + if (BE (new_state == NULL, 0)) + *err = REG_ESPACE; + + return new_state; +} + +/* Search for the state whose node_set is equivalent to NODES and + whose context is equivalent to CONTEXT. + Return the pointer to the state, if we found it in the DFA. + Otherwise create the new one and return it. In case of an error + return NULL and set the error code in ERR. + Note: - We assume NULL as the invalid state, then it is possible that + return value is NULL and ERR is REG_NOERROR. + - We never return non-NULL value in case of any errors, it is for + optimization. */ + +static re_dfastate_t * +internal_function __attribute_warn_unused_result__ +re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa, + const re_node_set *nodes, unsigned int context) +{ + re_hashval_t hash; + re_dfastate_t *new_state; + struct re_state_table_entry *spot; + Idx i; +#ifdef lint + /* Suppress bogus uninitialized-variable warnings. */ + *err = REG_NOERROR; +#endif + if (nodes->nelem == 0) + { + *err = REG_NOERROR; + return NULL; + } + hash = calc_state_hash (nodes, context); + spot = dfa->state_table + (hash & dfa->state_hash_mask); + + for (i = 0 ; i < spot->num ; i++) + { + re_dfastate_t *state = spot->array[i]; + if (state->hash == hash + && state->context == context + && re_node_set_compare (state->entrance_nodes, nodes)) + return state; + } + /* There are no appropriate state in `dfa', create the new one. */ + new_state = create_cd_newstate (dfa, nodes, context, hash); + if (BE (new_state == NULL, 0)) + *err = REG_ESPACE; + + return new_state; +} + +/* Finish initialization of the new state NEWSTATE, and using its hash value + HASH put in the appropriate bucket of DFA's state table. Return value + indicates the error code if failed. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +register_state (const re_dfa_t *dfa, re_dfastate_t *newstate, + re_hashval_t hash) +{ + struct re_state_table_entry *spot; + reg_errcode_t err; + Idx i; + + newstate->hash = hash; + err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem); + if (BE (err != REG_NOERROR, 0)) + return REG_ESPACE; + for (i = 0; i < newstate->nodes.nelem; i++) + { + Idx elem = newstate->nodes.elems[i]; + if (!IS_EPSILON_NODE (dfa->nodes[elem].type)) + if (BE (! re_node_set_insert_last (&newstate->non_eps_nodes, elem), 0)) + return REG_ESPACE; + } + + spot = dfa->state_table + (hash & dfa->state_hash_mask); + if (BE (spot->alloc <= spot->num, 0)) + { + Idx new_alloc = 2 * spot->num + 2; + re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *, + new_alloc); + if (BE (new_array == NULL, 0)) + return REG_ESPACE; + spot->array = new_array; + spot->alloc = new_alloc; + } + spot->array[spot->num++] = newstate; + return REG_NOERROR; +} + +static void +free_state (re_dfastate_t *state) +{ + re_node_set_free (&state->non_eps_nodes); + re_node_set_free (&state->inveclosure); + if (state->entrance_nodes != &state->nodes) + { + re_node_set_free (state->entrance_nodes); + re_free (state->entrance_nodes); + } + re_node_set_free (&state->nodes); + re_free (state->word_trtable); + re_free (state->trtable); + re_free (state); +} + +/* Create the new state which is independ of contexts. + Return the new state if succeeded, otherwise return NULL. */ + +static re_dfastate_t * +internal_function __attribute_warn_unused_result__ +create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes, + re_hashval_t hash) +{ + Idx i; + reg_errcode_t err; + re_dfastate_t *newstate; + + newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); + if (BE (newstate == NULL, 0)) + return NULL; + err = re_node_set_init_copy (&newstate->nodes, nodes); + if (BE (err != REG_NOERROR, 0)) + { + re_free (newstate); + return NULL; + } + + newstate->entrance_nodes = &newstate->nodes; + for (i = 0 ; i < nodes->nelem ; i++) + { + re_token_t *node = dfa->nodes + nodes->elems[i]; + re_token_type_t type = node->type; + if (type == CHARACTER && !node->constraint) + continue; +#ifdef RE_ENABLE_I18N + newstate->accept_mb |= node->accept_mb; +#endif /* RE_ENABLE_I18N */ + + /* If the state has the halt node, the state is a halt state. */ + if (type == END_OF_RE) + newstate->halt = 1; + else if (type == OP_BACK_REF) + newstate->has_backref = 1; + else if (type == ANCHOR || node->constraint) + newstate->has_constraint = 1; + } + err = register_state (dfa, newstate, hash); + if (BE (err != REG_NOERROR, 0)) + { + free_state (newstate); + newstate = NULL; + } + return newstate; +} + +/* Create the new state which is depend on the context CONTEXT. + Return the new state if succeeded, otherwise return NULL. */ + +static re_dfastate_t * +internal_function __attribute_warn_unused_result__ +create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes, + unsigned int context, re_hashval_t hash) +{ + Idx i, nctx_nodes = 0; + reg_errcode_t err; + re_dfastate_t *newstate; + + newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); + if (BE (newstate == NULL, 0)) + return NULL; + err = re_node_set_init_copy (&newstate->nodes, nodes); + if (BE (err != REG_NOERROR, 0)) + { + re_free (newstate); + return NULL; + } + + newstate->context = context; + newstate->entrance_nodes = &newstate->nodes; + + for (i = 0 ; i < nodes->nelem ; i++) + { + re_token_t *node = dfa->nodes + nodes->elems[i]; + re_token_type_t type = node->type; + unsigned int constraint = node->constraint; + + if (type == CHARACTER && !constraint) + continue; +#ifdef RE_ENABLE_I18N + newstate->accept_mb |= node->accept_mb; +#endif /* RE_ENABLE_I18N */ + + /* If the state has the halt node, the state is a halt state. */ + if (type == END_OF_RE) + newstate->halt = 1; + else if (type == OP_BACK_REF) + newstate->has_backref = 1; + + if (constraint) + { + if (newstate->entrance_nodes == &newstate->nodes) + { + newstate->entrance_nodes = re_malloc (re_node_set, 1); + if (BE (newstate->entrance_nodes == NULL, 0)) + { + free_state (newstate); + return NULL; + } + if (re_node_set_init_copy (newstate->entrance_nodes, nodes) + != REG_NOERROR) + return NULL; + nctx_nodes = 0; + newstate->has_constraint = 1; + } + + if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context)) + { + re_node_set_remove_at (&newstate->nodes, i - nctx_nodes); + ++nctx_nodes; + } + } + } + err = register_state (dfa, newstate, hash); + if (BE (err != REG_NOERROR, 0)) + { + free_state (newstate); + newstate = NULL; + } + return newstate; +} diff --git a/gnulib/regex_internal.h b/gnulib/regex_internal.h new file mode 100644 index 000000000..e1b4c61b3 --- /dev/null +++ b/gnulib/regex_internal.h @@ -0,0 +1,871 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free + Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + This program 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 2, or (at your option) + any later version. + + This program 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 this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _REGEX_INTERNAL_H +#define _REGEX_INTERNAL_H 1 + +#include +#include +#include +#include +#include +#include + +#include +#ifndef _LIBC +# include "localcharset.h" +#endif +#if defined HAVE_LOCALE_H || defined _LIBC +# include +#endif + +#include +#include +#include +#if defined _LIBC +# include +#else +# define __libc_lock_init(NAME) do { } while (0) +# define __libc_lock_lock(NAME) do { } while (0) +# define __libc_lock_unlock(NAME) do { } while (0) +#endif + +/* In case that the system doesn't have isblank(). */ +#if !defined _LIBC && ! (defined isblank || (HAVE_ISBLANK && HAVE_DECL_ISBLANK)) +# define isblank(ch) ((ch) == ' ' || (ch) == '\t') +#endif + +#ifdef _LIBC +# ifndef _RE_DEFINE_LOCALE_FUNCTIONS +# define _RE_DEFINE_LOCALE_FUNCTIONS 1 +# include +# include +# include +# endif +#endif + +/* This is for other GNU distributions with internationalized messages. */ +#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# ifdef _LIBC +# undef gettext +# define gettext(msgid) \ + INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES) +# endif +#else +# define gettext(msgid) (msgid) +#endif + +#ifndef gettext_noop +/* This define is so xgettext can find the internationalizable + strings. */ +# define gettext_noop(String) String +#endif + +/* For loser systems without the definition. */ +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +#if (defined MB_CUR_MAX && HAVE_LOCALE_H && HAVE_WCTYPE_H && HAVE_ISWCTYPE && HAVE_WCSCOLL) || _LIBC +# define RE_ENABLE_I18N +#endif + +#if __GNUC__ >= 3 +# define BE(expr, val) __builtin_expect (expr, val) +#else +# define BE(expr, val) (expr) +# ifdef _LIBC +# define inline +# endif +#endif + +/* Number of ASCII characters. */ +#define ASCII_CHARS 0x80 + +/* Number of single byte characters. */ +#define SBC_MAX (UCHAR_MAX + 1) + +#define COLL_ELEM_LEN_MAX 8 + +/* The character which represents newline. */ +#define NEWLINE_CHAR '\n' +#define WIDE_NEWLINE_CHAR L'\n' + +/* Rename to standard API for using out of glibc. */ +#ifndef _LIBC +# define __wctype wctype +# define __iswctype iswctype +# define __btowc btowc +# define __wcrtomb wcrtomb +# define __mbrtowc mbrtowc +# define __regfree regfree +# define attribute_hidden +#endif /* not _LIBC */ + +#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +# define __attribute(arg) __attribute__ (arg) +#else +# define __attribute(arg) +#endif + +typedef __re_idx_t Idx; + +/* Special return value for failure to match. */ +#define REG_MISSING ((Idx) -1) + +/* Special return value for internal error. */ +#define REG_ERROR ((Idx) -2) + +/* Test whether N is a valid index, and is not one of the above. */ +#ifdef _REGEX_LARGE_OFFSETS +# define REG_VALID_INDEX(n) ((Idx) (n) < REG_ERROR) +#else +# define REG_VALID_INDEX(n) (0 <= (n)) +#endif + +/* Test whether N is a valid nonzero index. */ +#ifdef _REGEX_LARGE_OFFSETS +# define REG_VALID_NONZERO_INDEX(n) ((Idx) ((n) - 1) < (Idx) (REG_ERROR - 1)) +#else +# define REG_VALID_NONZERO_INDEX(n) (0 < (n)) +#endif + +/* A hash value, suitable for computing hash tables. */ +typedef __re_size_t re_hashval_t; + +/* An integer used to represent a set of bits. It must be unsigned, + and must be at least as wide as unsigned int. */ +typedef unsigned long int bitset_word_t; +/* All bits set in a bitset_word_t. */ +#define BITSET_WORD_MAX ULONG_MAX + +/* Number of bits in a bitset_word_t. For portability to hosts with + padding bits, do not use '(sizeof (bitset_word_t) * CHAR_BIT)'; + instead, deduce it directly from BITSET_WORD_MAX. Avoid + greater-than-32-bit integers and unconditional shifts by more than + 31 bits, as they're not portable. */ +#if BITSET_WORD_MAX == 0xffffffffUL +# define BITSET_WORD_BITS 32 +#elif BITSET_WORD_MAX >> 31 >> 4 == 1 +# define BITSET_WORD_BITS 36 +#elif BITSET_WORD_MAX >> 31 >> 16 == 1 +# define BITSET_WORD_BITS 48 +#elif BITSET_WORD_MAX >> 31 >> 28 == 1 +# define BITSET_WORD_BITS 60 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 1 == 1 +# define BITSET_WORD_BITS 64 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 9 == 1 +# define BITSET_WORD_BITS 72 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 3 == 1 +# define BITSET_WORD_BITS 128 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 == 1 +# define BITSET_WORD_BITS 256 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 > 1 +# define BITSET_WORD_BITS 257 /* any value > SBC_MAX will do here */ +# if BITSET_WORD_BITS <= SBC_MAX +# error "Invalid SBC_MAX" +# endif +#else +# error "Add case for new bitset_word_t size" +#endif + +/* Number of bitset_word_t values in a bitset_t. */ +#define BITSET_WORDS ((SBC_MAX + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS) + +typedef bitset_word_t bitset_t[BITSET_WORDS]; +typedef bitset_word_t *re_bitset_ptr_t; +typedef const bitset_word_t *re_const_bitset_ptr_t; + +#define PREV_WORD_CONSTRAINT 0x0001 +#define PREV_NOTWORD_CONSTRAINT 0x0002 +#define NEXT_WORD_CONSTRAINT 0x0004 +#define NEXT_NOTWORD_CONSTRAINT 0x0008 +#define PREV_NEWLINE_CONSTRAINT 0x0010 +#define NEXT_NEWLINE_CONSTRAINT 0x0020 +#define PREV_BEGBUF_CONSTRAINT 0x0040 +#define NEXT_ENDBUF_CONSTRAINT 0x0080 +#define WORD_DELIM_CONSTRAINT 0x0100 +#define NOT_WORD_DELIM_CONSTRAINT 0x0200 + +typedef enum +{ + INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, + WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, + WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, + INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, + LINE_FIRST = PREV_NEWLINE_CONSTRAINT, + LINE_LAST = NEXT_NEWLINE_CONSTRAINT, + BUF_FIRST = PREV_BEGBUF_CONSTRAINT, + BUF_LAST = NEXT_ENDBUF_CONSTRAINT, + WORD_DELIM = WORD_DELIM_CONSTRAINT, + NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT +} re_context_type; + +typedef struct +{ + Idx alloc; + Idx nelem; + Idx *elems; +} re_node_set; + +typedef enum +{ + NON_TYPE = 0, + + /* Node type, These are used by token, node, tree. */ + CHARACTER = 1, + END_OF_RE = 2, + SIMPLE_BRACKET = 3, + OP_BACK_REF = 4, + OP_PERIOD = 5, +#ifdef RE_ENABLE_I18N + COMPLEX_BRACKET = 6, + OP_UTF8_PERIOD = 7, +#endif /* RE_ENABLE_I18N */ + + /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used + when the debugger shows values of this enum type. */ +#define EPSILON_BIT 8 + OP_OPEN_SUBEXP = EPSILON_BIT | 0, + OP_CLOSE_SUBEXP = EPSILON_BIT | 1, + OP_ALT = EPSILON_BIT | 2, + OP_DUP_ASTERISK = EPSILON_BIT | 3, + ANCHOR = EPSILON_BIT | 4, + + /* Tree type, these are used only by tree. */ + CONCAT = 16, + SUBEXP = 17, + + /* Token type, these are used only by token. */ + OP_DUP_PLUS = 18, + OP_DUP_QUESTION, + OP_OPEN_BRACKET, + OP_CLOSE_BRACKET, + OP_CHARSET_RANGE, + OP_OPEN_DUP_NUM, + OP_CLOSE_DUP_NUM, + OP_NON_MATCH_LIST, + OP_OPEN_COLL_ELEM, + OP_CLOSE_COLL_ELEM, + OP_OPEN_EQUIV_CLASS, + OP_CLOSE_EQUIV_CLASS, + OP_OPEN_CHAR_CLASS, + OP_CLOSE_CHAR_CLASS, + OP_WORD, + OP_NOTWORD, + OP_SPACE, + OP_NOTSPACE, + BACK_SLASH + +} re_token_type_t; + +#ifdef RE_ENABLE_I18N +typedef struct +{ + /* Multibyte characters. */ + wchar_t *mbchars; + + /* Collating symbols. */ +# ifdef _LIBC + int32_t *coll_syms; +# endif + + /* Equivalence classes. */ +# ifdef _LIBC + int32_t *equiv_classes; +# endif + + /* Range expressions. */ +# ifdef _LIBC + uint32_t *range_starts; + uint32_t *range_ends; +# else /* not _LIBC */ + wchar_t *range_starts; + wchar_t *range_ends; +# endif /* not _LIBC */ + + /* Character classes. */ + wctype_t *char_classes; + + /* If this character set is the non-matching list. */ + unsigned int non_match : 1; + + /* # of multibyte characters. */ + Idx nmbchars; + + /* # of collating symbols. */ + Idx ncoll_syms; + + /* # of equivalence classes. */ + Idx nequiv_classes; + + /* # of range expressions. */ + Idx nranges; + + /* # of character classes. */ + Idx nchar_classes; +} re_charset_t; +#endif /* RE_ENABLE_I18N */ + +typedef struct +{ + union + { + unsigned char c; /* for CHARACTER */ + re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */ +#ifdef RE_ENABLE_I18N + re_charset_t *mbcset; /* for COMPLEX_BRACKET */ +#endif /* RE_ENABLE_I18N */ + Idx idx; /* for BACK_REF */ + re_context_type ctx_type; /* for ANCHOR */ + } opr; +#if __GNUC__ >= 2 && !__STRICT_ANSI__ + re_token_type_t type : 8; +#else + re_token_type_t type; +#endif + unsigned int constraint : 10; /* context constraint */ + unsigned int duplicated : 1; + unsigned int opt_subexp : 1; +#ifdef RE_ENABLE_I18N + unsigned int accept_mb : 1; + /* These 2 bits can be moved into the union if needed (e.g. if running out + of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */ + unsigned int mb_partial : 1; +#endif + unsigned int word_char : 1; +} re_token_t; + +#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT) + +struct re_string_t +{ + /* Indicate the raw buffer which is the original string passed as an + argument of regexec(), re_search(), etc.. */ + const unsigned char *raw_mbs; + /* Store the multibyte string. In case of "case insensitive mode" like + REG_ICASE, upper cases of the string are stored, otherwise MBS points + the same address that RAW_MBS points. */ + unsigned char *mbs; +#ifdef RE_ENABLE_I18N + /* Store the wide character string which is corresponding to MBS. */ + wint_t *wcs; + Idx *offsets; + mbstate_t cur_state; +#endif + /* Index in RAW_MBS. Each character mbs[i] corresponds to + raw_mbs[raw_mbs_idx + i]. */ + Idx raw_mbs_idx; + /* The length of the valid characters in the buffers. */ + Idx valid_len; + /* The corresponding number of bytes in raw_mbs array. */ + Idx valid_raw_len; + /* The length of the buffers MBS and WCS. */ + Idx bufs_len; + /* The index in MBS, which is updated by re_string_fetch_byte. */ + Idx cur_idx; + /* length of RAW_MBS array. */ + Idx raw_len; + /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */ + Idx len; + /* End of the buffer may be shorter than its length in the cases such + as re_match_2, re_search_2. Then, we use STOP for end of the buffer + instead of LEN. */ + Idx raw_stop; + /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */ + Idx stop; + + /* The context of mbs[0]. We store the context independently, since + the context of mbs[0] may be different from raw_mbs[0], which is + the beginning of the input string. */ + unsigned int tip_context; + /* The translation passed as a part of an argument of re_compile_pattern. */ + RE_TRANSLATE_TYPE trans; + /* Copy of re_dfa_t's word_char. */ + re_const_bitset_ptr_t word_char; + /* true if REG_ICASE. */ + unsigned char icase; + unsigned char is_utf8; + unsigned char map_notascii; + unsigned char mbs_allocated; + unsigned char offsets_needed; + unsigned char newline_anchor; + unsigned char word_ops_used; + int mb_cur_max; +}; +typedef struct re_string_t re_string_t; + + +struct re_dfa_t; +typedef struct re_dfa_t re_dfa_t; + +#ifndef _LIBC +# if defined __i386__ && !defined __EMX__ +# define internal_function __attribute ((regparm (3), stdcall)) +# else +# define internal_function +# endif +#endif + +static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr, + Idx new_buf_len) + internal_function; +#ifdef RE_ENABLE_I18N +static void build_wcs_buffer (re_string_t *pstr) internal_function; +static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr) + internal_function; +#endif /* RE_ENABLE_I18N */ +static void build_upper_buffer (re_string_t *pstr) internal_function; +static void re_string_translate_buffer (re_string_t *pstr) internal_function; +static unsigned int re_string_context_at (const re_string_t *input, Idx idx, + int eflags) + internal_function __attribute ((pure)); +#define re_string_peek_byte(pstr, offset) \ + ((pstr)->mbs[(pstr)->cur_idx + offset]) +#define re_string_fetch_byte(pstr) \ + ((pstr)->mbs[(pstr)->cur_idx++]) +#define re_string_first_byte(pstr, idx) \ + ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF) +#define re_string_is_single_byte_char(pstr, idx) \ + ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \ + || (pstr)->wcs[(idx) + 1] != WEOF)) +#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx) +#define re_string_cur_idx(pstr) ((pstr)->cur_idx) +#define re_string_get_buffer(pstr) ((pstr)->mbs) +#define re_string_length(pstr) ((pstr)->len) +#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx]) +#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) +#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) + +#include + +#ifndef _LIBC +# if HAVE_ALLOCA +/* The OS usually guarantees only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + allocate anything larger than 4096 bytes. Also care for the possibility + of a few compiler-allocated temporary stack slots. */ +# define __libc_use_alloca(n) ((n) < 4032) +# else +/* alloca is implemented with malloc, so just use malloc. */ +# define __libc_use_alloca(n) 0 +# endif +#endif + +#ifndef MAX +# define MAX(a,b) ((a) < (b) ? (b) : (a)) +#endif + +#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) +#define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t))) +#define re_free(p) free (p) + +struct bin_tree_t +{ + struct bin_tree_t *parent; + struct bin_tree_t *left; + struct bin_tree_t *right; + struct bin_tree_t *first; + struct bin_tree_t *next; + + re_token_t token; + + /* `node_idx' is the index in dfa->nodes, if `type' == 0. + Otherwise `type' indicate the type of this node. */ + Idx node_idx; +}; +typedef struct bin_tree_t bin_tree_t; + +#define BIN_TREE_STORAGE_SIZE \ + ((1024 - sizeof (void *)) / sizeof (bin_tree_t)) + +struct bin_tree_storage_t +{ + struct bin_tree_storage_t *next; + bin_tree_t data[BIN_TREE_STORAGE_SIZE]; +}; +typedef struct bin_tree_storage_t bin_tree_storage_t; + +#define CONTEXT_WORD 1 +#define CONTEXT_NEWLINE (CONTEXT_WORD << 1) +#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1) +#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1) + +#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD) +#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE) +#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF) +#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF) +#define IS_ORDINARY_CONTEXT(c) ((c) == 0) + +#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_') +#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR) +#define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_') +#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR) + +#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \ + ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ + || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ + || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\ + || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context))) + +#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \ + ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ + || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ + || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \ + || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context))) + +struct re_dfastate_t +{ + re_hashval_t hash; + re_node_set nodes; + re_node_set non_eps_nodes; + re_node_set inveclosure; + re_node_set *entrance_nodes; + struct re_dfastate_t **trtable, **word_trtable; + unsigned int context : 4; + unsigned int halt : 1; + /* If this state can accept `multi byte'. + Note that we refer to multibyte characters, and multi character + collating elements as `multi byte'. */ + unsigned int accept_mb : 1; + /* If this state has backreference node(s). */ + unsigned int has_backref : 1; + unsigned int has_constraint : 1; +}; +typedef struct re_dfastate_t re_dfastate_t; + +struct re_state_table_entry +{ + Idx num; + Idx alloc; + re_dfastate_t **array; +}; + +/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */ + +typedef struct +{ + Idx next_idx; + Idx alloc; + re_dfastate_t **array; +} state_array_t; + +/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */ + +typedef struct +{ + Idx node; + Idx str_idx; /* The position NODE match at. */ + state_array_t path; +} re_sub_match_last_t; + +/* Store information about the node NODE whose type is OP_OPEN_SUBEXP. + And information about the node, whose type is OP_CLOSE_SUBEXP, + corresponding to NODE is stored in LASTS. */ + +typedef struct +{ + Idx str_idx; + Idx node; + state_array_t *path; + Idx alasts; /* Allocation size of LASTS. */ + Idx nlasts; /* The number of LASTS. */ + re_sub_match_last_t **lasts; +} re_sub_match_top_t; + +struct re_backref_cache_entry +{ + Idx node; + Idx str_idx; + Idx subexp_from; + Idx subexp_to; + char more; + char unused; + unsigned short int eps_reachable_subexps_map; +}; + +typedef struct +{ + /* The string object corresponding to the input string. */ + re_string_t input; +#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) + const re_dfa_t *const dfa; +#else + const re_dfa_t *dfa; +#endif + /* EFLAGS of the argument of regexec. */ + int eflags; + /* Where the matching ends. */ + Idx match_last; + Idx last_node; + /* The state log used by the matcher. */ + re_dfastate_t **state_log; + Idx state_log_top; + /* Back reference cache. */ + Idx nbkref_ents; + Idx abkref_ents; + struct re_backref_cache_entry *bkref_ents; + int max_mb_elem_len; + Idx nsub_tops; + Idx asub_tops; + re_sub_match_top_t **sub_tops; +} re_match_context_t; + +typedef struct +{ + re_dfastate_t **sifted_states; + re_dfastate_t **limited_states; + Idx last_node; + Idx last_str_idx; + re_node_set limits; +} re_sift_context_t; + +struct re_fail_stack_ent_t +{ + Idx idx; + Idx node; + regmatch_t *regs; + re_node_set eps_via_nodes; +}; + +struct re_fail_stack_t +{ + Idx num; + Idx alloc; + struct re_fail_stack_ent_t *stack; +}; + +struct re_dfa_t +{ + re_token_t *nodes; + size_t nodes_alloc; + size_t nodes_len; + Idx *nexts; + Idx *org_indices; + re_node_set *edests; + re_node_set *eclosures; + re_node_set *inveclosures; + struct re_state_table_entry *state_table; + re_dfastate_t *init_state; + re_dfastate_t *init_state_word; + re_dfastate_t *init_state_nl; + re_dfastate_t *init_state_begbuf; + bin_tree_t *str_tree; + bin_tree_storage_t *str_tree_storage; + re_bitset_ptr_t sb_char; + int str_tree_storage_idx; + + /* number of subexpressions `re_nsub' is in regex_t. */ + re_hashval_t state_hash_mask; + Idx init_node; + Idx nbackref; /* The number of backreference in this dfa. */ + + /* Bitmap expressing which backreference is used. */ + bitset_word_t used_bkref_map; + bitset_word_t completed_bkref_map; + + unsigned int has_plural_match : 1; + /* If this dfa has "multibyte node", which is a backreference or + a node which can accept multibyte character or multi character + collating element. */ + unsigned int has_mb_node : 1; + unsigned int is_utf8 : 1; + unsigned int map_notascii : 1; + unsigned int word_ops_used : 1; + int mb_cur_max; + bitset_t word_char; + reg_syntax_t syntax; + Idx *subexp_map; +#ifdef DEBUG + char* re_str; +#endif +#ifdef _LIBC + __libc_lock_define (, lock) +#endif +}; + +#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) +#define re_node_set_remove(set,id) \ + (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1)) +#define re_node_set_empty(p) ((p)->nelem = 0) +#define re_node_set_free(set) re_free ((set)->elems) + + +typedef enum +{ + SB_CHAR, + MB_CHAR, + EQUIV_CLASS, + COLL_SYM, + CHAR_CLASS +} bracket_elem_type; + +typedef struct +{ + bracket_elem_type type; + union + { + unsigned char ch; + unsigned char *name; + wchar_t wch; + } opr; +} bracket_elem_t; + + +/* Inline functions for bitset_t operation. */ + +static inline void +bitset_set (bitset_t set, Idx i) +{ + set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS; +} + +static inline void +bitset_clear (bitset_t set, Idx i) +{ + set[i / BITSET_WORD_BITS] &= ~ ((bitset_word_t) 1 << i % BITSET_WORD_BITS); +} + +static inline bool +bitset_contain (const bitset_t set, Idx i) +{ + return (set[i / BITSET_WORD_BITS] >> i % BITSET_WORD_BITS) & 1; +} + +static inline void +bitset_empty (bitset_t set) +{ + memset (set, '\0', sizeof (bitset_t)); +} + +static inline void +bitset_set_all (bitset_t set) +{ + memset (set, -1, sizeof (bitset_word_t) * (SBC_MAX / BITSET_WORD_BITS)); + if (SBC_MAX % BITSET_WORD_BITS != 0) + set[BITSET_WORDS - 1] = + ((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1; +} + +static inline void +bitset_copy (bitset_t dest, const bitset_t src) +{ + memcpy (dest, src, sizeof (bitset_t)); +} + +static inline void +bitset_not (bitset_t set) +{ + int bitset_i; + for (bitset_i = 0; bitset_i < SBC_MAX / BITSET_WORD_BITS; ++bitset_i) + set[bitset_i] = ~set[bitset_i]; + if (SBC_MAX % BITSET_WORD_BITS != 0) + set[BITSET_WORDS - 1] = + ((((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1) + & ~set[BITSET_WORDS - 1]); +} + +static inline void +bitset_merge (bitset_t dest, const bitset_t src) +{ + int bitset_i; + for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) + dest[bitset_i] |= src[bitset_i]; +} + +static inline void +bitset_mask (bitset_t dest, const bitset_t src) +{ + int bitset_i; + for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) + dest[bitset_i] &= src[bitset_i]; +} + +#ifdef RE_ENABLE_I18N +/* Inline functions for re_string. */ +static inline int +internal_function __attribute ((pure)) +re_string_char_size_at (const re_string_t *pstr, Idx idx) +{ + int byte_idx; + if (pstr->mb_cur_max == 1) + return 1; + for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx) + if (pstr->wcs[idx + byte_idx] != WEOF) + break; + return byte_idx; +} + +static inline wint_t +internal_function __attribute ((pure)) +re_string_wchar_at (const re_string_t *pstr, Idx idx) +{ + if (pstr->mb_cur_max == 1) + return (wint_t) pstr->mbs[idx]; + return (wint_t) pstr->wcs[idx]; +} + +static int +internal_function __attribute ((pure)) +re_string_elem_size_at (const re_string_t *pstr, Idx idx) +{ +# ifdef _LIBC + const unsigned char *p, *extra; + const int32_t *table, *indirect; + int32_t tmp; +# include + uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + + if (nrules != 0) + { + table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); + indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_INDIRECTMB); + p = pstr->mbs + idx; + tmp = findidx (&p); + return p - pstr->mbs - idx; + } + else +# endif /* _LIBC */ + return 1; +} +#endif /* RE_ENABLE_I18N */ + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +#if __GNUC_PREREQ (3,4) +# undef __attribute_warn_unused_result__ +# define __attribute_warn_unused_result__ \ + __attribute__ ((__warn_unused_result__)) +#else +# define __attribute_warn_unused_result__ /* empty */ +#endif + +#endif /* _REGEX_INTERNAL_H */ diff --git a/gnulib/regexec.c b/gnulib/regexec.c new file mode 100644 index 000000000..9388ac12b --- /dev/null +++ b/gnulib/regexec.c @@ -0,0 +1,4416 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free + Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + This program 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 2, or (at your option) + any later version. + + This program 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 this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags, + Idx n) internal_function; +static void match_ctx_clean (re_match_context_t *mctx) internal_function; +static void match_ctx_free (re_match_context_t *cache) internal_function; +static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, Idx node, + Idx str_idx, Idx from, Idx to) + internal_function; +static Idx search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx) + internal_function; +static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, Idx node, + Idx str_idx) internal_function; +static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop, + Idx node, Idx str_idx) + internal_function; +static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, + re_dfastate_t **limited_sts, Idx last_node, + Idx last_str_idx) + internal_function; +static reg_errcode_t re_search_internal (const regex_t *preg, + const char *string, Idx length, + Idx start, Idx last_start, Idx stop, + size_t nmatch, regmatch_t pmatch[], + int eflags) internal_function; +static regoff_t re_search_2_stub (struct re_pattern_buffer *bufp, + const char *string1, Idx length1, + const char *string2, Idx length2, + Idx start, regoff_t range, + struct re_registers *regs, + Idx stop, bool ret_len) internal_function; +static regoff_t re_search_stub (struct re_pattern_buffer *bufp, + const char *string, Idx length, Idx start, + regoff_t range, Idx stop, + struct re_registers *regs, + bool ret_len) internal_function; +static unsigned int re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, + Idx nregs, int regs_allocated) + internal_function; +static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx) + internal_function; +static Idx check_matching (re_match_context_t *mctx, bool fl_longest_match, + Idx *p_match_first) internal_function; +static Idx check_halt_state_context (const re_match_context_t *mctx, + const re_dfastate_t *state, Idx idx) + internal_function; +static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, + regmatch_t *prev_idx_match, Idx cur_node, + Idx cur_idx, Idx nmatch) internal_function; +static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs, + Idx str_idx, Idx dest_node, Idx nregs, + regmatch_t *regs, + re_node_set *eps_via_nodes) + internal_function; +static reg_errcode_t set_regs (const regex_t *preg, + const re_match_context_t *mctx, + size_t nmatch, regmatch_t *pmatch, + bool fl_backtrack) internal_function; +static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs) + internal_function; + +#ifdef RE_ENABLE_I18N +static int sift_states_iter_mb (const re_match_context_t *mctx, + re_sift_context_t *sctx, + Idx node_idx, Idx str_idx, Idx max_str_idx) + internal_function; +#endif /* RE_ENABLE_I18N */ +static reg_errcode_t sift_states_backward (const re_match_context_t *mctx, + re_sift_context_t *sctx) + internal_function; +static reg_errcode_t build_sifted_states (const re_match_context_t *mctx, + re_sift_context_t *sctx, Idx str_idx, + re_node_set *cur_dest) + internal_function; +static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx, + re_sift_context_t *sctx, + Idx str_idx, + re_node_set *dest_nodes) + internal_function; +static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa, + re_node_set *dest_nodes, + const re_node_set *candidates) + internal_function; +static bool check_dst_limits (const re_match_context_t *mctx, + const re_node_set *limits, + Idx dst_node, Idx dst_idx, Idx src_node, + Idx src_idx) internal_function; +static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, + int boundaries, Idx subexp_idx, + Idx from_node, Idx bkref_idx) + internal_function; +static int check_dst_limits_calc_pos (const re_match_context_t *mctx, + Idx limit, Idx subexp_idx, + Idx node, Idx str_idx, + Idx bkref_idx) internal_function; +static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa, + re_node_set *dest_nodes, + const re_node_set *candidates, + re_node_set *limits, + struct re_backref_cache_entry *bkref_ents, + Idx str_idx) internal_function; +static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx, + re_sift_context_t *sctx, + Idx str_idx, const re_node_set *candidates) + internal_function; +static reg_errcode_t merge_state_array (const re_dfa_t *dfa, + re_dfastate_t **dst, + re_dfastate_t **src, Idx num) + internal_function; +static re_dfastate_t *find_recover_state (reg_errcode_t *err, + re_match_context_t *mctx) internal_function; +static re_dfastate_t *transit_state (reg_errcode_t *err, + re_match_context_t *mctx, + re_dfastate_t *state) internal_function; +static re_dfastate_t *merge_state_with_log (reg_errcode_t *err, + re_match_context_t *mctx, + re_dfastate_t *next_state) + internal_function; +static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx, + re_node_set *cur_nodes, + Idx str_idx) internal_function; +#if 0 +static re_dfastate_t *transit_state_sb (reg_errcode_t *err, + re_match_context_t *mctx, + re_dfastate_t *pstate) + internal_function; +#endif +#ifdef RE_ENABLE_I18N +static reg_errcode_t transit_state_mb (re_match_context_t *mctx, + re_dfastate_t *pstate) + internal_function; +#endif /* RE_ENABLE_I18N */ +static reg_errcode_t transit_state_bkref (re_match_context_t *mctx, + const re_node_set *nodes) + internal_function; +static reg_errcode_t get_subexp (re_match_context_t *mctx, + Idx bkref_node, Idx bkref_str_idx) + internal_function; +static reg_errcode_t get_subexp_sub (re_match_context_t *mctx, + const re_sub_match_top_t *sub_top, + re_sub_match_last_t *sub_last, + Idx bkref_node, Idx bkref_str) + internal_function; +static Idx find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, + Idx subexp_idx, int type) internal_function; +static reg_errcode_t check_arrival (re_match_context_t *mctx, + state_array_t *path, Idx top_node, + Idx top_str, Idx last_node, Idx last_str, + int type) internal_function; +static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx, + Idx str_idx, + re_node_set *cur_nodes, + re_node_set *next_nodes) + internal_function; +static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa, + re_node_set *cur_nodes, + Idx ex_subexp, int type) + internal_function; +static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa, + re_node_set *dst_nodes, + Idx target, Idx ex_subexp, + int type) internal_function; +static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx, + re_node_set *cur_nodes, Idx cur_str, + Idx subexp_num, int type) + internal_function; +static bool build_trtable (const re_dfa_t *dfa, + re_dfastate_t *state) internal_function; +#ifdef RE_ENABLE_I18N +static int check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx, + const re_string_t *input, Idx idx) + internal_function; +# ifdef _LIBC +static unsigned int find_collation_sequence_value (const unsigned char *mbs, + size_t name_len) + internal_function; +# endif /* _LIBC */ +#endif /* RE_ENABLE_I18N */ +static Idx group_nodes_into_DFAstates (const re_dfa_t *dfa, + const re_dfastate_t *state, + re_node_set *states_node, + bitset_t *states_ch) internal_function; +static bool check_node_accept (const re_match_context_t *mctx, + const re_token_t *node, Idx idx) + internal_function; +static reg_errcode_t extend_buffers (re_match_context_t *mctx) + internal_function; + +/* Entry point for POSIX code. */ + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies `execution flags' which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec (preg, string, nmatch, pmatch, eflags) + const regex_t *_Restrict_ preg; + const char *_Restrict_ string; + size_t nmatch; + regmatch_t pmatch[_Restrict_arr_]; + int eflags; +{ + reg_errcode_t err; + Idx start, length; +#ifdef _LIBC + re_dfa_t *dfa = (re_dfa_t *) preg->buffer; +#endif + + if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND)) + return REG_BADPAT; + + if (eflags & REG_STARTEND) + { + start = pmatch[0].rm_so; + length = pmatch[0].rm_eo; + } + else + { + start = 0; + length = strlen (string); + } + + __libc_lock_lock (dfa->lock); + if (preg->no_sub) + err = re_search_internal (preg, string, length, start, length, + length, 0, NULL, eflags); + else + err = re_search_internal (preg, string, length, start, length, + length, nmatch, pmatch, eflags); + __libc_lock_unlock (dfa->lock); + return err != REG_NOERROR; +} + +#ifdef _LIBC +# include +versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4); + +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4) +__typeof__ (__regexec) __compat_regexec; + +int +attribute_compat_text_section +__compat_regexec (const regex_t *_Restrict_ preg, + const char *_Restrict_ string, size_t nmatch, + regmatch_t pmatch[], int eflags) +{ + return regexec (preg, string, nmatch, pmatch, + eflags & (REG_NOTBOL | REG_NOTEOL)); +} +compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0); +# endif +#endif + +/* Entry points for GNU code. */ + +/* re_match, re_search, re_match_2, re_search_2 + + The former two functions operate on STRING with length LENGTH, + while the later two operate on concatenation of STRING1 and STRING2 + with lengths LENGTH1 and LENGTH2, respectively. + + re_match() matches the compiled pattern in BUFP against the string, + starting at index START. + + re_search() first tries matching at index START, then it tries to match + starting from index START + 1, and so on. The last start position tried + is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same + way as re_match().) + + The parameter STOP of re_{match,search}_2 specifies that no match exceeding + the first STOP characters of the concatenation of the strings should be + concerned. + + If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match + and all groups is stored in REGS. (For the "_2" variants, the offsets are + computed relative to the concatenation, not relative to the individual + strings.) + + On success, re_match* functions return the length of the match, re_search* + return the position of the start of the match. Return value -1 means no + match was found and -2 indicates an internal error. */ + +regoff_t +re_match (bufp, string, length, start, regs) + struct re_pattern_buffer *bufp; + const char *string; + Idx length, start; + struct re_registers *regs; +{ + return re_search_stub (bufp, string, length, start, 0, length, regs, true); +} +#ifdef _LIBC +weak_alias (__re_match, re_match) +#endif + +regoff_t +re_search (bufp, string, length, start, range, regs) + struct re_pattern_buffer *bufp; + const char *string; + Idx length, start; + regoff_t range; + struct re_registers *regs; +{ + return re_search_stub (bufp, string, length, start, range, length, regs, + false); +} +#ifdef _LIBC +weak_alias (__re_search, re_search) +#endif + +regoff_t +re_match_2 (bufp, string1, length1, string2, length2, start, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + Idx length1, length2, start, stop; + struct re_registers *regs; +{ + return re_search_2_stub (bufp, string1, length1, string2, length2, + start, 0, regs, stop, true); +} +#ifdef _LIBC +weak_alias (__re_match_2, re_match_2) +#endif + +regoff_t +re_search_2 (bufp, string1, length1, string2, length2, start, range, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + Idx length1, length2, start, stop; + regoff_t range; + struct re_registers *regs; +{ + return re_search_2_stub (bufp, string1, length1, string2, length2, + start, range, regs, stop, false); +} +#ifdef _LIBC +weak_alias (__re_search_2, re_search_2) +#endif + +static regoff_t +internal_function +re_search_2_stub (struct re_pattern_buffer *bufp, + const char *string1, Idx length1, + const char *string2, Idx length2, + Idx start, regoff_t range, struct re_registers *regs, + Idx stop, bool ret_len) +{ + const char *str; + regoff_t rval; + Idx len = length1 + length2; + char *s = NULL; + + if (BE (length1 < 0 || length2 < 0 || stop < 0 || len < length1, 0)) + return -2; + + /* Concatenate the strings. */ + if (length2 > 0) + if (length1 > 0) + { + s = re_malloc (char, len); + + if (BE (s == NULL, 0)) + return -2; +#ifdef _LIBC + memcpy (__mempcpy (s, string1, length1), string2, length2); +#else + memcpy (s, string1, length1); + memcpy (s + length1, string2, length2); +#endif + str = s; + } + else + str = string2; + else + str = string1; + + rval = re_search_stub (bufp, str, len, start, range, stop, regs, + ret_len); + re_free (s); + return rval; +} + +/* The parameters have the same meaning as those of re_search. + Additional parameters: + If RET_LEN is true the length of the match is returned (re_match style); + otherwise the position of the match is returned. */ + +static regoff_t +internal_function +re_search_stub (struct re_pattern_buffer *bufp, + const char *string, Idx length, + Idx start, regoff_t range, Idx stop, struct re_registers *regs, + bool ret_len) +{ + reg_errcode_t result; + regmatch_t *pmatch; + Idx nregs; + regoff_t rval; + int eflags = 0; +#ifdef _LIBC + re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; +#endif + Idx last_start = start + range; + + /* Check for out-of-range. */ + if (BE (start < 0 || start > length, 0)) + return -1; + if (BE (length < last_start || (0 <= range && last_start < start), 0)) + last_start = length; + else if (BE (last_start < 0 || (range < 0 && start <= last_start), 0)) + last_start = 0; + + __libc_lock_lock (dfa->lock); + + eflags |= (bufp->not_bol) ? REG_NOTBOL : 0; + eflags |= (bufp->not_eol) ? REG_NOTEOL : 0; + + /* Compile fastmap if we haven't yet. */ + if (start < last_start && bufp->fastmap != NULL && !bufp->fastmap_accurate) + re_compile_fastmap (bufp); + + if (BE (bufp->no_sub, 0)) + regs = NULL; + + /* We need at least 1 register. */ + if (regs == NULL) + nregs = 1; + else if (BE (bufp->regs_allocated == REGS_FIXED + && regs->num_regs <= bufp->re_nsub, 0)) + { + nregs = regs->num_regs; + if (BE (nregs < 1, 0)) + { + /* Nothing can be copied to regs. */ + regs = NULL; + nregs = 1; + } + } + else + nregs = bufp->re_nsub + 1; + pmatch = re_malloc (regmatch_t, nregs); + if (BE (pmatch == NULL, 0)) + { + rval = -2; + goto out; + } + + result = re_search_internal (bufp, string, length, start, last_start, stop, + nregs, pmatch, eflags); + + rval = 0; + + /* I hope we needn't fill ther regs with -1's when no match was found. */ + if (result != REG_NOERROR) + rval = -1; + else if (regs != NULL) + { + /* If caller wants register contents data back, copy them. */ + bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs, + bufp->regs_allocated); + if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0)) + rval = -2; + } + + if (BE (rval == 0, 1)) + { + if (ret_len) + { + assert (pmatch[0].rm_so == start); + rval = pmatch[0].rm_eo - start; + } + else + rval = pmatch[0].rm_so; + } + re_free (pmatch); + out: + __libc_lock_unlock (dfa->lock); + return rval; +} + +static unsigned int +internal_function +re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, Idx nregs, + int regs_allocated) +{ + int rval = REGS_REALLOCATE; + Idx i; + Idx need_regs = nregs + 1; + /* We need one extra element beyond `num_regs' for the `-1' marker GNU code + uses. */ + + /* Have the register data arrays been allocated? */ + if (regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. */ + regs->start = re_malloc (regoff_t, need_regs); + if (BE (regs->start == NULL, 0)) + return REGS_UNALLOCATED; + regs->end = re_malloc (regoff_t, need_regs); + if (BE (regs->end == NULL, 0)) + { + re_free (regs->start); + return REGS_UNALLOCATED; + } + regs->num_regs = need_regs; + } + else if (regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (BE (need_regs > regs->num_regs, 0)) + { + regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs); + regoff_t *new_end; + if (BE (new_start == NULL, 0)) + return REGS_UNALLOCATED; + new_end = re_realloc (regs->end, regoff_t, need_regs); + if (BE (new_end == NULL, 0)) + { + re_free (new_start); + return REGS_UNALLOCATED; + } + regs->start = new_start; + regs->end = new_end; + regs->num_regs = need_regs; + } + } + else + { + assert (regs_allocated == REGS_FIXED); + /* This function may not be called with REGS_FIXED and nregs too big. */ + assert (regs->num_regs >= nregs); + rval = REGS_FIXED; + } + + /* Copy the regs. */ + for (i = 0; i < nregs; ++i) + { + regs->start[i] = pmatch[i].rm_so; + regs->end[i] = pmatch[i].rm_eo; + } + for ( ; i < regs->num_regs; ++i) + regs->start[i] = regs->end[i] = -1; + + return rval; +} + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use + this memory for recording register information. STARTS and ENDS + must be allocated using the malloc library routine, and must each + be at least NUM_REGS * sizeof (regoff_t) bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ + +void +re_set_registers (bufp, regs, num_regs, starts, ends) + struct re_pattern_buffer *bufp; + struct re_registers *regs; + __re_size_t num_regs; + regoff_t *starts, *ends; +{ + if (num_regs) + { + bufp->regs_allocated = REGS_REALLOCATE; + regs->num_regs = num_regs; + regs->start = starts; + regs->end = ends; + } + else + { + bufp->regs_allocated = REGS_UNALLOCATED; + regs->num_regs = 0; + regs->start = regs->end = NULL; + } +} +#ifdef _LIBC +weak_alias (__re_set_registers, re_set_registers) +#endif + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them unless specifically requested. */ + +#if defined _REGEX_RE_COMP || defined _LIBC +int +# ifdef _LIBC +weak_function +# endif +re_exec (s) + const char *s; +{ + return 0 == regexec (&re_comp_buf, s, 0, NULL, 0); +} +#endif /* _REGEX_RE_COMP */ + +/* Internal entry point. */ + +/* Searches for a compiled pattern PREG in the string STRING, whose + length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same + meaning as with regexec. LAST_START is START + RANGE, where + START and RANGE have the same meaning as with re_search. + Return REG_NOERROR if we find a match, and REG_NOMATCH if not, + otherwise return the error code. + Note: We assume front end functions already check ranges. + (0 <= LAST_START && LAST_START <= LENGTH) */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +re_search_internal (const regex_t *preg, + const char *string, Idx length, + Idx start, Idx last_start, Idx stop, + size_t nmatch, regmatch_t pmatch[], + int eflags) +{ + reg_errcode_t err; + const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; + Idx left_lim, right_lim; + int incr; + bool fl_longest_match; + int match_kind; + Idx match_first; + Idx match_last = REG_MISSING; + Idx extra_nmatch; + bool sb; + int ch; +#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) + re_match_context_t mctx = { .dfa = dfa }; +#else + re_match_context_t mctx; +#endif + char *fastmap = ((preg->fastmap != NULL && preg->fastmap_accurate + && start != last_start && !preg->can_be_null) + ? preg->fastmap : NULL); + RE_TRANSLATE_TYPE t = preg->translate; + +#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) + memset (&mctx, '\0', sizeof (re_match_context_t)); + mctx.dfa = dfa; +#endif + + extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0; + nmatch -= extra_nmatch; + + /* Check if the DFA haven't been compiled. */ + if (BE (preg->used == 0 || dfa->init_state == NULL + || dfa->init_state_word == NULL || dfa->init_state_nl == NULL + || dfa->init_state_begbuf == NULL, 0)) + return REG_NOMATCH; + +#ifdef DEBUG + /* We assume front-end functions already check them. */ + assert (0 <= last_start && last_start <= length); +#endif + + /* If initial states with non-begbuf contexts have no elements, + the regex must be anchored. If preg->newline_anchor is set, + we'll never use init_state_nl, so do not check it. */ + if (dfa->init_state->nodes.nelem == 0 + && dfa->init_state_word->nodes.nelem == 0 + && (dfa->init_state_nl->nodes.nelem == 0 + || !preg->newline_anchor)) + { + if (start != 0 && last_start != 0) + return REG_NOMATCH; + start = last_start = 0; + } + + /* We must check the longest matching, if nmatch > 0. */ + fl_longest_match = (nmatch != 0 || dfa->nbackref); + + err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1, + preg->translate, (preg->syntax & RE_ICASE) != 0, + dfa); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + mctx.input.stop = stop; + mctx.input.raw_stop = stop; + mctx.input.newline_anchor = preg->newline_anchor; + + err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + + /* We will log all the DFA states through which the dfa pass, + if nmatch > 1, or this dfa has "multibyte node", which is a + back-reference or a node which can accept multibyte character or + multi character collating element. */ + if (nmatch > 1 || dfa->has_mb_node) + { + /* Avoid overflow. */ + if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= mctx.input.bufs_len, 0)) + { + err = REG_ESPACE; + goto free_return; + } + + mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1); + if (BE (mctx.state_log == NULL, 0)) + { + err = REG_ESPACE; + goto free_return; + } + } + else + mctx.state_log = NULL; + + match_first = start; + mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF + : CONTEXT_NEWLINE | CONTEXT_BEGBUF; + + /* Check incrementally whether of not the input string match. */ + incr = (last_start < start) ? -1 : 1; + left_lim = (last_start < start) ? last_start : start; + right_lim = (last_start < start) ? start : last_start; + sb = dfa->mb_cur_max == 1; + match_kind = + (fastmap + ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0) + | (start <= last_start ? 2 : 0) + | (t != NULL ? 1 : 0)) + : 8); + + for (;; match_first += incr) + { + err = REG_NOMATCH; + if (match_first < left_lim || right_lim < match_first) + goto free_return; + + /* Advance as rapidly as possible through the string, until we + find a plausible place to start matching. This may be done + with varying efficiency, so there are various possibilities: + only the most common of them are specialized, in order to + save on code size. We use a switch statement for speed. */ + switch (match_kind) + { + case 8: + /* No fastmap. */ + break; + + case 7: + /* Fastmap with single-byte translation, match forward. */ + while (BE (match_first < right_lim, 1) + && !fastmap[t[(unsigned char) string[match_first]]]) + ++match_first; + goto forward_match_found_start_or_reached_end; + + case 6: + /* Fastmap without translation, match forward. */ + while (BE (match_first < right_lim, 1) + && !fastmap[(unsigned char) string[match_first]]) + ++match_first; + + forward_match_found_start_or_reached_end: + if (BE (match_first == right_lim, 0)) + { + ch = match_first >= length + ? 0 : (unsigned char) string[match_first]; + if (!fastmap[t ? t[ch] : ch]) + goto free_return; + } + break; + + case 4: + case 5: + /* Fastmap without multi-byte translation, match backwards. */ + while (match_first >= left_lim) + { + ch = match_first >= length + ? 0 : (unsigned char) string[match_first]; + if (fastmap[t ? t[ch] : ch]) + break; + --match_first; + } + if (match_first < left_lim) + goto free_return; + break; + + default: + /* In this case, we can't determine easily the current byte, + since it might be a component byte of a multibyte + character. Then we use the constructed buffer instead. */ + for (;;) + { + /* If MATCH_FIRST is out of the valid range, reconstruct the + buffers. */ + __re_size_t offset = match_first - mctx.input.raw_mbs_idx; + if (BE (offset >= (__re_size_t) mctx.input.valid_raw_len, 0)) + { + err = re_string_reconstruct (&mctx.input, match_first, + eflags); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + + offset = match_first - mctx.input.raw_mbs_idx; + } + /* If MATCH_FIRST is out of the buffer, leave it as '\0'. + Note that MATCH_FIRST must not be smaller than 0. */ + ch = (match_first >= length + ? 0 : re_string_byte_at (&mctx.input, offset)); + if (fastmap[ch]) + break; + match_first += incr; + if (match_first < left_lim || match_first > right_lim) + { + err = REG_NOMATCH; + goto free_return; + } + } + break; + } + + /* Reconstruct the buffers so that the matcher can assume that + the matching starts from the beginning of the buffer. */ + err = re_string_reconstruct (&mctx.input, match_first, eflags); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + +#ifdef RE_ENABLE_I18N + /* Don't consider this char as a possible match start if it part, + yet isn't the head, of a multibyte character. */ + if (!sb && !re_string_first_byte (&mctx.input, 0)) + continue; +#endif + + /* It seems to be appropriate one, then use the matcher. */ + /* We assume that the matching starts from 0. */ + mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0; + match_last = check_matching (&mctx, fl_longest_match, + start <= last_start ? &match_first : NULL); + if (match_last != REG_MISSING) + { + if (BE (match_last == REG_ERROR, 0)) + { + err = REG_ESPACE; + goto free_return; + } + else + { + mctx.match_last = match_last; + if ((!preg->no_sub && nmatch > 1) || dfa->nbackref) + { + re_dfastate_t *pstate = mctx.state_log[match_last]; + mctx.last_node = check_halt_state_context (&mctx, pstate, + match_last); + } + if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match) + || dfa->nbackref) + { + err = prune_impossible_nodes (&mctx); + if (err == REG_NOERROR) + break; + if (BE (err != REG_NOMATCH, 0)) + goto free_return; + match_last = REG_MISSING; + } + else + break; /* We found a match. */ + } + } + + match_ctx_clean (&mctx); + } + +#ifdef DEBUG + assert (match_last != REG_MISSING); + assert (err == REG_NOERROR); +#endif + + /* Set pmatch[] if we need. */ + if (nmatch > 0) + { + Idx reg_idx; + + /* Initialize registers. */ + for (reg_idx = 1; reg_idx < nmatch; ++reg_idx) + pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; + + /* Set the points where matching start/end. */ + pmatch[0].rm_so = 0; + pmatch[0].rm_eo = mctx.match_last; + /* FIXME: This function should fail if mctx.match_last exceeds + the maximum possible regoff_t value. We need a new error + code REG_OVERFLOW. */ + + if (!preg->no_sub && nmatch > 1) + { + err = set_regs (preg, &mctx, nmatch, pmatch, + dfa->has_plural_match && dfa->nbackref > 0); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + + /* At last, add the offset to the each registers, since we slided + the buffers so that we could assume that the matching starts + from 0. */ + for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) + if (pmatch[reg_idx].rm_so != -1) + { +#ifdef RE_ENABLE_I18N + if (BE (mctx.input.offsets_needed != 0, 0)) + { + pmatch[reg_idx].rm_so = + (pmatch[reg_idx].rm_so == mctx.input.valid_len + ? mctx.input.valid_raw_len + : mctx.input.offsets[pmatch[reg_idx].rm_so]); + pmatch[reg_idx].rm_eo = + (pmatch[reg_idx].rm_eo == mctx.input.valid_len + ? mctx.input.valid_raw_len + : mctx.input.offsets[pmatch[reg_idx].rm_eo]); + } +#else + assert (mctx.input.offsets_needed == 0); +#endif + pmatch[reg_idx].rm_so += match_first; + pmatch[reg_idx].rm_eo += match_first; + } + for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx) + { + pmatch[nmatch + reg_idx].rm_so = -1; + pmatch[nmatch + reg_idx].rm_eo = -1; + } + + if (dfa->subexp_map) + for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++) + if (dfa->subexp_map[reg_idx] != reg_idx) + { + pmatch[reg_idx + 1].rm_so + = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so; + pmatch[reg_idx + 1].rm_eo + = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo; + } + } + + free_return: + re_free (mctx.state_log); + if (dfa->nbackref) + match_ctx_free (&mctx); + re_string_destruct (&mctx.input); + return err; +} + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +prune_impossible_nodes (re_match_context_t *mctx) +{ + const re_dfa_t *const dfa = mctx->dfa; + Idx halt_node, match_last; + reg_errcode_t ret; + re_dfastate_t **sifted_states; + re_dfastate_t **lim_states = NULL; + re_sift_context_t sctx; +#ifdef DEBUG + assert (mctx->state_log != NULL); +#endif + match_last = mctx->match_last; + halt_node = mctx->last_node; + + /* Avoid overflow. */ + if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= match_last, 0)) + return REG_ESPACE; + + sifted_states = re_malloc (re_dfastate_t *, match_last + 1); + if (BE (sifted_states == NULL, 0)) + { + ret = REG_ESPACE; + goto free_return; + } + if (dfa->nbackref) + { + lim_states = re_malloc (re_dfastate_t *, match_last + 1); + if (BE (lim_states == NULL, 0)) + { + ret = REG_ESPACE; + goto free_return; + } + while (1) + { + memset (lim_states, '\0', + sizeof (re_dfastate_t *) * (match_last + 1)); + sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, + match_last); + ret = sift_states_backward (mctx, &sctx); + re_node_set_free (&sctx.limits); + if (BE (ret != REG_NOERROR, 0)) + goto free_return; + if (sifted_states[0] != NULL || lim_states[0] != NULL) + break; + do + { + --match_last; + if (! REG_VALID_INDEX (match_last)) + { + ret = REG_NOMATCH; + goto free_return; + } + } while (mctx->state_log[match_last] == NULL + || !mctx->state_log[match_last]->halt); + halt_node = check_halt_state_context (mctx, + mctx->state_log[match_last], + match_last); + } + ret = merge_state_array (dfa, sifted_states, lim_states, + match_last + 1); + re_free (lim_states); + lim_states = NULL; + if (BE (ret != REG_NOERROR, 0)) + goto free_return; + } + else + { + sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last); + ret = sift_states_backward (mctx, &sctx); + re_node_set_free (&sctx.limits); + if (BE (ret != REG_NOERROR, 0)) + goto free_return; + if (sifted_states[0] == NULL) + { + ret = REG_NOMATCH; + goto free_return; + } + } + re_free (mctx->state_log); + mctx->state_log = sifted_states; + sifted_states = NULL; + mctx->last_node = halt_node; + mctx->match_last = match_last; + ret = REG_NOERROR; + free_return: + re_free (sifted_states); + re_free (lim_states); + return ret; +} + +/* Acquire an initial state and return it. + We must select appropriate initial state depending on the context, + since initial states may have constraints like "\<", "^", etc.. */ + +static inline re_dfastate_t * +__attribute ((always_inline)) internal_function +acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx, + Idx idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + if (dfa->init_state->has_constraint) + { + unsigned int context; + context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags); + if (IS_WORD_CONTEXT (context)) + return dfa->init_state_word; + else if (IS_ORDINARY_CONTEXT (context)) + return dfa->init_state; + else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context)) + return dfa->init_state_begbuf; + else if (IS_NEWLINE_CONTEXT (context)) + return dfa->init_state_nl; + else if (IS_BEGBUF_CONTEXT (context)) + { + /* It is relatively rare case, then calculate on demand. */ + return re_acquire_state_context (err, dfa, + dfa->init_state->entrance_nodes, + context); + } + else + /* Must not happen? */ + return dfa->init_state; + } + else + return dfa->init_state; +} + +/* Check whether the regular expression match input string INPUT or not, + and return the index where the matching end. Return REG_MISSING if + there is no match, and return REG_ERROR in case of an error. + FL_LONGEST_MATCH means we want the POSIX longest matching. + If P_MATCH_FIRST is not NULL, and the match fails, it is set to the + next place where we may want to try matching. + Note that the matcher assume that the maching starts from the current + index of the buffer. */ + +static Idx +internal_function __attribute_warn_unused_result__ +check_matching (re_match_context_t *mctx, bool fl_longest_match, + Idx *p_match_first) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + Idx match = 0; + Idx match_last = REG_MISSING; + Idx cur_str_idx = re_string_cur_idx (&mctx->input); + re_dfastate_t *cur_state; + bool at_init_state = p_match_first != NULL; + Idx next_start_idx = cur_str_idx; + + err = REG_NOERROR; + cur_state = acquire_init_state_context (&err, mctx, cur_str_idx); + /* An initial state must not be NULL (invalid). */ + if (BE (cur_state == NULL, 0)) + { + assert (err == REG_ESPACE); + return REG_ERROR; + } + + if (mctx->state_log != NULL) + { + mctx->state_log[cur_str_idx] = cur_state; + + /* Check OP_OPEN_SUBEXP in the initial state in case that we use them + later. E.g. Processing back references. */ + if (BE (dfa->nbackref, 0)) + { + at_init_state = false; + err = check_subexp_matching_top (mctx, &cur_state->nodes, 0); + if (BE (err != REG_NOERROR, 0)) + return err; + + if (cur_state->has_backref) + { + err = transit_state_bkref (mctx, &cur_state->nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + } + } + } + + /* If the RE accepts NULL string. */ + if (BE (cur_state->halt, 0)) + { + if (!cur_state->has_constraint + || check_halt_state_context (mctx, cur_state, cur_str_idx)) + { + if (!fl_longest_match) + return cur_str_idx; + else + { + match_last = cur_str_idx; + match = 1; + } + } + } + + while (!re_string_eoi (&mctx->input)) + { + re_dfastate_t *old_state = cur_state; + Idx next_char_idx = re_string_cur_idx (&mctx->input) + 1; + + if (BE (next_char_idx >= mctx->input.bufs_len, 0) + || (BE (next_char_idx >= mctx->input.valid_len, 0) + && mctx->input.valid_len < mctx->input.len)) + { + err = extend_buffers (mctx); + if (BE (err != REG_NOERROR, 0)) + { + assert (err == REG_ESPACE); + return REG_ERROR; + } + } + + cur_state = transit_state (&err, mctx, cur_state); + if (mctx->state_log != NULL) + cur_state = merge_state_with_log (&err, mctx, cur_state); + + if (cur_state == NULL) + { + /* Reached the invalid state or an error. Try to recover a valid + state using the state log, if available and if we have not + already found a valid (even if not the longest) match. */ + if (BE (err != REG_NOERROR, 0)) + return REG_ERROR; + + if (mctx->state_log == NULL + || (match && !fl_longest_match) + || (cur_state = find_recover_state (&err, mctx)) == NULL) + break; + } + + if (BE (at_init_state, 0)) + { + if (old_state == cur_state) + next_start_idx = next_char_idx; + else + at_init_state = false; + } + + if (cur_state->halt) + { + /* Reached a halt state. + Check the halt state can satisfy the current context. */ + if (!cur_state->has_constraint + || check_halt_state_context (mctx, cur_state, + re_string_cur_idx (&mctx->input))) + { + /* We found an appropriate halt state. */ + match_last = re_string_cur_idx (&mctx->input); + match = 1; + + /* We found a match, do not modify match_first below. */ + p_match_first = NULL; + if (!fl_longest_match) + break; + } + } + } + + if (p_match_first) + *p_match_first += next_start_idx; + + return match_last; +} + +/* Check NODE match the current context. */ + +static bool +internal_function +check_halt_node_context (const re_dfa_t *dfa, Idx node, unsigned int context) +{ + re_token_type_t type = dfa->nodes[node].type; + unsigned int constraint = dfa->nodes[node].constraint; + if (type != END_OF_RE) + return false; + if (!constraint) + return true; + if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context)) + return false; + return true; +} + +/* Check the halt state STATE match the current context. + Return 0 if not match, if the node, STATE has, is a halt node and + match the context, return the node. */ + +static Idx +internal_function +check_halt_state_context (const re_match_context_t *mctx, + const re_dfastate_t *state, Idx idx) +{ + Idx i; + unsigned int context; +#ifdef DEBUG + assert (state->halt); +#endif + context = re_string_context_at (&mctx->input, idx, mctx->eflags); + for (i = 0; i < state->nodes.nelem; ++i) + if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context)) + return state->nodes.elems[i]; + return 0; +} + +/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA + corresponding to the DFA). + Return the destination node, and update EPS_VIA_NODES; + return REG_MISSING in case of errors. */ + +static Idx +internal_function +proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, + Idx *pidx, Idx node, re_node_set *eps_via_nodes, + struct re_fail_stack_t *fs) +{ + const re_dfa_t *const dfa = mctx->dfa; + Idx i; + bool ok; + if (IS_EPSILON_NODE (dfa->nodes[node].type)) + { + re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes; + re_node_set *edests = &dfa->edests[node]; + Idx dest_node; + ok = re_node_set_insert (eps_via_nodes, node); + if (BE (! ok, 0)) + return REG_ERROR; + /* Pick up a valid destination, or return REG_MISSING if none + is found. */ + for (dest_node = REG_MISSING, i = 0; i < edests->nelem; ++i) + { + Idx candidate = edests->elems[i]; + if (!re_node_set_contains (cur_nodes, candidate)) + continue; + if (dest_node == REG_MISSING) + dest_node = candidate; + + else + { + /* In order to avoid infinite loop like "(a*)*", return the second + epsilon-transition if the first was already considered. */ + if (re_node_set_contains (eps_via_nodes, dest_node)) + return candidate; + + /* Otherwise, push the second epsilon-transition on the fail stack. */ + else if (fs != NULL + && push_fail_stack (fs, *pidx, candidate, nregs, regs, + eps_via_nodes)) + return REG_ERROR; + + /* We know we are going to exit. */ + break; + } + } + return dest_node; + } + else + { + Idx naccepted = 0; + re_token_type_t type = dfa->nodes[node].type; + +#ifdef RE_ENABLE_I18N + if (dfa->nodes[node].accept_mb) + naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx); + else +#endif /* RE_ENABLE_I18N */ + if (type == OP_BACK_REF) + { + Idx subexp_idx = dfa->nodes[node].opr.idx + 1; + naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so; + if (fs != NULL) + { + if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1) + return REG_MISSING; + else if (naccepted) + { + char *buf = (char *) re_string_get_buffer (&mctx->input); + if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, + naccepted) != 0) + return REG_MISSING; + } + } + + if (naccepted == 0) + { + Idx dest_node; + ok = re_node_set_insert (eps_via_nodes, node); + if (BE (! ok, 0)) + return REG_ERROR; + dest_node = dfa->edests[node].elems[0]; + if (re_node_set_contains (&mctx->state_log[*pidx]->nodes, + dest_node)) + return dest_node; + } + } + + if (naccepted != 0 + || check_node_accept (mctx, dfa->nodes + node, *pidx)) + { + Idx dest_node = dfa->nexts[node]; + *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted; + if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL + || !re_node_set_contains (&mctx->state_log[*pidx]->nodes, + dest_node))) + return REG_MISSING; + re_node_set_empty (eps_via_nodes); + return dest_node; + } + } + return REG_MISSING; +} + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node, + Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes) +{ + reg_errcode_t err; + Idx num = fs->num++; + if (fs->num == fs->alloc) + { + struct re_fail_stack_ent_t *new_array; + new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t) + * fs->alloc * 2)); + if (new_array == NULL) + return REG_ESPACE; + fs->alloc *= 2; + fs->stack = new_array; + } + fs->stack[num].idx = str_idx; + fs->stack[num].node = dest_node; + fs->stack[num].regs = re_malloc (regmatch_t, nregs); + if (fs->stack[num].regs == NULL) + return REG_ESPACE; + memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); + err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); + return err; +} + +static Idx +internal_function +pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs, + regmatch_t *regs, re_node_set *eps_via_nodes) +{ + Idx num = --fs->num; + assert (REG_VALID_INDEX (num)); + *pidx = fs->stack[num].idx; + memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); + re_node_set_free (eps_via_nodes); + re_free (fs->stack[num].regs); + *eps_via_nodes = fs->stack[num].eps_via_nodes; + return fs->stack[num].node; +} + +/* Set the positions where the subexpressions are starts/ends to registers + PMATCH. + Note: We assume that pmatch[0] is already set, and + pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, + regmatch_t *pmatch, bool fl_backtrack) +{ + const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; + Idx idx, cur_node; + re_node_set eps_via_nodes; + struct re_fail_stack_t *fs; + struct re_fail_stack_t fs_body = { 0, 2, NULL }; + regmatch_t *prev_idx_match; + bool prev_idx_match_malloced = false; + +#ifdef DEBUG + assert (nmatch > 1); + assert (mctx->state_log != NULL); +#endif + if (fl_backtrack) + { + fs = &fs_body; + fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc); + if (fs->stack == NULL) + return REG_ESPACE; + } + else + fs = NULL; + + cur_node = dfa->init_node; + re_node_set_init_empty (&eps_via_nodes); + + if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) + prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t)); + else + { + prev_idx_match = re_malloc (regmatch_t, nmatch); + if (prev_idx_match == NULL) + { + free_fail_stack_return (fs); + return REG_ESPACE; + } + prev_idx_match_malloced = true; + } + memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); + + for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) + { + update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch); + + if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) + { + Idx reg_idx; + if (fs) + { + for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) + if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) + break; + if (reg_idx == nmatch) + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return free_fail_stack_return (fs); + } + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, + &eps_via_nodes); + } + else + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return REG_NOERROR; + } + } + + /* Proceed to next node. */ + cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node, + &eps_via_nodes, fs); + + if (BE (! REG_VALID_INDEX (cur_node), 0)) + { + if (BE (cur_node == REG_ERROR, 0)) + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + free_fail_stack_return (fs); + return REG_ESPACE; + } + if (fs) + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, + &eps_via_nodes); + else + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return REG_NOMATCH; + } + } + } + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return free_fail_stack_return (fs); +} + +static reg_errcode_t +internal_function +free_fail_stack_return (struct re_fail_stack_t *fs) +{ + if (fs) + { + Idx fs_idx; + for (fs_idx = 0; fs_idx < fs->num; ++fs_idx) + { + re_node_set_free (&fs->stack[fs_idx].eps_via_nodes); + re_free (fs->stack[fs_idx].regs); + } + re_free (fs->stack); + } + return REG_NOERROR; +} + +static void +internal_function +update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, + regmatch_t *prev_idx_match, Idx cur_node, Idx cur_idx, Idx nmatch) +{ + int type = dfa->nodes[cur_node].type; + if (type == OP_OPEN_SUBEXP) + { + Idx reg_num = dfa->nodes[cur_node].opr.idx + 1; + + /* We are at the first node of this sub expression. */ + if (reg_num < nmatch) + { + pmatch[reg_num].rm_so = cur_idx; + pmatch[reg_num].rm_eo = -1; + } + } + else if (type == OP_CLOSE_SUBEXP) + { + Idx reg_num = dfa->nodes[cur_node].opr.idx + 1; + if (reg_num < nmatch) + { + /* We are at the last node of this sub expression. */ + if (pmatch[reg_num].rm_so < cur_idx) + { + pmatch[reg_num].rm_eo = cur_idx; + /* This is a non-empty match or we are not inside an optional + subexpression. Accept this right away. */ + memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); + } + else + { + if (dfa->nodes[cur_node].opt_subexp + && prev_idx_match[reg_num].rm_so != -1) + /* We transited through an empty match for an optional + subexpression, like (a?)*, and this is not the subexp's + first match. Copy back the old content of the registers + so that matches of an inner subexpression are undone as + well, like in ((a?))*. */ + memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch); + else + /* We completed a subexpression, but it may be part of + an optional one, so do not update PREV_IDX_MATCH. */ + pmatch[reg_num].rm_eo = cur_idx; + } + } + } +} + +/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 + and sift the nodes in each states according to the following rules. + Updated state_log will be wrote to STATE_LOG. + + Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if... + 1. When STR_IDX == MATCH_LAST(the last index in the state_log): + If `a' isn't the LAST_NODE and `a' can't epsilon transit to + the LAST_NODE, we throw away the node `a'. + 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts + string `s' and transit to `b': + i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw + away the node `a'. + ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is + thrown away, we throw away the node `a'. + 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b': + i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the + node `a'. + ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away, + we throw away the node `a'. */ + +#define STATE_NODE_CONTAINS(state,node) \ + ((state) != NULL && re_node_set_contains (&(state)->nodes, node)) + +static reg_errcode_t +internal_function +sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx) +{ + reg_errcode_t err; + int null_cnt = 0; + Idx str_idx = sctx->last_str_idx; + re_node_set cur_dest; + +#ifdef DEBUG + assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL); +#endif + + /* Build sifted state_log[str_idx]. It has the nodes which can epsilon + transit to the last_node and the last_node itself. */ + err = re_node_set_init_1 (&cur_dest, sctx->last_node); + if (BE (err != REG_NOERROR, 0)) + return err; + err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + + /* Then check each states in the state_log. */ + while (str_idx > 0) + { + /* Update counters. */ + null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0; + if (null_cnt > mctx->max_mb_elem_len) + { + memset (sctx->sifted_states, '\0', + sizeof (re_dfastate_t *) * str_idx); + re_node_set_free (&cur_dest); + return REG_NOERROR; + } + re_node_set_empty (&cur_dest); + --str_idx; + + if (mctx->state_log[str_idx]) + { + err = build_sifted_states (mctx, sctx, str_idx, &cur_dest); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + + /* Add all the nodes which satisfy the following conditions: + - It can epsilon transit to a node in CUR_DEST. + - It is in CUR_SRC. + And update state_log. */ + err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + err = REG_NOERROR; + free_return: + re_node_set_free (&cur_dest); + return err; +} + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx, + Idx str_idx, re_node_set *cur_dest) +{ + const re_dfa_t *const dfa = mctx->dfa; + const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes; + Idx i; + + /* Then build the next sifted state. + We build the next sifted state on `cur_dest', and update + `sifted_states[str_idx]' with `cur_dest'. + Note: + `cur_dest' is the sifted state from `state_log[str_idx + 1]'. + `cur_src' points the node_set of the old `state_log[str_idx]' + (with the epsilon nodes pre-filtered out). */ + for (i = 0; i < cur_src->nelem; i++) + { + Idx prev_node = cur_src->elems[i]; + int naccepted = 0; + bool ok; + +#ifdef DEBUG + re_token_type_t type = dfa->nodes[prev_node].type; + assert (!IS_EPSILON_NODE (type)); +#endif +#ifdef RE_ENABLE_I18N + /* If the node may accept `multi byte'. */ + if (dfa->nodes[prev_node].accept_mb) + naccepted = sift_states_iter_mb (mctx, sctx, prev_node, + str_idx, sctx->last_str_idx); +#endif /* RE_ENABLE_I18N */ + + /* We don't check backreferences here. + See update_cur_sifted_state(). */ + if (!naccepted + && check_node_accept (mctx, dfa->nodes + prev_node, str_idx) + && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1], + dfa->nexts[prev_node])) + naccepted = 1; + + if (naccepted == 0) + continue; + + if (sctx->limits.nelem) + { + Idx to_idx = str_idx + naccepted; + if (check_dst_limits (mctx, &sctx->limits, + dfa->nexts[prev_node], to_idx, + prev_node, str_idx)) + continue; + } + ok = re_node_set_insert (cur_dest, prev_node); + if (BE (! ok, 0)) + return REG_ESPACE; + } + + return REG_NOERROR; +} + +/* Helper functions. */ + +static reg_errcode_t +internal_function +clean_state_log_if_needed (re_match_context_t *mctx, Idx next_state_log_idx) +{ + Idx top = mctx->state_log_top; + + if (next_state_log_idx >= mctx->input.bufs_len + || (next_state_log_idx >= mctx->input.valid_len + && mctx->input.valid_len < mctx->input.len)) + { + reg_errcode_t err; + err = extend_buffers (mctx); + if (BE (err != REG_NOERROR, 0)) + return err; + } + + if (top < next_state_log_idx) + { + memset (mctx->state_log + top + 1, '\0', + sizeof (re_dfastate_t *) * (next_state_log_idx - top)); + mctx->state_log_top = next_state_log_idx; + } + return REG_NOERROR; +} + +static reg_errcode_t +internal_function +merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst, + re_dfastate_t **src, Idx num) +{ + Idx st_idx; + reg_errcode_t err; + for (st_idx = 0; st_idx < num; ++st_idx) + { + if (dst[st_idx] == NULL) + dst[st_idx] = src[st_idx]; + else if (src[st_idx] != NULL) + { + re_node_set merged_set; + err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes, + &src[st_idx]->nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + dst[st_idx] = re_acquire_state (&err, dfa, &merged_set); + re_node_set_free (&merged_set); + if (BE (err != REG_NOERROR, 0)) + return err; + } + } + return REG_NOERROR; +} + +static reg_errcode_t +internal_function +update_cur_sifted_state (const re_match_context_t *mctx, + re_sift_context_t *sctx, Idx str_idx, + re_node_set *dest_nodes) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err = REG_NOERROR; + const re_node_set *candidates; + candidates = ((mctx->state_log[str_idx] == NULL) ? NULL + : &mctx->state_log[str_idx]->nodes); + + if (dest_nodes->nelem == 0) + sctx->sifted_states[str_idx] = NULL; + else + { + if (candidates) + { + /* At first, add the nodes which can epsilon transit to a node in + DEST_NODE. */ + err = add_epsilon_src_nodes (dfa, dest_nodes, candidates); + if (BE (err != REG_NOERROR, 0)) + return err; + + /* Then, check the limitations in the current sift_context. */ + if (sctx->limits.nelem) + { + err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits, + mctx->bkref_ents, str_idx); + if (BE (err != REG_NOERROR, 0)) + return err; + } + } + + sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + } + + if (candidates && mctx->state_log[str_idx]->has_backref) + { + err = sift_states_bkref (mctx, sctx, str_idx, candidates); + if (BE (err != REG_NOERROR, 0)) + return err; + } + return REG_NOERROR; +} + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, + const re_node_set *candidates) +{ + reg_errcode_t err = REG_NOERROR; + Idx i; + + re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + + if (!state->inveclosure.alloc) + { + err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem); + if (BE (err != REG_NOERROR, 0)) + return REG_ESPACE; + for (i = 0; i < dest_nodes->nelem; i++) + { + err = re_node_set_merge (&state->inveclosure, + dfa->inveclosures + dest_nodes->elems[i]); + if (BE (err != REG_NOERROR, 0)) + return REG_ESPACE; + } + } + return re_node_set_add_intersect (dest_nodes, candidates, + &state->inveclosure); +} + +static reg_errcode_t +internal_function +sub_epsilon_src_nodes (const re_dfa_t *dfa, Idx node, re_node_set *dest_nodes, + const re_node_set *candidates) +{ + Idx ecl_idx; + reg_errcode_t err; + re_node_set *inv_eclosure = dfa->inveclosures + node; + re_node_set except_nodes; + re_node_set_init_empty (&except_nodes); + for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) + { + Idx cur_node = inv_eclosure->elems[ecl_idx]; + if (cur_node == node) + continue; + if (IS_EPSILON_NODE (dfa->nodes[cur_node].type)) + { + Idx edst1 = dfa->edests[cur_node].elems[0]; + Idx edst2 = ((dfa->edests[cur_node].nelem > 1) + ? dfa->edests[cur_node].elems[1] : REG_MISSING); + if ((!re_node_set_contains (inv_eclosure, edst1) + && re_node_set_contains (dest_nodes, edst1)) + || (REG_VALID_NONZERO_INDEX (edst2) + && !re_node_set_contains (inv_eclosure, edst2) + && re_node_set_contains (dest_nodes, edst2))) + { + err = re_node_set_add_intersect (&except_nodes, candidates, + dfa->inveclosures + cur_node); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&except_nodes); + return err; + } + } + } + } + for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) + { + Idx cur_node = inv_eclosure->elems[ecl_idx]; + if (!re_node_set_contains (&except_nodes, cur_node)) + { + Idx idx = re_node_set_contains (dest_nodes, cur_node) - 1; + re_node_set_remove_at (dest_nodes, idx); + } + } + re_node_set_free (&except_nodes); + return REG_NOERROR; +} + +static bool +internal_function +check_dst_limits (const re_match_context_t *mctx, const re_node_set *limits, + Idx dst_node, Idx dst_idx, Idx src_node, Idx src_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + Idx lim_idx, src_pos, dst_pos; + + Idx dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx); + Idx src_bkref_idx = search_cur_bkref_entry (mctx, src_idx); + for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) + { + Idx subexp_idx; + struct re_backref_cache_entry *ent; + ent = mctx->bkref_ents + limits->elems[lim_idx]; + subexp_idx = dfa->nodes[ent->node].opr.idx; + + dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], + subexp_idx, dst_node, dst_idx, + dst_bkref_idx); + src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], + subexp_idx, src_node, src_idx, + src_bkref_idx); + + /* In case of: + ( ) + ( ) + ( ) */ + if (src_pos == dst_pos) + continue; /* This is unrelated limitation. */ + else + return true; + } + return false; +} + +static int +internal_function +check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries, + Idx subexp_idx, Idx from_node, Idx bkref_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + const re_node_set *eclosures = dfa->eclosures + from_node; + Idx node_idx; + + /* Else, we are on the boundary: examine the nodes on the epsilon + closure. */ + for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx) + { + Idx node = eclosures->elems[node_idx]; + switch (dfa->nodes[node].type) + { + case OP_BACK_REF: + if (bkref_idx != REG_MISSING) + { + struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx; + do + { + Idx dst; + int cpos; + + if (ent->node != node) + continue; + + if (subexp_idx < BITSET_WORD_BITS + && !(ent->eps_reachable_subexps_map + & ((bitset_word_t) 1 << subexp_idx))) + continue; + + /* Recurse trying to reach the OP_OPEN_SUBEXP and + OP_CLOSE_SUBEXP cases below. But, if the + destination node is the same node as the source + node, don't recurse because it would cause an + infinite loop: a regex that exhibits this behavior + is ()\1*\1* */ + dst = dfa->edests[node].elems[0]; + if (dst == from_node) + { + if (boundaries & 1) + return -1; + else /* if (boundaries & 2) */ + return 0; + } + + cpos = + check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, + dst, bkref_idx); + if (cpos == -1 /* && (boundaries & 1) */) + return -1; + if (cpos == 0 && (boundaries & 2)) + return 0; + + if (subexp_idx < BITSET_WORD_BITS) + ent->eps_reachable_subexps_map + &= ~((bitset_word_t) 1 << subexp_idx); + } + while (ent++->more); + } + break; + + case OP_OPEN_SUBEXP: + if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx) + return -1; + break; + + case OP_CLOSE_SUBEXP: + if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx) + return 0; + break; + + default: + break; + } + } + + return (boundaries & 2) ? 1 : 0; +} + +static int +internal_function +check_dst_limits_calc_pos (const re_match_context_t *mctx, Idx limit, + Idx subexp_idx, Idx from_node, Idx str_idx, + Idx bkref_idx) +{ + struct re_backref_cache_entry *lim = mctx->bkref_ents + limit; + int boundaries; + + /* If we are outside the range of the subexpression, return -1 or 1. */ + if (str_idx < lim->subexp_from) + return -1; + + if (lim->subexp_to < str_idx) + return 1; + + /* If we are within the subexpression, return 0. */ + boundaries = (str_idx == lim->subexp_from); + boundaries |= (str_idx == lim->subexp_to) << 1; + if (boundaries == 0) + return 0; + + /* Else, examine epsilon closure. */ + return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, + from_node, bkref_idx); +} + +/* Check the limitations of sub expressions LIMITS, and remove the nodes + which are against limitations from DEST_NODES. */ + +static reg_errcode_t +internal_function +check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes, + const re_node_set *candidates, re_node_set *limits, + struct re_backref_cache_entry *bkref_ents, Idx str_idx) +{ + reg_errcode_t err; + Idx node_idx, lim_idx; + + for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) + { + Idx subexp_idx; + struct re_backref_cache_entry *ent; + ent = bkref_ents + limits->elems[lim_idx]; + + if (str_idx <= ent->subexp_from || ent->str_idx < str_idx) + continue; /* This is unrelated limitation. */ + + subexp_idx = dfa->nodes[ent->node].opr.idx; + if (ent->subexp_to == str_idx) + { + Idx ops_node = REG_MISSING; + Idx cls_node = REG_MISSING; + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) + { + Idx node = dest_nodes->elems[node_idx]; + re_token_type_t type = dfa->nodes[node].type; + if (type == OP_OPEN_SUBEXP + && subexp_idx == dfa->nodes[node].opr.idx) + ops_node = node; + else if (type == OP_CLOSE_SUBEXP + && subexp_idx == dfa->nodes[node].opr.idx) + cls_node = node; + } + + /* Check the limitation of the open subexpression. */ + /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */ + if (REG_VALID_INDEX (ops_node)) + { + err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes, + candidates); + if (BE (err != REG_NOERROR, 0)) + return err; + } + + /* Check the limitation of the close subexpression. */ + if (REG_VALID_INDEX (cls_node)) + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) + { + Idx node = dest_nodes->elems[node_idx]; + if (!re_node_set_contains (dfa->inveclosures + node, + cls_node) + && !re_node_set_contains (dfa->eclosures + node, + cls_node)) + { + /* It is against this limitation. + Remove it form the current sifted state. */ + err = sub_epsilon_src_nodes (dfa, node, dest_nodes, + candidates); + if (BE (err != REG_NOERROR, 0)) + return err; + --node_idx; + } + } + } + else /* (ent->subexp_to != str_idx) */ + { + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) + { + Idx node = dest_nodes->elems[node_idx]; + re_token_type_t type = dfa->nodes[node].type; + if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP) + { + if (subexp_idx != dfa->nodes[node].opr.idx) + continue; + /* It is against this limitation. + Remove it form the current sifted state. */ + err = sub_epsilon_src_nodes (dfa, node, dest_nodes, + candidates); + if (BE (err != REG_NOERROR, 0)) + return err; + } + } + } + } + return REG_NOERROR; +} + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx, + Idx str_idx, const re_node_set *candidates) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + Idx node_idx, node; + re_sift_context_t local_sctx; + Idx first_idx = search_cur_bkref_entry (mctx, str_idx); + + if (first_idx == REG_MISSING) + return REG_NOERROR; + + local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */ + + for (node_idx = 0; node_idx < candidates->nelem; ++node_idx) + { + Idx enabled_idx; + re_token_type_t type; + struct re_backref_cache_entry *entry; + node = candidates->elems[node_idx]; + type = dfa->nodes[node].type; + /* Avoid infinite loop for the REs like "()\1+". */ + if (node == sctx->last_node && str_idx == sctx->last_str_idx) + continue; + if (type != OP_BACK_REF) + continue; + + entry = mctx->bkref_ents + first_idx; + enabled_idx = first_idx; + do + { + Idx subexp_len; + Idx to_idx; + Idx dst_node; + bool ok; + re_dfastate_t *cur_state; + + if (entry->node != node) + continue; + subexp_len = entry->subexp_to - entry->subexp_from; + to_idx = str_idx + subexp_len; + dst_node = (subexp_len ? dfa->nexts[node] + : dfa->edests[node].elems[0]); + + if (to_idx > sctx->last_str_idx + || sctx->sifted_states[to_idx] == NULL + || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node) + || check_dst_limits (mctx, &sctx->limits, node, + str_idx, dst_node, to_idx)) + continue; + + if (local_sctx.sifted_states == NULL) + { + local_sctx = *sctx; + err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + local_sctx.last_node = node; + local_sctx.last_str_idx = str_idx; + ok = re_node_set_insert (&local_sctx.limits, enabled_idx); + if (BE (! ok, 0)) + { + err = REG_ESPACE; + goto free_return; + } + cur_state = local_sctx.sifted_states[str_idx]; + err = sift_states_backward (mctx, &local_sctx); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + if (sctx->limited_states != NULL) + { + err = merge_state_array (dfa, sctx->limited_states, + local_sctx.sifted_states, + str_idx + 1); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + local_sctx.sifted_states[str_idx] = cur_state; + re_node_set_remove (&local_sctx.limits, enabled_idx); + + /* mctx->bkref_ents may have changed, reload the pointer. */ + entry = mctx->bkref_ents + enabled_idx; + } + while (enabled_idx++, entry++->more); + } + err = REG_NOERROR; + free_return: + if (local_sctx.sifted_states != NULL) + { + re_node_set_free (&local_sctx.limits); + } + + return err; +} + + +#ifdef RE_ENABLE_I18N +static int +internal_function +sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx, + Idx node_idx, Idx str_idx, Idx max_str_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + int naccepted; + /* Check the node can accept `multi byte'. */ + naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx); + if (naccepted > 0 && str_idx + naccepted <= max_str_idx && + !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted], + dfa->nexts[node_idx])) + /* The node can't accept the `multi byte', or the + destination was already thrown away, then the node + could't accept the current input `multi byte'. */ + naccepted = 0; + /* Otherwise, it is sure that the node could accept + `naccepted' bytes input. */ + return naccepted; +} +#endif /* RE_ENABLE_I18N */ + + +/* Functions for state transition. */ + +/* Return the next state to which the current state STATE will transit by + accepting the current input byte, and update STATE_LOG if necessary. + If STATE can accept a multibyte char/collating element/back reference + update the destination of STATE_LOG. */ + +static re_dfastate_t * +internal_function __attribute_warn_unused_result__ +transit_state (reg_errcode_t *err, re_match_context_t *mctx, + re_dfastate_t *state) +{ + re_dfastate_t **trtable; + unsigned char ch; + +#ifdef RE_ENABLE_I18N + /* If the current state can accept multibyte. */ + if (BE (state->accept_mb, 0)) + { + *err = transit_state_mb (mctx, state); + if (BE (*err != REG_NOERROR, 0)) + return NULL; + } +#endif /* RE_ENABLE_I18N */ + + /* Then decide the next state with the single byte. */ +#if 0 + if (0) + /* don't use transition table */ + return transit_state_sb (err, mctx, state); +#endif + + /* Use transition table */ + ch = re_string_fetch_byte (&mctx->input); + for (;;) + { + trtable = state->trtable; + if (BE (trtable != NULL, 1)) + return trtable[ch]; + + trtable = state->word_trtable; + if (BE (trtable != NULL, 1)) + { + unsigned int context; + context + = re_string_context_at (&mctx->input, + re_string_cur_idx (&mctx->input) - 1, + mctx->eflags); + if (IS_WORD_CONTEXT (context)) + return trtable[ch + SBC_MAX]; + else + return trtable[ch]; + } + + if (!build_trtable (mctx->dfa, state)) + { + *err = REG_ESPACE; + return NULL; + } + + /* Retry, we now have a transition table. */ + } +} + +/* Update the state_log if we need */ +static re_dfastate_t * +internal_function +merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx, + re_dfastate_t *next_state) +{ + const re_dfa_t *const dfa = mctx->dfa; + Idx cur_idx = re_string_cur_idx (&mctx->input); + + if (cur_idx > mctx->state_log_top) + { + mctx->state_log[cur_idx] = next_state; + mctx->state_log_top = cur_idx; + } + else if (mctx->state_log[cur_idx] == 0) + { + mctx->state_log[cur_idx] = next_state; + } + else + { + re_dfastate_t *pstate; + unsigned int context; + re_node_set next_nodes, *log_nodes, *table_nodes = NULL; + /* If (state_log[cur_idx] != 0), it implies that cur_idx is + the destination of a multibyte char/collating element/ + back reference. Then the next state is the union set of + these destinations and the results of the transition table. */ + pstate = mctx->state_log[cur_idx]; + log_nodes = pstate->entrance_nodes; + if (next_state != NULL) + { + table_nodes = next_state->entrance_nodes; + *err = re_node_set_init_union (&next_nodes, table_nodes, + log_nodes); + if (BE (*err != REG_NOERROR, 0)) + return NULL; + } + else + next_nodes = *log_nodes; + /* Note: We already add the nodes of the initial state, + then we don't need to add them here. */ + + context = re_string_context_at (&mctx->input, + re_string_cur_idx (&mctx->input) - 1, + mctx->eflags); + next_state = mctx->state_log[cur_idx] + = re_acquire_state_context (err, dfa, &next_nodes, context); + /* We don't need to check errors here, since the return value of + this function is next_state and ERR is already set. */ + + if (table_nodes != NULL) + re_node_set_free (&next_nodes); + } + + if (BE (dfa->nbackref, 0) && next_state != NULL) + { + /* Check OP_OPEN_SUBEXP in the current state in case that we use them + later. We must check them here, since the back references in the + next state might use them. */ + *err = check_subexp_matching_top (mctx, &next_state->nodes, + cur_idx); + if (BE (*err != REG_NOERROR, 0)) + return NULL; + + /* If the next state has back references. */ + if (next_state->has_backref) + { + *err = transit_state_bkref (mctx, &next_state->nodes); + if (BE (*err != REG_NOERROR, 0)) + return NULL; + next_state = mctx->state_log[cur_idx]; + } + } + + return next_state; +} + +/* Skip bytes in the input that correspond to part of a + multi-byte match, then look in the log for a state + from which to restart matching. */ +static re_dfastate_t * +internal_function +find_recover_state (reg_errcode_t *err, re_match_context_t *mctx) +{ + re_dfastate_t *cur_state; + do + { + Idx max = mctx->state_log_top; + Idx cur_str_idx = re_string_cur_idx (&mctx->input); + + do + { + if (++cur_str_idx > max) + return NULL; + re_string_skip_bytes (&mctx->input, 1); + } + while (mctx->state_log[cur_str_idx] == NULL); + + cur_state = merge_state_with_log (err, mctx, NULL); + } + while (*err == REG_NOERROR && cur_state == NULL); + return cur_state; +} + +/* Helper functions for transit_state. */ + +/* From the node set CUR_NODES, pick up the nodes whose types are + OP_OPEN_SUBEXP and which have corresponding back references in the regular + expression. And register them to use them later for evaluating the + correspoding back references. */ + +static reg_errcode_t +internal_function +check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes, + Idx str_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + Idx node_idx; + reg_errcode_t err; + + /* TODO: This isn't efficient. + Because there might be more than one nodes whose types are + OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all + nodes. + E.g. RE: (a){2} */ + for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx) + { + Idx node = cur_nodes->elems[node_idx]; + if (dfa->nodes[node].type == OP_OPEN_SUBEXP + && dfa->nodes[node].opr.idx < BITSET_WORD_BITS + && (dfa->used_bkref_map + & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx))) + { + err = match_ctx_add_subtop (mctx, node, str_idx); + if (BE (err != REG_NOERROR, 0)) + return err; + } + } + return REG_NOERROR; +} + +#if 0 +/* Return the next state to which the current state STATE will transit by + accepting the current input byte. */ + +static re_dfastate_t * +transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx, + re_dfastate_t *state) +{ + const re_dfa_t *const dfa = mctx->dfa; + re_node_set next_nodes; + re_dfastate_t *next_state; + Idx node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input); + unsigned int context; + + *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1); + if (BE (*err != REG_NOERROR, 0)) + return NULL; + for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt) + { + Idx cur_node = state->nodes.elems[node_cnt]; + if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx)) + { + *err = re_node_set_merge (&next_nodes, + dfa->eclosures + dfa->nexts[cur_node]); + if (BE (*err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return NULL; + } + } + } + context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags); + next_state = re_acquire_state_context (err, dfa, &next_nodes, context); + /* We don't need to check errors here, since the return value of + this function is next_state and ERR is already set. */ + + re_node_set_free (&next_nodes); + re_string_skip_bytes (&mctx->input, 1); + return next_state; +} +#endif + +#ifdef RE_ENABLE_I18N +static reg_errcode_t +internal_function +transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + Idx i; + + for (i = 0; i < pstate->nodes.nelem; ++i) + { + re_node_set dest_nodes, *new_nodes; + Idx cur_node_idx = pstate->nodes.elems[i]; + int naccepted; + Idx dest_idx; + unsigned int context; + re_dfastate_t *dest_state; + + if (!dfa->nodes[cur_node_idx].accept_mb) + continue; + + if (dfa->nodes[cur_node_idx].constraint) + { + context = re_string_context_at (&mctx->input, + re_string_cur_idx (&mctx->input), + mctx->eflags); + if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint, + context)) + continue; + } + + /* How many bytes the node can accept? */ + naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input, + re_string_cur_idx (&mctx->input)); + if (naccepted == 0) + continue; + + /* The node can accepts `naccepted' bytes. */ + dest_idx = re_string_cur_idx (&mctx->input) + naccepted; + mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted + : mctx->max_mb_elem_len); + err = clean_state_log_if_needed (mctx, dest_idx); + if (BE (err != REG_NOERROR, 0)) + return err; +#ifdef DEBUG + assert (dfa->nexts[cur_node_idx] != REG_MISSING); +#endif + new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx]; + + dest_state = mctx->state_log[dest_idx]; + if (dest_state == NULL) + dest_nodes = *new_nodes; + else + { + err = re_node_set_init_union (&dest_nodes, + dest_state->entrance_nodes, new_nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + } + context = re_string_context_at (&mctx->input, dest_idx - 1, + mctx->eflags); + mctx->state_log[dest_idx] + = re_acquire_state_context (&err, dfa, &dest_nodes, context); + if (dest_state != NULL) + re_node_set_free (&dest_nodes); + if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0)) + return err; + } + return REG_NOERROR; +} +#endif /* RE_ENABLE_I18N */ + +static reg_errcode_t +internal_function +transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + Idx i; + Idx cur_str_idx = re_string_cur_idx (&mctx->input); + + for (i = 0; i < nodes->nelem; ++i) + { + Idx dest_str_idx, prev_nelem, bkc_idx; + Idx node_idx = nodes->elems[i]; + unsigned int context; + const re_token_t *node = dfa->nodes + node_idx; + re_node_set *new_dest_nodes; + + /* Check whether `node' is a backreference or not. */ + if (node->type != OP_BACK_REF) + continue; + + if (node->constraint) + { + context = re_string_context_at (&mctx->input, cur_str_idx, + mctx->eflags); + if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) + continue; + } + + /* `node' is a backreference. + Check the substring which the substring matched. */ + bkc_idx = mctx->nbkref_ents; + err = get_subexp (mctx, node_idx, cur_str_idx); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + + /* And add the epsilon closures (which is `new_dest_nodes') of + the backreference to appropriate state_log. */ +#ifdef DEBUG + assert (dfa->nexts[node_idx] != REG_MISSING); +#endif + for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx) + { + Idx subexp_len; + re_dfastate_t *dest_state; + struct re_backref_cache_entry *bkref_ent; + bkref_ent = mctx->bkref_ents + bkc_idx; + if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx) + continue; + subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from; + new_dest_nodes = (subexp_len == 0 + ? dfa->eclosures + dfa->edests[node_idx].elems[0] + : dfa->eclosures + dfa->nexts[node_idx]); + dest_str_idx = (cur_str_idx + bkref_ent->subexp_to + - bkref_ent->subexp_from); + context = re_string_context_at (&mctx->input, dest_str_idx - 1, + mctx->eflags); + dest_state = mctx->state_log[dest_str_idx]; + prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0 + : mctx->state_log[cur_str_idx]->nodes.nelem); + /* Add `new_dest_node' to state_log. */ + if (dest_state == NULL) + { + mctx->state_log[dest_str_idx] + = re_acquire_state_context (&err, dfa, new_dest_nodes, + context); + if (BE (mctx->state_log[dest_str_idx] == NULL + && err != REG_NOERROR, 0)) + goto free_return; + } + else + { + re_node_set dest_nodes; + err = re_node_set_init_union (&dest_nodes, + dest_state->entrance_nodes, + new_dest_nodes); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&dest_nodes); + goto free_return; + } + mctx->state_log[dest_str_idx] + = re_acquire_state_context (&err, dfa, &dest_nodes, context); + re_node_set_free (&dest_nodes); + if (BE (mctx->state_log[dest_str_idx] == NULL + && err != REG_NOERROR, 0)) + goto free_return; + } + /* We need to check recursively if the backreference can epsilon + transit. */ + if (subexp_len == 0 + && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem) + { + err = check_subexp_matching_top (mctx, new_dest_nodes, + cur_str_idx); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + err = transit_state_bkref (mctx, new_dest_nodes); + if (BE (err != REG_NOERROR, 0)) + goto free_return; + } + } + } + err = REG_NOERROR; + free_return: + return err; +} + +/* Enumerate all the candidates which the backreference BKREF_NODE can match + at BKREF_STR_IDX, and register them by match_ctx_add_entry(). + Note that we might collect inappropriate candidates here. + However, the cost of checking them strictly here is too high, then we + delay these checking for prune_impossible_nodes(). */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +get_subexp (re_match_context_t *mctx, Idx bkref_node, Idx bkref_str_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + Idx subexp_num, sub_top_idx; + const char *buf = (const char *) re_string_get_buffer (&mctx->input); + /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */ + Idx cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx); + if (cache_idx != REG_MISSING) + { + const struct re_backref_cache_entry *entry + = mctx->bkref_ents + cache_idx; + do + if (entry->node == bkref_node) + return REG_NOERROR; /* We already checked it. */ + while (entry++->more); + } + + subexp_num = dfa->nodes[bkref_node].opr.idx; + + /* For each sub expression */ + for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx) + { + reg_errcode_t err; + re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx]; + re_sub_match_last_t *sub_last; + Idx sub_last_idx, sl_str, bkref_str_off; + + if (dfa->nodes[sub_top->node].opr.idx != subexp_num) + continue; /* It isn't related. */ + + sl_str = sub_top->str_idx; + bkref_str_off = bkref_str_idx; + /* At first, check the last node of sub expressions we already + evaluated. */ + for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx) + { + regoff_t sl_str_diff; + sub_last = sub_top->lasts[sub_last_idx]; + sl_str_diff = sub_last->str_idx - sl_str; + /* The matched string by the sub expression match with the substring + at the back reference? */ + if (sl_str_diff > 0) + { + if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0)) + { + /* Not enough chars for a successful match. */ + if (bkref_str_off + sl_str_diff > mctx->input.len) + break; + + err = clean_state_log_if_needed (mctx, + bkref_str_off + + sl_str_diff); + if (BE (err != REG_NOERROR, 0)) + return err; + buf = (const char *) re_string_get_buffer (&mctx->input); + } + if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0) + /* We don't need to search this sub expression any more. */ + break; + } + bkref_str_off += sl_str_diff; + sl_str += sl_str_diff; + err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node, + bkref_str_idx); + + /* Reload buf, since the preceding call might have reallocated + the buffer. */ + buf = (const char *) re_string_get_buffer (&mctx->input); + + if (err == REG_NOMATCH) + continue; + if (BE (err != REG_NOERROR, 0)) + return err; + } + + if (sub_last_idx < sub_top->nlasts) + continue; + if (sub_last_idx > 0) + ++sl_str; + /* Then, search for the other last nodes of the sub expression. */ + for (; sl_str <= bkref_str_idx; ++sl_str) + { + Idx cls_node; + regoff_t sl_str_off; + const re_node_set *nodes; + sl_str_off = sl_str - sub_top->str_idx; + /* The matched string by the sub expression match with the substring + at the back reference? */ + if (sl_str_off > 0) + { + if (BE (bkref_str_off >= mctx->input.valid_len, 0)) + { + /* If we are at the end of the input, we cannot match. */ + if (bkref_str_off >= mctx->input.len) + break; + + err = extend_buffers (mctx); + if (BE (err != REG_NOERROR, 0)) + return err; + + buf = (const char *) re_string_get_buffer (&mctx->input); + } + if (buf [bkref_str_off++] != buf[sl_str - 1]) + break; /* We don't need to search this sub expression + any more. */ + } + if (mctx->state_log[sl_str] == NULL) + continue; + /* Does this state have a ')' of the sub expression? */ + nodes = &mctx->state_log[sl_str]->nodes; + cls_node = find_subexp_node (dfa, nodes, subexp_num, + OP_CLOSE_SUBEXP); + if (cls_node == REG_MISSING) + continue; /* No. */ + if (sub_top->path == NULL) + { + sub_top->path = calloc (sizeof (state_array_t), + sl_str - sub_top->str_idx + 1); + if (sub_top->path == NULL) + return REG_ESPACE; + } + /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node + in the current context? */ + err = check_arrival (mctx, sub_top->path, sub_top->node, + sub_top->str_idx, cls_node, sl_str, + OP_CLOSE_SUBEXP); + if (err == REG_NOMATCH) + continue; + if (BE (err != REG_NOERROR, 0)) + return err; + sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str); + if (BE (sub_last == NULL, 0)) + return REG_ESPACE; + err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node, + bkref_str_idx); + if (err == REG_NOMATCH) + continue; + } + } + return REG_NOERROR; +} + +/* Helper functions for get_subexp(). */ + +/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR. + If it can arrive, register the sub expression expressed with SUB_TOP + and SUB_LAST. */ + +static reg_errcode_t +internal_function +get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top, + re_sub_match_last_t *sub_last, Idx bkref_node, Idx bkref_str) +{ + reg_errcode_t err; + Idx to_idx; + /* Can the subexpression arrive the back reference? */ + err = check_arrival (mctx, &sub_last->path, sub_last->node, + sub_last->str_idx, bkref_node, bkref_str, + OP_OPEN_SUBEXP); + if (err != REG_NOERROR) + return err; + err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx, + sub_last->str_idx); + if (BE (err != REG_NOERROR, 0)) + return err; + to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx; + return clean_state_log_if_needed (mctx, to_idx); +} + +/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX. + Search '(' if FL_OPEN, or search ')' otherwise. + TODO: This function isn't efficient... + Because there might be more than one nodes whose types are + OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all + nodes. + E.g. RE: (a){2} */ + +static Idx +internal_function +find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, + Idx subexp_idx, int type) +{ + Idx cls_idx; + for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx) + { + Idx cls_node = nodes->elems[cls_idx]; + const re_token_t *node = dfa->nodes + cls_node; + if (node->type == type + && node->opr.idx == subexp_idx) + return cls_node; + } + return REG_MISSING; +} + +/* Check whether the node TOP_NODE at TOP_STR can arrive to the node + LAST_NODE at LAST_STR. We record the path onto PATH since it will be + heavily reused. + Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +check_arrival (re_match_context_t *mctx, state_array_t *path, Idx top_node, + Idx top_str, Idx last_node, Idx last_str, int type) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err = REG_NOERROR; + Idx subexp_num, backup_cur_idx, str_idx, null_cnt; + re_dfastate_t *cur_state = NULL; + re_node_set *cur_nodes, next_nodes; + re_dfastate_t **backup_state_log; + unsigned int context; + + subexp_num = dfa->nodes[top_node].opr.idx; + /* Extend the buffer if we need. */ + if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0)) + { + re_dfastate_t **new_array; + Idx old_alloc = path->alloc; + Idx new_alloc = old_alloc + last_str + mctx->max_mb_elem_len + 1; + if (BE (new_alloc < old_alloc, 0) + || BE (SIZE_MAX / sizeof (re_dfastate_t *) < new_alloc, 0)) + return REG_ESPACE; + new_array = re_realloc (path->array, re_dfastate_t *, new_alloc); + if (BE (new_array == NULL, 0)) + return REG_ESPACE; + path->array = new_array; + path->alloc = new_alloc; + memset (new_array + old_alloc, '\0', + sizeof (re_dfastate_t *) * (path->alloc - old_alloc)); + } + + str_idx = path->next_idx ? path->next_idx : top_str; + + /* Temporary modify MCTX. */ + backup_state_log = mctx->state_log; + backup_cur_idx = mctx->input.cur_idx; + mctx->state_log = path->array; + mctx->input.cur_idx = str_idx; + + /* Setup initial node set. */ + context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags); + if (str_idx == top_str) + { + err = re_node_set_init_1 (&next_nodes, top_node); + if (BE (err != REG_NOERROR, 0)) + return err; + err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + else + { + cur_state = mctx->state_log[str_idx]; + if (cur_state && cur_state->has_backref) + { + err = re_node_set_init_copy (&next_nodes, &cur_state->nodes); + if (BE (err != REG_NOERROR, 0)) + return err; + } + else + re_node_set_init_empty (&next_nodes); + } + if (str_idx == top_str || (cur_state && cur_state->has_backref)) + { + if (next_nodes.nelem) + { + err = expand_bkref_cache (mctx, &next_nodes, str_idx, + subexp_num, type); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); + if (BE (cur_state == NULL && err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + mctx->state_log[str_idx] = cur_state; + } + + for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;) + { + re_node_set_empty (&next_nodes); + if (mctx->state_log[str_idx + 1]) + { + err = re_node_set_merge (&next_nodes, + &mctx->state_log[str_idx + 1]->nodes); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + if (cur_state) + { + err = check_arrival_add_next_nodes (mctx, str_idx, + &cur_state->non_eps_nodes, + &next_nodes); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + ++str_idx; + if (next_nodes.nelem) + { + err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + err = expand_bkref_cache (mctx, &next_nodes, str_idx, + subexp_num, type); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags); + cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); + if (BE (cur_state == NULL && err != REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + mctx->state_log[str_idx] = cur_state; + null_cnt = cur_state == NULL ? null_cnt + 1 : 0; + } + re_node_set_free (&next_nodes); + cur_nodes = (mctx->state_log[last_str] == NULL ? NULL + : &mctx->state_log[last_str]->nodes); + path->next_idx = str_idx; + + /* Fix MCTX. */ + mctx->state_log = backup_state_log; + mctx->input.cur_idx = backup_cur_idx; + + /* Then check the current node set has the node LAST_NODE. */ + if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node)) + return REG_NOERROR; + + return REG_NOMATCH; +} + +/* Helper functions for check_arrival. */ + +/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them + to NEXT_NODES. + TODO: This function is similar to the functions transit_state*(), + however this function has many additional works. + Can't we unify them? */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +check_arrival_add_next_nodes (re_match_context_t *mctx, Idx str_idx, + re_node_set *cur_nodes, re_node_set *next_nodes) +{ + const re_dfa_t *const dfa = mctx->dfa; + bool ok; + Idx cur_idx; +#ifdef RE_ENABLE_I18N + reg_errcode_t err = REG_NOERROR; +#endif + re_node_set union_set; + re_node_set_init_empty (&union_set); + for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx) + { + int naccepted = 0; + Idx cur_node = cur_nodes->elems[cur_idx]; +#ifdef DEBUG + re_token_type_t type = dfa->nodes[cur_node].type; + assert (!IS_EPSILON_NODE (type)); +#endif +#ifdef RE_ENABLE_I18N + /* If the node may accept `multi byte'. */ + if (dfa->nodes[cur_node].accept_mb) + { + naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input, + str_idx); + if (naccepted > 1) + { + re_dfastate_t *dest_state; + Idx next_node = dfa->nexts[cur_node]; + Idx next_idx = str_idx + naccepted; + dest_state = mctx->state_log[next_idx]; + re_node_set_empty (&union_set); + if (dest_state) + { + err = re_node_set_merge (&union_set, &dest_state->nodes); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&union_set); + return err; + } + } + ok = re_node_set_insert (&union_set, next_node); + if (BE (! ok, 0)) + { + re_node_set_free (&union_set); + return REG_ESPACE; + } + mctx->state_log[next_idx] = re_acquire_state (&err, dfa, + &union_set); + if (BE (mctx->state_log[next_idx] == NULL + && err != REG_NOERROR, 0)) + { + re_node_set_free (&union_set); + return err; + } + } + } +#endif /* RE_ENABLE_I18N */ + if (naccepted + || check_node_accept (mctx, dfa->nodes + cur_node, str_idx)) + { + ok = re_node_set_insert (next_nodes, dfa->nexts[cur_node]); + if (BE (! ok, 0)) + { + re_node_set_free (&union_set); + return REG_ESPACE; + } + } + } + re_node_set_free (&union_set); + return REG_NOERROR; +} + +/* For all the nodes in CUR_NODES, add the epsilon closures of them to + CUR_NODES, however exclude the nodes which are: + - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN. + - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN. +*/ + +static reg_errcode_t +internal_function +check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes, + Idx ex_subexp, int type) +{ + reg_errcode_t err; + Idx idx, outside_node; + re_node_set new_nodes; +#ifdef DEBUG + assert (cur_nodes->nelem); +#endif + err = re_node_set_alloc (&new_nodes, cur_nodes->nelem); + if (BE (err != REG_NOERROR, 0)) + return err; + /* Create a new node set NEW_NODES with the nodes which are epsilon + closures of the node in CUR_NODES. */ + + for (idx = 0; idx < cur_nodes->nelem; ++idx) + { + Idx cur_node = cur_nodes->elems[idx]; + const re_node_set *eclosure = dfa->eclosures + cur_node; + outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type); + if (outside_node == REG_MISSING) + { + /* There are no problematic nodes, just merge them. */ + err = re_node_set_merge (&new_nodes, eclosure); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&new_nodes); + return err; + } + } + else + { + /* There are problematic nodes, re-calculate incrementally. */ + err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node, + ex_subexp, type); + if (BE (err != REG_NOERROR, 0)) + { + re_node_set_free (&new_nodes); + return err; + } + } + } + re_node_set_free (cur_nodes); + *cur_nodes = new_nodes; + return REG_NOERROR; +} + +/* Helper function for check_arrival_expand_ecl. + Check incrementally the epsilon closure of TARGET, and if it isn't + problematic append it to DST_NODES. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes, + Idx target, Idx ex_subexp, int type) +{ + Idx cur_node; + for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);) + { + bool ok; + + if (dfa->nodes[cur_node].type == type + && dfa->nodes[cur_node].opr.idx == ex_subexp) + { + if (type == OP_CLOSE_SUBEXP) + { + ok = re_node_set_insert (dst_nodes, cur_node); + if (BE (! ok, 0)) + return REG_ESPACE; + } + break; + } + ok = re_node_set_insert (dst_nodes, cur_node); + if (BE (! ok, 0)) + return REG_ESPACE; + if (dfa->edests[cur_node].nelem == 0) + break; + if (dfa->edests[cur_node].nelem == 2) + { + reg_errcode_t err; + err = check_arrival_expand_ecl_sub (dfa, dst_nodes, + dfa->edests[cur_node].elems[1], + ex_subexp, type); + if (BE (err != REG_NOERROR, 0)) + return err; + } + cur_node = dfa->edests[cur_node].elems[0]; + } + return REG_NOERROR; +} + + +/* For all the back references in the current state, calculate the + destination of the back references by the appropriate entry + in MCTX->BKREF_ENTS. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes, + Idx cur_str, Idx subexp_num, int type) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + Idx cache_idx_start = search_cur_bkref_entry (mctx, cur_str); + struct re_backref_cache_entry *ent; + + if (cache_idx_start == REG_MISSING) + return REG_NOERROR; + + restart: + ent = mctx->bkref_ents + cache_idx_start; + do + { + Idx to_idx, next_node; + + /* Is this entry ENT is appropriate? */ + if (!re_node_set_contains (cur_nodes, ent->node)) + continue; /* No. */ + + to_idx = cur_str + ent->subexp_to - ent->subexp_from; + /* Calculate the destination of the back reference, and append it + to MCTX->STATE_LOG. */ + if (to_idx == cur_str) + { + /* The backreference did epsilon transit, we must re-check all the + node in the current state. */ + re_node_set new_dests; + reg_errcode_t err2, err3; + next_node = dfa->edests[ent->node].elems[0]; + if (re_node_set_contains (cur_nodes, next_node)) + continue; + err = re_node_set_init_1 (&new_dests, next_node); + err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type); + err3 = re_node_set_merge (cur_nodes, &new_dests); + re_node_set_free (&new_dests); + if (BE (err != REG_NOERROR || err2 != REG_NOERROR + || err3 != REG_NOERROR, 0)) + { + err = (err != REG_NOERROR ? err + : (err2 != REG_NOERROR ? err2 : err3)); + return err; + } + /* TODO: It is still inefficient... */ + goto restart; + } + else + { + re_node_set union_set; + next_node = dfa->nexts[ent->node]; + if (mctx->state_log[to_idx]) + { + bool ok; + if (re_node_set_contains (&mctx->state_log[to_idx]->nodes, + next_node)) + continue; + err = re_node_set_init_copy (&union_set, + &mctx->state_log[to_idx]->nodes); + ok = re_node_set_insert (&union_set, next_node); + if (BE (err != REG_NOERROR || ! ok, 0)) + { + re_node_set_free (&union_set); + err = err != REG_NOERROR ? err : REG_ESPACE; + return err; + } + } + else + { + err = re_node_set_init_1 (&union_set, next_node); + if (BE (err != REG_NOERROR, 0)) + return err; + } + mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set); + re_node_set_free (&union_set); + if (BE (mctx->state_log[to_idx] == NULL + && err != REG_NOERROR, 0)) + return err; + } + } + while (ent++->more); + return REG_NOERROR; +} + +/* Build transition table for the state. + Return true if successful. */ + +static bool +internal_function +build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) +{ + reg_errcode_t err; + Idx i, j; + int ch; + bool need_word_trtable = false; + bitset_word_t elem, mask; + bool dests_node_malloced = false; + bool dest_states_malloced = false; + Idx ndests; /* Number of the destination states from `state'. */ + re_dfastate_t **trtable; + re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl; + re_node_set follows, *dests_node; + bitset_t *dests_ch; + bitset_t acceptable; + + struct dests_alloc + { + re_node_set dests_node[SBC_MAX]; + bitset_t dests_ch[SBC_MAX]; + } *dests_alloc; + + /* We build DFA states which corresponds to the destination nodes + from `state'. `dests_node[i]' represents the nodes which i-th + destination state contains, and `dests_ch[i]' represents the + characters which i-th destination state accepts. */ + if (__libc_use_alloca (sizeof (struct dests_alloc))) + dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc)); + else + { + dests_alloc = re_malloc (struct dests_alloc, 1); + if (BE (dests_alloc == NULL, 0)) + return false; + dests_node_malloced = true; + } + dests_node = dests_alloc->dests_node; + dests_ch = dests_alloc->dests_ch; + + /* Initialize transiton table. */ + state->word_trtable = state->trtable = NULL; + + /* At first, group all nodes belonging to `state' into several + destinations. */ + ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch); + if (BE (! REG_VALID_NONZERO_INDEX (ndests), 0)) + { + if (dests_node_malloced) + free (dests_alloc); + if (ndests == 0) + { + state->trtable = (re_dfastate_t **) + calloc (sizeof (re_dfastate_t *), SBC_MAX); + return true; + } + return false; + } + + err = re_node_set_alloc (&follows, ndests + 1); + if (BE (err != REG_NOERROR, 0)) + goto out_free; + + /* Avoid arithmetic overflow in size calculation. */ + if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX) + / (3 * sizeof (re_dfastate_t *))) + < ndests), + 0)) + goto out_free; + + if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX + + ndests * 3 * sizeof (re_dfastate_t *))) + dest_states = (re_dfastate_t **) + alloca (ndests * 3 * sizeof (re_dfastate_t *)); + else + { + dest_states = (re_dfastate_t **) + malloc (ndests * 3 * sizeof (re_dfastate_t *)); + if (BE (dest_states == NULL, 0)) + { +out_free: + if (dest_states_malloced) + free (dest_states); + re_node_set_free (&follows); + for (i = 0; i < ndests; ++i) + re_node_set_free (dests_node + i); + if (dests_node_malloced) + free (dests_alloc); + return false; + } + dest_states_malloced = true; + } + dest_states_word = dest_states + ndests; + dest_states_nl = dest_states_word + ndests; + bitset_empty (acceptable); + + /* Then build the states for all destinations. */ + for (i = 0; i < ndests; ++i) + { + Idx next_node; + re_node_set_empty (&follows); + /* Merge the follows of this destination states. */ + for (j = 0; j < dests_node[i].nelem; ++j) + { + next_node = dfa->nexts[dests_node[i].elems[j]]; + if (next_node != REG_MISSING) + { + err = re_node_set_merge (&follows, dfa->eclosures + next_node); + if (BE (err != REG_NOERROR, 0)) + goto out_free; + } + } + dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0); + if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0)) + goto out_free; + /* If the new state has context constraint, + build appropriate states for these contexts. */ + if (dest_states[i]->has_constraint) + { + dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows, + CONTEXT_WORD); + if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0)) + goto out_free; + + if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1) + need_word_trtable = true; + + dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, + CONTEXT_NEWLINE); + if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0)) + goto out_free; + } + else + { + dest_states_word[i] = dest_states[i]; + dest_states_nl[i] = dest_states[i]; + } + bitset_merge (acceptable, dests_ch[i]); + } + + if (!BE (need_word_trtable, 0)) + { + /* We don't care about whether the following character is a word + character, or we are in a single-byte character set so we can + discern by looking at the character code: allocate a + 256-entry transition table. */ + trtable = state->trtable = + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); + if (BE (trtable == NULL, 0)) + goto out_free; + + /* For all characters ch...: */ + for (i = 0; i < BITSET_WORDS; ++i) + for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; + elem; + mask <<= 1, elem >>= 1, ++ch) + if (BE (elem & 1, 0)) + { + /* There must be exactly one destination which accepts + character ch. See group_nodes_into_DFAstates. */ + for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) + ; + + /* j-th destination accepts the word character ch. */ + if (dfa->word_char[i] & mask) + trtable[ch] = dest_states_word[j]; + else + trtable[ch] = dest_states[j]; + } + } + else + { + /* We care about whether the following character is a word + character, and we are in a multi-byte character set: discern + by looking at the character code: build two 256-entry + transition tables, one starting at trtable[0] and one + starting at trtable[SBC_MAX]. */ + trtable = state->word_trtable = + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); + if (BE (trtable == NULL, 0)) + goto out_free; + + /* For all characters ch...: */ + for (i = 0; i < BITSET_WORDS; ++i) + for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; + elem; + mask <<= 1, elem >>= 1, ++ch) + if (BE (elem & 1, 0)) + { + /* There must be exactly one destination which accepts + character ch. See group_nodes_into_DFAstates. */ + for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) + ; + + /* j-th destination accepts the word character ch. */ + trtable[ch] = dest_states[j]; + trtable[ch + SBC_MAX] = dest_states_word[j]; + } + } + + /* new line */ + if (bitset_contain (acceptable, NEWLINE_CHAR)) + { + /* The current state accepts newline character. */ + for (j = 0; j < ndests; ++j) + if (bitset_contain (dests_ch[j], NEWLINE_CHAR)) + { + /* k-th destination accepts newline character. */ + trtable[NEWLINE_CHAR] = dest_states_nl[j]; + if (need_word_trtable) + trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j]; + /* There must be only one destination which accepts + newline. See group_nodes_into_DFAstates. */ + break; + } + } + + if (dest_states_malloced) + free (dest_states); + + re_node_set_free (&follows); + for (i = 0; i < ndests; ++i) + re_node_set_free (dests_node + i); + + if (dests_node_malloced) + free (dests_alloc); + + return true; +} + +/* Group all nodes belonging to STATE into several destinations. + Then for all destinations, set the nodes belonging to the destination + to DESTS_NODE[i] and set the characters accepted by the destination + to DEST_CH[i]. This function return the number of destinations. */ + +static Idx +internal_function +group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, + re_node_set *dests_node, bitset_t *dests_ch) +{ + reg_errcode_t err; + bool ok; + Idx i, j, k; + Idx ndests; /* Number of the destinations from `state'. */ + bitset_t accepts; /* Characters a node can accept. */ + const re_node_set *cur_nodes = &state->nodes; + bitset_empty (accepts); + ndests = 0; + + /* For all the nodes belonging to `state', */ + for (i = 0; i < cur_nodes->nelem; ++i) + { + re_token_t *node = &dfa->nodes[cur_nodes->elems[i]]; + re_token_type_t type = node->type; + unsigned int constraint = node->constraint; + + /* Enumerate all single byte character this node can accept. */ + if (type == CHARACTER) + bitset_set (accepts, node->opr.c); + else if (type == SIMPLE_BRACKET) + { + bitset_merge (accepts, node->opr.sbcset); + } + else if (type == OP_PERIOD) + { +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + bitset_merge (accepts, dfa->sb_char); + else +#endif + bitset_set_all (accepts); + if (!(dfa->syntax & RE_DOT_NEWLINE)) + bitset_clear (accepts, '\n'); + if (dfa->syntax & RE_DOT_NOT_NULL) + bitset_clear (accepts, '\0'); + } +#ifdef RE_ENABLE_I18N + else if (type == OP_UTF8_PERIOD) + { + if (ASCII_CHARS % BITSET_WORD_BITS == 0) + memset (accepts, -1, ASCII_CHARS / CHAR_BIT); + else + bitset_merge (accepts, utf8_sb_map); + if (!(dfa->syntax & RE_DOT_NEWLINE)) + bitset_clear (accepts, '\n'); + if (dfa->syntax & RE_DOT_NOT_NULL) + bitset_clear (accepts, '\0'); + } +#endif + else + continue; + + /* Check the `accepts' and sift the characters which are not + match it the context. */ + if (constraint) + { + if (constraint & NEXT_NEWLINE_CONSTRAINT) + { + bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); + bitset_empty (accepts); + if (accepts_newline) + bitset_set (accepts, NEWLINE_CHAR); + else + continue; + } + if (constraint & NEXT_ENDBUF_CONSTRAINT) + { + bitset_empty (accepts); + continue; + } + + if (constraint & NEXT_WORD_CONSTRAINT) + { + bitset_word_t any_set = 0; + if (type == CHARACTER && !node->word_char) + { + bitset_empty (accepts); + continue; + } +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + for (j = 0; j < BITSET_WORDS; ++j) + any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j])); + else +#endif + for (j = 0; j < BITSET_WORDS; ++j) + any_set |= (accepts[j] &= dfa->word_char[j]); + if (!any_set) + continue; + } + if (constraint & NEXT_NOTWORD_CONSTRAINT) + { + bitset_word_t any_set = 0; + if (type == CHARACTER && node->word_char) + { + bitset_empty (accepts); + continue; + } +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + for (j = 0; j < BITSET_WORDS; ++j) + any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j])); + else +#endif + for (j = 0; j < BITSET_WORDS; ++j) + any_set |= (accepts[j] &= ~dfa->word_char[j]); + if (!any_set) + continue; + } + } + + /* Then divide `accepts' into DFA states, or create a new + state. Above, we make sure that accepts is not empty. */ + for (j = 0; j < ndests; ++j) + { + bitset_t intersec; /* Intersection sets, see below. */ + bitset_t remains; + /* Flags, see below. */ + bitset_word_t has_intersec, not_subset, not_consumed; + + /* Optimization, skip if this state doesn't accept the character. */ + if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c)) + continue; + + /* Enumerate the intersection set of this state and `accepts'. */ + has_intersec = 0; + for (k = 0; k < BITSET_WORDS; ++k) + has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k]; + /* And skip if the intersection set is empty. */ + if (!has_intersec) + continue; + + /* Then check if this state is a subset of `accepts'. */ + not_subset = not_consumed = 0; + for (k = 0; k < BITSET_WORDS; ++k) + { + not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k]; + not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k]; + } + + /* If this state isn't a subset of `accepts', create a + new group state, which has the `remains'. */ + if (not_subset) + { + bitset_copy (dests_ch[ndests], remains); + bitset_copy (dests_ch[j], intersec); + err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]); + if (BE (err != REG_NOERROR, 0)) + goto error_return; + ++ndests; + } + + /* Put the position in the current group. */ + ok = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]); + if (BE (! ok, 0)) + goto error_return; + + /* If all characters are consumed, go to next node. */ + if (!not_consumed) + break; + } + /* Some characters remain, create a new group. */ + if (j == ndests) + { + bitset_copy (dests_ch[ndests], accepts); + err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]); + if (BE (err != REG_NOERROR, 0)) + goto error_return; + ++ndests; + bitset_empty (accepts); + } + } + return ndests; + error_return: + for (j = 0; j < ndests; ++j) + re_node_set_free (dests_node + j); + return REG_MISSING; +} + +#ifdef RE_ENABLE_I18N +/* Check how many bytes the node `dfa->nodes[node_idx]' accepts. + Return the number of the bytes the node accepts. + STR_IDX is the current index of the input string. + + This function handles the nodes which can accept one character, or + one collating element like '.', '[a-z]', opposite to the other nodes + can only accept one byte. */ + +static int +internal_function +check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx, + const re_string_t *input, Idx str_idx) +{ + const re_token_t *node = dfa->nodes + node_idx; + int char_len, elem_len; + Idx i; + + if (BE (node->type == OP_UTF8_PERIOD, 0)) + { + unsigned char c = re_string_byte_at (input, str_idx), d; + if (BE (c < 0xc2, 1)) + return 0; + + if (str_idx + 2 > input->len) + return 0; + + d = re_string_byte_at (input, str_idx + 1); + if (c < 0xe0) + return (d < 0x80 || d > 0xbf) ? 0 : 2; + else if (c < 0xf0) + { + char_len = 3; + if (c == 0xe0 && d < 0xa0) + return 0; + } + else if (c < 0xf8) + { + char_len = 4; + if (c == 0xf0 && d < 0x90) + return 0; + } + else if (c < 0xfc) + { + char_len = 5; + if (c == 0xf8 && d < 0x88) + return 0; + } + else if (c < 0xfe) + { + char_len = 6; + if (c == 0xfc && d < 0x84) + return 0; + } + else + return 0; + + if (str_idx + char_len > input->len) + return 0; + + for (i = 1; i < char_len; ++i) + { + d = re_string_byte_at (input, str_idx + i); + if (d < 0x80 || d > 0xbf) + return 0; + } + return char_len; + } + + char_len = re_string_char_size_at (input, str_idx); + if (node->type == OP_PERIOD) + { + if (char_len <= 1) + return 0; + /* FIXME: I don't think this if is needed, as both '\n' + and '\0' are char_len == 1. */ + /* '.' accepts any one character except the following two cases. */ + if ((!(dfa->syntax & RE_DOT_NEWLINE) && + re_string_byte_at (input, str_idx) == '\n') || + ((dfa->syntax & RE_DOT_NOT_NULL) && + re_string_byte_at (input, str_idx) == '\0')) + return 0; + return char_len; + } + + elem_len = re_string_elem_size_at (input, str_idx); + if ((elem_len <= 1 && char_len <= 1) || char_len == 0) + return 0; + + if (node->type == COMPLEX_BRACKET) + { + const re_charset_t *cset = node->opr.mbcset; +# ifdef _LIBC + const unsigned char *pin + = ((const unsigned char *) re_string_get_buffer (input) + str_idx); + Idx j; + uint32_t nrules; +# endif /* _LIBC */ + int match_len = 0; + wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars) + ? re_string_wchar_at (input, str_idx) : 0); + + /* match with multibyte character? */ + for (i = 0; i < cset->nmbchars; ++i) + if (wc == cset->mbchars[i]) + { + match_len = char_len; + goto check_node_accept_bytes_match; + } + /* match with character_class? */ + for (i = 0; i < cset->nchar_classes; ++i) + { + wctype_t wt = cset->char_classes[i]; + if (__iswctype (wc, wt)) + { + match_len = char_len; + goto check_node_accept_bytes_match; + } + } + +# ifdef _LIBC + nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + if (nrules != 0) + { + unsigned int in_collseq = 0; + const int32_t *table, *indirect; + const unsigned char *weights, *extra; + const char *collseqwc; + int32_t idx; + /* This #include defines a local function! */ +# include + + /* match with collating_symbol? */ + if (cset->ncoll_syms) + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); + for (i = 0; i < cset->ncoll_syms; ++i) + { + const unsigned char *coll_sym = extra + cset->coll_syms[i]; + /* Compare the length of input collating element and + the length of current collating element. */ + if (*coll_sym != elem_len) + continue; + /* Compare each bytes. */ + for (j = 0; j < *coll_sym; j++) + if (pin[j] != coll_sym[1 + j]) + break; + if (j == *coll_sym) + { + /* Match if every bytes is equal. */ + match_len = j; + goto check_node_accept_bytes_match; + } + } + + if (cset->nranges) + { + if (elem_len <= char_len) + { + collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); + in_collseq = __collseq_table_lookup (collseqwc, wc); + } + else + in_collseq = find_collation_sequence_value (pin, elem_len); + } + /* match with range expression? */ + for (i = 0; i < cset->nranges; ++i) + if (cset->range_starts[i] <= in_collseq + && in_collseq <= cset->range_ends[i]) + { + match_len = elem_len; + goto check_node_accept_bytes_match; + } + + /* match with equivalence_class? */ + if (cset->nequiv_classes) + { + const unsigned char *cp = pin; + table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); + weights = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); + indirect = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); + int32_t idx = findidx (&cp); + if (idx > 0) + for (i = 0; i < cset->nequiv_classes; ++i) + { + int32_t equiv_class_idx = cset->equiv_classes[i]; + size_t weight_len = weights[idx & 0xffffff]; + if (weight_len == weights[equiv_class_idx & 0xffffff] + && (idx >> 24) == (equiv_class_idx >> 24)) + { + Idx cnt = 0; + + idx &= 0xffffff; + equiv_class_idx &= 0xffffff; + + while (cnt <= weight_len + && (weights[equiv_class_idx + 1 + cnt] + == weights[idx + 1 + cnt])) + ++cnt; + if (cnt > weight_len) + { + match_len = elem_len; + goto check_node_accept_bytes_match; + } + } + } + } + } + else +# endif /* _LIBC */ + { + /* match with range expression? */ +#if __GNUC__ >= 2 && ! (__STDC_VERSION__ < 199901L && __STRICT_ANSI__) + wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'}; +#else + wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; + cmp_buf[2] = wc; +#endif + for (i = 0; i < cset->nranges; ++i) + { + cmp_buf[0] = cset->range_starts[i]; + cmp_buf[4] = cset->range_ends[i]; + if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 + && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) + { + match_len = char_len; + goto check_node_accept_bytes_match; + } + } + } + check_node_accept_bytes_match: + if (!cset->non_match) + return match_len; + else + { + if (match_len > 0) + return 0; + else + return (elem_len > char_len) ? elem_len : char_len; + } + } + return 0; +} + +# ifdef _LIBC +static unsigned int +internal_function +find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len) +{ + uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + if (nrules == 0) + { + if (mbs_len == 1) + { + /* No valid character. Match it as a single byte character. */ + const unsigned char *collseq = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); + return collseq[mbs[0]]; + } + return UINT_MAX; + } + else + { + int32_t idx; + const unsigned char *extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); + int32_t extrasize = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra; + + for (idx = 0; idx < extrasize;) + { + int mbs_cnt; + bool found = false; + int32_t elem_mbs_len; + /* Skip the name of collating element name. */ + idx = idx + extra[idx] + 1; + elem_mbs_len = extra[idx++]; + if (mbs_len == elem_mbs_len) + { + for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt) + if (extra[idx + mbs_cnt] != mbs[mbs_cnt]) + break; + if (mbs_cnt == elem_mbs_len) + /* Found the entry. */ + found = true; + } + /* Skip the byte sequence of the collating element. */ + idx += elem_mbs_len; + /* Adjust for the alignment. */ + idx = (idx + 3) & ~3; + /* Skip the collation sequence value. */ + idx += sizeof (uint32_t); + /* Skip the wide char sequence of the collating element. */ + idx = idx + sizeof (uint32_t) * (extra[idx] + 1); + /* If we found the entry, return the sequence value. */ + if (found) + return *(uint32_t *) (extra + idx); + /* Skip the collation sequence value. */ + idx += sizeof (uint32_t); + } + return UINT_MAX; + } +} +# endif /* _LIBC */ +#endif /* RE_ENABLE_I18N */ + +/* Check whether the node accepts the byte which is IDX-th + byte of the INPUT. */ + +static bool +internal_function +check_node_accept (const re_match_context_t *mctx, const re_token_t *node, + Idx idx) +{ + unsigned char ch; + ch = re_string_byte_at (&mctx->input, idx); + switch (node->type) + { + case CHARACTER: + if (node->opr.c != ch) + return false; + break; + + case SIMPLE_BRACKET: + if (!bitset_contain (node->opr.sbcset, ch)) + return false; + break; + +#ifdef RE_ENABLE_I18N + case OP_UTF8_PERIOD: + if (ch >= ASCII_CHARS) + return false; + /* FALLTHROUGH */ +#endif + case OP_PERIOD: + if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE)) + || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL))) + return false; + break; + + default: + return false; + } + + if (node->constraint) + { + /* The node has constraints. Check whether the current context + satisfies the constraints. */ + unsigned int context = re_string_context_at (&mctx->input, idx, + mctx->eflags); + if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) + return false; + } + + return true; +} + +/* Extend the buffers, if the buffers have run out. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +extend_buffers (re_match_context_t *mctx) +{ + reg_errcode_t ret; + re_string_t *pstr = &mctx->input; + + /* Avoid overflow. */ + if (BE (SIZE_MAX / 2 / sizeof (re_dfastate_t *) <= pstr->bufs_len, 0)) + return REG_ESPACE; + + /* Double the lengthes of the buffers. */ + ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); + if (BE (ret != REG_NOERROR, 0)) + return ret; + + if (mctx->state_log != NULL) + { + /* And double the length of state_log. */ + /* XXX We have no indication of the size of this buffer. If this + allocation fail we have no indication that the state_log array + does not have the right size. */ + re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *, + pstr->bufs_len + 1); + if (BE (new_array == NULL, 0)) + return REG_ESPACE; + mctx->state_log = new_array; + } + + /* Then reconstruct the buffers. */ + if (pstr->icase) + { +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + { + ret = build_wcs_upper_buffer (pstr); + if (BE (ret != REG_NOERROR, 0)) + return ret; + } + else +#endif /* RE_ENABLE_I18N */ + build_upper_buffer (pstr); + } + else + { +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + build_wcs_buffer (pstr); + else +#endif /* RE_ENABLE_I18N */ + { + if (pstr->trans != NULL) + re_string_translate_buffer (pstr); + } + } + return REG_NOERROR; +} + + +/* Functions for matching context. */ + +/* Initialize MCTX. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +match_ctx_init (re_match_context_t *mctx, int eflags, Idx n) +{ + mctx->eflags = eflags; + mctx->match_last = REG_MISSING; + if (n > 0) + { + /* Avoid overflow. */ + size_t max_object_size = + MAX (sizeof (struct re_backref_cache_entry), + sizeof (re_sub_match_top_t *)); + if (BE (SIZE_MAX / max_object_size < n, 0)) + return REG_ESPACE; + + mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n); + mctx->sub_tops = re_malloc (re_sub_match_top_t *, n); + if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0)) + return REG_ESPACE; + } + /* Already zero-ed by the caller. + else + mctx->bkref_ents = NULL; + mctx->nbkref_ents = 0; + mctx->nsub_tops = 0; */ + mctx->abkref_ents = n; + mctx->max_mb_elem_len = 1; + mctx->asub_tops = n; + return REG_NOERROR; +} + +/* Clean the entries which depend on the current input in MCTX. + This function must be invoked when the matcher changes the start index + of the input, or changes the input string. */ + +static void +internal_function +match_ctx_clean (re_match_context_t *mctx) +{ + Idx st_idx; + for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx) + { + Idx sl_idx; + re_sub_match_top_t *top = mctx->sub_tops[st_idx]; + for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx) + { + re_sub_match_last_t *last = top->lasts[sl_idx]; + re_free (last->path.array); + re_free (last); + } + re_free (top->lasts); + if (top->path) + { + re_free (top->path->array); + re_free (top->path); + } + free (top); + } + + mctx->nsub_tops = 0; + mctx->nbkref_ents = 0; +} + +/* Free all the memory associated with MCTX. */ + +static void +internal_function +match_ctx_free (re_match_context_t *mctx) +{ + /* First, free all the memory associated with MCTX->SUB_TOPS. */ + match_ctx_clean (mctx); + re_free (mctx->sub_tops); + re_free (mctx->bkref_ents); +} + +/* Add a new backreference entry to MCTX. + Note that we assume that caller never call this function with duplicate + entry, and call with STR_IDX which isn't smaller than any existing entry. +*/ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +match_ctx_add_entry (re_match_context_t *mctx, Idx node, Idx str_idx, Idx from, + Idx to) +{ + if (mctx->nbkref_ents >= mctx->abkref_ents) + { + struct re_backref_cache_entry* new_entry; + new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry, + mctx->abkref_ents * 2); + if (BE (new_entry == NULL, 0)) + { + re_free (mctx->bkref_ents); + return REG_ESPACE; + } + mctx->bkref_ents = new_entry; + memset (mctx->bkref_ents + mctx->nbkref_ents, '\0', + sizeof (struct re_backref_cache_entry) * mctx->abkref_ents); + mctx->abkref_ents *= 2; + } + if (mctx->nbkref_ents > 0 + && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx) + mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1; + + mctx->bkref_ents[mctx->nbkref_ents].node = node; + mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx; + mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from; + mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to; + + /* This is a cache that saves negative results of check_dst_limits_calc_pos. + If bit N is clear, means that this entry won't epsilon-transition to + an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If + it is set, check_dst_limits_calc_pos_1 will recurse and try to find one + such node. + + A backreference does not epsilon-transition unless it is empty, so set + to all zeros if FROM != TO. */ + mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map + = (from == to ? -1 : 0); + + mctx->bkref_ents[mctx->nbkref_ents++].more = 0; + if (mctx->max_mb_elem_len < to - from) + mctx->max_mb_elem_len = to - from; + return REG_NOERROR; +} + +/* Return the first entry with the same str_idx, or REG_MISSING if none is + found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */ + +static Idx +internal_function +search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx) +{ + Idx left, right, mid, last; + last = right = mctx->nbkref_ents; + for (left = 0; left < right;) + { + mid = (left + right) / 2; + if (mctx->bkref_ents[mid].str_idx < str_idx) + left = mid + 1; + else + right = mid; + } + if (left < last && mctx->bkref_ents[left].str_idx == str_idx) + return left; + else + return REG_MISSING; +} + +/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches + at STR_IDX. */ + +static reg_errcode_t +internal_function __attribute_warn_unused_result__ +match_ctx_add_subtop (re_match_context_t *mctx, Idx node, Idx str_idx) +{ +#ifdef DEBUG + assert (mctx->sub_tops != NULL); + assert (mctx->asub_tops > 0); +#endif + if (BE (mctx->nsub_tops == mctx->asub_tops, 0)) + { + Idx new_asub_tops = mctx->asub_tops * 2; + re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops, + re_sub_match_top_t *, + new_asub_tops); + if (BE (new_array == NULL, 0)) + return REG_ESPACE; + mctx->sub_tops = new_array; + mctx->asub_tops = new_asub_tops; + } + mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t)); + if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0)) + return REG_ESPACE; + mctx->sub_tops[mctx->nsub_tops]->node = node; + mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx; + return REG_NOERROR; +} + +/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches + at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ + +static re_sub_match_last_t * +internal_function +match_ctx_add_sublast (re_sub_match_top_t *subtop, Idx node, Idx str_idx) +{ + re_sub_match_last_t *new_entry; + if (BE (subtop->nlasts == subtop->alasts, 0)) + { + Idx new_alasts = 2 * subtop->alasts + 1; + re_sub_match_last_t **new_array = re_realloc (subtop->lasts, + re_sub_match_last_t *, + new_alasts); + if (BE (new_array == NULL, 0)) + return NULL; + subtop->lasts = new_array; + subtop->alasts = new_alasts; + } + new_entry = calloc (1, sizeof (re_sub_match_last_t)); + if (BE (new_entry != NULL, 1)) + { + subtop->lasts[subtop->nlasts] = new_entry; + new_entry->node = node; + new_entry->str_idx = str_idx; + ++subtop->nlasts; + } + return new_entry; +} + +static void +internal_function +sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, + re_dfastate_t **limited_sts, Idx last_node, Idx last_str_idx) +{ + sctx->sifted_states = sifted_sts; + sctx->limited_states = limited_sts; + sctx->last_node = last_node; + sctx->last_str_idx = last_str_idx; + re_node_set_init_empty (&sctx->limits); +} diff --git a/hello/hello.c b/hello/hello.c index be60761ec..eff07d941 100644 --- a/hello/hello.c +++ b/hello/hello.c @@ -24,6 +24,7 @@ #include #include #include +#include static grub_err_t grub_cmd_hello (struct grub_extcmd *cmd __attribute__ ((unused)), @@ -39,7 +40,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(hello) { cmd = grub_register_extcmd ("hello", grub_cmd_hello, GRUB_COMMAND_FLAG_BOTH, - "hello", "Say hello", 0); + 0, N_("Say \"Hello World\"."), 0); } GRUB_MOD_FINI(hello) diff --git a/hook/datehook.c b/hook/datehook.c index b7663cc21..9b5b54bf3 100644 --- a/hook/datehook.c +++ b/hook/datehook.c @@ -76,7 +76,7 @@ grub_read_hook_datetime (struct grub_env_var *var, return grub_get_weekday_name (&datetime); } - grub_sprintf (buf, "%d", n); + grub_snprintf (buf, sizeof (buf), "%d", n); break; } } @@ -84,7 +84,7 @@ grub_read_hook_datetime (struct grub_env_var *var, return buf; } -GRUB_MOD_INIT(datetime) +GRUB_MOD_INIT(datehook) { int i; @@ -93,7 +93,7 @@ GRUB_MOD_INIT(datetime) grub_read_hook_datetime, 0); } -GRUB_MOD_FINI(datetime) +GRUB_MOD_FINI(datehook) { int i; diff --git a/include/grub/aout.h b/include/grub/aout.h index c5650ddf8..f962a97b3 100644 --- a/include/grub/aout.h +++ b/include/grub/aout.h @@ -16,6 +16,38 @@ * along with GRUB. If not, see . */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)exec.h 8.1 (Berkeley) 6/11/93 + * $FreeBSD$ + */ + #ifndef GRUB_AOUT_HEADER #define GRUB_AOUT_HEADER 1 @@ -70,6 +102,7 @@ union grub_aout_header #define AOUT_MID_I386 134 /* i386 BSD binary */ #define AOUT_MID_SPARC 138 /* sparc */ #define AOUT_MID_HP200 200 /* hp200 (68010) BSD binary */ +#define AOUT_MID_SUN 0x103 #define AOUT_MID_HP300 300 /* hp300 (68020+68881) BSD binary */ #define AOUT_MID_HPUX 0x20C /* hp200/300 HP-UX binary */ #define AOUT_MID_HPUX800 0x20B /* hp800 HP-UX binary */ @@ -82,10 +115,14 @@ union grub_aout_header #define AOUT_GETMID(header) ((header).a_midmag >> 16) & 0x03ff) #define AOUT_GETFLAG(header) ((header).a_midmag >> 26) & 0x3f) +#ifndef GRUB_UTIL + int EXPORT_FUNC(grub_aout_get_type) (union grub_aout_header *header); grub_err_t EXPORT_FUNC(grub_aout_load) (grub_file_t file, int offset, grub_addr_t load_addr, int load_size, grub_addr_t bss_end_addr); +#endif + #endif /* ! GRUB_AOUT_HEADER */ diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h new file mode 100644 index 000000000..10421540a --- /dev/null +++ b/include/grub/at_keyboard.h @@ -0,0 +1,54 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007,2008,2009 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 . + */ + +#ifndef GRUB_AT_KEYBOARD_HEADER +#define GRUB_AT_KEYBOARD_HEADER 1 + +#define SHIFT_L 0x2a +#define SHIFT_R 0x36 +#define CTRL 0x1d +#define ALT 0x38 +#define CAPS_LOCK 0x3a +#define NUM_LOCK 0x45 +#define SCROLL_LOCK 0x46 + +/* Used for sending commands to the controller. */ +#define KEYBOARD_COMMAND_ISREADY(x) !((x) & 0x02) +#define KEYBOARD_COMMAND_READ 0x20 +#define KEYBOARD_COMMAND_WRITE 0x60 +#define KEYBOARD_COMMAND_REBOOT 0xfe + +#define KEYBOARD_SCANCODE_SET1 0x40 + +#define KEYBOARD_ISMAKE(x) !((x) & 0x80) +#define KEYBOARD_ISREADY(x) ((x) & 0x01) +#define KEYBOARD_SCANCODE(x) ((x) & 0x7f) + +#ifdef GRUB_MACHINE_IEEE1275 +#define OLPC_UP GRUB_TERM_UP +#define OLPC_DOWN GRUB_TERM_DOWN +#define OLPC_LEFT GRUB_TERM_LEFT +#define OLPC_RIGHT GRUB_TERM_RIGHT +#else +#define OLPC_UP '\0' +#define OLPC_DOWN '\0' +#define OLPC_LEFT '\0' +#define OLPC_RIGHT '\0' +#endif + +#endif diff --git a/include/grub/ata.h b/include/grub/ata.h index aaa2e147a..940e67102 100644 --- a/include/grub/ata.h +++ b/include/grub/ata.h @@ -98,8 +98,8 @@ struct grub_ata_device /* IO addresses on which the registers for this device can be found. */ - int ioaddress; - int ioaddress2; + grub_port_t ioaddress; + grub_port_t ioaddress2; /* Two devices can be connected to a single cable. Use this field to select device 0 (commonly known as "master") or device 1 diff --git a/include/grub/auth.h b/include/grub/auth.h index da930eeda..747334451 100644 --- a/include/grub/auth.h +++ b/include/grub/auth.h @@ -15,23 +15,15 @@ * You should have received a copy of the GNU General Public License * along with GRUB. If not, see . */ -#ifndef GRUB_AURH_HEADER +#ifndef GRUB_AUTH_HEADER #define GRUB_AUTH_HEADER 1 #include +#include -/* Macros for indistinguishibility. */ -#define GRUB_ACCESS_DENIED grub_error (GRUB_ERR_ACCESS_DENIED, "Access denied.") -#define GRUB_GET_PASSWORD(string, len) grub_cmdline_get ("Enter password: ", \ - string, len, \ - '*', 0, 0) +#define GRUB_AUTH_MAX_PASSLEN 1024 -/* Like strcmp but untimeable. Accepts NULL as second argument. */ -int grub_auth_strcmp (const char *user_input, const char *template); -/* Like strcmp but untimeable and ignores commas in needle. */ -int grub_auth_strword (const char *haystack, const char *needle); - -typedef grub_err_t (*grub_auth_callback_t) (const char*, void *); +typedef grub_err_t (*grub_auth_callback_t) (const char *, const char *, void *); grub_err_t grub_auth_register_authentication (const char *user, grub_auth_callback_t callback, diff --git a/include/grub/autoefi.h b/include/grub/autoefi.h index b151cfc37..5ae4b3a21 100644 --- a/include/grub/autoefi.h +++ b/include/grub/autoefi.h @@ -26,8 +26,10 @@ # include # define grub_autoefi_get_memory_map grub_efi_get_memory_map # define grub_autoefi_finish_boot_services grub_efi_finish_boot_services +# define grub_autoefi_exit_boot_services grub_efi_exit_boot_services # define grub_autoefi_system_table grub_efi_system_table # define grub_autoefi_mmap_iterate grub_machine_mmap_iterate +# define grub_autoefi_set_virtual_address_map grub_efi_set_virtual_address_map static inline grub_err_t grub_autoefi_prepare (void) { return GRUB_ERR_NONE; @@ -53,9 +55,11 @@ static inline grub_err_t grub_autoefi_prepare (void) # include # define grub_autoefi_get_memory_map grub_efiemu_get_memory_map # define grub_autoefi_finish_boot_services grub_efiemu_finish_boot_services +# define grub_autoefi_exit_boot_services grub_efiemu_exit_boot_services # define grub_autoefi_system_table grub_efiemu_system_table # define grub_autoefi_mmap_iterate grub_efiemu_mmap_iterate # define grub_autoefi_prepare grub_efiemu_prepare +# define grub_autoefi_set_virtual_address_map grub_efiemu_set_virtual_address_map # define GRUB_AUTOEFI_MEMORY_AVAILABLE GRUB_EFIEMU_MEMORY_AVAILABLE # define GRUB_AUTOEFI_MEMORY_RESERVED GRUB_EFIEMU_MEMORY_RESERVED # define GRUB_AUTOEFI_MEMORY_ACPI GRUB_EFIEMU_MEMORY_ACPI diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h index 42c439d69..6e300391a 100644 --- a/include/grub/bitmap.h +++ b/include/grub/bitmap.h @@ -47,24 +47,24 @@ struct grub_video_bitmap_reader }; typedef struct grub_video_bitmap_reader *grub_video_bitmap_reader_t; -void grub_video_bitmap_reader_register (grub_video_bitmap_reader_t reader); -void grub_video_bitmap_reader_unregister (grub_video_bitmap_reader_t reader); +void EXPORT_FUNC (grub_video_bitmap_reader_register) (grub_video_bitmap_reader_t reader); +void EXPORT_FUNC (grub_video_bitmap_reader_unregister) (grub_video_bitmap_reader_t reader); -grub_err_t grub_video_bitmap_create (struct grub_video_bitmap **bitmap, - unsigned int width, unsigned int height, - enum grub_video_blit_format blit_format); +grub_err_t EXPORT_FUNC (grub_video_bitmap_create) (struct grub_video_bitmap **bitmap, + unsigned int width, unsigned int height, + enum grub_video_blit_format blit_format); -grub_err_t grub_video_bitmap_destroy (struct grub_video_bitmap *bitmap); +grub_err_t EXPORT_FUNC (grub_video_bitmap_destroy) (struct grub_video_bitmap *bitmap); -grub_err_t grub_video_bitmap_load (struct grub_video_bitmap **bitmap, - const char *filename); +grub_err_t EXPORT_FUNC (grub_video_bitmap_load) (struct grub_video_bitmap **bitmap, + const char *filename); -unsigned int grub_video_bitmap_get_width (struct grub_video_bitmap *bitmap); -unsigned int grub_video_bitmap_get_height (struct grub_video_bitmap *bitmap); +unsigned int EXPORT_FUNC (grub_video_bitmap_get_width) (struct grub_video_bitmap *bitmap); +unsigned int EXPORT_FUNC (grub_video_bitmap_get_height) (struct grub_video_bitmap *bitmap); -void grub_video_bitmap_get_mode_info (struct grub_video_bitmap *bitmap, - struct grub_video_mode_info *mode_info); +void EXPORT_FUNC (grub_video_bitmap_get_mode_info) (struct grub_video_bitmap *bitmap, + struct grub_video_mode_info *mode_info); -void *grub_video_bitmap_get_data (struct grub_video_bitmap *bitmap); +void *EXPORT_FUNC (grub_video_bitmap_get_data) (struct grub_video_bitmap *bitmap); #endif /* ! GRUB_BITMAP_HEADER */ diff --git a/include/grub/bitmap_scale.h b/include/grub/bitmap_scale.h new file mode 100644 index 000000000..dce9fbbf2 --- /dev/null +++ b/include/grub/bitmap_scale.h @@ -0,0 +1,49 @@ +/* bitmap_scale.h - Bitmap scaling functions. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#ifndef GRUB_BITMAP_SCALE_HEADER +#define GRUB_BITMAP_SCALE_HEADER 1 + +#include +#include +#include + +enum grub_video_bitmap_scale_method +{ + /* Choose the fastest interpolation algorithm. */ + GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST, + /* Choose the highest quality interpolation algorithm. */ + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST, + + /* Specific algorithms: */ + /* Nearest neighbor interpolation. */ + GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST, + /* Bilinear interpolation. */ + GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR +}; + +grub_err_t +EXPORT_FUNC (grub_video_bitmap_create_scaled) (struct grub_video_bitmap **dst, + int dst_width, int dst_height, + struct grub_video_bitmap *src, + enum + grub_video_bitmap_scale_method + scale_method); + +#endif /* ! GRUB_BITMAP_SCALE_HEADER */ diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h new file mode 100644 index 000000000..d88b25353 --- /dev/null +++ b/include/grub/bsdlabel.h @@ -0,0 +1,89 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2004,2007 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 . + */ + +#ifndef GRUB_BSDLABEL_PARTITION_HEADER +#define GRUB_BSDLABEL_PARTITION_HEADER 1 + +/* Constants for BSD disk label. */ +#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR 1 +#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC 0x82564557 + +/* BSD partition types. */ +#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED 0 +#define GRUB_PC_PARTITION_BSD_TYPE_SWAP 1 +#define GRUB_PC_PARTITION_BSD_TYPE_V6 2 +#define GRUB_PC_PARTITION_BSD_TYPE_V7 3 +#define GRUB_PC_PARTITION_BSD_TYPE_SYSV 4 +#define GRUB_PC_PARTITION_BSD_TYPE_V71K 5 +#define GRUB_PC_PARTITION_BSD_TYPE_V8 6 +#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS 7 +#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS 8 +#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS 9 +#define GRUB_PC_PARTITION_BSD_TYPE_OTHER 10 +#define GRUB_PC_PARTITION_BSD_TYPE_HPFS 11 +#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660 12 +#define GRUB_PC_PARTITION_BSD_TYPE_BOOT 13 + +/* FreeBSD-specific types. */ +#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM 14 +#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID 15 +#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2 21 + +/* NetBSD-specific types. */ +#define GRUB_PC_PARTITION_NETBSD_TYPE_ADOS 14 +#define GRUB_PC_PARTITION_NETBSD_TYPE_HFS 15 +#define GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE 16 +#define GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS 17 +#define GRUB_PC_PARTITION_NETBSD_TYPE_NTFS 18 +#define GRUB_PC_PARTITION_NETBSD_TYPE_RAID 19 +#define GRUB_PC_PARTITION_NETBSD_TYPE_CCD 20 +#define GRUB_PC_PARTITION_NETBSD_TYPE_JFS2 21 +#define GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS 22 + +/* OpenBSD-specific types. */ +#define GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS 14 +#define GRUB_PC_PARTITION_OPENBSD_TYPE_HFS 15 +#define GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE 16 +#define GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS 17 +#define GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS 18 +#define GRUB_PC_PARTITION_OPENBSD_TYPE_RAID 19 + +/* The BSD partition entry. */ +struct grub_partition_bsd_entry +{ + grub_uint32_t size; + grub_uint32_t offset; + grub_uint32_t fragment_size; + grub_uint8_t fs_type; + grub_uint8_t fs_fragments; + grub_uint16_t fs_cylinders; +} __attribute__ ((packed)); + +/* The BSD disk label. Only define members useful for GRUB. */ +struct grub_partition_bsd_disk_label +{ + grub_uint32_t magic; + grub_uint8_t padding[128]; + grub_uint32_t magic2; + grub_uint16_t checksum; + grub_uint16_t num_partitions; + grub_uint32_t boot_size; + grub_uint32_t superblock_size; +} __attribute__ ((packed)); + +#endif /* ! GRUB_PC_PARTITION_HEADER */ diff --git a/include/grub/bufio.h b/include/grub/bufio.h index 9a2294c26..acdd0c882 100644 --- a/include/grub/bufio.h +++ b/include/grub/bufio.h @@ -22,7 +22,7 @@ #include -grub_file_t grub_bufio_open (grub_file_t io, int size); -grub_file_t grub_buffile_open (const char *name, int size); +grub_file_t EXPORT_FUNC (grub_bufio_open) (grub_file_t io, int size); +grub_file_t EXPORT_FUNC (grub_buffile_open) (const char *name, int size); #endif /* ! GRUB_BUFIO_H */ diff --git a/include/grub/cache.h b/include/grub/cache.h index 745af43c3..27e44f0a2 100644 --- a/include/grub/cache.h +++ b/include/grub/cache.h @@ -23,6 +23,14 @@ #include #include +#if defined (__i386__) || defined (__x86_64__) +static inline void +grub_arch_sync_caches (void *address __attribute__ ((unused)), + grub_size_t len __attribute__ ((unused))) +{ +} +#else void EXPORT_FUNC(grub_arch_sync_caches) (void *address, grub_size_t len); +#endif #endif /* ! GRUB_CACHE_HEADER */ diff --git a/include/grub/charset.h b/include/grub/charset.h new file mode 100644 index 000000000..fc050da24 --- /dev/null +++ b/include/grub/charset.h @@ -0,0 +1,121 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 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 . + */ + +#ifndef GRUB_CHARSET_HEADER +#define GRUB_CHARSET_HEADER 1 + +#include + +#define GRUB_UINT8_1_LEADINGBIT 0x80 +#define GRUB_UINT8_2_LEADINGBITS 0xc0 +#define GRUB_UINT8_3_LEADINGBITS 0xe0 +#define GRUB_UINT8_4_LEADINGBITS 0xf0 +#define GRUB_UINT8_5_LEADINGBITS 0xf8 +#define GRUB_UINT8_6_LEADINGBITS 0xfc +#define GRUB_UINT8_7_LEADINGBITS 0xfe + +#define GRUB_UINT8_1_TRAILINGBIT 0x01 +#define GRUB_UINT8_2_TRAILINGBITS 0x03 +#define GRUB_UINT8_3_TRAILINGBITS 0x07 +#define GRUB_UINT8_4_TRAILINGBITS 0x0f +#define GRUB_UINT8_5_TRAILINGBITS 0x1f +#define GRUB_UINT8_6_TRAILINGBITS 0x3f + +#define GRUB_UCS2_LIMIT 0x10000 +#define GRUB_UTF16_UPPER_SURROGATE(code) \ + (0xD800 + ((((code) - GRUB_UCS2_LIMIT) >> 12) & 0xfff)) +#define GRUB_UTF16_LOWER_SURROGATE(code) \ + (0xDC00 + (((code) - GRUB_UCS2_LIMIT) & 0xfff)) + +grub_ssize_t +grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, + const grub_uint8_t *src, grub_size_t srcsize, + const grub_uint8_t **srcend); + +/* Convert UTF-16 to UTF-8. */ +static inline grub_uint8_t * +grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src, + grub_size_t size) +{ + grub_uint32_t code_high = 0; + + while (size--) + { + grub_uint32_t code = *src++; + + if (code_high) + { + if (code >= 0xDC00 && code <= 0xDFFF) + { + /* Surrogate pair. */ + code = ((code_high - 0xD800) << 12) + (code - 0xDC00) + 0x10000; + + *dest++ = (code >> 18) | 0xF0; + *dest++ = ((code >> 12) & 0x3F) | 0x80; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + } + else + { + /* Error... */ + *dest++ = '?'; + } + + code_high = 0; + } + else + { + if (code <= 0x007F) + *dest++ = code; + else if (code <= 0x07FF) + { + *dest++ = (code >> 6) | 0xC0; + *dest++ = (code & 0x3F) | 0x80; + } + else if (code >= 0xD800 && code <= 0xDBFF) + { + code_high = code; + continue; + } + else if (code >= 0xDC00 && code <= 0xDFFF) + { + /* Error... */ + *dest++ = '?'; + } + else + { + *dest++ = (code >> 12) | 0xE0; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + } + } + } + + return dest; +} + +/* Convert UCS-4 to UTF-8. */ +char *grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size); + +int +grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize); + +int grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg, + grub_uint32_t **last_position); + +#endif diff --git a/include/grub/cmos.h b/include/grub/cmos.h new file mode 100644 index 000000000..f508e3bf6 --- /dev/null +++ b/include/grub/cmos.h @@ -0,0 +1,72 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008, 2009 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 . + */ + +#ifndef GRUB_CMOS_H +#define GRUB_CMOS_H 1 + +#include +#include +#include + +#define GRUB_CMOS_INDEX_SECOND 0 +#define GRUB_CMOS_INDEX_SECOND_ALARM 1 +#define GRUB_CMOS_INDEX_MINUTE 2 +#define GRUB_CMOS_INDEX_MINUTE_ALARM 3 +#define GRUB_CMOS_INDEX_HOUR 4 +#define GRUB_CMOS_INDEX_HOUR_ALARM 5 +#define GRUB_CMOS_INDEX_DAY_OF_WEEK 6 +#define GRUB_CMOS_INDEX_DAY_OF_MONTH 7 +#define GRUB_CMOS_INDEX_MONTH 8 +#define GRUB_CMOS_INDEX_YEAR 9 + +#define GRUB_CMOS_INDEX_STATUS_A 0xA +#define GRUB_CMOS_INDEX_STATUS_B 0xB +#define GRUB_CMOS_INDEX_STATUS_C 0xC +#define GRUB_CMOS_INDEX_STATUS_D 0xD + +#define GRUB_CMOS_STATUS_B_DAYLIGHT 1 +#define GRUB_CMOS_STATUS_B_24HOUR 2 +#define GRUB_CMOS_STATUS_B_BINARY 4 + +static inline grub_uint8_t +grub_bcd_to_num (grub_uint8_t a) +{ + return ((a >> 4) * 10 + (a & 0xF)); +} + +static inline grub_uint8_t +grub_num_to_bcd (grub_uint8_t a) +{ + return (((a / 10) << 4) + (a % 10)); +} + +static inline grub_uint8_t +grub_cmos_read (grub_uint8_t index) +{ + grub_outb (index, GRUB_CMOS_ADDR_REG); + return grub_inb (GRUB_CMOS_DATA_REG); +} + +static inline void +grub_cmos_write (grub_uint8_t index, grub_uint8_t value) +{ + grub_outb (index, GRUB_CMOS_ADDR_REG); + grub_outb (value, GRUB_CMOS_DATA_REG); +} + +#endif /* GRUB_CMOS_H */ diff --git a/include/grub/crypto.h b/include/grub/crypto.h new file mode 100644 index 000000000..48b52ee65 --- /dev/null +++ b/include/grub/crypto.h @@ -0,0 +1,275 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 + * 2007, 2008, 2009 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 . + */ + +/* Contains elements based on gcrypt-module.h and gcrypt.h.in. + If it's changed please update this file. */ + +#ifndef GRUB_CRYPTO_HEADER +#define GRUB_CRYPTO_HEADER 1 + +#include +#include +#include + +typedef enum + { + GPG_ERR_NO_ERROR, + GPG_ERR_BAD_MPI, + GPG_ERR_BAD_SECKEY, + GPG_ERR_BAD_SIGNATURE, + GPG_ERR_CIPHER_ALGO, + GPG_ERR_CONFLICT, + GPG_ERR_DECRYPT_FAILED, + GPG_ERR_DIGEST_ALGO, + GPG_ERR_GENERAL, + GPG_ERR_INTERNAL, + GPG_ERR_INV_ARG, + GPG_ERR_INV_CIPHER_MODE, + GPG_ERR_INV_FLAG, + GPG_ERR_INV_KEYLEN, + GPG_ERR_INV_OBJ, + GPG_ERR_INV_OP, + GPG_ERR_INV_SEXP, + GPG_ERR_INV_VALUE, + GPG_ERR_MISSING_VALUE, + GPG_ERR_NO_ENCRYPTION_SCHEME, + GPG_ERR_NO_OBJ, + GPG_ERR_NO_PRIME, + GPG_ERR_NO_SIGNATURE_SCHEME, + GPG_ERR_NOT_FOUND, + GPG_ERR_NOT_IMPLEMENTED, + GPG_ERR_NOT_SUPPORTED, + GPG_ERROR_CFLAGS, + GPG_ERR_PUBKEY_ALGO, + GPG_ERR_SELFTEST_FAILED, + GPG_ERR_TOO_SHORT, + GPG_ERR_UNSUPPORTED, + GPG_ERR_WEAK_KEY, + GPG_ERR_WRONG_KEY_USAGE, + GPG_ERR_WRONG_PUBKEY_ALGO, + GPG_ERR_OUT_OF_MEMORY + } gcry_err_code_t; +#define gpg_err_code_t gcry_err_code_t +#define gpg_error_t gcry_err_code_t + +enum gcry_cipher_modes + { + GCRY_CIPHER_MODE_NONE = 0, /* Not yet specified. */ + GCRY_CIPHER_MODE_ECB = 1, /* Electronic codebook. */ + GCRY_CIPHER_MODE_CFB = 2, /* Cipher feedback. */ + GCRY_CIPHER_MODE_CBC = 3, /* Cipher block chaining. */ + GCRY_CIPHER_MODE_STREAM = 4, /* Used with stream ciphers. */ + GCRY_CIPHER_MODE_OFB = 5, /* Outer feedback. */ + GCRY_CIPHER_MODE_CTR = 6 /* Counter. */ + }; + +/* Type for the cipher_setkey function. */ +typedef gcry_err_code_t (*gcry_cipher_setkey_t) (void *c, + const unsigned char *key, + unsigned keylen); + +/* Type for the cipher_encrypt function. */ +typedef void (*gcry_cipher_encrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf); + +/* Type for the cipher_decrypt function. */ +typedef void (*gcry_cipher_decrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf); + +/* Type for the cipher_stencrypt function. */ +typedef void (*gcry_cipher_stencrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf, + unsigned int n); + +/* Type for the cipher_stdecrypt function. */ +typedef void (*gcry_cipher_stdecrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf, + unsigned int n); + +typedef struct gcry_cipher_oid_spec +{ + const char *oid; + int mode; +} gcry_cipher_oid_spec_t; + +/* Module specification structure for ciphers. */ +typedef struct gcry_cipher_spec +{ + const char *name; + const char **aliases; + gcry_cipher_oid_spec_t *oids; + grub_size_t blocksize; + grub_size_t keylen; + grub_size_t contextsize; + gcry_cipher_setkey_t setkey; + gcry_cipher_encrypt_t encrypt; + gcry_cipher_decrypt_t decrypt; + gcry_cipher_stencrypt_t stencrypt; + gcry_cipher_stdecrypt_t stdecrypt; + struct gcry_cipher_spec *next; +} gcry_cipher_spec_t; + +/* Type for the md_init function. */ +typedef void (*gcry_md_init_t) (void *c); + +/* Type for the md_write function. */ +typedef void (*gcry_md_write_t) (void *c, const void *buf, grub_size_t nbytes); + +/* Type for the md_final function. */ +typedef void (*gcry_md_final_t) (void *c); + +/* Type for the md_read function. */ +typedef unsigned char *(*gcry_md_read_t) (void *c); + +typedef struct gcry_md_oid_spec +{ + const char *oidstring; +} gcry_md_oid_spec_t; + +/* Module specification structure for message digests. */ +typedef struct gcry_md_spec +{ + const char *name; + unsigned char *asnoid; + int asnlen; + gcry_md_oid_spec_t *oids; + grub_size_t mdlen; + gcry_md_init_t init; + gcry_md_write_t write; + gcry_md_final_t final; + gcry_md_read_t read; + grub_size_t contextsize; /* allocate this amount of context */ + /* Block size, needed for HMAC. */ + grub_size_t blocksize; + struct gcry_md_spec *next; +} gcry_md_spec_t; + +struct grub_crypto_cipher_handle +{ + const struct gcry_cipher_spec *cipher; + char ctx[0]; +}; + +typedef struct grub_crypto_cipher_handle *grub_crypto_cipher_handle_t; + +struct grub_crypto_hmac_handle; + +const gcry_cipher_spec_t * +grub_crypto_lookup_cipher_by_name (const char *name); + +grub_crypto_cipher_handle_t +grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher); + +gcry_err_code_t +grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher, + const unsigned char *key, + unsigned keylen); + +void +grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher); + +void +grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size); + +gcry_err_code_t +grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size); + +gcry_err_code_t +grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size); +gcry_err_code_t +grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv_in); +gcry_err_code_t +grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv); +void +grub_cipher_register (gcry_cipher_spec_t *cipher); +void +grub_cipher_unregister (gcry_cipher_spec_t *cipher); +void +grub_md_register (gcry_md_spec_t *digest); +void +grub_md_unregister (gcry_md_spec_t *cipher); +void +grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, + grub_size_t inlen); +const gcry_md_spec_t * +grub_crypto_lookup_md_by_name (const char *name); + +grub_err_t +grub_crypto_gcry_error (gcry_err_code_t in); + +void grub_burn_stack (grub_size_t size); + +struct grub_crypto_hmac_handle * +grub_crypto_hmac_init (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen); +void +grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, void *data, + grub_size_t datalen); +gcry_err_code_t +grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out); + +gcry_err_code_t +grub_crypto_hmac_buffer (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen, + void *data, grub_size_t datalen, void *out); + +extern gcry_md_spec_t _gcry_digest_spec_md5; +extern gcry_md_spec_t _gcry_digest_spec_sha1; +extern gcry_md_spec_t _gcry_digest_spec_sha256; +extern gcry_md_spec_t _gcry_digest_spec_sha512; +#define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5) +#define GRUB_MD_SHA1 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha1) +#define GRUB_MD_SHA256 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha256) +#define GRUB_MD_SHA512 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha512) + +/* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant + of digest supplied by MD. Inputs are the password P of length PLEN, + the salt S of length SLEN, the iteration counter C (> 0), and the + desired derived output length DKLEN. Output buffer is DK which + must have room for at least DKLEN octets. The output buffer will + be filled with the derived data. */ +gcry_err_code_t +grub_crypto_pbkdf2 (const struct gcry_md_spec *md, + const grub_uint8_t *P, grub_size_t Plen, + const grub_uint8_t *S, grub_size_t Slen, + unsigned int c, + grub_uint8_t *DK, grub_size_t dkLen); + +int +grub_crypto_memcmp (const void *a, const void *b, grub_size_t n); + +int +grub_password_get (char buf[], unsigned buf_size); + +/* For indistinguishibility. */ +#define GRUB_ACCESS_DENIED grub_error (GRUB_ERR_ACCESS_DENIED, "Access denied.") + +extern void (*grub_crypto_autoload_hook) (const char *name); + +#endif diff --git a/include/grub/datetime.h b/include/grub/datetime.h index 2dbba55e2..e721e89af 100644 --- a/include/grub/datetime.h +++ b/include/grub/datetime.h @@ -33,10 +33,17 @@ struct grub_datetime }; /* Return date and time. */ +#ifdef GRUB_MACHINE_EMU +grub_err_t EXPORT_FUNC(grub_get_datetime) (struct grub_datetime *datetime); + +/* Set date and time. */ +grub_err_t EXPORT_FUNC(grub_set_datetime) (struct grub_datetime *datetime); +#else grub_err_t grub_get_datetime (struct grub_datetime *datetime); /* Set date and time. */ grub_err_t grub_set_datetime (struct grub_datetime *datetime); +#endif int grub_get_weekday (struct grub_datetime *datetime); char *grub_get_weekday_name (struct grub_datetime *datetime); diff --git a/include/grub/disk.h b/include/grub/disk.h index de71bb588..e60b1f3de 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 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 @@ -42,6 +42,7 @@ enum grub_disk_dev_id GRUB_DISK_DEVICE_PXE_ID, GRUB_DISK_DEVICE_SCSI_ID, GRUB_DISK_DEVICE_FILE_ID, + GRUB_DISK_DEVICE_LUKS_ID }; struct grub_disk; diff --git a/include/grub/dl.h b/include/grub/dl.h index 3f8b328da..cf5da7fd5 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -91,29 +91,24 @@ grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); void grub_dl_unload_unneeded (void); void grub_dl_unload_all (void); -#ifdef GRUB_UTIL -static inline int -grub_dl_ref (grub_dl_t mod) -{ - (void) mod; - return 0; -} -static inline int -grub_dl_unref (grub_dl_t mod) -{ - (void) mod; - return 0; -} +#if defined (GRUB_UTIL) || defined (GRUB_TARGET_NO_MODULES) +#define GRUB_NO_MODULES 1 #else +#define GRUB_NO_MODULES 0 +#endif int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); -#endif void EXPORT_FUNC(grub_dl_iterate) (int (*hook) (grub_dl_t mod)); grub_dl_t EXPORT_FUNC(grub_dl_get) (const char *name); -grub_err_t EXPORT_FUNC(grub_dl_register_symbol) (const char *name, void *addr, - grub_dl_t mod); +grub_err_t grub_dl_register_symbol (const char *name, void *addr, + grub_dl_t mod); grub_err_t grub_arch_dl_check_header (void *ehdr); grub_err_t grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr); +#if defined (_mips) && ! GRUB_NO_MODULES +#define GRUB_LINKER_HAVE_INIT 1 +void grub_arch_dl_init_linker (void); +#endif + #endif /* ! GRUB_DL_H */ diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index e870eab41..36363ae1e 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -1,7 +1,7 @@ /* efi.h - declare EFI types and functions */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009 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 @@ -21,6 +21,7 @@ #define GRUB_EFI_API_HEADER 1 #include +#include /* For consistency and safety, we name the EFI-defined types differently. All names are transformed into lower case, _t appended, and @@ -583,6 +584,16 @@ struct grub_efi_protocol_device_path }; typedef struct grub_efi_protocol_device_path grub_efi_protocol_device_path_t; +#define GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE 6 + +struct grub_efi_piwg_device_path +{ + grub_efi_device_path_t header; + grub_efi_guid_t guid __attribute__ ((packed)); +}; +typedef struct grub_efi_piwg_device_path grub_efi_piwg_device_path_t; + + /* BIOS Boot Specification Device Path. */ #define GRUB_EFI_BIOS_DEVICE_PATH_TYPE 5 diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index 43f152981..5852a476f 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -1,7 +1,7 @@ /* efi.h - declare variables and functions for EFI support */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009 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 @@ -55,6 +55,10 @@ grub_efi_device_path_t * EXPORT_FUNC(grub_efi_get_device_path) (grub_efi_handle_t handle); int EXPORT_FUNC(grub_efi_exit_boot_services) (grub_efi_uintn_t map_key); int EXPORT_FUNC (grub_efi_finish_boot_services) (void); +grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map); void grub_efi_mm_init (void); void grub_efi_mm_fini (void); diff --git a/include/grub/efi/graphics_output.h b/include/grub/efi/graphics_output.h index a55869dc7..a29221919 100644 --- a/include/grub/efi/graphics_output.h +++ b/include/grub/efi/graphics_output.h @@ -24,7 +24,7 @@ #define GRUB_EFI_GOP_GUID \ { 0x9042a9de, 0x23dc, 0x4a38, { 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a }} -typedef enum +typedef enum { GRUB_EFI_GOT_RGBA8, GRUB_EFI_GOT_BGRA8, diff --git a/include/grub/efi/memory.h b/include/grub/efi/memory.h index e5ea58d67..285be8359 100644 --- a/include/grub/efi/memory.h +++ b/include/grub/efi/memory.h @@ -34,9 +34,9 @@ by firmware. */ #define GRUB_MACHINE_MEMORY_HOLE 6 - -grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) -(int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); +grub_err_t grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, + grub_uint64_t, + grub_uint32_t)); grub_err_t grub_machine_mmap_register (grub_uint64_t start, grub_uint64_t size, int type, int handle); grub_err_t grub_machine_mmap_unregister (int handle); diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index 4fb8d098c..81a1a5797 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009 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 @@ -99,12 +99,8 @@ struct grub_pe32_optional_header grub_uint32_t entry_addr; grub_uint32_t code_base; -#if GRUB_TARGET_SIZEOF_VOID_P == 4 grub_uint32_t data_base; grub_uint32_t image_base; -#else - grub_uint64_t image_base; -#endif grub_uint32_t section_alignment; grub_uint32_t file_alignment; @@ -121,22 +117,11 @@ struct grub_pe32_optional_header grub_uint16_t subsystem; grub_uint16_t dll_characteristics; -#if GRUB_TARGET_SIZEOF_VOID_P == 4 - grub_uint32_t stack_reserve_size; grub_uint32_t stack_commit_size; grub_uint32_t heap_reserve_size; grub_uint32_t heap_commit_size; -#else - - grub_uint64_t stack_reserve_size; - grub_uint64_t stack_commit_size; - grub_uint64_t heap_reserve_size; - grub_uint64_t heap_commit_size; - -#endif - grub_uint32_t loader_flags; grub_uint32_t num_data_directories; @@ -159,15 +144,63 @@ struct grub_pe32_optional_header struct grub_pe32_data_directory reserved_entry; }; -#if GRUB_TARGET_SIZEOF_VOID_P == 4 +struct grub_pe64_optional_header +{ + grub_uint16_t magic; + grub_uint8_t major_linker_version; + grub_uint8_t minor_linker_version; + grub_uint32_t code_size; + grub_uint32_t data_size; + grub_uint32_t bss_size; + grub_uint32_t entry_addr; + grub_uint32_t code_base; + + grub_uint64_t image_base; + + grub_uint32_t section_alignment; + grub_uint32_t file_alignment; + grub_uint16_t major_os_version; + grub_uint16_t minor_os_version; + grub_uint16_t major_image_version; + grub_uint16_t minor_image_version; + grub_uint16_t major_subsystem_version; + grub_uint16_t minor_subsystem_version; + grub_uint32_t reserved; + grub_uint32_t image_size; + grub_uint32_t header_size; + grub_uint32_t checksum; + grub_uint16_t subsystem; + grub_uint16_t dll_characteristics; + + grub_uint64_t stack_reserve_size; + grub_uint64_t stack_commit_size; + grub_uint64_t heap_reserve_size; + grub_uint64_t heap_commit_size; + + grub_uint32_t loader_flags; + grub_uint32_t num_data_directories; + + /* Data directories. */ + struct grub_pe32_data_directory export_table; + struct grub_pe32_data_directory import_table; + struct grub_pe32_data_directory resource_table; + struct grub_pe32_data_directory exception_table; + struct grub_pe32_data_directory certificate_table; + struct grub_pe32_data_directory base_relocation_table; + struct grub_pe32_data_directory debug; + struct grub_pe32_data_directory architecture; + struct grub_pe32_data_directory global_ptr; + struct grub_pe32_data_directory tls_table; + struct grub_pe32_data_directory load_config_table; + struct grub_pe32_data_directory bound_import; + struct grub_pe32_data_directory iat; + struct grub_pe32_data_directory delay_import_descriptor; + struct grub_pe32_data_directory com_runtime_header; + struct grub_pe32_data_directory reserved_entry; +}; #define GRUB_PE32_PE32_MAGIC 0x10b - -#else - -#define GRUB_PE32_PE32_MAGIC 0x20b - -#endif +#define GRUB_PE32_PE64_MAGIC 0x20b #define GRUB_PE32_SUBSYSTEM_EFI_APPLICATION 10 @@ -205,6 +238,7 @@ struct grub_pe32_section_table #define GRUB_PE32_SCN_ALIGN_SHIFT 20 #define GRUB_PE32_SCN_ALIGN_MASK 7 +#define GRUB_PE32_SIGNATURE_SIZE 4 struct grub_pe32_header { @@ -212,13 +246,18 @@ struct grub_pe32_header grub_uint8_t msdos_stub[GRUB_PE32_MSDOS_STUB_SIZE]; /* This is always PE\0\0. */ - char signature[4]; + char signature[GRUB_PE32_SIGNATURE_SIZE]; /* The COFF file header. */ struct grub_pe32_coff_header coff_header; +#if GRUB_TARGET_SIZEOF_VOID_P == 8 + /* The Optional header. */ + struct grub_pe64_optional_header optional_header; +#else /* The Optional header. */ struct grub_pe32_optional_header optional_header; +#endif }; struct grub_pe32_fixup_block diff --git a/include/grub/efiemu/efiemu.h b/include/grub/efiemu/efiemu.h index 20163dd61..3980d32cd 100644 --- a/include/grub/efiemu/efiemu.h +++ b/include/grub/efiemu/efiemu.h @@ -268,9 +268,19 @@ void grub_efiemu_free_syms (void); grub_err_t grub_efiemu_write_value (void * addr, grub_uint32_t value, int plus_handle, int minus_handle, int ptv_needed, int size); +grub_err_t grub_efiemu_write_sym_markers (void); grub_err_t grub_efiemu_pnvram (void); grub_err_t grub_efiemu_prepare (void); char *grub_efiemu_get_default_core_name (void); void grub_efiemu_pnvram_cmd_unregister (void); grub_err_t grub_efiemu_autocore (void); +grub_err_t grub_efiemu_crc32 (void); +grub_err_t grub_efiemu_crc64 (void); +grub_err_t +grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version + __attribute__ ((unused)), + grub_efi_memory_descriptor_t *virtual_map); + #endif /* ! GRUB_EFI_EMU_HEADER */ diff --git a/include/grub/elf.h b/include/grub/elf.h index 1a1ec1310..b9401f241 100644 --- a/include/grub/elf.h +++ b/include/grub/elf.h @@ -1,5 +1,5 @@ /* This file defines standard ELF types, structures, and macros. - Copyright (C) 1995-1999, 2000, 2001, 2002,2008 Free Software Foundation, Inc. + Copyright (C) 1995-1999,2000,2001,2002,2008,2009 Free Software Foundation, Inc. This file was part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -555,6 +555,7 @@ typedef struct #define PT_NUM 8 /* Number of defined types */ #define PT_LOOS 0x60000000 /* Start of OS-specific */ #define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* GCC stack segment */ #define PT_LOSUNW 0x6ffffffa #define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ #define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ diff --git a/include/grub/elfload.h b/include/grub/elfload.h index 6e09e0d05..77ee41675 100644 --- a/include/grub/elfload.h +++ b/include/grub/elfload.h @@ -46,12 +46,12 @@ grub_elf_t grub_elf_file (grub_file_t); grub_err_t grub_elf_close (grub_elf_t); int grub_elf_is_elf32 (grub_elf_t); -grub_size_t grub_elf32_size (grub_elf_t); +grub_size_t grub_elf32_size (grub_elf_t, Elf32_Addr *); grub_err_t grub_elf32_load (grub_elf_t, grub_elf32_load_hook_t, grub_addr_t *, grub_size_t *); int grub_elf_is_elf64 (grub_elf_t); -grub_size_t grub_elf64_size (grub_elf_t); +grub_size_t grub_elf64_size (grub_elf_t, Elf64_Addr *); grub_err_t grub_elf64_load (grub_elf_t, grub_elf64_load_hook_t, grub_addr_t *, grub_size_t *); diff --git a/include/grub/util/console.h b/include/grub/emu/console.h similarity index 100% rename from include/grub/util/console.h rename to include/grub/emu/console.h diff --git a/include/grub/util/getroot.h b/include/grub/emu/getroot.h similarity index 96% rename from include/grub/util/getroot.h rename to include/grub/emu/getroot.h index f9f7f9baa..dff7b4df7 100644 --- a/include/grub/util/getroot.h +++ b/include/grub/emu/getroot.h @@ -26,7 +26,6 @@ enum grub_dev_abstraction_types { }; char *grub_guess_root_device (const char *dir); -char *grub_get_prefix (const char *dir); int grub_util_get_dev_abstraction (const char *os_dev); char *grub_util_get_grub_dev (const char *os_dev); const char *grub_util_check_block_device (const char *blk_dev); diff --git a/include/grub/util/hostdisk.h b/include/grub/emu/hostdisk.h similarity index 92% rename from include/grub/util/hostdisk.h rename to include/grub/emu/hostdisk.h index 21efb0d17..246046ee0 100644 --- a/include/grub/util/hostdisk.h +++ b/include/grub/emu/hostdisk.h @@ -20,8 +20,11 @@ #ifndef GRUB_BIOSDISK_MACHINE_UTIL_HEADER #define GRUB_BIOSDISK_MACHINE_UTIL_HEADER 1 +#include + void grub_util_biosdisk_init (const char *dev_map); void grub_util_biosdisk_fini (void); char *grub_util_biosdisk_get_grub_dev (const char *os_dev); +const char *grub_util_biosdisk_get_osdev (grub_disk_t disk); #endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */ diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h new file mode 100644 index 000000000..e037e6be7 --- /dev/null +++ b/include/grub/emu/misc.h @@ -0,0 +1,50 @@ +#ifndef GRUB_EMU_MISC_H +#define GRUB_EMU_MISC_H 1 + +#include +#include + +#ifdef __CYGWIN__ +# include +# include +# include +# define DEV_CYGDRIVE_MAJOR 98 +#endif + +#ifdef __NetBSD__ +/* NetBSD uses /boot for its boot block. */ +# define DEFAULT_DIRECTORY "/grub" +#else +# define DEFAULT_DIRECTORY "/boot/grub" +#endif + +#define DEFAULT_DEVICE_MAP DEFAULT_DIRECTORY "/device.map" + +extern int verbosity; +extern const char *program_name; + +void grub_init_all (void); +void grub_fini_all (void); + +char *grub_make_system_path_relative_to_its_root (const char *path); + +void * EXPORT_FUNC(xmalloc) (grub_size_t size); +void * EXPORT_FUNC(xrealloc) (void *ptr, grub_size_t size); +char * EXPORT_FUNC(xstrdup) (const char *str); +char * EXPORT_FUNC(xasprintf) (const char *fmt, ...); + +void EXPORT_FUNC(grub_util_warn) (const char *fmt, ...); +void EXPORT_FUNC(grub_util_info) (const char *fmt, ...); +void EXPORT_FUNC(grub_util_error) (const char *fmt, ...) __attribute__ ((noreturn)); + +#ifndef HAVE_VASPRINTF +int EXPORT_FUNC(vasprintf) (char **buf, const char *fmt, va_list ap); +#endif + +#ifndef HAVE_ASPRINTF +int EXPORT_FUNC(asprintf) (char **buf, const char *fmt, ...); +#endif + +char * EXPORT_FUNC(xasprintf) (const char *fmt, ...); + +#endif /* GRUB_EMU_MISC_H */ diff --git a/include/grub/env.h b/include/grub/env.h index 440185a59..ae4fd8745 100644 --- a/include/grub/env.h +++ b/include/grub/env.h @@ -22,6 +22,7 @@ #include #include #include +#include struct grub_env_var; @@ -30,18 +31,6 @@ typedef char *(*grub_env_read_hook_t) (struct grub_env_var *var, typedef char *(*grub_env_write_hook_t) (struct grub_env_var *var, const char *val); -enum grub_env_var_type - { - /* The default variable type which is local in current context. */ - GRUB_ENV_VAR_LOCAL, - - /* The exported type, which is passed to new contexts. */ - GRUB_ENV_VAR_GLOBAL, - - /* The data slot type, which is used to store arbitrary data. */ - GRUB_ENV_VAR_DATA - }; - struct grub_env_var { char *name; @@ -50,23 +39,24 @@ struct grub_env_var grub_env_write_hook_t write_hook; struct grub_env_var *next; struct grub_env_var **prevp; - enum grub_env_var_type type; + int global; }; grub_err_t EXPORT_FUNC(grub_env_set) (const char *name, const char *val); char *EXPORT_FUNC(grub_env_get) (const char *name); void EXPORT_FUNC(grub_env_unset) (const char *name); void EXPORT_FUNC(grub_env_iterate) (int (*func) (struct grub_env_var *var)); +struct grub_env_var *EXPORT_FUNC(grub_env_find) (const char *name); grub_err_t EXPORT_FUNC(grub_register_variable_hook) (const char *name, grub_env_read_hook_t read_hook, grub_env_write_hook_t write_hook); -grub_err_t EXPORT_FUNC(grub_env_context_open) (int export); -grub_err_t EXPORT_FUNC(grub_env_context_close) (void); -grub_err_t EXPORT_FUNC(grub_env_export) (const char *name); -grub_err_t EXPORT_FUNC(grub_env_set_data_slot) (const char *name, - const void *ptr); -void *EXPORT_FUNC(grub_env_get_data_slot) (const char *name); -void EXPORT_FUNC(grub_env_unset_data_slot) (const char *name); +grub_err_t grub_env_context_open (int export); +grub_err_t grub_env_context_close (void); +grub_err_t grub_env_export (const char *name); + +void grub_env_unset_menu (void); +grub_menu_t grub_env_get_menu (void); +void grub_env_set_menu (grub_menu_t nmenu); #endif /* ! GRUB_ENV_HEADER */ diff --git a/include/grub/env_private.h b/include/grub/env_private.h new file mode 100644 index 000000000..bb001533f --- /dev/null +++ b/include/grub/env_private.h @@ -0,0 +1,46 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2005,2006,2007,2009 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 . + */ + +#ifndef GRUB_ENV_PRIVATE_HEADER +#define GRUB_ENV_PRIVATE_HEADER 1 + +#include + +/* The size of the hash table. */ +#define HASHSZ 13 + +/* A hashtable for quick lookup of variables. */ +struct grub_env_context +{ + /* A hash table for variables. */ + struct grub_env_var *vars[HASHSZ]; + + /* One level deeper on the stack. */ + struct grub_env_context *prev; +}; + +/* This is used for sorting only. */ +struct grub_env_sorted_var +{ + struct grub_env_var *var; + struct grub_env_sorted_var *next; +}; + +extern struct grub_env_context *EXPORT_VAR(grub_current_context); + +#endif /* ! GRUB_ENV_PRIVATE_HEADER */ diff --git a/include/grub/err.h b/include/grub/err.h index 7a5ce1ae0..e44705389 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -66,7 +66,7 @@ void EXPORT_FUNC(grub_fatal) (const char *fmt, ...) __attribute__ ((noreturn)); void EXPORT_FUNC(grub_error_push) (void); int EXPORT_FUNC(grub_error_pop) (void); void EXPORT_FUNC(grub_print_error) (void); -int EXPORT_FUNC(grub_err_printf) (const char *fmt, ...) -__attribute__ ((format (printf, 1, 2))); +int grub_err_printf (const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); #endif /* ! GRUB_ERR_HEADER */ diff --git a/include/grub/font.h b/include/grub/font.h index 8a5f3ac7d..7c5c17403 100644 --- a/include/grub/font.h +++ b/include/grub/font.h @@ -21,6 +21,7 @@ #include #include +#include /* Forward declaration of opaque structure grub_font. Users only pass struct grub_font pointers to the font module functions, @@ -80,36 +81,38 @@ int grub_font_load (const char *filename); "Family Name Bold Italic 14", where Bold and Italic are optional. If no font matches the name specified, the most recently loaded font is returned as a fallback. */ -grub_font_t grub_font_get (const char *font_name); +grub_font_t EXPORT_FUNC (grub_font_get) (const char *font_name); -const char *grub_font_get_name (grub_font_t font); +const char *EXPORT_FUNC (grub_font_get_name) (grub_font_t font); -int grub_font_get_max_char_width (grub_font_t font); +int EXPORT_FUNC (grub_font_get_max_char_width) (grub_font_t font); -int grub_font_get_max_char_height (grub_font_t font); +int EXPORT_FUNC (grub_font_get_max_char_height) (grub_font_t font); -int grub_font_get_ascent (grub_font_t font); +int EXPORT_FUNC (grub_font_get_ascent) (grub_font_t font); -int grub_font_get_descent (grub_font_t font); +int EXPORT_FUNC (grub_font_get_descent) (grub_font_t font); -int grub_font_get_leading (grub_font_t font); +int EXPORT_FUNC (grub_font_get_leading) (grub_font_t font); -int grub_font_get_height (grub_font_t font); +int EXPORT_FUNC (grub_font_get_height) (grub_font_t font); -int grub_font_get_string_width (grub_font_t font, const char *str); +int EXPORT_FUNC (grub_font_get_string_width) (grub_font_t font, + const char *str); -struct grub_font_glyph *grub_font_get_glyph (grub_font_t font, - grub_uint32_t code); +struct grub_font_glyph *EXPORT_FUNC (grub_font_get_glyph) (grub_font_t font, + grub_uint32_t code); -struct grub_font_glyph *grub_font_get_glyph_with_fallback (grub_font_t font, - grub_uint32_t code); +struct grub_font_glyph *EXPORT_FUNC (grub_font_get_glyph_with_fallback) (grub_font_t font, + grub_uint32_t code); -grub_err_t grub_font_draw_glyph (struct grub_font_glyph *glyph, - grub_video_color_t color, - int left_x, int baseline_y); +grub_err_t EXPORT_FUNC (grub_font_draw_glyph) (struct grub_font_glyph *glyph, + grub_video_color_t color, + int left_x, int baseline_y); -grub_err_t grub_font_draw_string (const char *str, grub_font_t font, - grub_video_color_t color, - int left_x, int baseline_y); +grub_err_t EXPORT_FUNC (grub_font_draw_string) (const char *str, + grub_font_t font, + grub_video_color_t color, + int left_x, int baseline_y); #endif /* ! GRUB_FONT_HEADER */ diff --git a/include/grub/fontformat.h b/include/grub/fontformat.h new file mode 100644 index 000000000..b5060588c --- /dev/null +++ b/include/grub/fontformat.h @@ -0,0 +1,38 @@ +/* + * 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 . + */ + +#ifndef GRUB_FONT_FORMAT_HEADER +#define GRUB_FONT_FORMAT_HEADER 1 + +/* FONT_FORMAT_PFF2_MAGIC use only 4 relevants bytes and the \0. */ +#define FONT_FORMAT_PFF2_MAGIC "PFF2" +#define FONT_FORMAT_SECTION_NAMES_FILE "FILE" +#define FONT_FORMAT_SECTION_NAMES_FONT_NAME "NAME" +#define FONT_FORMAT_SECTION_NAMES_POINT_SIZE "PTSZ" +#define FONT_FORMAT_SECTION_NAMES_WEIGHT "WEIG" +#define FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH "MAXW" +#define FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT "MAXH" +#define FONT_FORMAT_SECTION_NAMES_ASCENT "ASCE" +#define FONT_FORMAT_SECTION_NAMES_DESCENT "DESC" +#define FONT_FORMAT_SECTION_NAMES_CHAR_INDEX "CHIX" +#define FONT_FORMAT_SECTION_NAMES_DATA "DATA" +#define FONT_FORMAT_SECTION_NAMES_FAMILY "FAMI" +#define FONT_FORMAT_SECTION_NAMES_SLAN "SLAN" + +#endif /* ! GRUB_FONT_FORMAT_HEADER */ + diff --git a/include/grub/fs.h b/include/grub/fs.h index 132ab4755..45f515768 100644 --- a/include/grub/fs.h +++ b/include/grub/fs.h @@ -1,7 +1,7 @@ /* fs.h - filesystem manager */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2004,2007,2008,2009 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 diff --git a/include/grub/gfxmenu_model.h b/include/grub/gfxmenu_model.h new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/include/grub/gfxmenu_model.h @@ -0,0 +1 @@ + diff --git a/include/grub/gfxmenu_view.h b/include/grub/gfxmenu_view.h new file mode 100644 index 000000000..7cbfa89d3 --- /dev/null +++ b/include/grub/gfxmenu_view.h @@ -0,0 +1,107 @@ +/* gfxmenu_view.h - gfxmenu view interface. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#ifndef GRUB_GFXMENU_VIEW_HEADER +#define GRUB_GFXMENU_VIEW_HEADER 1 + +#include +#include +#include +#include +#include + +struct grub_gfxmenu_view; /* Forward declaration of opaque type. */ +typedef struct grub_gfxmenu_view *grub_gfxmenu_view_t; + + +grub_gfxmenu_view_t grub_gfxmenu_view_new (const char *theme_path, + int width, int height); + +void grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view); + +/* Set properties on the view based on settings from the specified + theme file. */ +grub_err_t grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, + const char *theme_path); + +grub_err_t grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr, + const char *pattern, const char *theme_dir); + +void grub_gfxmenu_view_draw (grub_gfxmenu_view_t view); + +void +grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view); + +void +grub_gfxmenu_redraw_timeout (grub_gfxmenu_view_t view); + +void +grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, + const grub_video_rect_t *region); + +void +grub_gfxmenu_clear_timeout (void *data); +void +grub_gfxmenu_print_timeout (int timeout, void *data); +void +grub_gfxmenu_set_chosen_entry (int entry, void *data); + +/* Implementation details -- this should not be used outside of the + view itself. */ + +#include +#include +#include +#include +#include + +/* Definition of the private representation of the view. */ +struct grub_gfxmenu_view +{ + grub_video_rect_t screen; + + grub_font_t title_font; + grub_font_t message_font; + char *terminal_font_name; + grub_gui_color_t title_color; + grub_gui_color_t message_color; + grub_gui_color_t message_bg_color; + struct grub_video_bitmap *desktop_image; + grub_gui_color_t desktop_color; + grub_gfxmenu_box_t terminal_box; + char *title_text; + char *progress_message_text; + char *theme_path; + + grub_gui_container_t canvas; + + int double_repaint; + + int selected; + + grub_video_rect_t progress_message_frame; + + grub_menu_t menu; + + int nested; + + int first_timeout; +}; + +#endif /* ! GRUB_GFXMENU_VIEW_HEADER */ diff --git a/include/grub/gfxterm.h b/include/grub/gfxterm.h new file mode 100644 index 000000000..295354baf --- /dev/null +++ b/include/grub/gfxterm.h @@ -0,0 +1,44 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008 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 . + */ + +#ifndef GRUB_GFXTERM_HEADER +#define GRUB_GFXTERM_HEADER 1 + +#include +#include +#include +#include + +grub_err_t +EXPORT_FUNC (grub_gfxterm_set_window) (struct grub_video_render_target *target, + int x, int y, int width, int height, + int double_repaint, + const char *font_name, int border_width); + +typedef void (*grub_gfxterm_repaint_callback_t)(int x, int y, + int width, int height); + +void grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func); + +void EXPORT_FUNC (grub_gfxterm_schedule_repaint) (void); + +grub_err_t EXPORT_FUNC (grub_gfxterm_fullscreen) (void); + +extern void (*EXPORT_VAR (grub_gfxterm_decorator_hook)) (void); + +#endif /* ! GRUB_GFXTERM_HEADER */ diff --git a/include/grub/gfxwidgets.h b/include/grub/gfxwidgets.h new file mode 100644 index 000000000..f9678bf9e --- /dev/null +++ b/include/grub/gfxwidgets.h @@ -0,0 +1,49 @@ +/* gfxwidgets.h - Widgets for the graphical menu (gfxmenu). */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 . + */ + +#ifndef GRUB_GFXWIDGETS_HEADER +#define GRUB_GFXWIDGETS_HEADER 1 + +#include + +typedef struct grub_gfxmenu_box *grub_gfxmenu_box_t; + +struct grub_gfxmenu_box +{ + /* The size of the content. */ + int content_width; + int content_height; + + struct grub_video_bitmap **raw_pixmaps; + struct grub_video_bitmap **scaled_pixmaps; + + void (*draw) (grub_gfxmenu_box_t self, int x, int y); + void (*set_content_size) (grub_gfxmenu_box_t self, + int width, int height); + int (*get_left_pad) (grub_gfxmenu_box_t self); + int (*get_top_pad) (grub_gfxmenu_box_t self); + int (*get_right_pad) (grub_gfxmenu_box_t self); + int (*get_bottom_pad) (grub_gfxmenu_box_t self); + void (*destroy) (grub_gfxmenu_box_t self); +}; + +grub_gfxmenu_box_t grub_gfxmenu_create_box (const char *pixmaps_prefix, + const char *pixmaps_suffix); + +#endif /* ! GRUB_GFXWIDGETS_HEADER */ diff --git a/include/grub/gui.h b/include/grub/gui.h new file mode 100644 index 000000000..6e4a11cbe --- /dev/null +++ b/include/grub/gui.h @@ -0,0 +1,275 @@ +/* gui.h - GUI components header file. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include + +#ifndef GRUB_GUI_H +#define GRUB_GUI_H 1 + +/* The component ID identifying GUI components to be updated as the timeout + status changes. */ +#define GRUB_GFXMENU_TIMEOUT_COMPONENT_ID "__timeout__" + +/* A representation of a color. Unlike grub_video_color_t, this + representation is independent of any video mode specifics. */ +typedef struct grub_gui_color +{ + grub_uint8_t red; + grub_uint8_t green; + grub_uint8_t blue; + grub_uint8_t alpha; +} grub_gui_color_t; + +typedef struct grub_gui_component *grub_gui_component_t; +typedef struct grub_gui_container *grub_gui_container_t; +typedef struct grub_gui_list *grub_gui_list_t; + +typedef void (*grub_gui_component_callback) (grub_gui_component_t component, + void *userdata); + +/* Component interface. */ + +struct grub_gui_component_ops +{ + void (*destroy) (void *self); + const char * (*get_id) (void *self); + int (*is_instance) (void *self, const char *type); + void (*paint) (void *self, const grub_video_rect_t *bounds); + void (*set_parent) (void *self, grub_gui_container_t parent); + grub_gui_container_t (*get_parent) (void *self); + void (*set_bounds) (void *self, const grub_video_rect_t *bounds); + void (*get_bounds) (void *self, grub_video_rect_t *bounds); + void (*get_minimal_size) (void *self, unsigned *width, unsigned *height); + grub_err_t (*set_property) (void *self, const char *name, const char *value); + void (*repaint) (void *self, int second_pass); +}; + +struct grub_gui_container_ops +{ + void (*add) (void *self, grub_gui_component_t comp); + void (*remove) (void *self, grub_gui_component_t comp); + void (*iterate_children) (void *self, + grub_gui_component_callback cb, void *userdata); +}; + +struct grub_gui_list_ops +{ + void (*set_view_info) (void *self, + grub_gfxmenu_view_t view); +}; + +struct grub_gui_progress_ops +{ + void (*set_state) (void *self, int visible, int start, int current, int end); +}; + +typedef void (*grub_gfxmenu_set_state_t) (void *self, int visible, int start, + int current, int end); + +struct grub_gfxmenu_timeout_notify +{ + struct grub_gfxmenu_timeout_notify *next; + grub_gfxmenu_set_state_t set_state; + grub_gui_component_t self; +}; + +extern struct grub_gfxmenu_timeout_notify *grub_gfxmenu_timeout_notifications; + +static inline grub_err_t +grub_gfxmenu_timeout_register (grub_gui_component_t self, + grub_gfxmenu_set_state_t set_state) +{ + struct grub_gfxmenu_timeout_notify *ne = grub_malloc (sizeof (*ne)); + if (!ne) + return grub_errno; + ne->set_state = set_state; + ne->self = self; + ne->next = grub_gfxmenu_timeout_notifications; + grub_gfxmenu_timeout_notifications = ne; + return GRUB_ERR_NONE; +} + +static inline void +grub_gfxmenu_timeout_unregister (grub_gui_component_t self) +{ + struct grub_gfxmenu_timeout_notify **p, *q; + + for (p = &grub_gfxmenu_timeout_notifications, q = *p; + q; p = &(q->next), q = q->next) + if (q->self == self) + { + *p = q->next; + break; + } +} + +typedef signed grub_fixed_signed_t; +#define GRUB_FIXED_1 0x10000 + +static inline signed +grub_fixed_sfs_divide (signed a, grub_fixed_signed_t b) +{ + return (a * GRUB_FIXED_1) / b; +} + +static inline grub_fixed_signed_t +grub_fixed_fsf_divide (grub_fixed_signed_t a, signed b) +{ + return a / b; +} + +static inline signed +grub_fixed_sfs_multiply (signed a, grub_fixed_signed_t b) +{ + return (a * b) / GRUB_FIXED_1; +} + +static inline signed +grub_fixed_to_signed (grub_fixed_signed_t in) +{ + return in / GRUB_FIXED_1; +} + +static inline grub_fixed_signed_t +grub_signed_to_fixed (signed in) +{ + return in * GRUB_FIXED_1; +} + +struct grub_gui_component +{ + struct grub_gui_component_ops *ops; + signed x; + grub_fixed_signed_t xfrac; + signed y; + grub_fixed_signed_t yfrac; + signed w; + grub_fixed_signed_t wfrac; + signed h; + grub_fixed_signed_t hfrac; +}; + +struct grub_gui_progress +{ + struct grub_gui_component component; + struct grub_gui_progress_ops *ops; +}; + +struct grub_gui_container +{ + struct grub_gui_component component; + struct grub_gui_container_ops *ops; +}; + +struct grub_gui_list +{ + struct grub_gui_component component; + struct grub_gui_list_ops *ops; +}; + + +/* Interfaces to concrete component classes. */ + +grub_gui_container_t grub_gui_canvas_new (void); +grub_gui_container_t grub_gui_vbox_new (void); +grub_gui_container_t grub_gui_hbox_new (void); +grub_gui_component_t grub_gui_label_new (void); +grub_gui_component_t grub_gui_image_new (void); +grub_gui_component_t grub_gui_progress_bar_new (void); +grub_gui_component_t grub_gui_list_new (void); +grub_gui_component_t grub_gui_circular_progress_new (void); + +/* Manipulation functions. */ + +/* Visit all components with the specified ID. */ +void grub_gui_find_by_id (grub_gui_component_t root, + const char *id, + grub_gui_component_callback cb, + void *userdata); + +/* Visit all components. */ +void grub_gui_iterate_recursively (grub_gui_component_t root, + grub_gui_component_callback cb, + void *userdata); + +/* Helper functions. */ + +static __inline void +grub_gui_save_viewport (grub_video_rect_t *r) +{ + grub_video_get_viewport ((unsigned *) &r->x, + (unsigned *) &r->y, + (unsigned *) &r->width, + (unsigned *) &r->height); +} + +static __inline void +grub_gui_restore_viewport (const grub_video_rect_t *r) +{ + grub_video_set_viewport (r->x, r->y, r->width, r->height); +} + +/* Set a new viewport relative the the current one, saving the current + viewport in OLD so it can be later restored. */ +static __inline void +grub_gui_set_viewport (const grub_video_rect_t *r, grub_video_rect_t *old) +{ + grub_gui_save_viewport (old); + grub_video_set_viewport (old->x + r->x, + old->y + r->y, + r->width, + r->height); +} + +static __inline grub_gui_color_t +grub_gui_color_rgb (int r, int g, int b) +{ + grub_gui_color_t c; + c.red = r; + c.green = g; + c.blue = b; + c.alpha = 255; + return c; +} + +static __inline grub_video_color_t +grub_gui_map_color (grub_gui_color_t c) +{ + return grub_video_map_rgba (c.red, c.green, c.blue, c.alpha); +} + +static inline int +grub_video_have_common_points (const grub_video_rect_t *a, + const grub_video_rect_t *b) +{ + if (!((a->x <= b->x && b->x <= a->x + a->width) + || (b->x <= a->x && a->x <= b->x + b->width))) + return 0; + if (!((a->y <= b->y && b->y <= a->y + a->height) + || (b->y <= a->y && a->y <= b->y + b->height))) + return 0; + return 1; +} + +#endif /* ! GRUB_GUI_H */ diff --git a/include/grub/gui_string_util.h b/include/grub/gui_string_util.h new file mode 100644 index 000000000..1baa2eede --- /dev/null +++ b/include/grub/gui_string_util.h @@ -0,0 +1,37 @@ +/* gui_string_util.h - String utilities for the graphical menu interface. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#ifndef GRUB_GUI_STRING_UTIL_HEADER +#define GRUB_GUI_STRING_UTIL_HEADER 1 + +#include +#include + +char *grub_new_substring (const char *buf, + grub_size_t start, grub_size_t end); + +char *grub_resolve_relative_path (const char *base, const char *path); + +char *grub_get_dirname (const char *file_path); + +int grub_gui_get_named_color (const char *name, grub_gui_color_t *color); + +grub_err_t grub_gui_parse_color (const char *s, grub_gui_color_t *color); + +#endif /* GRUB_GUI_STRING_UTIL_HEADER */ diff --git a/include/grub/handler.h b/include/grub/handler.h index 3331bb417..77dd7d9c1 100644 --- a/include/grub/handler.h +++ b/include/grub/handler.h @@ -55,6 +55,6 @@ grub_err_t EXPORT_FUNC(grub_handler_set_current) (grub_handler_class_t class, GRUB_FIELD_MATCH (ptr, grub_handler_t, name) && \ GRUB_FIELD_MATCH (ptr, grub_handler_t, init) && \ GRUB_FIELD_MATCH (ptr, grub_handler_t, fini)) ? \ - (grub_handler_t) ptr : grub_assert_fail ()) + (grub_handler_t) ptr : grub_bad_type_cast ()) #endif /* ! GRUB_HANDLER_HEADER */ diff --git a/include/grub/hfs.h b/include/grub/hfs.h index 08b947ccb..d93b9a2c9 100644 --- a/include/grub/hfs.h +++ b/include/grub/hfs.h @@ -48,7 +48,8 @@ struct grub_hfs_sblock /* A pascal style string that holds the volumename. */ grub_uint8_t volname[28]; - grub_uint8_t unused5[60]; + grub_uint8_t unused5[52]; + grub_uint64_t num_serial; grub_uint16_t embed_sig; struct grub_hfs_extent embed_extent; grub_uint8_t unused6[4]; diff --git a/include/grub/i18n.h b/include/grub/i18n.h index f6f468744..a91d73346 100644 --- a/include/grub/i18n.h +++ b/include/grub/i18n.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 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 @@ -19,17 +19,49 @@ #ifndef GRUB_I18N_H #define GRUB_I18N_H 1 -#ifdef GRUB_UTIL -# include -# include -# define _(str) gettext(str) -#else -# define _(str) grub_gettext(str) +#include +#include + +/* NLS can be disabled through the configure --disable-nls option. */ +#if (defined(ENABLE_NLS) && ENABLE_NLS) || !defined (GRUB_UTIL) -const char *EXPORT_FUNC(grub_gettext_dummy) (const char *s); extern const char *(*EXPORT_VAR(grub_gettext)) (const char *s); -#endif +# ifdef GRUB_UTIL + +# include +# include + +# endif /* GRUB_UTIL */ + +#else /* ! (defined(ENABLE_NLS) && ENABLE_NLS) */ + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +static inline const char * __attribute__ ((always_inline)) +gettext (const char *str) +{ + return str; +} + +#endif /* (defined(ENABLE_NLS) && ENABLE_NLS) */ + +#ifdef GRUB_UTIL +static inline const char * __attribute__ ((always_inline)) +_ (const char *str) +{ + return gettext(str); +} +#else +static inline const char * __attribute__ ((always_inline)) +_ (const char *str) +{ + return grub_gettext(str); +} +#endif /* GRUB_UTIL */ #define N_(str) str diff --git a/include/grub/i386/at_keyboard.h b/include/grub/i386/at_keyboard.h index 12d61608e..da4e80654 100644 --- a/include/grub/i386/at_keyboard.h +++ b/include/grub/i386/at_keyboard.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2007,2008,2009 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 @@ -19,38 +19,7 @@ #ifndef GRUB_CPU_AT_KEYBOARD_HEADER #define GRUB_CPU_AT_KEYBOARD_HEADER 1 - -#define SHIFT_L 0x2a -#define SHIFT_R 0x36 -#define CTRL 0x1d -#define ALT 0x38 -#define CAPS_LOCK 0x3a - #define KEYBOARD_REG_DATA 0x60 #define KEYBOARD_REG_STATUS 0x64 -/* Used for sending commands to the controller. */ -#define KEYBOARD_COMMAND_ISREADY(x) !((x) & 0x02) -#define KEYBOARD_COMMAND_READ 0x20 -#define KEYBOARD_COMMAND_WRITE 0x60 -#define KEYBOARD_COMMAND_REBOOT 0xfe - -#define KEYBOARD_SCANCODE_SET1 0x40 - -#define KEYBOARD_ISMAKE(x) !((x) & 0x80) -#define KEYBOARD_ISREADY(x) ((x) & 0x01) -#define KEYBOARD_SCANCODE(x) ((x) & 0x7f) - -#ifdef GRUB_MACHINE_IEEE1275 -#define OLPC_UP GRUB_TERM_UP -#define OLPC_DOWN GRUB_TERM_DOWN -#define OLPC_LEFT GRUB_TERM_LEFT -#define OLPC_RIGHT GRUB_TERM_RIGHT -#else -#define OLPC_UP '\0' -#define OLPC_DOWN '\0' -#define OLPC_LEFT '\0' -#define OLPC_RIGHT '\0' -#endif - #endif diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h index 8ffaf7d18..4d55f04fb 100644 --- a/include/grub/i386/bsd.h +++ b/include/grub/i386/bsd.h @@ -20,6 +20,13 @@ #define GRUB_BSD_CPU_HEADER 1 #include +#include +#include +#include +#include +#include +#include + enum bsd_kernel_types { @@ -31,61 +38,11 @@ enum bsd_kernel_types #define GRUB_BSD_TEMP_BUFFER 0x80000 -#define FREEBSD_RB_ASKNAME (1 << 0) /* ask for file name to reboot from */ -#define FREEBSD_RB_SINGLE (1 << 1) /* reboot to single user only */ -#define FREEBSD_RB_NOSYNC (1 << 2) /* dont sync before reboot */ -#define FREEBSD_RB_HALT (1 << 3) /* don't reboot, just halt */ -#define FREEBSD_RB_INITNAME (1 << 4) /* name given for /etc/init (unused) */ -#define FREEBSD_RB_DFLTROOT (1 << 5) /* use compiled-in rootdev */ -#define FREEBSD_RB_KDB (1 << 6) /* give control to kernel debugger */ -#define FREEBSD_RB_RDONLY (1 << 7) /* mount root fs read-only */ -#define FREEBSD_RB_DUMP (1 << 8) /* dump kernel memory before reboot */ -#define FREEBSD_RB_MINIROOT (1 << 9) /* mini-root present in memory at boot time */ -#define FREEBSD_RB_CONFIG (1 << 10) /* invoke user configuration routing */ -#define FREEBSD_RB_VERBOSE (1 << 11) /* print all potentially useful info */ -#define FREEBSD_RB_SERIAL (1 << 12) /* user serial port as console */ -#define FREEBSD_RB_CDROM (1 << 13) /* use cdrom as root */ -#define FREEBSD_RB_GDB (1 << 15) /* use GDB remote debugger instead of DDB */ -#define FREEBSD_RB_MUTE (1 << 16) /* Come up with the console muted */ -#define FREEBSD_RB_PAUSE (1 << 20) -#define FREEBSD_RB_QUIET (1 << 21) -#define FREEBSD_RB_NOINTR (1 << 28) -#define FREENSD_RB_MULTIPLE (1 << 29) /* Use multiple consoles */ -#define FREEBSD_RB_DUAL FREENSD_RB_MULTIPLE -#define FREEBSD_RB_BOOTINFO (1 << 31) /* have `struct bootinfo *' arg */ - -#define FREEBSD_B_DEVMAGIC 0xa0000000 -#define FREEBSD_B_SLICESHIFT 20 -#define FREEBSD_B_UNITSHIFT 16 -#define FREEBSD_B_PARTSHIFT 8 -#define FREEBSD_B_TYPESHIFT 0 - -#define FREEBSD_BOOTINFO_VERSION 1 -#define FREEBSD_N_BIOS_GEOM 8 - -#define FREEBSD_MODINFO_END 0x0000 /* End of list */ -#define FREEBSD_MODINFO_NAME 0x0001 /* Name of module (string) */ -#define FREEBSD_MODINFO_TYPE 0x0002 /* Type of module (string) */ -#define FREEBSD_MODINFO_ADDR 0x0003 /* Loaded address */ -#define FREEBSD_MODINFO_SIZE 0x0004 /* Size of module */ -#define FREEBSD_MODINFO_EMPTY 0x0005 /* Has been deleted */ -#define FREEBSD_MODINFO_ARGS 0x0006 /* Parameters string */ -#define FREEBSD_MODINFO_METADATA 0x8000 /* Module-specfic */ - -#define FREEBSD_MODINFOMD_AOUTEXEC 0x0001 /* a.out exec header */ -#define FREEBSD_MODINFOMD_ELFHDR 0x0002 /* ELF header */ -#define FREEBSD_MODINFOMD_SSYM 0x0003 /* start of symbols */ -#define FREEBSD_MODINFOMD_ESYM 0x0004 /* end of symbols */ -#define FREEBSD_MODINFOMD_DYNAMIC 0x0005 /* _DYNAMIC pointer */ -#define FREEBSD_MODINFOMD_ENVP 0x0006 /* envp[] */ -#define FREEBSD_MODINFOMD_HOWTO 0x0007 /* boothowto */ -#define FREEBSD_MODINFOMD_KERNEND 0x0008 /* kernend */ -#define FREEBSD_MODINFOMD_SHDR 0x0009 /* section header table */ -#define FREEBSD_MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */ - -#define FREEBSD_MODINFOMD_SMAP 0x1001 - -#define FREEBSD_MODINFOMD_DEPLIST (0x4001 | FREEBSD_MODINFOMD_NOCOPY) /* depends on */ +#define FREEBSD_B_DEVMAGIC OPENBSD_B_DEVMAGIC +#define FREEBSD_B_SLICESHIFT OPENBSD_B_CTRLSHIFT +#define FREEBSD_B_UNITSHIFT OPENBSD_B_UNITSHIFT +#define FREEBSD_B_PARTSHIFT OPENBSD_B_PARTSHIFT +#define FREEBSD_B_TYPESHIFT OPENBSD_B_TYPESHIFT #define FREEBSD_MODTYPE_KERNEL "elf kernel" #define FREEBSD_MODTYPE_KERNEL64 "elf64 kernel" @@ -93,64 +50,21 @@ enum bsd_kernel_types #define FREEBSD_MODTYPE_ELF_MODULE_OBJ "elf obj module" #define FREEBSD_MODTYPE_RAW "raw" +#define FREEBSD_BOOTINFO_VERSION 1 + struct grub_freebsd_bootinfo { - grub_uint32_t bi_version; - grub_uint8_t *bi_kernelname; - struct nfs_diskless *bi_nfs_diskless; - grub_uint32_t bi_n_bios_used; - grub_uint32_t bi_bios_geom[FREEBSD_N_BIOS_GEOM]; - grub_uint32_t bi_size; - grub_uint8_t bi_memsizes_valid; - grub_uint8_t bi_bios_dev; - grub_uint8_t bi_pad[2]; - grub_uint32_t bi_basemem; - grub_uint32_t bi_extmem; - grub_uint32_t bi_symtab; - grub_uint32_t bi_esymtab; - grub_uint32_t bi_kernend; - grub_uint32_t bi_envp; - grub_uint32_t bi_modulep; + grub_uint32_t version; + grub_uint8_t unused1[44]; + grub_uint32_t length; + grub_uint8_t unused2; + grub_uint8_t boot_device; + grub_uint8_t unused3[18]; + grub_uint32_t kern_end; + grub_uint32_t environment; + grub_uint32_t tags; } __attribute__ ((packed)); -#define OPENBSD_RB_ASKNAME (1 << 0) /* ask for file name to reboot from */ -#define OPENBSD_RB_SINGLE (1 << 1) /* reboot to single user only */ -#define OPENBSD_RB_NOSYNC (1 << 2) /* dont sync before reboot */ -#define OPENBSD_RB_HALT (1 << 3) /* don't reboot, just halt */ -#define OPENBSD_RB_INITNAME (1 << 4) /* name given for /etc/init (unused) */ -#define OPENBSD_RB_DFLTROOT (1 << 5) /* use compiled-in rootdev */ -#define OPENBSD_RB_KDB (1 << 6) /* give control to kernel debugger */ -#define OPENBSD_RB_RDONLY (1 << 7) /* mount root fs read-only */ -#define OPENBSD_RB_DUMP (1 << 8) /* dump kernel memory before reboot */ -#define OPENBSD_RB_MINIROOT (1 << 9) /* mini-root present in memory at boot time */ -#define OPENBSD_RB_CONFIG (1 << 10) /* change configured devices */ -#define OPENBSD_RB_TIMEBAD (1 << 11) /* don't call resettodr() in boot() */ -#define OPENBSD_RB_POWERDOWN (1 << 12) /* attempt to power down machine */ -#define OPENBSD_RB_SERCONS (1 << 13) /* use serial console if available */ -#define OPENBSD_RB_USERREQ (1 << 14) /* boot() called at user request (e.g. ddb) */ - -#define OPENBSD_B_DEVMAGIC 0xa0000000 -#define OPENBSD_B_ADAPTORSHIFT 24 -#define OPENBSD_B_CTRLSHIFT 20 -#define OPENBSD_B_UNITSHIFT 16 -#define OPENBSD_B_PARTSHIFT 8 -#define OPENBSD_B_TYPESHIFT 0 - -#define OPENBSD_BOOTARG_APIVER (OPENBSD_BAPIV_VECTOR | \ - OPENBSD_BAPIV_ENV | \ - OPENBSD_BAPIV_BMEMMAP) - -#define OPENBSD_BAPIV_ANCIENT 0x0 /* MD old i386 bootblocks */ -#define OPENBSD_BAPIV_VARS 0x1 /* MD structure w/ add info passed */ -#define OPENBSD_BAPIV_VECTOR 0x2 /* MI vector of MD structures passed */ -#define OPENBSD_BAPIV_ENV 0x4 /* MI environment vars vector */ -#define OPENBSD_BAPIV_BMEMMAP 0x8 /* MI memory map passed is in bytes */ - -#define OPENBSD_BOOTARG_ENV 0x1000 -#define OPENBSD_BOOTARG_END -1 - -#define OPENBSD_BOOTARG_MMAP 0 - struct grub_openbsd_bios_mmap { grub_uint64_t addr; @@ -162,97 +76,6 @@ struct grub_openbsd_bios_mmap grub_uint32_t type; }; -struct grub_openbsd_bootargs -{ - int ba_type; - int ba_size; - struct grub_openbsd_bootargs *ba_next; -} __attribute__ ((packed)); - -#define NETBSD_RB_AUTOBOOT 0 /* flags for system auto-booting itself */ - -#define NETBSD_RB_ASKNAME (1 << 0) /* ask for file name to reboot from */ -#define NETBSD_RB_SINGLE (1 << 1) /* reboot to single user only */ -#define NETBSD_RB_NOSYNC (1 << 2) /* dont sync before reboot */ -#define NETBSD_RB_HALT (1 << 3) /* don't reboot, just halt */ -#define NETBSD_RB_INITNAME (1 << 4) /* name given for /etc/init (unused) */ -#define NETBSD_RB_UNUSED1 (1 << 5) /* was RB_DFLTROOT, obsolete */ -#define NETBSD_RB_KDB (1 << 6) /* give control to kernel debugger */ -#define NETBSD_RB_RDONLY (1 << 7) /* mount root fs read-only */ -#define NETBSD_RB_DUMP (1 << 8) /* dump kernel memory before reboot */ -#define NETBSD_RB_MINIROOT (1 << 9) /* mini-root present in memory at boot time */ -#define NETBSD_RB_STRING (1 << 10) /* use provided bootstr */ -#define NETBSD_RB_POWERDOWN ((1 << 11) | RB_HALT) /* turn power off (or at least halt) */ -#define NETBSD_RB_USERCONFIG (1 << 12) /* change configured devices */ - -#define NETBSD_AB_NORMAL 0 /* boot normally (default) */ - -#define NETBSD_AB_QUIET (1 << 16) /* boot quietly */ -#define NETBSD_AB_VERBOSE (1 << 17) /* boot verbosely */ -#define NETBSD_AB_SILENT (1 << 18) /* boot silently */ -#define NETBSD_AB_DEBUG (1 << 19) /* boot with debug messages */ -#define NETBSD_AB_NOSMP (1 << 28) /* Boot without SMP support. */ -#define NETBSD_AB_NOACPI (1 << 29) /* Boot without ACPI support. */ - -struct grub_netbsd_bootinfo -{ - grub_uint32_t bi_count; - void *bi_data[1]; -}; - -#define NETBSD_BTINFO_BOOTPATH 0 -#define NETBSD_BTINFO_ROOTDEVICE 1 -#define NETBSD_BTINFO_BOOTDISK 3 -#define NETBSD_BTINFO_MEMMAP 9 - -struct grub_netbsd_btinfo_common -{ - int len; - int type; -}; - -struct grub_netbsd_btinfo_mmap_header -{ - struct grub_netbsd_btinfo_common common; - grub_uint32_t count; -}; - -struct grub_netbsd_btinfo_mmap_entry -{ - grub_uint64_t addr; - grub_uint64_t len; -#define NETBSD_MMAP_AVAILABLE 1 -#define NETBSD_MMAP_RESERVED 2 -#define NETBSD_MMAP_ACPI 3 -#define NETBSD_MMAP_NVS 4 - grub_uint32_t type; -}; - -struct grub_netbsd_btinfo_bootpath -{ - struct grub_netbsd_btinfo_common common; - char bootpath[80]; -}; - -struct grub_netbsd_btinfo_rootdevice -{ - struct grub_netbsd_btinfo_common common; - char devname[16]; -}; - -struct grub_netbsd_btinfo_bootdisk -{ - struct grub_netbsd_btinfo_common common; - int labelsector; /* label valid if != -1 */ - struct - { - grub_uint16_t type, checksum; - char packname[16]; - } label; - int biosdev; - int partition; -}; - void grub_unix_real_boot (grub_addr_t entry, ...) __attribute__ ((cdecl,noreturn)); grub_err_t grub_freebsd_load_elfmodule32 (grub_file_t file, int argc, diff --git a/include/grub/i386/cmos.h b/include/grub/i386/cmos.h index 1c0530dba..8b1fa3586 100644 --- a/include/grub/i386/cmos.h +++ b/include/grub/i386/cmos.h @@ -20,55 +20,9 @@ #define GRUB_CPU_CMOS_H 1 #include -#include +#include #define GRUB_CMOS_ADDR_REG 0x70 #define GRUB_CMOS_DATA_REG 0x71 -#define GRUB_CMOS_INDEX_SECOND 0 -#define GRUB_CMOS_INDEX_SECOND_ALARM 1 -#define GRUB_CMOS_INDEX_MINUTE 2 -#define GRUB_CMOS_INDEX_MINUTE_ALARM 3 -#define GRUB_CMOS_INDEX_HOUR 4 -#define GRUB_CMOS_INDEX_HOUR_ALARM 5 -#define GRUB_CMOS_INDEX_DAY_OF_WEEK 6 -#define GRUB_CMOS_INDEX_DAY_OF_MONTH 7 -#define GRUB_CMOS_INDEX_MONTH 8 -#define GRUB_CMOS_INDEX_YEAR 9 - -#define GRUB_CMOS_INDEX_STATUS_A 0xA -#define GRUB_CMOS_INDEX_STATUS_B 0xB -#define GRUB_CMOS_INDEX_STATUS_C 0xC -#define GRUB_CMOS_INDEX_STATUS_D 0xD - -#define GRUB_CMOS_STATUS_B_DAYLIGHT 1 -#define GRUB_CMOS_STATUS_B_24HOUR 2 -#define GRUB_CMOS_STATUS_B_BINARY 4 - -static inline grub_uint8_t -grub_bcd_to_num (grub_uint8_t a) -{ - return ((a >> 4) * 10 + (a & 0xF)); -} - -static inline grub_uint8_t -grub_num_to_bcd (grub_uint8_t a) -{ - return (((a / 10) << 4) + (a % 10)); -} - -static inline grub_uint8_t -grub_cmos_read (grub_uint8_t index) -{ - grub_outb (index, GRUB_CMOS_ADDR_REG); - return grub_inb (GRUB_CMOS_DATA_REG); -} - -static inline void -grub_cmos_write (grub_uint8_t index, grub_uint8_t value) -{ - grub_outb (index, GRUB_CMOS_ADDR_REG); - grub_outb (value, GRUB_CMOS_DATA_REG); -} - #endif /* GRUB_CPU_CMOS_H */ diff --git a/include/grub/i386/coreboot/memory.h b/include/grub/i386/coreboot/memory.h index 434ae622e..664086a81 100644 --- a/include/grub/i386/coreboot/memory.h +++ b/include/grub/i386/coreboot/memory.h @@ -44,8 +44,9 @@ typedef struct grub_linuxbios_table_header *grub_linuxbios_table_header_t; struct grub_linuxbios_table_item { -#define GRUB_LINUXBIOS_MEMBER_UNUSED 0 -#define GRUB_LINUXBIOS_MEMBER_MEMORY 1 +#define GRUB_LINUXBIOS_MEMBER_UNUSED 0x00 +#define GRUB_LINUXBIOS_MEMBER_MEMORY 0x01 +#define GRUB_LINUXBIOS_MEMBER_LINK 0x11 grub_uint32_t tag; grub_uint32_t size; }; diff --git a/include/grub/i386/coreboot/serial.h b/include/grub/i386/coreboot/serial.h index 2c527f626..b6819d587 100644 --- a/include/grub/i386/coreboot/serial.h +++ b/include/grub/i386/coreboot/serial.h @@ -1 +1,24 @@ -#include +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#ifndef GRUB_MACHINE_SERIAL_HEADER +#define GRUB_MACHINE_SERIAL_HEADER 1 + +#define GRUB_MACHINE_SERIAL_PORTS { 0x3f8, 0x2f8, 0x3e8, 0x2e8 } + +#endif diff --git a/include/grub/i386/efi/serial.h b/include/grub/i386/efi/serial.h new file mode 100644 index 000000000..2d8563414 --- /dev/null +++ b/include/grub/i386/efi/serial.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/freebsd_linker.h b/include/grub/i386/freebsd_linker.h new file mode 100644 index 000000000..3c1eb64b6 --- /dev/null +++ b/include/grub/i386/freebsd_linker.h @@ -0,0 +1,74 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +/*- + * Copyright (c) 1997-2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: stable/8/sys/sys/linker.h 199583 2009-11-20 15:27:52Z jhb $ + */ + +#ifndef GRUB_FREEBSD_LINKER_CPU_HEADER +#define GRUB_FREEBSD_LINKER_CPU_HEADER 1 + +#define FREEBSD_MODINFO_END 0x0000 /* End of list */ +#define FREEBSD_MODINFO_NAME 0x0001 /* Name of module (string) */ +#define FREEBSD_MODINFO_TYPE 0x0002 /* Type of module (string) */ +#define FREEBSD_MODINFO_ADDR 0x0003 /* Loaded address */ +#define FREEBSD_MODINFO_SIZE 0x0004 /* Size of module */ +#define FREEBSD_MODINFO_EMPTY 0x0005 /* Has been deleted */ +#define FREEBSD_MODINFO_ARGS 0x0006 /* Parameters string */ +#define FREEBSD_MODINFO_METADATA 0x8000 /* Module-specfic */ + +#define FREEBSD_MODINFOMD_AOUTEXEC 0x0001 /* a.out exec header */ +#define FREEBSD_MODINFOMD_ELFHDR 0x0002 /* ELF header */ +#define FREEBSD_MODINFOMD_SSYM 0x0003 /* start of symbols */ +#define FREEBSD_MODINFOMD_ESYM 0x0004 /* end of symbols */ +#define FREEBSD_MODINFOMD_DYNAMIC 0x0005 /* _DYNAMIC pointer */ +#define FREEBSD_MODINFOMD_ENVP 0x0006 /* envp[] */ +#define FREEBSD_MODINFOMD_HOWTO 0x0007 /* boothowto */ +#define FREEBSD_MODINFOMD_KERNEND 0x0008 /* kernend */ +#define FREEBSD_MODINFOMD_SHDR 0x0009 /* section header table */ +#define FREEBSD_MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */ + +#define FREEBSD_MODINFOMD_SMAP 0x1001 + +#define FREEBSD_MODINFOMD_DEPLIST (0x4001 | FREEBSD_MODINFOMD_NOCOPY) /* depends on */ + +#endif diff --git a/include/grub/i386/freebsd_reboot.h b/include/grub/i386/freebsd_reboot.h new file mode 100644 index 000000000..9c17f6efa --- /dev/null +++ b/include/grub/i386/freebsd_reboot.h @@ -0,0 +1,77 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +/*- + * Copyright (c) 1982, 1986, 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)reboot.h 8.3 (Berkeley) 12/13/94 + * $FreeBSD: stable/8/sys/sys/reboot.h 199583 2009-11-20 15:27:52Z jhb $ + */ + +#ifndef GRUB_FREEBSD_REBOOT_CPU_HEADER +#define GRUB_FREEBSD_REBOOT_CPU_HEADER 1 + +#define FREEBSD_RB_ASKNAME (1 << 0) /* ask for file name to reboot from */ +#define FREEBSD_RB_SINGLE (1 << 1) /* reboot to single user only */ +#define FREEBSD_RB_NOSYNC (1 << 2) /* dont sync before reboot */ +#define FREEBSD_RB_HALT (1 << 3) /* don't reboot, just halt */ +#define FREEBSD_RB_INITNAME (1 << 4) /* name given for /etc/init (unused) */ +#define FREEBSD_RB_DFLTROOT (1 << 5) /* use compiled-in rootdev */ +#define FREEBSD_RB_KDB (1 << 6) /* give control to kernel debugger */ +#define FREEBSD_RB_RDONLY (1 << 7) /* mount root fs read-only */ +#define FREEBSD_RB_DUMP (1 << 8) /* dump kernel memory before reboot */ +#define FREEBSD_RB_MINIROOT (1 << 9) /* mini-root present in memory at boot time */ +#define FREEBSD_RB_CONFIG (1 << 10) /* invoke user configuration routing */ +#define FREEBSD_RB_VERBOSE (1 << 11) /* print all potentially useful info */ +#define FREEBSD_RB_SERIAL (1 << 12) /* user serial port as console */ +#define FREEBSD_RB_CDROM (1 << 13) /* use cdrom as root */ +#define FREEBSD_RB_GDB (1 << 15) /* use GDB remote debugger instead of DDB */ +#define FREEBSD_RB_MUTE (1 << 16) /* Come up with the console muted */ +#define FREEBSD_RB_PAUSE (1 << 20) +#define FREEBSD_RB_QUIET (1 << 21) +#define FREEBSD_RB_NOINTR (1 << 28) +#define FREENSD_RB_MULTIPLE (1 << 29) /* Use multiple consoles */ +#define FREEBSD_RB_DUAL FREENSD_RB_MULTIPLE +#define FREEBSD_RB_BOOTINFO (1 << 31) /* have `struct bootinfo *' arg */ + +#endif diff --git a/include/grub/i386/ieee1275/kernel.h b/include/grub/i386/ieee1275/kernel.h deleted file mode 100644 index dccf8cbe1..000000000 --- a/include/grub/i386/ieee1275/kernel.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/grub/i386/ieee1275/serial.h b/include/grub/i386/ieee1275/serial.h index 2c527f626..2d8563414 100644 --- a/include/grub/i386/ieee1275/serial.h +++ b/include/grub/i386/ieee1275/serial.h @@ -1 +1 @@ -#include +#include diff --git a/include/grub/i386/io.h b/include/grub/i386/io.h index 0e567766b..ae12a3e3d 100644 --- a/include/grub/i386/io.h +++ b/include/grub/i386/io.h @@ -21,6 +21,8 @@ #ifndef GRUB_IO_H #define GRUB_IO_H 1 +typedef unsigned short int grub_port_t; + static __inline unsigned char grub_inb (unsigned short int port) { diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h index 8a5a84da3..f02a722d6 100644 --- a/include/grub/i386/linux.h +++ b/include/grub/i386/linux.h @@ -79,9 +79,9 @@ struct grub_e820_mmap grub_uint32_t type; } __attribute__((packed)); -#define GRUB_VIDEO_TYPE_TEXT 0x01 -#define GRUB_VIDEO_TYPE_VLFB 0x23 /* VESA VGA in graphic mode */ -#define GRUB_VIDEO_TYPE_EFI 0x70 +#define GRUB_VIDEO_LINUX_TYPE_TEXT 0x01 +#define GRUB_VIDEO_LINUX_TYPE_VESA 0x23 /* VESA VGA in graphic mode. */ +#define GRUB_VIDEO_LINUX_TYPE_SIMPLE 0x70 /* Linear framebuffer without any additional functions. */ /* For the Linux/i386 boot protocol version 2.03. */ struct linux_kernel_header diff --git a/include/grub/i386/loader.h b/include/grub/i386/loader.h index 0df5f757f..05954b6db 100644 --- a/include/grub/i386/loader.h +++ b/include/grub/i386/loader.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2004,2007,2008,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 @@ -31,7 +31,7 @@ extern grub_uint32_t EXPORT_VAR(grub_linux_prot_size); extern char *EXPORT_VAR(grub_linux_tmp_addr); extern char *EXPORT_VAR(grub_linux_real_addr); extern grub_int32_t EXPORT_VAR(grub_linux_is_bzimage); -grub_err_t EXPORT_FUNC(grub_linux16_boot) (void); +grub_err_t EXPORT_FUNC(grub_linux16_real_boot) (void); #endif #endif /* ! GRUB_LOADER_CPU_HEADER */ diff --git a/include/grub/i386/macho.h b/include/grub/i386/macho.h index 61e72a71b..f22c21190 100644 --- a/include/grub/i386/macho.h +++ b/include/grub/i386/macho.h @@ -1,3 +1,26 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#ifndef GRUB_CPU_MACHO_H +#define GRUB_CPU_MACHO_H 1 + +#include + #define GRUB_MACHO_CPUTYPE_IS_HOST32(x) ((x)==0x00000007) #define GRUB_MACHO_CPUTYPE_IS_HOST64(x) ((x)==0x01000007) @@ -9,3 +32,15 @@ struct grub_macho_thread32 grub_uint32_t entry_point; grub_uint8_t unknown2[20]; } __attribute__ ((packed)); + + +struct grub_macho_thread64 +{ + grub_uint32_t cmd; + grub_uint32_t cmdsize; + grub_uint8_t unknown1[0x88]; + grub_uint64_t entry_point; + grub_uint8_t unknown2[0x20]; +} __attribute__ ((packed)); + +#endif diff --git a/include/grub/i386/efi/kernel.h b/include/grub/i386/memory.h similarity index 58% rename from include/grub/i386/efi/kernel.h rename to include/grub/i386/memory.h index c0549f41a..466947cc6 100644 --- a/include/grub/i386/efi/kernel.h +++ b/include/grub/i386/memory.h @@ -1,6 +1,7 @@ +/* memory.h - describe the memory map */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2007 Free Software Foundation, Inc. + * Copyright (C) 2002,2007,2008,2009 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 @@ -16,18 +17,14 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_MACHINE_KERNEL_HEADER -#define GRUB_MACHINE_KERNEL_HEADER 1 +#ifndef GRUB_MEMORY_CPU_HEADER +#define GRUB_MEMORY_CPU_HEADER 1 -/* The prefix which points to the directory where GRUB modules and its - configuration file are located. */ -extern char grub_prefix[]; - -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_MACHINE_PREFIX 0x8 - -/* End of the data section. */ -#define GRUB_KERNEL_MACHINE_DATA_END 0x50 - -#endif /* ! GRUB_MACHINE_KERNEL_HEADER */ +/* The flag for protected mode. */ +#define GRUB_MEMORY_CPU_CR0_PE_ON 0x1 +#define GRUB_MEMORY_CPU_CR4_PAE_ON 0x00000040 +#define GRUB_MEMORY_CPU_CR0_PAGING_ON 0x80000000 +#define GRUB_MEMORY_CPU_AMD64_MSR 0xc0000080 +#define GRUB_MEMORY_CPU_AMD64_MSR_ON 0x00000100 +#endif /* ! GRUB_MEMORY_CPU_HEADER */ diff --git a/include/grub/i386/multiboot.h b/include/grub/i386/multiboot.h index b8cab9d24..1c711fad4 100644 --- a/include/grub/i386/multiboot.h +++ b/include/grub/i386/multiboot.h @@ -19,24 +19,23 @@ #ifndef GRUB_MULTIBOOT_CPU_HEADER #define GRUB_MULTIBOOT_CPU_HEADER 1 -/* The asm part of the multiboot loader. */ -void grub_multiboot_real_boot (grub_addr_t entry, - struct multiboot_info *mbi) - __attribute__ ((noreturn)); -void grub_multiboot2_real_boot (grub_addr_t entry, - struct multiboot_info *mbi) - __attribute__ ((noreturn)); - -extern grub_addr_t grub_multiboot_payload_orig; +extern grub_uint32_t grub_multiboot_payload_eip; +extern char *grub_multiboot_payload_orig; extern grub_addr_t grub_multiboot_payload_dest; extern grub_size_t grub_multiboot_payload_size; -extern grub_uint32_t grub_multiboot_payload_entry_offset; -extern grub_uint8_t grub_multiboot_forward_relocator; -extern grub_uint8_t grub_multiboot_forward_relocator_end; -extern grub_uint8_t grub_multiboot_backward_relocator; -extern grub_uint8_t grub_multiboot_backward_relocator_end; +#define MULTIBOOT_INITIAL_STATE { .eax = MULTIBOOT_BOOTLOADER_MAGIC, \ + .ecx = 0, \ + .edx = 0, \ + /* Set esp to some random location in low memory to avoid breaking */ \ + /* non-compliant kernels. */ \ + .esp = 0x7ff00 \ + } +#define MULTIBOOT_ENTRY_REGISTER eip +#define MULTIBOOT_MBI_REGISTER ebx +#define MULTIBOOT_ARCHITECTURE_CURRENT MULTIBOOT_ARCHITECTURE_I386 -#define RELOCATOR_SIZEOF(x) (&grub_multiboot_##x##_relocator_end - &grub_multiboot_##x##_relocator) +#define MULTIBOOT_ELF32_MACHINE EM_386 +#define MULTIBOOT_ELF64_MACHINE EM_X86_64 #endif /* ! GRUB_MULTIBOOT_CPU_HEADER */ diff --git a/include/grub/i386/multiboot/boot.h b/include/grub/i386/multiboot/boot.h new file mode 100644 index 000000000..c33f9bac0 --- /dev/null +++ b/include/grub/i386/multiboot/boot.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/multiboot/console.h b/include/grub/i386/multiboot/console.h new file mode 100644 index 000000000..774399a4e --- /dev/null +++ b/include/grub/i386/multiboot/console.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/multiboot/init.h b/include/grub/i386/multiboot/init.h new file mode 100644 index 000000000..fd935c3a2 --- /dev/null +++ b/include/grub/i386/multiboot/init.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/multiboot/kernel.h b/include/grub/i386/multiboot/kernel.h new file mode 100644 index 000000000..b41e86ebb --- /dev/null +++ b/include/grub/i386/multiboot/kernel.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/multiboot/loader.h b/include/grub/i386/multiboot/loader.h new file mode 100644 index 000000000..1c725be19 --- /dev/null +++ b/include/grub/i386/multiboot/loader.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/multiboot/memory.h b/include/grub/i386/multiboot/memory.h new file mode 100644 index 000000000..8dd6f7c8c --- /dev/null +++ b/include/grub/i386/multiboot/memory.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/multiboot/serial.h b/include/grub/i386/multiboot/serial.h new file mode 100644 index 000000000..2d8563414 --- /dev/null +++ b/include/grub/i386/multiboot/serial.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/multiboot/time.h b/include/grub/i386/multiboot/time.h new file mode 100644 index 000000000..7177c7488 --- /dev/null +++ b/include/grub/i386/multiboot/time.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/i386/netbsd_bootinfo.h b/include/grub/i386/netbsd_bootinfo.h new file mode 100644 index 000000000..776ecf3b0 --- /dev/null +++ b/include/grub/i386/netbsd_bootinfo.h @@ -0,0 +1,112 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +/* $NetBSD: bootinfo.h,v 1.16 2009/08/24 02:15:46 jmcneill Exp $ */ + +/* + * Copyright (c) 1997 + * Matthias Drochner. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRUB_NETBSD_BOOTINFO_CPU_HEADER +#define GRUB_NETBSD_BOOTINFO_CPU_HEADER 1 + +#include + + +#define NETBSD_BTINFO_BOOTPATH 0 +#define NETBSD_BTINFO_ROOTDEVICE 1 +#define NETBSD_BTINFO_BOOTDISK 3 +#define NETBSD_BTINFO_MEMMAP 9 + +struct grub_netbsd_btinfo_common +{ + int len; + int type; +}; + +struct grub_netbsd_btinfo_mmap_header +{ + struct grub_netbsd_btinfo_common common; + grub_uint32_t count; +}; + +struct grub_netbsd_btinfo_mmap_entry +{ + grub_uint64_t addr; + grub_uint64_t len; +#define NETBSD_MMAP_AVAILABLE 1 +#define NETBSD_MMAP_RESERVED 2 +#define NETBSD_MMAP_ACPI 3 +#define NETBSD_MMAP_NVS 4 + grub_uint32_t type; +}; + +struct grub_netbsd_btinfo_bootpath +{ + struct grub_netbsd_btinfo_common common; + char bootpath[80]; +}; + +struct grub_netbsd_btinfo_rootdevice +{ + struct grub_netbsd_btinfo_common common; + char devname[16]; +}; + +struct grub_netbsd_btinfo_bootdisk +{ + struct grub_netbsd_btinfo_common common; + int labelsector; /* label valid if != -1 */ + struct + { + grub_uint16_t type, checksum; + char packname[16]; + } label; + int biosdev; + int partition; +}; + +struct grub_netbsd_bootinfo +{ + grub_uint32_t bi_count; + void *bi_data[1]; +}; + +#endif diff --git a/include/grub/i386/netbsd_reboot.h b/include/grub/i386/netbsd_reboot.h new file mode 100644 index 000000000..ee82455bc --- /dev/null +++ b/include/grub/i386/netbsd_reboot.h @@ -0,0 +1,81 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +/* $NetBSD: reboot.h,v 1.25 2007/12/25 18:33:48 perry Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)reboot.h 8.3 (Berkeley) 12/13/94 + */ + +#ifndef GRUB_NETBSD_REBOOT_CPU_HEADER +#define GRUB_NETBSD_REBOOT_CPU_HEADER 1 + +#define NETBSD_RB_AUTOBOOT 0 /* flags for system auto-booting itself */ + +#define NETBSD_RB_ASKNAME (1 << 0) /* ask for file name to reboot from */ +#define NETBSD_RB_SINGLE (1 << 1) /* reboot to single user only */ +#define NETBSD_RB_NOSYNC (1 << 2) /* dont sync before reboot */ +#define NETBSD_RB_HALT (1 << 3) /* don't reboot, just halt */ +#define NETBSD_RB_INITNAME (1 << 4) /* name given for /etc/init (unused) */ +#define NETBSD_RB_UNUSED1 (1 << 5) /* was RB_DFLTROOT, obsolete */ +#define NETBSD_RB_KDB (1 << 6) /* give control to kernel debugger */ +#define NETBSD_RB_RDONLY (1 << 7) /* mount root fs read-only */ +#define NETBSD_RB_DUMP (1 << 8) /* dump kernel memory before reboot */ +#define NETBSD_RB_MINIROOT (1 << 9) /* mini-root present in memory at boot time */ +#define NETBSD_RB_STRING (1 << 10) /* use provided bootstr */ +#define NETBSD_RB_POWERDOWN ((1 << 11) | RB_HALT) /* turn power off (or at least halt) */ +#define NETBSD_RB_USERCONFIG (1 << 12) /* change configured devices */ + +#define NETBSD_AB_NORMAL 0 /* boot normally (default) */ + +#define NETBSD_AB_QUIET (1 << 16) /* boot quietly */ +#define NETBSD_AB_VERBOSE (1 << 17) /* boot verbosely */ +#define NETBSD_AB_SILENT (1 << 18) /* boot silently */ +#define NETBSD_AB_DEBUG (1 << 19) /* boot with debug messages */ +#define NETBSD_AB_NOSMP (1 << 28) /* Boot without SMP support. */ +#define NETBSD_AB_NOACPI (1 << 29) /* Boot without ACPI support. */ + + +#endif diff --git a/include/grub/i386/openbsd_bootarg.h b/include/grub/i386/openbsd_bootarg.h new file mode 100644 index 000000000..ccbe1ca12 --- /dev/null +++ b/include/grub/i386/openbsd_bootarg.h @@ -0,0 +1,72 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +/* $OpenBSD: bootarg.h,v 1.11 2003/06/02 20:20:54 mickey Exp $ */ + +/* + * Copyright (c) 1996-1999 Michael Shalayeff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GRUB_OPENBSD_BOOTARG_CPU_HEADER +#define GRUB_OPENBSD_BOOTARG_CPU_HEADER 1 + +#define OPENBSD_BOOTARG_APIVER (OPENBSD_BAPIV_VECTOR | \ + OPENBSD_BAPIV_ENV | \ + OPENBSD_BAPIV_BMEMMAP) + +#define OPENBSD_BAPIV_ANCIENT 0x0 /* MD old i386 bootblocks */ +#define OPENBSD_BAPIV_VARS 0x1 /* MD structure w/ add info passed */ +#define OPENBSD_BAPIV_VECTOR 0x2 /* MI vector of MD structures passed */ +#define OPENBSD_BAPIV_ENV 0x4 /* MI environment vars vector */ +#define OPENBSD_BAPIV_BMEMMAP 0x8 /* MI memory map passed is in bytes */ + +#define OPENBSD_BOOTARG_ENV 0x1000 +#define OPENBSD_BOOTARG_END -1 + +#define OPENBSD_BOOTARG_MMAP 0 + +struct grub_openbsd_bootargs +{ + int ba_type; + int ba_size; + struct grub_openbsd_bootargs *ba_next; +} __attribute__ ((packed)); + +#endif diff --git a/include/grub/i386/openbsd_reboot.h b/include/grub/i386/openbsd_reboot.h new file mode 100644 index 000000000..3f6571a44 --- /dev/null +++ b/include/grub/i386/openbsd_reboot.h @@ -0,0 +1,79 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +/* $OpenBSD: reboot.h,v 1.13 2004/03/10 23:02:53 tom Exp $ */ +/* $NetBSD: reboot.h,v 1.9 1996/04/22 01:23:25 christos Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)reboot.h 8.2 (Berkeley) 7/10/94 + */ + +#ifndef GRUB_OPENBSD_REBOOT_CPU_HEADER +#define GRUB_OPENBSD_REBOOT_CPU_HEADER 1 + +#define OPENBSD_RB_ASKNAME (1 << 0) /* ask for file name to reboot from */ +#define OPENBSD_RB_SINGLE (1 << 1) /* reboot to single user only */ +#define OPENBSD_RB_NOSYNC (1 << 2) /* dont sync before reboot */ +#define OPENBSD_RB_HALT (1 << 3) /* don't reboot, just halt */ +#define OPENBSD_RB_INITNAME (1 << 4) /* name given for /etc/init (unused) */ +#define OPENBSD_RB_DFLTROOT (1 << 5) /* use compiled-in rootdev */ +#define OPENBSD_RB_KDB (1 << 6) /* give control to kernel debugger */ +#define OPENBSD_RB_RDONLY (1 << 7) /* mount root fs read-only */ +#define OPENBSD_RB_DUMP (1 << 8) /* dump kernel memory before reboot */ +#define OPENBSD_RB_MINIROOT (1 << 9) /* mini-root present in memory at boot time */ +#define OPENBSD_RB_CONFIG (1 << 10) /* change configured devices */ +#define OPENBSD_RB_TIMEBAD (1 << 11) /* don't call resettodr() in boot() */ +#define OPENBSD_RB_POWERDOWN (1 << 12) /* attempt to power down machine */ +#define OPENBSD_RB_SERCONS (1 << 13) /* use serial console if available */ +#define OPENBSD_RB_USERREQ (1 << 14) /* boot() called at user request (e.g. ddb) */ + +#define OPENBSD_B_DEVMAGIC 0xa0000000 +#define OPENBSD_B_ADAPTORSHIFT 24 +#define OPENBSD_B_CTRLSHIFT 20 +#define OPENBSD_B_UNITSHIFT 16 +#define OPENBSD_B_PARTSHIFT 8 +#define OPENBSD_B_TYPESHIFT 0 + +#endif diff --git a/include/grub/i386/pc/boot.h b/include/grub/i386/pc/boot.h index f45fe6da0..a4d42ff3c 100644 --- a/include/grub/i386/pc/boot.h +++ b/include/grub/i386/pc/boot.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2002,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2002,2005,2006,2007,2008,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 @@ -19,6 +19,8 @@ #ifndef GRUB_BOOT_MACHINE_HEADER #define GRUB_BOOT_MACHINE_HEADER 1 +#include + /* The signature for bootloader. */ #define GRUB_BOOT_MACHINE_SIGNATURE 0xaa55 @@ -57,13 +59,15 @@ floppy. */ #define GRUB_BOOT_MACHINE_BIOS_HD_FLAG 0x80 -/* The segment where the kernel is loaded. */ -#define GRUB_BOOT_MACHINE_KERNEL_SEG 0x800 - /* The address where the kernel is loaded. */ #define GRUB_BOOT_MACHINE_KERNEL_ADDR (GRUB_BOOT_MACHINE_KERNEL_SEG << 4) /* The size of a block list used in the kernel startup code. */ #define GRUB_BOOT_MACHINE_LIST_SIZE 12 +#define GRUB_BOOT_MACHINE_PXE_DL 0x7f + +/* This is the blocklist used in the diskboot image. */ +#define grub_boot_blocklist grub_pc_bios_boot_blocklist + #endif /* ! BOOT_MACHINE_HEADER */ diff --git a/include/grub/i386/pc/init.h b/include/grub/i386/pc/init.h index 2be80e773..30130d189 100644 --- a/include/grub/i386/pc/init.h +++ b/include/grub/i386/pc/init.h @@ -33,7 +33,7 @@ grub_uint32_t grub_get_eisa_mmap (void); /* Get a memory map entry. Return next continuation value. Zero means the end. */ -grub_uint32_t EXPORT_FUNC(grub_get_mmap_entry) (struct grub_machine_mmap_entry *entry, +grub_uint32_t grub_get_mmap_entry (struct grub_machine_mmap_entry *entry, grub_uint32_t cont); /* Turn on/off Gate A20. */ diff --git a/include/grub/i386/pc/kernel.h b/include/grub/i386/pc/kernel.h index e830afae2..1de37a5d5 100644 --- a/include/grub/i386/pc/kernel.h +++ b/include/grub/i386/pc/kernel.h @@ -19,29 +19,7 @@ #ifndef KERNEL_MACHINE_HEADER #define KERNEL_MACHINE_HEADER 1 -/* The offset of GRUB_TOTAL_MODULE_SIZE. */ -#define GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE 0x8 - -/* The offset of GRUB_KERNEL_IMAGE_SIZE. */ -#define GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE 0xc - -/* The offset of GRUB_COMPRESSED_SIZE. */ -#define GRUB_KERNEL_MACHINE_COMPRESSED_SIZE 0x10 - -/* The offset of GRUB_INSTALL_DOS_PART. */ -#define GRUB_KERNEL_MACHINE_INSTALL_DOS_PART 0x14 - -/* The offset of GRUB_INSTALL_BSD_PART. */ -#define GRUB_KERNEL_MACHINE_INSTALL_BSD_PART 0x18 - -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_MACHINE_PREFIX 0x1c - -/* End of the data section. */ -#define GRUB_KERNEL_MACHINE_DATA_END 0x5c - -/* The size of the first region which won't be compressed. */ -#define GRUB_KERNEL_MACHINE_RAW_SIZE (GRUB_KERNEL_MACHINE_DATA_END + 0x5F0) +#include /* Enable LZMA compression */ #define ENABLE_LZMA 1 @@ -63,10 +41,6 @@ extern grub_int32_t grub_install_dos_part; /* The BSD partition number of the installed partition. */ extern grub_int32_t grub_install_bsd_part; -/* The prefix which points to the directory where GRUB modules and its - configuration file are located. */ -extern char grub_prefix[]; - /* The boot BIOS drive number. */ extern grub_uint8_t EXPORT_VAR(grub_boot_drive); diff --git a/include/grub/i386/pc/memory.h b/include/grub/i386/pc/memory.h index 4ce3a6283..68f5e8bc9 100644 --- a/include/grub/i386/pc/memory.h +++ b/include/grub/i386/pc/memory.h @@ -1,7 +1,7 @@ /* memory.h - describe the memory map */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2007,2008,2009 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 @@ -27,6 +27,10 @@ #include #endif +#include + +#include + /* The scratch buffer used in real mode code. */ #define GRUB_MEMORY_MACHINE_SCRATCH_ADDR 0x68000 #define GRUB_MEMORY_MACHINE_SCRATCH_SEG (GRUB_MEMORY_MACHINE_SCRATCH_ADDR >> 4) @@ -38,9 +42,6 @@ /* The size of the protect mode stack. */ #define GRUB_MEMORY_MACHINE_PROT_STACK_SIZE 0x8000 -/* The upper memory area (starting at 640 kiB). */ -#define GRUB_MEMORY_MACHINE_UPPER 0xa0000 - /* The protected mode stack. */ #define GRUB_MEMORY_MACHINE_PROT_STACK \ (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + GRUB_MEMORY_MACHINE_SCRATCH_SIZE \ @@ -62,9 +63,6 @@ /* The address where another boot loader is loaded. */ #define GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR 0x7c00 -/* The flag for protected mode. */ -#define GRUB_MEMORY_MACHINE_CR0_PE_ON 0x1 - /* The code segment of the protected mode. */ #define GRUB_MEMORY_MACHINE_PROT_MODE_CSEG 0x8 @@ -86,7 +84,7 @@ struct grub_machine_bios_data_area { grub_uint8_t unused1[0x17]; - grub_uint8_t keyboard_flag_lower; /* 0x17 */ + grub_uint8_t keyboard_flag_lower; /* 0x17 */ grub_uint8_t unused2[0xf0 - 0x18]; }; diff --git a/include/grub/i386/pc/pxe.h b/include/grub/i386/pc/pxe.h index 482132896..39f356c83 100644 --- a/include/grub/i386/pc/pxe.h +++ b/include/grub/i386/pc/pxe.h @@ -201,7 +201,7 @@ struct grub_pxenv_get_cached_info #define GRUB_PXE_MAC_ADDR_LEN 16 -typedef grub_uint8_t grub_pxe_mac_addr[GRUB_PXE_MAC_ADDR_LEN]; +typedef grub_uint8_t grub_pxe_mac_addr_t[GRUB_PXE_MAC_ADDR_LEN]; struct grub_pxenv_boot_player { @@ -216,7 +216,7 @@ struct grub_pxenv_boot_player grub_uint32_t your_ip; grub_uint32_t server_ip; grub_uint32_t gateway_ip; - grub_pxe_mac_addr mac_addr; + grub_pxe_mac_addr_t mac_addr; grub_uint8_t server_name[64]; grub_uint8_t boot_file[128]; union @@ -306,10 +306,6 @@ struct grub_pxenv * EXPORT_FUNC(grub_pxe_scan) (void); int EXPORT_FUNC(grub_pxe_call) (int func, void * data); extern struct grub_pxenv *grub_pxe_pxenv; -extern grub_uint32_t grub_pxe_your_ip; -extern grub_uint32_t grub_pxe_server_ip; -extern grub_uint32_t grub_pxe_gateway_ip; -extern int grub_pxe_blksize; void grub_pxe_unload (void); diff --git a/include/grub/i386/pc/vbe.h b/include/grub/i386/pc/vbe.h index 32427679b..abf246fa1 100644 --- a/include/grub/i386/pc/vbe.h +++ b/include/grub/i386/pc/vbe.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2005,2006,2007,2008,2009 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 @@ -19,8 +19,6 @@ #ifndef GRUB_VBE_MACHINE_HEADER #define GRUB_VBE_MACHINE_HEADER 1 -#include - /* Default video mode to be used. */ #define GRUB_VBE_DEFAULT_VIDEO_MODE 0x101 diff --git a/include/grub/i386/pc/vga.h b/include/grub/i386/pc/vga.h index b9822395b..2724f6401 100644 --- a/include/grub/i386/pc/vga.h +++ b/include/grub/i386/pc/vga.h @@ -28,7 +28,4 @@ /* Set the video mode to MODE and return the previous mode. */ unsigned char EXPORT_FUNC(grub_vga_set_mode) (unsigned char mode); -/* Return a pointer to the ROM font table. */ -unsigned char *EXPORT_FUNC(grub_vga_get_font) (void); - #endif /* ! GRUB_VGA_MACHINE_HEADER */ diff --git a/include/grub/i386/pci.h b/include/grub/i386/pci.h index 996f64245..bab42adb6 100644 --- a/include/grub/i386/pci.h +++ b/include/grub/i386/pci.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 @@ -22,8 +22,11 @@ #include #include +#define GRUB_MACHINE_PCI_IO_BASE 0 #define GRUB_PCI_ADDR_REG 0xcf8 #define GRUB_PCI_DATA_REG 0xcfc +#define GRUB_PCI_NUM_BUS 256 +#define GRUB_PCI_NUM_DEVICES 32 static inline grub_uint32_t grub_pci_read (grub_pci_address_t addr) @@ -67,4 +70,20 @@ grub_pci_write_byte (grub_pci_address_t addr, grub_uint8_t data) grub_outb (data, GRUB_PCI_DATA_REG + (addr & 3)); } +static inline volatile void * +grub_pci_device_map_range (grub_pci_device_t dev __attribute__ ((unused)), + grub_addr_t base, + grub_size_t size __attribute__ ((unused))) +{ + return (volatile void *) base; +} + +static inline void +grub_pci_device_unmap_range (grub_pci_device_t dev __attribute__ ((unused)), + void *mem __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ +} + + #endif /* GRUB_CPU_PCI_H */ diff --git a/include/grub/i386/qemu/boot.h b/include/grub/i386/qemu/boot.h index 6fbb57750..5f53eabfb 100644 --- a/include/grub/i386/qemu/boot.h +++ b/include/grub/i386/qemu/boot.h @@ -22,7 +22,4 @@ /* The size of boot.img. */ #define GRUB_BOOT_MACHINE_SIZE (0x100000 - GRUB_BOOT_MACHINE_LINK_ADDR) -/* The offset of GRUB_CORE_ENTRY_ADDR. */ -#define GRUB_BOOT_MACHINE_CORE_ENTRY_ADDR 0x4 - #endif diff --git a/include/grub/i386/qemu/kernel.h b/include/grub/i386/qemu/kernel.h index bc0b93d4f..0aa2b3d09 100644 --- a/include/grub/i386/qemu/kernel.h +++ b/include/grub/i386/qemu/kernel.h @@ -19,17 +19,7 @@ #ifndef GRUB_KERNEL_MACHINE_HEADER #define GRUB_KERNEL_MACHINE_HEADER 1 -/* The offset of GRUB_CORE_ENTRY_ADDR. */ -#define GRUB_KERNEL_MACHINE_CORE_ENTRY_ADDR 0x8 - -/* The offset of GRUB_KERNEL_IMAGE_SIZE. */ -#define GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE 0xc - -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_MACHINE_PREFIX 0x10 - -/* End of the data section. */ -#define GRUB_KERNEL_MACHINE_DATA_END 0x50 +#include #ifndef ASM_FILE @@ -44,10 +34,6 @@ extern grub_int32_t grub_kernel_image_size; /* The total size of module images following the kernel. */ extern grub_int32_t grub_total_module_size; -/* The prefix which points to the directory where GRUB modules and its - configuration file are located. */ -extern char grub_prefix[]; - #endif /* ! ASM_FILE */ #endif /* ! GRUB_KERNEL_MACHINE_HEADER */ diff --git a/kern/reader.c b/include/grub/i386/relocator.h similarity index 55% rename from kern/reader.c rename to include/grub/i386/relocator.h index 271a90f5a..ef7fe23aa 100644 --- a/kern/reader.c +++ b/include/grub/i386/relocator.h @@ -1,4 +1,3 @@ -/* reader.c - reader support */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2009 Free Software Foundation, Inc. @@ -17,33 +16,26 @@ * along with GRUB. If not, see . */ +#ifndef GRUB_RELOCATOR_CPU_HEADER +#define GRUB_RELOCATOR_CPU_HEADER 1 + #include -#include -#include -#include +#include -struct grub_handler_class grub_reader_class = - { - .name = "reader" - }; - -grub_err_t -grub_reader_loop (grub_reader_getline_t getline) +struct grub_relocator32_state { - while (1) - { - char *line; - grub_reader_getline_t func; + grub_uint32_t esp; + grub_uint32_t eax; + grub_uint32_t ebx; + grub_uint32_t ecx; + grub_uint32_t edx; + grub_uint32_t eip; +}; - /* Print an error, if any. */ - grub_print_error (); - grub_errno = GRUB_ERR_NONE; +void *grub_relocator32_alloc (grub_size_t size); +grub_err_t grub_relocator32_boot (void *relocator, grub_uint32_t dest, + struct grub_relocator32_state state); +void *grub_relocator32_realloc (void *relocator, grub_size_t size); +void grub_relocator32_free (void *relocator); - func = (getline) ? : grub_reader_get_current ()->read_line; - if ((func (&line, 0)) || (! line)) - return grub_errno; - - grub_parser_get_current ()->parse_line (line, func); - grub_free (line); - } -} +#endif /* ! GRUB_RELOCATOR_CPU_HEADER */ diff --git a/include/grub/i386/tsc.h b/include/grub/i386/tsc.h index 46041c2b2..dad9d062d 100644 --- a/include/grub/i386/tsc.h +++ b/include/grub/i386/tsc.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 diff --git a/include/grub/i386/xnu.h b/include/grub/i386/xnu.h index 68674e605..3be2c3bcc 100644 --- a/include/grub/i386/xnu.h +++ b/include/grub/i386/xnu.h @@ -20,6 +20,10 @@ #define GRUB_CPU_XNU_H 1 #include +#include +#include + +#define XNU_RELOCATOR(x) (grub_relocator32_ ## x) #define GRUB_XNU_PAGESIZE 4096 typedef grub_uint32_t grub_xnu_ptr_t; @@ -64,17 +68,54 @@ struct grub_xnu_boot_params /* Size of grub_efi_uintn_t in bits. */ grub_uint8_t efi_uintnbits; } __attribute__ ((packed)); -#define GRUB_XNU_BOOTARGS_VERMINOR 4 +#define GRUB_XNU_BOOTARGS_VERMINOR 5 #define GRUB_XNU_BOOTARGS_VERMAJOR 1 +struct grub_xnu_devprop_header +{ + grub_uint32_t length; + /* Always set to 1. Version? */ + grub_uint32_t alwaysone; + grub_uint32_t num_devices; +}; + +struct grub_xnu_devprop_device_header +{ + grub_uint32_t length; + grub_uint32_t num_values; +}; + +void grub_cpu_xnu_unload (void); + +struct grub_xnu_devprop_device_descriptor; + +struct grub_xnu_devprop_device_descriptor * +grub_xnu_devprop_add_device (struct grub_efi_device_path *path, int length); +grub_err_t +grub_xnu_devprop_remove_device (struct grub_xnu_devprop_device_descriptor *dev); +grub_err_t +grub_xnu_devprop_remove_property (struct grub_xnu_devprop_device_descriptor *dev, + char *name); +grub_err_t +grub_xnu_devprop_add_property_utf8 (struct grub_xnu_devprop_device_descriptor *dev, + char *name, void *data, int datalen); +grub_err_t +grub_xnu_devprop_add_property_utf16 (struct grub_xnu_devprop_device_descriptor *dev, + grub_uint16_t *name, int namelen, + void *data, int datalen); +grub_err_t +grub_xnu_devprop_remove_property_utf8 (struct grub_xnu_devprop_device_descriptor *dev, + char *name); +void grub_cpu_xnu_init (void); +void grub_cpu_xnu_fini (void); + extern grub_uint32_t grub_xnu_entry_point; extern grub_uint32_t grub_xnu_stack; extern grub_uint32_t grub_xnu_arg1; extern char grub_xnu_cmdline[1024]; grub_err_t grub_xnu_boot (void); -grub_err_t grub_cpu_xnu_fill_devicetree (void); grub_err_t grub_xnu_set_video (struct grub_xnu_boot_params *bootparams_relloc); +grub_err_t +grub_cpu_xnu_fill_devicetree (void); extern grub_uint32_t grub_xnu_heap_will_be_at; -extern grub_uint8_t grub_xnu_launcher_start[]; -extern grub_uint8_t grub_xnu_launcher_end[]; #endif diff --git a/include/grub/icon_manager.h b/include/grub/icon_manager.h new file mode 100644 index 000000000..81c488416 --- /dev/null +++ b/include/grub/icon_manager.h @@ -0,0 +1,41 @@ +/* icon_manager.h - gfxmenu icon manager. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 . + */ + +#ifndef GRUB_ICON_MANAGER_HEADER +#define GRUB_ICON_MANAGER_HEADER 1 + +#include +#include + +/* Forward declaration of opaque structure handle type. */ +typedef struct grub_gfxmenu_icon_manager *grub_gfxmenu_icon_manager_t; + +grub_gfxmenu_icon_manager_t grub_gfxmenu_icon_manager_new (void); +void grub_gfxmenu_icon_manager_destroy (grub_gfxmenu_icon_manager_t mgr); +void grub_gfxmenu_icon_manager_clear_cache (grub_gfxmenu_icon_manager_t mgr); +void grub_gfxmenu_icon_manager_set_theme_path (grub_gfxmenu_icon_manager_t mgr, + const char *path); +void grub_gfxmenu_icon_manager_set_icon_size (grub_gfxmenu_icon_manager_t mgr, + int width, int height); +struct grub_video_bitmap * +grub_gfxmenu_icon_manager_get_icon (grub_gfxmenu_icon_manager_t mgr, + grub_menu_entry_t entry); + +#endif /* GRUB_ICON_MANAGER_HEADER */ + diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h index 0e6aae548..b30909c68 100644 --- a/include/grub/ieee1275/ieee1275.h +++ b/include/grub/ieee1275/ieee1275.h @@ -1,7 +1,7 @@ /* ieee1275.h - Access the Open Firmware client interface. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2007,2008,2009 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 @@ -100,6 +100,9 @@ enum grub_ieee1275_flag /* Open Hack'Ware don't support the ANSI sequence. */ GRUB_IEEE1275_FLAG_NO_ANSI, + + /* OpenFirmware hangs on qemu if one requests any memory below 1.5 MiB. */ + GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM, }; extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag); @@ -138,7 +141,7 @@ int EXPORT_FUNC(grub_ieee1275_read) (grub_ieee1275_ihandle_t ihandle, void *buffer, grub_size_t len, grub_ssize_t *actualp); int EXPORT_FUNC(grub_ieee1275_seek) (grub_ieee1275_ihandle_t ihandle, - int pos_hi, int pos_lo, + grub_disk_addr_t pos, grub_ssize_t *result); int EXPORT_FUNC(grub_ieee1275_peer) (grub_ieee1275_phandle_t node, grub_ieee1275_phandle_t *result); @@ -173,7 +176,15 @@ grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); int EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size); +int +EXPORT_FUNC(grub_ieee1275_map) (grub_addr_t phys, grub_addr_t virt, + grub_size_t size, grub_uint32_t mode); + char *EXPORT_FUNC(grub_ieee1275_encode_devname) (const char *path); char *EXPORT_FUNC(grub_ieee1275_get_filename) (const char *path); +int EXPORT_FUNC(grub_ieee1275_devices_iterate) (int (*hook) + (struct grub_ieee1275_devalias * + alias)); + #endif /* ! GRUB_IEEE1275_HEADER */ diff --git a/include/grub/kernel.h b/include/grub/kernel.h index 75ec77c2a..fed875db1 100644 --- a/include/grub/kernel.h +++ b/include/grub/kernel.h @@ -26,7 +26,8 @@ enum { OBJ_TYPE_ELF, OBJ_TYPE_MEMDISK, - OBJ_TYPE_CONFIG + OBJ_TYPE_CONFIG, + OBJ_TYPE_FONT }; /* The module header. */ @@ -41,23 +42,39 @@ struct grub_module_header /* "gmim" (GRUB Module Info Magic). */ #define GRUB_MODULE_MAGIC 0x676d696d -struct grub_module_info +struct grub_module_info32 { /* Magic number so we know we have modules present. */ grub_uint32_t magic; -#if GRUB_TARGET_SIZEOF_VOID_P == 8 - grub_uint32_t padding; -#endif /* The offset of the modules. */ - grub_target_off_t offset; + grub_uint32_t offset; /* The size of all modules plus this header. */ - grub_target_size_t size; + grub_uint32_t size; }; +struct grub_module_info64 +{ + /* Magic number so we know we have modules present. */ + grub_uint32_t magic; + grub_uint32_t padding; + /* The offset of the modules. */ + grub_uint64_t offset; + /* The size of all modules plus this header. */ + grub_uint64_t size; +}; + +#if GRUB_TARGET_SIZEOF_VOID_P == 8 +#define grub_module_info grub_module_info64 +#else +#define grub_module_info grub_module_info32 +#endif + extern grub_addr_t grub_arch_modules_addr (void); extern void EXPORT_FUNC(grub_module_iterate) (int (*hook) (struct grub_module_header *)); +grub_addr_t grub_modules_get_end (void); + /* The start point of the C code. */ void grub_main (void); @@ -73,4 +90,8 @@ void grub_machine_set_prefix (void); /* Register all the exported symbols. This is automatically generated. */ void grub_register_exported_symbols (void); +#if ! defined (ASM_FILE) && !defined (GRUB_MACHINE_EMU) +extern char grub_prefix[]; +#endif + #endif /* ! GRUB_KERNEL_HEADER */ diff --git a/include/grub/libgcc.h b/include/grub/libgcc.h new file mode 100644 index 000000000..d0adae8c1 --- /dev/null +++ b/include/grub/libgcc.h @@ -0,0 +1,84 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2004,2007,2009 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 . + */ + +#include + +/* On x86 these functions aren't really needed. Save some space. */ +#if !defined (__i386__) && !defined (__x86_64__) +# ifdef HAVE___ASHLDI3 +void EXPORT_FUNC (__ashldi3) (void); +# endif +# ifdef HAVE___ASHRDI3 +void EXPORT_FUNC (__ashrdi3) (void); +# endif +# ifdef HAVE___LSHRDI3 +void EXPORT_FUNC (__lshrdi3) (void); +# endif +# ifdef HAVE___UCMPDI2 +void EXPORT_FUNC (__ucmpdi2) (void); +# endif +# ifdef HAVE___BSWAPSI2 +void EXPORT_FUNC (__bswapsi2) (void); +# endif +# ifdef HAVE___BSWAPDI2 +void EXPORT_FUNC (__bswapdi2) (void); +# endif +#endif + +#ifdef HAVE___TRAMPOLINE_SETUP +void EXPORT_FUNC (__trampoline_setup) (void); +#endif + +#ifdef HAVE__RESTGPR_14_X +void EXPORT_FUNC (_restgpr_14_x) (void); +void EXPORT_FUNC (_restgpr_15_x) (void); +void EXPORT_FUNC (_restgpr_16_x) (void); +void EXPORT_FUNC (_restgpr_17_x) (void); +void EXPORT_FUNC (_restgpr_18_x) (void); +void EXPORT_FUNC (_restgpr_19_x) (void); +void EXPORT_FUNC (_restgpr_20_x) (void); +void EXPORT_FUNC (_restgpr_21_x) (void); +void EXPORT_FUNC (_restgpr_22_x) (void); +void EXPORT_FUNC (_restgpr_23_x) (void); +void EXPORT_FUNC (_restgpr_24_x) (void); +void EXPORT_FUNC (_restgpr_25_x) (void); +void EXPORT_FUNC (_restgpr_26_x) (void); +void EXPORT_FUNC (_restgpr_27_x) (void); +void EXPORT_FUNC (_restgpr_28_x) (void); +void EXPORT_FUNC (_restgpr_29_x) (void); +void EXPORT_FUNC (_restgpr_30_x) (void); +void EXPORT_FUNC (_restgpr_31_x) (void); +void EXPORT_FUNC (_savegpr_14) (void); +void EXPORT_FUNC (_savegpr_15) (void); +void EXPORT_FUNC (_savegpr_16) (void); +void EXPORT_FUNC (_savegpr_17) (void); +void EXPORT_FUNC (_savegpr_18) (void); +void EXPORT_FUNC (_savegpr_19) (void); +void EXPORT_FUNC (_savegpr_20) (void); +void EXPORT_FUNC (_savegpr_21) (void); +void EXPORT_FUNC (_savegpr_22) (void); +void EXPORT_FUNC (_savegpr_23) (void); +void EXPORT_FUNC (_savegpr_24) (void); +void EXPORT_FUNC (_savegpr_25) (void); +void EXPORT_FUNC (_savegpr_26) (void); +void EXPORT_FUNC (_savegpr_27) (void); +void EXPORT_FUNC (_savegpr_28) (void); +void EXPORT_FUNC (_savegpr_29) (void); +void EXPORT_FUNC (_savegpr_30) (void); +void EXPORT_FUNC (_savegpr_31) (void); +#endif diff --git a/include/grub/powerpc/libgcc.h b/include/grub/libpciaccess.h similarity index 60% rename from include/grub/powerpc/libgcc.h rename to include/grub/libpciaccess.h index 452ad4366..4d2b3bde5 100644 --- a/include/grub/powerpc/libgcc.h +++ b/include/grub/libpciaccess.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2007,2009 Free Software Foundation, Inc. + * 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 @@ -16,20 +16,11 @@ * along with GRUB. If not, see . */ -#include - -#ifdef HAVE___ASHLDI3 -void EXPORT_FUNC (__ashldi3) (void); -#endif -#ifdef HAVE___ASHRDI3 -void EXPORT_FUNC (__ashrdi3) (void); -#endif -#ifdef HAVE___LSHRDI3 -void EXPORT_FUNC (__lshrdi3) (void); -#endif -#ifdef HAVE___TRAMPOLINE_SETUP -void EXPORT_FUNC (__trampoline_setup) (void); -#endif -#ifdef HAVE___UCMPDI2 -void EXPORT_FUNC (__ucmpdi2) (void); -#endif +void EXPORT_FUNC (pci_slot_match_iterator_create) (void); +void EXPORT_FUNC (pci_system_cleanup) (void); +void EXPORT_FUNC (pci_device_unmap_range) (void); +void EXPORT_FUNC (pci_iterator_destroy) (void); +void EXPORT_FUNC (pci_device_map_range) (void); +void EXPORT_FUNC (pci_device_cfg_read_u32) (void); +void EXPORT_FUNC (pci_device_next) (void); +void EXPORT_FUNC (pci_system_init) (void); diff --git a/include/grub/libusb.h b/include/grub/libusb.h new file mode 100644 index 000000000..26548bccb --- /dev/null +++ b/include/grub/libusb.h @@ -0,0 +1,29 @@ +/* + * 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 . + */ + +void EXPORT_FUNC (usb_bulk_write) (void); +void EXPORT_FUNC (usb_find_busses) (void); +void EXPORT_FUNC (usb_init) (void); +void EXPORT_FUNC (usb_find_devices) (void); +void EXPORT_FUNC (usb_open) (void); +void EXPORT_FUNC (usb_get_busses) (void); +void EXPORT_FUNC (usb_control_msg) (void); +void EXPORT_FUNC (usb_release_interface) (void); +void EXPORT_FUNC (usb_close) (void); +void EXPORT_FUNC (usb_bulk_read) (void); +void EXPORT_FUNC (usb_claim_interface) (void); diff --git a/include/grub/list.h b/include/grub/list.h index 2dffdc08d..5559158dc 100644 --- a/include/grub/list.h +++ b/include/grub/list.h @@ -22,6 +22,7 @@ #include #include +#include struct grub_list { @@ -39,31 +40,30 @@ int EXPORT_FUNC(grub_list_iterate) (grub_list_t head, grub_list_hook_t hook); void EXPORT_FUNC(grub_list_insert) (grub_list_t *head, grub_list_t item, grub_list_test_t test); -/* This function doesn't exist, so if assertion is false for some reason, the - linker would fail. */ -#ifdef APPLE_CC -/* This approach fails with Apple's gcc. Use grub_abort. */ -#include static inline void * -grub_assert_fail (void) +grub_bad_type_cast_real (int line, const char *file) + ATTRIBUTE_ERROR ("bad type cast between incompatible grub types"); + +static inline void * +grub_bad_type_cast_real (int line, const char *file) { - grub_abort (); - return 0; + grub_fatal ("error:%s:%u: bad type cast between incompatible grub types", + file, line); + return 0; } -#else -extern void* grub_assert_fail (void); -#endif + +#define grub_bad_type_cast() grub_bad_type_cast_real(__LINE__, GRUB_FILE) #define GRUB_FIELD_MATCH(ptr, type, field) \ ((char *) &(ptr)->field == (char *) &((type) (ptr))->field) #define GRUB_AS_LIST(ptr) \ (GRUB_FIELD_MATCH (ptr, grub_list_t, next) ? \ - (grub_list_t) ptr : grub_assert_fail ()) + (grub_list_t) ptr : grub_bad_type_cast ()) #define GRUB_AS_LIST_P(pptr) \ (GRUB_FIELD_MATCH (*pptr, grub_list_t, next) ? \ - (grub_list_t *) (void *) pptr : grub_assert_fail ()) + (grub_list_t *) (void *) pptr : grub_bad_type_cast ()) struct grub_named_list { @@ -78,12 +78,12 @@ void * EXPORT_FUNC(grub_named_list_find) (grub_named_list_t head, #define GRUB_AS_NAMED_LIST(ptr) \ ((GRUB_FIELD_MATCH (ptr, grub_named_list_t, next) && \ GRUB_FIELD_MATCH (ptr, grub_named_list_t, name))? \ - (grub_named_list_t) ptr : grub_assert_fail ()) + (grub_named_list_t) ptr : grub_bad_type_cast ()) #define GRUB_AS_NAMED_LIST_P(pptr) \ ((GRUB_FIELD_MATCH (*pptr, grub_named_list_t, next) && \ GRUB_FIELD_MATCH (*pptr, grub_named_list_t, name))? \ - (grub_named_list_t *) (void *) pptr : grub_assert_fail ()) + (grub_named_list_t *) (void *) pptr : grub_bad_type_cast ()) #define GRUB_PRIO_LIST_PRIO_MASK 0xff #define GRUB_PRIO_LIST_FLAG_ACTIVE 0x100 @@ -111,12 +111,12 @@ grub_prio_list_remove (grub_prio_list_t *head, grub_prio_list_t item) ((GRUB_FIELD_MATCH (ptr, grub_prio_list_t, next) && \ GRUB_FIELD_MATCH (ptr, grub_prio_list_t, name) && \ GRUB_FIELD_MATCH (ptr, grub_prio_list_t, prio))? \ - (grub_prio_list_t) ptr : grub_assert_fail ()) + (grub_prio_list_t) ptr : grub_bad_type_cast ()) #define GRUB_AS_PRIO_LIST_P(pptr) \ ((GRUB_FIELD_MATCH (*pptr, grub_prio_list_t, next) && \ GRUB_FIELD_MATCH (*pptr, grub_prio_list_t, name) && \ GRUB_FIELD_MATCH (*pptr, grub_prio_list_t, prio))? \ - (grub_prio_list_t *) (void *) pptr : grub_assert_fail ()) + (grub_prio_list_t *) (void *) pptr : grub_bad_type_cast ()) #endif /* ! GRUB_LIST_HEADER */ diff --git a/include/grub/macho.h b/include/grub/macho.h index 0604100e9..82145835f 100644 --- a/include/grub/macho.h +++ b/include/grub/macho.h @@ -102,6 +102,23 @@ struct grub_macho_segment32 grub_uint32_t flags; } __attribute__ ((packed)); +/* 64-bit segment command. */ +struct grub_macho_segment64 +{ +#define GRUB_MACHO_CMD_SEGMENT64 0x19 + grub_uint32_t cmd; + grub_uint32_t cmdsize; + grub_uint8_t segname[16]; + grub_uint64_t vmaddr; + grub_uint64_t vmsize; + grub_uint64_t fileoff; + grub_uint64_t filesize; + grub_macho_vmprot_t maxprot; + grub_macho_vmprot_t initprot; + grub_uint32_t nsects; + grub_uint32_t flags; +} __attribute__ ((packed)); + #define GRUB_MACHO_CMD_THREAD 5 #endif diff --git a/include/grub/machoload.h b/include/grub/machoload.h index a80bac68c..8410162fb 100644 --- a/include/grub/machoload.h +++ b/include/grub/machoload.h @@ -46,17 +46,28 @@ grub_macho_t grub_macho_file (grub_file_t); grub_err_t grub_macho_close (grub_macho_t); int grub_macho_contains_macho32 (grub_macho_t); -grub_err_t grub_macho32_size (grub_macho_t macho, grub_addr_t *segments_start, - grub_addr_t *segments_end, int flags); -grub_uint32_t grub_macho32_get_entry_point (grub_macho_t macho); +grub_err_t grub_macho_size32 (grub_macho_t macho, grub_uint32_t *segments_start, + grub_uint32_t *segments_end, int flags); +grub_uint32_t grub_macho_get_entry_point32 (grub_macho_t macho); + +int grub_macho_contains_macho64 (grub_macho_t); +grub_err_t grub_macho_size64 (grub_macho_t macho, grub_uint64_t *segments_start, + grub_uint64_t *segments_end, int flags); +grub_uint64_t grub_macho_get_entry_point64 (grub_macho_t macho); /* Ignore BSS segments when loading. */ #define GRUB_MACHO_NOBSS 0x1 -grub_err_t grub_macho32_load (grub_macho_t macho, char *offset, int flags); +grub_err_t grub_macho_load32 (grub_macho_t macho, char *offset, int flags); +grub_err_t grub_macho_load64 (grub_macho_t macho, char *offset, int flags); /* Like filesize and file_read but take only 32-bit part for current architecture. */ -grub_size_t grub_macho32_filesize (grub_macho_t macho); -grub_err_t grub_macho32_readfile (grub_macho_t macho, void *dest); +grub_size_t grub_macho_filesize32 (grub_macho_t macho); +grub_err_t grub_macho_readfile32 (grub_macho_t macho, void *dest); +grub_size_t grub_macho_filesize64 (grub_macho_t macho); +grub_err_t grub_macho_readfile64 (grub_macho_t macho, void *dest); + +void grub_macho_parse32 (grub_macho_t macho); +void grub_macho_parse64 (grub_macho_t macho); #endif /* ! GRUB_MACHOLOAD_HEADER */ diff --git a/include/grub/menu.h b/include/grub/menu.h index c7114a93b..e5e5fb110 100644 --- a/include/grub/menu.h +++ b/include/grub/menu.h @@ -47,6 +47,8 @@ struct grub_menu_entry /* The sourcecode of the menu entry, used by the editor. */ const char *sourcecode; + int hotkey; + /* The next element. */ struct grub_menu_entry *next; }; @@ -83,7 +85,6 @@ typedef struct grub_menu_execute_callback } *grub_menu_execute_callback_t; - grub_menu_entry_t grub_menu_get_entry (grub_menu_t menu, int no); int grub_menu_get_timeout (void); void grub_menu_set_timeout (int timeout); @@ -93,5 +94,6 @@ void grub_menu_execute_with_fallback (grub_menu_t menu, grub_menu_execute_callback_t callback, void *callback_data); void grub_menu_entry_run (grub_menu_entry_t entry); +int grub_menu_get_default_entry_index (grub_menu_t menu); #endif /* GRUB_MENU_HEADER */ diff --git a/include/grub/menu_viewer.h b/include/grub/menu_viewer.h index 725c97548..c6513c4e8 100644 --- a/include/grub/menu_viewer.h +++ b/include/grub/menu_viewer.h @@ -24,20 +24,25 @@ #include #include #include +#include struct grub_menu_viewer { - /* The menu viewer name. */ - const char *name; - - grub_err_t (*show_menu) (grub_menu_t menu, int nested); - struct grub_menu_viewer *next; + void *data; + void (*set_chosen_entry) (int entry, void *data); + void (*print_timeout) (int timeout, void *data); + void (*clear_timeout) (void *data); + void (*fini) (void *fini); }; -typedef struct grub_menu_viewer *grub_menu_viewer_t; -void grub_menu_viewer_register (grub_menu_viewer_t viewer); +void grub_menu_register_viewer (struct grub_menu_viewer *viewer); -grub_err_t grub_menu_viewer_show_menu (grub_menu_t menu, int nested); +grub_err_t +grub_menu_try_text (struct grub_term_output *term, + int entry, grub_menu_t menu, int nested); + +extern grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu, + int nested); #endif /* GRUB_MENU_VIEWER_HEADER */ diff --git a/include/grub/mips/at_keyboard.h b/include/grub/mips/at_keyboard.h new file mode 100644 index 000000000..0c307537d --- /dev/null +++ b/include/grub/mips/at_keyboard.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/sparc64/libgcc.h b/include/grub/mips/cache.h similarity index 74% rename from include/grub/sparc64/libgcc.h rename to include/grub/mips/cache.h index 008821d81..c3470571e 100644 --- a/include/grub/sparc64/libgcc.h +++ b/include/grub/mips/cache.h @@ -1,3 +1,4 @@ +/* cache.h - Flush the processor's cache. */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2004,2007 Free Software Foundation, Inc. @@ -16,14 +17,11 @@ * along with GRUB. If not, see . */ -#include +#ifndef GRUB_CPU_CACHE_H +#define GRUB_CPU_CACHE_H 1 -#ifdef HAVE___BSWAPSI2 -typedef int SItype __attribute__ ((mode (SI))); -SItype EXPORT_FUNC (__bswapsi2) (SItype); -#endif +#include +#include -#ifdef HAVE___BSWAPDI2 -typedef int DItype __attribute__ ((mode (DI))); -DItype EXPORT_FUNC (__bswapdi2) (DItype); -#endif +void EXPORT_FUNC(grub_cpu_flush_cache) (void *start, grub_size_t size, int type); +#endif diff --git a/include/grub/mips/cmos.h b/include/grub/mips/cmos.h new file mode 100644 index 000000000..79a7a4c1b --- /dev/null +++ b/include/grub/mips/cmos.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/mips/io.h b/include/grub/mips/io.h new file mode 100644 index 000000000..dee76bde5 --- /dev/null +++ b/include/grub/mips/io.h @@ -0,0 +1,62 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#ifndef GRUB_IO_H +#define GRUB_IO_H 1 + +#include + +typedef grub_addr_t grub_port_t; + +static __inline unsigned char +grub_inb (grub_port_t port) +{ + return *(volatile grub_uint8_t *) port; +} + +static __inline unsigned short int +grub_inw (grub_port_t port) +{ + return *(volatile grub_uint16_t *) port; +} + +static __inline unsigned int +grub_inl (grub_port_t port) +{ + return *(volatile grub_uint32_t *) port; +} + +static __inline void +grub_outb (unsigned char value, grub_port_t port) +{ + *(volatile grub_uint8_t *) port = value; +} + +static __inline void +grub_outw (unsigned short int value, grub_port_t port) +{ + *(volatile grub_uint16_t *) port = value; +} + +static __inline void +grub_outl (unsigned int value, grub_port_t port) +{ + *(volatile grub_uint32_t *) port = value; +} + +#endif /* _SYS_IO_H */ diff --git a/include/grub/mips/multiboot.h b/include/grub/mips/multiboot.h new file mode 100644 index 000000000..a27229efe --- /dev/null +++ b/include/grub/mips/multiboot.h @@ -0,0 +1,36 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2007,2008,2009 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 . + */ + +#ifndef GRUB_MULTIBOOT_CPU_HEADER +#define GRUB_MULTIBOOT_CPU_HEADER 1 + +extern grub_uint32_t grub_multiboot_payload_eip; +extern char *grub_multiboot_payload_orig; +extern grub_addr_t grub_multiboot_payload_dest; +extern grub_size_t grub_multiboot_payload_size; + +#define MULTIBOOT_INITIAL_STATE { .gpr[4] = MULTIBOOT_BOOTLOADER_MAGIC, \ + .jumpreg = 1 } +#define MULTIBOOT_ENTRY_REGISTER gpr[1] +#define MULTIBOOT_MBI_REGISTER gpr[5] +#define MULTIBOOT_ARCHITECTURE_CURRENT MULTIBOOT_ARCHITECTURE_MIPS32 + +#define MULTIBOOT_ELF32_MACHINE EM_MIPS +#define MULTIBOOT_ELF64_MACHINE EM_MIPS + +#endif /* ! GRUB_MULTIBOOT_CPU_HEADER */ diff --git a/include/grub/mips/pci.h b/include/grub/mips/pci.h new file mode 100644 index 000000000..8b49d8479 --- /dev/null +++ b/include/grub/mips/pci.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/powerpc/ieee1275/kernel.h b/include/grub/mips/qemu-mips/kernel.h similarity index 80% rename from include/grub/powerpc/ieee1275/kernel.h rename to include/grub/mips/qemu-mips/kernel.h index a76c2a4df..230455dbf 100644 --- a/include/grub/powerpc/ieee1275/kernel.h +++ b/include/grub/mips/qemu-mips/kernel.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2005,2006,2007,2008,2009 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 @@ -20,12 +20,12 @@ #define GRUB_KERNEL_MACHINE_HEADER 1 #include +#include #ifndef ASM_FILE -/* The prefix which points to the directory where GRUB modules and its - configuration file are located. */ -extern char grub_prefix[]; +void EXPORT_FUNC (grub_reboot) (void); +void EXPORT_FUNC (grub_halt) (void); #endif diff --git a/include/grub/mips/qemu-mips/loader.h b/include/grub/mips/qemu-mips/loader.h new file mode 100644 index 000000000..e69de29bb diff --git a/include/grub/mips/qemu-mips/memory.h b/include/grub/mips/qemu-mips/memory.h new file mode 100644 index 000000000..87e68674e --- /dev/null +++ b/include/grub/mips/qemu-mips/memory.h @@ -0,0 +1,54 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#ifndef GRUB_MEMORY_MACHINE_HEADER +#define GRUB_MEMORY_MACHINE_HEADER 1 + +#ifndef ASM_FILE +#include +#include +#include +#endif + +#define GRUB_MACHINE_MEMORY_STACK_HIGH 0x80f00000 +#define GRUB_MACHINE_MEMORY_USABLE 0x81000000 + +#define GRUB_MACHINE_MEMORY_AVAILABLE 1 + +#ifndef ASM_FILE +grub_err_t EXPORT_FUNC (grub_machine_mmap_iterate) +(int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); +grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) + (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); + +static inline grub_err_t +grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + int type __attribute__ ((unused)), + int handle __attribute__ ((unused))) +{ + return GRUB_ERR_NONE; +} +static inline grub_err_t +grub_machine_mmap_unregister (int handle __attribute__ ((unused))) +{ + return GRUB_ERR_NONE; +} +#endif + +#endif diff --git a/include/grub/mips/qemu-mips/serial.h b/include/grub/mips/qemu-mips/serial.h new file mode 100644 index 000000000..1f8ce0804 --- /dev/null +++ b/include/grub/mips/qemu-mips/serial.h @@ -0,0 +1,24 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#ifndef GRUB_MACHINE_SERIAL_HEADER +#define GRUB_MACHINE_SERIAL_HEADER 1 + +#define GRUB_MACHINE_SERIAL_PORTS { 0x140003f8 } + +#endif diff --git a/include/grub/mips/qemu-mips/time.h b/include/grub/mips/qemu-mips/time.h new file mode 100644 index 000000000..a73f64dea --- /dev/null +++ b/include/grub/mips/qemu-mips/time.h @@ -0,0 +1,34 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,2005,2007 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 . + */ + +#ifndef KERNEL_MACHINE_TIME_HEADER +#define KERNEL_MACHINE_TIME_HEADER 1 + +#include + +#define GRUB_TICKS_PER_SECOND 1000 + +/* Return the real time in ticks. */ +grub_uint32_t EXPORT_FUNC (grub_get_rtc) (void); + +static inline void +grub_cpu_idle(void) +{ +} + +#endif /* ! KERNEL_MACHINE_TIME_HEADER */ diff --git a/include/grub/mips/relocator.h b/include/grub/mips/relocator.h new file mode 100644 index 000000000..838ef832f --- /dev/null +++ b/include/grub/mips/relocator.h @@ -0,0 +1,39 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#ifndef GRUB_RELOCATOR_CPU_HEADER +#define GRUB_RELOCATOR_CPU_HEADER 1 + +#include +#include + +struct grub_relocator32_state +{ + /* gpr[0] is ignored since it's hardwired to 0. */ + grub_uint32_t gpr[32]; + /* Register holding target $pc. */ + int jumpreg; +}; + +void *grub_relocator32_alloc (grub_size_t size); +grub_err_t grub_relocator32_boot (void *relocator, grub_uint32_t dest, + struct grub_relocator32_state state); +void *grub_relocator32_realloc (void *relocator, grub_size_t size); +void grub_relocator32_free (void *relocator); + +#endif /* ! GRUB_RELOCATOR_CPU_HEADER */ diff --git a/include/grub/mips/setjmp.h b/include/grub/mips/setjmp.h new file mode 100644 index 000000000..5e5985586 --- /dev/null +++ b/include/grub/mips/setjmp.h @@ -0,0 +1,27 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2006,2007,2009 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 . + */ + +#ifndef GRUB_SETJMP_CPU_HEADER +#define GRUB_SETJMP_CPU_HEADER 1 + +typedef unsigned long grub_jmp_buf[11]; + +int grub_setjmp (grub_jmp_buf env) __attribute__ ((returns_twice)); +void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn)); + +#endif /* ! GRUB_SETJMP_CPU_HEADER */ diff --git a/include/grub/mips/time.h b/include/grub/mips/time.h new file mode 100644 index 000000000..e69de29bb diff --git a/include/grub/mips/types.h b/include/grub/mips/types.h new file mode 100644 index 000000000..fe09afa3e --- /dev/null +++ b/include/grub/mips/types.h @@ -0,0 +1,38 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2006,2007,2009 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 . + */ + +#ifndef GRUB_TYPES_CPU_HEADER +#define GRUB_TYPES_CPU_HEADER 1 + +/* The size of void *. */ +#define GRUB_TARGET_SIZEOF_VOID_P 4 + +/* The size of long. */ +#define GRUB_TARGET_SIZEOF_LONG 4 + +#ifdef GRUB_CPU_MIPSEL +/* mipsEL is little-endian. */ +#undef GRUB_TARGET_WORDS_BIGENDIAN +#elif defined (GRUB_CPU_MIPS) +/* mips is big-endian. */ +#define GRUB_TARGET_WORDS_BIGENDIAN +#elif !defined (GRUB_SYMBOL_GENERATOR) +#error Neither GRUB_CPU_MIPS nor GRUB_CPU_MIPSEL is defined +#endif + +#endif /* ! GRUB_TYPES_CPU_HEADER */ diff --git a/include/grub/mips/yeeloong/at_keyboard.h b/include/grub/mips/yeeloong/at_keyboard.h new file mode 100644 index 000000000..f279ac86d --- /dev/null +++ b/include/grub/mips/yeeloong/at_keyboard.h @@ -0,0 +1,25 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007,2008,2009 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 . + */ + +#ifndef GRUB_MACHINE_AT_KEYBOARD_HEADER +#define GRUB_MACHINE_AT_KEYBOARD_HEADER 1 + +#define KEYBOARD_REG_DATA 0xbfd00060 +#define KEYBOARD_REG_STATUS 0xbfd00064 + +#endif diff --git a/include/grub/mips/yeeloong/cmos.h b/include/grub/mips/yeeloong/cmos.h new file mode 100644 index 000000000..f2a32d736 --- /dev/null +++ b/include/grub/mips/yeeloong/cmos.h @@ -0,0 +1,28 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 . + */ + +#ifndef GRUB_CPU_CMOS_H +#define GRUB_CPU_CMOS_H 1 + +#include +#include + +#define GRUB_CMOS_ADDR_REG 0xbfd00070 +#define GRUB_CMOS_DATA_REG 0xbfd00071 + +#endif /* GRUB_CPU_CMOS_H */ diff --git a/include/grub/i386/coreboot/kernel.h b/include/grub/mips/yeeloong/kernel.h similarity index 84% rename from include/grub/i386/coreboot/kernel.h rename to include/grub/mips/yeeloong/kernel.h index fb60668cc..c08405e83 100644 --- a/include/grub/i386/coreboot/kernel.h +++ b/include/grub/mips/yeeloong/kernel.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2005,2006,2007,2008,2009 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 @@ -22,7 +22,10 @@ #include #ifndef ASM_FILE -extern char grub_prefix[]; + +void EXPORT_FUNC (grub_reboot) (void); +void EXPORT_FUNC (grub_halt) (void); + #endif #endif /* ! GRUB_KERNEL_MACHINE_HEADER */ diff --git a/include/grub/mips/yeeloong/loader.h b/include/grub/mips/yeeloong/loader.h new file mode 100644 index 000000000..e69de29bb diff --git a/include/grub/mips/yeeloong/memory.h b/include/grub/mips/yeeloong/memory.h new file mode 100644 index 000000000..922db2404 --- /dev/null +++ b/include/grub/mips/yeeloong/memory.h @@ -0,0 +1,68 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#ifndef GRUB_MEMORY_MACHINE_HEADER +#define GRUB_MEMORY_MACHINE_HEADER 1 + +#ifndef ASM_FILE +#include +#include +#include +#endif + +#define GRUB_MACHINE_MEMORY_STACK_HIGH 0x801ffff0 +#define GRUB_ARCH_LOWMEMVSTART 0x80000000 +#define GRUB_ARCH_LOWMEMPSTART 0x00000000 +#define GRUB_ARCH_LOWMEMMAXSIZE 0x10000000 +#define GRUB_ARCH_HIGHMEMPSTART 0x10000000 + + +#define GRUB_MACHINE_MEMORY_AVAILABLE 1 +#define GRUB_MACHINE_MEMORY_MAX_TYPE 1 + /* This one is special: it's used internally but is never reported + by firmware. */ +#define GRUB_MACHINE_MEMORY_HOLE 2 +#define GRUB_MACHINE_MEMORY_RESERVED GRUB_MACHINE_MEMORY_HOLE + +#ifndef ASM_FILE +grub_err_t EXPORT_FUNC (grub_machine_mmap_iterate) +(int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); + +static inline grub_err_t +grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + int type __attribute__ ((unused)), + int handle __attribute__ ((unused))) +{ + return GRUB_ERR_NONE; +} +static inline grub_err_t +grub_machine_mmap_unregister (int handle __attribute__ ((unused))) +{ + return GRUB_ERR_NONE; +} + +grub_uint64_t grub_mmap_get_lower (void); +grub_uint64_t grub_mmap_get_upper (void); + +extern grub_uint32_t EXPORT_VAR (grub_arch_memsize); +extern grub_uint32_t EXPORT_VAR (grub_arch_highmemsize); + +#endif + +#endif diff --git a/include/grub/mips/yeeloong/pci.h b/include/grub/mips/yeeloong/pci.h new file mode 100644 index 000000000..c7bd31d4f --- /dev/null +++ b/include/grub/mips/yeeloong/pci.h @@ -0,0 +1,105 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 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 . + */ + +#ifndef GRUB_MACHINE_PCI_H +#define GRUB_MACHINE_PCI_H 1 + +#include +#include + +#define GRUB_PCI_NUM_BUS 1 +#define GRUB_PCI_NUM_DEVICES 16 + +#define GRUB_MACHINE_PCI_IO_BASE 0xbfd00000 +#define GRUB_MACHINE_PCI_CONFSPACE 0xbfe80000 +#define GRUB_MACHINE_PCI_CONF_CTRL_REG (*(volatile grub_uint32_t *) 0xbfe00118) +#define GRUB_MACHINE_PCI_IO_CTRL_REG (*(volatile grub_uint32_t *) 0xbfe00110) +#define GRUB_MACHINE_PCI_WIN_MASK_SIZE 6 +#define GRUB_MACHINE_PCI_WIN_MASK ((1 << GRUB_MACHINE_PCI_WIN_MASK_SIZE) - 1) + +/* We have 3 PCI windows. */ +#define GRUB_MACHINE_PCI_NUM_WIN 3 +/* Each window is 64MiB. */ +#define GRUB_MACHINE_PCI_WIN_SHIFT 26 +#define GRUB_MACHINE_PCI_WIN_OFFSET_MASK ((1 << GRUB_MACHINE_PCI_WIN_SHIFT) - 1) + +#define GRUB_MACHINE_PCI_WIN_SIZE 0x04000000 +/* Graphical acceleration takes 1 MiB away. */ +#define GRUB_MACHINE_PCI_WIN1_SIZE 0x03f00000 + +#define GRUB_MACHINE_PCI_WIN1_ADDR 0xb0000000 +#define GRUB_MACHINE_PCI_WIN2_ADDR 0xb4000000 +#define GRUB_MACHINE_PCI_WIN3_ADDR 0xb8000000 + +static inline grub_uint32_t +grub_pci_read (grub_pci_address_t addr) +{ + GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); + return *(volatile grub_uint32_t *) (GRUB_MACHINE_PCI_CONFSPACE + | (addr & 0x03ff)); +} + +static inline grub_uint16_t +grub_pci_read_word (grub_pci_address_t addr) +{ + GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); + return *(volatile grub_uint16_t *) (GRUB_MACHINE_PCI_CONFSPACE + | (addr & 0x03ff)); +} + +static inline grub_uint8_t +grub_pci_read_byte (grub_pci_address_t addr) +{ + GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); + return *(volatile grub_uint8_t *) (GRUB_MACHINE_PCI_CONFSPACE + | (addr & 0x03ff)); +} + +static inline void +grub_pci_write (grub_pci_address_t addr, grub_uint32_t data) +{ + GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); + *(volatile grub_uint32_t *) (GRUB_MACHINE_PCI_CONFSPACE + | (addr & 0x03ff)) = data; +} + +static inline void +grub_pci_write_word (grub_pci_address_t addr, grub_uint16_t data) +{ + GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); + *(volatile grub_uint16_t *) (GRUB_MACHINE_PCI_CONFSPACE + | (addr & 0x03ff)) = data; +} + +static inline void +grub_pci_write_byte (grub_pci_address_t addr, grub_uint8_t data) +{ + GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); + *(volatile grub_uint8_t *) (GRUB_MACHINE_PCI_CONFSPACE + | (addr & 0x03ff)) = data; +} + +volatile void * +grub_pci_device_map_range (grub_pci_device_t dev __attribute__ ((unused)), + grub_addr_t base, grub_size_t size); +void +grub_pci_device_unmap_range (grub_pci_device_t dev __attribute__ ((unused)), + volatile void *mem, + grub_size_t size __attribute__ ((unused))); + +#endif /* GRUB_MACHINE_PCI_H */ diff --git a/include/grub/mips/yeeloong/serial.h b/include/grub/mips/yeeloong/serial.h new file mode 100644 index 000000000..9390ea18a --- /dev/null +++ b/include/grub/mips/yeeloong/serial.h @@ -0,0 +1,24 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#ifndef GRUB_MACHINE_SERIAL_HEADER +#define GRUB_MACHINE_SERIAL_HEADER 1 + +#define GRUB_MACHINE_SERIAL_PORTS { 0xbff003f8 } + +#endif diff --git a/include/grub/mips/yeeloong/time.h b/include/grub/mips/yeeloong/time.h new file mode 100644 index 000000000..7f468bf12 --- /dev/null +++ b/include/grub/mips/yeeloong/time.h @@ -0,0 +1,37 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,2005,2007 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 . + */ + +#ifndef KERNEL_MACHINE_TIME_HEADER +#define KERNEL_MACHINE_TIME_HEADER 1 + +#include + +#define GRUB_TICKS_PER_SECOND (grub_arch_cpuclock / 2) + +/* Return the real time in ticks. */ +grub_uint64_t EXPORT_FUNC (grub_get_rtc) (void); + +extern grub_uint32_t EXPORT_VAR (grub_arch_busclock); +extern grub_uint32_t EXPORT_VAR (grub_arch_cpuclock); + +static inline void +grub_cpu_idle(void) +{ +} + +#endif /* ! KERNEL_MACHINE_TIME_HEADER */ diff --git a/include/grub/misc.h b/include/grub/misc.h index 1ab63ac0b..9bfc6974e 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -1,7 +1,7 @@ /* misc.h - prototypes for misc functions */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2005,2006,2007,2008,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 @@ -25,12 +25,28 @@ #include #include +/* GCC version checking borrowed from glibc. */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define GNUC_PREREQ(maj,min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +# define GNUC_PREREQ(maj,min) 0 +#endif + +/* Does this compiler support compile-time error attributes? */ +#if GNUC_PREREQ(4,3) +# define ATTRIBUTE_ERROR(msg) \ + __attribute__ ((__error__ (msg))) +#else +# define ATTRIBUTE_ERROR(msg) +#endif + #define ALIGN_UP(addr, align) \ ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1)) #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } -#define grub_dprintf(condition, fmt, args...) grub_real_dprintf(__FILE__, __LINE__, condition, fmt, ## args) +#define grub_dprintf(condition, fmt, args...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, fmt, ## args) /* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */ #define grub_memcpy(d,s,n) grub_memmove ((d), (s), (n)) @@ -94,6 +110,12 @@ char *EXPORT_FUNC(grub_strstr) (const char *haystack, const char *needle); int EXPORT_FUNC(grub_isspace) (int c); int EXPORT_FUNC(grub_isprint) (int c); +static inline int +grub_iscntrl (int c) +{ + return (c >= 0x00 && c <= 0x1F) || c == 0x7F; +} + static inline int grub_isalpha (int c) { @@ -112,6 +134,12 @@ grub_isdigit (int c) return (c >= '0' && c <= '9'); } +static inline int +grub_isalnum (int c) +{ + return grub_isalpha (c) || grub_isdigit (c); +} + static inline int grub_tolower (int c) { @@ -166,36 +194,82 @@ grub_strncasecmp (const char *s1, const char *s2, grub_size_t n) unsigned long EXPORT_FUNC(grub_strtoul) (const char *str, char **end, int base); unsigned long long EXPORT_FUNC(grub_strtoull) (const char *str, char **end, int base); + +static inline long +grub_strtol (const char *str, char **end, int base) +{ + int negative = 0; + unsigned long magnitude; + + while (*str && grub_isspace (*str)) + str++; + + if (*str == '-') + { + negative = 1; + str++; + } + + magnitude = grub_strtoull (str, end, base); + if (negative) + { + if (magnitude > (unsigned long) GRUB_LONG_MAX + 1) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "negative overflow"); + return GRUB_LONG_MIN; + } + return -((long) magnitude); + } + else + { + if (magnitude > GRUB_LONG_MAX) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "positive overflow"); + return GRUB_LONG_MAX; + } + return (long) magnitude; + } +} + char *EXPORT_FUNC(grub_strdup) (const char *s); char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n); void *EXPORT_FUNC(grub_memset) (void *s, int c, grub_size_t n); grub_size_t EXPORT_FUNC(grub_strlen) (const char *s); int EXPORT_FUNC(grub_printf) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); int EXPORT_FUNC(grub_printf_) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +int EXPORT_FUNC(grub_puts) (const char *s); +int EXPORT_FUNC(grub_puts_) (const char *s); void EXPORT_FUNC(grub_real_dprintf) (const char *file, const int line, const char *condition, const char *fmt, ...) __attribute__ ((format (printf, 4, 5))); int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args); -int EXPORT_FUNC(grub_sprintf) (char *str, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); -int EXPORT_FUNC(grub_vsprintf) (char *str, const char *fmt, va_list args); +int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...) + __attribute__ ((format (printf, 3, 4))); +int EXPORT_FUNC(grub_vsnprintf) (char *str, grub_size_t n, const char *fmt, + va_list args); +char *EXPORT_FUNC(grub_xasprintf) (const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); +char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args); void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn)); void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn)); -grub_uint8_t *EXPORT_FUNC(grub_utf16_to_utf8) (grub_uint8_t *dest, - grub_uint16_t *src, - grub_size_t size); -grub_ssize_t EXPORT_FUNC(grub_utf8_to_ucs4) (grub_uint32_t *dest, - grub_size_t destsize, - const grub_uint8_t *src, - grub_size_t srcsize, - const grub_uint8_t **srcend); +grub_size_t EXPORT_FUNC(grub_utf8_to_ucs4) (grub_uint32_t *dest, + grub_size_t destsize, + const grub_uint8_t *src, + grub_size_t srcsize, + const grub_uint8_t **srcend); grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, grub_uint32_t d, grub_uint32_t *r); -#ifdef NEED_ENABLE_EXECUTE_STACK +#if defined(NEED_ENABLE_EXECUTE_STACK) && !defined(GRUB_UTIL) void EXPORT_FUNC(__enable_execute_stack) (void *addr); #endif +#if defined (NEED_REGISTER_FRAME_INFO) && !defined(GRUB_UTIL) +void EXPORT_FUNC (__register_frame_info) (void); +void EXPORT_FUNC (__deregister_frame_info) (void); +#endif + /* Inline functions. */ static inline unsigned int diff --git a/include/grub/mm.h b/include/grub/mm.h index 4caf80511..38dd39646 100644 --- a/include/grub/mm.h +++ b/include/grub/mm.h @@ -36,7 +36,7 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size); void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size); /* For debugging. */ -#if defined(MM_DEBUG) && !defined(GRUB_UTIL) +#if defined(MM_DEBUG) && !defined(GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) /* Set this variable to 1 when you want to trace all memory function calls. */ extern int EXPORT_VAR(grub_mm_debug); @@ -44,19 +44,19 @@ void grub_mm_dump_free (void); void grub_mm_dump (unsigned lineno); #define grub_malloc(size) \ - grub_debug_malloc (__FILE__, __LINE__, size) + grub_debug_malloc (GRUB_FILE, __LINE__, size) #define grub_zalloc(size) \ - grub_debug_zalloc (__FILE__, __LINE__, size) + grub_debug_zalloc (GRUB_FILE, __LINE__, size) #define grub_realloc(ptr,size) \ - grub_debug_realloc (__FILE__, __LINE__, ptr, size) + grub_debug_realloc (GRUB_FILE, __LINE__, ptr, size) #define grub_memalign(align,size) \ - grub_debug_memalign (__FILE__, __LINE__, align, size) + grub_debug_memalign (GRUB_FILE, __LINE__, align, size) #define grub_free(ptr) \ - grub_debug_free (__FILE__, __LINE__, ptr) + grub_debug_free (GRUB_FILE, __LINE__, ptr) void *EXPORT_FUNC(grub_debug_malloc) (const char *file, int line, grub_size_t size); diff --git a/include/grub/msdos_partition.h b/include/grub/msdos_partition.h index 273d8c95e..650d78493 100644 --- a/include/grub/msdos_partition.h +++ b/include/grub/msdos_partition.h @@ -53,75 +53,6 @@ #define GRUB_PC_PARTITION_TYPE_GPT_DISK 0xee #define GRUB_PC_PARTITION_TYPE_LINUX_RAID 0xfd -/* Constants for BSD disk label. */ -#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR 1 -#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC 0x82564557 -#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES 8 - -/* BSD partition types. */ -#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED 0 -#define GRUB_PC_PARTITION_BSD_TYPE_SWAP 1 -#define GRUB_PC_PARTITION_BSD_TYPE_V6 2 -#define GRUB_PC_PARTITION_BSD_TYPE_V7 3 -#define GRUB_PC_PARTITION_BSD_TYPE_SYSV 4 -#define GRUB_PC_PARTITION_BSD_TYPE_V71K 5 -#define GRUB_PC_PARTITION_BSD_TYPE_V8 6 -#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS 7 -#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS 8 -#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS 9 -#define GRUB_PC_PARTITION_BSD_TYPE_OTHER 10 -#define GRUB_PC_PARTITION_BSD_TYPE_HPFS 11 -#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660 12 -#define GRUB_PC_PARTITION_BSD_TYPE_BOOT 13 - -/* FreeBSD-specific types. */ -#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM 14 -#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID 15 -#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2 21 - -/* NetBSD-specific types. */ -#define GRUB_PC_PARTITION_NETBSD_TYPE_ADOS 14 -#define GRUB_PC_PARTITION_NETBSD_TYPE_HFS 15 -#define GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE 16 -#define GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS 17 -#define GRUB_PC_PARTITION_NETBSD_TYPE_NTFS 18 -#define GRUB_PC_PARTITION_NETBSD_TYPE_RAID 19 -#define GRUB_PC_PARTITION_NETBSD_TYPE_CCD 20 -#define GRUB_PC_PARTITION_NETBSD_TYPE_JFS2 21 -#define GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS 22 - -/* OpenBSD-specific types. */ -#define GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS 14 -#define GRUB_PC_PARTITION_OPENBSD_TYPE_HFS 15 -#define GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE 16 -#define GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS 17 -#define GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS 18 -#define GRUB_PC_PARTITION_OPENBSD_TYPE_RAID 19 - -/* The BSD partition entry. */ -struct grub_msdos_partition_bsd_entry -{ - grub_uint32_t size; - grub_uint32_t offset; - grub_uint32_t fragment_size; - grub_uint8_t fs_type; - grub_uint8_t fs_fragments; - grub_uint16_t fs_cylinders; -} __attribute__ ((packed)); - -/* The BSD disk label. Only define members useful for GRUB. */ -struct grub_msdos_partition_disk_label -{ - grub_uint32_t magic; - grub_uint8_t padding[128]; - grub_uint32_t magic2; - grub_uint16_t checksum; - grub_uint16_t num_partitions; - grub_uint32_t boot_size; - grub_uint32_t superblock_size; - struct grub_msdos_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES]; -} __attribute__ ((packed)); - /* The partition entry. */ struct grub_msdos_partition_entry { @@ -168,23 +99,6 @@ struct grub_msdos_partition_mbr } __attribute__ ((packed)); -struct grub_msdos_partition -{ - /* The DOS partition number. */ - int dos_part; - - /* The BSD partition number (a == 0). */ - int bsd_part; - - /* The DOS partition type. */ - int dos_type; - - /* The BSD partition type. */ - int bsd_type; - - /* The offset of the extended partition. */ - unsigned long ext_offset; -}; static inline int grub_msdos_partition_is_empty (int type) @@ -200,12 +114,4 @@ grub_msdos_partition_is_extended (int type) || type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED); } -static inline int -grub_msdos_partition_is_bsd (int type) -{ - return (type == GRUB_PC_PARTITION_TYPE_FREEBSD - || type == GRUB_PC_PARTITION_TYPE_OPENBSD - || type == GRUB_PC_PARTITION_TYPE_NETBSD); -} - #endif /* ! GRUB_PC_PARTITION_HEADER */ diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index c54874942..63947d1bc 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -1,7 +1,7 @@ /* multiboot.h - multiboot header file with grub definitions. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2003,2007,2008,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 @@ -20,9 +20,55 @@ #ifndef GRUB_MULTIBOOT_HEADER #define GRUB_MULTIBOOT_HEADER 1 +#include + +#ifdef GRUB_USE_MULTIBOOT2 +#include +/* Same thing as far as our loader is concerned. */ +#define MULTIBOOT_BOOTLOADER_MAGIC MULTIBOOT2_BOOTLOADER_MAGIC +#define MULTIBOOT_HEADER_MAGIC MULTIBOOT2_HEADER_MAGIC +#else #include +#endif + +#include +#include void grub_multiboot (int argc, char *argv[]); void grub_module (int argc, char *argv[]); +grub_size_t grub_multiboot_get_mbi_size (void); +grub_err_t grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, + grub_off_t buf_off, grub_size_t bufsize); +void grub_multiboot_free_mbi (void); +grub_err_t grub_multiboot_init_mbi (int argc, char *argv[]); +grub_err_t grub_multiboot_add_module (grub_addr_t start, grub_size_t size, + int argc, char *argv[]); +void grub_multiboot_set_bootdev (void); + +grub_uint32_t grub_get_multiboot_mmap_count (void); +grub_err_t grub_multiboot_set_video_mode (void); + +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_QEMU) +#include +#define GRUB_MACHINE_HAS_VGA_TEXT 1 +#else +#define GRUB_MACHINE_HAS_VGA_TEXT 0 +#endif + +#define GRUB_MULTIBOOT_CONSOLE_EGA_TEXT 1 +#define GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER 2 + +grub_err_t +grub_multiboot_set_console (int console_type, int accepted_consoles, + int width, int height, int depth, + int console_required); +grub_err_t +grub_multiboot_load (grub_file_t file); +/* Load ELF32 or ELF64. */ +grub_err_t +grub_multiboot_load_elf (grub_file_t file, void *buffer); +extern grub_size_t grub_multiboot_pure_size; +extern grub_size_t grub_multiboot_alloc_mbi; + #endif /* ! GRUB_MULTIBOOT_HEADER */ diff --git a/include/grub/multiboot2.h b/include/grub/multiboot2.h deleted file mode 100644 index af10cdc21..000000000 --- a/include/grub/multiboot2.h +++ /dev/null @@ -1,70 +0,0 @@ -/* multiboot2.h - multiboot2 header file with grub definitions. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007 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 . - */ - -#ifndef GRUB_MULTIBOOT2_HEADER -#define GRUB_MULTIBOOT2_HEADER 1 - -#include -#include -#include - -#ifndef GRUB_UTIL -typedef grub_uint32_t uint32_t; -typedef grub_uint64_t uint64_t; -#define __WORDSIZE GRUB_TARGET_WORDSIZE -#endif - -struct multiboot2_tag_header; - -grub_err_t -grub_mb2_tag_alloc (grub_addr_t *addr, int key, grub_size_t len); - -grub_err_t -grub_mb2_tags_arch_create (void); - -void -grub_mb2_arch_boot (grub_addr_t entry, void *tags); - -void -grub_mb2_arch_unload (struct multiboot2_tag_header *tags); - -grub_err_t -grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load); - -grub_err_t -grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load); - -grub_err_t -grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr); - -grub_err_t -grub_mb2_arch_module_free (grub_addr_t addr, grub_size_t size); - -void -grub_multiboot2 (int argc, char *argv[]); - -void -grub_module2 (int argc, char *argv[]); - -#define for_each_tag(tag, tags) \ - for (tag = tags; \ - tag && tag->key != MULTIBOOT2_TAG_END; \ - tag = (struct multiboot2_tag_header *)((char *)tag + tag->len)) - -#endif /* ! GRUB_MULTIBOOT2_HEADER */ diff --git a/include/grub/normal.h b/include/grub/normal.h index feebc85b1..35eedf5ae 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -20,6 +20,7 @@ #ifndef GRUB_NORMAL_HEADER #define GRUB_NORMAL_HEADER 1 +#include #include #include #include @@ -30,6 +31,9 @@ /* The maximum size of a command-line. */ #define GRUB_MAX_CMDLINE 1600 +/* The standard left and right margin for some messages. */ +#define STANDARD_MARGIN 6 + /* The type of a completion item. */ enum grub_completion_type { @@ -42,21 +46,21 @@ enum grub_completion_type typedef enum grub_completion_type grub_completion_type_t; extern struct grub_menu_viewer grub_normal_text_menu_viewer; - +extern int grub_normal_exit_level; /* Defined in `main.c'. */ void grub_enter_normal_mode (const char *config); void grub_normal_execute (const char *config, int nested, int batch); -void grub_normal_init_page (void); -void grub_menu_init_page (int nested, int edit); +void grub_menu_init_page (int nested, int edit, + struct grub_term_output *term); +void grub_normal_init_page (struct grub_term_output *term); grub_err_t grub_normal_add_menu_entry (int argc, const char **args, const char *sourcecode); char *grub_file_getline (grub_file_t file); void grub_cmdline_run (int nested); /* Defined in `cmdline.c'. */ -int grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, - int echo_char, int readline, int history); +char *grub_cmdline_get (const char *prompt); grub_err_t grub_set_history (int newsize); /* Defined in `completion.c'. */ @@ -73,49 +77,40 @@ void grub_parse_color_name_pair (grub_uint8_t *ret, const char *name); /* Defined in `menu_text.c'. */ void grub_wait_after_message (void); +void grub_print_ucs4 (const grub_uint32_t * str, + const grub_uint32_t * last_position, + struct grub_term_output *term); +grub_ssize_t grub_getstringwidth (grub_uint32_t * str, + const grub_uint32_t * last_position, + struct grub_term_output *term); +void grub_print_message_indented (const char *msg, int margin_left, + int margin_right, + struct grub_term_output *term); +void +grub_menu_text_register_instances (int entry, grub_menu_t menu, int nested); +grub_err_t +grub_show_menu (grub_menu_t menu, int nested); /* Defined in `handler.c'. */ void read_handler_list (void); void free_handler_list (void); /* Defined in `dyncmd.c'. */ -void read_command_list (void); +void read_command_list (const char *prefix); /* Defined in `autofs.c'. */ -void read_fs_list (void); +void read_fs_list (const char *prefix); +void grub_context_init (void); +void grub_context_fini (void); -#ifdef GRUB_UTIL -void grub_normal_init (void); -void grub_normal_fini (void); -void grub_hello_init (void); -void grub_hello_fini (void); -void grub_ls_init (void); -void grub_ls_fini (void); -void grub_cat_init (void); -void grub_cat_fini (void); -void grub_boot_init (void); -void grub_boot_fini (void); -void grub_cmp_init (void); -void grub_cmp_fini (void); -void grub_terminal_init (void); -void grub_terminal_fini (void); -void grub_loop_init (void); -void grub_loop_fini (void); -void grub_help_init (void); -void grub_help_fini (void); -void grub_halt_init (void); -void grub_halt_fini (void); -void grub_reboot_init (void); -void grub_reboot_fini (void); -void grub_configfile_init (void); -void grub_configfile_fini (void); -void grub_search_init (void); -void grub_search_fini (void); -void grub_test_init (void); -void grub_test_fini (void); -void grub_blocklist_init (void); -void grub_blocklist_fini (void); -#endif +void read_crypto_list (const char *prefix); + +void read_terminal_list (const char *prefix); + +void grub_set_more (int onoff); + +int grub_normal_get_line_counter (void); +void grub_install_newline_hook (void); #endif /* ! GRUB_NORMAL_HEADER */ diff --git a/include/grub/ntfs.h b/include/grub/ntfs.h index 6f9d4ad6e..31b99398b 100644 --- a/include/grub/ntfs.h +++ b/include/grub/ntfs.h @@ -1,7 +1,7 @@ /* ntfs.h - header for the NTFS filesystem */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007 Free Software Foundation, Inc. + * Copyright (C) 2007,2009 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 diff --git a/include/grub/offsets.h b/include/grub/offsets.h new file mode 100644 index 000000000..ae0b2557e --- /dev/null +++ b/include/grub/offsets.h @@ -0,0 +1,173 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2007,2008 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 . + */ + +#ifndef OFFSETS_HEADER +#define OFFSETS_HEADER 1 + +/* The offset of GRUB_TOTAL_MODULE_SIZE. */ +#define GRUB_KERNEL_I386_PC_TOTAL_MODULE_SIZE 0x8 + +/* The offset of GRUB_KERNEL_IMAGE_SIZE. */ +#define GRUB_KERNEL_I386_PC_KERNEL_IMAGE_SIZE 0xc + +/* The offset of GRUB_COMPRESSED_SIZE. */ +#define GRUB_KERNEL_I386_PC_COMPRESSED_SIZE 0x10 + +/* The offset of GRUB_INSTALL_DOS_PART. */ +#define GRUB_KERNEL_I386_PC_INSTALL_DOS_PART 0x14 + +/* The offset of GRUB_INSTALL_BSD_PART. */ +#define GRUB_KERNEL_I386_PC_INSTALL_BSD_PART 0x18 + +/* The offset of GRUB_PREFIX. */ +#define GRUB_KERNEL_I386_PC_PREFIX 0x1c + +/* End of the data section. */ +#define GRUB_KERNEL_I386_PC_DATA_END 0x5c + +/* The size of the first region which won't be compressed. */ +#define GRUB_KERNEL_I386_PC_RAW_SIZE (GRUB_KERNEL_I386_PC_DATA_END + 0x5F0) + +/* The segment where the kernel is loaded. */ +#define GRUB_BOOT_I386_PC_KERNEL_SEG 0x800 + +#define GRUB_KERNEL_I386_PC_LINK_ADDR 0x8200 + +/* The upper memory area (starting at 640 kiB). */ +#define GRUB_MEMORY_I386_PC_UPPER 0xa0000 +#define GRUB_MEMORY_I386_QEMU_UPPER GRUB_MEMORY_I386_PC_UPPER + +/* The offset of GRUB_CORE_ENTRY_ADDR. */ +#define GRUB_BOOT_I386_QEMU_CORE_ENTRY_ADDR 0x4 + +/* The offset of GRUB_CORE_ENTRY_ADDR. */ +#define GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR 0x8 + +/* The offset of GRUB_KERNEL_IMAGE_SIZE. */ +#define GRUB_KERNEL_I386_QEMU_KERNEL_IMAGE_SIZE 0xc + +/* The offset of GRUB_PREFIX. */ +#define GRUB_KERNEL_I386_QEMU_PREFIX 0x10 + +/* End of the data section. */ +#define GRUB_KERNEL_I386_QEMU_DATA_END 0x50 + +#define GRUB_KERNEL_I386_QEMU_LINK_ADDR 0x8200 + +/* The offset of GRUB_TOTAL_MODULE_SIZE. */ +#define GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE 0x8 + +/* The offset of GRUB_KERNEL_IMAGE_SIZE. */ +#define GRUB_KERNEL_SPARC64_IEEE1275_KERNEL_IMAGE_SIZE 0xc + +/* The offset of GRUB_COMPRESSED_SIZE. */ +#define GRUB_KERNEL_SPARC64_IEEE1275_COMPRESSED_SIZE 0x10 + +/* The offset of GRUB_PREFIX. */ +#define GRUB_KERNEL_SPARC64_IEEE1275_PREFIX 0x14 + +/* End of the data section. */ +#define GRUB_KERNEL_SPARC64_IEEE1275_DATA_END 0x114 + +#define GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE 12 + +#define GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS 0x4400 +#define GRUB_KERNEL_SPARC64_IEEE1275_RAW_SIZE 0 +#define GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR 0x4400 + +#define GRUB_KERNEL_POWERPC_IEEE1275_PREFIX 0x4 +#define GRUB_KERNEL_POWERPC_IEEE1275_DATA_END 0x44 +#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ALIGN 4 +#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x200000 + +#define GRUB_KERNEL_MIPS_YEELOONG_LINK_ADDR 0x80200000 + +#define GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN 32 + +#define GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE 0x200 +#define GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE 0x8 +#define GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE 0xc +#define GRUB_KERNEL_MIPS_YEELOONG_KERNEL_IMAGE_SIZE 0x10 + +#define GRUB_KERNEL_MIPS_YEELOONG_PREFIX GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE +#define GRUB_KERNEL_MIPS_YEELOONG_DATA_END GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE + 0x48 + +/* The offset of GRUB_PREFIX. */ +#define GRUB_KERNEL_I386_EFI_PREFIX 0x8 + +/* End of the data section. */ +#define GRUB_KERNEL_I386_EFI_DATA_END 0x50 + +/* The offset of GRUB_PREFIX. */ +#define GRUB_KERNEL_X86_64_EFI_PREFIX 0x8 + +/* End of the data section. */ +#define GRUB_KERNEL_X86_64_EFI_DATA_END 0x50 + +#define GRUB_KERNEL_I386_COREBOOT_PREFIX 0x2 +#define GRUB_KERNEL_I386_COREBOOT_DATA_END 0x42 +#define GRUB_KERNEL_I386_COREBOOT_LINK_ADDR 0x8200 + +#define GRUB_KERNEL_I386_IEEE1275_PREFIX 0x2 +#define GRUB_KERNEL_I386_IEEE1275_DATA_END 0x42 +#define GRUB_KERNEL_I386_IEEE1275_LINK_ADDR 0x10000 + +#define GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN 0x1000 +#define GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN 0x1 + +/* Non-zero value is only needed for PowerMacs. */ +#define GRUB_KERNEL_I386_IEEE1275_MOD_GAP 0x0 +#define GRUB_KERNEL_I386_COREBOOT_MOD_GAP 0x0 + +#define GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN 0x1000 + +#define GRUB_KERNEL_MIPS_YEELOONG_MOD_ALIGN 0x1 + +/* Minimal gap between _end and the start of the modules. It's a hack + for PowerMac to prevent "CLAIM failed" error. The real fix is to + rewrite grub-mkimage to generate valid ELF files. */ +#define GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP 0x8000 + +#ifdef MACHINE +#define GRUB_OFFSETS_CONCAT_(a,b,c) a ## b ## c +#define GRUB_OFFSETS_CONCAT(a,b,c) GRUB_OFFSETS_CONCAT_(a,b,c) +#define GRUB_KERNEL_MACHINE_MOD_ALIGN GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _MOD_ALIGN) +#define GRUB_KERNEL_MACHINE_MOD_GAP GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _MOD_GAP) +#define GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _TOTAL_MODULE_SIZE) +#define GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _KERNEL_IMAGE_SIZE) +#define GRUB_KERNEL_MACHINE_COMPRESSED_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _COMPRESSED_SIZE) + +#define GRUB_KERNEL_MACHINE_PREFIX GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _PREFIX) +#define GRUB_KERNEL_MACHINE_DATA_END GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _DATA_END) +#define GRUB_BOOT_MACHINE_KERNEL_SEG GRUB_OFFSETS_CONCAT (GRUB_BOOT_, MACHINE, _KERNEL_SEG) +#define GRUB_MEMORY_MACHINE_UPPER GRUB_OFFSETS_CONCAT (GRUB_MEMORY_, MACHINE, _UPPER) +#define GRUB_KERNEL_MACHINE_RAW_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _RAW_SIZE) +#define GRUB_KERNEL_MACHINE_INSTALL_BSD_PART GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _INSTALL_BSD_PART) +#define GRUB_KERNEL_MACHINE_INSTALL_DOS_PART GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _INSTALL_DOS_PART) +#endif + +#ifndef ASM_FILE +struct grub_pc_bios_boot_blocklist +{ + grub_uint64_t start; + grub_uint16_t len; + grub_uint16_t segment; +} __attribute__ ((packed)); +#endif + +#endif diff --git a/include/grub/parser.h b/include/grub/parser.h index 41f768bba..17f0c4303 100644 --- a/include/grub/parser.h +++ b/include/grub/parser.h @@ -22,6 +22,7 @@ #include #include +#include #include /* All the states for the command line. */ diff --git a/include/grub/partition.h b/include/grub/partition.h index d35658cdd..80a9c15f0 100644 --- a/include/grub/partition.h +++ b/include/grub/partition.h @@ -20,6 +20,7 @@ #define GRUB_PART_HEADER 1 #include +#include struct grub_disk; @@ -28,6 +29,9 @@ typedef struct grub_partition *grub_partition_t; /* Partition map type. */ struct grub_partition_map { + /* The next partition map type. */ + struct grub_partition_map *next; + /* The name of the partition map type. */ const char *name; @@ -35,22 +39,15 @@ struct grub_partition_map grub_err_t (*iterate) (struct grub_disk *disk, int (*hook) (struct grub_disk *disk, const grub_partition_t partition)); - - /* Return the partition named STR on the disk DISK. */ - grub_partition_t (*probe) (struct grub_disk *disk, - const char *str); - - /* Return the name of the partition PARTITION. */ - char *(*get_name) (const grub_partition_t partition); - - /* The next partition map type. */ - struct grub_partition_map *next; }; typedef struct grub_partition_map *grub_partition_map_t; /* Partition description. */ struct grub_partition { + /* The partition number. */ + int number; + /* The start sector. */ grub_disk_addr_t start; @@ -63,8 +60,8 @@ struct grub_partition /* The index of this partition in the partition table. */ int index; - /* Partition map type specific data. */ - void *data; + /* Parent partition map. */ + struct grub_partition *parent; /* The type partition map. */ grub_partition_map_t partmap; @@ -77,31 +74,36 @@ int EXPORT_FUNC(grub_partition_iterate) (struct grub_disk *disk, const grub_partition_t partition)); char *EXPORT_FUNC(grub_partition_get_name) (const grub_partition_t partition); -int EXPORT_FUNC(grub_partition_map_iterate) (int (*hook) (const grub_partition_map_t partmap)); -void EXPORT_FUNC(grub_partition_map_register) (grub_partition_map_t partmap); +extern grub_partition_map_t EXPORT_VAR(grub_partition_map_list); -void EXPORT_FUNC(grub_partition_map_unregister) (grub_partition_map_t partmap); +static inline void +grub_partition_map_register (grub_partition_map_t partmap) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_partition_map_list), + GRUB_AS_LIST (partmap)); +} + +static inline void +grub_partition_map_unregister (grub_partition_map_t partmap) +{ + grub_list_remove (GRUB_AS_LIST_P (&grub_partition_map_list), + GRUB_AS_LIST (partmap)); +} + +#define FOR_PARTITION_MAPS(var) for (var = grub_partition_map_list; var; var = var->next) -#ifdef GRUB_UTIL -void grub_msdos_partition_map_init (void); -void grub_msdos_partition_map_fini (void); -void grub_amiga_partition_map_init (void); -void grub_amiga_partition_map_fini (void); -void grub_apple_partition_map_init (void); -void grub_apple_partition_map_fini (void); -void grub_sun_partition_map_init (void); -void grub_sun_partition_map_fini (void); -void grub_gpt_partition_map_init (void); -void grub_gpt_partition_map_fini (void); -void grub_apple_partition_map_init (void); -void grub_apple_partition_map_fini (void); -#endif static inline grub_disk_addr_t grub_partition_get_start (const grub_partition_t p) { - return p->start; + grub_partition_t part; + grub_uint64_t part_start = 0; + + for (part = p; part; part = part->parent) + part_start += part->start; + + return part_start; } static inline grub_uint64_t diff --git a/include/grub/pci.h b/include/grub/pci.h index 7c8b50528..89bd1034a 100644 --- a/include/grub/pci.h +++ b/include/grub/pci.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 @@ -35,16 +35,76 @@ #define GRUB_PCI_ADDR_MEM_MASK ~0xf #define GRUB_PCI_ADDR_IO_MASK ~0x03 -typedef grub_uint32_t grub_pci_id_t; -typedef int NESTED_FUNC_ATTR (*grub_pci_iteratefunc_t) - (int bus, int device, int func, grub_pci_id_t pciid); -typedef grub_uint32_t grub_pci_address_t; +#define GRUB_PCI_REG_PCI_ID 0x00 +#define GRUB_PCI_REG_VENDOR 0x00 +#define GRUB_PCI_REG_DEVICE 0x02 +#define GRUB_PCI_REG_COMMAND 0x04 +#define GRUB_PCI_REG_STATUS 0x06 +#define GRUB_PCI_REG_REVISION 0x08 +#define GRUB_PCI_REG_CLASS 0x08 +#define GRUB_PCI_REG_CACHELINE 0x0c +#define GRUB_PCI_REG_LAT_TIMER 0x0d +#define GRUB_PCI_REG_HEADER_TYPE 0x0e +#define GRUB_PCI_REG_BIST 0x0f +#define GRUB_PCI_REG_ADDRESSES 0x10 -grub_pci_address_t EXPORT_FUNC(grub_pci_make_address) (int bus, int device, - int function, int reg); +/* Beware that 64-bit address takes 2 registers. */ +#define GRUB_PCI_REG_ADDRESS_REG0 0x10 +#define GRUB_PCI_REG_ADDRESS_REG1 0x14 +#define GRUB_PCI_REG_ADDRESS_REG2 0x18 +#define GRUB_PCI_REG_ADDRESS_REG3 0x1c +#define GRUB_PCI_REG_ADDRESS_REG4 0x20 +#define GRUB_PCI_REG_ADDRESS_REG5 0x24 + +#define GRUB_PCI_REG_CIS_POINTER 0x28 +#define GRUB_PCI_REG_SUBVENDOR 0x2c +#define GRUB_PCI_REG_SUBSYSTEM 0x2e +#define GRUB_PCI_REG_ROM_ADDRESS 0x30 +#define GRUB_PCI_REG_CAP_POINTER 0x34 +#define GRUB_PCI_REG_IRQ_LINE 0x3c +#define GRUB_PCI_REG_IRQ_PIN 0x3d +#define GRUB_PCI_REG_MIN_GNT 0x3e +#define GRUB_PCI_REG_MAX_LAT 0x3f + +typedef grub_uint32_t grub_pci_id_t; + +#ifdef GRUB_MACHINE_EMU +#include +#else +typedef grub_uint32_t grub_pci_address_t; +struct grub_pci_device +{ + int bus; + int device; + int function; +}; +typedef struct grub_pci_device grub_pci_device_t; +static inline int +grub_pci_get_bus (grub_pci_device_t dev) +{ + return dev.bus; +} + +static inline int +grub_pci_get_device (grub_pci_device_t dev) +{ + return dev.device; +} + +static inline int +grub_pci_get_function (grub_pci_device_t dev) +{ + return dev.function; +} +#include +#endif + +typedef int NESTED_FUNC_ATTR (*grub_pci_iteratefunc_t) + (grub_pci_device_t dev, grub_pci_id_t pciid); + +grub_pci_address_t EXPORT_FUNC(grub_pci_make_address) (grub_pci_device_t dev, + int reg); void EXPORT_FUNC(grub_pci_iterate) (grub_pci_iteratefunc_t hook); -#include - #endif /* GRUB_PCI_H */ diff --git a/include/grub/pciutils.h b/include/grub/pciutils.h new file mode 100644 index 000000000..36d47e5c8 --- /dev/null +++ b/include/grub/pciutils.h @@ -0,0 +1,103 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#ifndef GRUB_PCIUTILS_H +#define GRUB_PCIUTILS_H 1 + +#include + +typedef struct pci_device *grub_pci_device_t; + +static inline int +grub_pci_get_bus (grub_pci_device_t dev) +{ + return dev->bus; +} + +static inline int +grub_pci_get_device (grub_pci_device_t dev) +{ + return dev->dev; +} + +static inline int +grub_pci_get_function (grub_pci_device_t dev) +{ + return dev->func; +} + +struct grub_pci_address +{ + grub_pci_device_t dev; + int pos; +}; + +typedef struct grub_pci_address grub_pci_address_t; + +static inline grub_uint32_t +grub_pci_read (grub_pci_address_t addr) +{ + grub_uint32_t ret; + pci_device_cfg_read_u32 (addr.dev, &ret, addr.pos); + return ret; +} + +static inline grub_uint16_t +grub_pci_read_word (grub_pci_address_t addr) +{ + grub_uint16_t ret; + pci_device_cfg_read_u16 (addr.dev, &ret, addr.pos); + return ret; +} + +static inline grub_uint8_t +grub_pci_read_byte (grub_pci_address_t addr) +{ + grub_uint8_t ret; + pci_device_cfg_read_u8 (addr.dev, &ret, addr.pos); + return ret; +} + +static inline void +grub_pci_write (grub_pci_address_t addr, grub_uint32_t data) +{ + pci_device_cfg_write_u32 (addr.dev, data, addr.pos); +} + +static inline void +grub_pci_write_word (grub_pci_address_t addr, grub_uint16_t data) +{ + pci_device_cfg_write_u16 (addr.dev, data, addr.pos); +} + +static inline void +grub_pci_write_byte (grub_pci_address_t addr, grub_uint8_t data) +{ + pci_device_cfg_write_u8 (addr.dev, data, addr.pos); +} + +void * +grub_pci_device_map_range (grub_pci_device_t dev, grub_addr_t base, + grub_size_t size); + +void +grub_pci_device_unmap_range (grub_pci_device_t dev, void *mem, + grub_size_t size); + + +#endif /* GRUB_PCIUTILS_H */ diff --git a/include/grub/powerpc/ieee1275/ieee1275.h b/include/grub/powerpc/ieee1275/ieee1275.h index 7e93055c9..3c7683fad 100644 --- a/include/grub/powerpc/ieee1275/ieee1275.h +++ b/include/grub/powerpc/ieee1275/ieee1275.h @@ -22,6 +22,7 @@ #include +#define GRUB_IEEE1275_CELL_SIZEOF 4 typedef grub_uint32_t grub_ieee1275_cell_t; #endif /* ! GRUB_IEEE1275_MACHINE_HEADER */ diff --git a/include/grub/powerpc/kernel.h b/include/grub/powerpc/kernel.h index b4687337f..3fc0b9e23 100644 --- a/include/grub/powerpc/kernel.h +++ b/include/grub/powerpc/kernel.h @@ -19,14 +19,4 @@ #ifndef GRUB_KERNEL_CPU_HEADER #define GRUB_KERNEL_CPU_HEADER 1 -#define GRUB_MOD_ALIGN 0x1000 - -/* Minimal gap between _end and the start of the modules. It's a hack - for PowerMac to prevent "CLAIM failed" error. The real fix is to - rewrite grub-mkimage to generate valid ELF files. */ -#define GRUB_MOD_GAP 0x8000 - -#define GRUB_KERNEL_CPU_PREFIX 0x4 -#define GRUB_KERNEL_CPU_DATA_END 0x44 - #endif diff --git a/include/grub/reader.h b/include/grub/reader.h index c7e67bf5e..fd72a3252 100644 --- a/include/grub/reader.h +++ b/include/grub/reader.h @@ -20,60 +20,10 @@ #ifndef GRUB_READER_HEADER #define GRUB_READER_HEADER 1 -#include #include -#include typedef grub_err_t (*grub_reader_getline_t) (char **, int); -struct grub_reader -{ - /* The next reader. */ - struct grub_parser *next; - - /* The reader name. */ - const char *name; - - /* Initialize the reader. */ - grub_err_t (*init) (void); - - /* Clean up the reader. */ - grub_err_t (*fini) (void); - - grub_reader_getline_t read_line; -}; -typedef struct grub_reader *grub_reader_t; - -extern struct grub_handler_class EXPORT_VAR(grub_reader_class); - -grub_err_t EXPORT_FUNC(grub_reader_loop) (grub_reader_getline_t getline); - -static inline void -grub_reader_register (const char *name __attribute__ ((unused)), - grub_reader_t reader) -{ - grub_handler_register (&grub_reader_class, GRUB_AS_HANDLER (reader)); -} - -static inline void -grub_reader_unregister (grub_reader_t reader) -{ - grub_handler_unregister (&grub_reader_class, GRUB_AS_HANDLER (reader)); -} - -static inline grub_reader_t -grub_reader_get_current (void) -{ - return (grub_reader_t) grub_reader_class.cur_handler; -} - -static inline grub_err_t -grub_reader_set_current (grub_reader_t reader) -{ - return grub_handler_set_current (&grub_reader_class, - GRUB_AS_HANDLER (reader)); -} - -void grub_register_rescue_reader (void); +void grub_rescue_run (void); #endif /* ! GRUB_READER_HEADER */ diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index f6177b02a..b55b6a806 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -1,7 +1,7 @@ /* normal_parser.h */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007,2009 Free Software Foundation, Inc. + * Copyright (C) 2005,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 @@ -45,8 +45,11 @@ struct grub_script typedef enum { - GRUB_SCRIPT_ARG_TYPE_STR, - GRUB_SCRIPT_ARG_TYPE_VAR + GRUB_SCRIPT_ARG_TYPE_VAR, + GRUB_SCRIPT_ARG_TYPE_TEXT, + GRUB_SCRIPT_ARG_TYPE_DQVAR, + GRUB_SCRIPT_ARG_TYPE_DQSTR, + GRUB_SCRIPT_ARG_TYPE_SQSTR } grub_script_arg_type_t; /* A part of an argument. */ @@ -103,6 +106,36 @@ struct grub_script_cmdif struct grub_script_cmd *exec_on_false; }; +/* A for statement. */ +struct grub_script_cmdfor +{ + struct grub_script_cmd cmd; + + /* The name used as looping variable. */ + struct grub_script_arg *name; + + /* The words loop iterates over. */ + struct grub_script_arglist *words; + + /* The command list executed in each loop. */ + struct grub_script_cmd *list; +}; + +/* A while/until command. */ +struct grub_script_cmdwhile +{ + struct grub_script_cmd cmd; + + /* The command list used as condition. */ + struct grub_script_cmd *cond; + + /* The command list executed in each loop. */ + struct grub_script_cmd *list; + + /* The flag to indicate this as "until" loop. */ + int until; +}; + /* A menu entry generate statement. */ struct grub_script_cmd_menuentry { @@ -121,12 +154,6 @@ struct grub_script_cmd_menuentry /* State of the lexer as passed to the lexer. */ struct grub_lexer_param { - /* Set to 0 when the lexer is done. */ - int done; - - /* State of the state machine. */ - grub_parser_state_t state; - /* Function used by the lexer to get a new line when more input is expected, but not available. */ grub_reader_getline_t getline; @@ -137,10 +164,6 @@ struct grub_lexer_param depleted. */ int refs; - /* The character stream that has to be parsed. */ - char *script; - char *newscript; /* XXX */ - /* While walking through the databuffer, `record' the characters to this other buffer. It can be used to edit the menu entry at a later moment. */ @@ -157,13 +180,31 @@ struct grub_lexer_param /* Size of RECORDING. */ int recordlen; - /* The token that is already parsed but not yet returned. */ - int tokenonhold; + /* End of file reached. */ + int eof; - /* Was the last token a newline? */ - int was_newline; + /* Merge multiple word tokens. */ + int merge_start; + int merge_end; + + /* Part of a multi-part token. */ + char *text; + unsigned used; + unsigned size; + + /* Type of text. */ + grub_script_arg_type_t type; + + /* Flex scanner. */ + void *yyscanner; + + /* Flex scanner buffer. */ + void *buffer; }; +#define GRUB_LEXER_INITIAL_TEXT_SIZE 32 +#define GRUB_LEXER_INITIAL_RECORD_SIZE 256 + /* State of the parser as passes to the parser. */ struct grub_parser_param { @@ -202,6 +243,18 @@ grub_script_create_cmdif (struct grub_parser_param *state, struct grub_script_cmd *exec_on_true, struct grub_script_cmd *exec_on_false); +struct grub_script_cmd * +grub_script_create_cmdfor (struct grub_parser_param *state, + struct grub_script_arg *name, + struct grub_script_arglist *words, + struct grub_script_cmd *list); + +struct grub_script_cmd * +grub_script_create_cmdwhile (struct grub_parser_param *state, + struct grub_script_cmd *cond, + struct grub_script_cmd *list, + int is_an_until_loop); + struct grub_script_cmd * grub_script_create_cmdmenu (struct grub_parser_param *state, struct grub_script_arglist *arglist, @@ -223,12 +276,16 @@ void grub_script_free (struct grub_script *script); struct grub_script *grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem); -struct grub_lexer_param *grub_script_lexer_init (char *s, +struct grub_lexer_param *grub_script_lexer_init (struct grub_parser_param *parser, + char *script, grub_reader_getline_t getline); +void grub_script_lexer_fini (struct grub_lexer_param *); void grub_script_lexer_ref (struct grub_lexer_param *); void grub_script_lexer_deref (struct grub_lexer_param *); -void grub_script_lexer_record_start (struct grub_lexer_param *); -char *grub_script_lexer_record_stop (struct grub_lexer_param *); +void grub_script_lexer_record_start (struct grub_parser_param *); +char *grub_script_lexer_record_stop (struct grub_parser_param *); +int grub_script_lexer_yywrap (struct grub_parser_param *); +void grub_script_lexer_record (struct grub_parser_param *, char *); /* Functions to track allocated memory. */ struct grub_script_mem *grub_script_mem_record (struct grub_parser_param *state); @@ -246,6 +303,8 @@ void grub_script_yyerror (struct grub_parser_param *, char const *); grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdblock (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd); +grub_err_t grub_script_execute_cmdfor (struct grub_script_cmd *cmd); +grub_err_t grub_script_execute_cmdwhile (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd); /* Execute any GRUB pre-parsed command or script. */ @@ -284,7 +343,7 @@ int grub_script_function_iterate (int (*iterate) (grub_script_function_t)); int grub_script_function_call (grub_script_function_t func, int argc, char **args); -char * -grub_script_execute_argument_to_string (struct grub_script_arg *arg); +char ** +grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *count); #endif /* ! GRUB_NORMAL_PARSER_HEADER */ diff --git a/include/grub/sdl.h b/include/grub/sdl.h new file mode 100644 index 000000000..e4efdc9b1 --- /dev/null +++ b/include/grub/sdl.h @@ -0,0 +1,24 @@ +/* + * 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 . + */ + +void EXPORT_FUNC (SDL_Quit) (void); +void EXPORT_FUNC (SDL_SetColors) (void); +void EXPORT_FUNC (SDL_Init) (void); +void EXPORT_FUNC (SDL_GetError) (void); +void EXPORT_FUNC (SDL_Flip) (void); +void EXPORT_FUNC (SDL_SetVideoMode) (void); diff --git a/include/grub/search.h b/include/grub/search.h new file mode 100644 index 000000000..e8f9db285 --- /dev/null +++ b/include/grub/search.h @@ -0,0 +1,26 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#ifndef GRUB_SEARCH_HEADER +#define GRUB_SEARCH_HEADER 1 + +void grub_search_fs_file (const char *key, const char *var, int no_floppy); +void grub_search_fs_uuid (const char *key, const char *var, int no_floppy); +void grub_search_label (const char *key, const char *var, int no_floppy); + +#endif diff --git a/include/grub/i386/pc/serial.h b/include/grub/serial.h similarity index 96% rename from include/grub/i386/pc/serial.h rename to include/grub/serial.h index 0632ff79d..1c35b4093 100644 --- a/include/grub/i386/pc/serial.h +++ b/include/grub/serial.h @@ -17,8 +17,8 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_SERIAL_MACHINE_HEADER -#define GRUB_SERIAL_MACHINE_HEADER 1 +#ifndef GRUB_SERIAL_HEADER +#define GRUB_SERIAL_HEADER 1 /* Macros. */ diff --git a/include/grub/sparc64/ieee1275/boot.h b/include/grub/sparc64/ieee1275/boot.h index 95f311ce5..bd0a7bf3c 100644 --- a/include/grub/sparc64/ieee1275/boot.h +++ b/include/grub/sparc64/ieee1275/boot.h @@ -25,7 +25,8 @@ #define BOOTDEV_REG %l6 #define PIC_REG %l7 -#define SCRATCH_PAD 0x10000 +#define SCRATCH_PAD_BOOT 0x5000 +#define SCRATCH_PAD_DISKBOOT 0x4000 #define GET_ABS(symbol, reg) \ add PIC_REG, (symbol - pic_base), reg @@ -44,15 +45,11 @@ #define GRUB_BOOT_MACHINE_BOOT_DEVPATH_END 0x80 -#define GRUB_BOOT_MACHINE_KERNEL_SECTOR 0x88 +#define GRUB_BOOT_MACHINE_KERNEL_BYTE 0x80 #define GRUB_BOOT_MACHINE_CODE_END \ (0x1fc - GRUB_BOOT_AOUT_HEADER_SIZE) -#define GRUB_BOOT_MACHINE_LIST_SIZE 12 - -#define GRUB_BOOT_MACHINE_IMAGE_ADDRESS 0x200000 - #define GRUB_BOOT_MACHINE_KERNEL_ADDR 0x4200 #endif /* ! BOOT_MACHINE_HEADER */ diff --git a/include/grub/sparc64/ieee1275/ieee1275.h b/include/grub/sparc64/ieee1275/ieee1275.h index 7626e93c1..32c77f80f 100644 --- a/include/grub/sparc64/ieee1275/ieee1275.h +++ b/include/grub/sparc64/ieee1275/ieee1275.h @@ -1,7 +1,7 @@ /* ieee1275.h - Access the Open Firmware client interface. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2004,2005,2007 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2007,2009 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 @@ -22,6 +22,7 @@ #include +#define GRUB_IEEE1275_CELL_SIZEOF 8 typedef grub_uint64_t grub_ieee1275_cell_t; /* Encoding of 'mode' argument to grub_ieee1275_map_physical() */ @@ -36,14 +37,12 @@ typedef grub_uint64_t grub_ieee1275_cell_t; #define IEEE1275_MAP_DEFAULT (IEEE1275_MAP_WRITE | IEEE1275_MAP_READ | \ IEEE1275_MAP_EXEC | IEEE1275_MAP_CACHED) -extern int EXPORT_FUNC(grub_ieee1275_map_physical) (grub_addr_t paddr, - grub_addr_t vaddr, - grub_size_t size, - grub_uint32_t mode); extern int EXPORT_FUNC(grub_ieee1275_claim_vaddr) (grub_addr_t vaddr, grub_size_t size); extern int EXPORT_FUNC(grub_ieee1275_alloc_physmem) (grub_addr_t *paddr, grub_size_t size, grub_uint32_t align); +extern grub_addr_t EXPORT_VAR (grub_ieee1275_original_stack); + #endif /* ! GRUB_IEEE1275_MACHINE_HEADER */ diff --git a/include/grub/sparc64/ieee1275/kernel.h b/include/grub/sparc64/ieee1275/kernel.h index e63e1f616..5aa50b852 100644 --- a/include/grub/sparc64/ieee1275/kernel.h +++ b/include/grub/sparc64/ieee1275/kernel.h @@ -19,25 +19,7 @@ #ifndef GRUB_KERNEL_MACHINE_HEADER #define GRUB_KERNEL_MACHINE_HEADER 1 -#define GRUB_MOD_ALIGN 0x2000 - -/* Non-zero value is only needed for PowerMacs. */ -#define GRUB_MOD_GAP 0x0 - -/* The offset of GRUB_TOTAL_MODULE_SIZE. */ -#define GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE 0x8 - -/* The offset of GRUB_KERNEL_IMAGE_SIZE. */ -#define GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE 0xc - -/* The offset of GRUB_COMPRESSED_SIZE. */ -#define GRUB_KERNEL_MACHINE_COMPRESSED_SIZE 0x10 - -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_MACHINE_PREFIX 0x14 - -/* End of the data section. */ -#define GRUB_KERNEL_MACHINE_DATA_END 0x114 +#define GRUB_KERNEL_MACHINE_STACK_SIZE 0x40000 #ifndef ASM_FILE @@ -50,10 +32,6 @@ extern grub_int32_t grub_kernel_image_size; /* The total size of module images following the kernel. */ extern grub_int32_t grub_total_module_size; -/* The prefix which points to the directory where GRUB modules and its - configuration file are located. */ -extern char grub_prefix[]; - #endif /* ! ASM_FILE */ #endif /* ! GRUB_KERNEL_MACHINE_HEADER */ diff --git a/include/grub/symbol.h b/include/grub/symbol.h index 6bf512d12..63ed19436 100644 --- a/include/grub/symbol.h +++ b/include/grub/symbol.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2006,2007,2008,2009 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 diff --git a/include/grub/term.h b/include/grub/term.h index 316d75390..143aabe1e 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2005,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2005,2007,2008,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 @@ -68,8 +68,6 @@ grub_term_color_state; #define GRUB_TERM_NO_EDIT (1 << 1) /* Set when the terminal cannot do fancy things. */ #define GRUB_TERM_DUMB (1 << 2) -/* Set when the terminal needs to be initialized. */ -#define GRUB_TERM_NEED_INIT (1 << 16) /* Bitmasks for modifier keys returned by grub_getkeystatus. */ @@ -93,10 +91,6 @@ grub_term_color_state; /* Menu-related geometrical constants. */ -/* FIXME: Ugly way to get them form terminal. */ -#define GRUB_TERM_WIDTH ((grub_getwh()&0xFF00)>>8) -#define GRUB_TERM_HEIGHT (grub_getwh()&0xFF) - /* The number of lines of "GRUB version..." at the top. */ #define GRUB_TERM_INFO_HEIGHT 1 @@ -113,37 +107,12 @@ grub_term_color_state; /* The X position of the left border. */ #define GRUB_TERM_LEFT_BORDER_X GRUB_TERM_MARGIN -/* The width of the border. */ -#define GRUB_TERM_BORDER_WIDTH (GRUB_TERM_WIDTH \ - - GRUB_TERM_MARGIN * 3 \ - - GRUB_TERM_SCROLL_WIDTH) - /* The number of lines of messages at the bottom. */ #define GRUB_TERM_MESSAGE_HEIGHT 8 -/* The height of the border. */ -#define GRUB_TERM_BORDER_HEIGHT (GRUB_TERM_HEIGHT \ - - GRUB_TERM_TOP_BORDER_Y \ - - GRUB_TERM_MESSAGE_HEIGHT) - -/* The number of entries shown at a time. */ -#define GRUB_TERM_NUM_ENTRIES (GRUB_TERM_BORDER_HEIGHT - 2) - /* The Y position of the first entry. */ #define GRUB_TERM_FIRST_ENTRY_Y (GRUB_TERM_TOP_BORDER_Y + 1) -/* The max column number of an entry. The last "-1" is for a - continuation marker. */ -#define GRUB_TERM_ENTRY_WIDTH (GRUB_TERM_BORDER_WIDTH - 2 \ - - GRUB_TERM_MARGIN * 2 - 1) - -/* The standard X position of the cursor. */ -#define GRUB_TERM_CURSOR_X (GRUB_TERM_LEFT_BORDER_X \ - + GRUB_TERM_BORDER_WIDTH \ - - GRUB_TERM_MARGIN \ - - 1) - - struct grub_term_input { /* The next terminal. */ @@ -224,80 +193,222 @@ struct grub_term_output }; typedef struct grub_term_output *grub_term_output_t; -extern struct grub_handler_class EXPORT_VAR(grub_term_input_class); -extern struct grub_handler_class EXPORT_VAR(grub_term_output_class); +extern struct grub_term_output *EXPORT_VAR(grub_term_outputs_disabled); +extern struct grub_term_input *EXPORT_VAR(grub_term_inputs_disabled); +extern struct grub_term_output *EXPORT_VAR(grub_term_outputs); +extern struct grub_term_input *EXPORT_VAR(grub_term_inputs); static inline void grub_term_register_input (const char *name __attribute__ ((unused)), grub_term_input_t term) { - grub_handler_register (&grub_term_input_class, GRUB_AS_HANDLER (term)); + if (grub_term_inputs) + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs_disabled), + GRUB_AS_LIST (term)); + else + { + /* If this is the first terminal, enable automatically. */ + if (! term->init || term->init () == GRUB_ERR_NONE) + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs), GRUB_AS_LIST (term)); + } } static inline void grub_term_register_output (const char *name __attribute__ ((unused)), grub_term_output_t term) { - grub_handler_register (&grub_term_output_class, GRUB_AS_HANDLER (term)); + if (grub_term_outputs) + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs_disabled), + GRUB_AS_LIST (term)); + else + { + /* If this is the first terminal, enable automatically. */ + if (! term->init || term->init () == GRUB_ERR_NONE) + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs), + GRUB_AS_LIST (term)); + } } static inline void grub_term_unregister_input (grub_term_input_t term) { - grub_handler_unregister (&grub_term_input_class, GRUB_AS_HANDLER (term)); + grub_list_remove (GRUB_AS_LIST_P (&grub_term_inputs), GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST_P (&grub_term_inputs_disabled), + GRUB_AS_LIST (term)); } static inline void grub_term_unregister_output (grub_term_output_t term) { - grub_handler_unregister (&grub_term_output_class, GRUB_AS_HANDLER (term)); + grub_list_remove (GRUB_AS_LIST_P (&grub_term_outputs), GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST_P (&(grub_term_outputs_disabled)), + GRUB_AS_LIST (term)); } -static inline grub_err_t -grub_term_set_current_input (grub_term_input_t term) -{ - return grub_handler_set_current (&grub_term_input_class, - GRUB_AS_HANDLER (term)); -} - -static inline grub_err_t -grub_term_set_current_output (grub_term_output_t term) -{ - return grub_handler_set_current (&grub_term_output_class, - GRUB_AS_HANDLER (term)); -} - -static inline grub_term_input_t -grub_term_get_current_input (void) -{ - return (grub_term_input_t) grub_term_input_class.cur_handler; -} - -static inline grub_term_output_t -grub_term_get_current_output (void) -{ - return (grub_term_output_t) grub_term_output_class.cur_handler; -} +#define FOR_ACTIVE_TERM_INPUTS(var) for (var = grub_term_inputs; var; var = var->next) +#define FOR_DISABLED_TERM_INPUTS(var) for (var = grub_term_inputs_disabled; var; var = var->next) +#define FOR_ACTIVE_TERM_OUTPUTS(var) for (var = grub_term_outputs; var; var = var->next) +#define FOR_DISABLED_TERM_OUTPUTS(var) for (var = grub_term_outputs_disabled; var; var = var->next) void EXPORT_FUNC(grub_putchar) (int c); -void EXPORT_FUNC(grub_putcode) (grub_uint32_t code); -grub_ssize_t EXPORT_FUNC(grub_getcharwidth) (grub_uint32_t code); +void EXPORT_FUNC(grub_putcode) (grub_uint32_t code, + struct grub_term_output *term); int EXPORT_FUNC(grub_getkey) (void); int EXPORT_FUNC(grub_checkkey) (void); int EXPORT_FUNC(grub_getkeystatus) (void); -grub_uint16_t EXPORT_FUNC(grub_getwh) (void); -grub_uint16_t EXPORT_FUNC(grub_getxy) (void); -void EXPORT_FUNC(grub_gotoxy) (grub_uint8_t x, grub_uint8_t y); void EXPORT_FUNC(grub_cls) (void); void EXPORT_FUNC(grub_setcolorstate) (grub_term_color_state state); -void EXPORT_FUNC(grub_setcolor) (grub_uint8_t normal_color, - grub_uint8_t highlight_color); -void EXPORT_FUNC(grub_getcolor) (grub_uint8_t *normal_color, - grub_uint8_t *highlight_color); -int EXPORT_FUNC(grub_setcursor) (int on); -int EXPORT_FUNC(grub_getcursor) (void); void EXPORT_FUNC(grub_refresh) (void); -void EXPORT_FUNC(grub_set_more) (int onoff); +void grub_puts_terminal (const char *str, struct grub_term_output *term); +grub_uint16_t *grub_term_save_pos (void); +void grub_term_restore_pos (grub_uint16_t *pos); + +static inline unsigned grub_term_width (struct grub_term_output *term) +{ + return ((term->getwh()&0xFF00)>>8); +} + +static inline unsigned grub_term_height (struct grub_term_output *term) +{ + return (term->getwh()&0xFF); +} + +/* The width of the border. */ +static inline unsigned +grub_term_border_width (struct grub_term_output *term) +{ + return grub_term_width (term) - GRUB_TERM_MARGIN * 3 - GRUB_TERM_SCROLL_WIDTH; +} + +/* The max column number of an entry. The last "-1" is for a + continuation marker. */ +static inline int +grub_term_entry_width (struct grub_term_output *term) +{ + return grub_term_border_width (term) - 2 - GRUB_TERM_MARGIN * 2 - 1; +} + +/* The height of the border. */ + +static inline unsigned +grub_term_border_height (struct grub_term_output *term) +{ + return grub_term_height (term) - GRUB_TERM_TOP_BORDER_Y + - GRUB_TERM_MESSAGE_HEIGHT; +} + +/* The number of entries shown at a time. */ +static inline int +grub_term_num_entries (struct grub_term_output *term) +{ + return grub_term_border_height (term) - 2; +} + +static inline int +grub_term_cursor_x (struct grub_term_output *term) +{ + return (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term) + - GRUB_TERM_MARGIN - 1); +} + +static inline grub_uint16_t +grub_term_getxy (struct grub_term_output *term) +{ + return term->getxy (); +} + +static inline void +grub_term_refresh (struct grub_term_output *term) +{ + if (term->refresh) + term->refresh (); +} + +static inline void +grub_term_gotoxy (struct grub_term_output *term, grub_uint8_t x, grub_uint8_t y) +{ + term->gotoxy (x, y); +} + +static inline void +grub_term_setcolorstate (struct grub_term_output *term, + grub_term_color_state state) +{ + if (term->setcolorstate) + term->setcolorstate (state); +} + + /* Set the normal color and the highlight color. The format of each + color is VGA's. */ +static inline void +grub_term_setcolor (struct grub_term_output *term, + grub_uint8_t normal_color, grub_uint8_t highlight_color) +{ + if (term->setcolor) + term->setcolor (normal_color, highlight_color); +} + +/* Turn on/off the cursor. */ +static inline void +grub_term_setcursor (struct grub_term_output *term, int on) +{ + if (term->setcursor) + term->setcursor (on); +} + +static inline void +grub_term_cls (struct grub_term_output *term) +{ + if (term->cls) + (term->cls) (); + else + { + grub_putcode ('\n', term); + grub_term_refresh (term); + } +} + +static inline grub_ssize_t +grub_term_getcharwidth (struct grub_term_output *term, grub_uint32_t c) +{ + if (term->getcharwidth) + return term->getcharwidth (c); + else + return 1; +} + +static inline void +grub_term_getcolor (struct grub_term_output *term, + grub_uint8_t *normal_color, grub_uint8_t *highlight_color) +{ + if (term->getcolor) + term->getcolor (normal_color, highlight_color); + else + { + *normal_color = 0x07; + *highlight_color = 0x07; + } +} + +extern void (*EXPORT_VAR (grub_newline_hook)) (void); + +struct grub_term_autoload +{ + struct grub_term_autoload *next; + char *name; + char *modname; +}; + +extern struct grub_term_autoload *grub_term_input_autoload; +extern struct grub_term_autoload *grub_term_output_autoload; + +static inline void +grub_print_spaces (struct grub_term_output *term, int number_spaces) +{ + while (--number_spaces >= 0) + grub_putcode (' ', term); +} + /* For convenience. */ #define GRUB_TERM_ASCII_CHAR(c) ((c) & 0xff) diff --git a/include/grub/terminfo.h b/include/grub/terminfo.h index 1ea741e04..e3a2c170a 100644 --- a/include/grub/terminfo.h +++ b/include/grub/terminfo.h @@ -21,15 +21,17 @@ #include #include +#include char *grub_terminfo_get_current (void); grub_err_t grub_terminfo_set_current (const char *); -void grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y); -void grub_terminfo_cls (void); -void grub_terminfo_reverse_video_on (void); -void grub_terminfo_reverse_video_off (void); -void grub_terminfo_cursor_on (void); -void grub_terminfo_cursor_off (void); +void grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y, + grub_term_output_t oterm); +void grub_terminfo_cls (grub_term_output_t oterm); +void grub_terminfo_reverse_video_on (grub_term_output_t oterm); +void grub_terminfo_reverse_video_off (grub_term_output_t oterm); +void grub_terminfo_cursor_on (grub_term_output_t oterm); +void grub_terminfo_cursor_off (grub_term_output_t oterm); #endif /* ! GRUB_TERMINFO_HEADER */ diff --git a/include/grub/test.h b/include/grub/test.h new file mode 100644 index 000000000..27591cca2 --- /dev/null +++ b/include/grub/test.h @@ -0,0 +1,85 @@ +/* + * 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 . + */ + +#ifndef GRUB_TEST_HEADER +#define GRUB_TEST_HEADER + +#include +#include +#include +#include +#include + +struct grub_test +{ + /* The next test. */ + struct grub_test *next; + + /* The test name. */ + char *name; + + /* The test main function. */ + void (*main) (void); +}; +typedef struct grub_test *grub_test_t; + +extern grub_test_t grub_test_list; + +void grub_test_register (const char *name, void (*test) (void)); +void grub_test_unregister (const char *name); + +/* Execute a test and print results. */ +int grub_test_run (grub_test_t test); + +/* Test `cond' for nonzero; log failure otherwise. */ +void grub_test_nonzero (int cond, const char *file, + const char *func, grub_uint32_t line, + const char *fmt, ...) + __attribute__ ((format (printf, 5, 6))); + +/* Macro to fill in location details and an optional error message. */ +#define grub_test_assert(cond, ...) \ + grub_test_nonzero(cond, GRUB_FILE, __FUNCTION__, __LINE__, \ + ## __VA_ARGS__, \ + "assert failed: %s", #cond) + +/* Macro to define a unit test. */ +#define GRUB_UNIT_TEST(name, funp) \ + void grub_unit_test_init (void) \ + { \ + grub_test_register (name, funp); \ + } \ + \ + void grub_unit_test_fini (void) \ + { \ + grub_test_unregister (name); \ + } + +/* Macro to define a functional test. */ +#define GRUB_FUNCTIONAL_TEST(name, funp) \ + GRUB_MOD_INIT(functional_test_##funp) \ + { \ + grub_test_register (name, funp); \ + } \ + \ + GRUB_MOD_FINI(functional_test_##funp) \ + { \ + grub_test_unregister (name); \ + } + +#endif /* ! GRUB_TEST_HEADER */ diff --git a/include/grub/time.h b/include/grub/time.h index 115fbd95e..ae2617edb 100644 --- a/include/grub/time.h +++ b/include/grub/time.h @@ -23,8 +23,10 @@ #include #include -#ifdef GRUB_MACHINE_EMU +#if defined (GRUB_MACHINE_EMU) || defined (GRUB_UTIL) #define GRUB_TICKS_PER_SECOND 100000 +/* Return the real time in ticks. */ +grub_uint32_t EXPORT_FUNC (grub_get_rtc) (void); #else #include #endif diff --git a/include/grub/x86_64/efi/kernel.h b/include/grub/trig.h similarity index 55% rename from include/grub/x86_64/efi/kernel.h rename to include/grub/trig.h index c0549f41a..2512a5f07 100644 --- a/include/grub/x86_64/efi/kernel.h +++ b/include/grub/trig.h @@ -1,6 +1,7 @@ +/* trig.h - Trigonometric function support. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2007 Free Software Foundation, Inc. + * Copyright (C) 2008 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 @@ -16,18 +17,28 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_MACHINE_KERNEL_HEADER -#define GRUB_MACHINE_KERNEL_HEADER 1 +#ifndef GRUB_TRIG_HEADER +#define GRUB_TRIG_HEADER 1 -/* The prefix which points to the directory where GRUB modules and its - configuration file are located. */ -extern char grub_prefix[]; +#define GRUB_TRIG_ANGLE_MAX 256 +#define GRUB_TRIG_ANGLE_MASK 255 +#define GRUB_TRIG_FRACTION_SCALE 16384 -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_MACHINE_PREFIX 0x8 +extern short grub_trig_sintab[]; +extern short grub_trig_costab[]; -/* End of the data section. */ -#define GRUB_KERNEL_MACHINE_DATA_END 0x50 +static __inline int +grub_sin (int x) +{ + x &= GRUB_TRIG_ANGLE_MASK; + return grub_trig_sintab[x]; +} -#endif /* ! GRUB_MACHINE_KERNEL_HEADER */ +static __inline int +grub_cos (int x) +{ + x &= GRUB_TRIG_ANGLE_MASK; + return grub_trig_costab[x]; +} +#endif /* ! GRUB_TRIG_HEADER */ diff --git a/include/grub/types.h b/include/grub/types.h index 8e2ad15ef..6e9461f1d 100644 --- a/include/grub/types.h +++ b/include/grub/types.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2005,2006,2007,2008,2009 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 @@ -22,8 +22,6 @@ #include #include -#define UNUSED __attribute__ ((unused)) - #ifdef GRUB_UTIL # define GRUB_CPU_SIZEOF_VOID_P SIZEOF_VOID_P # define GRUB_CPU_SIZEOF_LONG SIZEOF_LONG @@ -180,21 +178,6 @@ static inline grub_uint64_t grub_swap_bytes64(grub_uint64_t x) # define grub_be_to_cpu16(x) ((grub_uint16_t) (x)) # define grub_be_to_cpu32(x) ((grub_uint32_t) (x)) # define grub_be_to_cpu64(x) ((grub_uint64_t) (x)) -# ifdef GRUB_TARGET_WORDS_BIGENDIAN -# define grub_target_to_host16(x) ((grub_uint16_t) (x)) -# define grub_target_to_host32(x) ((grub_uint32_t) (x)) -# define grub_target_to_host64(x) ((grub_uint64_t) (x)) -# define grub_host_to_target16(x) ((grub_uint16_t) (x)) -# define grub_host_to_target32(x) ((grub_uint32_t) (x)) -# define grub_host_to_target64(x) ((grub_uint64_t) (x)) -# else /* ! GRUB_TARGET_WORDS_BIGENDIAN */ -# define grub_target_to_host16(x) grub_swap_bytes16(x) -# define grub_target_to_host32(x) grub_swap_bytes32(x) -# define grub_target_to_host64(x) grub_swap_bytes64(x) -# define grub_host_to_target16(x) grub_swap_bytes16(x) -# define grub_host_to_target32(x) grub_swap_bytes32(x) -# define grub_host_to_target64(x) grub_swap_bytes64(x) -# endif #else /* ! WORDS_BIGENDIAN */ # define grub_cpu_to_le16(x) ((grub_uint16_t) (x)) # define grub_cpu_to_le32(x) ((grub_uint32_t) (x)) @@ -208,21 +191,6 @@ static inline grub_uint64_t grub_swap_bytes64(grub_uint64_t x) # define grub_be_to_cpu16(x) grub_swap_bytes16(x) # define grub_be_to_cpu32(x) grub_swap_bytes32(x) # define grub_be_to_cpu64(x) grub_swap_bytes64(x) -# ifdef GRUB_TARGET_WORDS_BIGENDIAN -# define grub_target_to_host16(x) grub_swap_bytes16(x) -# define grub_target_to_host32(x) grub_swap_bytes32(x) -# define grub_target_to_host64(x) grub_swap_bytes64(x) -# define grub_host_to_target16(x) grub_swap_bytes16(x) -# define grub_host_to_target32(x) grub_swap_bytes32(x) -# define grub_host_to_target64(x) grub_swap_bytes64(x) -# else /* ! GRUB_TARGET_WORDS_BIGENDIAN */ -# define grub_target_to_host16(x) ((grub_uint16_t) (x)) -# define grub_target_to_host32(x) ((grub_uint32_t) (x)) -# define grub_target_to_host64(x) ((grub_uint64_t) (x)) -# define grub_host_to_target16(x) ((grub_uint16_t) (x)) -# define grub_host_to_target32(x) ((grub_uint32_t) (x)) -# define grub_host_to_target64(x) ((grub_uint64_t) (x)) -# endif #endif /* ! WORDS_BIGENDIAN */ #endif /* ! GRUB_TYPES_HEADER */ diff --git a/include/grub/usb.h b/include/grub/usb.h index 8dd3b6e2e..dc90e7879 100644 --- a/include/grub/usb.h +++ b/include/grub/usb.h @@ -64,9 +64,6 @@ grub_usb_err_t grub_usb_clear_halt (grub_usb_device_t dev, int endpoint); grub_usb_err_t grub_usb_set_configuration (grub_usb_device_t dev, int configuration); -grub_usb_err_t grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, - int langid, char **string); - void grub_usb_controller_dev_register (grub_usb_controller_dev_t usb); void grub_usb_controller_dev_unregister (grub_usb_controller_dev_t usb); diff --git a/include/grub/util/misc.h b/include/grub/util/misc.h index 09108547c..48dfbb868 100644 --- a/include/grub/util/misc.h +++ b/include/grub/util/misc.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2005,2006,2007,2008,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 @@ -27,26 +27,8 @@ #include #include - -#ifdef __NetBSD__ -/* NetBSD uses /boot for its boot block. */ -# define DEFAULT_DIRECTORY "/grub" -#else -# define DEFAULT_DIRECTORY "/boot/grub" -#endif - -#define DEFAULT_DEVICE_MAP DEFAULT_DIRECTORY "/device.map" - -extern char *progname; -extern int verbosity; - -void grub_util_warn (const char *fmt, ...); -void grub_util_info (const char *fmt, ...); -void grub_util_error (const char *fmt, ...) __attribute__ ((noreturn)); - -void *xmalloc (size_t size); -void *xrealloc (void *ptr, size_t size); -char *xstrdup (const char *str); +#include +#include char *grub_util_get_path (const char *dir, const char *file); size_t grub_util_get_fp_size (FILE *fp); @@ -58,20 +40,6 @@ void grub_util_write_image (const char *img, size_t size, FILE *out); void grub_util_write_image_at (const void *img, size_t size, off_t offset, FILE *out); -#ifndef HAVE_VASPRINTF - -int vasprintf (char **buf, const char *fmt, va_list ap); - -#endif - -#ifndef HAVE_ASPRINTF - -int asprintf (char **buf, const char *fmt, ...); - -#endif - -char *xasprintf (const char *fmt, ...); - #ifdef __MINGW32__ #define fseeko fseeko64 @@ -88,4 +56,8 @@ grub_int64_t grub_util_get_disk_size (char *name); char *make_system_path_relative_to_its_root (const char *path); +char *canonicalize_file_name (const char *path); + +void grub_util_init_nls (void); + #endif /* ! GRUB_UTIL_MISC_HEADER */ diff --git a/include/grub/util/ofpath.h b/include/grub/util/ofpath.h index 78f24d784..b43c523cb 100644 --- a/include/grub/util/ofpath.h +++ b/include/grub/util/ofpath.h @@ -1,6 +1,6 @@ #ifndef GRUB_OFPATH_MACHINE_UTIL_HEADER #define GRUB_OFPATH_MACHINE_UTIL_HEADER 1 -char *grub_util_devname_to_ofpath (char *devname); +char *grub_util_devname_to_ofpath (const char *devname); #endif /* ! GRUB_OFPATH_MACHINE_UTIL_HEADER */ diff --git a/include/grub/video.h b/include/grub/video.h index 4145db465..5fd7e0c47 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -34,6 +34,10 @@ struct grub_video_render_target; struct grub_video_bitmap; /* Defines used to describe video mode or rendering target. */ +/* If following is set render target contains currenly displayed image + after swapping buffers (otherwise it contains previously displayed image). + */ +#define GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP 0x00000080 #define GRUB_VIDEO_MODE_TYPE_PURE_TEXT 0x00000040 #define GRUB_VIDEO_MODE_TYPE_ALPHA 0x00000020 #define GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED 0x00000010 @@ -48,6 +52,8 @@ struct grub_video_bitmap; #define GRUB_VIDEO_MODE_TYPE_DEPTH_MASK 0x0000ff00 #define GRUB_VIDEO_MODE_TYPE_DEPTH_POS 8 +/* The basic render target representing the whole display. This always + renders to the back buffer when double-buffering is in use. */ #define GRUB_VIDEO_RENDER_TARGET_DISPLAY \ ((struct grub_video_render_target *) 0) @@ -151,6 +157,16 @@ struct grub_video_mode_info grub_uint8_t fg_alpha; }; +/* A 2D rectangle type. */ +struct grub_video_rect +{ + unsigned x; + unsigned y; + unsigned width; + unsigned height; +}; +typedef struct grub_video_rect grub_video_rect_t; + struct grub_video_palette_data { grub_uint8_t r; /* Red color value (0-255). */ @@ -159,10 +175,21 @@ struct grub_video_palette_data grub_uint8_t a; /* Reserved bits value (0-255). */ }; +typedef enum grub_video_driver_id + { + GRUB_VIDEO_DRIVER_NONE, + GRUB_VIDEO_DRIVER_VBE, + GRUB_VIDEO_DRIVER_EFI_UGA, + GRUB_VIDEO_DRIVER_EFI_GOP, + GRUB_VIDEO_DRIVER_SM712, + GRUB_VIDEO_DRIVER_VGA + } grub_video_driver_id_t; + struct grub_video_adapter { /* The video adapter name. */ const char *name; + grub_video_driver_id_t id; /* Initialize the video adapter. */ grub_err_t (*init) (void); @@ -171,7 +198,7 @@ struct grub_video_adapter grub_err_t (*fini) (void); grub_err_t (*setup) (unsigned int width, unsigned int height, - unsigned int mode_type); + unsigned int mode_type, unsigned int mode_mask); grub_err_t (*get_info) (struct grub_video_mode_info *mode_info); @@ -234,20 +261,20 @@ struct grub_video_adapter }; typedef struct grub_video_adapter *grub_video_adapter_t; -void grub_video_register (grub_video_adapter_t adapter); +void EXPORT_FUNC (grub_video_register) (grub_video_adapter_t adapter); void grub_video_unregister (grub_video_adapter_t adapter); void grub_video_iterate (int (*hook) (grub_video_adapter_t adapter)); -grub_err_t grub_video_restore (void); +grub_err_t EXPORT_FUNC (grub_video_restore) (void); -grub_err_t grub_video_get_info (struct grub_video_mode_info *mode_info); +grub_err_t EXPORT_FUNC (grub_video_get_info) (struct grub_video_mode_info *mode_info); /* Framebuffer address may change as a part of normal operation (e.g. double buffering). That's why you need to stop video subsystem to be sure that framebuffer address doesn't change. To ensure this abstraction grub_video_get_info_and_fini is the only function supplying framebuffer address. */ -grub_err_t grub_video_get_info_and_fini (struct grub_video_mode_info *mode_info, +grub_err_t EXPORT_FUNC (grub_video_get_info_and_fini) (struct grub_video_mode_info *mode_info, void **framebuffer); enum grub_video_blit_format grub_video_get_blit_format (struct grub_video_mode_info *mode_info); @@ -255,59 +282,83 @@ enum grub_video_blit_format grub_video_get_blit_format (struct grub_video_mode_i grub_err_t grub_video_set_palette (unsigned int start, unsigned int count, struct grub_video_palette_data *palette_data); -grub_err_t grub_video_get_palette (unsigned int start, unsigned int count, - struct grub_video_palette_data *palette_data); +grub_err_t EXPORT_FUNC (grub_video_get_palette) (unsigned int start, + unsigned int count, + struct grub_video_palette_data *palette_data); -grub_err_t grub_video_set_viewport (unsigned int x, unsigned int y, - unsigned int width, unsigned int height); +grub_err_t EXPORT_FUNC (grub_video_set_viewport) (unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height); -grub_err_t grub_video_get_viewport (unsigned int *x, unsigned int *y, - unsigned int *width, unsigned int *height); +grub_err_t EXPORT_FUNC (grub_video_get_viewport) (unsigned int *x, + unsigned int *y, + unsigned int *width, + unsigned int *height); -grub_video_color_t grub_video_map_color (grub_uint32_t color_name); +grub_video_color_t EXPORT_FUNC (grub_video_map_color) (grub_uint32_t color_name); -grub_video_color_t grub_video_map_rgb (grub_uint8_t red, grub_uint8_t green, - grub_uint8_t blue); +grub_video_color_t EXPORT_FUNC (grub_video_map_rgb) (grub_uint8_t red, + grub_uint8_t green, + grub_uint8_t blue); -grub_video_color_t grub_video_map_rgba (grub_uint8_t red, grub_uint8_t green, - grub_uint8_t blue, grub_uint8_t alpha); +grub_video_color_t EXPORT_FUNC (grub_video_map_rgba) (grub_uint8_t red, + grub_uint8_t green, + grub_uint8_t blue, + grub_uint8_t alpha); -grub_err_t grub_video_unmap_color (grub_video_color_t color, - grub_uint8_t *red, grub_uint8_t *green, - grub_uint8_t *blue, grub_uint8_t *alpha); +grub_err_t EXPORT_FUNC (grub_video_unmap_color) (grub_video_color_t color, + grub_uint8_t *red, + grub_uint8_t *green, + grub_uint8_t *blue, + grub_uint8_t *alpha); -grub_err_t grub_video_fill_rect (grub_video_color_t color, int x, int y, - unsigned int width, unsigned int height); +grub_err_t EXPORT_FUNC (grub_video_fill_rect) (grub_video_color_t color, + int x, int y, + unsigned int width, + unsigned int height); -grub_err_t grub_video_blit_bitmap (struct grub_video_bitmap *bitmap, - enum grub_video_blit_operators oper, - int x, int y, int offset_x, int offset_y, - unsigned int width, unsigned int height); +grub_err_t EXPORT_FUNC (grub_video_blit_bitmap) (struct grub_video_bitmap *bitmap, + enum grub_video_blit_operators oper, + int x, int y, + int offset_x, int offset_y, + unsigned int width, + unsigned int height); -grub_err_t grub_video_blit_render_target (struct grub_video_render_target *source, - enum grub_video_blit_operators oper, - int x, int y, - int offset_x, int offset_y, - unsigned int width, - unsigned int height); +grub_err_t EXPORT_FUNC (grub_video_blit_render_target) (struct grub_video_render_target *source, + enum grub_video_blit_operators oper, + int x, int y, + int offset_x, + int offset_y, + unsigned int width, + unsigned int height); grub_err_t grub_video_scroll (grub_video_color_t color, int dx, int dy); -grub_err_t grub_video_swap_buffers (void); +grub_err_t EXPORT_FUNC (grub_video_swap_buffers) (void); -grub_err_t grub_video_create_render_target (struct grub_video_render_target **result, - unsigned int width, - unsigned int height, - unsigned int mode_type); +grub_err_t EXPORT_FUNC (grub_video_create_render_target) (struct grub_video_render_target **result, + unsigned int width, + unsigned int height, + unsigned int mode_type); -grub_err_t grub_video_delete_render_target (struct grub_video_render_target *target); +grub_err_t EXPORT_FUNC (grub_video_delete_render_target) (struct grub_video_render_target *target); -grub_err_t grub_video_set_active_render_target (struct grub_video_render_target *target); +grub_err_t EXPORT_FUNC (grub_video_set_active_render_target) (struct grub_video_render_target *target); grub_err_t grub_video_get_active_render_target (struct grub_video_render_target **target); -grub_err_t grub_video_set_mode (const char *modestring, - int NESTED_FUNC_ATTR (*hook) (grub_video_adapter_t p, - struct grub_video_mode_info *mode_info)); +grub_err_t EXPORT_FUNC (grub_video_set_mode) (const char *modestring, + unsigned int modemask, + unsigned int modevalue); + +static inline int +grub_video_check_mode_flag (unsigned int flags, unsigned int mask, + unsigned int flag, int def) +{ + return (flag & mask) ? !! (flags & flag) : def; +} + +grub_video_driver_id_t EXPORT_FUNC (grub_video_get_driver_id) (void); #endif /* ! GRUB_VIDEO_HEADER */ diff --git a/include/grub/video_fb.h b/include/grub/video_fb.h index 17debd69f..3046a597b 100644 --- a/include/grub/video_fb.h +++ b/include/grub/video_fb.h @@ -115,4 +115,15 @@ grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **targ grub_err_t grub_video_fb_set_active_render_target (struct grub_video_fbrender_target *target); +typedef grub_err_t +(*grub_video_fb_doublebuf_update_screen_t) (struct grub_video_fbrender_target *front, + struct grub_video_fbrender_target *back); + +grub_err_t +grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **front, + struct grub_video_fbrender_target **back, + grub_video_fb_doublebuf_update_screen_t *update_screen, + struct grub_video_mode_info mode_info, + void *framebuf); + #endif /* ! GRUB_VIDEO_FB_HEADER */ diff --git a/include/grub/x86_64/at_keyboard.h b/include/grub/x86_64/at_keyboard.h new file mode 100644 index 000000000..c632aa85c --- /dev/null +++ b/include/grub/x86_64/at_keyboard.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/x86_64/efi/boot.h b/include/grub/x86_64/efi/boot.h new file mode 100644 index 000000000..e69de29bb diff --git a/include/grub/x86_64/efi/serial.h b/include/grub/x86_64/efi/serial.h new file mode 100644 index 000000000..2d8563414 --- /dev/null +++ b/include/grub/x86_64/efi/serial.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/x86_64/kernel.h b/include/grub/x86_64/kernel.h deleted file mode 100644 index 25ac57e40..000000000 --- a/include/grub/x86_64/kernel.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/grub/x86_64/multiboot.h b/include/grub/x86_64/multiboot.h new file mode 100644 index 000000000..957c7a5ad --- /dev/null +++ b/include/grub/x86_64/multiboot.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/x86_64/relocator.h b/include/grub/x86_64/relocator.h new file mode 100644 index 000000000..247e7a18b --- /dev/null +++ b/include/grub/x86_64/relocator.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/xnu.h b/include/grub/xnu.h index c3902e670..6089aad34 100644 --- a/include/grub/xnu.h +++ b/include/grub/xnu.h @@ -76,6 +76,8 @@ struct grub_xnu_extheader grub_uint32_t infoplistsize; grub_uint32_t binaryaddr; grub_uint32_t binarysize; + grub_uint32_t nameaddr; + grub_uint32_t namesize; } __attribute__ ((packed)); struct grub_xnu_devtree_key *grub_xnu_create_key (struct grub_xnu_devtree_key **parent, @@ -92,6 +94,7 @@ struct grub_xnu_devtree_key *grub_xnu_create_value (struct grub_xnu_devtree_key void grub_xnu_lock (void); void grub_xnu_unlock (void); grub_err_t grub_xnu_resume (char *imagename); +grub_err_t grub_xnu_boot_resume (void); struct grub_xnu_devtree_key *grub_xnu_find_key (struct grub_xnu_devtree_key *parent, char *name); grub_err_t grub_xnu_align_heap (int align); @@ -100,8 +103,13 @@ grub_err_t grub_xnu_scan_dir_for_kexts (char *dirname, char *osbundlerequired, grub_err_t grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, int maxrecursion); void *grub_xnu_heap_malloc (int size); +grub_err_t grub_xnu_fill_devicetree (void); extern grub_uint32_t grub_xnu_heap_real_start; extern grub_size_t grub_xnu_heap_size; -extern char *grub_xnu_heap_start; +extern void *grub_xnu_heap_start; extern struct grub_video_bitmap *grub_xnu_bitmap; +typedef enum {GRUB_XNU_BITMAP_CENTER, GRUB_XNU_BITMAP_STRETCH} + grub_xnu_bitmap_mode_t; +extern grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode; +extern int grub_xnu_is_64bit; #endif diff --git a/include/multiboot.h b/include/multiboot.h index 9ce34f437..fda863e85 100644 --- a/include/multiboot.h +++ b/include/multiboot.h @@ -1,6 +1,5 @@ -/* - * multiboot.h - Multiboot header file. - * Copyright (C) 2003,2007,2008,2009 Free Software Foundation, Inc. +/* multiboot.h - Multiboot header file. */ +/* Copyright (C) 1999,2003,2007,2008,2009 Free Software Foundation, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -24,175 +23,236 @@ #define MULTIBOOT_HEADER 1 /* How many bytes from the start of the file we search for the header. */ -#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_HEADER_ALIGN 4 /* The magic field should contain this. */ -#define MULTIBOOT_MAGIC 0x1BADB002 +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 /* This should be in %eax. */ -#define MULTIBOOT_MAGIC2 0x2BADB002 - -/* The bits in the required part of flags field we don't support. */ -#define MULTIBOOT_UNSUPPORTED 0x0000fffc +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 /* Alignment of multiboot modules. */ -#define MULTIBOOT_MOD_ALIGN 0x00001000 +#define MULTIBOOT_MOD_ALIGN 0x00001000 /* Alignment of the multiboot info structure. */ -#define MULTIBOOT_INFO_ALIGN 0x00000004 +#define MULTIBOOT_INFO_ALIGN 0x00000004 -/* - * Flags set in the 'flags' member of the multiboot header. - */ +/* Flags set in the 'flags' member of the multiboot header. */ /* Align all boot modules on i386 page (4KB) boundaries. */ -#define MULTIBOOT_PAGE_ALIGN 0x00000001 +#define MULTIBOOT_PAGE_ALIGN 0x00000001 /* Must pass memory information to OS. */ -#define MULTIBOOT_MEMORY_INFO 0x00000002 +#define MULTIBOOT_MEMORY_INFO 0x00000002 /* Must pass video information to OS. */ -#define MULTIBOOT_VIDEO_MODE 0x00000004 +#define MULTIBOOT_VIDEO_MODE 0x00000004 /* This flag indicates the use of the address fields in the header. */ -#define MULTIBOOT_AOUT_KLUDGE 0x00010000 +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 -/* - * Flags to be set in the 'flags' member of the multiboot info structure. - */ +/* Flags to be set in the 'flags' member of the multiboot info structure. */ /* is there basic lower/upper memory information? */ -#define MULTIBOOT_INFO_MEMORY 0x00000001 +#define MULTIBOOT_INFO_MEMORY 0x00000001 /* is there a boot device set? */ -#define MULTIBOOT_INFO_BOOTDEV 0x00000002 +#define MULTIBOOT_INFO_BOOTDEV 0x00000002 /* is the command-line defined? */ -#define MULTIBOOT_INFO_CMDLINE 0x00000004 +#define MULTIBOOT_INFO_CMDLINE 0x00000004 /* are there modules to do something with? */ -#define MULTIBOOT_INFO_MODS 0x00000008 +#define MULTIBOOT_INFO_MODS 0x00000008 /* These next two are mutually exclusive */ /* is there a symbol table loaded? */ #define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 /* is there an ELF section header table? */ -#define MULTIBOOT_INFO_ELF_SHDR 0x00000020 +#define MULTIBOOT_INFO_ELF_SHDR 0X00000020 /* is there a full memory map? */ -#define MULTIBOOT_INFO_MEM_MAP 0x00000040 +#define MULTIBOOT_INFO_MEM_MAP 0x00000040 /* Is there drive info? */ #define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 /* Is there a config table? */ -#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 +#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 /* Is there a boot loader name? */ -#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 +#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 /* Is there a APM table? */ #define MULTIBOOT_INFO_APM_TABLE 0x00000400 /* Is there video information? */ -#define MULTIBOOT_INFO_VIDEO_INFO 0x00000800 +#define MULTIBOOT_INFO_VBE_INFO 0x00000800 +#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 #ifndef ASM_FILE -#include +typedef unsigned char multiboot_uint8_t; +typedef unsigned short multiboot_uint16_t; +typedef unsigned int multiboot_uint32_t; +typedef unsigned long long multiboot_uint64_t; struct multiboot_header { /* Must be MULTIBOOT_MAGIC - see above. */ - grub_uint32_t magic; + multiboot_uint32_t magic; /* Feature flags. */ - grub_uint32_t flags; + multiboot_uint32_t flags; /* The above fields plus this one must equal 0 mod 2^32. */ - grub_uint32_t checksum; + multiboot_uint32_t checksum; /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ - grub_uint32_t header_addr; - grub_uint32_t load_addr; - grub_uint32_t load_end_addr; - grub_uint32_t bss_end_addr; - grub_uint32_t entry_addr; + multiboot_uint32_t header_addr; + multiboot_uint32_t load_addr; + multiboot_uint32_t load_end_addr; + multiboot_uint32_t bss_end_addr; + multiboot_uint32_t entry_addr; /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ - grub_uint32_t mode_type; - grub_uint32_t width; - grub_uint32_t height; - grub_uint32_t depth; + multiboot_uint32_t mode_type; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; }; +/* The symbol table for a.out. */ +struct multiboot_aout_symbol_table +{ + multiboot_uint32_t tabsize; + multiboot_uint32_t strsize; + multiboot_uint32_t addr; + multiboot_uint32_t reserved; +}; +typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; + +/* The section header table for ELF. */ +struct multiboot_elf_section_header_table +{ + multiboot_uint32_t num; + multiboot_uint32_t size; + multiboot_uint32_t addr; + multiboot_uint32_t shndx; +}; +typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; + struct multiboot_info { /* Multiboot info version number */ - grub_uint32_t flags; + multiboot_uint32_t flags; /* Available memory from BIOS */ - grub_uint32_t mem_lower; - grub_uint32_t mem_upper; + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; /* "root" partition */ - grub_uint32_t boot_device; + multiboot_uint32_t boot_device; /* Kernel command line */ - grub_uint32_t cmdline; + multiboot_uint32_t cmdline; /* Boot-Module list */ - grub_uint32_t mods_count; - grub_uint32_t mods_addr; + multiboot_uint32_t mods_count; + multiboot_uint32_t mods_addr; - grub_uint32_t syms[4]; + union + { + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } u; /* Memory Mapping buffer */ - grub_uint32_t mmap_length; - grub_uint32_t mmap_addr; + multiboot_uint32_t mmap_length; + multiboot_uint32_t mmap_addr; /* Drive Info buffer */ - grub_uint32_t drives_length; - grub_uint32_t drives_addr; + multiboot_uint32_t drives_length; + multiboot_uint32_t drives_addr; /* ROM configuration table */ - grub_uint32_t config_table; + multiboot_uint32_t config_table; /* Boot Loader Name */ - grub_uint32_t boot_loader_name; + multiboot_uint32_t boot_loader_name; /* APM table */ - grub_uint32_t apm_table; + multiboot_uint32_t apm_table; /* Video */ - grub_uint32_t vbe_control_info; - grub_uint32_t vbe_mode_info; - grub_uint16_t vbe_mode; - grub_uint16_t vbe_interface_seg; - grub_uint16_t vbe_interface_off; - grub_uint16_t vbe_interface_len; + multiboot_uint32_t vbe_control_info; + multiboot_uint32_t vbe_mode_info; + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + union + { + struct + { + multiboot_uint32_t framebuffer_palette_addr; + multiboot_uint16_t framebuffer_palette_num_colors; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; +typedef struct multiboot_info multiboot_info_t; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; }; struct multiboot_mmap_entry { - grub_uint32_t size; - grub_uint64_t addr; - grub_uint64_t len; + multiboot_uint32_t size; + multiboot_uint64_t addr; + multiboot_uint64_t len; #define MULTIBOOT_MEMORY_AVAILABLE 1 #define MULTIBOOT_MEMORY_RESERVED 2 - grub_uint32_t type; +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 + multiboot_uint32_t type; } __attribute__((packed)); +typedef struct multiboot_mmap_entry multiboot_memory_map_t; struct multiboot_mod_list { /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ - grub_uint32_t mod_start; - grub_uint32_t mod_end; + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; /* Module command line */ - grub_uint32_t cmdline; + multiboot_uint32_t cmdline; /* padding to take it to 16 bytes (must be zero) */ - grub_uint32_t pad; + multiboot_uint32_t pad; }; +typedef struct multiboot_mod_list multiboot_module_t; #endif /* ! ASM_FILE */ diff --git a/include/multiboot2.h b/include/multiboot2.h index e55af8392..275debe75 100644 --- a/include/multiboot2.h +++ b/include/multiboot2.h @@ -1,110 +1,314 @@ -/* multiboot2.h - multiboot 2 header file. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007 Free Software Foundation, Inc. +/* multiboot2.h - Multiboot 2 header file. */ +/* Copyright (C) 1999,2003,2007,2008,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. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY + * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef MULTIBOOT2_HEADER -#define MULTIBOOT2_HEADER 1 +#ifndef MULTIBOOT_HEADER +#define MULTIBOOT_HEADER 1 /* How many bytes from the start of the file we search for the header. */ -#define MULTIBOOT2_HEADER_SEARCH 8192 +#define MULTIBOOT_SEARCH 32768 +#define MULTIBOOT_HEADER_ALIGN 8 /* The magic field should contain this. */ -#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 +#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 -/* Passed from the bootloader to the kernel. */ -#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289 +/* This should be in %eax. */ +#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289 /* Alignment of multiboot modules. */ -#define MULTIBOOT2_MOD_ALIGN 0x00001000 +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT_INFO_ALIGN 0x00000008 + +/* Flags set in the 'flags' member of the multiboot header. */ + +#define MULTIBOOT_TAG_ALIGN 8 +#define MULTIBOOT_TAG_TYPE_END 0 +#define MULTIBOOT_TAG_TYPE_CMDLINE 1 +#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 +#define MULTIBOOT_TAG_TYPE_MODULE 3 +#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 +#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 +#define MULTIBOOT_TAG_TYPE_MMAP 6 +#define MULTIBOOT_TAG_TYPE_VBE 7 +#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 +#define MULTIBOOT_TAG_TYPE_APM 10 + +#define MULTIBOOT_HEADER_TAG_END 0 +#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 +#define MULTIBOOT_HEADER_TAG_ADDRESS 2 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3 +#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4 +#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5 +#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6 + +#define MULTIBOOT_ARCHITECTURE_I386 0 +#define MULTIBOOT_ARCHITECTURE_MIPS32 4 +#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 + +#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 +#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2 #ifndef ASM_FILE -#ifndef __WORDSIZE -#include -#endif +typedef unsigned char multiboot_uint8_t; +typedef unsigned short multiboot_uint16_t; +typedef unsigned int multiboot_uint32_t; +typedef unsigned long long multiboot_uint64_t; -/* XXX not portable? */ -#if __WORDSIZE == 64 -typedef uint64_t multiboot2_word; -#else -typedef uint32_t multiboot2_word; -#endif - -struct multiboot2_header +struct multiboot_header { - uint32_t magic; - uint32_t flags; + /* Must be MULTIBOOT_MAGIC - see above. */ + multiboot_uint32_t magic; + + /* ISA */ + multiboot_uint32_t architecture; + + /* Total header length. */ + multiboot_uint32_t header_length; + + /* The above fields plus this one must equal 0 mod 2^32. */ + multiboot_uint32_t checksum; }; -struct multiboot2_tag_header +struct multiboot_header_tag { - uint32_t key; - uint32_t len; + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; }; -#define MULTIBOOT2_TAG_RESERVED1 0 -#define MULTIBOOT2_TAG_RESERVED2 (~0) - -#define MULTIBOOT2_TAG_START 1 -struct multiboot2_tag_start +struct multiboot_header_tag_information_request { - struct multiboot2_tag_header header; - multiboot2_word size; /* Total size of all multiboot tags. */ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t requests[0]; }; -#define MULTIBOOT2_TAG_NAME 2 -struct multiboot2_tag_name +struct multiboot_header_tag_address { - struct multiboot2_tag_header header; - char name[1]; + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t header_addr; + multiboot_uint32_t load_addr; + multiboot_uint32_t load_end_addr; + multiboot_uint32_t bss_end_addr; }; -#define MULTIBOOT2_TAG_MODULE 3 -struct multiboot2_tag_module +struct multiboot_header_tag_entry_address { - struct multiboot2_tag_header header; - multiboot2_word addr; - multiboot2_word size; - char type[36]; - char cmdline[1]; + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t entry_addr; }; -#define MULTIBOOT2_TAG_MEMORY 4 -struct multiboot2_tag_memory +struct multiboot_header_tag_console_flags { - struct multiboot2_tag_header header; - multiboot2_word addr; - multiboot2_word size; - multiboot2_word type; + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t console_flags; }; -#define MULTIBOOT2_TAG_UNUSED 5 -struct multiboot2_tag_unused +struct multiboot_header_tag_framebuffer { - struct multiboot2_tag_header header; + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; }; -#define MULTIBOOT2_TAG_END 0xffff -struct multiboot2_tag_end +struct multiboot_header_tag_module_align { - struct multiboot2_tag_header header; + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; +}; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; +}; + +struct multiboot_mmap_entry +{ + multiboot_uint64_t addr; + multiboot_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 + multiboot_uint32_t type; + multiboot_uint32_t zero; +} __attribute__((packed)); +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_tag +{ + multiboot_uint32_t type; + multiboot_uint32_t size; +}; + +struct multiboot_tag_string +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + char string[0]; +}; + +struct multiboot_tag_module +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; + char cmdline[0]; +}; + +struct multiboot_tag_basic_meminfo +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; +}; + +struct multiboot_tag_bootdev +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t biosdev; + multiboot_uint32_t slice; + multiboot_uint32_t part; +}; + +struct multiboot_tag_mmap +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t entry_size; + multiboot_uint32_t entry_version; + struct multiboot_mmap_entry entries[0]; +}; + +struct multiboot_vbe_info_block +{ + multiboot_uint8_t external_specification[512]; +}; + +struct multiboot_vbe_mode_info_block +{ + multiboot_uint8_t external_specification[256]; +}; + +struct multiboot_tag_vbe +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + struct multiboot_vbe_info_block vbe_control_info; + struct multiboot_vbe_mode_info_block vbe_mode_info; +}; + +struct multiboot_tag_framebuffer_common +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + multiboot_uint16_t reserved; +}; + +struct multiboot_tag_framebuffer +{ + struct multiboot_tag_framebuffer_common common; + + union + { + struct + { + multiboot_uint16_t framebuffer_palette_num_colors; + struct multiboot_color framebuffer_palette[0]; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; + +struct multiboot_tag_elf_sections +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t num; + multiboot_uint32_t entsize; + multiboot_uint32_t shndx; + char sections[0]; +}; + +struct multiboot_tag_apm +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint16_t version; + multiboot_uint16_t cseg; + multiboot_uint32_t offset; + multiboot_uint16_t cseg_16; + multiboot_uint16_t dseg; + multiboot_uint16_t flags; + multiboot_uint16_t cseg_len; + multiboot_uint16_t cseg_16_len; + multiboot_uint16_t dseg_len; }; #endif /* ! ASM_FILE */ -#endif /* ! MULTIBOOT2_HEADER */ +#endif /* ! MULTIBOOT_HEADER */ diff --git a/io/gzio.c b/io/gzio.c index a38bfb372..9bf609105 100644 --- a/io/gzio.c +++ b/io/gzio.c @@ -1,7 +1,7 @@ /* gzio.c - decompression support for gzip */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2005,2006,2007 Free Software Foundation, Inc. + * Copyright (C) 1999,2005,2006,2007,2009 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 @@ -1121,14 +1121,13 @@ grub_gzio_open (grub_file_t io, int transparent) if (! file) return 0; - gzio = grub_malloc (sizeof (*gzio)); + gzio = grub_zalloc (sizeof (*gzio)); if (! gzio) { grub_free (file); return 0; } - grub_memset (gzio, 0, sizeof (*gzio)); gzio->file = io; file->device = io->device; diff --git a/kern/command.c b/kern/command.c index 9b3c92b9b..477240d57 100644 --- a/kern/command.c +++ b/kern/command.c @@ -37,7 +37,7 @@ grub_register_command_prio (const char *name, cmd->name = name; cmd->func = func; - cmd->summary = (summary) ? summary : name; + cmd->summary = (summary) ? summary : ""; cmd->description = description; cmd->flags = GRUB_COMMAND_FLAG_BOTH; diff --git a/kern/corecmd.c b/kern/corecmd.c index 03944f2df..9af706e94 100644 --- a/kern/corecmd.c +++ b/kern/corecmd.c @@ -26,6 +26,7 @@ #include #include #include +#include /* set ENVVAR=VALUE */ static grub_err_t @@ -73,18 +74,6 @@ grub_core_cmd_unset (struct grub_command *cmd __attribute__ ((unused)), return 0; } -static grub_err_t -grub_core_cmd_export (struct grub_command *cmd __attribute__ ((unused)), - int argc, char **args) -{ - if (argc < 1) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "no environment variable specified"); - - grub_env_export (args[0]); - return 0; -} - /* insmod MODULE */ static grub_err_t grub_core_cmd_insmod (struct grub_command *cmd __attribute__ ((unused)), @@ -190,13 +179,13 @@ void grub_register_core_commands (void) { grub_register_command ("set", grub_core_cmd_set, - "set [ENVVAR=VALUE]", "set an environment variable"); + N_("[ENVVAR=VALUE]"), + N_("Set an environment variable.")); grub_register_command ("unset", grub_core_cmd_unset, - "unset ENVVAR", "remove an environment variable"); - grub_register_command ("export", grub_core_cmd_export, - "export ENVVAR", "Export a variable."); + N_("ENVVAR"), + N_("Remove an environment variable.")); grub_register_command ("ls", grub_core_cmd_ls, - "ls [ARG]", "list devices or files"); + N_("[ARG]"), N_("List devices or files.")); grub_register_command ("insmod", grub_core_cmd_insmod, - "insmod MODULE", "insert a module"); + N_("MODULE"), N_("Insert a module.")); } diff --git a/kern/device.c b/kern/device.c index 9f219949b..4273fedfe 100644 --- a/kern/device.c +++ b/kern/device.c @@ -1,7 +1,7 @@ /* device.c - device manager */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2005,2007,2008,2009 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 @@ -86,7 +86,7 @@ grub_device_iterate (int (*hook) (const char *name)) struct part_ent { struct part_ent *next; - char name[0]; + char *name; } *ents; int iterate_disk (const char *disk_name) @@ -98,7 +98,10 @@ grub_device_iterate (int (*hook) (const char *name)) dev = grub_device_open (disk_name); if (! dev) - return 0; + { + grub_errno = GRUB_ERR_NONE; + return 0; + } if (dev->disk && dev->disk->has_partitions) { @@ -118,6 +121,7 @@ grub_device_iterate (int (*hook) (const char *name)) if (!ret) ret = hook (p->name); + grub_free (p->name); grub_free (p); p = next; } @@ -138,15 +142,20 @@ grub_device_iterate (int (*hook) (const char *name)) if (! partition_name) return 1; - p = grub_malloc (sizeof (p->next) + grub_strlen (disk->name) + 1 + - grub_strlen (partition_name) + 1); + p = grub_malloc (sizeof (*p)); if (!p) { grub_free (partition_name); return 1; } - grub_sprintf (p->name, "%s,%s", disk->name, partition_name); + p->name = grub_xasprintf ("%s,%s", disk->name, partition_name); + if (!p->name) + { + grub_free (partition_name); + grub_free (p); + return 1; + } grub_free (partition_name); p->next = ents; diff --git a/kern/disk.c b/kern/disk.c index e463626fb..ccd5f200f 100644 --- a/kern/disk.c +++ b/kern/disk.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2004,2006,2007,2008,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 @@ -330,6 +330,7 @@ grub_disk_open (const char *name) void grub_disk_close (grub_disk_t disk) { + grub_partition_t part; grub_dprintf ("disk", "Closing `%s'.\n", disk->name); if (disk->dev && disk->dev->close) @@ -338,7 +339,12 @@ grub_disk_close (grub_disk_t disk) /* Reset the timer. */ grub_last_time = grub_get_time_ms (); - grub_free (disk->partition); + while (disk->partition) + { + part = disk->partition->parent; + grub_free (disk->partition); + disk->partition = part; + } grub_free ((void *) disk->name); grub_free (disk); } @@ -349,18 +355,19 @@ grub_disk_close (grub_disk_t disk) - Verify that the range is inside the partition. */ static grub_err_t grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector, - grub_off_t *offset, grub_size_t size) + grub_off_t *offset, grub_size_t size) { + grub_partition_t part; *sector += *offset >> GRUB_DISK_SECTOR_BITS; *offset &= GRUB_DISK_SECTOR_SIZE - 1; - if (disk->partition) + for (part = disk->partition; part; part = part->parent) { grub_disk_addr_t start; grub_uint64_t len; - start = grub_partition_get_start (disk->partition); - len = grub_partition_get_len (disk->partition); + start = part->start; + len = part->len; if (*sector >= len || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1) @@ -386,8 +393,6 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, char *tmp_buf; unsigned real_offset; - grub_dprintf ("disk", "Reading `%s'...\n", disk->name); - /* First of all, check if the region is within the disk. */ if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE) { @@ -432,8 +437,9 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, else { /* Otherwise read data from the disk actually. */ - if ((disk->dev->read) (disk, start_sector, - GRUB_DISK_CACHE_SIZE, tmp_buf) + if (start_sector + GRUB_DISK_CACHE_SIZE > disk->total_sectors + || (disk->dev->read) (disk, start_sector, + GRUB_DISK_CACHE_SIZE, tmp_buf) != GRUB_ERR_NONE) { /* Uggh... Failed. Instead, just read necessary data. */ @@ -442,7 +448,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, grub_errno = GRUB_ERR_NONE; - num = ((size + GRUB_DISK_SECTOR_SIZE - 1) + num = ((size + real_offset + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); p = grub_realloc (tmp_buf, num << GRUB_DISK_SECTOR_BITS); @@ -465,12 +471,14 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, if (disk->read_hook) while (size) { + grub_size_t to_read = (size > GRUB_DISK_SECTOR_SIZE) ? GRUB_DISK_SECTOR_SIZE : size; (disk->read_hook) (sector, real_offset, - ((size > GRUB_DISK_SECTOR_SIZE) - ? GRUB_DISK_SECTOR_SIZE - : size)); + to_read); + if (grub_errno != GRUB_ERR_NONE) + goto finish; + sector++; - size -= GRUB_DISK_SECTOR_SIZE - real_offset; + size -= to_read - real_offset; real_offset = 0; } diff --git a/kern/dl.c b/kern/dl.c index 20ab1c5c2..c6a038cfa 100644 --- a/kern/dl.c +++ b/kern/dl.c @@ -341,24 +341,23 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) switch (type) { case STT_NOTYPE: + case STT_OBJECT: /* Resolve a global symbol. */ if (sym->st_name != 0 && sym->st_shndx == 0) { sym->st_value = (Elf_Addr) grub_dl_resolve_symbol (name); if (! sym->st_value) return grub_error (GRUB_ERR_BAD_MODULE, - "the symbol `%s' not found", name); + "symbol not found: `%s'", name); } else - sym->st_value = 0; - break; - - case STT_OBJECT: - sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod, - sym->st_shndx); - if (bind != STB_LOCAL) - if (grub_dl_register_symbol (name, (void *) sym->st_value, mod)) - return grub_errno; + { + sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod, + sym->st_shndx); + if (bind != STB_LOCAL) + if (grub_dl_register_symbol (name, (void *) sym->st_value, mod)) + return grub_errno; + } break; case STT_FUNC: @@ -470,12 +469,14 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e) return GRUB_ERR_NONE; } -#ifndef GRUB_UTIL int grub_dl_ref (grub_dl_t mod) { grub_dl_dep_t dep; + if (!mod) + return 0; + for (dep = mod->dep; dep; dep = dep->next) grub_dl_ref (dep->mod); @@ -487,12 +488,14 @@ grub_dl_unref (grub_dl_t mod) { grub_dl_dep_t dep; + if (!mod) + return 0; + for (dep = mod->dep; dep; dep = dep->next) grub_dl_unref (dep->mod); return --mod->ref_count; } -#endif static void grub_dl_flush_cache (grub_dl_t mod) @@ -628,12 +631,10 @@ grub_dl_load (const char *name) return 0; } - filename = (char *) grub_malloc (grub_strlen (grub_dl_dir) + 1 - + grub_strlen (name) + 4 + 1); + filename = grub_xasprintf ("%s/%s.mod", grub_dl_dir, name); if (! filename) return 0; - grub_sprintf (filename, "%s/%s.mod", grub_dl_dir, name); mod = grub_dl_load_file (filename); grub_free (filename); diff --git a/kern/efi/efi.c b/kern/efi/efi.c index 8e09a90c0..d8b225535 100644 --- a/kern/efi/efi.c +++ b/kern/efi/efi.c @@ -1,7 +1,7 @@ /* efi.c - generic EFI support */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,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 @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -161,6 +162,8 @@ grub_exit (void) for (;;) ; } +/* On i386, a firmware-independant grub_reboot() is provided by realmode.S. */ +#ifndef __i386__ void grub_reboot (void) { @@ -168,6 +171,7 @@ grub_reboot (void) efi_call_4 (grub_efi_system_table->runtime_services->reset_system, GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); } +#endif void grub_halt (void) @@ -188,6 +192,25 @@ grub_efi_exit_boot_services (grub_efi_uintn_t map_key) return status == GRUB_EFI_SUCCESS; } +grub_err_t +grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map) +{ + grub_efi_runtime_services_t *r; + grub_efi_status_t status; + + r = grub_efi_system_table->runtime_services; + status = efi_call_4 (r->set_virtual_address_map, memory_map_size, + descriptor_size, descriptor_version, virtual_map); + + if (status == GRUB_EFI_SUCCESS) + return GRUB_ERR_NONE; + + return grub_error (GRUB_ERR_IO, "set_virtual_address_map failed"); +} + grub_uint32_t grub_get_rtc (void) { diff --git a/kern/efi/init.c b/kern/efi/init.c index f9ba03852..b79084a6a 100644 --- a/kern/efi/init.c +++ b/kern/efi/init.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include void grub_efi_init (void) @@ -42,46 +42,63 @@ grub_efi_init (void) void grub_efi_set_prefix (void) { - grub_efi_loaded_image_t *image; + grub_efi_loaded_image_t *image = NULL; + char *device = NULL; + char *path = NULL; - image = grub_efi_get_loaded_image (grub_efi_image_handle); - if (image) + { + char *pptr = NULL; + if (grub_prefix[0] == '(') + { + pptr = grub_strrchr (grub_prefix, ')'); + if (pptr) + { + device = grub_strndup (grub_prefix + 1, pptr - grub_prefix - 1); + pptr++; + } + } + if (!pptr) + pptr = grub_prefix; + if (pptr[0]) + path = grub_strdup (pptr); + } + + if (!device || !path) + image = grub_efi_get_loaded_image (grub_efi_image_handle); + if (image && !device) + device = grub_efidisk_get_device_name (image->device_handle); + + if (image && !path) { - char *device; - char *file; + char *p; - device = grub_efidisk_get_device_name (image->device_handle); - file = grub_efi_get_filename (image->file_path); + path = grub_efi_get_filename (image->file_path); - if (device && file) - { - char *p; - char *prefix; - - /* Get the directory. */ - p = grub_strrchr (file, '/'); - if (p) - *p = '\0'; - - prefix = grub_malloc (1 + grub_strlen (device) + 1 - + grub_strlen (file) + 1); - if (prefix) - { - grub_sprintf (prefix, "(%s)%s", device, file); - grub_env_set ("prefix", prefix); - grub_free (prefix); - } - } - - grub_free (device); - grub_free (file); + /* Get the directory. */ + p = grub_strrchr (path, '/'); + if (p) + *p = '\0'; } + + if (device && path) + { + char *prefix; + + prefix = grub_xasprintf ("(%s)%s", device, path); + if (prefix) + { + grub_env_set ("prefix", prefix); + grub_free (prefix); + } + } + + grub_free (device); + grub_free (path); } void grub_efi_fini (void) { grub_efidisk_fini (); - grub_efi_mm_fini (); grub_console_fini (); } diff --git a/kern/efi/mm.c b/kern/efi/mm.c index e1fca81f3..ceb8fc9ba 100644 --- a/kern/efi/mm.c +++ b/kern/efi/mm.c @@ -1,7 +1,7 @@ /* mm.c - generic EFI memory management */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009 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 diff --git a/kern/elf.c b/kern/elf.c index f14161060..d9948a822 100644 --- a/kern/elf.c +++ b/kern/elf.c @@ -1,7 +1,7 @@ /* elf.c - load ELF files */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2006,2007,2008,2009 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 @@ -74,7 +74,7 @@ grub_elf_file (grub_file_t file) != sizeof (elf->ehdr)) { grub_error_push (); - grub_error (GRUB_ERR_READ_ERROR, "Cannot read ELF header."); + grub_error (GRUB_ERR_READ_ERROR, "cannot read ELF header"); goto fail; } @@ -134,7 +134,7 @@ grub_elf32_load_phdrs (grub_elf_t elf) || (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size)) { grub_error_push (); - return grub_error (GRUB_ERR_READ_ERROR, "Cannot read program headers"); + return grub_error (GRUB_ERR_READ_ERROR, "cannot read program headers"); } return GRUB_ERR_NONE; @@ -172,7 +172,7 @@ grub_elf32_phdr_iterate (grub_elf_t elf, /* Calculate the amount of memory spanned by the segments. */ grub_size_t -grub_elf32_size (grub_elf_t elf) +grub_elf32_size (grub_elf_t elf, Elf32_Addr *base) { Elf32_Addr segments_start = (Elf32_Addr) -1; Elf32_Addr segments_end = 0; @@ -181,7 +181,9 @@ grub_elf32_size (grub_elf_t elf) /* Run through the program headers to calculate the total memory size we * should claim. */ auto int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf, Elf32_Phdr *phdr, void *_arg); - int NESTED_FUNC_ATTR calcsize (grub_elf_t UNUSED _elf, Elf32_Phdr *phdr, void UNUSED *_arg) + int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf __attribute__ ((unused)), + Elf32_Phdr *phdr, + void *_arg __attribute__ ((unused))) { /* Only consider loadable segments. */ if (phdr->p_type != PT_LOAD) @@ -196,23 +198,28 @@ grub_elf32_size (grub_elf_t elf) grub_elf32_phdr_iterate (elf, calcsize, 0); + if (base) + *base = 0; + if (nr_phdrs == 0) { - grub_error (GRUB_ERR_BAD_OS, "No program headers present"); + grub_error (GRUB_ERR_BAD_OS, "no program headers present"); return 0; } if (segments_end < segments_start) { /* Very bad addresses. */ - grub_error (GRUB_ERR_BAD_OS, "Bad program header load addresses"); + grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses"); return 0; } + if (base) + *base = segments_start; + return segments_end - segments_start; } - /* Load every loadable segment into memory specified by `_load_hook'. */ grub_err_t grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook, @@ -247,7 +254,7 @@ grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook, { grub_error_push (); return grub_error (GRUB_ERR_BAD_OS, - "Invalid offset in program header."); + "invalid offset in program header"); } if (phdr->p_filesz) @@ -259,8 +266,8 @@ grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook, /* XXX How can we free memory from `load_hook'? */ grub_error_push (); return grub_error (GRUB_ERR_BAD_OS, - "Couldn't read segment from file: " - "wanted 0x%lx bytes; read 0x%lx bytes.", + "couldn't read segment from file: " + "wanted 0x%lx bytes; read 0x%lx bytes", phdr->p_filesz, read); } } @@ -313,7 +320,7 @@ grub_elf64_load_phdrs (grub_elf_t elf) || (grub_file_read (elf->file, elf->phdrs, phdrs_size) != phdrs_size)) { grub_error_push (); - return grub_error (GRUB_ERR_READ_ERROR, "Cannot read program headers"); + return grub_error (GRUB_ERR_READ_ERROR, "cannot read program headers"); } return GRUB_ERR_NONE; @@ -351,7 +358,7 @@ grub_elf64_phdr_iterate (grub_elf_t elf, /* Calculate the amount of memory spanned by the segments. */ grub_size_t -grub_elf64_size (grub_elf_t elf) +grub_elf64_size (grub_elf_t elf, Elf64_Addr *base) { Elf64_Addr segments_start = (Elf64_Addr) -1; Elf64_Addr segments_end = 0; @@ -360,7 +367,9 @@ grub_elf64_size (grub_elf_t elf) /* Run through the program headers to calculate the total memory size we * should claim. */ auto int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf, Elf64_Phdr *phdr, void *_arg); - int NESTED_FUNC_ATTR calcsize (grub_elf_t UNUSED _elf, Elf64_Phdr *phdr, void UNUSED *_arg) + int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf __attribute__ ((unused)), + Elf64_Phdr *phdr, + void *_arg __attribute__ ((unused))) { /* Only consider loadable segments. */ if (phdr->p_type != PT_LOAD) @@ -375,19 +384,25 @@ grub_elf64_size (grub_elf_t elf) grub_elf64_phdr_iterate (elf, calcsize, 0); + if (base) + *base = 0; + if (nr_phdrs == 0) { - grub_error (GRUB_ERR_BAD_OS, "No program headers present"); + grub_error (GRUB_ERR_BAD_OS, "no program headers present"); return 0; } if (segments_end < segments_start) { /* Very bad addresses. */ - grub_error (GRUB_ERR_BAD_OS, "Bad program header load addresses"); + grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses"); return 0; } + if (base) + *base = segments_start; + return segments_end - segments_start; } @@ -427,7 +442,7 @@ grub_elf64_load (grub_elf_t _elf, grub_elf64_load_hook_t _load_hook, { grub_error_push (); return grub_error (GRUB_ERR_BAD_OS, - "Invalid offset in program header."); + "invalid offset in program header"); } if (phdr->p_filesz) @@ -439,8 +454,8 @@ grub_elf64_load (grub_elf_t _elf, grub_elf64_load_hook_t _load_hook, /* XXX How can we free memory from `load_hook'? */ grub_error_push (); return grub_error (GRUB_ERR_BAD_OS, - "Couldn't read segment from file: " - "wanted 0x%lx bytes; read 0x%lx bytes.", + "couldn't read segment from file: " + "wanted 0x%lx bytes; read 0x%lx bytes", phdr->p_filesz, read); } } diff --git a/util/console.c b/kern/emu/console.c similarity index 97% rename from util/console.c rename to kern/emu/console.c index 9d8bb1a63..f7fbc899a 100644 --- a/util/console.c +++ b/kern/emu/console.c @@ -19,14 +19,6 @@ #include -#if defined(HAVE_NCURSES_CURSES_H) -# include -#elif defined(HAVE_NCURSES_H) -# include -#elif defined(HAVE_CURSES_H) -# include -#endif - /* For compatibility. */ #ifndef A_NORMAL # define A_NORMAL 0 @@ -35,10 +27,18 @@ # define A_STANDOUT 0 #endif /* ! A_STANDOUT */ -#include +#include #include #include +#if defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#endif + static int grub_console_attr = A_NORMAL; grub_uint8_t grub_console_cur_color = 7; @@ -367,8 +367,7 @@ static struct grub_term_output grub_ncurses_term_output = .setcolor = grub_ncurses_setcolor, .getcolor = grub_ncurses_getcolor, .setcursor = grub_ncurses_setcursor, - .refresh = grub_ncurses_refresh, - .flags = 0, + .refresh = grub_ncurses_refresh }; void @@ -376,8 +375,6 @@ grub_console_init (void) { grub_term_register_output ("console", &grub_ncurses_term_output); grub_term_register_input ("console", &grub_ncurses_term_input); - grub_term_set_current_output (&grub_ncurses_term_output); - grub_term_set_current_input (&grub_ncurses_term_input); } void diff --git a/util/getroot.c b/kern/emu/getroot.c similarity index 79% rename from util/getroot.c rename to kern/emu/getroot.c index c6c229967..6875044da 100644 --- a/util/getroot.c +++ b/kern/emu/getroot.c @@ -19,16 +19,15 @@ #include #include +#include +#include #include #include #include - -#ifdef __CYGWIN__ -# include -# include -# include -# define DEV_CYGDRIVE_MAJOR 98 -#endif +#include +#include +#include +#include #ifdef __GNU__ #include @@ -36,9 +35,11 @@ #include #endif -#include -#include -#include +#include +#include +#include +#include +#include static void strip_extra_slashes (char *dir) @@ -79,103 +80,6 @@ xgetcwd (void) return path; } -#ifdef __CYGWIN__ -/* Convert POSIX path to Win32 path, - remove drive letter, replace backslashes. */ -static char * -get_win32_path (const char *path) -{ - char winpath[PATH_MAX]; - cygwin_conv_to_full_win32_path (path, winpath); - - int len = strlen (winpath); - if (len > 2 && winpath[1] == ':') - { - len -= 2; - memmove (winpath, winpath + 2, len + 1); - } - - int i; - for (i = 0; i < len; i++) - if (winpath[i] == '\\') - winpath[i] = '/'; - return xstrdup (winpath); -} -#endif - -char * -grub_get_prefix (const char *dir) -{ - char *saved_cwd; - char *abs_dir, *prev_dir; - char *prefix; - struct stat st, prev_st; - - /* Save the current directory. */ - saved_cwd = xgetcwd (); - - if (chdir (dir) < 0) - grub_util_error ("Cannot change directory to `%s'", dir); - - abs_dir = xgetcwd (); - strip_extra_slashes (abs_dir); - prev_dir = xstrdup (abs_dir); - - if (stat (".", &prev_st) < 0) - grub_util_error ("Cannot stat `%s'", dir); - - if (! S_ISDIR (prev_st.st_mode)) - grub_util_error ("`%s' is not a directory", dir); - - while (1) - { - if (chdir ("..") < 0) - grub_util_error ("Cannot change directory to the parent"); - - if (stat (".", &st) < 0) - grub_util_error ("Cannot stat current directory"); - - if (! S_ISDIR (st.st_mode)) - grub_util_error ("Current directory is not a directory???"); - - if (prev_st.st_dev != st.st_dev || prev_st.st_ino == st.st_ino) - break; - - free (prev_dir); - prev_dir = xgetcwd (); - prev_st = st; - } - - strip_extra_slashes (prev_dir); - prefix = xmalloc (strlen (abs_dir) - strlen (prev_dir) + 2); - prefix[0] = '/'; - strcpy (prefix + 1, abs_dir + strlen (prev_dir)); - strip_extra_slashes (prefix); - - if (chdir (saved_cwd) < 0) - grub_util_error ("Cannot change directory to `%s'", dir); - -#ifdef __CYGWIN__ - if (st.st_dev != (DEV_CYGDRIVE_MAJOR << 16)) - { - /* Reached some mount point not below /cygdrive. - GRUB does not know Cygwin's emulated mounts, - convert to Win32 path. */ - grub_util_info ("Cygwin prefix = %s", prefix); - char * wprefix = get_win32_path (prefix); - free (prefix); - prefix = wprefix; - } -#endif - - free (saved_cwd); - free (abs_dir); - free (prev_dir); - - grub_util_info ("prefix = %s", prefix); - return prefix; -} - #ifdef __MINGW32__ static char * @@ -236,7 +140,7 @@ find_root_device (const char *dir, dev_t dev) if (res) { if (chdir (saved_cwd) < 0) - grub_util_error ("Cannot restore the original directory"); + grub_util_error ("cannot restore the original directory"); free (saved_cwd); closedir (dp); @@ -264,10 +168,17 @@ find_root_device (const char *dir, dev_t dev) /* Found! */ char *res; char *cwd; +#if defined(__NetBSD__) + /* Convert this block device to its character (raw) device. */ + const char *template = "%s/r%s"; +#else + /* Keep the device name as it is. */ + const char *template = "%s/%s"; +#endif cwd = xgetcwd (); - res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 2); - sprintf (res, "%s/%s", cwd, ent->d_name); + res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 3); + sprintf (res, template, cwd, ent->d_name); strip_extra_slashes (res); free (cwd); @@ -279,7 +190,7 @@ find_root_device (const char *dir, dev_t dev) continue; if (chdir (saved_cwd) < 0) - grub_util_error ("Cannot restore the original directory"); + grub_util_error ("cannot restore the original directory"); free (saved_cwd); closedir (dp); @@ -288,7 +199,7 @@ find_root_device (const char *dir, dev_t dev) } if (chdir (saved_cwd) < 0) - grub_util_error ("Cannot restore the original directory"); + grub_util_error ("cannot restore the original directory"); free (saved_cwd); closedir (dp); @@ -445,7 +356,7 @@ grub_guess_root_device (const char *dir) struct stat st; if (stat (dir, &st) < 0) - grub_util_error ("Cannot stat `%s'", dir); + grub_util_error ("cannot stat `%s'", dir); #ifdef __CYGWIN__ /* Cygwin specific function. */ @@ -460,7 +371,8 @@ grub_guess_root_device (const char *dir) return os_dev; } -int + +static int grub_util_is_dmraid (const char *os_dev) { if (! strncmp (os_dev, "/dev/mapper/nvidia_", 19)) @@ -483,12 +395,12 @@ grub_util_is_dmraid (const char *os_dev) return 1; else if (! strncmp (os_dev, "/dev/mapper/sil_", 16)) return 1; - + return 0; } int -grub_util_get_dev_abstraction (const char *os_dev UNUSED) +grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused))) { #ifdef __linux__ /* Check for LVM. */ @@ -591,7 +503,7 @@ grub_util_get_grub_dev (const char *os_dev) free (p); } else - grub_util_error ("Unknown kind of RAID device `%s'", os_dev); + grub_util_error ("unknown kind of RAID device `%s'", os_dev); break; @@ -608,7 +520,7 @@ grub_util_check_block_device (const char *blk_dev) struct stat st; if (stat (blk_dev, &st) < 0) - grub_util_error ("Cannot stat `%s'", blk_dev); + grub_util_error ("cannot stat `%s'", blk_dev); if (S_ISBLK (st.st_mode)) return (blk_dev); @@ -622,11 +534,10 @@ grub_util_check_char_device (const char *blk_dev) struct stat st; if (stat (blk_dev, &st) < 0) - grub_util_error ("Cannot stat `%s'", blk_dev); + grub_util_error ("cannot stat `%s'", blk_dev); if (S_ISCHR (st.st_mode)) return (blk_dev); else return 0; } - diff --git a/util/hostdisk.c b/kern/emu/hostdisk.c similarity index 60% rename from util/hostdisk.c rename to kern/emu/hostdisk.c index 11caaf407..9c4697552 100644 --- a/util/hostdisk.c +++ b/kern/emu/hostdisk.c @@ -22,10 +22,11 @@ #include #include #include -#include -#include +#include +#include #include #include +#include #include #include @@ -97,12 +98,35 @@ struct hd_geometry # include #endif +#ifdef HAVE_DEVICE_MAPPER +# include +#endif + +#if defined(__NetBSD__) +# include +# include /* struct disklabel */ +# ifdef HAVE_GETRAWPARTITION +# include /* getrawpartition */ +# endif /* HAVE_GETRAWPARTITION */ +# include +# ifndef RAW_FLOPPY_MAJOR +# define RAW_FLOPPY_MAJOR 9 +# endif /* ! RAW_FLOPPY_MAJOR */ +#endif /* defined(__NetBSD__) */ + struct { char *drive; char *device; } map[256]; +struct grub_util_biosdisk_data +{ + char *dev; + int access_mode; + int fd; +}; + #ifdef __linux__ /* Check if we have devfs support. */ static int @@ -121,6 +145,31 @@ have_devfs (void) } #endif /* __linux__ */ +#if defined(__NetBSD__) +/* Adjust device driver parameters. This function should be called just + after successfully opening the device. For now, it simply prevents the + floppy driver from retrying operations on failure, as otherwise the + driver takes a while to abort when there is no floppy in the drive. */ +static void +configure_device_driver (int fd) +{ + struct stat st; + + if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode)) + return; + if (major(st.st_rdev) == RAW_FLOPPY_MAJOR) + { + int floppy_opts; + + if (ioctl (fd, FDIOCGETOPTS, &floppy_opts) == -1) + return; + floppy_opts |= FDOPT_NORETRY; + if (ioctl (fd, FDIOCSETOPTS, &floppy_opts) == -1) + return; + } +} +#endif /* defined(__NetBSD__) */ + static int find_grub_drive (const char *name) { @@ -137,7 +186,7 @@ find_grub_drive (const char *name) } static int -find_free_slot () +find_free_slot (void) { unsigned int i; @@ -165,14 +214,19 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk) { int drive; struct stat st; + struct grub_util_biosdisk_data *data; drive = find_grub_drive (name); if (drive < 0) - return grub_error (GRUB_ERR_BAD_DEVICE, + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no mapping exists for `%s'", name); disk->has_partitions = 1; disk->id = drive; + disk->data = data = xmalloc (sizeof (struct grub_util_biosdisk_data)); + data->dev = NULL; + data->access_mode = 0; + data->fd = -1; /* Get the size. */ #if defined(__MINGW32__) @@ -191,16 +245,20 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk) return GRUB_ERR_NONE; } #elif defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || defined(__APPLE__) + defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) { +# if defined(__NetBSD__) + struct disklabel label; +# else unsigned long long nr; +# endif int fd; fd = open (map[drive].device, O_RDONLY); if (fd == -1) - return grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk size", map[drive].device); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot open `%s' while attempting to get disk size", map[drive].device); -# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) +# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode)) # else if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode)) @@ -214,6 +272,9 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk) if (ioctl (fd, DIOCGMEDIASIZE, &nr)) # elif defined(__APPLE__) if (ioctl (fd, DKIOCGETBLOCKCOUNT, &nr)) +# elif defined(__NetBSD__) + configure_device_driver (fd); + if (ioctl (fd, DIOCGDINFO, &label) == -1) # else if (ioctl (fd, BLKGETSIZE64, &nr)) # endif @@ -224,14 +285,16 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk) close (fd); -#if defined (__APPLE__) +# if defined (__APPLE__) disk->total_sectors = nr; -#else +# elif defined(__NetBSD__) + disk->total_sectors = label.d_secperunit; +# else disk->total_sectors = nr / 512; if (nr % 512) grub_util_error ("unaligned device size"); -#endif +# endif grub_util_info ("the size of %s is %llu", name, disk->total_sectors); @@ -244,7 +307,7 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk) # warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal." #endif if (stat (map[drive].device, &st) < 0) - return grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", map[drive].device); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot stat `%s'", map[drive].device); disk->total_sectors = st.st_size >> GRUB_DISK_SECTOR_BITS; @@ -253,7 +316,150 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk) return GRUB_ERR_NONE; } +#ifdef HAVE_DEVICE_MAPPER +static int +device_is_mapped (const char *dev) +{ + struct stat st; + + if (stat (dev, &st) < 0) + return 0; + + return dm_is_dm_major (major (st.st_rdev)); +} +#endif /* HAVE_DEVICE_MAPPER */ + +#if defined(__linux__) || defined(__CYGWIN__) || defined(__NetBSD__) +static grub_disk_addr_t +find_partition_start (const char *dev) +{ + int fd; +# if !defined(__NetBSD__) + struct hd_geometry hdg; +# else /* defined(__NetBSD__) */ + struct disklabel label; + int index; +# endif /* !defined(__NetBSD__) */ + +# ifdef HAVE_DEVICE_MAPPER + if (device_is_mapped (dev)) { + struct dm_task *task = NULL; + grub_uint64_t start, length; + char *target_type, *params, *space; + grub_disk_addr_t partition_start; + + /* If any device-mapper operation fails, we fall back silently to + HDIO_GETGEO. */ + task = dm_task_create (DM_DEVICE_TABLE); + if (! task) + { + grub_dprintf ("hostdisk", "dm_task_create failed\n"); + goto devmapper_fail; + } + + if (! dm_task_set_name (task, dev)) + { + grub_dprintf ("hostdisk", "dm_task_set_name failed\n"); + goto devmapper_fail; + } + + if (! dm_task_run (task)) + { + grub_dprintf ("hostdisk", "dm_task_run failed\n"); + goto devmapper_fail; + } + + dm_get_next_target (task, NULL, &start, &length, &target_type, ¶ms); + if (! target_type) + { + grub_dprintf ("hostdisk", "no dm target\n"); + goto devmapper_fail; + } + if (strcmp (target_type, "linear") != 0) + { + grub_dprintf ("hostdisk", "ignoring dm target %s (not linear)\n", + target_type); + goto devmapper_fail; + } + if (! params) + { + grub_dprintf ("hostdisk", "no dm params\n"); + goto devmapper_fail; + } + + /* The params string for a linear target looks like this: + DEVICE-NAME START-SECTOR + Parse this out. */ + space = strchr (params, ' '); + if (! space) + goto devmapper_fail; + errno = 0; + partition_start = strtoull (space + 1, NULL, 10); + if (errno == 0) + { + grub_dprintf ("hostdisk", "dm %s starts at %llu\n", + dev, (unsigned long long) partition_start); + dm_task_destroy (task); + return partition_start; + } + +devmapper_fail: + if (task) + dm_task_destroy (task); + } +# endif /* HAVE_DEVICE_MAPPER */ + + fd = open (dev, O_RDONLY); + if (fd == -1) + { + grub_error (GRUB_ERR_BAD_DEVICE, + "cannot open `%s' while attempting to get disk geometry", dev); + return 0; + } + +# if !defined(__NetBSD__) + if (ioctl (fd, HDIO_GETGEO, &hdg)) +# else /* defined(__NetBSD__) */ + configure_device_driver (fd); + if (ioctl (fd, DIOCGDINFO, &label) == -1) +# endif /* !defined(__NetBSD__) */ + { + grub_error (GRUB_ERR_BAD_DEVICE, + "cannot get disk geometry of `%s'", dev); + close (fd); + return 0; + } + + close (fd); + +# if !defined(__NetBSD__) + return hdg.start; +# else /* defined(__NetBSD__) */ + index = dev[strlen(dev) - 1] - 'a'; + + if (index >= label.d_npartitions) + { + grub_error (GRUB_ERR_BAD_DEVICE, + "no disk label entry for `%s'", dev); + return 0; + } + return (grub_disk_addr_t) label.d_partitions[index].p_offset; +# endif /* !defined(__NetBSD__) */ +} +#endif /* __linux__ || __CYGWIN__ */ + #ifdef __linux__ +/* Cache of partition start sectors for each disk. */ +struct linux_partition_cache +{ + struct linux_partition_cache *next; + char *dev; + unsigned long start; + int partno; +}; + +struct linux_partition_cache *linux_partition_cache_list; + static int linux_find_partition (char *dev, unsigned long sector) { @@ -262,6 +468,7 @@ linux_find_partition (char *dev, unsigned long sector) char *p; int i; char real_dev[PATH_MAX]; + struct linux_partition_cache *cache; strcpy(real_dev, dev); @@ -281,26 +488,43 @@ linux_find_partition (char *dev, unsigned long sector) format = "%d"; } + for (cache = linux_partition_cache_list; cache; cache = cache->next) + { + if (strcmp (cache->dev, dev) == 0 && cache->start == sector) + { + sprintf (p, format, cache->partno); + strcpy (dev, real_dev); + return 1; + } + } + for (i = 1; i < 10000; i++) { int fd; - struct hd_geometry hdg; + grub_disk_addr_t start; sprintf (p, format, i); + fd = open (real_dev, O_RDONLY); if (fd == -1) return 0; - - if (ioctl (fd, HDIO_GETGEO, &hdg)) - { - close (fd); - return 0; - } - close (fd); - if (hdg.start == sector) + start = find_partition_start (real_dev); + /* We don't care about errors here. */ + grub_errno = GRUB_ERR_NONE; + + if (start == sector) { + struct linux_partition_cache *new_cache_item; + + new_cache_item = xmalloc (sizeof *new_cache_item); + new_cache_item->dev = xstrdup (dev); + new_cache_item->start = start; + new_cache_item->partno = i; + grub_list_push (GRUB_AS_LIST_P (&linux_partition_cache_list), + GRUB_AS_LIST (new_cache_item)); + strcpy (dev, real_dev); return 1; } @@ -314,6 +538,7 @@ static int open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) { int fd; + struct grub_util_biosdisk_data *data = disk->data; #ifdef O_LARGEFILE flags |= O_LARGEFILE; @@ -334,25 +559,47 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) { int is_partition = 0; char dev[PATH_MAX]; + grub_disk_addr_t part_start = 0; + + part_start = grub_partition_get_start (disk->partition); strcpy (dev, map[disk->id].device); - if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0) - is_partition = linux_find_partition (dev, disk->partition->start); + if (disk->partition && sector >= part_start + && strncmp (map[disk->id].device, "/dev/", 5) == 0) + is_partition = linux_find_partition (dev, part_start); - /* Open the partition. */ - grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev); - fd = open (dev, flags); - if (fd < 0) + if (data->dev && strcmp (data->dev, dev) == 0 && + data->access_mode == (flags & O_ACCMODE)) { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s'", dev); - return -1; + grub_dprintf ("hostdisk", "reusing open device `%s'\n", dev); + fd = data->fd; + } + else + { + free (data->dev); + if (data->fd != -1) + close (data->fd); + + /* Open the partition. */ + grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev); + fd = open (dev, flags); + if (fd < 0) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s'", dev); + return -1; + } + + /* Flush the buffer cache to the physical disk. + XXX: This also empties the buffer cache. */ + ioctl (fd, BLKFLSBUF, 0); + + data->dev = xstrdup (dev); + data->access_mode = (flags & O_ACCMODE); + data->fd = fd; } - /* Make the buffer cache consistent with the physical disk. */ - ioctl (fd, BLKFLSBUF, 0); - if (is_partition) - sector -= disk->partition->start; + sector -= part_start; } #else /* ! __linux__ */ #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) @@ -373,7 +620,26 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) } #endif - fd = open (map[disk->id].device, flags); + if (data->dev && strcmp (data->dev, map[disk->id].device) == 0 && + data->access_mode == (flags & O_ACCMODE)) + { + grub_dprintf ("hostdisk", "reusing open device `%s'\n", data->dev); + fd = data->fd; + } + else + { + free (data->dev); + if (data->fd != -1) + close (data->fd); + + fd = open (map[disk->id].device, flags); + if (fd >= 0) + { + data->dev = xstrdup (map[disk->id].device); + data->access_mode = (flags & O_ACCMODE); + data->fd = fd; + } + } #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) if (! (sysctl_oldflags & 0x10) @@ -397,6 +663,10 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) } #endif /* ! __linux__ */ +#if defined(__NetBSD__) + configure_device_driver (fd); +#endif /* defined(__NetBSD__) */ + #if defined(__linux__) && (!defined(__GLIBC__) || \ ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))) /* Maybe libc doesn't have large file support. */ @@ -489,6 +759,23 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, { int fd; + /* Split pre-partition and partition reads. */ + if (disk->partition && sector < disk->partition->start + && sector + size > disk->partition->start) + { + grub_err_t err; + err = grub_util_biosdisk_read (disk, sector, + disk->partition->start - sector, + buf); + if (err) + return err; + + return grub_util_biosdisk_read (disk, disk->partition->start, + size - (disk->partition->start - sector), + buf + ((disk->partition->start - sector) + << GRUB_DISK_SECTOR_BITS)); + } + fd = open_device (disk, sector, O_RDONLY); if (fd < 0) return grub_errno; @@ -516,7 +803,6 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, != (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device); - close (fd); return grub_errno; } @@ -526,6 +812,23 @@ grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector, { int fd; + /* Split pre-partition and partition writes. */ + if (disk->partition && sector < disk->partition->start + && sector + size > disk->partition->start) + { + grub_err_t err; + err = grub_util_biosdisk_write (disk, sector, + disk->partition->start - sector, + buf); + if (err) + return err; + + return grub_util_biosdisk_write (disk, disk->partition->start, + size - (disk->partition->start - sector), + buf + ((disk->partition->start - sector) + << GRUB_DISK_SECTOR_BITS)); + } + fd = open_device (disk, sector, O_WRONLY); if (fd < 0) return grub_errno; @@ -534,17 +837,27 @@ grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector, != (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device); - close (fd); return grub_errno; } +static void +grub_util_biosdisk_close (struct grub_disk *disk) +{ + struct grub_util_biosdisk_data *data = disk->data; + + free (data->dev); + if (data->fd != -1) + close (data->fd); + free (data); +} + static struct grub_disk_dev grub_util_biosdisk_dev = { .name = "biosdisk", .id = GRUB_DISK_DEVICE_BIOSDISK_ID, .iterate = grub_util_biosdisk_iterate, .open = grub_util_biosdisk_open, - .close = 0, + .close = grub_util_biosdisk_close, .read = grub_util_biosdisk_read, .write = grub_util_biosdisk_write, .next = 0 @@ -567,7 +880,7 @@ read_device_map (const char *dev_map) fp = fopen (dev_map, "r"); if (! fp) { - grub_util_info (_("Cannot open `%s'"), dev_map); + grub_util_info (_("cannot open `%s'"), dev_map); return; } @@ -638,7 +951,7 @@ read_device_map (const char *dev_map) symbolic links. */ map[drive].device = xmalloc (PATH_MAX); if (! realpath (p, map[drive].device)) - grub_util_error ("Cannot get the real path of `%s'", p); + grub_util_error ("cannot get the real path of `%s'", p); #else map[drive].device = xstrdup (p); #endif @@ -682,7 +995,7 @@ make_device_name (int drive, int dos_part, int bsd_part) dos_part_str = xasprintf (",%d", dos_part + 1); if (bsd_part >= 0) - bsd_part_str = xasprintf (",%c", dos_part + 'a'); + bsd_part_str = xasprintf (",%d", bsd_part + 1); ret = xasprintf ("%s%s%s", map[drive].drive, dos_part_str ? : "", @@ -698,7 +1011,7 @@ make_device_name (int drive, int dos_part, int bsd_part) } static char * -convert_system_partition_to_system_disk (const char *os_dev) +convert_system_partition_to_system_disk (const char *os_dev, struct stat *st) { #if defined(__linux__) char *path = xmalloc (PATH_MAX); @@ -816,6 +1129,96 @@ convert_system_partition_to_system_disk (const char *os_dev) p[4] = '\0'; return path; } + +#ifdef HAVE_DEVICE_MAPPER + /* If this is a DM-RAID device. */ + if ((strncmp ("mapper/", p, 7) == 0)) + { + static struct dm_tree *tree = NULL; + uint32_t maj, min; + struct dm_tree_node *node, *child; + void *handle; + const char *node_uuid, *mapper_name, *child_uuid, *child_name; + + if (! tree) + tree = dm_tree_create (); + + if (! tree) + { + grub_dprintf ("hostdisk", "dm_tree_create failed\n"); + return NULL; + } + + maj = major (st->st_rdev); + min = minor (st->st_rdev); + if (! dm_tree_add_dev (tree, maj, min)) + { + grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n"); + return NULL; + } + + node = dm_tree_find_node (tree, maj, min); + if (! node) + { + grub_dprintf ("hostdisk", "dm_tree_find_node failed\n"); + return NULL; + } + node_uuid = dm_tree_node_get_uuid (node); + if (! node_uuid) + { + grub_dprintf ("hostdisk", "%s has no DM uuid\n", path); + return NULL; + } + else if (strncmp (node_uuid, "DMRAID-", 7) != 0) + { + grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path); + return NULL; + } + + handle = NULL; + mapper_name = NULL; + /* Counter-intuitively, device-mapper refers to the disk-like + device containing a DM-RAID partition device as a "child" of + the partition device. */ + child = dm_tree_next_child (&handle, node, 0); + if (! child) + { + grub_dprintf ("hostdisk", "%s has no DM children\n", path); + goto devmapper_out; + } + child_uuid = dm_tree_node_get_uuid (child); + if (! child_uuid) + { + grub_dprintf ("hostdisk", "%s child has no DM uuid\n", path); + goto devmapper_out; + } + else if (strncmp (child_uuid, "DMRAID-", 7) != 0) + { + grub_dprintf ("hostdisk", "%s child is not DM-RAID\n", path); + goto devmapper_out; + } + child_name = dm_tree_node_get_name (child); + if (! child_name) + { + grub_dprintf ("hostdisk", "%s child has no DM name\n", path); + goto devmapper_out; + } + mapper_name = child_name; + +devmapper_out: + if (! mapper_name) + { + /* This is a DM-RAID disk, not a partition. */ + mapper_name = dm_tree_node_get_name (node); + if (! mapper_name) + { + grub_dprintf ("hostdisk", "%s has no DM name\n", path); + return NULL; + } + } + return xasprintf ("/dev/mapper/%s", mapper_name); + } +#endif /* HAVE_DEVICE_MAPPER */ } return path; @@ -852,6 +1255,27 @@ convert_system_partition_to_system_disk (const char *os_dev) } return path; +#elif defined(__NetBSD__) + /* NetBSD uses "/dev/r[wsc]d[0-9]+[a-z]". */ + char *path = xstrdup (os_dev); + if (strncmp ("/dev/rwd", path, 8) == 0 || + strncmp ("/dev/rsd", path, 8) == 0 || + strncmp ("/dev/rcd", path, 8) == 0) + { + char *q; + q = path + strlen(path) - 1; /* last character */ + if (grub_isalpha(*q) && grub_isdigit(*(q-1))) + { + int rawpart = -1; +# ifdef HAVE_GETRAWPARTITION + rawpart = getrawpartition(); +# endif /* HAVE_GETRAWPARTITION */ + if (rawpart >= 0) + *q = 'a' + rawpart; + } + } + return path; + #else # warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly." return xstrdup (os_dev); @@ -870,13 +1294,33 @@ device_is_wholedisk (const char *os_dev) } #endif +#if defined(__NetBSD__) +/* Try to determine whether a given device name corresponds to a whole disk. + This function should give in most cases a definite answer, but it may + actually give an approximate one in the following sense: if the return + value is 0 then the device name does not correspond to a whole disk. */ static int -find_system_device (const char *os_dev) +device_is_wholedisk (const char *os_dev) +{ + int len = strlen (os_dev); + int rawpart = -1; + +# ifdef HAVE_GETRAWPARTITION + rawpart = getrawpartition(); +# endif /* HAVE_GETRAWPARTITION */ + if (rawpart < 0) + return 1; + return (os_dev[len - 1] == ('a' + rawpart)); +} +#endif /* defined(__NetBSD__) */ + +static int +find_system_device (const char *os_dev, struct stat *st) { unsigned int i; char *os_disk; - os_disk = convert_system_partition_to_system_disk (os_dev); + os_disk = convert_system_partition_to_system_disk (os_dev, st); if (! os_disk) return -1; @@ -910,26 +1354,26 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev) return 0; } - drive = find_system_device (os_dev); + drive = find_system_device (os_dev, &st); if (drive < 0) { - grub_error (GRUB_ERR_BAD_DEVICE, + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no mapping exists for `%s'", os_dev); return 0; } - if (grub_strcmp (os_dev, convert_system_partition_to_system_disk (os_dev)) - == 0) + if (grub_strcmp (os_dev, + convert_system_partition_to_system_disk (os_dev, &st)) == 0) return make_device_name (drive, -1, -1); -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) if (! S_ISCHR (st.st_mode)) #else if (! S_ISBLK (st.st_mode)) #endif return make_device_name (drive, -1, -1); -#if defined(__linux__) || defined(__CYGWIN__) +#if defined(__linux__) || defined(__CYGWIN__) || defined(__NetBSD__) /* Linux counts partitions uniformly, whether a BSD partition or a DOS partition, so mapping them to GRUB devices is not trivial. Here, get the start sector of a partition by HDIO_GETGEO, and @@ -937,53 +1381,41 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev) Cygwin /dev/sdXN emulation uses Windows partition mapping. It does not count the extended partition and missing primary - partitions. Use same method as on Linux here. */ + partitions. Use same method as on Linux here. + + For NetBSD, proceed as for Linux, except that the start sector is + obtained from the disk label. */ { char *name; grub_disk_t disk; - int fd; - struct hd_geometry hdg; + grub_disk_addr_t start; int dos_part = -1; int bsd_part = -1; - auto int find_partition (grub_disk_t disk, + auto int find_partition (grub_disk_t dsk, const grub_partition_t partition); - int find_partition (grub_disk_t disk __attribute__ ((unused)), + int find_partition (grub_disk_t dsk __attribute__ ((unused)), const grub_partition_t partition) { - struct grub_msdos_partition *pcdata = NULL; + grub_disk_addr_t part_start = 0; + grub_util_info ("Partition %d starts from %lu", + partition->number, partition->start); - if (strcmp (partition->partmap->name, "part_msdos") == 0) - pcdata = partition->data; + part_start = grub_partition_get_start (partition); - if (pcdata) + if (start == part_start) { - if (pcdata->bsd_part < 0) - grub_util_info ("DOS partition %d starts from %lu", - pcdata->dos_part, partition->start); - else - grub_util_info ("BSD partition %d,%c starts from %lu", - pcdata->dos_part, pcdata->bsd_part + 'a', - partition->start); - } - else - { - grub_util_info ("Partition %d starts from %lu", - partition->index, partition->start); - } - - if (hdg.start == partition->start) - { - if (pcdata) + if (partition->parent) { - dos_part = pcdata->dos_part; - bsd_part = pcdata->bsd_part; + dos_part = partition->parent->number; + bsd_part = partition->number; } else { - dos_part = partition->index; + dos_part = partition->number; bsd_part = -1; } + return 1; } @@ -992,31 +1424,25 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev) name = make_device_name (drive, -1, -1); +# if !defined(__NetBSD__) if (MAJOR (st.st_rdev) == FLOPPY_MAJOR) return name; +# else /* defined(__NetBSD__) */ + /* Since os_dev and convert_system_partition_to_system_disk (os_dev) are + * different, we know that os_dev is of the form /dev/r[wsc]d[0-9]+[a-z] + * and in particular it cannot be a floppy device. */ +# endif /* !defined(__NetBSD__) */ - fd = open (os_dev, O_RDONLY); - if (fd == -1) + start = find_partition_start (os_dev); + if (grub_errno != GRUB_ERR_NONE) { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk geometry", os_dev); free (name); return 0; } - if (ioctl (fd, HDIO_GETGEO, &hdg)) - { - grub_error (GRUB_ERR_BAD_DEVICE, - "cannot get geometry of `%s'", os_dev); - close (fd); - free (name); - return 0; - } + grub_util_info ("%s starts from %lu", os_dev, start); - close (fd); - - grub_util_info ("%s starts from %lu", os_dev, hdg.start); - - if (hdg.start == 0 && device_is_wholedisk (os_dev)) + if (start == 0 && device_is_wholedisk (os_dev)) return name; grub_util_info ("opening the device %s", name); @@ -1111,3 +1537,9 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev) return make_device_name (drive, -1, -1); #endif } + +const char * +grub_util_biosdisk_get_osdev (grub_disk_t disk) +{ + return map[disk->id].device; +} diff --git a/util/hostfs.c b/kern/emu/hostfs.c similarity index 89% rename from util/hostfs.c rename to kern/emu/hostfs.c index 83db2f1a9..501ad4664 100644 --- a/util/hostfs.c +++ b/kern/emu/hostfs.c @@ -1,7 +1,7 @@ /* hostfs.c - Dummy filesystem to provide access to the hosts filesystem */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2007,2008,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 @@ -26,6 +26,7 @@ #include #include +#include /* dirent.d_type is a BSD extension, not part of POSIX */ @@ -118,10 +119,17 @@ grub_hostfs_read (grub_file_t file, char *buf, grub_size_t len) FILE *f; f = (FILE *) file->data; - fseeko (f, file->offset, SEEK_SET); - int s = fread (buf, 1, len, f); + if (fseeko (f, file->offset, SEEK_SET) != 0) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "fseeko: %s", strerror (errno)); + return -1; + } - return s; + unsigned int s = fread (buf, 1, len, f); + if (s != len) + grub_error (GRUB_ERR_FILE_READ_ERROR, "fread: %s", strerror (errno)); + + return (signed) s; } static grub_err_t diff --git a/util/grub-emu.c b/kern/emu/main.c similarity index 76% rename from util/grub-emu.c rename to kern/emu/main.c index e65c8585e..fb5dbf19f 100644 --- a/util/grub-emu.c +++ b/kern/emu/main.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2006,2007,2008,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 @@ -16,7 +16,10 @@ * along with GRUB. If not, see . */ +#include +#include #include +#include #include #include #include @@ -24,22 +27,22 @@ #include #include +#include #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include -#include +#include #include #include #include -#include - +#define ENABLE_RELOCATABLE 0 #include "progname.h" /* Used for going back to the main function. */ @@ -51,9 +54,10 @@ static char *prefix = NULL; grub_addr_t grub_arch_modules_addr (void) { - return NULL; + return 0; } +#if GRUB_NO_MODULES grub_err_t grub_arch_dl_check_header (void *ehdr) { @@ -70,6 +74,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) return GRUB_ERR_BAD_MODULE; } +#endif void grub_reboot (void) @@ -106,10 +111,6 @@ grub_machine_fini (void) grub_console_fini (); } -void -read_command_list (void) -{ -} static struct option options[] = @@ -129,10 +130,10 @@ usage (int status) { if (status) fprintf (stderr, - "Try ``grub-emu --help'' for more information.\n"); + "Try `%s --help' for more information.\n", program_name); else printf ( - "Usage: grub-emu [OPTION]...\n" + "Usage: %s [OPTION]...\n" "\n" "GRUB emulator.\n" "\n" @@ -144,11 +145,20 @@ usage (int status) " -h, --help display this message and exit\n" " -V, --version print version information and exit\n" "\n" - "Report bugs to <%s>.\n", DEFAULT_DEVICE_MAP, DEFAULT_DIRECTORY, PACKAGE_BUGREPORT); + "Report bugs to <%s>.\n", program_name, DEFAULT_DEVICE_MAP, DEFAULT_DIRECTORY, PACKAGE_BUGREPORT); return status; } +void grub_hostfs_init (void); +void grub_hostfs_fini (void); +void grub_host_init (void); +void grub_host_fini (void); +#if GRUB_NO_MODULES +void grub_init_all (void); +void grub_fini_all (void); +#endif + int main (int argc, char *argv[]) { @@ -159,9 +169,6 @@ main (int argc, char *argv[]) int opt; set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); while ((opt = getopt_long (argc, argv, "r:d:m:vH:hV", options, 0)) != -1) switch (opt) @@ -210,29 +217,36 @@ main (int argc, char *argv[]) signal (SIGINT, SIG_IGN); grub_console_init (); + grub_host_init (); + grub_hostfs_init (); /* XXX: This is a bit unportable. */ grub_util_biosdisk_init (dev_map); +#if GRUB_NO_MODULES grub_init_all (); +#endif /* Make sure that there is a root device. */ if (! root_dev) { char *device_name = grub_guess_root_device (dir); if (! device_name) - grub_util_error ("cannot find a device for %s.\n", dir); + grub_util_error ("cannot find a device for %s", dir); root_dev = grub_util_get_grub_dev (device_name); if (! root_dev) { grub_util_info ("guessing the root device failed, because of `%s'", grub_errmsg); - grub_util_error ("Cannot guess the root device. Specify the option ``--root-device''."); + grub_util_error ("cannot guess the root device. Specify the option `--root-device'"); } } - dir = grub_get_prefix (dir); + if (strcmp (root_dev, "host") == 0) + dir = xstrdup (dir); + else + dir = grub_make_system_path_relative_to_its_root (dir); prefix = xmalloc (strlen (root_dev) + 2 + strlen (dir) + 1); sprintf (prefix, "(%s)%s", root_dev, dir); free (dir); @@ -241,9 +255,42 @@ main (int argc, char *argv[]) if (setjmp (main_env) == 0) grub_main (); +#if GRUB_NO_MODULES grub_fini_all (); +#endif + grub_hostfs_fini (); + grub_host_fini (); grub_machine_fini (); return 0; } + +#ifdef __MINGW32__ + +void +grub_millisleep (grub_uint32_t ms) +{ + Sleep (ms); +} + +#else + +void +grub_millisleep (grub_uint32_t ms) +{ + struct timespec ts; + + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000000; + nanosleep (&ts, NULL); +} + +#endif + +#if GRUB_NO_MODULES +void +grub_register_exported_symbols (void) +{ +} +#endif diff --git a/kern/emu/misc.c b/kern/emu/misc.c new file mode 100644 index 000000000..a3ccb3076 --- /dev/null +++ b/kern/emu/misc.c @@ -0,0 +1,312 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LIMITS_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +int verbosity; + +void +grub_util_warn (const char *fmt, ...) +{ + va_list ap; + + fprintf (stderr, _("%s: warn:"), program_name); + fprintf (stderr, " "); + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + fprintf (stderr, ".\n"); + fflush (stderr); +} + +void +grub_util_info (const char *fmt, ...) +{ + if (verbosity > 0) + { + va_list ap; + + fprintf (stderr, _("%s: info:"), program_name); + fprintf (stderr, " "); + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + fprintf (stderr, ".\n"); + fflush (stderr); + } +} + +void +grub_util_error (const char *fmt, ...) +{ + va_list ap; + + fprintf (stderr, _("%s: error:"), program_name); + fprintf (stderr, " "); + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + fprintf (stderr, ".\n"); + exit (1); +} + +void * +xmalloc (grub_size_t size) +{ + void *p; + + p = malloc (size); + if (! p) + grub_util_error ("out of memory"); + + return p; +} + +void * +xrealloc (void *ptr, grub_size_t size) +{ + ptr = realloc (ptr, size); + if (! ptr) + grub_util_error ("out of memory"); + + return ptr; +} + +char * +xstrdup (const char *str) +{ + size_t len; + char *newstr; + + len = strlen (str); + newstr = (char *) xmalloc (len + 1); + memcpy (newstr, str, len + 1); + + return newstr; +} + +#ifndef HAVE_VASPRINTF + +int +vasprintf (char **buf, const char *fmt, va_list ap) +{ + /* Should be large enough. */ + *buf = xmalloc (512); + + return vsprintf (*buf, fmt, ap); +} + +#endif + +#ifndef HAVE_ASPRINTF + +int +asprintf (char **buf, const char *fmt, ...) +{ + int status; + va_list ap; + + va_start (ap, fmt); + status = vasprintf (*buf, fmt, ap); + va_end (ap); + + return status; +} + +#endif + +char * +xasprintf (const char *fmt, ...) +{ + va_list ap; + char *result; + + va_start (ap, fmt); + if (vasprintf (&result, fmt, ap) < 0) + { + if (errno == ENOMEM) + grub_util_error ("out of memory"); + return NULL; + } + + return result; +} + +void +grub_exit (void) +{ + exit (1); +} + +grub_uint64_t +grub_get_time_ms (void) +{ + struct timeval tv; + + gettimeofday (&tv, 0); + + return (tv.tv_sec * 1000 + tv.tv_usec / 1000); +} + +grub_uint32_t +grub_get_rtc (void) +{ + struct timeval tv; + + gettimeofday (&tv, 0); + + return (tv.tv_sec * GRUB_TICKS_PER_SECOND + + (((tv.tv_sec % GRUB_TICKS_PER_SECOND) * 1000000 + tv.tv_usec) + * GRUB_TICKS_PER_SECOND / 1000000)); +} + +char * +canonicalize_file_name (const char *path) +{ + char *ret; +#ifdef PATH_MAX + ret = xmalloc (PATH_MAX); + (void) realpath (path, ret); +#else + ret = realpath (path, NULL); +#endif + return ret; +} + +#ifdef __CYGWIN__ +/* Convert POSIX path to Win32 path, + remove drive letter, replace backslashes. */ +static char * +get_win32_path (const char *path) +{ + char winpath[PATH_MAX]; + if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, path, winpath, sizeof(winpath))) + grub_util_error ("cygwin_conv_path() failed"); + + int len = strlen (winpath); + int offs = (len > 2 && winpath[1] == ':' ? 2 : 0); + + int i; + for (i = offs; i < len; i++) + if (winpath[i] == '\\') + winpath[i] = '/'; + return xstrdup (winpath + offs); +} +#endif + +/* This function never prints trailing slashes (so that its output + can be appended a slash unconditionally). */ +char * +grub_make_system_path_relative_to_its_root (const char *path) +{ + struct stat st; + char *p, *buf, *buf2, *buf3; + uintptr_t offset = 0; + dev_t num; + size_t len; + + /* canonicalize. */ + p = canonicalize_file_name (path); + + if (p == NULL) + grub_util_error ("failed to get canonical path of %s", path); + + len = strlen (p) + 1; + buf = xstrdup (p); + free (p); + + if (stat (buf, &st) < 0) + grub_util_error ("cannot stat %s: %s", buf, strerror (errno)); + + buf2 = xstrdup (buf); + num = st.st_dev; + + /* This loop sets offset to the number of chars of the root + directory we're inspecting. */ + while (1) + { + p = strrchr (buf, '/'); + if (p == NULL) + /* This should never happen. */ + grub_util_error ("FIXME: no / in buf. (make_system_path_relative_to_its_root)"); + if (p != buf) + *p = 0; + else + *++p = 0; + + if (stat (buf, &st) < 0) + grub_util_error ("cannot stat %s: %s", buf, strerror (errno)); + + /* buf is another filesystem; we found it. */ + if (st.st_dev != num) + { + /* offset == 0 means path given is the mount point. + This works around special-casing of "/" in Un*x. This function never + prints trailing slashes (so that its output can be appended a slash + unconditionally). Each slash in is considered a preceding slash, and + therefore the root directory is an empty string. */ + if (offset == 0) + { + free (buf); + free (buf2); + return xstrdup (""); + } + else + break; + } + + offset = p - buf; + /* offset == 1 means root directory. */ + if (offset == 1) + { + /* Include leading slash. */ + offset = 0; + break; + } + } + free (buf); + buf3 = xstrdup (buf2 + offset); + free (buf2); + +#ifdef __CYGWIN__ + if (st.st_dev != (DEV_CYGDRIVE_MAJOR << 16)) + { + /* Reached some mount point not below /cygdrive. + GRUB does not know Cygwin's emulated mounts, + convert to Win32 path. */ + grub_util_info ("Cygwin path = %s\n", buf3); + char * temp = get_win32_path (buf3); + free (buf3); + buf3 = temp; + } +#endif + + /* Remove trailing slashes, return empty string if root directory. */ + len = strlen (buf3); + while (len > 0 && buf3[len - 1] == '/') + { + buf3[len - 1] = '\0'; + len--; + } + + return buf3; +} diff --git a/kern/emu/mm.c b/kern/emu/mm.c new file mode 100644 index 000000000..0e9e9f3a8 --- /dev/null +++ b/kern/emu/mm.c @@ -0,0 +1,85 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2006,2007,2008,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 . + */ + +#include +#include +#include +#include +#include + +void * +grub_malloc (grub_size_t size) +{ + void *ret; + ret = malloc (size); + if (!ret) + grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + return ret; +} + +void * +grub_zalloc (grub_size_t size) +{ + void *ret; + + ret = grub_malloc (size); + if (!ret) + return NULL; + memset (ret, 0, size); + return ret; +} + +void +grub_free (void *ptr) +{ + free (ptr); +} + +void * +grub_realloc (void *ptr, grub_size_t size) +{ + void *ret; + ret = realloc (ptr, size); + if (!ret) + grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + return ret; +} + +void * +grub_memalign (grub_size_t align, grub_size_t size) +{ + void *p; + +#if defined(HAVE_POSIX_MEMALIGN) + if (align < sizeof (void *)) + align = sizeof (void *); + if (posix_memalign (&p, align, size) != 0) + p = 0; +#elif defined(HAVE_MEMALIGN) + p = memalign (align, size); +#else + (void) align; + (void) size; + grub_util_error ("grub_memalign is not supported"); +#endif + + if (!p) + grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + + return p; +} diff --git a/kern/emu/time.c b/kern/emu/time.c new file mode 100644 index 000000000..5da8092a9 --- /dev/null +++ b/kern/emu/time.c @@ -0,0 +1,46 @@ +/* + * 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 . + */ + +#include +#include + +grub_err_t +grub_get_datetime (struct grub_datetime *datetime) +{ + struct tm *mytm; + time_t mytime; + + mytime = time (&mytime); + mytm = gmtime (&mytime); + + datetime->year = mytm->tm_year + 1900; + datetime->month = mytm->tm_mon + 1; + datetime->day = mytm->tm_mday; + datetime->hour = mytm->tm_hour; + datetime->minute = mytm->tm_min; + datetime->second = mytm->tm_sec; + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_set_datetime (struct grub_datetime *datetime __attribute__ ((unused))) +{ + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "no clock setting routine available"); +} diff --git a/kern/env.c b/kern/env.c index 750902af8..84b3a001d 100644 --- a/kern/env.c +++ b/kern/env.c @@ -18,34 +18,15 @@ */ #include +#include #include #include -/* The size of the hash table. */ -#define HASHSZ 13 - -/* A hashtable for quick lookup of variables. */ -struct grub_env_context -{ - /* A hash table for variables. */ - struct grub_env_var *vars[HASHSZ]; - - /* One level deeper on the stack. */ - struct grub_env_context *prev; -}; - -/* This is used for sorting only. */ -struct grub_env_sorted_var -{ - struct grub_env_var *var; - struct grub_env_sorted_var *next; -}; - /* The initial context. */ static struct grub_env_context initial_context; /* The current context. */ -static struct grub_env_context *current_context = &initial_context; +struct grub_env_context *grub_current_context = &initial_context; /* Return the hash representation of the string S. */ static unsigned int @@ -60,87 +41,20 @@ grub_env_hashval (const char *s) return i % HASHSZ; } -static struct grub_env_var * +struct grub_env_var * grub_env_find (const char *name) { struct grub_env_var *var; int idx = grub_env_hashval (name); /* Look for the variable in the current context. */ - for (var = current_context->vars[idx]; var; var = var->next) + for (var = grub_current_context->vars[idx]; var; var = var->next) if (grub_strcmp (var->name, name) == 0) return var; return 0; } -grub_err_t -grub_env_context_open (int export) -{ - struct grub_env_context *context; - int i; - - context = grub_zalloc (sizeof (*context)); - if (! context) - return grub_errno; - - context->prev = current_context; - current_context = context; - - /* Copy exported variables. */ - for (i = 0; i < HASHSZ; i++) - { - struct grub_env_var *var; - - for (var = context->prev->vars[i]; var; var = var->next) - { - if (export && var->type == GRUB_ENV_VAR_GLOBAL) - { - if (grub_env_set (var->name, var->value) != GRUB_ERR_NONE) - { - grub_env_context_close (); - return grub_errno; - } - grub_register_variable_hook (var->name, var->read_hook, var->write_hook); - } - } - } - - return GRUB_ERR_NONE; -} - -grub_err_t -grub_env_context_close (void) -{ - struct grub_env_context *context; - int i; - - if (! current_context->prev) - grub_fatal ("cannot close the initial context"); - - /* Free the variables associated with this context. */ - for (i = 0; i < HASHSZ; i++) - { - struct grub_env_var *p, *q; - - for (p = current_context->vars[i]; p; p = q) - { - q = p->next; - grub_free (p->name); - if (p->type != GRUB_ENV_VAR_DATA) - grub_free (p->value); - grub_free (p); - } - } - - /* Restore the previous context. */ - context = current_context->prev; - grub_free (current_context); - current_context = context; - - return GRUB_ERR_NONE; -} - static void grub_env_insert (struct grub_env_context *context, struct grub_env_var *var) @@ -164,18 +78,6 @@ grub_env_remove (struct grub_env_var *var) var->next->prevp = var->prevp; } -grub_err_t -grub_env_export (const char *name) -{ - struct grub_env_var *var; - - var = grub_env_find (name); - if (var) - var->type = GRUB_ENV_VAR_GLOBAL; - - return GRUB_ERR_NONE; -} - grub_err_t grub_env_set (const char *name, const char *val) { @@ -207,9 +109,8 @@ grub_env_set (const char *name, const char *val) if (! var) return grub_errno; - /* This is not necessary, because GRUB_ENV_VAR_LOCAL == 0. But leave - this for readability. */ - var->type = GRUB_ENV_VAR_LOCAL; + /* This is not necessary. But leave this for readability. */ + var->global = 0; var->name = grub_strdup (name); if (! var->name) @@ -219,7 +120,7 @@ grub_env_set (const char *name, const char *val) if (! var->value) goto fail; - grub_env_insert (current_context, var); + grub_env_insert (grub_current_context, var); return GRUB_ERR_NONE; @@ -255,16 +156,16 @@ grub_env_unset (const char *name) if (! var) return; - /* XXX: It is not possible to unset variables with a read or write - hook. */ if (var->read_hook || var->write_hook) - return; + { + grub_env_set (name, ""); + return; + } grub_env_remove (var); grub_free (var->name); - if (var->type != GRUB_ENV_VAR_DATA) - grub_free (var->value); + grub_free (var->value); grub_free (var); } @@ -280,14 +181,10 @@ grub_env_iterate (int (*func) (struct grub_env_var *var)) { struct grub_env_var *var; - for (var = current_context->vars[i]; var; var = var->next) + for (var = grub_current_context->vars[i]; var; var = var->next) { struct grub_env_sorted_var *p, **q; - /* Ignore data slots. */ - if (var->type == GRUB_ENV_VAR_DATA) - continue; - sorted_var = grub_malloc (sizeof (*sorted_var)); if (! sorted_var) goto fail; @@ -343,84 +240,3 @@ grub_register_variable_hook (const char *name, return GRUB_ERR_NONE; } - -static char * -mangle_data_slot_name (const char *name) -{ - char *mangled_name; - - mangled_name = grub_malloc (grub_strlen (name) + 2); - if (! mangled_name) - return 0; - - grub_sprintf (mangled_name, "\e%s", name); - return mangled_name; -} - -grub_err_t -grub_env_set_data_slot (const char *name, const void *ptr) -{ - char *mangled_name; - struct grub_env_var *var; - - mangled_name = mangle_data_slot_name (name); - if (! mangled_name) - goto fail; - - /* If the variable does already exist, just update the variable. */ - var = grub_env_find (mangled_name); - if (var) - { - var->value = (char *) ptr; - return GRUB_ERR_NONE; - } - - /* The variable does not exist, so create a new one. */ - var = grub_zalloc (sizeof (*var)); - if (! var) - goto fail; - - var->type = GRUB_ENV_VAR_DATA; - var->name = mangled_name; - var->value = (char *) ptr; - - grub_env_insert (current_context, var); - - return GRUB_ERR_NONE; - - fail: - - grub_free (mangled_name); - return grub_errno; -} - -void * -grub_env_get_data_slot (const char *name) -{ - char *mangled_name; - void *ptr = 0; - - mangled_name = mangle_data_slot_name (name); - if (! mangled_name) - goto fail; - - ptr = grub_env_get (mangled_name); - grub_free (mangled_name); - - fail: - - return ptr; -} - -void -grub_env_unset_data_slot (const char *name) -{ - char *mangled_name; - - mangled_name = mangle_data_slot_name (name); - if (! mangled_name) - return; - - grub_env_unset (mangled_name); - grub_free (mangled_name); -} diff --git a/kern/err.c b/kern/err.c index 311130154..8272467f5 100644 --- a/kern/err.c +++ b/kern/err.c @@ -20,6 +20,7 @@ #include #include #include +#include #define GRUB_MAX_ERRMSG 256 #define GRUB_ERROR_STACK_SIZE 10 @@ -44,7 +45,7 @@ grub_error (grub_err_t n, const char *fmt, ...) grub_errno = n; va_start (ap, fmt); - grub_vsprintf (grub_errmsg, fmt, ap); + grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap); va_end (ap); return n; @@ -56,7 +57,7 @@ grub_fatal (const char *fmt, ...) va_list ap; va_start (ap, fmt); - grub_vprintf (fmt, ap); + grub_vprintf (_(fmt), ap); va_end (ap); grub_abort (); @@ -121,7 +122,7 @@ grub_print_error (void) do { if (grub_errno != GRUB_ERR_NONE) - grub_err_printf ("error: %s\n", grub_errmsg); + grub_err_printf (_("error: %s.\n"), grub_errmsg); } while (grub_error_pop ()); diff --git a/kern/file.c b/kern/file.c index f713acbca..e17c35f95 100644 --- a/kern/file.c +++ b/kern/file.c @@ -1,7 +1,7 @@ /* file.c - file I/O functions */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2006,2007 Free Software Foundation, Inc. + * Copyright (C) 2002,2006,2007,2009 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 @@ -115,7 +115,7 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) if (file->offset > file->size) { grub_error (GRUB_ERR_OUT_OF_RANGE, - "Attempt to read past the end of file."); + "attempt to read past the end of file"); return -1; } diff --git a/kern/i386/coreboot/init.c b/kern/i386/coreboot/init.c index 550a2a60a..8defc9589 100644 --- a/kern/i386/coreboot/init.c +++ b/kern/i386/coreboot/init.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -33,8 +32,10 @@ #include #include #include -#include #include +#ifdef GRUB_MACHINE_QEMU +#include +#endif #define GRUB_FLOPPY_REG_DIGITAL_OUTPUT 0x3f2 @@ -67,12 +68,6 @@ grub_exit (void) grub_cpu_idle (); } -void -grub_arch_sync_caches (void *address __attribute__ ((unused)), - grub_size_t len __attribute__ ((unused))) -{ -} - void grub_machine_init (void) { @@ -123,7 +118,9 @@ grub_machine_init (void) return 0; } +#if defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_QEMU) grub_machine_mmap_init (); +#endif grub_machine_mmap_iterate (heap_init); grub_tsc_init (); @@ -150,6 +147,6 @@ grub_arch_modules_addr (void) #ifdef GRUB_MACHINE_QEMU return grub_core_entry_addr + grub_kernel_image_size; #else - return ALIGN_UP((grub_addr_t) _end, GRUB_MOD_ALIGN); + return ALIGN_UP((grub_addr_t) _end, GRUB_KERNEL_MACHINE_MOD_ALIGN); #endif } diff --git a/kern/i386/coreboot/mmap.c b/kern/i386/coreboot/mmap.c index b15369ee5..d06627a08 100644 --- a/kern/i386/coreboot/mmap.c +++ b/kern/i386/coreboot/mmap.c @@ -57,13 +57,23 @@ signature_found: (long) table_header->size); for (; table_item->size; table_item = (grub_linuxbios_table_item_t) ((long) table_item + (long) table_item->size)) - if (hook (table_item)) - return 1; + { + if (table_item->tag == GRUB_LINUXBIOS_MEMBER_LINK + && check_signature ((grub_linuxbios_table_header_t) (grub_addr_t) + *(grub_uint64_t *) (table_item + 1))) + { + table_header = (grub_linuxbios_table_header_t) (grub_addr_t) + *(grub_uint64_t *) (table_item + 1); + goto signature_found; + } + if (hook (table_item)) + return 1; + } return 0; } -void +grub_err_t grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)) { mem_region_t mem_region; diff --git a/kern/i386/coreboot/startup.S b/kern/i386/coreboot/startup.S index 3f2dd5f50..bcc0d14ab 100644 --- a/kern/i386/coreboot/startup.S +++ b/kern/i386/coreboot/startup.S @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include @@ -42,7 +42,7 @@ _start: * This is a special data area at a fixed offset from the beginning. */ - . = _start + GRUB_KERNEL_CPU_PREFIX + . = _start + GRUB_KERNEL_MACHINE_PREFIX VARIABLE(grub_prefix) /* to be filled by grub-mkimage */ @@ -51,7 +51,7 @@ VARIABLE(grub_prefix) * Leave some breathing room for the prefix. */ - . = _start + GRUB_KERNEL_CPU_DATA_END + . = _start + GRUB_KERNEL_MACHINE_DATA_END /* * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself). @@ -66,10 +66,12 @@ multiboot_header: .long -0x1BADB002 - MULTIBOOT_MEMORY_INFO codestart: - cmpl $MULTIBOOT_MAGIC2, %eax +#ifdef GRUB_MACHINE_MULTIBOOT + cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax jne 0f movl %ebx, EXT_C(startup_multiboot_info) 0: +#endif /* initialize the stack */ movl $GRUB_MEMORY_MACHINE_PROT_STACK, %esp diff --git a/kern/i386/dl.c b/kern/i386/dl.c index 91121f614..57854964b 100644 --- a/kern/i386/dl.c +++ b/kern/i386/dl.c @@ -1,7 +1,7 @@ /* dl-386.c - arch-dependent part of loadable module support */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2005,2007 Free Software Foundation, Inc. + * Copyright (C) 2002,2005,2007,2009 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 diff --git a/kern/i386/efi/init.c b/kern/i386/efi/init.c index e1950d758..f73f828c6 100644 --- a/kern/i386/efi/init.c +++ b/kern/i386/efi/init.c @@ -45,9 +45,3 @@ grub_machine_set_prefix (void) { grub_efi_set_prefix (); } - -void -grub_arch_sync_caches (void *address __attribute__ ((unused)), - grub_size_t len __attribute__ ((unused))) -{ -} diff --git a/kern/i386/efi/startup.S b/kern/i386/efi/startup.S index b88628010..5b464ab83 100644 --- a/kern/i386/efi/startup.S +++ b/kern/i386/efi/startup.S @@ -1,7 +1,7 @@ /* startup.S - bootstrap GRUB itself */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,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 @@ -62,3 +62,5 @@ codestart: movl %eax, EXT_C(grub_efi_system_table) call EXT_C(grub_main) ret + +#include "../realmode.S" diff --git a/kern/i386/ieee1275/init.c b/kern/i386/ieee1275/init.c index 7658ee1a7..9fb98739b 100644 --- a/kern/i386/ieee1275/init.c +++ b/kern/i386/ieee1275/init.c @@ -26,9 +26,3 @@ void grub_stop_floppy (void) { } - -void -grub_arch_sync_caches (void *address __attribute__ ((unused)), - grub_size_t len __attribute__ ((unused))) -{ -} diff --git a/kern/i386/ieee1275/startup.S b/kern/i386/ieee1275/startup.S index 35258adb6..c0a08a954 100644 --- a/kern/i386/ieee1275/startup.S +++ b/kern/i386/ieee1275/startup.S @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -43,7 +42,7 @@ _start: * This is a special data area at a fixed offset from the beginning. */ - . = _start + GRUB_KERNEL_CPU_PREFIX + . = _start + GRUB_KERNEL_MACHINE_PREFIX VARIABLE(grub_prefix) /* to be filled by grub-mkimage */ @@ -52,7 +51,7 @@ VARIABLE(grub_prefix) * Leave some breathing room for the prefix. */ - . = _start + GRUB_KERNEL_CPU_DATA_END + . = _start + GRUB_KERNEL_MACHINE_DATA_END codestart: movl %eax, EXT_C(grub_ieee1275_entry_fn) diff --git a/kern/i386/loader.S b/kern/i386/loader.S index 3e9c71327..ed57c43ca 100644 --- a/kern/i386/loader.S +++ b/kern/i386/loader.S @@ -59,7 +59,7 @@ VARIABLE(grub_linux_real_addr) VARIABLE(grub_linux_is_bzimage) .long 0 -FUNCTION(grub_linux16_boot) +FUNCTION(grub_linux16_real_boot) /* Must be done before zImage copy. */ call EXT_C(grub_dl_unload_all) diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c index ebe4bb6ea..d81b1e117 100644 --- a/kern/i386/pc/init.c +++ b/kern/i386/pc/init.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,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 @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -46,32 +47,40 @@ static int num_regions; grub_addr_t grub_os_area_addr; grub_size_t grub_os_area_size; -void -grub_arch_sync_caches (void *address __attribute__ ((unused)), - grub_size_t len __attribute__ ((unused))) -{ -} - static char * make_install_device (void) { /* XXX: This should be enough. */ - char dev[100]; + char dev[100], *ptr = dev; if (grub_prefix[0] != '(') { /* No hardcoded root partition - make it from the boot drive and the partition number encoded at the install time. */ - grub_sprintf (dev, "(%cd%u", (grub_boot_drive & 0x80) ? 'h' : 'f', - grub_boot_drive & 0x7f); + if (grub_boot_drive == GRUB_BOOT_MACHINE_PXE_DL) + { + grub_strcpy (dev, "(pxe"); + ptr += sizeof ("(pxe") - 1; + } + else + { + grub_snprintf (dev, sizeof (dev), + "(%cd%u", (grub_boot_drive & 0x80) ? 'h' : 'f', + grub_boot_drive & 0x7f); + ptr += grub_strlen (ptr); - if (grub_install_dos_part >= 0) - grub_sprintf (dev + grub_strlen (dev), ",%u", grub_install_dos_part + 1); + if (grub_install_dos_part >= 0) + grub_snprintf (ptr, sizeof (dev) - (ptr - dev), + ",%u", grub_install_dos_part + 1); + ptr += grub_strlen (ptr); - if (grub_install_bsd_part >= 0) - grub_sprintf (dev + grub_strlen (dev), ",%c", grub_install_bsd_part + 'a'); + if (grub_install_bsd_part >= 0) + grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ",%u", + grub_install_bsd_part + 1); + ptr += grub_strlen (ptr); + } - grub_sprintf (dev + grub_strlen (dev), ")%s", grub_prefix); + grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ")%s", grub_prefix); grub_strcpy (grub_prefix, dev); } diff --git a/kern/i386/pc/mmap.c b/kern/i386/pc/mmap.c index 52d8fd597..72a6b3539 100644 --- a/kern/i386/pc/mmap.c +++ b/kern/i386/pc/mmap.c @@ -20,6 +20,7 @@ #include #include #include +#include grub_err_t grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)) @@ -28,6 +29,8 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin struct grub_machine_mmap_entry *entry = (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + grub_memset (entry, 0, sizeof (entry)); + /* Check if grub_get_mmap_entry works. */ cont = grub_get_mmap_entry (entry, 0); @@ -43,6 +46,8 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin if (! cont) break; + grub_memset (entry, 0, sizeof (entry)); + cont = grub_get_mmap_entry (entry, cont); } while (entry->size); diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index 87365c0ed..374277767 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 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 @@ -53,7 +53,7 @@ #include #include -#define ABS(x) ((x) - _start + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200) +#define ABS(x) ((x) - LOCAL (base) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200) .file "startup.S" @@ -66,16 +66,15 @@ .globl start, _start start: _start: +LOCAL (base): /* * Guarantee that "main" is loaded at 0x0:0x8200. */ -#ifdef APPLE_CC - codestart_abs = ABS(codestart) - 0x10000 - ljmp $0, $(codestart_abs) +#ifdef __APPLE__ + ljmp $0, $(ABS(LOCAL (codestart)) - 0x10000) #else - ljmp $0, $ABS(codestart) + ljmp $0, $ABS(LOCAL (codestart)) #endif - /* * Compatibility version number * @@ -146,6 +145,9 @@ multiboot_entry: /* obtain the boot device */ movl 12(%ebx), %edx + movl $GRUB_MEMORY_MACHINE_PROT_STACK, %ebp + movl %ebp, %esp + /* relocate the code */ movl $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx addl EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx @@ -180,7 +182,7 @@ multiboot_trampoline: .code16 /* the real mode code continues... */ -codestart: +LOCAL (codestart): cli /* we're not safe here! */ /* set up %ds, %ss, and %es */ @@ -761,6 +763,11 @@ FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions) movw %cx, %ax movw %bx, %ds int $0x13 /* do the operation */ + jc noclean + /* Clean return value if carry isn't set to workaround + some buggy BIOSes. */ + xor %ax, %ax +noclean: movb %ah, %bl /* save return value in %bl */ /* back to protected mode */ DATA32 call real_to_prot @@ -804,6 +811,11 @@ FUNCTION(grub_biosdisk_get_diskinfo_standard) .code16 movb $0x8, %ah int $0x13 /* do the operation */ + jc noclean2 + /* Clean return value if carry isn't set to workaround + some buggy BIOSes. */ + xor %ax, %ax +noclean2: /* check if successful */ testb %ah, %ah jnz 1f @@ -1143,7 +1155,7 @@ FUNCTION(grub_console_real_putchar) */ /* this table is used in translate_keycode below */ -translation_table: +LOCAL (translation_table): .word GRUB_CONSOLE_KEY_LEFT, GRUB_TERM_LEFT .word GRUB_CONSOLE_KEY_RIGHT, GRUB_TERM_RIGHT .word GRUB_CONSOLE_KEY_UP, GRUB_TERM_UP @@ -1165,11 +1177,10 @@ translate_keycode: pushw %bx pushw %si -#ifdef APPLE_CC - translation_table_abs = ABS (translation_table) - 0x10000 - movw $(translation_table_abs), %si +#ifdef __APPLE__ + movw $(ABS(LOCAL (translation_table)) - 0x10000), %si #else - movw $ABS(translation_table), %si + movw $ABS(LOCAL (translation_table)), %si #endif 1: lodsw @@ -1433,47 +1444,6 @@ FUNCTION(grub_console_setcursor) popl %ebp ret -/* - * grub_getrtsecs() - * if a seconds value can be read, read it and return it (BCD), - * otherwise return 0xFF - * BIOS call "INT 1AH Function 02H" to check whether a character is pending - * Call with %ah = 0x2 - * Return: - * If RT Clock can give correct values - * %ch = hour (BCD) - * %cl = minutes (BCD) - * %dh = seconds (BCD) - * %dl = daylight savings time (00h std, 01h daylight) - * Carry flag = clear - * else - * Carry flag = set - * (this indicates that the clock is updating, or - * that it isn't running) - */ -FUNCTION(grub_getrtsecs) - pushl %ebp - - call prot_to_real /* enter real mode */ - .code16 - - clc - movb $0x2, %ah - int $0x1a - - DATA32 jnc gottime - movb $0xff, %dh - -gottime: - DATA32 call real_to_prot - .code32 - - movb %dh, %al - - popl %ebp - ret - - /* * grub_get_rtc() * return the real time in ticks, of which there are about @@ -1528,33 +1498,6 @@ FUNCTION(grub_vga_set_mode) popl %ebp ret - -/* - * unsigned char *grub_vga_get_font (void) - */ -FUNCTION(grub_vga_get_font) - pushl %ebp - pushl %ebx - - call prot_to_real - .code16 - movw $0x1130, %ax - movb $0x06, %bh - int $0x10 - movw %es, %bx - movw %bp, %dx - DATA32 call real_to_prot - .code32 - - movzwl %bx, %ecx - shll $4, %ecx - movw %dx, %ax - addl %ecx, %eax - - popl %ebx - popl %ebp - ret - /* * grub_vbe_bios_status_t grub_vbe_get_controller_info (struct grub_vbe_info_block *controller_info) * diff --git a/kern/i386/qemu/mmap.c b/kern/i386/qemu/mmap.c index 4ccae023a..c7fc4f45e 100644 --- a/kern/i386/qemu/mmap.c +++ b/kern/i386/qemu/mmap.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #define QEMU_CMOS_MEMSIZE_HIGH 0x35 #define QEMU_CMOS_MEMSIZE_LOW 0x34 diff --git a/kern/i386/qemu/startup.S b/kern/i386/qemu/startup.S index 7d3cb1b5e..dc40cc4a2 100644 --- a/kern/i386/qemu/startup.S +++ b/kern/i386/qemu/startup.S @@ -27,7 +27,7 @@ _start: jmp codestart - . = _start + GRUB_KERNEL_MACHINE_CORE_ENTRY_ADDR + . = _start + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR VARIABLE(grub_core_entry_addr) .long 0 VARIABLE(grub_kernel_image_size) @@ -81,7 +81,7 @@ codestart: movl $END_SYMBOL, %ecx subl %edi, %ecx #endif - + /* clean out */ xorl %eax, %eax cld diff --git a/kern/i386/realmode.S b/kern/i386/realmode.S index 424dd0eca..578c8d2a8 100644 --- a/kern/i386/realmode.S +++ b/kern/i386/realmode.S @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2009 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,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 @@ -16,6 +16,7 @@ * along with GRUB. If not, see . */ +#include /* * Note: These functions defined in this file may be called from C. @@ -127,7 +128,7 @@ real_to_prot: /* turn on protected mode */ movl %cr0, %eax - orl $GRUB_MEMORY_MACHINE_CR0_PE_ON, %eax + orl $GRUB_MEMORY_CPU_CR0_PE_ON, %eax movl %eax, %cr0 /* jump to relocation, flush prefetch queue, and reload %cs */ @@ -196,7 +197,7 @@ tmpcseg: /* clear the PE bit of CR0 */ movl %cr0, %eax - andl $(~GRUB_MEMORY_MACHINE_CR0_PE_ON), %eax + andl $(~GRUB_MEMORY_CPU_CR0_PE_ON), %eax movl %eax, %cr0 /* flush prefetch queue, reload %cs */ diff --git a/kern/ieee1275/cmain.c b/kern/ieee1275/cmain.c index c1185f82c..d3c3a8d88 100644 --- a/kern/ieee1275/cmain.c +++ b/kern/ieee1275/cmain.c @@ -20,7 +20,6 @@ #include #include #include -#include #include int (*grub_ieee1275_entry_fn) (void *); @@ -59,6 +58,7 @@ grub_ieee1275_find_options (void) char tmp[32]; int is_smartfirmware = 0; int is_olpc = 0; + int is_qemu = 0; grub_ieee1275_finddevice ("/", &root); grub_ieee1275_finddevice ("/options", &options); @@ -79,6 +79,11 @@ grub_ieee1275_find_options (void) if (rc >= 0 && !grub_strcmp (tmp, "OLPC")) is_olpc = 1; + rc = grub_ieee1275_get_property (root, "model", + tmp, sizeof (tmp), 0); + if (rc >= 0 && !grub_strcmp (tmp, "Emulated PC")) + is_qemu = 1; + if (is_smartfirmware) { /* Broken in all versions */ @@ -135,6 +140,10 @@ grub_ieee1275_find_options (void) grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY); } + if (is_qemu) + /* OpenFirmware hangs on qemu if one requests any memory below 1.5 MiB. */ + grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM); + if (! grub_ieee1275_finddevice ("/rom/boot-rom", &bootrom)) { rc = grub_ieee1275_get_property (bootrom, "model", tmp, sizeof (tmp), 0); diff --git a/kern/ieee1275/ieee1275.c b/kern/ieee1275/ieee1275.c index 37a98071c..9e2919172 100644 --- a/kern/ieee1275/ieee1275.c +++ b/kern/ieee1275/ieee1275.c @@ -1,7 +1,7 @@ /* of.c - Access the Open Firmware client interface. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2007,2008,2009 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 @@ -284,8 +284,8 @@ grub_ieee1275_read (grub_ieee1275_ihandle_t ihandle, void *buffer, } int -grub_ieee1275_seek (grub_ieee1275_ihandle_t ihandle, int pos_hi, - int pos_lo, grub_ssize_t *result) +grub_ieee1275_seek (grub_ieee1275_ihandle_t ihandle, grub_disk_addr_t pos, + grub_ssize_t *result) { struct write_args { @@ -299,8 +299,15 @@ grub_ieee1275_seek (grub_ieee1275_ihandle_t ihandle, int pos_hi, INIT_IEEE1275_COMMON (&args.common, "seek", 3, 1); args.ihandle = ihandle; - args.pos_hi = (grub_ieee1275_cell_t) pos_hi; - args.pos_lo = (grub_ieee1275_cell_t) pos_lo; + /* To prevent stupid gcc warning. */ +#if GRUB_IEEE1275_CELL_SIZEOF >= 8 + args.pos_hi = 0; + args.pos_lo = pos; +#else + args.pos_hi = (grub_ieee1275_cell_t) (pos >> (8 * GRUB_IEEE1275_CELL_SIZEOF)); + args.pos_lo = (grub_ieee1275_cell_t) + (pos & ((1ULL << (8 * GRUB_IEEE1275_CELL_SIZEOF)) - 1)); +#endif if (IEEE1275_CALL_ENTRY_FN (&args) == -1) return -1; diff --git a/kern/ieee1275/init.c b/kern/ieee1275/init.c index 5d5d733d9..b7e5c337e 100644 --- a/kern/ieee1275/init.c +++ b/kern/ieee1275/init.c @@ -1,7 +1,7 @@ /* init.c -- Initialize GRUB on the newworld mac (PPC). */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2007,2008,2009 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 @@ -29,20 +29,19 @@ #include #include #include -#include -#include #include #include +#include /* The minimal heap size we can live with. */ #define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) /* The maximum heap size we're going to claim */ -#define HEAP_MAX_SIZE (unsigned long) (4 * 1024 * 1024) +#define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) /* If possible, we will avoid claiming heap above this address, because it seems to cause relocation problems with OSes that link at 4 MiB */ -#define HEAP_MAX_ADDR (unsigned long) (4 * 1024 * 1024) +#define HEAP_MAX_ADDR (unsigned long) (32 * 1024 * 1024) extern char _start[]; extern char _end[]; @@ -75,10 +74,6 @@ grub_machine_set_prefix (void) char *filename; char *prefix; - if (grub_env_get ("prefix")) - /* We already set prefix in grub_machine_init(). */ - return; - if (grub_prefix[0]) { grub_env_set ("prefix", grub_prefix); @@ -111,11 +106,12 @@ grub_machine_set_prefix (void) *lastslash = '\0'; grub_translate_ieee1275_path (filename); - newprefix = grub_malloc (grub_strlen (prefix) - + grub_strlen (filename)); - grub_sprintf (newprefix, "%s%s", prefix, filename); - grub_free (prefix); - prefix = newprefix; + newprefix = grub_xasprintf ("%s%s", prefix, filename); + if (newprefix) + { + grub_free (prefix); + prefix = newprefix; + } } } @@ -136,6 +132,17 @@ static void grub_claim_heap (void) if (type != 1) return 0; + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM)) + { + if (addr + len <= 0x180000) + return 0; + + if (addr < 0x180000) + { + len = addr + len - 0x180000; + addr = 0x180000; + } + } len -= 1; /* Required for some firmware. */ /* Never exceed HEAP_MAX_SIZE */ @@ -164,7 +171,7 @@ static void grub_claim_heap (void) /* Claim and use it. */ if (grub_claimmap (addr, len) < 0) return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Failed to claim heap at 0x%llx, len 0x%llx\n", + "failed to claim heap at 0x%llx, len 0x%llx", addr, len); grub_mm_init_region ((void *) (grub_addr_t) addr, len); } @@ -287,5 +294,5 @@ grub_get_rtc (void) grub_addr_t grub_arch_modules_addr (void) { - return ALIGN_UP((grub_addr_t) _end + GRUB_MOD_GAP, GRUB_MOD_ALIGN); + return ALIGN_UP((grub_addr_t) _end + GRUB_KERNEL_MACHINE_MOD_GAP, GRUB_KERNEL_MACHINE_MOD_ALIGN); } diff --git a/kern/ieee1275/mmap.c b/kern/ieee1275/mmap.c index 317a12117..6f0652770 100644 --- a/kern/ieee1275/mmap.c +++ b/kern/ieee1275/mmap.c @@ -44,11 +44,11 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin /* Load `/memory/available'. */ if (grub_ieee1275_finddevice ("/memory", &memory)) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, - "Couldn't find /memory node"); + "couldn't find /memory node"); if (grub_ieee1275_get_integer_property (memory, "available", available, sizeof available, &available_size)) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, - "Couldn't examine /memory/available property"); + "couldn't examine /memory/available property"); /* Decode each entry and call `hook'. */ i = 0; diff --git a/kern/ieee1275/openfw.c b/kern/ieee1275/openfw.c index 9a2b0c9aa..5693f3be0 100644 --- a/kern/ieee1275/openfw.c +++ b/kern/ieee1275/openfw.c @@ -21,7 +21,6 @@ #include #include #include -#include #include enum grub_ieee1275_parse_type @@ -38,7 +37,7 @@ grub_children_iterate (char *devpath, grub_ieee1275_phandle_t dev; grub_ieee1275_phandle_t child; char *childtype, *childpath; - char *childname, *fullname; + char *childname; int ret = 0; if (grub_ieee1275_finddevice (devpath, &dev)) @@ -63,14 +62,6 @@ grub_children_iterate (char *devpath, grub_free (childtype); return 0; } - fullname = grub_malloc (IEEE1275_MAX_PATH_LEN); - if (!fullname) - { - grub_free (childname); - grub_free (childpath); - grub_free (childtype); - return 0; - } do { @@ -79,28 +70,31 @@ grub_children_iterate (char *devpath, if (grub_ieee1275_get_property (child, "device_type", childtype, IEEE1275_MAX_PROP_LEN, &actual)) + childtype[0] = 0; + + if (dev == child) continue; if (grub_ieee1275_package_to_path (child, childpath, IEEE1275_MAX_PATH_LEN, &actual)) continue; + if (grub_strcmp (devpath, childpath) == 0) + continue; + if (grub_ieee1275_get_property (child, "name", childname, IEEE1275_MAX_PROP_LEN, &actual)) continue; - grub_sprintf (fullname, "%s/%s", devpath, childname); - alias.type = childtype; alias.path = childpath; - alias.name = fullname; + alias.name = childname; ret = hook (&alias); if (ret) break; } - while (grub_ieee1275_peer (child, &child)); + while (grub_ieee1275_peer (child, &child) != -1); - grub_free (fullname); grub_free (childname); grub_free (childpath); grub_free (childtype); @@ -108,6 +102,20 @@ grub_children_iterate (char *devpath, return ret; } +int +grub_ieee1275_devices_iterate (int (*hook) (struct grub_ieee1275_devalias *alias)) +{ + auto int it_through (struct grub_ieee1275_devalias *alias); + int it_through (struct grub_ieee1275_devalias *alias) + { + if (hook (alias)) + return 1; + return grub_children_iterate (alias->path, it_through); + } + + return grub_children_iterate ("/", it_through); +} + /* Iterate through all device aliases. This function can be used to find a device of a specific type. */ int @@ -135,7 +143,7 @@ grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias)) /* Find the first property. */ aliasname[0] = '\0'; - while (grub_ieee1275_next_property (aliases, aliasname, aliasname)) + while (grub_ieee1275_next_property (aliases, aliasname, aliasname) > 0) { grub_ieee1275_phandle_t dev; grub_ssize_t pathlen; @@ -199,9 +207,9 @@ nextprop: } /* Call the "map" method of /chosen/mmu. */ -static int -grub_map (grub_addr_t phys, grub_addr_t virt, grub_uint32_t size, - grub_uint8_t mode) +int +grub_ieee1275_map (grub_addr_t phys, grub_addr_t virt, grub_size_t size, + grub_uint32_t mode) { struct map_args { struct grub_ieee1275_common_hdr common; @@ -210,17 +218,30 @@ grub_map (grub_addr_t phys, grub_addr_t virt, grub_uint32_t size, grub_ieee1275_cell_t mode; grub_ieee1275_cell_t size; grub_ieee1275_cell_t virt; - grub_ieee1275_cell_t phys; +#ifdef GRUB_MACHINE_SPARC64 + grub_ieee1275_cell_t phys_high; +#endif + grub_ieee1275_cell_t phys_low; grub_ieee1275_cell_t catch_result; } args; - INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 1); + INIT_IEEE1275_COMMON (&args.common, "call-method", +#ifdef GRUB_MACHINE_SPARC64 + 7, +#else + 6, +#endif + 1); args.method = (grub_ieee1275_cell_t) "map"; args.ihandle = grub_ieee1275_mmu; - args.phys = phys; +#ifdef GRUB_MACHINE_SPARC64 + args.phys_high = 0; +#endif + args.phys_low = phys; args.virt = virt; args.size = size; args.mode = mode; /* Format is WIMG0PP. */ + args.catch_result = (grub_ieee1275_cell_t) -1; if (IEEE1275_CALL_ENTRY_FN (&args) == -1) return -1; @@ -235,7 +256,7 @@ grub_claimmap (grub_addr_t addr, grub_size_t size) return -1; if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_REAL_MODE) - && grub_map (addr, addr, size, 0x00)) + && grub_ieee1275_map (addr, addr, size, 0x00)) { grub_printf ("map failed: address 0x%llx, size 0x%llx\n", (long long) addr, (long long) size); @@ -308,13 +329,13 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype) file path properly. */ if (grub_ieee1275_finddevice (device, &dev)) { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Device %s not found\n", device); + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "device %s not found", device); goto fail; } if (grub_ieee1275_get_property (dev, "device_type", &type, sizeof type, 0)) { grub_error (GRUB_ERR_UNKNOWN_DEVICE, - "Device %s lacks a device_type property\n", device); + "device %s lacks a device_type property", device); goto fail; } @@ -330,12 +351,11 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype) { char *filepath = comma + 1; - ret = grub_malloc (grub_strlen (filepath) + 1); /* Make sure filepath has leading backslash. */ if (filepath[0] != '\\') - grub_sprintf (ret, "\\%s", filepath); + ret = grub_xasprintf ("\\%s", filepath); else - grub_strcpy (ret, filepath); + ret = grub_strdup (filepath); } } else if (ptype == GRUB_PARSE_PARTITION) @@ -375,7 +395,7 @@ grub_ieee1275_encode_devname (const char *path) char *partition = grub_ieee1275_parse_args (path, GRUB_PARSE_PARTITION); char *encoding; - if (partition) + if (partition && partition[0]) { unsigned int partno = grub_strtoul (partition, 0, 0); @@ -383,15 +403,10 @@ grub_ieee1275_encode_devname (const char *path) /* GRUB partition 1 is OF partition 0. */ partno++; - /* Assume partno will require less than five bytes to encode. */ - encoding = grub_malloc (grub_strlen (device) + 3 + 5); - grub_sprintf (encoding, "(%s,%d)", device, partno); + encoding = grub_xasprintf ("(%s,%d)", device, partno); } else - { - encoding = grub_malloc (grub_strlen (device) + 2); - grub_sprintf (encoding, "(%s)", device); - } + encoding = grub_xasprintf ("(%s)", device); grub_free (partition); grub_free (device); @@ -411,8 +426,9 @@ grub_reboot (void) void grub_halt (void) { - /* Not standardized. We try both known commands. */ + /* Not standardized. We try three known commands. */ grub_ieee1275_interpret ("shut-down", 0); grub_ieee1275_interpret ("power-off", 0); + grub_ieee1275_interpret ("poweroff", 0); } diff --git a/kern/main.c b/kern/main.c index 9215d55e7..1fdf4ab07 100644 --- a/kern/main.c +++ b/kern/main.c @@ -1,7 +1,7 @@ /* main.c - the kernel main routine */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2005,2006,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2005,2006,2008,2009 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 @@ -53,6 +53,25 @@ grub_module_iterate (int (*hook) (struct grub_module_header *header)) } } +/* This is actualy platform-independant but used only on yeeloong and sparc. */ +#if defined (GRUB_MACHINE_MIPS_YEELOONG) || defined (GRUB_MACHINE_SPARC64) +grub_addr_t +grub_modules_get_end (void) +{ + struct grub_module_info *modinfo; + grub_addr_t modbase; + + modbase = grub_arch_modules_addr (); + modinfo = (struct grub_module_info *) modbase; + + /* Check if there are any modules. */ + if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC) + return modbase; + + return modbase + modinfo->size; +} +#endif + /* Load all modules in core. */ static void grub_load_modules (void) @@ -68,6 +87,9 @@ grub_load_modules (void) (header->size - sizeof (struct grub_module_header)))) grub_fatal ("%s", grub_errmsg); + if (grub_errno) + grub_print_error (); + return 0; } @@ -80,7 +102,7 @@ grub_load_config (void) auto int hook (struct grub_module_header *); int hook (struct grub_module_header *header) { - /* Not an ELF module, skip. */ + /* Not an embedded config, skip. */ if (header->type != OBJ_TYPE_CONFIG) return 0; @@ -114,7 +136,6 @@ grub_set_root_dev (void) const char *prefix; grub_register_variable_hook ("root", 0, grub_env_write_root); - grub_env_export ("root"); prefix = grub_env_get ("prefix"); @@ -159,19 +180,20 @@ grub_main (void) /* Load pre-loaded modules and free the space. */ grub_register_exported_symbols (); +#ifdef GRUB_LINKER_HAVE_INIT + grub_arch_dl_init_linker (); +#endif grub_load_modules (); /* It is better to set the root device as soon as possible, for convenience. */ grub_machine_set_prefix (); - grub_env_export ("prefix"); grub_set_root_dev (); grub_register_core_commands (); grub_register_rescue_parser (); - grub_register_rescue_reader (); grub_load_config (); grub_load_normal_mode (); - grub_reader_loop (0); + grub_rescue_run (); } diff --git a/kern/mips/cache.S b/kern/mips/cache.S new file mode 100644 index 000000000..2c35b6da2 --- /dev/null +++ b/kern/mips/cache.S @@ -0,0 +1,7 @@ + +#include + +FUNCTION (grub_cpu_flush_cache) +FUNCTION (grub_arch_sync_caches) +#include "cache_flush.S" + j $ra diff --git a/kern/mips/cache_flush.S b/kern/mips/cache_flush.S new file mode 100644 index 000000000..5667ee7b4 --- /dev/null +++ b/kern/mips/cache_flush.S @@ -0,0 +1,23 @@ + move $t2, $a0 + addu $t3, $a0, $a1 + srl $t2, $t2, 5 + sll $t2, $t2, 5 + addu $t3, $t3, 0x1f + srl $t3, $t3, 5 + sll $t3, $t3, 5 + move $t0, $t2 + subu $t1, $t3, $t2 +1: + cache 1, 0($t0) + addiu $t0, $t0, 0x1 + addiu $t1, $t1, 0xffff + bne $t1, $zero, 1b + sync + move $t0, $t2 + subu $t1, $t3, $t2 +2: + cache 0, 0($t0) + addiu $t0, $t0, 0x1 + addiu $t1, $t1, 0xffff + bne $t1, $zero, 2b + sync diff --git a/kern/mips/dl.c b/kern/mips/dl.c new file mode 100644 index 000000000..485955e7f --- /dev/null +++ b/kern/mips/dl.c @@ -0,0 +1,237 @@ +/* dl-386.c - arch-dependent part of loadable module support */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2007,2009 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 . + */ + +#include +#include +#include +#include +#include +#include + +/* Dummy __gnu_local_gp. Resolved by linker. */ +static char __gnu_local_gp_dummy; + +/* Check if EHDR is a valid ELF header. */ +grub_err_t +grub_arch_dl_check_header (void *ehdr) +{ + Elf_Ehdr *e = ehdr; + + /* Check the magic numbers. */ +#ifdef WORDS_BIGENDIAN + if (e->e_ident[EI_CLASS] != ELFCLASS32 + || e->e_ident[EI_DATA] != ELFDATA2MSB + || e->e_machine != EM_MIPS) +#else + if (e->e_ident[EI_CLASS] != ELFCLASS32 + || e->e_ident[EI_DATA] != ELFDATA2LSB + || e->e_machine != EM_MIPS) +#endif + return grub_error (GRUB_ERR_BAD_OS, "invalid arch specific ELF magic"); + + return GRUB_ERR_NONE; +} + +/* Relocate symbols. */ +grub_err_t +grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) +{ + Elf_Ehdr *e = ehdr; + Elf_Shdr *s; + Elf_Word entsize; + unsigned i; + grub_size_t gp_size = 0; + /* FIXME: suboptimal. */ + grub_uint32_t *gp, *gpptr; + grub_uint32_t gp0; + + /* Find a symbol table. */ + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_SYMTAB) + break; + + if (i == e->e_shnum) + return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found"); + + entsize = s->sh_entsize; + + /* Find reginfo. */ + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_MIPS_REGINFO) + break; + + if (i == e->e_shnum) + return grub_error (GRUB_ERR_BAD_MODULE, "no reginfo found"); + + gp0 = ((grub_uint32_t *)((char *) e + s->sh_offset))[5]; + + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_REL) + { + grub_dl_segment_t seg; + + /* Find the target segment. */ + for (seg = mod->segment; seg; seg = seg->next) + if (seg->section == s->sh_info) + break; + + if (seg) + { + Elf_Rel *rel, *max; + + for (rel = (Elf_Rel *) ((char *) e + s->sh_offset), + max = rel + s->sh_size / s->sh_entsize; + rel < max; + rel++) + switch (ELF_R_TYPE (rel->r_info)) + { + case R_MIPS_GOT16: + case R_MIPS_CALL16: + case R_MIPS_GPREL32: + gp_size += 4; + break; + } + } + } + + if (gp_size > 0x08000) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "__gnu_local_gp is too big\n"); + + gpptr = gp = grub_malloc (gp_size); + if (!gp) + return grub_errno; + + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_REL) + { + grub_dl_segment_t seg; + + /* Find the target segment. */ + for (seg = mod->segment; seg; seg = seg->next) + if (seg->section == s->sh_info) + break; + + if (seg) + { + Elf_Rel *rel, *max; + + for (rel = (Elf_Rel *) ((char *) e + s->sh_offset), + max = rel + s->sh_size / s->sh_entsize; + rel < max; + rel++) + { + Elf_Word *addr; + Elf_Sym *sym; + + if (seg->size < rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, + "reloc offset is out of the segment"); + + addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset); + sym = (Elf_Sym *) ((char *) mod->symtab + + entsize * ELF_R_SYM (rel->r_info)); + if (sym->st_value == (grub_addr_t) &__gnu_local_gp_dummy) + sym->st_value = (grub_addr_t) gp; + + switch (ELF_R_TYPE (rel->r_info)) + { + case R_MIPS_HI16: + { + grub_uint32_t value; + Elf_Rel *rel2; + + /* Handle partner lo16 relocation. Lower part is + treated as signed. Hence add 0x8000 to compensate. + */ + value = (*(grub_uint16_t *) addr << 16) + + sym->st_value + 0x8000; + for (rel2 = rel + 1; rel2 < max; rel2++) + if (ELF_R_SYM (rel2->r_info) + == ELF_R_SYM (rel->r_info) + && ELF_R_TYPE (rel2->r_info) == R_MIPS_LO16) + { + value += *(grub_int16_t *) + ((char *) seg->addr + rel2->r_offset); + break; + } + *(grub_uint16_t *) addr = (value >> 16) & 0xffff; + } + break; + case R_MIPS_LO16: + *(grub_uint16_t *) addr += (sym->st_value) & 0xffff; + break; + case R_MIPS_32: + *(grub_uint32_t *) addr += sym->st_value; + break; + case R_MIPS_GPREL32: + *(grub_uint32_t *) addr = sym->st_value + + *(grub_uint32_t *) addr + gp0 - (grub_uint32_t)gp; + break; + + case R_MIPS_26: + { + grub_uint32_t value; + grub_uint32_t raw; + raw = (*(grub_uint32_t *) addr) & 0x3ffffff; + value = raw << 2; + value += sym->st_value; + raw = (value >> 2) & 0x3ffffff; + + *(grub_uint32_t *) addr = + raw | ((*(grub_uint32_t *) addr) & 0xfc000000); + } + break; + case R_MIPS_GOT16: + case R_MIPS_CALL16: + /* FIXME: reuse*/ + *gpptr = sym->st_value + *(grub_uint16_t *) addr; + *(grub_uint16_t *) addr + = sizeof (grub_uint32_t) * (gpptr - gp); + gpptr++; + break; + default: + { + grub_free (gp); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unknown relocation type %d\n", + ELF_R_TYPE (rel->r_info)); + } + break; + } + } + } + } + + return GRUB_ERR_NONE; +} + +void +grub_arch_dl_init_linker (void) +{ + grub_dl_register_symbol ("__gnu_local_gp", &__gnu_local_gp_dummy, 0); +} + diff --git a/kern/mips/init.c b/kern/mips/init.c new file mode 100644 index 000000000..f220108d4 --- /dev/null +++ b/kern/mips/init.c @@ -0,0 +1,34 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include + +void +grub_machine_set_prefix (void) +{ + grub_env_set ("prefix", grub_prefix); +} + +extern char _end[]; + +grub_addr_t +grub_arch_modules_addr (void) +{ + return (grub_addr_t) _end; +} diff --git a/kern/mips/qemu-mips/init.c b/kern/mips/qemu-mips/init.c new file mode 100644 index 000000000..866c7a82a --- /dev/null +++ b/kern/mips/qemu-mips/init.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RAMSIZE (*(grub_uint32_t *) ((16 << 20) - 264)) + +grub_uint32_t +grub_get_rtc (void) +{ + static int calln = 0; + return calln++; +} + +void +grub_machine_init (void) +{ + grub_mm_init_region ((void *) GRUB_MACHINE_MEMORY_USABLE, + RAMSIZE - (GRUB_MACHINE_MEMORY_USABLE & 0x7fffffff)); + grub_install_get_time_ms (grub_rtc_get_time_ms); +} + +void +grub_machine_fini (void) +{ +} + +void +grub_exit (void) +{ + while (1); +} + +void +grub_halt (void) +{ + while (1); +} + +void +grub_reboot (void) +{ + while (1); +} + +grub_err_t +grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, + grub_uint64_t, + grub_uint32_t)) +{ + hook (0, RAMSIZE, + GRUB_MACHINE_MEMORY_AVAILABLE); + return GRUB_ERR_NONE; +} diff --git a/kern/mips/startup.S b/kern/mips/startup.S new file mode 100644 index 000000000..1d18131be --- /dev/null +++ b/kern/mips/startup.S @@ -0,0 +1,219 @@ +/* startup.S - Startup code for the MIPS. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include +#include +#include + +#define BASE_ADDR 8 + +.extern __bss_start +.extern _end + + .globl __start, _start, start +__start: +_start: +start: + bal codestart +base: + . = _start + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE +compressed_size: + .long 0 + . = _start + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE +total_module_size: + .long 0 + . = _start + GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE +kernel_image_size: + .long 0 +codestart: + /* Save our base. */ + move $s0, $ra + + /* Parse arguments. Has to be done before relocation. + So need to do it in asm. */ +#ifdef GRUB_MACHINE_MIPS_YEELOONG + /* $a2 has the environment. */ + move $t0, $a2 +argcont: + lw $t1, 0($t0) + beq $t1, $zero, argdone +#define DO_PARSE(str, reg) \ + addiu $t2, $s0, (str-base);\ + bal parsestr;\ + beq $v0, $zero, 1f;\ + move reg, $v0;\ + b 2f;\ +1: + DO_PARSE (busclockstr, $s2) + DO_PARSE (cpuclockstr, $s3) + DO_PARSE (memsizestr, $s4) + DO_PARSE (highmemsizestr, $s5) +2: + addiu $t0, $t0, 4 + b argcont +parsestr: + move $v0, $zero + move $t3, $t1 +3: + lb $t4, 0($t2) + lb $t5, 0($t3) + addiu $t2, $t2, 1 + addiu $t3, $t3, 1 + beq $t5, $zero, 1f + beq $t5, $t4, 3b + bne $t4, $zero, 1f + + addiu $t3, $t3, 0xffff +digcont: + lb $t5, 0($t3) + /* Substract '0' from digit. */ + addiu $t5, $t5, 0xffd0 + bltz $t5, 1f + addiu $t4, $t5, 0xfff7 + bgtz $t4, 1f + /* Multiply $v0 by 10 with bitshifts. */ + sll $v0, $v0, 1 + sll $t4, $v0, 2 + addu $v0, $v0, $t4 + addu $v0, $v0, $t5 + addiu $t3, $t3, 1 + b digcont +1: + jr $ra +busclockstr: .asciiz "busclock=" +cpuclockstr: .asciiz "cpuclock=" +memsizestr: .asciiz "memsize=" +highmemsizestr: .asciiz "highmemsize=" + .p2align 2 +argdone: +#endif + + /* Decompress the payload. */ + addiu $a0, $s0, GRUB_KERNEL_MACHINE_RAW_SIZE - BASE_ADDR + lui $a1, %hi(compressed) + addiu $a1, %lo(compressed) + lw $a2, (GRUB_KERNEL_MACHINE_COMPRESSED_SIZE - BASE_ADDR)($s0) + move $s1, $a1 + + /* $a0 contains source compressed address, $a1 is destination, + $a2 is compressed size. FIXME: put LZMA here. Don't clober $s0, + $s1, $s2, $s3, $s4 and $s5. + On return $v0 contains uncompressed size. + */ + move $v0, $a2 +reloccont: + lb $t4, 0($a0) + sb $t4, 0($a1) + addiu $a1,$a1,1 + addiu $a0,$a0,1 + addiu $a2, 0xffff + bne $a2, $0, reloccont + + move $a0, $s1 + move $a1, $v0 + +#include "cache_flush.S" + + lui $t1, %hi(cont) + addiu $t1, %lo(cont) + + jr $t1 + . = _start + GRUB_KERNEL_MACHINE_RAW_SIZE +compressed: + . = _start + GRUB_KERNEL_MACHINE_PREFIX + +VARIABLE(grub_prefix) + + /* to be filled by grub-mkelfimage */ + + /* + * Leave some breathing room for the prefix. + */ + + . = _start + GRUB_KERNEL_MACHINE_DATA_END +#ifdef GRUB_MACHINE_MIPS_YEELOONG +VARIABLE (grub_arch_busclock) + .long 0 +VARIABLE (grub_arch_cpuclock) + .long 0 +VARIABLE (grub_arch_memsize) + .long 0 +VARIABLE (grub_arch_highmemsize) + .long 0 +#endif +cont: + +#ifdef GRUB_MACHINE_MIPS_YEELOONG + lui $t1, %hi(grub_arch_busclock) + addiu $t1, %lo(grub_arch_busclock) + sw $s2, 0($t1) + sw $s3, 4($t1) + sw $s4, 8($t1) + sw $s5, 12($t1) +#endif + + /* Move the modules out of BSS. */ + lui $t1, %hi(_start) + addiu $t1, %lo(_start) + lw $t2, (GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE - BASE_ADDR)($s0) + addu $t2, $t1, $t2 + + lui $t1, %hi(_end) + addiu $t1, %lo(_end) + addiu $t1, (GRUB_KERNEL_MACHINE_MOD_ALIGN-1) + li $t3, (GRUB_KERNEL_MACHINE_MOD_ALIGN-1) + nor $t3, $t3, $0 + and $t1, $t1, $t3 + + lw $t3, (GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE - BASE_ADDR)($s0) + + /* Backward copy. */ + add $t1, $t1, $t3 + add $t2, $t2, $t3 + addiu $t1, $t1, 0xffff + addiu $t2, $t2, 0xffff + + /* $t2 is source. $t1 is destination. $t3 is size. */ +modulesmovcont: + lb $t4, 0($t2) + sb $t4, 0($t1) + addiu $t1,$t1,0xffff + addiu $t2,$t2,0xffff + addiu $t3, 0xffff + bne $t3, $0, modulesmovcont + + /* Clean BSS. */ + + lui $t1, %hi(__bss_start) + addiu $t1, %lo(__bss_start) + lui $t2, %hi(_end) + addiu $t2, %lo(_end) +bsscont: + sb $0,0($t1) + addiu $t1,$t1,1 + sltu $t3,$t1,$t2 + bne $t3, $0, bsscont + + li $sp, GRUB_MACHINE_MEMORY_STACK_HIGH + lui $t1, %hi(grub_main) + addiu $t1, %lo(grub_main) + + jr $t1 + diff --git a/kern/mips/yeeloong/init.c b/kern/mips/yeeloong/init.c new file mode 100644 index 000000000..47aa774a0 --- /dev/null +++ b/kern/mips/yeeloong/init.c @@ -0,0 +1,108 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void grub_video_sm712_init (void); +extern void grub_video_init (void); +extern void grub_bitmap_init (void); +extern void grub_font_init (void); +extern void grub_gfxterm_init (void); +extern void grub_at_keyboard_init (void); + +/* FIXME: use interrupt to count high. */ +grub_uint64_t +grub_get_rtc (void) +{ + static grub_uint32_t high = 0; + static grub_uint32_t last = 0; + grub_uint32_t low; + + asm volatile ("mfc0 %0, $9": "=r" (low)); + if (low < last) + high++; + last = low; + + return (((grub_uint64_t) high) << 32) | low; +} + +grub_err_t +grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, + grub_uint64_t, + grub_uint32_t)) +{ + hook (GRUB_ARCH_LOWMEMPSTART, grub_arch_memsize << 20, + GRUB_MACHINE_MEMORY_AVAILABLE); + hook (GRUB_ARCH_HIGHMEMPSTART, grub_arch_highmemsize << 20, + GRUB_MACHINE_MEMORY_AVAILABLE); + return GRUB_ERR_NONE; +} + +void +grub_machine_init (void) +{ + grub_addr_t modend; + modend = grub_modules_get_end (); + grub_mm_init_region ((void *) modend, (grub_arch_memsize << 20) + - (modend - GRUB_ARCH_LOWMEMVSTART)); + /* FIXME: use upper memory as well. */ + grub_install_get_time_ms (grub_rtc_get_time_ms); + + /* Initialize output terminal (can't be done earlier, as gfxterm + relies on a working heap. */ + grub_video_sm712_init (); + grub_video_init (); + grub_bitmap_init (); + grub_font_init (); + grub_gfxterm_init (); + + grub_at_keyboard_init (); +} + +void +grub_machine_fini (void) +{ +} + +void +grub_exit (void) +{ + while (1); +} + +void +grub_halt (void) +{ + while (1); +} + +void +grub_reboot (void) +{ + while (1); +} + diff --git a/kern/misc.c b/kern/misc.c index 4415b8204..ccc01d43f 100644 --- a/kern/misc.c +++ b/kern/misc.c @@ -1,7 +1,7 @@ /* misc.c - definitions of misc functions */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,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 @@ -25,6 +25,9 @@ #include #include +static int +grub_vsnprintf_real (char *str, grub_size_t n, const char *fmt, va_list args); + static int grub_iswordseparator (int c) { @@ -32,7 +35,7 @@ grub_iswordseparator (int c) } /* grub_gettext_dummy is not translating anything. */ -const char * +static const char * grub_gettext_dummy (const char *s) { return s; @@ -139,6 +142,25 @@ grub_printf_ (const char *fmt, ...) return ret; } +int +grub_puts (const char *s) +{ + while (*s) + { + grub_putchar (*s); + s++; + } + grub_putchar ('\n'); + + return 1; /* Cannot fail. */ +} + +int +grub_puts_ (const char *s) +{ + return grub_puts (_(s)); +} + #if defined (APPLE_CC) && ! defined (GRUB_UTIL) int grub_err_printf (const char *fmt, ...) @@ -183,8 +205,7 @@ grub_vprintf (const char *fmt, va_list args) { int ret; - ret = grub_vsprintf (0, fmt, args); - grub_refresh (); + ret = grub_vsnprintf_real (0, 0, fmt, args); return ret; } @@ -208,6 +229,11 @@ grub_memcmp (const void *s1, const void *s2, grub_size_t n) #ifndef APPLE_CC int memcmp (const void *s1, const void *s2, grub_size_t n) __attribute__ ((alias ("grub_memcmp"))); +#else +int memcmp (const void *s1, const void *s2, grub_size_t n) +{ + return grub_memcmp (s1, s2, n); +} #endif int @@ -493,6 +519,11 @@ grub_memset (void *s, int c, grub_size_t n) #ifndef APPLE_CC void *memset (void *s, int c, grub_size_t n) __attribute__ ((alias ("grub_memset"))); +#else +void *memset (void *s, int c, grub_size_t n) +{ + return grub_memset (s, c, n); +} #endif grub_size_t @@ -607,11 +638,11 @@ grub_lltoa (char *str, int c, unsigned long long n) return p; } -int -grub_vsprintf (char *str, const char *fmt, va_list args) +static int +grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt, va_list args) { char c; - int count = 0; + grub_size_t count = 0; auto void write_char (unsigned char ch); auto void write_str (const char *s); auto void write_fill (const char ch, int n); @@ -619,7 +650,10 @@ grub_vsprintf (char *str, const char *fmt, va_list args) void write_char (unsigned char ch) { if (str) - *str++ = ch; + { + if (count < max_len) + *str++ = ch; + } else grub_putchar (ch); @@ -841,94 +875,80 @@ grub_vsprintf (char *str, const char *fmt, va_list args) if (str) *str = '\0'; - if (count && !str) - grub_refresh (); - return count; } int -grub_sprintf (char *str, const char *fmt, ...) +grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list ap) +{ + grub_size_t ret; + + if (!n) + return 0; + + n--; + + ret = grub_vsnprintf_real (str, n, fmt, ap); + + return ret < n ? ret : n; +} + +int +grub_snprintf (char *str, grub_size_t n, const char *fmt, ...) { va_list ap; int ret; va_start (ap, fmt); - ret = grub_vsprintf (str, fmt, ap); + ret = grub_vsnprintf (str, n, fmt, ap); va_end (ap); return ret; } -/* Convert UTF-16 to UTF-8. */ -grub_uint8_t * -grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src, - grub_size_t size) +#define PREALLOC_SIZE 255 + +char * +grub_xvasprintf (const char *fmt, va_list ap) { - grub_uint32_t code_high = 0; + grub_size_t s, as = PREALLOC_SIZE; + char *ret; - while (size--) + while (1) { - grub_uint32_t code = *src++; + ret = grub_malloc (as + 1); + if (!ret) + return NULL; - if (code_high) - { - if (code >= 0xDC00 && code <= 0xDFFF) - { - /* Surrogate pair. */ - code = ((code_high - 0xD800) << 12) + (code - 0xDC00) + 0x10000; + s = grub_vsnprintf_real (ret, as, fmt, ap); + if (s <= as) + return ret; - *dest++ = (code >> 18) | 0xF0; - *dest++ = ((code >> 12) & 0x3F) | 0x80; - *dest++ = ((code >> 6) & 0x3F) | 0x80; - *dest++ = (code & 0x3F) | 0x80; - } - else - { - /* Error... */ - *dest++ = '?'; - } - - code_high = 0; - } - else - { - if (code <= 0x007F) - *dest++ = code; - else if (code <= 0x07FF) - { - *dest++ = (code >> 6) | 0xC0; - *dest++ = (code & 0x3F) | 0x80; - } - else if (code >= 0xD800 && code <= 0xDBFF) - { - code_high = code; - continue; - } - else if (code >= 0xDC00 && code <= 0xDFFF) - { - /* Error... */ - *dest++ = '?'; - } - else - { - *dest++ = (code >> 12) | 0xE0; - *dest++ = ((code >> 6) & 0x3F) | 0x80; - *dest++ = (code & 0x3F) | 0x80; - } - } + grub_free (ret); + as = s; } +} - return dest; +char * +grub_xasprintf (const char *fmt, ...) +{ + va_list ap; + char *ret; + + va_start (ap, fmt); + ret = grub_xvasprintf (fmt, ap); + va_end (ap); + + return ret; } /* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE bytes (if SRCSIZE is -1, it is ignored) in length to a UCS-4 string. Return the number of characters converted. DEST must be able to hold - at least DESTSIZE characters. If an invalid sequence is found, return -1. + at least DESTSIZE characters. If SRCEND is not NULL, then *SRCEND is set to the next byte after the last byte used in SRC. */ -grub_ssize_t +grub_size_t grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, const grub_uint8_t *src, grub_size_t srcsize, const grub_uint8_t **srcend) @@ -950,7 +970,12 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, if ((c & 0xc0) != 0x80) { /* invalid */ - return -1; + code = '?'; + /* Character c may be valid, don't eat it. */ + src--; + if (srcsize != (grub_size_t)-1) + srcsize++; + count = 0; } else { @@ -992,7 +1017,11 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, code = c & 0x01; } else - return -1; + { + /* invalid */ + code = '?'; + count = 0; + } } if (count == 0) @@ -1011,15 +1040,14 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, void grub_abort (void) { - if (grub_term_get_current_output ()) + grub_printf ("\nAborted."); + +#ifndef GRUB_UTIL + if (grub_term_inputs) +#endif { - grub_printf ("\nAborted."); - - if (grub_term_get_current_input ()) - { - grub_printf (" Press any key to exit."); - grub_getkey (); - } + grub_printf (" Press any key to exit."); + grub_getkey (); } grub_exit (); @@ -1030,7 +1058,7 @@ grub_abort (void) void abort (void) __attribute__ ((alias ("grub_abort"))); #endif -#ifdef NEED_ENABLE_EXECUTE_STACK +#if defined(NEED_ENABLE_EXECUTE_STACK) && !defined(GRUB_UTIL) /* Some gcc versions generate a call to this function in trampolines for nested functions. */ void __enable_execute_stack (void *addr __attribute__ ((unused))) @@ -1038,3 +1066,12 @@ void __enable_execute_stack (void *addr __attribute__ ((unused))) } #endif +#if defined (NEED_REGISTER_FRAME_INFO) && !defined(GRUB_UTIL) +void __register_frame_info (void) +{ +} + +void __deregister_frame_info (void) +{ +} +#endif diff --git a/kern/mm.c b/kern/mm.c index cbcb99560..47324a662 100644 --- a/kern/mm.c +++ b/kern/mm.c @@ -1,7 +1,7 @@ /* mm.c - functions for memory manager */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2005,2007,2008,2009 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 @@ -148,15 +148,14 @@ grub_mm_init_region (void *addr, grub_size_t size) grub_printf ("Using memory for heap: start=%p, end=%p\n", addr, addr + (unsigned int) size); #endif - /* If this region is too small, ignore it. */ - if (size < GRUB_MM_ALIGN * 2) - return; - /* Allocate a region from the head. */ - r = (grub_mm_region_t) (((grub_addr_t) addr + GRUB_MM_ALIGN - 1) - & (~(GRUB_MM_ALIGN - 1))); + r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); size -= (char *) r - (char *) addr + sizeof (*r); + /* If this region is too small, ignore it. */ + if (size < GRUB_MM_ALIGN) + return; + h = (grub_mm_header_t) ((char *) r + GRUB_MM_ALIGN); h->next = h; h->magic = GRUB_MM_FREE_MAGIC; @@ -221,9 +220,8 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) +---------------+ v */ q->next = p->next; - p->magic = GRUB_MM_ALLOC_MAGIC; } - else if (extra == 0 || p->size == n + extra) + else if (align == 1 || p->size == n + extra) { /* There might be alignment requirement, when taking it into account memory block fits in. @@ -240,10 +238,25 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) | alloc, size=n | | +---------------+ v */ + p->size -= n; p += p->size; - p->size = n; - p->magic = GRUB_MM_ALLOC_MAGIC; + } + else if (extra == 0) + { + grub_mm_header_t r; + + r = p + extra + n; + r->magic = GRUB_MM_FREE_MAGIC; + r->size = p->size - extra - n; + r->next = p->next; + q->next = r; + + if (q == p) + { + q = r; + r->next = r; + } } else { @@ -276,10 +289,11 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) p->size = extra; p->next = r; p += extra; - p->size = n; - p->magic = GRUB_MM_ALLOC_MAGIC; } + p->magic = GRUB_MM_ALLOC_MAGIC; + p->size = n; + /* Mark find as a start marker for next allocation to fasten it. This will have side effect of fragmenting memory as small pieces before this will be un-used. */ @@ -388,7 +402,7 @@ grub_free (void *ptr) do { grub_printf ("%s:%d: q=%p, q->size=0x%x, q->magic=0x%x\n", - __FILE__, __LINE__, q, q->size, q->magic); + GRUB_FILE, __LINE__, q, q->size, q->magic); q = q->next; } while (q != r->first); diff --git a/kern/parser.c b/kern/parser.c index db59af056..07597a1a8 100644 --- a/kern/parser.c +++ b/kern/parser.c @@ -26,32 +26,31 @@ /* All the possible state transitions on the command line. If a transition can not be found, it is assumed that there is no transition and keep_value is assumed to be 1. */ -static struct grub_parser_state_transition state_transitions[] = -{ - { GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_QUOTE, '\'', 0}, - { GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_DQUOTE, '\"', 0}, - { GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_VAR, '$', 0}, - { GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_ESC, '\\', 0}, +static struct grub_parser_state_transition state_transitions[] = { + {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_QUOTE, '\'', 0}, + {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_DQUOTE, '\"', 0}, + {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_VAR, '$', 0}, + {GRUB_PARSER_STATE_TEXT, GRUB_PARSER_STATE_ESC, '\\', 0}, - { GRUB_PARSER_STATE_ESC, GRUB_PARSER_STATE_TEXT, 0, 1}, + {GRUB_PARSER_STATE_ESC, GRUB_PARSER_STATE_TEXT, 0, 1}, - { GRUB_PARSER_STATE_QUOTE, GRUB_PARSER_STATE_TEXT, '\'', 0}, + {GRUB_PARSER_STATE_QUOTE, GRUB_PARSER_STATE_TEXT, '\'', 0}, - { GRUB_PARSER_STATE_DQUOTE, GRUB_PARSER_STATE_TEXT, '\"', 0}, - { GRUB_PARSER_STATE_DQUOTE, GRUB_PARSER_STATE_QVAR, '$', 0}, + {GRUB_PARSER_STATE_DQUOTE, GRUB_PARSER_STATE_TEXT, '\"', 0}, + {GRUB_PARSER_STATE_DQUOTE, GRUB_PARSER_STATE_QVAR, '$', 0}, - { GRUB_PARSER_STATE_VAR, GRUB_PARSER_STATE_VARNAME2, '{', 0}, - { GRUB_PARSER_STATE_VAR, GRUB_PARSER_STATE_VARNAME, 0, 1}, - { GRUB_PARSER_STATE_VARNAME, GRUB_PARSER_STATE_TEXT, ' ', 1}, - { GRUB_PARSER_STATE_VARNAME2, GRUB_PARSER_STATE_TEXT, '}', 0}, + {GRUB_PARSER_STATE_VAR, GRUB_PARSER_STATE_VARNAME2, '{', 0}, + {GRUB_PARSER_STATE_VAR, GRUB_PARSER_STATE_VARNAME, 0, 1}, + {GRUB_PARSER_STATE_VARNAME, GRUB_PARSER_STATE_TEXT, ' ', 1}, + {GRUB_PARSER_STATE_VARNAME2, GRUB_PARSER_STATE_TEXT, '}', 0}, - { GRUB_PARSER_STATE_QVAR, GRUB_PARSER_STATE_QVARNAME2, '{', 0}, - { GRUB_PARSER_STATE_QVAR, GRUB_PARSER_STATE_QVARNAME, 0, 1}, - { GRUB_PARSER_STATE_QVARNAME, GRUB_PARSER_STATE_TEXT, '\"', 0}, - { GRUB_PARSER_STATE_QVARNAME, GRUB_PARSER_STATE_DQUOTE, ' ', 1}, - { GRUB_PARSER_STATE_QVARNAME2, GRUB_PARSER_STATE_DQUOTE, '}', 0}, + {GRUB_PARSER_STATE_QVAR, GRUB_PARSER_STATE_QVARNAME2, '{', 0}, + {GRUB_PARSER_STATE_QVAR, GRUB_PARSER_STATE_QVARNAME, 0, 1}, + {GRUB_PARSER_STATE_QVARNAME, GRUB_PARSER_STATE_TEXT, '\"', 0}, + {GRUB_PARSER_STATE_QVARNAME, GRUB_PARSER_STATE_DQUOTE, ' ', 1}, + {GRUB_PARSER_STATE_QVARNAME2, GRUB_PARSER_STATE_DQUOTE, '}', 0}, - { 0, 0, 0, 0} + {0, 0, 0, 0} }; @@ -74,17 +73,17 @@ grub_parser_cmdline_state (grub_parser_state_t state, char c, char *result) if (transition->input == c) break; - if (transition->input == ' ' && ! grub_isalpha (c) - && ! grub_isdigit (c) && c != '_') + if (transition->input == ' ' && !grub_isalpha (c) + && !grub_isdigit (c) && c != '_') break; /* A less perfect match was found, use this one if no exact - match can be found. */ + match can be found. */ if (transition->input == 0) break; } - if (! transition->from_state) + if (!transition->from_state) transition = &default_transition; if (transition->keep_value) @@ -113,45 +112,49 @@ grub_parser_split_cmdline (const char *cmdline, grub_reader_getline_t getline, auto int check_varstate (grub_parser_state_t s); int check_varstate (grub_parser_state_t s) - { - return (s == GRUB_PARSER_STATE_VARNAME - || s == GRUB_PARSER_STATE_VARNAME2 - || s == GRUB_PARSER_STATE_QVARNAME - || s == GRUB_PARSER_STATE_QVARNAME2); - } + { + return (s == GRUB_PARSER_STATE_VARNAME + || s == GRUB_PARSER_STATE_VARNAME2 + || s == GRUB_PARSER_STATE_QVARNAME + || s == GRUB_PARSER_STATE_QVARNAME2); + } auto void add_var (grub_parser_state_t newstate); void add_var (grub_parser_state_t newstate) - { - char *val; + { + char *val; - /* Check if a variable was being read in and the end of the name - was reached. */ - if (! (check_varstate (state) && !check_varstate (newstate))) - return; + /* Check if a variable was being read in and the end of the name + was reached. */ + if (!(check_varstate (state) && !check_varstate (newstate))) + return; - *(vp++) = '\0'; - val = grub_env_get (varname); - vp = varname; - if (! val) - return; + *(vp++) = '\0'; + val = grub_env_get (varname); + vp = varname; + if (!val) + return; - /* Insert the contents of the variable in the buffer. */ - for (; *val; val++) - *(bp++) = *val; - } + /* Insert the contents of the variable in the buffer. */ + for (; *val; val++) + *(bp++) = *val; + } - *argc = 1; + *argc = 0; do { - if (! *rd) + if (!rd || !*rd) { if (getline) getline (&rd, 1); - else break; + else + break; } + if (!rd) + break; + for (; *rd; rd++) { grub_parser_state_t newstate; @@ -187,22 +190,27 @@ grub_parser_split_cmdline (const char *cmdline, grub_reader_getline_t getline, } state = newstate; } - } while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state)); - *(bp++) = '\0'; + } + while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state)); /* A special case for when the last character was part of a variable. */ add_var (GRUB_PARSER_STATE_TEXT); + if (bp != buffer && *(bp - 1)) + { + *(bp++) = '\0'; + (*argc)++; + } /* Reserve memory for the return values. */ args = grub_malloc (bp - buffer); - if (! args) + if (!args) return grub_errno; grub_memcpy (args, buffer, bp - buffer); *argv = grub_malloc (sizeof (char *) * (*argc + 1)); - if (! *argv) + if (!*argv) { grub_free (args); return grub_errno; @@ -219,40 +227,36 @@ grub_parser_split_cmdline (const char *cmdline, grub_reader_getline_t getline, bp++; } - (*argc)--; - return 0; } -struct grub_handler_class grub_parser_class = - { - .name = "parser" - }; +struct grub_handler_class grub_parser_class = { + .name = "parser" +}; grub_err_t grub_parser_execute (char *source) { auto grub_err_t getline (char **line, int cont); grub_err_t getline (char **line, int cont __attribute__ ((unused))) - { - char *p; + { + char *p; - if (! source) - { - *line = 0; - return 0; - } + if (!source) + { + *line = 0; + return 0; + } - p = grub_strchr (source, '\n'); - if (p) - *p = 0; + p = grub_strchr (source, '\n'); + if (p) + *line = grub_strndup (source, p - source); + else *line = grub_strdup (source); - if (p) - *p = '\n'; - source = p ? p + 1 : 0; - return 0; - } + source = p ? p + 1 : 0; + return 0; + } while (source) { diff --git a/kern/partition.c b/kern/partition.c index 4d5c63a95..2a33ac329 100644 --- a/kern/partition.c +++ b/kern/partition.c @@ -17,40 +17,44 @@ */ #include +#include #include #include -static grub_partition_map_t grub_partition_map_list; +grub_partition_map_t grub_partition_map_list; -void -grub_partition_map_register (grub_partition_map_t partmap) +static grub_partition_t +grub_partition_map_probe (const grub_partition_map_t partmap, + grub_disk_t disk, int partnum) { - partmap->next = grub_partition_map_list; - grub_partition_map_list = partmap; -} + grub_partition_t p = 0; -void -grub_partition_map_unregister (grub_partition_map_t partmap) -{ - grub_partition_map_t *p, q; + auto int find_func (grub_disk_t d, const grub_partition_t partition); - for (p = &grub_partition_map_list, q = *p; q; p = &(q->next), q = q->next) - if (q == partmap) - { - *p = q->next; - break; - } -} + int find_func (grub_disk_t d __attribute__ ((unused)), + const grub_partition_t partition) + { + if (partnum == partition->number) + { + p = (grub_partition_t) grub_malloc (sizeof (*p)); + if (! p) + return 1; -int -grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap)) -{ - grub_partition_map_t p; + grub_memcpy (p, partition, sizeof (*p)); + return 1; + } - for (p = grub_partition_map_list; p; p = p->next) - if (hook (p)) - return 1; + return 0; + } + partmap->iterate (disk, find_func); + if (grub_errno) + goto fail; + + return p; + + fail: + grub_free (p); return 0; } @@ -58,28 +62,66 @@ grub_partition_t grub_partition_probe (struct grub_disk *disk, const char *str) { grub_partition_t part = 0; + grub_partition_t curpart = 0; + grub_partition_t tail; + const char *ptr; - auto int part_map_probe (const grub_partition_map_t partmap); + part = tail = disk->partition; - int part_map_probe (const grub_partition_map_t partmap) + for (ptr = str; *ptr;) { - part = partmap->probe (disk, str); - if (part) - return 1; + grub_partition_map_t partmap; + int num; + const char *partname, *partname_end; - if (grub_errno == GRUB_ERR_BAD_PART_TABLE) + partname = ptr; + while (*ptr && grub_isalpha (*ptr)) + ptr++; + partname_end = ptr; + num = grub_strtoul (ptr, (char **) &ptr, 0) - 1; + + curpart = 0; + /* Use the first partition map type found. */ + FOR_PARTITION_MAPS(partmap) + { + if (partname_end != partname && + (grub_strncmp (partmap->name, partname, partname_end - partname) + != 0 || partmap->name[partname_end - partname] != 0)) + continue; + + disk->partition = part; + curpart = grub_partition_map_probe (partmap, disk, num); + disk->partition = tail; + if (curpart) + break; + + if (grub_errno == GRUB_ERR_BAD_PART_TABLE) + { + /* Continue to next partition map type. */ + grub_errno = GRUB_ERR_NONE; + continue; + } + + break; + } + + if (! curpart) { - /* Continue to next partition map type. */ - grub_errno = GRUB_ERR_NONE; + while (part) + { + curpart = part->parent; + grub_free (part); + part = curpart; + } return 0; } - - return 1; + curpart->parent = part; + part = curpart; + if (! ptr || *ptr != ',') + break; + ptr++; } - /* Use the first partition map type found. */ - grub_partition_map_iterate (part_map_probe); - return part; } @@ -88,40 +130,51 @@ grub_partition_iterate (struct grub_disk *disk, int (*hook) (grub_disk_t disk, const grub_partition_t partition)) { - grub_partition_map_t partmap = 0; int ret = 0; - auto int part_map_iterate (const grub_partition_map_t p); - auto int part_map_iterate_hook (grub_disk_t d, - const grub_partition_t partition); + auto int part_iterate (grub_disk_t dsk, const grub_partition_t p); - int part_map_iterate_hook (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition __attribute__ ((unused))) + int part_iterate (grub_disk_t dsk, + const grub_partition_t partition) { - return 1; - } - - int part_map_iterate (const grub_partition_map_t p) - { - grub_dprintf ("partition", "Detecting %s...\n", p->name); - p->iterate (disk, part_map_iterate_hook); - - if (grub_errno != GRUB_ERR_NONE) + struct grub_partition p = *partition; + p.parent = dsk->partition; + dsk->partition = 0; + if (hook (dsk, &p)) { - /* Continue to next partition map type. */ - grub_dprintf ("partition", "%s detection failed.\n", p->name); - grub_errno = GRUB_ERR_NONE; - return 0; + ret = 1; + return 1; } - - grub_dprintf ("partition", "%s detection succeeded.\n", p->name); - partmap = p; - return 1; + if (p.start != 0) + { + const struct grub_partition_map *partmap; + dsk->partition = &p; + FOR_PARTITION_MAPS(partmap) + { + grub_err_t err; + err = partmap->iterate (dsk, part_iterate); + if (err) + grub_errno = GRUB_ERR_NONE; + if (ret) + break; + } + } + dsk->partition = p.parent; + return ret; } - grub_partition_map_iterate (part_map_iterate); - if (partmap) - ret = partmap->iterate (disk, hook); + { + const struct grub_partition_map *partmap; + FOR_PARTITION_MAPS(partmap) + { + grub_err_t err; + err = partmap->iterate (disk, part_iterate); + if (err) + grub_errno = GRUB_ERR_NONE; + if (ret) + break; + } + } return ret; } @@ -129,5 +182,32 @@ grub_partition_iterate (struct grub_disk *disk, char * grub_partition_get_name (const grub_partition_t partition) { - return partition->partmap->get_name (partition); + char *out = 0; + int curlen = 0; + grub_partition_t part; + for (part = partition; part; part = part->parent) + { + /* Even on 64-bit machines this buffer is enough to hold + longest number. */ + char buf[grub_strlen (part->partmap->name) + 25]; + int strl; + grub_snprintf (buf, sizeof (buf), "%s%d", part->partmap->name, + part->number + 1); + strl = grub_strlen (buf); + if (curlen) + { + out = grub_realloc (out, curlen + strl + 2); + grub_memcpy (out + strl + 1, out, curlen); + out[curlen + 1 + strl] = 0; + grub_memcpy (out, buf, strl); + out[strl] = ','; + curlen = curlen + 1 + strl; + } + else + { + curlen = strl; + out = grub_strdup (buf); + } + } + return out; } diff --git a/kern/powerpc/dl.c b/kern/powerpc/dl.c index 2891b0dbb..ad19e5600 100644 --- a/kern/powerpc/dl.c +++ b/kern/powerpc/dl.c @@ -1,7 +1,7 @@ /* dl.c - arch-dependent part of loadable module support */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2004,2005,2007 Free Software Foundation, Inc. + * Copyright (C) 2002,2004,2005,2007,2009 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 @@ -106,7 +106,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) Elf_Sword delta = value - (Elf_Word) addr; if (delta << 6 >> 6 != delta) - return grub_error (GRUB_ERR_BAD_MODULE, "Relocation overflow"); + return grub_error (GRUB_ERR_BAD_MODULE, "relocation overflow"); *addr = (*addr & 0xfc000003) | (delta & 0x3fffffc); break; } @@ -125,7 +125,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) default: return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "This relocation (%d) is not implemented yet", + "this relocation (%d) is not implemented yet", ELF_R_TYPE (rel->r_info)); } } diff --git a/kern/powerpc/ieee1275/startup.S b/kern/powerpc/ieee1275/startup.S index 75e1ed852..96d153778 100644 --- a/kern/powerpc/ieee1275/startup.S +++ b/kern/powerpc/ieee1275/startup.S @@ -18,7 +18,7 @@ */ #include -#include +#include .extern __bss_start .extern _end @@ -30,7 +30,7 @@ start: _start: b codestart - . = _start + GRUB_KERNEL_CPU_PREFIX + . = _start + GRUB_KERNEL_MACHINE_PREFIX VARIABLE(grub_prefix) /* to be filled by grub-mkelfimage */ @@ -39,7 +39,7 @@ VARIABLE(grub_prefix) * Leave some breathing room for the prefix. */ - . = _start + GRUB_KERNEL_CPU_DATA_END + . = _start + GRUB_KERNEL_MACHINE_DATA_END codestart: li 2, 0 diff --git a/kern/rescue_parser.c b/kern/rescue_parser.c index 1e0841e49..d3725e739 100644 --- a/kern/rescue_parser.c +++ b/kern/rescue_parser.c @@ -35,9 +35,12 @@ grub_rescue_parse_line (char *line, grub_reader_getline_t getline) if (grub_parser_split_cmdline (line, getline, &n, &args) || n < 0) return grub_errno; + if (n == 0) + return GRUB_ERR_NONE; + /* In case of an assignment set the environment accordingly instead of calling a function. */ - if (n == 0 && grub_strchr (line, '=')) + if (n == 1 && grub_strchr (line, '=')) { char *val = grub_strchr (args[0], '='); val[0] = 0; @@ -56,7 +59,7 @@ grub_rescue_parse_line (char *line, grub_reader_getline_t getline) cmd = grub_command_find (name); if (cmd) { - (cmd->func) (cmd, n, &args[1]); + (cmd->func) (cmd, n - 1, &args[1]); } else { diff --git a/kern/rescue_reader.c b/kern/rescue_reader.c index 2a06f3fc2..f573cf41f 100644 --- a/kern/rescue_reader.c +++ b/kern/rescue_reader.c @@ -1,7 +1,7 @@ /* rescue_reader.c - rescue mode reader */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 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 @@ -19,20 +19,15 @@ #include #include +#include #include #include +#include #define GRUB_RESCUE_BUF_SIZE 256 static char linebuf[GRUB_RESCUE_BUF_SIZE]; -static grub_err_t -grub_rescue_init (void) -{ - grub_printf ("Entering rescue mode...\n"); - return 0; -} - /* Prompt to input a command and read the line. */ static grub_err_t grub_rescue_read_line (char **line, int cont) @@ -74,15 +69,24 @@ grub_rescue_read_line (char **line, int cont) return 0; } -static struct grub_reader grub_rescue_reader = - { - .name = "rescue", - .init = grub_rescue_init, - .read_line = grub_rescue_read_line - }; - void -grub_register_rescue_reader (void) +grub_rescue_run (void) { - grub_reader_register ("rescue", &grub_rescue_reader); + grub_printf ("Entering rescue mode...\n"); + + while (1) + { + char *line; + + /* Print an error, if any. */ + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + + grub_rescue_read_line (&line, 0); + if (! line || line[0] == '\0') + continue; + + grub_parser_get_current ()->parse_line (line, grub_rescue_read_line); + grub_free (line); + } } diff --git a/kern/sparc64/dl.c b/kern/sparc64/dl.c index a4d99ff08..7b6266cac 100644 --- a/kern/sparc64/dl.c +++ b/kern/sparc64/dl.c @@ -1,7 +1,7 @@ /* dl.c - arch-dependent part of loadable module support */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2004,2005,2007 Free Software Foundation, Inc. + * Copyright (C) 2002,2004,2005,2007,2009 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 @@ -98,7 +98,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) case R_SPARC_32: /* 3 V-word32 */ if (value & 0xFFFFFFFF00000000) return grub_error (GRUB_ERR_BAD_MODULE, - "Address out of 32 bits range"); + "address out of 32 bits range"); *addr = value; break; case R_SPARC_WDISP30: /* 7 V-disp30 */ @@ -106,7 +106,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (((value - (Elf_Addr) addr) & 0xFFFFFFFF00000000) != 0xFFFFFFFF00000000)) return grub_error (GRUB_ERR_BAD_MODULE, - "Displacement out of 30 bits range"); + "displacement out of 30 bits range"); *addr = (*addr & 0xC0000000) | (((grub_int32_t) ((value - (Elf_Addr) addr) >> 2)) & 0x3FFFFFFF); @@ -114,7 +114,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) case R_SPARC_HI22: /* 9 V-imm22 */ if (((grub_int32_t) value) & 0xFF00000000) return grub_error (GRUB_ERR_BAD_MODULE, - "High address out of 22 bits range"); + "high address out of 22 bits range"); *addr = (*addr & 0xFFC00000) | ((value >> 10) & 0x3FFFFF); break; case R_SPARC_LO10: /* 12 T-simm13 */ @@ -131,7 +131,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) break; default: return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "This relocation (%d) is not implemented yet", + "this relocation (%d) is not implemented yet", ELF_R_TYPE (rel->r_info)); } } diff --git a/kern/sparc64/ieee1275/crt0.S b/kern/sparc64/ieee1275/crt0.S index 4e67cbc19..f0f47416d 100644 --- a/kern/sparc64/ieee1275/crt0.S +++ b/kern/sparc64/ieee1275/crt0.S @@ -18,13 +18,14 @@ */ #include #include +#include .text .align 4 .globl _start _start: ba codestart - nop + mov %o4, %o0 . = EXT_C(_start) + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE @@ -53,12 +54,25 @@ codestart: or %o3, %lo(_end), %o3 sethi %hi(grub_total_module_size), %o4 lduw [%o4 + %lo(grub_total_module_size)], %o4 + + add %o2, %o4, %o2 + add %o3, %o4, %o3 + + /* Save ieee1275 stack for future use by booter. */ + mov %o6, %o1 + /* Our future stack. */ + sethi %hi(GRUB_KERNEL_MACHINE_STACK_SIZE - 2047), %o5 + or %o5, %lo(GRUB_KERNEL_MACHINE_STACK_SIZE - 2047), %o5 + add %o3, %o5, %o6 + + sub %o2, 4, %o2 + sub %o3, 4, %o3 1: lduw [%o2], %o5 stw %o5, [%o3] subcc %o4, 4, %o4 - add %o2, 4, %o2 + sub %o2, 4, %o2 bne,pt %icc, 1b - add %o3, 4, %o3 + sub %o3, 4, %o3 /* Now it's safe to clear out the BSS. */ sethi %hi(__bss_start), %o2 @@ -70,8 +84,9 @@ codestart: cmp %o2, %o3 blt,pt %xcc, 1b nop + sethi %hi(grub_ieee1275_original_stack), %o2 + stx %o1, [%o2 + %lo(grub_ieee1275_original_stack)] sethi %hi(grub_ieee1275_entry_fn), %o2 - stx %o0, [%o2 + %lo(grub_ieee1275_entry_fn)] call grub_main - nop + stx %o0, [%o2 + %lo(grub_ieee1275_entry_fn)] 1: ba,a 1b diff --git a/kern/sparc64/ieee1275/ieee1275.c b/kern/sparc64/ieee1275/ieee1275.c index 438a171ca..53be692c3 100644 --- a/kern/sparc64/ieee1275/ieee1275.c +++ b/kern/sparc64/ieee1275/ieee1275.c @@ -21,39 +21,6 @@ /* Sun specific ieee1275 interfaces used by GRUB. */ -int -grub_ieee1275_map_physical (grub_addr_t paddr, grub_addr_t vaddr, - grub_size_t size, grub_uint32_t mode) -{ - struct map_physical_args - { - struct grub_ieee1275_common_hdr common; - grub_ieee1275_cell_t method; - grub_ieee1275_cell_t ihandle; - grub_ieee1275_cell_t mode; - grub_ieee1275_cell_t size; - grub_ieee1275_cell_t virt; - grub_ieee1275_cell_t phys_high; - grub_ieee1275_cell_t phys_low; - grub_ieee1275_cell_t catch_result; - } - args; - - INIT_IEEE1275_COMMON (&args.common, "call-method", 7, 1); - args.method = (grub_ieee1275_cell_t) "map"; - args.ihandle = grub_ieee1275_mmu; - args.mode = mode; - args.size = size; - args.virt = vaddr; - args.phys_high = 0; - args.phys_low = paddr; - args.catch_result = (grub_ieee1275_cell_t) -1; - - if (IEEE1275_CALL_ENTRY_FN (&args) == -1) - return -1; - return args.catch_result; -} - int grub_ieee1275_claim_vaddr (grub_addr_t vaddr, grub_size_t size) { diff --git a/kern/sparc64/ieee1275/init.c b/kern/sparc64/ieee1275/init.c index 699f9631b..a995217bc 100644 --- a/kern/sparc64/ieee1275/init.c +++ b/kern/sparc64/ieee1275/init.c @@ -23,12 +23,15 @@ #include #include #include +#include #include #include #include #include #include +grub_addr_t grub_ieee1275_original_stack; + void grub_exit (void) { @@ -90,10 +93,7 @@ grub_machine_set_prefix (void) } prefix = grub_ieee1275_encode_devname (bootpath); - path = grub_malloc (grub_strlen (grub_prefix) - + grub_strlen (prefix) - + 2); - grub_sprintf(path, "%s%s", prefix, grub_prefix); + path = grub_xasprintf("%s%s", prefix, grub_prefix); grub_strcpy (grub_prefix, path); @@ -107,7 +107,8 @@ grub_machine_set_prefix (void) static void grub_heap_init (void) { - grub_mm_init_region ((void *)(long)0x4000UL, 0x200000 - 0x4000); + grub_mm_init_region ((void *) (grub_modules_get_end () + + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000); } static void diff --git a/kern/term.c b/kern/term.c index 94d5a9e1d..6e3a2b454 100644 --- a/kern/term.c +++ b/kern/term.c @@ -21,79 +21,33 @@ #include #include #include +#include -/* The amount of lines counted by the pager. */ -static int grub_more_lines; +struct grub_term_output *grub_term_outputs_disabled; +struct grub_term_input *grub_term_inputs_disabled; +struct grub_term_output *grub_term_outputs; +struct grub_term_input *grub_term_inputs; -/* If the more pager is active. */ -static int grub_more; - -/* The current cursor state. */ -static int cursor_state = 1; - -struct grub_handler_class grub_term_input_class = - { - .name = "terminal_input" - }; - -struct grub_handler_class grub_term_output_class = - { - .name = "terminal_output" - }; - -#define grub_cur_term_input grub_term_get_current_input () -#define grub_cur_term_output grub_term_get_current_output () +void (*grub_newline_hook) (void) = NULL; /* Put a Unicode character. */ void -grub_putcode (grub_uint32_t code) +grub_putcode (grub_uint32_t code, struct grub_term_output *term) { - int height = grub_getwh () & 255; - - if (code == '\t' && grub_cur_term_output->getxy) + if (code == '\t' && term->getxy) { int n; - n = 8 - ((grub_getxy () >> 8) & 7); + n = 8 - ((term->getxy () >> 8) & 7); while (n--) - grub_putcode (' '); + grub_putcode (' ', term); return; } - (grub_cur_term_output->putchar) (code); - + (term->putchar) (code); if (code == '\n') - { - grub_putcode ('\r'); - - grub_more_lines++; - - if (grub_more && grub_more_lines == height - 1) - { - char key; - int pos = grub_getxy (); - - /* Show --MORE-- on the lower left side of the screen. */ - grub_gotoxy (1, height - 1); - grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); - grub_printf ("--MORE--"); - grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); - - key = grub_getkey (); - - /* Remove the message. */ - grub_gotoxy (1, height - 1); - grub_printf (" "); - grub_gotoxy (pos >> 8, pos & 0xFF); - - /* Scroll one lines or an entire page, depending on the key. */ - if (key == '\r' || key =='\n') - grub_more_lines--; - else - grub_more_lines = 0; - } - } + (term->putchar) ('\r'); } /* Put a character. C is one byte of a UTF-8 stream. @@ -103,137 +57,105 @@ grub_putchar (int c) { static grub_size_t size = 0; static grub_uint8_t buf[6]; + grub_uint8_t *rest; grub_uint32_t code; - grub_ssize_t ret; buf[size++] = c; - ret = grub_utf8_to_ucs4 (&code, 1, buf, size, 0); - if (ret > 0) + while (grub_utf8_to_ucs4 (&code, 1, buf, size, (const grub_uint8_t **) &rest) + != 0) { - size = 0; - grub_putcode (code); + struct grub_term_output *term; + size -= rest - buf; + grub_memmove (buf, rest, size); + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_putcode (code, term); + if (code == '\n' && grub_newline_hook) + grub_newline_hook (); } - else if (ret < 0) - { - size = 0; - grub_putcode ('?'); - } -} - -/* Return the number of columns occupied by the character code CODE. */ -grub_ssize_t -grub_getcharwidth (grub_uint32_t code) -{ - return (grub_cur_term_output->getcharwidth) (code); } int grub_getkey (void) { - return (grub_cur_term_input->getkey) (); + grub_term_input_t term; + + grub_refresh (); + + while (1) + { + FOR_ACTIVE_TERM_INPUTS(term) + { + int key = term->checkkey (); + if (key != -1) + return term->getkey (); + } + + grub_cpu_idle (); + } } int grub_checkkey (void) { - return (grub_cur_term_input->checkkey) (); + grub_term_input_t term; + + FOR_ACTIVE_TERM_INPUTS(term) + { + int key = term->checkkey (); + if (key != -1) + return key; + } + + return -1; } int grub_getkeystatus (void) { - if (grub_cur_term_input->getkeystatus) - return (grub_cur_term_input->getkeystatus) (); - else - return 0; -} + int status = 0; + grub_term_input_t term; -grub_uint16_t -grub_getxy (void) -{ - return (grub_cur_term_output->getxy) (); -} + FOR_ACTIVE_TERM_INPUTS(term) + { + if (term->getkeystatus) + status |= term->getkeystatus (); + } -grub_uint16_t -grub_getwh (void) -{ - return (grub_cur_term_output->getwh) (); -} - -void -grub_gotoxy (grub_uint8_t x, grub_uint8_t y) -{ - (grub_cur_term_output->gotoxy) (x, y); + return status; } void grub_cls (void) { - if ((grub_cur_term_output->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug"))) - { - grub_putchar ('\n'); - grub_refresh (); - } - else - (grub_cur_term_output->cls) (); + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + if ((term->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug"))) + { + grub_putcode ('\n', term); + grub_term_refresh (term); + } + else + (term->cls) (); + } } void grub_setcolorstate (grub_term_color_state state) { - if (grub_cur_term_output->setcolorstate) - (grub_cur_term_output->setcolorstate) (state); -} - -void -grub_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color) -{ - if (grub_cur_term_output->setcolor) - (grub_cur_term_output->setcolor) (normal_color, highlight_color); -} - -void -grub_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color) -{ - if (grub_cur_term_output->getcolor) - (grub_cur_term_output->getcolor) (normal_color, highlight_color); -} - -int -grub_setcursor (int on) -{ - int ret = cursor_state; - - if (grub_cur_term_output->setcursor) - { - (grub_cur_term_output->setcursor) (on); - cursor_state = on; - } - - return ret; -} - -int -grub_getcursor (void) -{ - return cursor_state; + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_term_setcolorstate (term, state); } void grub_refresh (void) { - if (grub_cur_term_output->refresh) - (grub_cur_term_output->refresh) (); -} + struct grub_term_output *term; -void -grub_set_more (int onoff) -{ - if (onoff == 1) - grub_more++; - else - grub_more--; - - grub_more_lines = 0; + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_term_refresh (term); } diff --git a/kern/x86_64/dl.c b/kern/x86_64/dl.c index 73a7337e7..090ad78b8 100644 --- a/kern/x86_64/dl.c +++ b/kern/x86_64/dl.c @@ -1,7 +1,7 @@ /* dl-x86_64.c - arch-dependent part of loadable module support */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2005,2007 Free Software Foundation, Inc. + * Copyright (C) 2002,2005,2007,2009 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 diff --git a/lib/arg.c b/lib/arg.c index 24e9d5b15..6a7bb8beb 100644 --- a/lib/arg.c +++ b/lib/arg.c @@ -22,6 +22,7 @@ #include #include #include +#include /* Built-in parser for default options. */ #define SHORT_ARG_HELP -100 @@ -30,9 +31,9 @@ static const struct grub_arg_option help_options[] = { {"help", SHORT_ARG_HELP, 0, - "display this help and exit", 0, ARG_TYPE_NONE}, + N_("Display this help and exit."), 0, ARG_TYPE_NONE}, {"usage", SHORT_ARG_USAGE, 0, - "display the usage of this command and exit", 0, ARG_TYPE_NONE}, + N_("Display the usage of this command and exit."), 0, ARG_TYPE_NONE}, {0, 0, 0, 0, 0, 0} }; @@ -106,7 +107,7 @@ find_long (const struct grub_arg_option *options, const char *s, int len) static void show_usage (grub_extcmd_t cmd) { - grub_printf ("Usage: %s\n", cmd->cmd->summary); + grub_printf ("%s %s %s\n", _("Usage:"), cmd->cmd->name, _(cmd->cmd->summary)); } void @@ -143,7 +144,7 @@ grub_arg_show_help (grub_extcmd_t cmd) } } - const char *doc = opt->doc; + const char *doc = _(opt->doc); for (;;) { while (spacing-- > 0) @@ -176,7 +177,7 @@ grub_arg_show_help (grub_extcmd_t cmd) } show_usage (cmd); - grub_printf ("%s\n\n", cmd->cmd->description); + grub_printf ("%s\n\n", _(cmd->cmd->description)); if (cmd->options) showargs (cmd->options); showargs (help_options); @@ -274,7 +275,7 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, if (! opt) { grub_error (GRUB_ERR_BAD_ARGUMENT, - "Unknown argument `-%c'\n", *curshort); + "unknown argument `-%c'", *curshort); goto fail; } @@ -326,7 +327,7 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, opt = find_long (cmd->options, arg + 2, arglen); if (! opt) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown argument `%s'\n", arg); + grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown argument `%s'", arg); goto fail; } } @@ -337,7 +338,7 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, if (! option) { grub_error (GRUB_ERR_BAD_ARGUMENT, - "Missing mandatory option for `%s'\n", opt->longarg); + "missing mandatory option for `%s'", opt->longarg); goto fail; } @@ -359,7 +360,7 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, if (tail == 0 || tail == option || *tail != '\0' || grub_errno) { grub_error (GRUB_ERR_BAD_ARGUMENT, - "The argument `%s' requires an integer.", + "the argument `%s' requires an integer", arg); goto fail; @@ -382,8 +383,8 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, if (option) { grub_error (GRUB_ERR_BAD_ARGUMENT, - "A value was assigned to the argument `%s' while it " - "doesn't require an argument\n", arg); + "a value was assigned to the argument `%s' while it " + "doesn't require an argument", arg); goto fail; } diff --git a/lib/charset.c b/lib/charset.c new file mode 100644 index 000000000..f2e1b036d --- /dev/null +++ b/lib/charset.c @@ -0,0 +1,269 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 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 . + */ + +/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE + bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string. + Return the number of characters converted. DEST must be able to hold + at least DESTSIZE characters. If an invalid sequence is found, return -1. + If SRCEND is not NULL, then *SRCEND is set to the next byte after the + last byte used in SRC. */ + +#include +#include +#include + +grub_ssize_t +grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, + const grub_uint8_t *src, grub_size_t srcsize, + const grub_uint8_t **srcend) +{ + grub_uint16_t *p = dest; + int count = 0; + grub_uint32_t code = 0; + + if (srcend) + *srcend = src; + + while (srcsize && destsize) + { + grub_uint32_t c = *src++; + if (srcsize != (grub_size_t)-1) + srcsize--; + if (count) + { + if ((c & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT) + { + /* invalid */ + return -1; + } + else + { + code <<= 6; + code |= (c & GRUB_UINT8_6_TRAILINGBITS); + count--; + } + } + else + { + if (c == 0) + break; + + if ((c & GRUB_UINT8_1_LEADINGBIT) == 0) + code = c; + else if ((c & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS) + { + count = 1; + code = c & GRUB_UINT8_5_TRAILINGBITS; + } + else if ((c & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS) + { + count = 2; + code = c & GRUB_UINT8_4_TRAILINGBITS; + } + else if ((c & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS) + { + count = 3; + code = c & GRUB_UINT8_3_TRAILINGBITS; + } + else if ((c & GRUB_UINT8_6_LEADINGBITS) == GRUB_UINT8_5_LEADINGBITS) + { + count = 4; + code = c & GRUB_UINT8_2_TRAILINGBITS; + } + else if ((c & GRUB_UINT8_7_LEADINGBITS) == GRUB_UINT8_6_LEADINGBITS) + { + count = 5; + code = c & GRUB_UINT8_1_TRAILINGBIT; + } + else + return -1; + } + + if (count == 0) + { + if (destsize < 2 && code >= GRUB_UCS2_LIMIT) + break; + if (code >= GRUB_UCS2_LIMIT) + { + *p++ = GRUB_UTF16_UPPER_SURROGATE (code); + *p++ = GRUB_UTF16_LOWER_SURROGATE (code); + destsize -= 2; + } + else + { + *p++ = code; + destsize--; + } + } + } + + if (srcend) + *srcend = src; + return p - dest; +} + +/* Convert UCS-4 to UTF-8. */ +char * +grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size) +{ + grub_size_t remaining; + grub_uint32_t *ptr; + grub_size_t cnt = 0; + grub_uint8_t *ret, *dest; + + remaining = size; + ptr = src; + while (remaining--) + { + grub_uint32_t code = *ptr++; + + if (code <= 0x007F) + cnt++; + else if (code <= 0x07FF) + cnt += 2; + else if ((code >= 0xDC00 && code <= 0xDFFF) + || (code >= 0xD800 && code <= 0xDBFF)) + /* No surrogates in UCS-4... */ + cnt++; + else + cnt += 3; + } + cnt++; + + ret = grub_malloc (cnt); + if (!ret) + return 0; + + dest = ret; + remaining = size; + ptr = src; + while (remaining--) + { + grub_uint32_t code = *ptr++; + + if (code <= 0x007F) + *dest++ = code; + else if (code <= 0x07FF) + { + *dest++ = (code >> 6) | 0xC0; + *dest++ = (code & 0x3F) | 0x80; + } + else if ((code >= 0xDC00 && code <= 0xDFFF) + || (code >= 0xD800 && code <= 0xDBFF)) + { + /* No surrogates in UCS-4... */ + *dest++ = '?'; + } + else + { + *dest++ = (code >> 12) | 0xE0; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + } + } + *dest = 0; + + return (char *) ret; +} + +int +grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize) +{ + grub_uint32_t code = 0; + int count = 0; + + while (srcsize) + { + grub_uint32_t c = *src++; + if (srcsize != (grub_size_t)-1) + srcsize--; + if (count) + { + if ((c & 0xc0) != 0x80) + { + /* invalid */ + return 0; + } + else + { + code <<= 6; + code |= (c & 0x3f); + count--; + } + } + else + { + if (c == 0) + break; + + if ((c & 0x80) == 0x00) + code = c; + else if ((c & 0xe0) == 0xc0) + { + count = 1; + code = c & 0x1f; + } + else if ((c & 0xf0) == 0xe0) + { + count = 2; + code = c & 0x0f; + } + else if ((c & 0xf8) == 0xf0) + { + count = 3; + code = c & 0x07; + } + else if ((c & 0xfc) == 0xf8) + { + count = 4; + code = c & 0x03; + } + else if ((c & 0xfe) == 0xfc) + { + count = 5; + code = c & 0x01; + } + else + return 0; + } + } + + return 1; +} + +int +grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg, + grub_uint32_t **last_position) +{ + grub_size_t msg_len = grub_strlen (msg); + + *unicode_msg = grub_malloc (grub_strlen (msg) * sizeof (grub_uint32_t)); + + if (!*unicode_msg) + { + grub_printf ("utf8_to_ucs4 ERROR1: %s", msg); + return -1; + } + + msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len, + (grub_uint8_t *) msg, -1, 0); + + *last_position = *unicode_msg + msg_len; + + return msg_len; +} diff --git a/lib/i386/datetime.c b/lib/cmos_datetime.c similarity index 95% rename from lib/i386/datetime.c rename to lib/cmos_datetime.c index 63858ed03..8db60b48c 100644 --- a/lib/i386/datetime.c +++ b/lib/cmos_datetime.c @@ -1,7 +1,7 @@ -/* kern/i386/datetime.c - x86 CMOS datetime function. +/* kern/cmos_datetime.c - CMOS datetime function. * * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 @@ -18,7 +18,7 @@ */ #include -#include +#include grub_err_t grub_get_datetime (struct grub_datetime *datetime) diff --git a/lib/crypto.c b/lib/crypto.c new file mode 100644 index 000000000..d11f0994f --- /dev/null +++ b/lib/crypto.c @@ -0,0 +1,453 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 + * 2007, 2008, 2009 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 . + */ + +#include +#include +#include +#include + +struct grub_crypto_hmac_handle +{ + const struct gcry_md_spec *md; + void *ctx; + void *opad; +}; + +static gcry_cipher_spec_t *grub_ciphers = NULL; +static gcry_md_spec_t *grub_digests = NULL; + +void (*grub_crypto_autoload_hook) (const char *name) = NULL; + +/* Based on libgcrypt-1.4.4/src/misc.c. */ +void +grub_burn_stack (grub_size_t size) +{ + char buf[64]; + + grub_memset (buf, 0, sizeof (buf)); + if (size > sizeof (buf)) + grub_burn_stack (size - sizeof (buf)); +} + + +void +grub_cipher_register (gcry_cipher_spec_t *cipher) +{ + cipher->next = grub_ciphers; + grub_ciphers = cipher; +} + +void +grub_cipher_unregister (gcry_cipher_spec_t *cipher) +{ + gcry_cipher_spec_t **ciph; + for (ciph = &grub_ciphers; *ciph; ciph = &((*ciph)->next)) + if (*ciph == cipher) + { + *ciph = (*ciph)->next; + break; + } +} + +void +grub_md_register (gcry_md_spec_t *digest) +{ + digest->next = grub_digests; + grub_digests = digest; +} + +void +grub_md_unregister (gcry_md_spec_t *cipher) +{ + gcry_md_spec_t **ciph; + for (ciph = &grub_digests; *ciph; ciph = &((*ciph)->next)) + if (*ciph == cipher) + { + *ciph = (*ciph)->next; + break; + } +} + +void +grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, + grub_size_t inlen) +{ + grub_uint8_t ctx[hash->contextsize]; + hash->init (&ctx); + hash->write (&ctx, in, inlen); + hash->final (&ctx); + grub_memcpy (out, hash->read (&ctx), hash->mdlen); +} + +const gcry_md_spec_t * +grub_crypto_lookup_md_by_name (const char *name) +{ + const gcry_md_spec_t *md; + int first = 1; + while (1) + { + for (md = grub_digests; md; md = md->next) + if (grub_strcasecmp (name, md->name) == 0) + return md; + if (grub_crypto_autoload_hook && first) + grub_crypto_autoload_hook (name); + else + return NULL; + first = 0; + } +} + +const gcry_cipher_spec_t * +grub_crypto_lookup_cipher_by_name (const char *name) +{ + const gcry_cipher_spec_t *ciph; + int first = 1; + while (1) + { + for (ciph = grub_ciphers; ciph; ciph = ciph->next) + { + const char **alias; + if (grub_strcasecmp (name, ciph->name) == 0) + return ciph; + if (!ciph->aliases) + continue; + for (alias = ciph->aliases; *alias; alias++) + if (grub_strcasecmp (name, *alias) == 0) + return ciph; + } + if (grub_crypto_autoload_hook && first) + grub_crypto_autoload_hook (name); + else + return NULL; + first = 0; + } +} + + +grub_crypto_cipher_handle_t +grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher) +{ + grub_crypto_cipher_handle_t ret; + ret = grub_malloc (sizeof (*ret) + cipher->contextsize); + if (!ret) + return NULL; + ret->cipher = cipher; + return ret; +} + +gcry_err_code_t +grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher, + const unsigned char *key, + unsigned keylen) +{ + return cipher->cipher->setkey (cipher->ctx, key, keylen); +} + + +void +grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher) +{ + grub_free (cipher); +} + + +void +grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size) +{ + const grub_uint8_t *in1ptr = in1, *in2ptr = in2; + grub_uint8_t *outptr = out; + while (size--) + { + *outptr = *in1ptr ^ *in2ptr; + in1ptr++; + in2ptr++; + outptr++; + } +} + +gcry_err_code_t +grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size) +{ + grub_uint8_t *inptr, *outptr, *end; + if (!cipher->cipher->decrypt) + return GPG_ERR_NOT_SUPPORTED; + if (size % cipher->cipher->blocksize != 0) + return GPG_ERR_INV_ARG; + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + cipher->cipher->decrypt (cipher->ctx, outptr, inptr); + return GPG_ERR_NO_ERROR; +} + +gcry_err_code_t +grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size) +{ + grub_uint8_t *inptr, *outptr, *end; + if (!cipher->cipher->encrypt) + return GPG_ERR_NOT_SUPPORTED; + if (size % cipher->cipher->blocksize != 0) + return GPG_ERR_INV_ARG; + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + cipher->cipher->encrypt (cipher->ctx, outptr, inptr); + return GPG_ERR_NO_ERROR; +} + +gcry_err_code_t +grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv_in) +{ + grub_uint8_t *inptr, *outptr, *end; + void *iv; + if (!cipher->cipher->decrypt) + return GPG_ERR_NOT_SUPPORTED; + if (size % cipher->cipher->blocksize != 0) + return GPG_ERR_INV_ARG; + end = (grub_uint8_t *) in + size; + iv = iv_in; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_crypto_xor (outptr, inptr, iv, cipher->cipher->blocksize); + cipher->cipher->encrypt (cipher->ctx, outptr, outptr); + iv = outptr; + } + grub_memcpy (iv_in, iv, cipher->cipher->blocksize); + return GPG_ERR_NO_ERROR; +} + +gcry_err_code_t +grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv) +{ + grub_uint8_t *inptr, *outptr, *end; + grub_uint8_t ivt[cipher->cipher->blocksize]; + if (!cipher->cipher->decrypt) + return GPG_ERR_NOT_SUPPORTED; + if (size % cipher->cipher->blocksize != 0) + return GPG_ERR_INV_ARG; + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_memcpy (ivt, inptr, cipher->cipher->blocksize); + cipher->cipher->decrypt (cipher->ctx, outptr, inptr); + grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize); + grub_memcpy (iv, ivt, cipher->cipher->blocksize); + } + return GPG_ERR_NO_ERROR; +} + +/* Based on gcry/cipher/md.c. */ +struct grub_crypto_hmac_handle * +grub_crypto_hmac_init (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen) +{ + grub_uint8_t *helpkey = NULL; + grub_uint8_t *ipad = NULL, *opad = NULL; + void *ctx = NULL; + struct grub_crypto_hmac_handle *ret = NULL; + unsigned i; + + if (md->mdlen > md->blocksize) + return NULL; + + ctx = grub_malloc (md->contextsize); + if (!ctx) + goto err; + + if ( keylen > md->blocksize ) + { + helpkey = grub_malloc (md->mdlen); + if (!helpkey) + goto err; + grub_crypto_hash (md, helpkey, key, keylen); + + key = helpkey; + keylen = md->mdlen; + } + + ipad = grub_zalloc (md->blocksize); + if (!ipad) + goto err; + + opad = grub_zalloc (md->blocksize); + if (!opad) + goto err; + + grub_memcpy ( ipad, key, keylen ); + grub_memcpy ( opad, key, keylen ); + for (i=0; i < md->blocksize; i++ ) + { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + grub_free (helpkey); + helpkey = NULL; + + md->init (ctx); + + md->write (ctx, ipad, md->blocksize); /* inner pad */ + grub_memset (ipad, 0, md->blocksize); + grub_free (ipad); + ipad = NULL; + + ret = grub_malloc (sizeof (*ret)); + if (!ret) + goto err; + + ret->md = md; + ret->ctx = ctx; + ret->opad = opad; + + return ret; + + err: + grub_free (helpkey); + grub_free (ctx); + grub_free (ipad); + grub_free (opad); + return NULL; +} + +void +grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, void *data, + grub_size_t datalen) +{ + hnd->md->write (hnd->ctx, data, datalen); +} + +gcry_err_code_t +grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out) +{ + grub_uint8_t *p; + grub_uint8_t *ctx2; + + ctx2 = grub_malloc (hnd->md->contextsize); + if (!ctx2) + return GPG_ERR_OUT_OF_MEMORY; + + hnd->md->final (hnd->ctx); + hnd->md->read (hnd->ctx); + p = hnd->md->read (hnd->ctx); + + hnd->md->init (ctx2); + hnd->md->write (ctx2, hnd->opad, hnd->md->blocksize); + hnd->md->write (ctx2, p, hnd->md->mdlen); + hnd->md->final (ctx2); + grub_memset (hnd->opad, 0, hnd->md->blocksize); + grub_free (hnd->opad); + grub_memset (hnd->ctx, 0, hnd->md->contextsize); + grub_free (hnd->ctx); + + grub_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen); + grub_memset (ctx2, 0, hnd->md->contextsize); + grub_free (ctx2); + + grub_memset (hnd, 0, sizeof (*hnd)); + grub_free (hnd); + + return GPG_ERR_NO_ERROR; +} + +gcry_err_code_t +grub_crypto_hmac_buffer (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen, + void *data, grub_size_t datalen, void *out) +{ + struct grub_crypto_hmac_handle *hnd; + + hnd = grub_crypto_hmac_init (md, key, keylen); + if (!hnd) + return GPG_ERR_OUT_OF_MEMORY; + + grub_crypto_hmac_write (hnd, data, datalen); + return grub_crypto_hmac_fini (hnd, out); +} + + +grub_err_t +grub_crypto_gcry_error (gcry_err_code_t in) +{ + if (in == GPG_ERR_NO_ERROR) + return GRUB_ERR_NONE; + return GRUB_ACCESS_DENIED; +} + +int +grub_crypto_memcmp (const void *a, const void *b, grub_size_t n) +{ + register grub_size_t counter = 0; + const grub_uint8_t *pa, *pb; + + for (pa = a, pb = b; n; pa++, pb++, n--) + { + if (*pa != *pb) + counter++; + } + + return !!counter; +} + +#ifndef GRUB_MKPASSWD +int +grub_password_get (char buf[], unsigned buf_size) +{ + unsigned cur_len = 0; + int key; + + while (1) + { + key = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + if (key == '\n' || key == '\r') + break; + + if (key == '\e') + { + cur_len = 0; + break; + } + + if (key == '\b') + { + cur_len--; + continue; + } + + if (!grub_isprint (key)) + continue; + + if (cur_len + 2 < buf_size) + buf[cur_len++] = key; + } + + grub_memset (buf + cur_len, 0, buf_size - cur_len); + + grub_putchar ('\n'); + grub_refresh (); + + return (key != '\e'); +} +#endif diff --git a/lib/hexdump.c b/lib/hexdump.c index c69cb093b..317635a2b 100644 --- a/lib/hexdump.c +++ b/lib/hexdump.c @@ -1,7 +1,7 @@ /* hexdump.c - hexdump function */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 @@ -31,21 +31,22 @@ hexdump (unsigned long bse, char *buf, int len) { int cnt, i; - pos = grub_sprintf (line, "%08lx ", bse); + pos = grub_snprintf (line, sizeof (line), "%08lx ", bse); cnt = 16; if (cnt > len) cnt = len; for (i = 0; i < cnt; i++) { - pos += grub_sprintf (&line[pos], "%02x ", (unsigned char) buf[i]); + pos += grub_snprintf (&line[pos], sizeof (line) - pos, + "%02x ", (unsigned char) buf[i]); if ((i & 7) == 7) line[pos++] = ' '; } for (; i < 16; i++) { - pos += grub_sprintf (&line[pos], " "); + pos += grub_snprintf (&line[pos], sizeof (line) - pos, " "); if ((i & 7) == 7) line[pos++] = ' '; } diff --git a/lib/i386/pc/biosnum.c b/lib/i386/pc/biosnum.c index 1f9b5f3fc..058c9d331 100644 --- a/lib/i386/pc/biosnum.c +++ b/lib/i386/pc/biosnum.c @@ -33,7 +33,7 @@ grub_get_root_biosnumber_default (void) return grub_strtoul (biosnum, 0, 0); dev = grub_device_open (0); - if (dev && dev->disk && dev->disk->dev + if (dev && dev->disk && dev->disk->dev && dev->disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID) ret = (int) dev->disk->id; diff --git a/lib/i386/relocator.c b/lib/i386/relocator.c new file mode 100644 index 000000000..453f73fdd --- /dev/null +++ b/lib/i386/relocator.c @@ -0,0 +1,102 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include + +#include +#include +#include + +#include + +extern grub_uint8_t grub_relocator32_forward_start; +extern grub_uint8_t grub_relocator32_forward_end; +extern grub_uint8_t grub_relocator32_backward_start; +extern grub_uint8_t grub_relocator32_backward_end; + +extern grub_uint32_t grub_relocator32_backward_dest; +extern grub_uint32_t grub_relocator32_backward_size; +extern grub_addr_t grub_relocator32_backward_src; + +extern grub_uint32_t grub_relocator32_forward_dest; +extern grub_uint32_t grub_relocator32_forward_size; +extern grub_addr_t grub_relocator32_forward_src; + +extern grub_uint32_t grub_relocator32_forward_eax; +extern grub_uint32_t grub_relocator32_forward_ebx; +extern grub_uint32_t grub_relocator32_forward_ecx; +extern grub_uint32_t grub_relocator32_forward_edx; +extern grub_uint32_t grub_relocator32_forward_eip; +extern grub_uint32_t grub_relocator32_forward_esp; + +extern grub_uint32_t grub_relocator32_backward_eax; +extern grub_uint32_t grub_relocator32_backward_ebx; +extern grub_uint32_t grub_relocator32_backward_ecx; +extern grub_uint32_t grub_relocator32_backward_edx; +extern grub_uint32_t grub_relocator32_backward_eip; +extern grub_uint32_t grub_relocator32_backward_esp; + +#define RELOCATOR_SIZEOF(x) (&grub_relocator32_##x##_end - &grub_relocator32_##x##_start) +#define RELOCATOR_ALIGN 16 +#define PREFIX(x) grub_relocator32_ ## x + +static void +write_call_relocator_bw (void *ptr, void *src, grub_uint32_t dest, + grub_size_t size, struct grub_relocator32_state state) +{ + grub_relocator32_backward_dest = dest; + grub_relocator32_backward_src = PTR_TO_UINT64 (src); + grub_relocator32_backward_size = size; + + grub_relocator32_backward_eax = state.eax; + grub_relocator32_backward_ebx = state.ebx; + grub_relocator32_backward_ecx = state.ecx; + grub_relocator32_backward_edx = state.edx; + grub_relocator32_backward_eip = state.eip; + grub_relocator32_backward_esp = state.esp; + + grub_memmove (ptr, + &grub_relocator32_backward_start, + RELOCATOR_SIZEOF (backward)); + ((void (*) (void)) ptr) (); +} + +static void +write_call_relocator_fw (void *ptr, void *src, grub_uint32_t dest, + grub_size_t size, struct grub_relocator32_state state) +{ + + grub_relocator32_forward_dest = dest; + grub_relocator32_forward_src = PTR_TO_UINT64 (src); + grub_relocator32_forward_size = size; + + grub_relocator32_forward_eax = state.eax; + grub_relocator32_forward_ebx = state.ebx; + grub_relocator32_forward_ecx = state.ecx; + grub_relocator32_forward_edx = state.edx; + grub_relocator32_forward_eip = state.eip; + grub_relocator32_forward_esp = state.esp; + + grub_memmove (ptr, + &grub_relocator32_forward_start, + RELOCATOR_SIZEOF (forward)); + ((void (*) (void)) ptr) (); +} + +#include "../relocator.c" diff --git a/lib/i386/relocator_asm.S b/lib/i386/relocator_asm.S new file mode 100644 index 000000000..6b803db13 --- /dev/null +++ b/lib/i386/relocator_asm.S @@ -0,0 +1,248 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include + +#ifdef BACKWARD +#define RELOCATOR_VARIABLE(x) VARIABLE(grub_relocator32_backward_ ## x) +#else +#define RELOCATOR_VARIABLE(x) VARIABLE(grub_relocator32_forward_ ## x) +#endif +#ifdef __x86_64__ +#define RAX %rax +#define RCX %rcx +#define RDI %rdi +#define RSI %rdi +#else +#define RAX %eax +#define RCX %ecx +#define RDI %edi +#define RSI %esi +#endif + +/* The code segment of the protected mode. */ +#define CODE_SEGMENT 0x10 + +/* The data segment of the protected mode. */ +#define DATA_SEGMENT 0x18 + + .p2align 4 /* force 16-byte alignment */ + +RELOCATOR_VARIABLE(start) +#ifdef BACKWARD +LOCAL(base): +#endif + cli + +#ifndef __x86_64__ + /* mov imm32, %eax */ + .byte 0xb8 +RELOCATOR_VARIABLE(dest) + .long 0 + movl %eax, %edi + + /* mov imm32, %eax */ + .byte 0xb8 +RELOCATOR_VARIABLE(src) + .long 0 + movl %eax, %esi + + /* mov imm32, %ecx */ + .byte 0xb9 +RELOCATOR_VARIABLE(size) + .long 0 +#else + xorq %rax, %rax + + /* mov imm32, %eax */ + .byte 0xb8 +RELOCATOR_VARIABLE(dest) + .long 0 + movq %rax, %rdi + + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +RELOCATOR_VARIABLE(src) + .long 0, 0 + movq %rax, %rsi + + xorq %rcx, %rcx + /* mov imm32, %ecx */ + .byte 0xb9 +RELOCATOR_VARIABLE(size) + .long 0 + +#endif + + mov RDI, RAX + +#ifdef BACKWARD + add RCX, RSI + add RCX, RDI +#endif + +#ifndef BACKWARD + add RCX, RAX +#endif + add $0x3, RCX + shr $2, RCX + + +#ifdef BACKWARD + /* Backward movsl is implicitly off-by-four. compensate that. */ + sub $4, RSI + sub $4, RDI + + /* Backward copy. */ + std + + rep + movsl + +#else + /* Forward copy. */ + cld + rep + movsl +#endif + + /* %rax contains now our new 'base'. */ + mov RAX, RSI + add $(LOCAL(cont0) - LOCAL(base)), RAX + jmp *RAX +LOCAL(cont0): + lea (LOCAL(cont1) - LOCAL(base)) (RSI, 1), RAX + movl %eax, (LOCAL(jump_vector) - LOCAL(base)) (RSI, 1) + + lea (LOCAL(gdt) - LOCAL(base)) (RSI, 1), RAX + mov RAX, (LOCAL(gdt_addr) - LOCAL(base)) (RSI, 1) + + /* Switch to compatibility mode. */ + + lgdt (LOCAL(gdtdesc) - LOCAL(base)) (RSI, 1) + + /* Update %cs. */ + ljmp *(LOCAL(jump_vector) - LOCAL(base)) (RSI, 1) + +LOCAL(cont1): + .code32 + + /* Update other registers. */ + movl $DATA_SEGMENT, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + /* Disable paging. */ + movl %cr0, %eax + andl $(~GRUB_MEMORY_CPU_CR0_PAGING_ON), %eax + movl %eax, %cr0 + + /* Disable amd64. */ + movl $GRUB_MEMORY_CPU_AMD64_MSR, %ecx + rdmsr + andl $(~GRUB_MEMORY_CPU_AMD64_MSR_ON), %eax + wrmsr + + /* Turn off PAE. */ + movl %cr4, %eax + andl $GRUB_MEMORY_CPU_CR4_PAE_ON, %eax + movl %eax, %cr4 + + jmp LOCAL(cont2) +LOCAL(cont2): + .code32 + + /* mov imm32, %eax */ + .byte 0xb8 +RELOCATOR_VARIABLE (esp) + .long 0 + + movl %eax, %esp + + /* mov imm32, %eax */ + .byte 0xb8 +RELOCATOR_VARIABLE (eax) + .long 0 + + /* mov imm32, %ebx */ + .byte 0xbb +RELOCATOR_VARIABLE (ebx) + .long 0 + + /* mov imm32, %ecx */ + .byte 0xb9 +RELOCATOR_VARIABLE (ecx) + .long 0 + + /* mov imm32, %edx */ + .byte 0xba +RELOCATOR_VARIABLE (edx) + .long 0 + + /* Cleared direction flag is of no problem with any current + payload and makes this implementation easier. */ + cld + + .byte 0xea +RELOCATOR_VARIABLE (eip) + .long 0 + .word CODE_SEGMENT + + /* GDT. Copied from loader/i386/linux.c. */ + .p2align 4 +LOCAL(gdt): + /* NULL. */ + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + + /* Reserved. */ + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + + /* Code segment. */ + .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00 + + /* Data segment. */ + .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 + + .p2align 4 +LOCAL(gdtdesc): + .word 0x27 +LOCAL(gdt_addr): +#ifdef __x86_64__ + /* Filled by the code. */ + .quad 0 +#else + /* Filled by the code. */ + .long 0 +#endif + + .p2align 4 +LOCAL(jump_vector): + /* Jump location. Is filled by the code */ + .long 0 + .long CODE_SEGMENT + +#ifndef BACKWARD +LOCAL(base): +#endif + +RELOCATOR_VARIABLE(end) diff --git a/lib/i386/relocator_backward.S b/lib/i386/relocator_backward.S new file mode 100644 index 000000000..06913470e --- /dev/null +++ b/lib/i386/relocator_backward.S @@ -0,0 +1,2 @@ +#define BACKWARD +#include "relocator_asm.S" diff --git a/lib/ieee1275/datetime.c b/lib/ieee1275/datetime.c new file mode 100644 index 000000000..7e6f8d1f1 --- /dev/null +++ b/lib/ieee1275/datetime.c @@ -0,0 +1,142 @@ +/* kern/cmos_datetime.c - CMOS datetime function. + * + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 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 . + */ + +#include +#include +#include + +static char *rtc = 0; + +static void +find_rtc (void) +{ + auto int hook (struct grub_ieee1275_devalias *alias); + int hook (struct grub_ieee1275_devalias *alias) + { + if (grub_strcmp (alias->type, "rtc") == 0) + { + grub_dprintf ("datetime", "Found RTC %s\n", alias->path); + rtc = grub_strdup (alias->path); + return 1; + } + return 0; + } + + grub_ieee1275_devices_iterate (hook); +} + +grub_err_t +grub_get_datetime (struct grub_datetime *datetime) +{ + struct get_time_args + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t method; + grub_ieee1275_cell_t device; + grub_ieee1275_cell_t catch_result; + grub_ieee1275_cell_t year; + grub_ieee1275_cell_t month; + grub_ieee1275_cell_t day; + grub_ieee1275_cell_t hour; + grub_ieee1275_cell_t minute; + grub_ieee1275_cell_t second; + } + args; + int status; + grub_ieee1275_ihandle_t ihandle; + + if (!rtc) + find_rtc (); + if (!rtc) + return grub_error (GRUB_ERR_IO, "no RTC found"); + + status = grub_ieee1275_open (rtc, &ihandle); + if (status == -1) + return grub_error (GRUB_ERR_IO, "couldn't open RTC"); + + INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 7); + args.device = (grub_ieee1275_cell_t) ihandle; + args.method = (grub_ieee1275_cell_t) "get-time"; + + status = IEEE1275_CALL_ENTRY_FN (&args); + + grub_ieee1275_close (ihandle); + + if (status == -1) + return grub_error (GRUB_ERR_IO, "get-time failed"); + + datetime->year = args.year; + datetime->month = args.month; + datetime->day = args.day; + datetime->hour = args.hour; + datetime->minute = args.minute; + datetime->second = args.second; + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_set_datetime (struct grub_datetime *datetime) +{ + struct set_time_args + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t method; + grub_ieee1275_cell_t device; + grub_ieee1275_cell_t year; + grub_ieee1275_cell_t month; + grub_ieee1275_cell_t day; + grub_ieee1275_cell_t hour; + grub_ieee1275_cell_t minute; + grub_ieee1275_cell_t second; + grub_ieee1275_cell_t catch_result; + } + args; + int status; + grub_ieee1275_ihandle_t ihandle; + + if (!rtc) + find_rtc (); + if (!rtc) + return grub_error (GRUB_ERR_IO, "no RTC found"); + + status = grub_ieee1275_open (rtc, &ihandle); + if (status == -1) + return grub_error (GRUB_ERR_IO, "couldn't open RTC"); + + INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 1); + args.device = (grub_ieee1275_cell_t) ihandle; + args.method = (grub_ieee1275_cell_t) "set-time"; + + args.year = datetime->year; + args.month = datetime->month; + args.day = datetime->day; + args.hour = datetime->hour; + args.minute = datetime->minute; + args.second = datetime->second; + + status = IEEE1275_CALL_ENTRY_FN (&args); + + grub_ieee1275_close (ihandle); + + if (status == -1) + return grub_error (GRUB_ERR_IO, "set-time failed"); + + return GRUB_ERR_NONE; +} diff --git a/lib/libgcrypt_wrap/cipher_wrap.h b/lib/libgcrypt_wrap/cipher_wrap.h new file mode 100644 index 000000000..b4530c112 --- /dev/null +++ b/lib/libgcrypt_wrap/cipher_wrap.h @@ -0,0 +1,86 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#ifndef GRUB_GCRY_WRAP_HEADER +#define GRUB_GCRY_WRAP_HEADER 1 + +#include +#include +#include +#include +#include + +#define __GNU_LIBRARY__ + +#define DIM ARRAY_SIZE + +typedef grub_uint64_t u64; +typedef grub_uint32_t u32; +typedef grub_uint16_t u16; +typedef grub_uint8_t byte; +typedef grub_size_t size_t; + +#define U64_C(c) (c ## ULL) + +#define _gcry_burn_stack grub_burn_stack +#define log_error(fmt, args...) grub_dprintf ("crypto", fmt, ## args) + + +#define PUBKEY_FLAG_NO_BLINDING (1 << 0) + +#define CIPHER_INFO_NO_WEAK_KEY 1 + +#define HAVE_U64_TYPEDEF 1 + +typedef union { + int a; + short b; + char c[1]; + long d; +#ifdef HAVE_U64_TYPEDEF + u64 e; +#endif + float f; + double g; +} PROPERLY_ALIGNED_TYPE; + +#define gcry_assert(x) grub_assert_real(GRUB_FILE, __LINE__, x) + +static inline void +grub_assert_real (const char *file, int line, int cond) +{ + if (!cond) + grub_fatal ("Assertion failed at %s:%d\n", file, line); +} + +/* Selftests are in separate modules. */ +static inline char * +selftest (void) +{ + return NULL; +} + +static inline int +fips_mode (void) +{ + return 0; +} + +#define memset grub_memset + +#endif diff --git a/lib/mips/relocator.c b/lib/mips/relocator.c new file mode 100644 index 000000000..118ddbd6f --- /dev/null +++ b/lib/mips/relocator.c @@ -0,0 +1,112 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include + +#include +#include +#include +#include + +#include + +/* Remark: doesn't work with source outside of 4G. + Use relocator64 in this case. + */ + +extern grub_uint8_t grub_relocator32_forward_start; +extern grub_uint8_t grub_relocator32_forward_end; +extern grub_uint8_t grub_relocator32_backward_start; +extern grub_uint8_t grub_relocator32_backward_end; + +#define REGW_SIZEOF (2 * sizeof (grub_uint32_t)) +#define JUMP_SIZEOF (2 * sizeof (grub_uint32_t)) + +#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator32_##x##_end \ + - &grub_relocator32_##x##_start) +#define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \ + + REGW_SIZEOF * (31 + 3) + JUMP_SIZEOF) +#define RELOCATOR_ALIGN 16 + +#define PREFIX(x) grub_relocator32_ ## x + +static void +write_reg (int regn, grub_uint32_t val, void **target) +{ + /* lui $r, (val+0x8000). */ + *(grub_uint32_t *) *target = ((0x3c00 | regn) << 16) | ((val + 0x8000) >> 16); + *target = ((grub_uint32_t *) *target) + 1; + /* addiu $r, $r, val. */ + *(grub_uint32_t *) *target = (((0x2400 | regn << 5 | regn) << 16) + | (val & 0xffff)); + *target = ((grub_uint32_t *) *target) + 1; +} + +static void +write_jump (int regn, void **target) +{ + /* j $r. */ + *(grub_uint32_t *) *target = (regn<<21) | 0x8; + *target = ((grub_uint32_t *) *target) + 1; + /* nop. */ + *(grub_uint32_t *) *target = 0; + *target = ((grub_uint32_t *) *target) + 1; +} + +static void +write_call_relocator_bw (void *ptr0, void *src, grub_uint32_t dest, + grub_size_t size, struct grub_relocator32_state state) +{ + void *ptr = ptr0; + int i; + write_reg (8, (grub_uint32_t) src, &ptr); + write_reg (9, dest, &ptr); + write_reg (10, size, &ptr); + grub_memcpy (ptr, &grub_relocator32_backward_start, + RELOCATOR_SRC_SIZEOF (backward)); + ptr = (grub_uint8_t *) ptr + RELOCATOR_SRC_SIZEOF (backward); + for (i = 1; i < 32; i++) + write_reg (i, state.gpr[i], &ptr); + write_jump (state.jumpreg, &ptr); + grub_arch_sync_caches (ptr0, (grub_uint8_t *) ptr - (grub_uint8_t *) ptr0); + grub_dprintf ("relocator", "Backward relocator: about to jump to %p\n", ptr0); + ((void (*) (void)) ptr0) (); +} + +static void +write_call_relocator_fw (void *ptr0, void *src, grub_uint32_t dest, + grub_size_t size, struct grub_relocator32_state state) +{ + void *ptr = ptr0; + int i; + write_reg (8, (grub_uint32_t) src, &ptr); + write_reg (9, dest, &ptr); + write_reg (10, size, &ptr); + grub_memcpy (ptr, &grub_relocator32_forward_start, + RELOCATOR_SRC_SIZEOF (forward)); + ptr = (grub_uint8_t *) ptr + RELOCATOR_SRC_SIZEOF (forward); + for (i = 1; i < 32; i++) + write_reg (i, state.gpr[i], &ptr); + write_jump (state.jumpreg, &ptr); + grub_arch_sync_caches (ptr0, (grub_uint8_t *) ptr - (grub_uint8_t *) ptr0); + grub_dprintf ("relocator", "Forward relocator: about to jump to %p\n", ptr0); + ((void (*) (void)) ptr0) (); +} + +#include "../relocator.c" diff --git a/lib/mips/relocator_asm.S b/lib/mips/relocator_asm.S new file mode 100644 index 000000000..ff4fa31e0 --- /dev/null +++ b/lib/mips/relocator_asm.S @@ -0,0 +1,58 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include + + .p2align 4 /* force 16-byte alignment */ + +VARIABLE (grub_relocator32_forward_start) + move $a0, $9 + move $a1, $10 + +copycont1: + lb $11,0($8) + sb $11,0($9) + addiu $8, $8, 0x1 + addiu $9, $9, 0x1 + addiu $10, $10, 0xffff + bne $10, $0, copycont1 + +#include "../../kern/mips/cache_flush.S" + +VARIABLE (grub_relocator32_forward_end) + +VARIABLE (grub_relocator32_backward_start) + move $a0, $9 + move $a1, $10 + + addu $9, $9, $10 + addu $8, $8, $10 + /* Backward movsl is implicitly off-by-one. compensate that. */ + addiu $9, $9, 0xffff + addiu $8, $8, 0xffff +copycont2: + lb $11,0($8) + sb $11,0($9) + addiu $8, $8, 0xffff + addiu $9, $9, 0xffff + addiu $10, 0xffff + bne $10, $0, copycont2 + +#include "../../kern/mips/cache_flush.S" + +VARIABLE (grub_relocator32_backward_end) diff --git a/lib/mips/setjmp.S b/lib/mips/setjmp.S new file mode 100644 index 000000000..8ab6222c4 --- /dev/null +++ b/lib/mips/setjmp.S @@ -0,0 +1,65 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2007,2009 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 . + */ + +#include + + .file "setjmp.S" + + .text + +/* + * int grub_setjmp (grub_jmp_buf env) + */ +FUNCTION(grub_setjmp) + sw $s0, 0($a0) + sw $s1, 4($a0) + sw $s2, 8($a0) + sw $s3, 12($a0) + sw $s4, 16($a0) + sw $s5, 20($a0) + sw $s6, 24($a0) + sw $s7, 28($a0) + sw $s8, 32($a0) + sw $gp, 36($a0) + sw $sp, 40($a0) + sw $ra, 44($a0) + move $v0, $zero + move $v1, $zero + jr $ra +/* + * int grub_longjmp (grub_jmp_buf env, int val) + */ +FUNCTION(grub_longjmp) + lw $s0, 0($a0) + lw $s1, 4($a0) + lw $s2, 8($a0) + lw $s3, 12($a0) + lw $s4, 16($a0) + lw $s5, 20($a0) + lw $s6, 24($a0) + lw $s7, 28($a0) + lw $s8, 32($a0) + lw $gp, 36($a0) + lw $sp, 40($a0) + lw $ra, 44($a0) + move $v0, $a1 + bne $v0, $zero, 1f + addiu $v0, $v0, 1 +1: + move $v1, $zero + jr $ra diff --git a/lib/pbkdf2.c b/lib/pbkdf2.c new file mode 100644 index 000000000..083446ab9 --- /dev/null +++ b/lib/pbkdf2.c @@ -0,0 +1,102 @@ +/* gc-pbkdf2-sha1.c --- Password-Based Key Derivation Function a'la PKCS#5 + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2009 Free Software Foundation, Inc. + + This program 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 2, or (at your option) + any later version. + + This program 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 this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Simon Josefsson. */ +/* Imported from gnulib. */ + +#include +#include +#include + +/* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant + of digest supplied by MD. Inputs are the password P of length PLEN, + the salt S of length SLEN, the iteration counter C (> 0), and the + desired derived output length DKLEN. Output buffer is DK which + must have room for at least DKLEN octets. The output buffer will + be filled with the derived data. */ +gcry_err_code_t +grub_crypto_pbkdf2 (const struct gcry_md_spec *md, + const grub_uint8_t *P, grub_size_t Plen, + const grub_uint8_t *S, grub_size_t Slen, + unsigned int c, + grub_uint8_t *DK, grub_size_t dkLen) +{ + unsigned int hLen = md->mdlen; + grub_uint8_t U[md->mdlen]; + grub_uint8_t T[md->mdlen]; + unsigned int u; + unsigned int l; + unsigned int r; + unsigned int i; + unsigned int k; + gcry_err_code_t rc; + grub_uint8_t *tmp; + grub_size_t tmplen = Slen + 4; + + if (c == 0) + return GPG_ERR_INV_ARG; + + if (dkLen == 0) + return GPG_ERR_INV_ARG; + + if (dkLen > 4294967295U) + return GPG_ERR_INV_ARG; + + l = ((dkLen - 1) / hLen) + 1; + r = dkLen - (l - 1) * hLen; + + tmp = grub_malloc (tmplen); + if (tmp == NULL) + return GPG_ERR_OUT_OF_MEMORY; + + grub_memcpy (tmp, S, Slen); + + for (i = 1; i <= l; i++) + { + grub_memset (T, 0, hLen); + + for (u = 1; u <= c; u++) + { + if (u == 1) + { + tmp[Slen + 0] = (i & 0xff000000) >> 24; + tmp[Slen + 1] = (i & 0x00ff0000) >> 16; + tmp[Slen + 2] = (i & 0x0000ff00) >> 8; + tmp[Slen + 3] = (i & 0x000000ff) >> 0; + + rc = grub_crypto_hmac_buffer (md, P, Plen, tmp, tmplen, U); + } + else + rc = grub_crypto_hmac_buffer (md, P, Plen, U, hLen, U); + + if (rc != GPG_ERR_NO_ERROR) + { + grub_free (tmp); + return rc; + } + + for (k = 0; k < hLen; k++) + T[k] ^= U[k]; + } + + grub_memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen); + } + + grub_free (tmp); + + return GPG_ERR_NO_ERROR; +} diff --git a/lib/posix_wrap/assert.h b/lib/posix_wrap/assert.h new file mode 100644 index 000000000..94cfdd543 --- /dev/null +++ b/lib/posix_wrap/assert.h @@ -0,0 +1,33 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#ifndef GRUB_POSIX_ASSERT_H +#define GRUB_POSIX_ASSERT_H 1 + +#include + +#define assert(x) assert_real(__FILE__, __LINE__, x) + +static inline void +assert_real (const char *file, int line, int cond) +{ + if (!cond) + grub_fatal ("Assertion failed at %s:%d\n", file, line); +} + +#endif diff --git a/lib/posix_wrap/ctype.h b/lib/posix_wrap/ctype.h new file mode 100644 index 000000000..2dc3e53e9 --- /dev/null +++ b/lib/posix_wrap/ctype.h @@ -0,0 +1,103 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#ifndef GRUB_POSIX_CTYPE_H +#define GRUB_POSIX_CTYPE_H 1 + +#include + +static inline int +toupper (int c) +{ + return grub_toupper (c); +} + +static inline int +isspace (int c) +{ + return grub_isspace (c); +} + +static inline int +isdigit (int c) +{ + return grub_isdigit (c); +} + +static inline int +islower (int c) +{ + return (c >= 'a' && c <= 'z'); +} + +static inline int +isupper (int c) +{ + return (c >= 'A' && c <= 'Z'); +} + +static inline int +isxdigit (int c) +{ + return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') + || (c >= '0' && c <= '9'); +} + +static inline int +isprint (int c) +{ + return grub_isprint (c); +} + +static inline int +iscntrl (int c) +{ + return !grub_isprint (c); +} + +static inline int +isgraph (int c) +{ + return grub_isprint (c) && !grub_isspace (c); +} + +static inline int +isalnum (int c) +{ + return grub_isalpha (c) || grub_isdigit (c); +} + +static inline int +ispunct (int c) +{ + return grub_isprint (c) && !grub_isspace (c) && !isalnum (c); +} + +static inline int +isalpha (int c) +{ + return grub_isalpha (c); +} + +static inline int +tolower (int c) +{ + return grub_tolower (c); +} + +#endif diff --git a/lib/posix_wrap/errno.h b/lib/posix_wrap/errno.h new file mode 100644 index 000000000..9031722e2 --- /dev/null +++ b/lib/posix_wrap/errno.h @@ -0,0 +1,28 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#ifndef GRUB_POSIX_ERRNO_H +#define GRUB_POSIX_ERRNO_H 1 + +#include + +#define errno grub_errno +#define EINVAL GRUB_ERR_BAD_NUMBER +#define ENOMEM GRUB_ERR_OUT_OF_MEMORY + +#endif diff --git a/lib/posix_wrap/langinfo.h b/lib/posix_wrap/langinfo.h new file mode 100644 index 000000000..14833c0b8 --- /dev/null +++ b/lib/posix_wrap/langinfo.h @@ -0,0 +1,38 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#ifndef GRUB_POSIX_LANGINFO_H +#define GRUB_POSIX_LANGINFO_H 1 + +#include + +typedef enum { CODESET } nl_item; + +static inline char * +nl_langinfo (nl_item item) +{ + switch (item) + { + case CODESET: + return locale_charset (); + default: + return ""; + } +} + +#endif diff --git a/lib/posix_wrap/limits.h b/lib/posix_wrap/limits.h new file mode 100644 index 000000000..e69de29bb diff --git a/lib/posix_wrap/localcharset.h b/lib/posix_wrap/localcharset.h new file mode 100644 index 000000000..92eb815ec --- /dev/null +++ b/lib/posix_wrap/localcharset.h @@ -0,0 +1,28 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#ifndef GRUB_POSIX_LOCALCHARSET_H +#define GRUB_POSIX_LOCALCHARSET_H 1 + +static inline char * +locale_charset (void) +{ + return "UTF-8"; +} + +#endif diff --git a/lib/posix_wrap/locale.h b/lib/posix_wrap/locale.h new file mode 100644 index 000000000..e69de29bb diff --git a/lib/posix_wrap/stdint.h b/lib/posix_wrap/stdint.h new file mode 100644 index 000000000..a12c43b15 --- /dev/null +++ b/lib/posix_wrap/stdint.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/sparc64/kernel.h b/lib/posix_wrap/stdio.h similarity index 68% rename from include/grub/sparc64/kernel.h rename to lib/posix_wrap/stdio.h index 9f404b05d..701fceaa4 100644 --- a/include/grub/sparc64/kernel.h +++ b/lib/posix_wrap/stdio.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 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 @@ -16,15 +16,14 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_KERNEL_CPU_HEADER -#define GRUB_KERNEL_CPU_HEADER 1 +#ifndef GRUB_POSIX_STDIO_H +#define GRUB_POSIX_STDIO_H 1 -#define GRUB_MOD_ALIGN 0x2000 +#include +#include -/* Non-zero value is only needed for PowerMacs. */ -#define GRUB_MOD_GAP 0x0 +typedef struct grub_file FILE; -#define GRUB_KERNEL_CPU_PREFIX 0x2 -#define GRUB_KERNEL_CPU_DATA_END 0x42 +#define EOF -1 #endif diff --git a/lib/posix_wrap/stdlib.h b/lib/posix_wrap/stdlib.h new file mode 100644 index 000000000..5ef6159ef --- /dev/null +++ b/lib/posix_wrap/stdlib.h @@ -0,0 +1,56 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#ifndef GRUB_POSIX_STDLIB_H +#define GRUB_POSIX_STDLIB_H 1 + +#include + +static inline void +free (void *ptr) +{ + grub_free (ptr); +} + +static inline void * +malloc (grub_size_t size) +{ + return grub_malloc (size); +} + +static inline void * +calloc (grub_size_t size, grub_size_t nelem) +{ + return grub_zalloc (size * nelem); +} + +static inline void * +realloc (void *ptr, grub_size_t size) +{ + return grub_realloc (ptr, size); +} + +static inline void +abort (void) +{ + grub_abort (); +} + +#define MB_CUR_MAX 6 + +#endif diff --git a/include/grub/i386/kernel.h b/lib/posix_wrap/string.h similarity index 63% rename from include/grub/i386/kernel.h rename to lib/posix_wrap/string.h index 5514c8ccf..7bb6f1e6f 100644 --- a/include/grub/i386/kernel.h +++ b/lib/posix_wrap/string.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 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 @@ -16,20 +16,25 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_KERNEL_CPU_HEADER -#define GRUB_KERNEL_CPU_HEADER 1 +#ifndef GRUB_POSIX_STRING_H +#define GRUB_POSIX_STRING_H 1 +static inline grub_size_t +strlen (const char *s) +{ + return grub_strlen (s); +} -#ifdef GRUB_MACHINE_IEEE1275 -#define GRUB_MOD_ALIGN 0x1000 -#else -#define GRUB_MOD_ALIGN 0x1 -#endif +static inline int +strcmp (const char *s1, const char *s2) +{ + return grub_strcmp (s1, s2); +} -/* Non-zero value is only needed for PowerMacs. */ -#define GRUB_MOD_GAP 0x0 - -#define GRUB_KERNEL_CPU_PREFIX 0x2 -#define GRUB_KERNEL_CPU_DATA_END 0x42 +static inline int +strcasecmp (const char *s1, const char *s2) +{ + return grub_strcasecmp (s1, s2); +} #endif diff --git a/lib/posix_wrap/sys/types.h b/lib/posix_wrap/sys/types.h new file mode 100644 index 000000000..ce3794087 --- /dev/null +++ b/lib/posix_wrap/sys/types.h @@ -0,0 +1,32 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#ifndef GRUB_POSIX_SYS_TYPES_H +#define GRUB_POSIX_SYS_TYPES_H 1 + +#include + +typedef grub_size_t size_t; +typedef int bool; +static const bool true = 1; +static const bool false = 0; + +#define ULONG_MAX GRUB_ULONG_MAX +#define UCHAR_MAX 0xff + +#endif diff --git a/lib/posix_wrap/unistd.h b/lib/posix_wrap/unistd.h new file mode 100644 index 000000000..e69de29bb diff --git a/lib/posix_wrap/wchar.h b/lib/posix_wrap/wchar.h new file mode 100644 index 000000000..fd56fd332 --- /dev/null +++ b/lib/posix_wrap/wchar.h @@ -0,0 +1,25 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#ifndef GRUB_POSIX_WCHAR_H +#define GRUB_POSIX_WCHAR_H 1 + +/* UCS-4. */ +typedef grub_uint32_t wchar_t; + +#endif diff --git a/lib/posix_wrap/wctype.h b/lib/posix_wrap/wctype.h new file mode 100644 index 000000000..e69de29bb diff --git a/lib/relocator.c b/lib/relocator.c new file mode 100644 index 000000000..6a5acc548 --- /dev/null +++ b/lib/relocator.c @@ -0,0 +1,137 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#define MAX_OVERHEAD ((RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) \ + + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN) \ + + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) \ + + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN)) +#define PRE_REGION_SIZE (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN) + +void * +PREFIX (alloc) (grub_size_t size) +{ + char *playground; + + playground = grub_malloc (size + MAX_OVERHEAD); + if (!playground) + return 0; + + *(grub_size_t *) playground = size; + + return playground + PRE_REGION_SIZE; +} + +void * +PREFIX (realloc) (void *relocator, grub_size_t size) +{ + char *playground; + + if (!relocator) + return PREFIX (alloc) (size); + + playground = (char *) relocator - PRE_REGION_SIZE; + + playground = grub_realloc (playground, size + MAX_OVERHEAD); + if (!playground) + return 0; + + *(grub_size_t *) playground = size; + + return playground + PRE_REGION_SIZE; +} + +void +PREFIX(free) (void *relocator) +{ + if (relocator) + grub_free ((char *) relocator - PRE_REGION_SIZE); +} + +grub_err_t +PREFIX (boot) (void *relocator, grub_uint32_t dest, + struct grub_relocator32_state state) +{ + grub_size_t size; + char *playground; + + playground = (char *) relocator - PRE_REGION_SIZE; + size = *(grub_size_t *) playground; + + grub_dprintf ("relocator", + "Relocator: source: %p, destination: 0x%x, size: 0x%lx\n", + relocator, (unsigned) dest, (unsigned long) size); + + /* Very unlikely condition: Relocator may risk overwrite itself. + Just move it a bit up. */ + if ((grub_addr_t) dest < (grub_addr_t) relocator + + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN) + && (grub_addr_t) dest + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) + > (grub_addr_t) relocator) + { + void *relocator_new = ((grub_uint8_t *) relocator) + + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) + + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN); + grub_dprintf ("relocator", "Overwrite condition detected moving " + "relocator from %p to %p\n", relocator, relocator_new); + grub_memmove (relocator_new, relocator, + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) + + size + + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN)); + relocator = relocator_new; + } + + if ((grub_addr_t) dest >= (grub_addr_t) relocator) + { + int overhead; + overhead = dest - + ALIGN_UP (dest - RELOCATOR_SIZEOF (backward) - RELOCATOR_ALIGN, + RELOCATOR_ALIGN); + grub_dprintf ("relocator", + "Backward relocator: code %p, source: %p, " + "destination: 0x%x, size: 0x%lx\n", + (char *) relocator - overhead, + (char *) relocator - overhead, + (unsigned) dest - overhead, + (unsigned long) size + overhead); + + write_call_relocator_bw ((char *) relocator - overhead, + (char *) relocator - overhead, + dest - overhead, size + overhead, state); + } + else + { + int overhead; + + overhead = ALIGN_UP (dest + size, RELOCATOR_ALIGN) + + RELOCATOR_SIZEOF (forward) - (dest + size); + grub_dprintf ("relocator", + "Forward relocator: code %p, source: %p, " + "destination: 0x%x, size: 0x%lx\n", + (char *) relocator + size + overhead + - RELOCATOR_SIZEOF (forward), + relocator, (unsigned) dest, + (unsigned long) size + overhead); + + write_call_relocator_fw ((char *) relocator + size + overhead + - RELOCATOR_SIZEOF (forward), + relocator, dest, size + overhead, state); + } + + /* Not reached. */ + return GRUB_ERR_NONE; +} diff --git a/loader/efi/appleloader.c b/loader/efi/appleloader.c index 94d501bcf..dc42683a6 100644 --- a/loader/efi/appleloader.c +++ b/loader/efi/appleloader.c @@ -1,7 +1,7 @@ /* appleloader.c - apple legacy boot loader. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 @@ -25,6 +25,7 @@ #include #include #include +#include static grub_dl_t my_mod; @@ -59,58 +60,171 @@ grub_appleloader_boot (void) return grub_errno; } -/* early 2006 Core Duo / Core Solo models */ -static grub_uint8_t devpath_1[] = +struct piwg_full_device_path { - 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, - 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, - 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, + struct grub_efi_memory_mapped_device_path comp1; + struct grub_efi_piwg_device_path comp2; + struct grub_efi_device_path end; +}; + +/* early 2006 Core Duo / Core Solo models */ +static struct piwg_full_device_path devpath_1 = +{ + .comp1 = + { + .header = { + .type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_memory_mapped_device_path), 0} + }, + .memory_type = GRUB_EFI_MEMORY_MAPPED_IO, + .start_address = 0xffe00000, + .end_address = 0xfff9ffff + }, + .comp2 = + { + .header = { + .type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_piwg_device_path), 0} + }, + .guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7}} + }, + .end = + { + .type = GRUB_EFI_END_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_device_path), 0} + } }; /* mid-2006 Mac Pro (and probably other Core 2 models) */ -static grub_uint8_t devpath_2[] = +static struct piwg_full_device_path devpath_2 = { - 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, - 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, - 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, + .comp1 = + { + .header = { + .type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_memory_mapped_device_path), 0} + }, + .memory_type = GRUB_EFI_MEMORY_MAPPED_IO, + .start_address = 0xffe00000, + .end_address = 0xfff7ffff + }, + .comp2 = + { + .header = { + .type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_piwg_device_path), 0} + }, + .guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7}} + }, + .end = + { + .type = GRUB_EFI_END_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_device_path), 0} + } }; /* mid-2007 MBP ("Santa Rosa" based models) */ -static grub_uint8_t devpath_3[] = +static struct piwg_full_device_path devpath_3 = { - 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, - 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, - 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, + .comp1 = + { + .header = { + .type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_memory_mapped_device_path), 0} + }, + .memory_type = GRUB_EFI_MEMORY_MAPPED_IO, + .start_address = 0xffe00000, + .end_address = 0xfff8ffff + }, + .comp2 = + { + .header = { + .type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_piwg_device_path), 0} + }, + .guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7}} + }, + .end = + { + .type = GRUB_EFI_END_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_device_path), 0} + } }; /* early-2008 MBA */ -static grub_uint8_t devpath_4[] = +static struct piwg_full_device_path devpath_4 = { - 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, - 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, - 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, + .comp1 = + { + .header = { + .type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_memory_mapped_device_path), 0} + }, + .memory_type = GRUB_EFI_MEMORY_MAPPED_IO, + .start_address = 0xffc00000, + .end_address = 0xfff8ffff + }, + .comp2 = + { + .header = { + .type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_piwg_device_path), 0} + }, + .guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7}} + }, + .end = + { + .type = GRUB_EFI_END_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_device_path), 0} + } }; /* late-2008 MB/MBP (NVidia chipset) */ -static grub_uint8_t devpath_5[] = { - 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x40, 0xCB, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, - 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, - 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +static struct piwg_full_device_path devpath_5 = +{ + .comp1 = + { + .header = { + .type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_memory_mapped_device_path), 0} + }, + .memory_type = GRUB_EFI_MEMORY_MAPPED_IO, + .start_address = 0xffcb4000, + .end_address = 0xffffbfff + }, + .comp2 = + { + .header = { + .type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_piwg_device_path), 0} + }, + .guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7}} + }, + .end = + { + .type = GRUB_EFI_END_DEVICE_PATH_TYPE, + .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, + .length = {sizeof (struct grub_efi_device_path), 0} + } }; struct devdata @@ -121,11 +235,11 @@ struct devdata struct devdata devs[] = { - {"Core Duo/Solo", (grub_efi_device_path_t *) devpath_1}, - {"Mac Pro", (grub_efi_device_path_t *) devpath_2}, - {"MBP", (grub_efi_device_path_t *) devpath_3}, - {"MBA", (grub_efi_device_path_t *) devpath_4}, - {"MB NV", (grub_efi_device_path_t *) devpath_5}, + {"Core Duo/Solo", (grub_efi_device_path_t *) &devpath_1}, + {"Mac Pro", (grub_efi_device_path_t *) &devpath_2}, + {"MBP", (grub_efi_device_path_t *) &devpath_3}, + {"MBA", (grub_efi_device_path_t *) &devpath_4}, + {"MB NV", (grub_efi_device_path_t *) &devpath_5}, {NULL, NULL}, }; @@ -208,7 +322,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(appleloader) { cmd = grub_register_command ("appleloader", grub_cmd_appleloader, - "appleloader [OPTS]", "Boot legacy system."); + "[OPTS]", N_("Boot legacy system.")); my_mod = mod; } diff --git a/loader/efi/chainloader.c b/loader/efi/chainloader.c index 01acc4135..a095ad931 100644 --- a/loader/efi/chainloader.c +++ b/loader/efi/chainloader.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include static grub_dl_t my_mod; @@ -335,7 +337,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(chainloader) { cmd = grub_register_command ("chainloader", grub_cmd_chainloader, - 0, "load another boot loader"); + 0, N_("Load another boot loader.")); my_mod = mod; } diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c index 6f2202a67..3c7fe2fee 100644 --- a/loader/i386/bsd.c +++ b/loader/i386/bsd.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008, 2009 Free Software Foundation, Inc. + * Copyright (C) 2008,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 @@ -34,7 +34,8 @@ #include #include #include - +#include +#include #ifdef GRUB_MACHINE_PCBIOS #include #endif @@ -61,20 +62,20 @@ static grub_uint32_t openbsd_root; static const struct grub_arg_option freebsd_opts[] = { - {"dual", 'D', 0, "Display output on all consoles.", 0, 0}, - {"serial", 'h', 0, "Use serial console.", 0, 0}, - {"askname", 'a', 0, "Ask for file name to reboot from.", 0, 0}, - {"cdrom", 'C', 0, "Use cdrom as root.", 0, 0}, - {"config", 'c', 0, "Invoke user configuration routing.", 0, 0}, - {"kdb", 'd', 0, "Enter in KDB on boot.", 0, 0}, - {"gdb", 'g', 0, "Use GDB remote debugger instead of DDB.", 0, 0}, - {"mute", 'm', 0, "Disable all boot output.", 0, 0}, + {"dual", 'D', 0, N_("Display output on all consoles."), 0, 0}, + {"serial", 'h', 0, N_("Use serial console."), 0, 0}, + {"askname", 'a', 0, N_("Ask for file name to reboot from."), 0, 0}, + {"cdrom", 'C', 0, N_("Use CDROM as root."), 0, 0}, + {"config", 'c', 0, N_("Invoke user configuration routing."), 0, 0}, + {"kdb", 'd', 0, N_("Enter in KDB on boot."), 0, 0}, + {"gdb", 'g', 0, N_("Use GDB remote debugger instead of DDB."), 0, 0}, + {"mute", 'm', 0, N_("Disable all boot output."), 0, 0}, {"nointr", 'n', 0, "", 0, 0}, - {"pause", 'p', 0, "Wait for keypress after every line of output.", 0, 0}, + {"pause", 'p', 0, N_("Wait for keypress after every line of output."), 0, 0}, {"quiet", 'q', 0, "", 0, 0}, - {"dfltroot", 'r', 0, "Use compiled-in rootdev.", 0, 0}, - {"single", 's', 0, "Boot into single mode.", 0, 0}, - {"verbose", 'v', 0, "Boot with verbose messages.", 0, 0}, + {"dfltroot", 'r', 0, N_("Use compiled-in rootdev."), 0, 0}, + {"single", 's', 0, N_("Boot into single mode."), 0, 0}, + {"verbose", 'v', 0, N_("Boot with verbose messages."), 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -89,12 +90,12 @@ static const grub_uint32_t freebsd_flags[] = static const struct grub_arg_option openbsd_opts[] = { - {"askname", 'a', 0, "Ask for file name to reboot from.", 0, 0}, - {"halt", 'b', 0, "Don't reboot, just halt.", 0, 0}, - {"config", 'c', 0, "Change configured devices.", 0, 0}, - {"single", 's', 0, "Boot into single mode.", 0, 0}, - {"kdb", 'd', 0, "Enter in KDB on boot.", 0, 0}, - {"root", 'r', 0, "Set root device.", "wdXY", ARG_TYPE_STRING}, + {"askname", 'a', 0, N_("Ask for file name to reboot from."), 0, 0}, + {"halt", 'b', 0, N_("Don't reboot, just halt."), 0, 0}, + {"config", 'c', 0, N_("Change configured devices."), 0, 0}, + {"single", 's', 0, N_("Boot into single mode."), 0, 0}, + {"kdb", 'd', 0, N_("Enter in KDB on boot."), 0, 0}, + {"root", 'r', 0, N_("Set root device."), "wdXY", ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -108,19 +109,19 @@ static const grub_uint32_t openbsd_flags[] = static const struct grub_arg_option netbsd_opts[] = { - {"no-smp", '1', 0, "Disable SMP.", 0, 0}, - {"no-acpi", '2', 0, "Disable ACPI.", 0, 0}, - {"askname", 'a', 0, "Ask for file name to reboot from.", 0, 0}, - {"halt", 'b', 0, "Don't reboot, just halt.", 0, 0}, - {"config", 'c', 0, "Change configured devices.", 0, 0}, - {"kdb", 'd', 0, "Enter in KDB on boot.", 0, 0}, + {"no-smp", '1', 0, N_("Disable SMP."), 0, 0}, + {"no-acpi", '2', 0, N_("Disable ACPI."), 0, 0}, + {"askname", 'a', 0, N_("Ask for file name to reboot from."), 0, 0}, + {"halt", 'b', 0, N_("Don't reboot, just halt."), 0, 0}, + {"config", 'c', 0, N_("Change configured devices."), 0, 0}, + {"kdb", 'd', 0, N_("Enter in KDB on boot."), 0, 0}, {"miniroot", 'm', 0, "", 0, 0}, - {"quiet", 'q', 0, "Don't display boot diagnostic messages.", 0, 0}, - {"single", 's', 0, "Boot into single mode.", 0, 0}, - {"verbose", 'v', 0, "Boot with verbose messages.", 0, 0}, - {"debug", 'x', 0, "Boot with debug messages.", 0, 0}, - {"silent", 'z', 0, "Supress normal output (warnings remain).", 0, 0}, - {"root", 'r', 0, "Set root device.", "DEVICE", ARG_TYPE_STRING}, + {"quiet", 'q', 0, N_("Don't display boot diagnostic messages."), 0, 0}, + {"single", 's', 0, N_("Boot into single mode."), 0, 0}, + {"verbose", 'v', 0, N_("Boot with verbose messages."), 0, 0}, + {"debug", 'x', 0, N_("Boot with debug messages."), 0, 0}, + {"silent", 'z', 0, N_("Supress normal output (warnings remain)."), 0, 0}, + {"root", 'r', 0, N_("Set root device."), N_("DEVICE"), ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -139,8 +140,7 @@ grub_bsd_get_device (grub_uint32_t * biosdev, grub_uint32_t * unit, grub_uint32_t * slice, grub_uint32_t * part) { - char *p; - grub_device_t dev; + grub_device_t dev; #ifdef GRUB_MACHINE_PCBIOS *biosdev = grub_get_root_biosnumber () & 0xff; @@ -153,21 +153,13 @@ grub_bsd_get_device (grub_uint32_t * biosdev, dev = grub_device_open (0); if (dev && dev->disk && dev->disk->partition) { - - p = dev->disk->partition->partmap->get_name (dev->disk->partition); - if (p) + if (dev->disk->partition->parent) { - if ((p[0] >= '0') && (p[0] <= '9')) - { - *slice = grub_strtoul (p, &p, 0); - - if ((p) && (p[0] == ',')) - p++; - } - - if ((p[0] >= 'a') && (p[0] <= 'z')) - *part = p[0] - 'a'; + *part = dev->disk->partition->number; + *slice = dev->disk->partition->parent->number + 1; } + else + *slice = dev->disk->partition->number + 1; } if (dev) grub_device_close (dev); @@ -460,14 +452,14 @@ grub_freebsd_boot (void) } grub_memset (&bi, 0, sizeof (bi)); - bi.bi_version = FREEBSD_BOOTINFO_VERSION; - bi.bi_size = sizeof (bi); + bi.version = FREEBSD_BOOTINFO_VERSION; + bi.length = sizeof (bi); grub_bsd_get_device (&biosdev, &unit, &slice, &part); bootdev = (FREEBSD_B_DEVMAGIC + ((slice + 1) << FREEBSD_B_SLICESHIFT) + (unit << FREEBSD_B_UNITSHIFT) + (part << FREEBSD_B_PARTSHIFT)); - bi.bi_bios_dev = biosdev; + bi.boot_device = biosdev; p = (char *) kern_end; @@ -477,7 +469,7 @@ grub_freebsd_boot (void) { *(p++) = 0; - bi.bi_envp = kern_end; + bi.environment = kern_end; kern_end = ALIGN_PAGE ((grub_uint32_t) p); } @@ -490,23 +482,25 @@ grub_freebsd_boot (void) return grub_errno; grub_memcpy ((char *) kern_end, mod_buf, mod_buf_len); - bi.bi_modulep = kern_end; + bi.tags = kern_end; kern_end = ALIGN_PAGE (kern_end + mod_buf_len); if (is_64bit) kern_end += 4096 * 4; - md_ofs = bi.bi_modulep + kern_end_mdofs; + md_ofs = bi.tags + kern_end_mdofs; ofs = (is_64bit) ? 16 : 12; *((grub_uint32_t *) md_ofs) = kern_end; md_ofs -= ofs; - *((grub_uint32_t *) md_ofs) = bi.bi_envp; + *((grub_uint32_t *) md_ofs) = bi.environment; md_ofs -= ofs; *((grub_uint32_t *) md_ofs) = bootflags; } - bi.bi_kernend = kern_end; + bi.kern_end = kern_end; + + grub_video_set_mode ("text", 0, 0); if (is_64bit) { @@ -551,12 +545,12 @@ grub_freebsd_boot (void) &grub_bsd64_trampoline_end - &grub_bsd64_trampoline_start); /* Launch trampoline. */ - launch_trampoline (entry, entry_hi, pagetable, bi.bi_modulep, + launch_trampoline (entry, entry_hi, pagetable, bi.tags, kern_end); } else grub_unix_real_boot (entry, bootflags | FREEBSD_RB_BOOTINFO, bootdev, - 0, 0, 0, &bi, bi.bi_modulep, kern_end); + 0, 0, 0, &bi, bi.tags, kern_end); /* Not reached. */ return GRUB_ERR_NONE; @@ -616,6 +610,8 @@ grub_openbsd_boot (void) pa->ba_type = OPENBSD_BOOTARG_END; pa++; + grub_video_set_mode ("text", 0, 0); + grub_unix_real_boot (entry, bootflags, openbsd_root, OPENBSD_BOOTARG_APIVER, 0, (grub_uint32_t) (grub_mmap_get_upper () >> 10), (grub_uint32_t) (grub_mmap_get_lower () >> 10), @@ -679,7 +675,7 @@ grub_netbsd_boot (void) + sizeof (struct grub_netbsd_btinfo_mmap_header) + count * sizeof (struct grub_netbsd_btinfo_mmap_entry) > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "No memory for boot info."); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); curarg = mmap = (struct grub_netbsd_btinfo_mmap_header *) kern_end; pm = (struct grub_netbsd_btinfo_mmap_entry *) (mmap + 1); @@ -712,6 +708,8 @@ grub_netbsd_boot (void) bootinfo->bi_data[0] = mmap; } + grub_video_set_mode ("text", 0, 0); + grub_unix_real_boot (entry, bootflags, 0, bootinfo, 0, (grub_uint32_t) (grub_mmap_get_upper () >> 10), (grub_uint32_t) (grub_mmap_get_lower () >> 10)); @@ -750,10 +748,10 @@ grub_bsd_load_aout (grub_file_t file) return grub_errno; if (grub_file_read (file, &ah, sizeof (ah)) != sizeof (ah)) - return grub_error (GRUB_ERR_READ_ERROR, "Cannot read the a.out header"); + return grub_error (GRUB_ERR_READ_ERROR, "cannot read the a.out header"); if (grub_aout_get_type (&ah) != AOUT_TYPE_AOUT32) - return grub_error (GRUB_ERR_BAD_OS, "Invalid a.out header"); + return grub_error (GRUB_ERR_BAD_OS, "invalid a.out header"); entry = ah.aout32.a_entry & 0xFFFFFF; @@ -771,7 +769,7 @@ grub_bsd_load_aout (grub_file_t file) } if (load_addr < 0x100000) - return grub_error (GRUB_ERR_BAD_OS, "Load address below 1M"); + return grub_error (GRUB_ERR_BAD_OS, "load address below 1M"); kern_start = load_addr; kern_end = load_addr + ah.aout32.a_text + ah.aout32.a_data; @@ -811,7 +809,7 @@ grub_bsd_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr, int *do_load) if ((paddr < grub_os_area_addr) || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "Address 0x%x is out of range", + return grub_error (GRUB_ERR_OUT_OF_RANGE, "address 0x%x is out of range", paddr); if ((!kern_start) || (paddr < kern_start)) @@ -842,7 +840,7 @@ grub_bsd_elf64_hook (Elf64_Phdr * phdr, grub_addr_t * addr, int *do_load) if ((paddr < grub_os_area_addr) || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "Address 0x%x is out of range", + return grub_error (GRUB_ERR_OUT_OF_RANGE, "address 0x%x is out of range", paddr); if ((!kern_start) || (paddr < kern_start)) @@ -871,7 +869,7 @@ grub_bsd_load_elf (grub_elf_t elf) is_64bit = 1; if (! grub_cpuid_has_longmode) - return grub_error (GRUB_ERR_BAD_OS, "Your CPU does not implement AMD64 architecture."); + return grub_error (GRUB_ERR_BAD_OS, "your CPU does not implement AMD64 architecture"); /* FreeBSD has 64-bit entry point. */ if (kernel_type == KERNEL_TYPE_FREEBSD) @@ -887,7 +885,7 @@ grub_bsd_load_elf (grub_elf_t elf) return grub_elf64_load (elf, grub_bsd_elf64_hook, 0, 0); } else - return grub_error (GRUB_ERR_BAD_OS, "Invalid elf"); + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); } static grub_err_t @@ -902,7 +900,7 @@ grub_bsd_load (int argc, char *argv[]) if (argc == 0) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified"); + grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); goto fail; } @@ -1024,14 +1022,14 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[]) int unit, part; if (*(arg++) != 'w' || *(arg++) != 'd') return grub_error (GRUB_ERR_BAD_ARGUMENT, - "Only device specifications of form " - "wd are supported."); + "only device specifications of form " + "wd are supported"); unit = grub_strtoul (arg, (char **) &arg, 10); if (! (arg && *arg >= 'a' && *arg <= 'z')) return grub_error (GRUB_ERR_BAD_ARGUMENT, - "Only device specifications of form " - "wd are supported."); + "only device specifications of form " + "wd are supported"); part = *arg - 'a'; @@ -1076,15 +1074,15 @@ grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)), if (kernel_type == KERNEL_TYPE_NONE) return grub_error (GRUB_ERR_BAD_ARGUMENT, - "You need to load the kernel first."); + "you need to load the kernel first"); if (kernel_type != KERNEL_TYPE_FREEBSD) return grub_error (GRUB_ERR_BAD_ARGUMENT, - "Only FreeBSD support environment"); + "only FreeBSD supports environment"); if (argc == 0) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No filename"); + grub_error (GRUB_ERR_BAD_ARGUMENT, "no filename"); goto fail; } @@ -1138,14 +1136,20 @@ grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)), if (*curr) { - char name[grub_strlen (curr) + sizeof("kFreeBSD.")]; + char *name; if (*p == '"') p++; - grub_sprintf (name, "kFreeBSD.%s", curr); - if (grub_env_set (name, p)) + name = grub_xasprintf ("kFreeBSD.%s", curr); + if (!name) goto fail; + if (grub_env_set (name, p)) + { + grub_free (name); + goto fail; + } + grub_free (name); } } @@ -1170,15 +1174,15 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)), if (kernel_type == KERNEL_TYPE_NONE) return grub_error (GRUB_ERR_BAD_ARGUMENT, - "You need to load the kernel first."); + "you need to load the kernel first"); if (kernel_type != KERNEL_TYPE_FREEBSD) return grub_error (GRUB_ERR_BAD_ARGUMENT, - "Only FreeBSD support module"); + "only FreeBSD supports module"); if (!is_elf_kernel) return grub_error (GRUB_ERR_BAD_ARGUMENT, - "Only ELF kernel support module"); + "only ELF kernel supports module"); /* List the current modules if no parameter. */ if (!argc) @@ -1193,7 +1197,7 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)), if (kern_end + file->size > grub_os_area_addr + grub_os_area_size) { - grub_error (GRUB_ERR_OUT_OF_RANGE, "Not enough memory for the module"); + grub_error (GRUB_ERR_OUT_OF_RANGE, "not enough memory for the module"); goto fail; } @@ -1236,15 +1240,15 @@ grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)), if (kernel_type == KERNEL_TYPE_NONE) return grub_error (GRUB_ERR_BAD_ARGUMENT, - "You need to load the kernel first."); + "you need to load the kernel first"); if (kernel_type != KERNEL_TYPE_FREEBSD) return grub_error (GRUB_ERR_BAD_ARGUMENT, - "Only FreeBSD support module"); + "only FreeBSD supports module"); if (! is_elf_kernel) return grub_error (GRUB_ERR_BAD_ARGUMENT, - "Only ELF kernel support module"); + "only ELF kernel supports module"); /* List the current modules if no parameter. */ if (! argc) @@ -1280,25 +1284,25 @@ GRUB_MOD_INIT (bsd) { cmd_freebsd = grub_register_extcmd ("kfreebsd", grub_cmd_freebsd, GRUB_COMMAND_FLAG_BOTH, - "kfreebsd FILE", "Load kernel of FreeBSD.", + N_("FILE"), N_("Load kernel of FreeBSD."), freebsd_opts); cmd_openbsd = grub_register_extcmd ("kopenbsd", grub_cmd_openbsd, GRUB_COMMAND_FLAG_BOTH, - "kopenbsd FILE", "Load kernel of OpenBSD.", + N_("FILE"), N_("Load kernel of OpenBSD."), openbsd_opts); cmd_netbsd = grub_register_extcmd ("knetbsd", grub_cmd_netbsd, GRUB_COMMAND_FLAG_BOTH, - "knetbsd FILE", "Load kernel of NetBSD.", + N_("FILE"), N_("Load kernel of NetBSD."), netbsd_opts); cmd_freebsd_loadenv = grub_register_command ("kfreebsd_loadenv", grub_cmd_freebsd_loadenv, - 0, "load FreeBSD env"); + 0, N_("Load FreeBSD env.")); cmd_freebsd_module = grub_register_command ("kfreebsd_module", grub_cmd_freebsd_module, - 0, "load FreeBSD kernel module"); + 0, N_("Load FreeBSD kernel module.")); cmd_freebsd_module_elf = grub_register_command ("kfreebsd_module_elf", grub_cmd_freebsd_module_elf, - 0, "load FreeBSD kernel module (ELF)"); + 0, N_("Load FreeBSD kernel module (ELF).")); my_mod = mod; } diff --git a/loader/i386/bsdXX.c b/loader/i386/bsdXX.c index aedc204b2..cd5ba85dc 100644 --- a/loader/i386/bsdXX.c +++ b/loader/i386/bsdXX.c @@ -12,7 +12,7 @@ load (grub_file_t file, void *where, grub_off_t off, grub_size_t size) { if (PTR_TO_UINT32 (where) + size > grub_os_area_addr + grub_os_area_size) return grub_error (GRUB_ERR_OUT_OF_RANGE, - "Not enough memory for the module"); + "not enough memory for the module"); if (grub_file_seek (file, off) == (grub_off_t) -1) return grub_errno; if (grub_file_read (file, where, size) @@ -80,7 +80,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, { Elf_Ehdr e; Elf_Shdr *s; - char *shdr; + char *shdr = 0; grub_addr_t curload, module; grub_err_t err; @@ -116,7 +116,7 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, case SHT_NOBITS: if (curload + s->sh_size > grub_os_area_addr + grub_os_area_size) return grub_error (GRUB_ERR_OUT_OF_RANGE, - "Not enough memory for the module"); + "not enough memory for the module"); grub_memset (UINT_TO_PTR (curload), 0, s->sh_size); break; } @@ -148,7 +148,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], { Elf_Ehdr e; Elf_Shdr *s; - char *shdr; + char *shdr = 0; grub_addr_t curload, module; grub_err_t err; @@ -185,7 +185,7 @@ SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], if (module + s->sh_addr + s->sh_size > grub_os_area_addr + grub_os_area_size) return grub_error (GRUB_ERR_OUT_OF_RANGE, - "Not enough memory for the module"); + "not enough memory for the module"); grub_memset (UINT_TO_PTR (module + s->sh_addr), 0, s->sh_size); break; } @@ -223,7 +223,7 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) grub_err_t err; Elf_Ehdr e; Elf_Shdr *s; - char *shdr; + char *shdr = 0; unsigned symoff, stroff, symsize, strsize; grub_addr_t curload; grub_freebsd_addr_t symstart, symend, symentsize, dynamic; @@ -259,7 +259,7 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) if (*kern_end + 4 * sizeof (grub_freebsd_addr_t) + symsize + strsize > grub_os_area_addr + grub_os_area_size) return grub_error (GRUB_ERR_OUT_OF_RANGE, - "Not enough memory for kernel symbols"); + "not enough memory for kernel symbols"); symstart = curload = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t)); *((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = symsize; @@ -271,7 +271,7 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) (grub_ssize_t) symsize) { if (! grub_errno) - return grub_error (GRUB_ERR_BAD_OS, "invalid elf"); + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); return grub_errno; } curload += symsize; @@ -285,7 +285,7 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) != (grub_ssize_t) strsize) { if (! grub_errno) - return grub_error (GRUB_ERR_BAD_OS, "invalid elf"); + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); return grub_errno; } curload += strsize; diff --git a/loader/i386/efi/linux.c b/loader/i386/efi/linux.c index f96c60e11..a6db22e22 100644 --- a/loader/i386/efi/linux.c +++ b/loader/i386/efi/linux.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,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 @@ -33,6 +33,7 @@ #include #include #include +#include #define GRUB_LINUX_CL_OFFSET 0x1000 #define GRUB_LINUX_CL_END_OFFSET 0x2000 @@ -469,21 +470,22 @@ find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len) { int found = 0; - auto int NESTED_FUNC_ATTR find_card (int bus, int dev, int func, + auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid); - int NESTED_FUNC_ATTR find_card (int bus, int dev, int func, + int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid) { grub_pci_address_t addr; - addr = grub_pci_make_address (bus, dev, func, 2); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); if (grub_pci_read (addr) >> 24 == 0x3) { int i; grub_printf ("Display controller: %d:%d.%d\nDevice id: %x\n", - bus, dev, func, pciid); + grub_pci_get_bus (dev), grub_pci_get_device (dev), + grub_pci_get_function (dev), pciid); addr += 8; for (i = 0; i < 6; i++, addr += 4) { @@ -574,7 +576,7 @@ grub_linux_setup_video (struct linux_kernel_params *params) params->lfb_line_len = line_len; params->lfb_base = fb_base; - params->lfb_size = (line_len * params->lfb_height + 65535) >> 16; + params->lfb_size = ALIGN_UP (line_len * params->lfb_height, 65536); params->red_mask_size = 8; params->red_field_pos = 16; @@ -585,7 +587,7 @@ grub_linux_setup_video (struct linux_kernel_params *params) params->reserved_mask_size = 8; params->reserved_field_pos = 24; - params->have_vga = GRUB_VIDEO_TYPE_VLFB; + params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA; params->vid_mode = 0x338; /* 1024x768x32 */ return 0; @@ -618,7 +620,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) { - grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux header"); + grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); goto fail; } @@ -670,12 +672,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), len = 0x400 - sizeof (lh); if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } - /* XXX Linux assumes that only elilo can boot Linux on EFI!!! */ - params->type_of_loader = (LINUX_LOADER_ID_ELILO << 4); + params->type_of_loader = (LINUX_LOADER_ID_GRUB << 4); params->cl_magic = GRUB_LINUX_CL_MAGIC; params->cl_offset = 0x1000; @@ -692,13 +693,32 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), params->ext_mem = ((32 * 0x100000) >> 10); params->alt_mem = ((32 * 0x100000) >> 10); - params->video_cursor_x = grub_getxy () >> 8; - params->video_cursor_y = grub_getxy () & 0xff; + { + grub_term_output_t term; + int found = 0; + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_strcmp (term->name, "vga_text") == 0 + || grub_strcmp (term->name, "console") == 0) + { + grub_uint16_t pos = grub_term_getxy (term); + params->video_cursor_x = pos >> 8; + params->video_cursor_y = pos & 0xff; + params->video_width = grub_term_width (term); + params->video_height = grub_term_height (term); + found = 1; + break; + } + if (!found) + { + params->video_cursor_x = 0; + params->video_cursor_y = 0; + params->video_width = 80; + params->video_height = 25; + } + } params->video_page = 0; /* ??? */ params->video_mode = grub_efi_system_table->con_out->mode->mode; - params->video_width = (grub_getwh () >> 8); params->video_ega_bx = 0; - params->video_height = (grub_getwh () & 0xff); params->have_vga = 0; params->font_size = 16; /* XXX */ @@ -831,7 +851,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), else if (grub_memcmp (argv[i], "video=efifb", 11) == 0) { if (params->have_vga) - params->have_vga = GRUB_VIDEO_TYPE_EFI; + params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; } /* Specify the boot file. */ @@ -852,7 +872,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), len = prot_size; if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len) - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); if (grub_errno == GRUB_ERR_NONE) { @@ -889,13 +909,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (argc == 0) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); + grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); goto fail; } if (! loaded) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first."); + grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); goto fail; } @@ -965,7 +985,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, initrd_mem, size) != size) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } @@ -988,9 +1008,9 @@ static grub_command_t cmd_linux, cmd_initrd; GRUB_MOD_INIT(linux) { cmd_linux = grub_register_command ("linux", grub_cmd_linux, - 0, "load linux"); + 0, N_("Load Linux.")); cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, - 0, "load initrd"); + 0, N_("Load initrd.")); my_mod = mod; } diff --git a/loader/i386/efi/xnu.c b/loader/i386/efi/xnu.c index 5085cdbea..e80f7f3dd 100644 --- a/loader/i386/efi/xnu.c +++ b/loader/i386/efi/xnu.c @@ -71,21 +71,22 @@ find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len) { int found = 0; - auto int NESTED_FUNC_ATTR find_card (int bus, int dev, int func, + auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid); - int NESTED_FUNC_ATTR find_card (int bus, int dev, int func, + int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid) { grub_pci_address_t addr; - addr = grub_pci_make_address (bus, dev, func, 2); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); if (grub_pci_read (addr) >> 24 == 0x3) { int i; grub_printf ("Display controller: %d:%d.%d\nDevice id: %x\n", - bus, dev, func, pciid); + grub_pci_get_bus (dev), grub_pci_get_device (dev), + grub_pci_get_function (dev), pciid); addr += 8; for (i = 0; i < 6; i++, addr += 4) { @@ -147,10 +148,10 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) c = grub_efi_locate_protocol (&uga_draw_guid, 0); if (! c) - return grub_error (GRUB_ERR_IO, "Couldn't find UGADraw"); + return grub_error (GRUB_ERR_IO, "couldn't find UGADraw"); if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate)) - return grub_error (GRUB_ERR_IO, "Couldn't retrieve video mode"); + return grub_error (GRUB_ERR_IO, "couldn't retrieve video mode"); grub_printf ("Video mode: %ux%u-%u@%u\n", width, height, depth, rate); @@ -162,7 +163,7 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) grub_efi_set_text_mode (1); if (! ret) - return grub_error (GRUB_ERR_IO, "Can\'t find frame buffer address\n"); + return grub_error (GRUB_ERR_IO, "can\'t find frame buffer address"); grub_printf ("Frame buffer base: 0x%x\n", fb_base); grub_printf ("Video line length: %d\n", line_len); diff --git a/loader/i386/ieee1275/linux.c b/loader/i386/ieee1275/linux.c index 529d1590a..8780804fd 100644 --- a/loader/i386/ieee1275/linux.c +++ b/loader/i386/ieee1275/linux.c @@ -1,7 +1,7 @@ /* linux.c - boot Linux zImage or bzImage */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,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 @@ -32,6 +32,7 @@ #include #include #include +#include #define GRUB_OFW_LINUX_PARAMS_ADDR 0x90000 #define GRUB_OFW_LINUX_KERNEL_ADDR 0x100000 @@ -109,8 +110,29 @@ grub_linux_boot (void) params->cl_magic = GRUB_LINUX_CL_MAGIC; params->cl_offset = GRUB_OFW_LINUX_CL_OFFSET; - params->video_width = (grub_getwh () >> 8); - params->video_height = (grub_getwh () & 0xff); + { + grub_term_output_t term; + int found = 0; + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_strcmp (term->name, "ofconsole") == 0) + { + grub_uint16_t pos = grub_term_getxy (term); + params->video_cursor_x = pos >> 8; + params->video_cursor_y = pos & 0xff; + params->video_width = grub_term_width (term); + params->video_height = grub_term_height (term); + found = 1; + break; + } + if (!found) + { + params->video_cursor_x = 0; + params->video_cursor_y = 0; + params->video_width = 80; + params->video_height = 25; + } + } + params->font_size = 16; params->ofw_signature = GRUB_LINUX_OFW_SIGNATURE; @@ -165,7 +187,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) { - grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux header"); + grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); goto fail; } @@ -211,7 +233,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), kernel_size = prot_size; if (grub_file_read (file, kernel_addr, prot_size) != (int) prot_size) - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); if (grub_errno == GRUB_ERR_NONE) grub_loader_set (grub_linux_boot, grub_linux_unload, 1); @@ -242,13 +264,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (argc == 0) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); + grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); goto fail; } if (! kernel_addr) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first."); + grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); goto fail; } @@ -260,7 +282,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, (void *) GRUB_OFW_LINUX_INITRD_ADDR, initrd_size) != (int) initrd_size) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } @@ -276,9 +298,9 @@ static grub_command_t cmd_linux, cmd_initrd; GRUB_MOD_INIT(linux) { cmd_linux = grub_register_command ("linux", grub_cmd_linux, - 0, "load linux"); + 0, N_("Load Linux.")); cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, - 0, "load initrd"); + 0, N_("Load initrd.")); my_mod = mod; } diff --git a/loader/i386/linux.c b/loader/i386/linux.c index 82bfd6b95..d3d935182 100644 --- a/loader/i386/linux.c +++ b/loader/i386/linux.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,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 @@ -33,6 +33,8 @@ #include #include #include +#include +#include #define GRUB_LINUX_CL_OFFSET 0x1000 #define GRUB_LINUX_CL_END_OFFSET 0x2000 @@ -392,12 +394,15 @@ grub_linux_setup_video (struct linux_kernel_params *params) { struct grub_video_mode_info mode_info; void *framebuffer; - int ret; + grub_err_t err; - ret = grub_video_get_info_and_fini (&mode_info, &framebuffer); + err = grub_video_get_info_and_fini (&mode_info, &framebuffer); - if (ret) - return 1; + if (err) + { + grub_errno = GRUB_ERR_NONE; + return 1; + } params->lfb_width = mode_info.width; params->lfb_height = mode_info.height; @@ -405,7 +410,7 @@ grub_linux_setup_video (struct linux_kernel_params *params) params->lfb_line_len = mode_info.pitch; params->lfb_base = (grub_size_t) framebuffer; - params->lfb_size = (params->lfb_line_len * params->lfb_height + 65535) >> 16; + params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height, 65536); params->red_mask_size = mode_info.red_mask_size; params->red_field_pos = mode_info.red_field_pos; @@ -517,16 +522,14 @@ grub_linux_boot (void) May change in future if we have modes without framebuffer. */ if (modevar && *modevar != 0) { - tmp = grub_malloc (grub_strlen (modevar) - + sizeof (";text")); + tmp = grub_xasprintf ("%s;text", modevar); if (! tmp) return grub_errno; - grub_sprintf (tmp, "%s;text", modevar); - err = grub_video_set_mode (tmp, 0); + err = grub_video_set_mode (tmp, 0, 0); grub_free (tmp); } else - err = grub_video_set_mode ("text", 0); + err = grub_video_set_mode ("text", 0, 0); if (err) { @@ -536,19 +539,40 @@ grub_linux_boot (void) } if (! grub_linux_setup_video (params)) - params->have_vga = GRUB_VIDEO_TYPE_VLFB; + { + /* Use generic framebuffer unless VESA is known to be supported. */ + if (params->have_vga != GRUB_VIDEO_LINUX_TYPE_VESA) + params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; + else + params->lfb_size >>= 16; + } else { - params->have_vga = GRUB_VIDEO_TYPE_TEXT; + params->have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT; params->video_width = 80; params->video_height = 25; } /* Initialize these last, because terminal position could be affected by printfs above. */ - if (params->have_vga == GRUB_VIDEO_TYPE_TEXT) + if (params->have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT) { - params->video_cursor_x = grub_getxy () >> 8; - params->video_cursor_y = grub_getxy () & 0xff; + grub_term_output_t term; + int found = 0; + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_strcmp (term->name, "vga_text") == 0 + || grub_strcmp (term->name, "console") == 0) + { + grub_uint16_t pos = grub_term_getxy (term); + params->video_cursor_x = pos >> 8; + params->video_cursor_y = pos & 0xff; + found = 1; + break; + } + if (!found) + { + params->video_cursor_x = 0; + params->video_cursor_y = 0; + } } #ifdef __x86_64__ @@ -613,7 +637,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) { - grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux header"); + grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); goto fail; } @@ -673,7 +697,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), len = 0x400 - sizeof (lh); if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } @@ -712,8 +736,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); - grub_printf (" [Linux-bzImage, setup=0x%x, size=0x%x]\n", - (unsigned) real_size, (unsigned) prot_size); + grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n", + (unsigned) real_size, (unsigned) prot_size); /* Look for memory size and video mode specified on the command line. */ linux_mem_size = 0; @@ -779,19 +803,22 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), break; } - buf = grub_malloc (sizeof ("WWWWxHHHHxDD;WWWWxHHHH")); - if (! buf) - goto fail; + /* We can't detect VESA, but user is implicitly telling us that it + is built-in because `vga=' parameter was used. */ + params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA; linux_mode = &linux_vesafb_modes[vid_mode - GRUB_LINUX_VID_MODE_VESA_START]; - grub_sprintf (buf, "%ux%ux%u,%ux%u", - linux_vesafb_res[linux_mode->res_index].width, - linux_vesafb_res[linux_mode->res_index].height, - linux_mode->depth, - linux_vesafb_res[linux_mode->res_index].width, - linux_vesafb_res[linux_mode->res_index].height); + buf = grub_xasprintf ("%ux%ux%u,%ux%u", + linux_vesafb_res[linux_mode->res_index].width, + linux_vesafb_res[linux_mode->res_index].height, + linux_mode->depth, + linux_vesafb_res[linux_mode->res_index].width, + linux_vesafb_res[linux_mode->res_index].height); + if (! buf) + goto fail; + grub_printf ("%s is deprecated. " "Use set gfxpayload=%s before " "linux command instead.\n", @@ -862,7 +889,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), len = prot_size; if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len) - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); if (grub_errno == GRUB_ERR_NONE) { @@ -897,13 +924,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (argc == 0) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); + grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); goto fail; } if (! loaded) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first."); + grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); goto fail; } @@ -951,7 +978,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (addr < addr_min) { - grub_error (GRUB_ERR_OUT_OF_RANGE, "The initrd is too big"); + grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big"); goto fail; } @@ -959,12 +986,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, initrd_mem, size) != size) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } - grub_printf (" [Initrd, addr=0x%x, size=0x%x]\n", - (unsigned) addr, (unsigned) size); + grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n", + (unsigned) addr, (unsigned) size); lh->ramdisk_image = addr; lh->ramdisk_size = size; @@ -982,9 +1009,9 @@ static grub_command_t cmd_linux, cmd_initrd; GRUB_MOD_INIT(linux) { cmd_linux = grub_register_command ("linux", grub_cmd_linux, - 0, "load linux"); + 0, N_("Load Linux.")); cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, - 0, "load initrd"); + 0, N_("Load initrd.")); my_mod = mod; } diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c deleted file mode 100644 index d1ea307d2..000000000 --- a/loader/i386/multiboot.c +++ /dev/null @@ -1,501 +0,0 @@ -/* multiboot.c - boot a multiboot OS image. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009 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 . - */ - -/* - * FIXME: The following features from the Multiboot specification still - * need to be implemented: - * - VBE support - * - symbol table - * - drives table - * - ROM configuration table - * - APM table - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef GRUB_MACHINE_PCBIOS -#include -#include -#include -#include -#endif - -extern grub_dl_t my_mod; -static struct multiboot_info *mbi, *mbi_dest; -static grub_addr_t entry; - -static char *playground = 0; -static grub_size_t code_size; - -static grub_err_t -grub_multiboot_boot (void) -{ - grub_multiboot_real_boot (entry, mbi_dest); - - /* Not reached. */ - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_multiboot_unload (void) -{ - if (playground) - { - unsigned int i; - for (i = 0; i < mbi->mods_count; i++) - { - grub_free ((void *) - ((struct multiboot_mod_list *) mbi->mods_addr)[i].mod_start); - grub_free ((void *) - ((struct multiboot_mod_list *) mbi->mods_addr)[i].cmdline); - } - grub_free ((void *) mbi->mods_addr); - grub_free (playground); - } - - mbi = NULL; - playground = NULL; - grub_dl_unref (my_mod); - - return GRUB_ERR_NONE; -} - -/* Return the length of the Multiboot mmap that will be needed to allocate - our platform's map. */ -static grub_uint32_t -grub_get_multiboot_mmap_len (void) -{ - grub_size_t count = 0; - - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)), - grub_uint64_t size __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))) - { - count++; - return 0; - } - - grub_mmap_iterate (hook); - - return count * sizeof (struct multiboot_mmap_entry); -} - -/* Fill previously allocated Multiboot mmap. */ -static void -grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) -{ - struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry; - - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) - { - mmap_entry->addr = addr; - mmap_entry->len = size; - mmap_entry->type = type; - mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof (mmap_entry->size); - mmap_entry++; - - return 0; - } - - grub_mmap_iterate (hook); -} - -#define MULTIBOOT_LOAD_ELF64 -#include "multiboot_elfxx.c" -#undef MULTIBOOT_LOAD_ELF64 - -#define MULTIBOOT_LOAD_ELF32 -#include "multiboot_elfxx.c" -#undef MULTIBOOT_LOAD_ELF32 - -/* Load ELF32 or ELF64. */ -static grub_err_t -grub_multiboot_load_elf (grub_file_t file, void *buffer) -{ - if (grub_multiboot_is_elf32 (buffer)) - return grub_multiboot_load_elf32 (file, buffer); - else if (grub_multiboot_is_elf64 (buffer)) - return grub_multiboot_load_elf64 (file, buffer); - - return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class"); -} - -static int -grub_multiboot_get_bootdev (grub_uint32_t *bootdev) -{ -#ifdef GRUB_MACHINE_PCBIOS - char *p; - grub_uint32_t biosdev, slice = ~0, part = ~0; - grub_device_t dev; - - biosdev = grub_get_root_biosnumber (); - - dev = grub_device_open (0); - if (dev && dev->disk && dev->disk->partition) - { - - p = dev->disk->partition->partmap->get_name (dev->disk->partition); - if (p) - { - if ((p[0] >= '0') && (p[0] <= '9')) - { - slice = grub_strtoul (p, &p, 0) - 1; - - if ((p) && (p[0] == ',')) - p++; - } - - if ((p[0] >= 'a') && (p[0] <= 'z')) - part = p[0] - 'a'; - } - } - if (dev) - grub_device_close (dev); - - *bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) - | ((part & 0xff) << 8) | 0xff; - return (biosdev != ~0UL); -#else - *bootdev = 0xffffffff; - return 0; -#endif -} - -void -grub_multiboot (int argc, char *argv[]) -{ - grub_file_t file = 0; - char buffer[MULTIBOOT_SEARCH], *cmdline = 0, *p; - struct multiboot_header *header; - grub_ssize_t len, cmdline_length, boot_loader_name_length; - grub_uint32_t mmap_length; - int i; - int cmdline_argc; - char **cmdline_argv; - - grub_loader_unset (); - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified"); - goto fail; - } - - file = grub_gzfile_open (argv[0], 1); - if (! file) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file"); - goto fail; - } - - len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); - if (len < 32) - { - grub_error (GRUB_ERR_BAD_OS, "File too small"); - goto fail; - } - - /* Look for the multiboot header in the buffer. The header should - be at least 12 bytes and aligned on a 4-byte boundary. */ - for (header = (struct multiboot_header *) buffer; - ((char *) header <= buffer + len - 12) || (header = 0); - header = (struct multiboot_header *) ((char *) header + 4)) - { - if (header->magic == MULTIBOOT_MAGIC - && !(header->magic + header->flags + header->checksum)) - break; - } - - if (header == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No multiboot header found"); - goto fail; - } - - if (header->flags & MULTIBOOT_UNSUPPORTED) - { - grub_error (GRUB_ERR_UNKNOWN_OS, - "Unsupported flag: 0x%x", header->flags); - goto fail; - } - - if (playground) - { - grub_free (playground); - playground = NULL; - } - - mmap_length = grub_get_multiboot_mmap_len (); - - /* Figure out cmdline length. */ - /* Skip filename. */ - cmdline_argc = argc - 1; - cmdline_argv = argv + 1; - - for (i = 0, cmdline_length = 0; i < cmdline_argc; i++) - cmdline_length += grub_strlen (cmdline_argv[i]) + 1; - - if (cmdline_length == 0) - cmdline_length = 1; - - boot_loader_name_length = sizeof(PACKAGE_STRING); - -#define cmdline_addr(x) ((void *) ((x) + code_size)) -#define boot_loader_name_addr(x) \ - ((void *) ((x) + code_size + cmdline_length)) -#define mbi_addr(x) ((void *) ((x) + code_size + cmdline_length + boot_loader_name_length)) -#define mmap_addr(x) ((void *) ((x) + code_size + cmdline_length + boot_loader_name_length + sizeof (struct multiboot_info))) - - grub_multiboot_payload_size = cmdline_length - /* boot_loader_name_length might need to grow for mbi,etc to be aligned (see below) */ - + boot_loader_name_length + 3 - + sizeof (struct multiboot_info) + mmap_length; - - if (header->flags & MULTIBOOT_AOUT_KLUDGE) - { - int offset = ((char *) header - buffer - - (header->header_addr - header->load_addr)); - int load_size = ((header->load_end_addr == 0) ? file->size - offset : - header->load_end_addr - header->load_addr); - - if (header->bss_end_addr) - code_size = (header->bss_end_addr - header->load_addr); - else - code_size = load_size; - grub_multiboot_payload_dest = header->load_addr; - - grub_multiboot_payload_size += code_size; - playground = grub_malloc (RELOCATOR_SIZEOF(forward) + grub_multiboot_payload_size + RELOCATOR_SIZEOF(backward)); - if (! playground) - goto fail; - - grub_multiboot_payload_orig = (long) playground + RELOCATOR_SIZEOF(forward); - - if ((grub_file_seek (file, offset)) == (grub_off_t) - 1) - goto fail; - - grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); - if (grub_errno) - goto fail; - - if (header->bss_end_addr) - grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, - header->bss_end_addr - header->load_addr - load_size); - - grub_multiboot_payload_entry_offset = header->entry_addr - header->load_addr; - - } - else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) - goto fail; - - /* This provides alignment for the MBI, the memory map and the backward relocator. */ - boot_loader_name_length += (0x04 - ((unsigned long) mbi_addr (grub_multiboot_payload_dest) & 0x03)); - - mbi = mbi_addr (grub_multiboot_payload_orig); - mbi_dest = mbi_addr (grub_multiboot_payload_dest); - grub_memset (mbi, 0, sizeof (struct multiboot_info)); - mbi->mmap_length = mmap_length; - - grub_fill_multiboot_mmap (mmap_addr (grub_multiboot_payload_orig)); - - /* FIXME: grub_uint32_t will break for addresses above 4 GiB, but is mandated - by the spec. Is there something we can do about it? */ - mbi->mmap_addr = (grub_uint32_t) mmap_addr (grub_multiboot_payload_dest); - mbi->flags |= MULTIBOOT_INFO_MEM_MAP; - - if (grub_multiboot_payload_dest >= grub_multiboot_payload_orig) - { - grub_memmove (playground, &grub_multiboot_forward_relocator, RELOCATOR_SIZEOF(forward)); - entry = (grub_addr_t) playground; - } - else - { - grub_memmove ((char *) (grub_multiboot_payload_orig + grub_multiboot_payload_size), - &grub_multiboot_backward_relocator, RELOCATOR_SIZEOF(backward)); - entry = (grub_addr_t) grub_multiboot_payload_orig + grub_multiboot_payload_size; - } - - grub_dprintf ("multiboot_loader", "dest=%p, size=0x%x, entry_offset=0x%x\n", - (void *) grub_multiboot_payload_dest, - grub_multiboot_payload_size, - grub_multiboot_payload_entry_offset); - - /* Convert from bytes to kilobytes. */ - mbi->mem_lower = grub_mmap_get_lower () / 1024; - mbi->mem_upper = grub_mmap_get_upper () / 1024; - mbi->flags |= MULTIBOOT_INFO_MEMORY; - - cmdline = p = cmdline_addr (grub_multiboot_payload_orig); - if (! cmdline) - goto fail; - - for (i = 0; i < cmdline_argc; i++) - { - p = grub_stpcpy (p, cmdline_argv[i]); - *(p++) = ' '; - } - - /* Remove the space after the last word. */ - if (p != cmdline) - p--; - *p = 0; - - mbi->flags |= MULTIBOOT_INFO_CMDLINE; - mbi->cmdline = (grub_uint32_t) cmdline_addr (grub_multiboot_payload_dest); - - - grub_strcpy (boot_loader_name_addr (grub_multiboot_payload_orig), PACKAGE_STRING); - mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME; - mbi->boot_loader_name = (grub_uint32_t) boot_loader_name_addr (grub_multiboot_payload_dest); - - if (grub_multiboot_get_bootdev (&mbi->boot_device)) - mbi->flags |= MULTIBOOT_INFO_BOOTDEV; - - grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 1); - - fail: - if (file) - grub_file_close (file); - - if (grub_errno != GRUB_ERR_NONE) - { - grub_free (cmdline); - grub_free (mbi); - grub_dl_unref (my_mod); - } -} - - -void -grub_module (int argc, char *argv[]) -{ - grub_file_t file = 0; - grub_ssize_t size, len = 0; - char *module = 0, *cmdline = 0, *p; - int i; - int cmdline_argc; - char **cmdline_argv; - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); - goto fail; - } - - if (!mbi) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, - "You need to load the multiboot kernel first"); - goto fail; - } - - file = grub_gzfile_open (argv[0], 1); - if (! file) - goto fail; - - size = grub_file_size (file); - module = grub_memalign (MULTIBOOT_MOD_ALIGN, size); - if (! module) - goto fail; - - if (grub_file_read (file, module, size) != size) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); - goto fail; - } - - /* Skip module name. */ - cmdline_argc = argc - 1; - cmdline_argv = argv + 1; - - for (i = 0; i < cmdline_argc; i++) - len += grub_strlen (cmdline_argv[i]) + 1; - - if (len == 0) - len = 1; - - cmdline = p = grub_malloc (len); - if (! cmdline) - goto fail; - - for (i = 0; i < cmdline_argc; i++) - { - p = grub_stpcpy (p, cmdline_argv[i]); - *(p++) = ' '; - } - - /* Remove the space after the last word. */ - if (p != cmdline) - p--; - *p = '\0'; - - if (mbi->flags & MULTIBOOT_INFO_MODS) - { - struct multiboot_mod_list *modlist = (struct multiboot_mod_list *) mbi->mods_addr; - - modlist = grub_realloc (modlist, (mbi->mods_count + 1) - * sizeof (struct multiboot_mod_list)); - if (! modlist) - goto fail; - mbi->mods_addr = (grub_uint32_t) modlist; - modlist += mbi->mods_count; - modlist->mod_start = (grub_uint32_t) module; - modlist->mod_end = (grub_uint32_t) module + size; - modlist->cmdline = (grub_uint32_t) cmdline; - modlist->pad = 0; - mbi->mods_count++; - } - else - { - struct multiboot_mod_list *modlist = grub_zalloc (sizeof (struct multiboot_mod_list)); - if (! modlist) - goto fail; - modlist->mod_start = (grub_uint32_t) module; - modlist->mod_end = (grub_uint32_t) module + size; - modlist->cmdline = (grub_uint32_t) cmdline; - mbi->mods_count = 1; - mbi->mods_addr = (grub_uint32_t) modlist; - mbi->flags |= MULTIBOOT_INFO_MODS; - } - - fail: - if (file) - grub_file_close (file); - - if (grub_errno != GRUB_ERR_NONE) - { - grub_free (module); - grub_free (cmdline); - } -} diff --git a/loader/i386/multiboot_helper.S b/loader/i386/multiboot_helper.S deleted file mode 100644 index d1094588b..000000000 --- a/loader/i386/multiboot_helper.S +++ /dev/null @@ -1,118 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 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 . - */ - -#include -#include -#include - - .p2align 2 /* force 4-byte alignment */ - -/* - * This starts the multiboot kernel. - */ - -VARIABLE(grub_multiboot_payload_size) - .long 0 -VARIABLE(grub_multiboot_payload_orig) - .long 0 -VARIABLE(grub_multiboot_payload_dest) - .long 0 -VARIABLE(grub_multiboot_payload_entry_offset) - .long 0 - -/* - * The relocators below understand the following parameters: - * ecx: Size of the block to be copied. - * esi: Where to copy from (always lowest address, even if we're relocating - * backwards). - * edi: Where to copy to (likewise). - * edx: Offset of the entry point (relative to the beginning of the block). - */ - -VARIABLE(grub_multiboot_forward_relocator) - /* Add entry offset. */ - addl %edi, %edx - - /* Forward copy. */ - cld - rep - movsb - - jmp *%edx -VARIABLE(grub_multiboot_forward_relocator_end) - -VARIABLE(grub_multiboot_backward_relocator) - /* Add entry offset (before %edi is mangled). */ - addl %edi, %edx - - /* Backward movsb is implicitly off-by-one. compensate that. */ - decl %esi - decl %edi - - /* Backward copy. */ - std - addl %ecx, %esi - addl %ecx, %edi - rep - movsb - - cld - jmp *%edx -VARIABLE(grub_multiboot_backward_relocator_end) - -FUNCTION(grub_multiboot_real_boot) - /* Push the entry address on the stack. */ - pushl %eax - /* Move the address of the multiboot information structure to ebx. */ - movl %edx,%ebx - - /* Interrupts should be disabled. */ - cli - - /* Where do we copy what from. */ - movl EXT_C(grub_multiboot_payload_size), %ecx - movl EXT_C(grub_multiboot_payload_orig), %esi - movl EXT_C(grub_multiboot_payload_dest), %edi - movl EXT_C(grub_multiboot_payload_entry_offset), %edx - - /* Move the magic value into eax. */ - movl $MULTIBOOT_MAGIC2, %eax - - /* Jump to the relocator. */ - popl %ebp - jmp *%ebp - -/* - * This starts the multiboot 2 kernel. - */ - -FUNCTION(grub_multiboot2_real_boot) - /* Push the entry address on the stack. */ - pushl %eax - /* Move the address of the multiboot information structure to ebx. */ - movl %edx,%ebx - - /* Interrupts should be disabled. */ - cli - - /* Move the magic value into eax and jump to the kernel. */ - movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax - popl %ecx - - cld - jmp *%ecx diff --git a/loader/i386/multiboot_mbi.c b/loader/i386/multiboot_mbi.c new file mode 100644 index 000000000..3d974f04e --- /dev/null +++ b/loader/i386/multiboot_mbi.c @@ -0,0 +1,541 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009 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 . + */ + +#include +#include +#ifdef GRUB_MACHINE_PCBIOS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The bits in the required part of flags field we don't support. */ +#define UNSUPPORTED_FLAGS 0x0000fff8 + +struct module +{ + struct module *next; + grub_addr_t start; + grub_size_t size; + char *cmdline; + int cmdline_size; +}; + +struct module *modules, *modules_last; +static grub_size_t cmdline_size; +static grub_size_t total_modcmd; +static unsigned modcnt; +static char *cmdline = NULL; +static grub_uint32_t bootdev; +static int bootdev_set; + +grub_err_t +grub_multiboot_load (grub_file_t file) +{ + char *buffer; + grub_ssize_t len; + struct multiboot_header *header; + grub_err_t err; + + buffer = grub_malloc (MULTIBOOT_SEARCH); + if (!buffer) + return grub_errno; + + len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); + if (len < 32) + { + grub_free (buffer); + return grub_error (GRUB_ERR_BAD_OS, "file too small"); + } + + /* Look for the multiboot header in the buffer. The header should + be at least 12 bytes and aligned on a 4-byte boundary. */ + for (header = (struct multiboot_header *) buffer; + ((char *) header <= buffer + len - 12) || (header = 0); + header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN)) + { + if (header->magic == MULTIBOOT_HEADER_MAGIC + && !(header->magic + header->flags + header->checksum)) + break; + } + + if (header == 0) + { + grub_free (buffer); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); + } + + if (header->flags & UNSUPPORTED_FLAGS) + { + grub_free (buffer); + return grub_error (GRUB_ERR_UNKNOWN_OS, + "unsupported flag: 0x%x", header->flags); + } + + if (header->flags & MULTIBOOT_AOUT_KLUDGE) + { + int offset = ((char *) header - buffer - + (header->header_addr - header->load_addr)); + int load_size = ((header->load_end_addr == 0) ? file->size - offset : + header->load_end_addr - header->load_addr); + grub_size_t code_size; + + if (header->bss_end_addr) + code_size = (header->bss_end_addr - header->load_addr); + else + code_size = load_size; + grub_multiboot_payload_dest = header->load_addr; + + grub_multiboot_pure_size += code_size; + + /* Allocate a bit more to avoid relocations in most cases. */ + grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; + grub_multiboot_payload_orig + = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); + + if (! grub_multiboot_payload_orig) + { + grub_free (buffer); + return grub_errno; + } + + if ((grub_file_seek (file, offset)) == (grub_off_t) -1) + { + grub_free (buffer); + return grub_errno; + } + + grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); + if (grub_errno) + { + grub_free (buffer); + return grub_errno; + } + + if (header->bss_end_addr) + grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, + header->bss_end_addr - header->load_addr - load_size); + + grub_multiboot_payload_eip = header->entry_addr; + + } + else + { + err = grub_multiboot_load_elf (file, buffer); + if (err) + { + grub_free (buffer); + return err; + } + } + + if (header->flags & MULTIBOOT_VIDEO_MODE) + { + switch (header->mode_type) + { + case 1: + err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, + GRUB_MULTIBOOT_CONSOLE_EGA_TEXT + | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, + 0, 0, 0, 0); + break; + case 0: + err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, + GRUB_MULTIBOOT_CONSOLE_EGA_TEXT + | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, + header->width, header->height, + header->depth, 0); + break; + default: + err = grub_error (GRUB_ERR_BAD_OS, + "unsupported graphical mode type %d", + header->mode_type); + break; + } + } + else + err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, + GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, + 0, 0, 0, 0); + return err; +} + +grub_size_t +grub_multiboot_get_mbi_size (void) +{ + return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4) + + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd + + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry) + + 256 * sizeof (struct multiboot_color); +} + +/* Fill previously allocated Multiboot mmap. */ +static void +grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) +{ + struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry; + + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + { + mmap_entry->addr = addr; + mmap_entry->len = size; + switch (type) + { + case GRUB_MACHINE_MEMORY_AVAILABLE: + mmap_entry->type = MULTIBOOT_MEMORY_AVAILABLE; + break; + +#ifdef GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE + case GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE: + mmap_entry->type = MULTIBOOT_MEMORY_ACPI_RECLAIMABLE; + break; +#endif + +#ifdef GRUB_MACHINE_MEMORY_NVS + case GRUB_MACHINE_MEMORY_NVS: + mmap_entry->type = MULTIBOOT_MEMORY_NVS; + break; +#endif + + default: + mmap_entry->type = MULTIBOOT_MEMORY_RESERVED; + break; + } + mmap_entry->size = sizeof (struct multiboot_mmap_entry) - sizeof (mmap_entry->size); + mmap_entry++; + + return 0; + } + + grub_mmap_iterate (hook); +} + +static grub_err_t +retrieve_video_parameters (struct multiboot_info *mbi, + grub_uint8_t *ptrorig, grub_uint32_t ptrdest) +{ + grub_err_t err; + struct grub_video_mode_info mode_info; + void *framebuffer; + grub_video_driver_id_t driv_id; + struct grub_video_palette_data palette[256]; + + err = grub_multiboot_set_video_mode (); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + + grub_video_get_palette (0, ARRAY_SIZE (palette), palette); + + driv_id = grub_video_get_driver_id (); + if (driv_id == GRUB_VIDEO_DRIVER_NONE) + return GRUB_ERR_NONE; + + err = grub_video_get_info_and_fini (&mode_info, &framebuffer); + if (err) + return err; + + mbi->framebuffer_addr = (grub_addr_t) framebuffer; + mbi->framebuffer_pitch = mode_info.pitch; + + mbi->framebuffer_width = mode_info.width; + mbi->framebuffer_height = mode_info.height; + + mbi->framebuffer_bpp = mode_info.bpp; + + if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) + { + struct multiboot_color *mb_palette; + unsigned i; + mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED; + mbi->framebuffer_palette_addr = ptrdest; + mbi->framebuffer_palette_num_colors = mode_info.number_of_colors; + if (mbi->framebuffer_palette_num_colors > ARRAY_SIZE (palette)) + mbi->framebuffer_palette_num_colors = ARRAY_SIZE (palette); + mb_palette = (struct multiboot_color *) ptrorig; + for (i = 0; i < mbi->framebuffer_palette_num_colors; i++) + { + mb_palette[i].red = palette[i].r; + mb_palette[i].green = palette[i].g; + mb_palette[i].blue = palette[i].b; + } + ptrorig += mbi->framebuffer_palette_num_colors + * sizeof (struct multiboot_color); + ptrdest += mbi->framebuffer_palette_num_colors + * sizeof (struct multiboot_color); + } + else + { + mbi->framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + mbi->framebuffer_red_field_position = mode_info.green_field_pos; + mbi->framebuffer_red_mask_size = mode_info.green_mask_size; + mbi->framebuffer_green_field_position = mode_info.green_field_pos; + mbi->framebuffer_green_mask_size = mode_info.green_mask_size; + mbi->framebuffer_blue_field_position = mode_info.blue_field_pos; + mbi->framebuffer_blue_mask_size = mode_info.blue_mask_size; + } + + mbi->flags |= MULTIBOOT_INFO_FRAMEBUFFER_INFO; + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, + grub_size_t bufsize) +{ + grub_uint8_t *ptrorig = (grub_uint8_t *) orig + buf_off; + grub_uint32_t ptrdest = dest + buf_off; + struct multiboot_info *mbi; + struct multiboot_mod_list *modlist; + unsigned i; + struct module *cur; + grub_size_t mmap_size; + grub_err_t err; + + if (bufsize < grub_multiboot_get_mbi_size ()) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + + mbi = (struct multiboot_info *) ptrorig; + ptrorig += sizeof (*mbi); + ptrdest += sizeof (*mbi); + grub_memset (mbi, 0, sizeof (*mbi)); + + grub_memcpy (ptrorig, cmdline, cmdline_size); + mbi->flags |= MULTIBOOT_INFO_CMDLINE; + mbi->cmdline = ptrdest; + ptrorig += ALIGN_UP (cmdline_size, 4); + ptrdest += ALIGN_UP (cmdline_size, 4); + + grub_memcpy (ptrorig, PACKAGE_STRING, sizeof(PACKAGE_STRING)); + mbi->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME; + mbi->boot_loader_name = ptrdest; + ptrorig += ALIGN_UP (sizeof(PACKAGE_STRING), 4); + ptrdest += ALIGN_UP (sizeof(PACKAGE_STRING), 4); + + if (modcnt) + { + mbi->flags |= MULTIBOOT_INFO_MODS; + mbi->mods_addr = ptrdest; + mbi->mods_count = modcnt; + modlist = (struct multiboot_mod_list *) ptrorig; + ptrorig += modcnt * sizeof (struct multiboot_mod_list); + ptrdest += modcnt * sizeof (struct multiboot_mod_list); + + for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) + { + modlist[i].mod_start = cur->start; + modlist[i].mod_end = modlist[i].mod_start + cur->size; + modlist[i].cmdline = ptrdest; + grub_memcpy (ptrorig, cur->cmdline, cur->cmdline_size); + ptrorig += ALIGN_UP (cur->cmdline_size, 4); + ptrdest += ALIGN_UP (cur->cmdline_size, 4); + } + } + else + { + mbi->mods_addr = 0; + mbi->mods_count = 0; + } + + mmap_size = grub_get_multiboot_mmap_count () + * sizeof (struct multiboot_mmap_entry); + grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig); + mbi->mmap_length = mmap_size; + mbi->mmap_addr = ptrdest; + mbi->flags |= MULTIBOOT_INFO_MEM_MAP; + ptrorig += mmap_size; + ptrdest += mmap_size; + + /* Convert from bytes to kilobytes. */ + mbi->mem_lower = grub_mmap_get_lower () / 1024; + mbi->mem_upper = grub_mmap_get_upper () / 1024; + mbi->flags |= MULTIBOOT_INFO_MEMORY; + + if (bootdev_set) + { + mbi->boot_device = bootdev; + mbi->flags |= MULTIBOOT_INFO_BOOTDEV; + } + + err = retrieve_video_parameters (mbi, ptrorig, ptrdest); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + + return GRUB_ERR_NONE; +} + +void +grub_multiboot_free_mbi (void) +{ + struct module *cur, *next; + + cmdline_size = 0; + total_modcmd = 0; + modcnt = 0; + grub_free (cmdline); + cmdline = NULL; + bootdev_set = 0; + + for (cur = modules; cur; cur = next) + { + next = cur->next; + grub_free (cur->cmdline); + grub_free (cur); + } + modules = NULL; + modules_last = NULL; +} + +grub_err_t +grub_multiboot_init_mbi (int argc, char *argv[]) +{ + grub_ssize_t len = 0; + char *p; + int i; + + grub_multiboot_free_mbi (); + + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + if (len == 0) + len = 1; + + cmdline = p = grub_malloc (len); + if (! cmdline) + return grub_errno; + cmdline_size = len; + + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + if (p != cmdline) + p--; + *p = '\0'; + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_multiboot_add_module (grub_addr_t start, grub_size_t size, + int argc, char *argv[]) +{ + struct module *newmod; + char *p; + grub_ssize_t len = 0; + int i; + + newmod = grub_malloc (sizeof (*newmod)); + if (!newmod) + return grub_errno; + newmod->start = start; + newmod->size = size; + + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + + if (len == 0) + len = 1; + + newmod->cmdline = p = grub_malloc (len); + if (! newmod->cmdline) + { + grub_free (newmod); + return grub_errno; + } + newmod->cmdline_size = len; + total_modcmd += ALIGN_UP (len, 4); + + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + if (p != newmod->cmdline) + p--; + *p = '\0'; + + if (modules_last) + modules_last->next = newmod; + else + { + modules = newmod; + modules_last->next = NULL; + } + modules_last = newmod; + + modcnt++; + + return GRUB_ERR_NONE; +} + +void +grub_multiboot_set_bootdev (void) +{ + grub_uint32_t biosdev, slice = ~0, part = ~0; + grub_device_t dev; + +#ifdef GRUB_MACHINE_PCBIOS + biosdev = grub_get_root_biosnumber (); +#else + biosdev = 0xffffffff; +#endif + + if (biosdev == 0xffffffff) + return; + + dev = grub_device_open (0); + if (dev && dev->disk && dev->disk->partition) + { + if (dev->disk->partition->parent) + { + part = dev->disk->partition->number; + slice = dev->disk->partition->parent->number; + } + else + slice = dev->disk->partition->number; + } + if (dev) + grub_device_close (dev); + + bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) + | ((part & 0xff) << 8) | 0xff; + bootdev_set = 1; +} diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c index caf1450e4..502031d0e 100644 --- a/loader/i386/pc/chainloader.c +++ b/loader/i386/pc/chainloader.c @@ -1,7 +1,7 @@ /* chainloader.c - boot another boot loader */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2004,2007 Free Software Foundation, Inc. + * Copyright (C) 2002,2004,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 @@ -31,7 +31,11 @@ #include #include #include +#include #include +#include +#include +#include static grub_dl_t my_mod; static int boot_drive; @@ -40,6 +44,7 @@ static void *boot_part_addr; static grub_err_t grub_chainloader_boot (void) { + grub_video_set_mode ("text", 0, 0); grub_chainloader_real_boot (boot_drive, boot_part_addr); /* Never reach here. */ @@ -94,15 +99,27 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) dev = grub_device_open (0); if (dev && dev->disk && dev->disk->partition) { - grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64, - (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR); - part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR - + (dev->disk->partition->index << 4)); + grub_disk_t disk = dev->disk; + + if (disk) + { + grub_partition_t p = disk->partition; + + if (p && grub_strcmp (p->partmap->name, "msdos") == 0) + { + disk->partition = p->parent; + grub_disk_read (disk, p->offset, 446, 64, + (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR); + part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR + + (p->index << 4)); + disk->partition = p; + } + } } if (dev) grub_device_close (dev); - + /* Ignore errors. Perhaps it's not fatal. */ grub_errno = GRUB_ERR_NONE; @@ -146,7 +163,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(chainloader) { cmd = grub_register_command ("chainloader", grub_cmd_chainloader, - 0, "load another boot loader"); + 0, N_("Load another boot loader.")); my_mod = mod; } diff --git a/loader/i386/pc/linux.c b/loader/i386/pc/linux.c index c5279f6ce..0fa9abc12 100644 --- a/loader/i386/pc/linux.c +++ b/loader/i386/pc/linux.c @@ -1,7 +1,7 @@ /* linux.c - boot Linux zImage or bzImage */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,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 @@ -30,6 +30,9 @@ #include #include #include +#include +#include +#include #define GRUB_LINUX_CL_OFFSET 0x9000 #define GRUB_LINUX_CL_END_OFFSET 0x90FF @@ -47,6 +50,16 @@ grub_linux_unload (void) return GRUB_ERR_NONE; } +static grub_err_t +grub_linux16_boot (void) +{ + grub_video_set_mode ("text", 0, 0); + grub_linux16_real_boot (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + static grub_err_t grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) @@ -81,7 +94,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) { - grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux header"); + grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); goto fail; } @@ -234,7 +247,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh); if (grub_file_read (file, grub_linux_tmp_addr + sizeof (lh), len) != len) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } @@ -265,7 +278,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), len = prot_size; if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len) - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); if (grub_errno == GRUB_ERR_NONE) { @@ -299,13 +312,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (argc == 0) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); + grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); goto fail; } if (!loaded) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first."); + grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); goto fail; } @@ -314,7 +327,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (!(lh->header == grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE) && grub_le_to_cpu16 (lh->version) >= 0x0200)) { - grub_error (GRUB_ERR_BAD_OS, "The kernel is too old for initrd."); + grub_error (GRUB_ERR_BAD_OS, "the kernel is too old for initrd"); goto fail; } @@ -357,13 +370,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (addr < addr_min) { - grub_error (GRUB_ERR_OUT_OF_RANGE, "The initrd is too big"); + grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big"); goto fail; } if (grub_file_read (file, (void *) addr, size) != size) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } @@ -383,10 +396,10 @@ GRUB_MOD_INIT(linux16) { cmd_linux = grub_register_command ("linux16", grub_cmd_linux, - 0, "load linux"); + 0, N_("Load Linux.")); cmd_initrd = grub_register_command ("initrd16", grub_cmd_initrd, - 0, "load initrd"); + 0, N_("Load initrd.")); my_mod = mod; } diff --git a/loader/i386/pc/multiboot2.c b/loader/i386/pc/multiboot2.c deleted file mode 100644 index e2d649613..000000000 --- a/loader/i386/pc/multiboot2.c +++ /dev/null @@ -1,119 +0,0 @@ -/* multiboot2.c - boot a multiboot 2 OS image. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007,2008 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -grub_err_t -grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr, - int *do_load) -{ - Elf32_Addr paddr = phdr->p_paddr; - - if (phdr->p_type != PT_LOAD) - { - *do_load = 0; - return 0; - } - *do_load = 1; - - if ((paddr < grub_os_area_addr) - || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)) - return grub_error(GRUB_ERR_OUT_OF_RANGE,"Address 0x%x is out of range", - paddr); - - return GRUB_ERR_NONE; -} - -grub_err_t -grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr, - int *do_load) -{ - Elf64_Addr paddr = phdr->p_paddr; - - if (phdr->p_type != PT_LOAD) - { - *do_load = 0; - return 0; - } - *do_load = 1; - - if ((paddr < grub_os_area_addr) - || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "Address 0x%x is out of range", - paddr); - - return GRUB_ERR_NONE; -} - -grub_err_t -grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr) -{ - grub_addr_t modaddr; - - modaddr = (grub_addr_t) grub_memalign (MULTIBOOT2_MOD_ALIGN, size); - if (! modaddr) - return grub_errno; - - *addr = modaddr; - return GRUB_ERR_NONE; -} - -grub_err_t -grub_mb2_arch_module_free (grub_addr_t addr, UNUSED grub_size_t size) -{ - grub_free((void *) addr); - return GRUB_ERR_NONE; -} - -void -grub_mb2_arch_boot (grub_addr_t entry, void *tags) -{ - grub_multiboot2_real_boot (entry, tags); -} - -void -grub_mb2_arch_unload (struct multiboot2_tag_header *tags) -{ - struct multiboot2_tag_header *tag; - - /* Free all module memory in the tag list. */ - for_each_tag (tag, tags) - { - if (tag->key == MULTIBOOT2_TAG_MODULE) - { - struct multiboot2_tag_module *module = - (struct multiboot2_tag_module *) tag; - grub_free((void *) module->addr); - } - } -} - -grub_err_t -grub_mb2_tags_arch_create (void) -{ - /* XXX Create boot device et al. */ - return GRUB_ERR_NONE; -} diff --git a/loader/i386/pc/xnu.c b/loader/i386/pc/xnu.c index ebb176bb4..39a595d9b 100644 --- a/loader/i386/pc/xnu.c +++ b/loader/i386/pc/xnu.c @@ -22,20 +22,12 @@ #include #include #include +#include #define min(a,b) (((a) < (b)) ? (a) : (b)) #define max(a,b) (((a) > (b)) ? (a) : (b)) -#define DEFAULT_VIDEO_MODE "1024x768x32,800x600x32,640x480x32" - -static int NESTED_FUNC_ATTR video_hook (grub_video_adapter_t p __attribute__ ((unused)), - struct grub_video_mode_info *info) -{ - if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT) - return 0; - - return 1; -} +#define DEFAULT_VIDEO_MODE "auto" /* Setup video for xnu. */ grub_err_t @@ -43,53 +35,74 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) { struct grub_video_mode_info mode_info; int ret; - char *tmp, *modevar; + char *tmp; + const char *modevar; void *framebuffer; grub_err_t err; + struct grub_video_bitmap *bitmap = NULL; modevar = grub_env_get ("gfxpayload"); + /* Consider only graphical 32-bit deep modes. */ if (! modevar || *modevar == 0) - err = grub_video_set_mode (DEFAULT_VIDEO_MODE, video_hook); + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT + | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK, + 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS); else { - tmp = grub_malloc (grub_strlen (modevar) - + sizeof (DEFAULT_VIDEO_MODE) + 1); + tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); if (! tmp) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "couldn't allocate temporary storag"); - grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); - err = grub_video_set_mode (tmp, video_hook); + return grub_errno; + err = grub_video_set_mode (tmp, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT + | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK, + 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS); grub_free (tmp); } if (err) return err; + ret = grub_video_get_info (&mode_info); + if (ret) + return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters"); + if (grub_xnu_bitmap) + { + if (grub_xnu_bitmap_mode == GRUB_XNU_BITMAP_STRETCH) + err = grub_video_bitmap_create_scaled (&bitmap, + mode_info.width, + mode_info.height, + grub_xnu_bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + else + bitmap = grub_xnu_bitmap; + } + + if (bitmap) { int x, y; - x = mode_info.width - grub_xnu_bitmap->mode_info.width; + x = mode_info.width - bitmap->mode_info.width; x /= 2; - y = mode_info.height - grub_xnu_bitmap->mode_info.height; + y = mode_info.height - bitmap->mode_info.height; y /= 2; - err = grub_video_blit_bitmap (grub_xnu_bitmap, + err = grub_video_blit_bitmap (bitmap, GRUB_VIDEO_BLIT_REPLACE, x > 0 ? x : 0, y > 0 ? y : 0, x < 0 ? -x : 0, y < 0 ? -y : 0, - min (grub_xnu_bitmap->mode_info.width, + min (bitmap->mode_info.width, mode_info.width), - min (grub_xnu_bitmap->mode_info.height, + min (bitmap->mode_info.height, mode_info.height)); - if (err) - { - grub_print_error (); - grub_errno = GRUB_ERR_NONE; - grub_xnu_bitmap = 0; - } - err = GRUB_ERR_NONE; + } + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + bitmap = 0; } ret = grub_video_get_info_and_fini (&mode_info, &framebuffer); @@ -102,8 +115,8 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) params->lfb_line_len = mode_info.pitch; params->lfb_base = PTR_TO_UINT32 (framebuffer); - params->lfb_mode = grub_xnu_bitmap - ? GRUB_XNU_VIDEO_SPLASH : GRUB_XNU_VIDEO_TEXT_IN_VIDEO; + params->lfb_mode = bitmap ? GRUB_XNU_VIDEO_SPLASH + : GRUB_XNU_VIDEO_TEXT_IN_VIDEO; return GRUB_ERR_NONE; } diff --git a/loader/i386/xnu.c b/loader/i386/xnu.c index 275b50dbc..8000579d0 100644 --- a/loader/i386/xnu.c +++ b/loader/i386/xnu.c @@ -25,11 +25,18 @@ #include #include #include +#include #include #include +#include #include +#include +#include +#include char grub_xnu_cmdline[1024]; +grub_uint32_t grub_xnu_heap_will_be_at; +grub_uint32_t grub_xnu_entry_point, grub_xnu_arg1, grub_xnu_stack; /* Aliases set for some tables. */ struct tbl_alias @@ -44,20 +51,13 @@ struct tbl_alias table_aliases[] = {GRUB_EFI_ACPI_TABLE_GUID, "ACPI"}, }; -/* The following function is used to be able to debug xnu loader - with grub-emu. */ -#ifdef GRUB_UTIL -static grub_err_t -grub_xnu_launch (void) +struct grub_xnu_devprop_device_descriptor { - grub_printf ("Fake launch %x:%p:%p", grub_xnu_entry_point, grub_xnu_arg1, - grub_xnu_stack); - grub_getkey (); - return 0; -} -#else -static void (*grub_xnu_launch) (void) = 0; -#endif + struct grub_xnu_devprop_device_descriptor *next; + struct property_descriptor *properties; + struct grub_efi_device_path *path; + int pathlen; +}; static int utf16_strlen (grub_uint16_t *in) @@ -205,6 +205,417 @@ guessfsb (void) ((msrlow >> 7) & 0x3e) + ((msrlow >> 14) & 1), 0); } +struct property_descriptor +{ + struct property_descriptor *next; + grub_uint8_t *name; + grub_uint16_t *name16; + int name16len; + int length; + void *data; +}; + +struct grub_xnu_devprop_device_descriptor *devices = 0; + +grub_err_t +grub_xnu_devprop_remove_property (struct grub_xnu_devprop_device_descriptor *dev, + char *name) +{ + struct property_descriptor *prop; + prop = grub_named_list_find (GRUB_AS_NAMED_LIST_P (&dev->properties), name); + if (!prop) + return GRUB_ERR_NONE; + + grub_free (prop->name); + grub_free (prop->name16); + grub_free (prop->data); + + grub_list_remove (GRUB_AS_LIST_P (&dev->properties), GRUB_AS_LIST (prop)); + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_xnu_devprop_remove_device (struct grub_xnu_devprop_device_descriptor *dev) +{ + void *t; + struct property_descriptor *prop; + + grub_list_remove (GRUB_AS_LIST_P (&devices), GRUB_AS_LIST (dev)); + + for (prop = dev->properties; prop; ) + { + grub_free (prop->name); + grub_free (prop->name16); + grub_free (prop->data); + t = prop; + prop = prop->next; + grub_free (t); + } + + grub_free (dev->path); + grub_free (dev); + + return GRUB_ERR_NONE; +} + +struct grub_xnu_devprop_device_descriptor * +grub_xnu_devprop_add_device (struct grub_efi_device_path *path, int length) +{ + struct grub_xnu_devprop_device_descriptor *ret; + + ret = grub_zalloc (sizeof (*ret)); + if (!ret) + return 0; + + ret->path = grub_malloc (length); + if (!ret->path) + { + grub_free (ret); + return 0; + } + ret->pathlen = length; + grub_memcpy (ret->path, path, length); + + grub_list_push (GRUB_AS_LIST_P (&devices), GRUB_AS_LIST (ret)); + + return ret; +} + +static grub_err_t +grub_xnu_devprop_add_property (struct grub_xnu_devprop_device_descriptor *dev, + grub_uint8_t *utf8, grub_uint16_t *utf16, + int utf16len, void *data, int datalen) +{ + struct property_descriptor *prop; + + prop = grub_malloc (sizeof (*prop)); + if (!prop) + return grub_errno; + + prop->name = utf8; + prop->name16 = utf16; + prop->name16len = utf16len; + + prop->length = datalen; + prop->data = grub_malloc (prop->length); + if (!prop->data) + { + grub_free (prop); + grub_free (prop->name); + grub_free (prop->name16); + return grub_errno; + } + grub_memcpy (prop->data, data, prop->length); + grub_list_push (GRUB_AS_LIST_P (&dev->properties), + GRUB_AS_LIST (prop)); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_xnu_devprop_add_property_utf8 (struct grub_xnu_devprop_device_descriptor *dev, + char *name, void *data, int datalen) +{ + grub_uint8_t *utf8; + grub_uint16_t *utf16; + int len, utf16len; + grub_err_t err; + + utf8 = (grub_uint8_t *) grub_strdup (name); + if (!utf8) + return grub_errno; + + len = grub_strlen (name); + utf16 = grub_malloc (sizeof (grub_uint16_t) * len); + if (!utf16) + { + grub_free (utf8); + return grub_errno; + } + + utf16len = grub_utf8_to_utf16 (utf16, len, utf8, len, NULL); + if (utf16len < 0) + { + grub_free (utf8); + grub_free (utf16); + return grub_errno; + } + + err = grub_xnu_devprop_add_property (dev, utf8, utf16, + utf16len, data, datalen); + if (err) + { + grub_free (utf8); + grub_free (utf16); + return err; + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_xnu_devprop_add_property_utf16 (struct grub_xnu_devprop_device_descriptor *dev, + grub_uint16_t *name, int namelen, + void *data, int datalen) +{ + grub_uint8_t *utf8; + grub_uint16_t *utf16; + grub_err_t err; + + utf16 = grub_malloc (sizeof (grub_uint16_t) * namelen); + if (!utf16) + return grub_errno; + grub_memcpy (utf16, name, sizeof (grub_uint16_t) * namelen); + + utf8 = grub_malloc (namelen * 4 + 1); + if (!utf8) + { + grub_free (utf8); + return grub_errno; + } + + *grub_utf16_to_utf8 ((grub_uint8_t *) utf8, name, namelen) = '\0'; + + err = grub_xnu_devprop_add_property (dev, utf8, utf16, + namelen, data, datalen); + if (err) + { + grub_free (utf8); + grub_free (utf16); + return err; + } + + return GRUB_ERR_NONE; +} + +static inline int +hextoval (char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'z') + return c - 'a' + 10; + if (c >= 'A' && c <= 'Z') + return c - 'A' + 10; + return 0; +} + +void +grub_cpu_xnu_unload (void) +{ + struct grub_xnu_devprop_device_descriptor *dev1, *dev2; + + for (dev1 = devices; dev1; ) + { + dev2 = dev1->next; + grub_xnu_devprop_remove_device (dev1); + dev1 = dev2; + } +} + +static grub_err_t +grub_cpu_xnu_fill_devprop (void) +{ + struct grub_xnu_devtree_key *efikey; + int total_length = sizeof (struct grub_xnu_devprop_header); + struct grub_xnu_devtree_key *devprop; + struct grub_xnu_devprop_device_descriptor *device; + void *ptr; + struct grub_xnu_devprop_header *head; + void *t; + int numdevs = 0; + + /* The key "efi". */ + efikey = grub_xnu_create_key (&grub_xnu_devtree_root, "efi"); + if (! efikey) + return grub_errno; + + for (device = devices; device; device = device->next) + { + struct property_descriptor *propdesc; + total_length += sizeof (struct grub_xnu_devprop_device_header); + total_length += device->pathlen; + + for (propdesc = device->properties; propdesc; propdesc = propdesc->next) + { + total_length += sizeof (grub_uint32_t); + total_length += sizeof (grub_uint16_t) + * (propdesc->name16len + 1); + total_length += sizeof (grub_uint32_t); + total_length += propdesc->length; + } + numdevs++; + } + + devprop = grub_xnu_create_value (&(efikey->first_child), "device-properties"); + if (devprop) + { + devprop->data = grub_malloc (total_length); + devprop->datasize = total_length; + } + + ptr = devprop->data; + head = ptr; + ptr = head + 1; + head->length = total_length; + head->alwaysone = 1; + head->num_devices = numdevs; + for (device = devices; device; ) + { + struct grub_xnu_devprop_device_header *devhead; + struct property_descriptor *propdesc; + devhead = ptr; + devhead->num_values = 0; + ptr = devhead + 1; + + grub_memcpy (ptr, device->path, device->pathlen); + ptr = (char *) ptr + device->pathlen; + + for (propdesc = device->properties; propdesc; ) + { + grub_uint32_t *len; + grub_uint16_t *name; + void *data; + + len = ptr; + *len = 2 * propdesc->name16len + sizeof (grub_uint16_t) + + sizeof (grub_uint32_t); + ptr = len + 1; + + name = ptr; + grub_memcpy (name, propdesc->name16, 2 * propdesc->name16len); + name += propdesc->name16len; + + /* NUL terminator. */ + *name = 0; + ptr = name + 1; + + len = ptr; + *len = propdesc->length + sizeof (grub_uint32_t); + data = len + 1; + ptr = data; + grub_memcpy (ptr, propdesc->data, propdesc->length); + ptr = (char *) ptr + propdesc->length; + + grub_free (propdesc->name); + grub_free (propdesc->name16); + grub_free (propdesc->data); + t = propdesc; + propdesc = propdesc->next; + grub_free (t); + devhead->num_values++; + } + + devhead->length = (char *) ptr - (char *) devhead; + t = device; + device = device->next; + grub_free (t); + } + + devices = 0; + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)), + int argc, char *args[]) +{ + grub_file_t file; + void *buf, *bufstart, *bufend; + struct grub_xnu_devprop_header *head; + grub_size_t size; + unsigned i, j; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + + file = grub_gzfile_open (args[0], 1); + if (! file) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + "couldn't load device-propertie dump"); + size = grub_file_size (file); + buf = grub_malloc (size); + if (!buf) + { + grub_file_close (file); + return grub_errno; + } + if (grub_file_read (file, buf, size) != (grub_ssize_t) size) + { + grub_file_close (file); + return grub_errno; + } + grub_file_close (file); + + bufstart = buf; + bufend = (char *) buf + size; + head = buf; + buf = head + 1; + for (i = 0; i < grub_le_to_cpu32 (head->num_devices) && buf < bufend; i++) + { + struct grub_efi_device_path *dp, *dpstart; + struct grub_xnu_devprop_device_descriptor *dev; + struct grub_xnu_devprop_device_header *devhead; + + devhead = buf; + buf = devhead + 1; + dpstart = buf; + + do + { + dp = buf; + buf = (char *) buf + GRUB_EFI_DEVICE_PATH_LENGTH (dp); + } + while (!GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp) && buf < bufend); + + dev = grub_xnu_devprop_add_device (dpstart, (char *) buf + - (char *) dpstart); + + for (j = 0; j < grub_le_to_cpu32 (devhead->num_values) && buf < bufend; + j++) + { + grub_uint32_t *namelen; + grub_uint32_t *datalen; + grub_uint16_t *utf16; + void *data; + grub_err_t err; + + namelen = buf; + buf = namelen + 1; + if (buf >= bufend) + break; + + utf16 = buf; + buf = (char *) buf + *namelen - sizeof (grub_uint32_t); + if (buf >= bufend) + break; + + datalen = buf; + buf = datalen + 1; + if (buf >= bufend) + break; + + data = buf; + buf = (char *) buf + *datalen - sizeof (grub_uint32_t); + if (buf >= bufend) + break; + err = grub_xnu_devprop_add_property_utf16 + (dev, utf16, (*namelen - sizeof (grub_uint32_t) + - sizeof (grub_uint16_t)) / sizeof (grub_uint16_t), + data, *datalen - sizeof (grub_uint32_t)); + if (err) + { + grub_free (bufstart); + return err; + } + } + } + + grub_free (bufstart); + return GRUB_ERR_NONE; +} + /* Fill device tree. */ /* FIXME: some entries may be platform-agnostic. Move them to loader/xnu.c. */ grub_err_t @@ -216,11 +627,6 @@ grub_cpu_xnu_fill_devicetree (void) struct grub_xnu_devtree_key *runtimesrvkey; struct grub_xnu_devtree_key *platformkey; unsigned i, j; - grub_err_t err; - - err = grub_autoefi_prepare (); - if (err) - return err; /* The value "model". */ /* FIXME: may this value be sometimes different? */ @@ -343,11 +749,13 @@ grub_cpu_xnu_fill_devicetree (void) #endif /* The name of key for new table. */ - grub_sprintf (guidbuf, "%08x-%04x-%04x-%02x%02x-", - guid.data1, guid.data2, guid.data3, guid.data4[0], - guid.data4[1]); + grub_snprintf (guidbuf, sizeof (guidbuf), "%08x-%04x-%04x-%02x%02x-", + guid.data1, guid.data2, guid.data3, guid.data4[0], + guid.data4[1]); for (j = 2; j < 8; j++) - grub_sprintf (guidbuf + grub_strlen (guidbuf), "%02x", guid.data4[j]); + grub_snprintf (guidbuf + grub_strlen (guidbuf), + sizeof (guidbuf) - grub_strlen (guidbuf), + "%02x", guid.data4[j]); /* For some reason GUID has to be in uppercase. */ for (j = 0; guidbuf[j] ; j++) if (guidbuf[j] >= 'a' && guidbuf[j] <= 'f') @@ -417,6 +825,19 @@ grub_cpu_xnu_fill_devicetree (void) return GRUB_ERR_NONE; } +grub_err_t +grub_xnu_boot_resume (void) +{ + struct grub_relocator32_state state; + + state.esp = grub_xnu_stack; + state.eip = grub_xnu_entry_point; + state.eax = grub_xnu_arg1; + + return grub_relocator32_boot (grub_xnu_heap_start, grub_xnu_heap_will_be_at, + state); +} + /* Boot xnu. */ grub_err_t grub_xnu_boot (void) @@ -430,10 +851,28 @@ grub_xnu_boot (void) grub_efi_uintn_t map_key = 0; grub_efi_uintn_t descriptor_size = 0; grub_efi_uint32_t descriptor_version = 0; - grub_uint64_t firstruntimeaddr, lastruntimeaddr; + grub_uint64_t firstruntimepage, lastruntimepage; + grub_uint64_t curruntimepage; void *devtree; grub_size_t devtreelen; int i; + struct grub_relocator32_state state; + + err = grub_autoefi_prepare (); + if (err) + return err; + + err = grub_cpu_xnu_fill_devprop (); + if (err) + return err; + + err = grub_cpu_xnu_fill_devicetree (); + if (err) + return err; + + err = grub_xnu_fill_devicetree (); + if (err) + return err; /* Page-align to avoid following parts to be inadvertently freed. */ err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); @@ -447,94 +886,7 @@ grub_xnu_boot (void) descriptor_size = 0; descriptor_version = 0; - if (grub_autoefi_get_memory_map (&memory_map_size, memory_map, - &map_key, &descriptor_size, - &descriptor_version) < 0) - return grub_errno; - - memory_map = grub_xnu_heap_malloc (memory_map_size); - if (! memory_map) - return grub_errno; - - if (grub_autoefi_get_memory_map (&memory_map_size, memory_map, - &map_key, &descriptor_size, - &descriptor_version) <= 0) - return grub_errno; - mmap_relloc_off = (grub_uint8_t *) memory_map - - (grub_uint8_t *) grub_xnu_heap_start; - - firstruntimeaddr = (grub_uint64_t) (-1); - lastruntimeaddr = 0; - for (i = 0; (unsigned) i < memory_map_size / descriptor_size; i++) - { - grub_efi_memory_descriptor_t *curdesc = (grub_efi_memory_descriptor_t *) - ((char *) memory_map + descriptor_size * i); - - /* Some EFI implementations set physical_start to 0 which - causes XNU crash. */ - curdesc->virtual_start = curdesc->physical_start; - - if (curdesc->type == GRUB_EFI_RUNTIME_SERVICES_DATA - || curdesc->type == GRUB_EFI_RUNTIME_SERVICES_CODE) - { - if (firstruntimeaddr > curdesc->physical_start) - firstruntimeaddr = curdesc->physical_start; - if (lastruntimeaddr < curdesc->physical_start - + curdesc->num_pages * 4096) - lastruntimeaddr = curdesc->physical_start - + curdesc->num_pages * 4096; - } - } - - /* Relocate the boot parameters to heap. */ - bootparams_relloc = grub_xnu_heap_malloc (sizeof (*bootparams_relloc)); - if (! bootparams_relloc) - return grub_errno; - bootparams_relloc_off = (grub_uint8_t *) bootparams_relloc - - (grub_uint8_t *) grub_xnu_heap_start; - err = grub_xnu_writetree_toheap (&devtree, &devtreelen); - if (err) - return err; - bootparams_relloc = (struct grub_xnu_boot_params *) - (bootparams_relloc_off + (grub_uint8_t *) grub_xnu_heap_start); - - grub_memcpy (bootparams_relloc->cmdline, grub_xnu_cmdline, - sizeof (bootparams_relloc->cmdline)); - - bootparams_relloc->devtree = ((char *) devtree - grub_xnu_heap_start) - + grub_xnu_heap_will_be_at; - bootparams_relloc->devtreelen = devtreelen; - - bootparams_relloc->heap_start = grub_xnu_heap_will_be_at; - bootparams_relloc->heap_size = grub_xnu_heap_size; - - bootparams_relloc->efi_mmap = grub_xnu_heap_will_be_at + mmap_relloc_off; - bootparams_relloc->efi_mmap_size = memory_map_size; - bootparams_relloc->efi_mem_desc_size = descriptor_size; - bootparams_relloc->efi_mem_desc_version = descriptor_version; - - bootparams_relloc->efi_runtime_first_page = firstruntimeaddr - / GRUB_XNU_PAGESIZE; - bootparams_relloc->efi_runtime_npages - = ((lastruntimeaddr + GRUB_XNU_PAGESIZE - 1) / GRUB_XNU_PAGESIZE) - - (firstruntimeaddr / GRUB_XNU_PAGESIZE); - bootparams_relloc->efi_uintnbits = SIZEOF_OF_UINTN * 8; - bootparams_relloc->efi_system_table - = PTR_TO_UINT32 (grub_autoefi_system_table); - - bootparams_relloc->verminor = GRUB_XNU_BOOTARGS_VERMINOR; - bootparams_relloc->vermajor = GRUB_XNU_BOOTARGS_VERMAJOR; - - /* Parameters for asm helper. */ - grub_xnu_stack = bootparams_relloc->heap_start - + bootparams_relloc->heap_size + GRUB_XNU_PAGESIZE; - grub_xnu_arg1 = bootparams_relloc_off + grub_xnu_heap_will_be_at; -#ifndef GRUB_UTIL - grub_xnu_launch = (void (*) (void)) - (grub_xnu_heap_start + grub_xnu_heap_size); -#endif grub_dprintf ("xnu", "eip=%x\n", grub_xnu_entry_point); - grub_dprintf ("xnu", "launch=%p\n", grub_xnu_launch); const char *debug = grub_env_get ("debug"); @@ -544,6 +896,13 @@ grub_xnu_boot (void) grub_getkey (); } + /* Relocate the boot parameters to heap. */ + bootparams_relloc = grub_xnu_heap_malloc (sizeof (*bootparams_relloc)); + if (! bootparams_relloc) + return grub_errno; + bootparams_relloc_off = (grub_uint8_t *) bootparams_relloc + - (grub_uint8_t *) grub_xnu_heap_start; + /* Set video. */ err = grub_xnu_set_video (bootparams_relloc); if (err != GRUB_ERR_NONE) @@ -560,16 +919,121 @@ grub_xnu_boot (void) bootparams_relloc->lfb_base = 0; } - grub_memcpy (grub_xnu_heap_start + grub_xnu_heap_size, - grub_xnu_launcher_start, - grub_xnu_launcher_end - grub_xnu_launcher_start); + if (grub_autoefi_get_memory_map (&memory_map_size, memory_map, + &map_key, &descriptor_size, + &descriptor_version) < 0) + return grub_errno; + /* We will do few allocations later. Reserve some space for possible + memory map growth. */ + memory_map_size += 20 * descriptor_size; + memory_map = grub_xnu_heap_malloc (memory_map_size); + if (! memory_map) + return grub_errno; + mmap_relloc_off = (grub_uint8_t *) memory_map + - (grub_uint8_t *) grub_xnu_heap_start; - if (! grub_autoefi_finish_boot_services ()) + err = grub_xnu_writetree_toheap (&devtree, &devtreelen); + if (err) + return err; + bootparams_relloc = (struct grub_xnu_boot_params *) + (bootparams_relloc_off + (grub_uint8_t *) grub_xnu_heap_start); + + grub_memcpy (bootparams_relloc->cmdline, grub_xnu_cmdline, + sizeof (bootparams_relloc->cmdline)); + + bootparams_relloc->devtree + = ((grub_uint8_t *) devtree - (grub_uint8_t *) grub_xnu_heap_start) + + grub_xnu_heap_will_be_at; + bootparams_relloc->devtreelen = devtreelen; + + memory_map = (grub_efi_memory_descriptor_t *) + ((grub_uint8_t *) grub_xnu_heap_start + mmap_relloc_off); + + if (grub_autoefi_get_memory_map (&memory_map_size, memory_map, + &map_key, &descriptor_size, + &descriptor_version) <= 0) + return grub_errno; + + bootparams_relloc->efi_system_table + = PTR_TO_UINT32 (grub_autoefi_system_table); + + firstruntimepage = (((grub_addr_t) grub_xnu_heap_will_be_at + + grub_xnu_heap_size + GRUB_XNU_PAGESIZE - 1) + / GRUB_XNU_PAGESIZE) + 20; + curruntimepage = firstruntimepage; + + for (i = 0; (unsigned) i < memory_map_size / descriptor_size; i++) + { + grub_efi_memory_descriptor_t *curdesc = (grub_efi_memory_descriptor_t *) + ((char *) memory_map + descriptor_size * i); + + curdesc->virtual_start = curdesc->physical_start; + + if (curdesc->type == GRUB_EFI_RUNTIME_SERVICES_DATA + || curdesc->type == GRUB_EFI_RUNTIME_SERVICES_CODE) + { + curdesc->virtual_start = curruntimepage << 12; + curruntimepage += curdesc->num_pages; + if (curdesc->physical_start + <= PTR_TO_UINT64 (grub_autoefi_system_table) + && curdesc->physical_start + (curdesc->num_pages << 12) + > PTR_TO_UINT64 (grub_autoefi_system_table)) + bootparams_relloc->efi_system_table + = PTR_TO_UINT64 (grub_autoefi_system_table) + - curdesc->physical_start + curdesc->virtual_start; + if (SIZEOF_OF_UINTN == 8 && grub_xnu_is_64bit) + curdesc->virtual_start |= 0xffffff8000000000ULL; + } + } + + lastruntimepage = curruntimepage; + + bootparams_relloc->efi_mmap = grub_xnu_heap_will_be_at + mmap_relloc_off; + bootparams_relloc->efi_mmap_size = memory_map_size; + bootparams_relloc->efi_mem_desc_size = descriptor_size; + bootparams_relloc->efi_mem_desc_version = descriptor_version; + + bootparams_relloc->heap_start = grub_xnu_heap_will_be_at; + bootparams_relloc->heap_size = grub_xnu_heap_size; + bootparams_relloc->efi_runtime_first_page = firstruntimepage; + + bootparams_relloc->efi_runtime_npages = lastruntimepage - firstruntimepage; + bootparams_relloc->efi_uintnbits = SIZEOF_OF_UINTN * 8; + + bootparams_relloc->verminor = GRUB_XNU_BOOTARGS_VERMINOR; + bootparams_relloc->vermajor = GRUB_XNU_BOOTARGS_VERMAJOR; + + /* Parameters for asm helper. */ + grub_xnu_stack = bootparams_relloc->heap_start + + bootparams_relloc->heap_size + GRUB_XNU_PAGESIZE; + grub_xnu_arg1 = bootparams_relloc_off + grub_xnu_heap_will_be_at; + + if (! grub_autoefi_exit_boot_services (map_key)) return grub_error (GRUB_ERR_IO, "can't exit boot services"); - grub_xnu_launch (); + grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size, + descriptor_version,memory_map); - /* Never reaches here. */ - return 0; + state.eip = grub_xnu_entry_point; + state.eax = grub_xnu_arg1; + state.esp = grub_xnu_stack; + return grub_relocator32_boot (grub_xnu_heap_start, grub_xnu_heap_will_be_at, + state); +} + +static grub_command_t cmd_devprop_load; + +void +grub_cpu_xnu_init (void) +{ + cmd_devprop_load = grub_register_command ("xnu_devprop_load", + grub_cmd_devprop_load, + 0, N_("Load device-properties dump.")); +} + +void +grub_cpu_xnu_fini (void) +{ + grub_unregister_command (cmd_devprop_load); } diff --git a/loader/i386/xnu_helper.S b/loader/i386/xnu_helper.S deleted file mode 100644 index 4250c58ad..000000000 --- a/loader/i386/xnu_helper.S +++ /dev/null @@ -1,211 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 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 . - */ - -#include - - - .p2align 4 /* force 16-byte alignment */ - -VARIABLE(grub_xnu_launcher_start) -base: - cli - -#ifndef __x86_64__ - /* mov imm32, %eax */ - .byte 0xb8 -VARIABLE(grub_xnu_heap_will_be_at) - .long 0 - mov %eax, %edi - - /* mov imm32, %eax */ - .byte 0xb8 -VARIABLE(grub_xnu_heap_start) - .long 0 - mov %eax, %esi - - /* mov imm32, %ecx */ - .byte 0xb9 -VARIABLE(grub_xnu_heap_size) - .long 0 - mov %edi, %eax - add %ecx, %eax - /* %rax now contains our starting position after relocation. */ - /* One more page to copy: ourselves. */ - add $0x403, %ecx - shr $2, %ecx - - /* Forward copy. */ - cld - rep - movsl - - mov %eax, %esi - add $(cont0-base), %eax - jmp *%eax -cont0: -#else - xorq %rax, %rax - - /* mov imm32, %eax */ - .byte 0xb8 -VARIABLE(grub_xnu_heap_will_be_at) - .long 0 - mov %rax, %rdi - - /* mov imm32, %rax */ - .byte 0x48 - .byte 0xb8 -VARIABLE(grub_xnu_heap_start) - .long 0 - .long 0 - mov %rax, %rsi - - /* mov imm32, %rcx */ - .byte 0x48 - .byte 0xb9 -VARIABLE(grub_xnu_heap_size) - .long 0 - .long 0 - mov %rdi, %rax - add %rcx, %rax - /* %rax now contains our starting position after relocation. */ - /* One more page to copy: ourselves. */ - add $0x403, %rcx - shr $2, %rcx - - /* Forward copy. */ - cld - rep - movsl - - mov %rax, %rsi -#ifdef APPLE_CC - add $(cont0-base), %eax -#else - add $(cont0-base), %rax -#endif - jmp *%rax - -cont0: -#ifdef APPLE_CC - lea (cont1 - base) (%esi, 1), %eax - mov %eax, (jump_vector - base) (%esi, 1) - - lea (gdt - base) (%esi, 1), %eax - mov %eax, (gdt_addr - base) (%esi, 1) - - /* Switch to compatibility mode. */ - - lgdt (gdtdesc - base) (%esi, 1) - - /* Update %cs. Thanks to David Miller for pointing this mistake out. */ - ljmp *(jump_vector - base) (%esi,1) -#else - lea (cont1 - base) (%rsi, 1), %rax - mov %eax, (jump_vector - base) (%rsi, 1) - - lea (gdt - base) (%rsi, 1), %rax - mov %rax, (gdt_addr - base) (%rsi, 1) - - /* Switch to compatibility mode. */ - - lgdt (gdtdesc - base) (%rsi, 1) - - /* Update %cs. Thanks to David Miller for pointing this mistake out. */ - ljmp *(jump_vector - base) (%rsi, 1) -#endif - -cont1: - .code32 - - /* Update other registers. */ - mov $0x18, %eax - mov %eax, %ds - mov %eax, %es - mov %eax, %fs - mov %eax, %gs - mov %eax, %ss - - /* Disable paging. */ - mov %cr0, %eax - and $0x7fffffff, %eax - mov %eax, %cr0 - - /* Disable amd64. */ - mov $0xc0000080, %ecx - rdmsr - and $0xfffffeff, %eax - wrmsr - - /* Turn off PAE. */ - movl %cr4, %eax - and $0xffffffcf, %eax - mov %eax, %cr4 - - jmp cont2 -cont2: -#endif - .code32 - - /* Registers on XNU boot: eip, esp and eax. */ - /* mov imm32, %ecx */ - .byte 0xb9 -VARIABLE (grub_xnu_entry_point) - .long 0 - /* mov imm32, %eax */ - .byte 0xb8 -VARIABLE (grub_xnu_arg1) - .long 0 - /* mov imm32, %ebx */ - .byte 0xbb -VARIABLE (grub_xnu_stack) - .long 0 - - movl %ebx, %esp - - jmp *%ecx - -#ifdef __x86_64__ - /* GDT. Copied from loader/i386/linux.c. */ - .p2align 4 -gdt: - /* NULL. */ - .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - - /* Reserved. */ - .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - - /* Code segment. */ - .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00 - - /* Data segment. */ - .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 - -gdtdesc: - .word 31 -gdt_addr: - /* Filled by the code. */ - .quad 0 - - .p2align 4 -jump_vector: - /* Jump location. Is filled by the code */ - .long 0 - .long 0x10 -#endif -VARIABLE(grub_xnu_launcher_end) diff --git a/loader/ieee1275/multiboot2.c b/loader/ieee1275/multiboot2.c deleted file mode 100644 index 3646e8091..000000000 --- a/loader/ieee1275/multiboot2.c +++ /dev/null @@ -1,145 +0,0 @@ -/* multiboot.c - boot a multiboot 2 OS image. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __i386__ -#include -#endif - -typedef void (*kernel_entry_t) (unsigned long, void *, int (void *), - unsigned long, unsigned long); - -/* Claim the memory occupied by the multiboot kernel. */ -grub_err_t -grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr, - int *do_load) -{ - int rc; - - if (phdr->p_type != PT_LOAD) - { - *do_load = 0; - return 0; - } - *do_load = 1; - - rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz); - if (rc) - return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim %x - %x", - phdr->p_paddr, phdr->p_paddr + phdr->p_memsz); - - grub_dprintf ("loader", "Loading segment at 0x%x - 0x%x\n", phdr->p_paddr, - phdr->p_paddr + phdr->p_memsz); - - return GRUB_ERR_NONE; -} - -/* Claim the memory occupied by the multiboot kernel. */ -grub_err_t -grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr, - int *do_load) -{ - int rc; - - if (phdr->p_type != PT_LOAD) - { - *do_load = 0; - return 0; - } - *do_load = 1; - - rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz); - if (rc) - return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim 0x%lx - 0x%lx", - phdr->p_paddr, phdr->p_paddr + phdr->p_memsz); - - grub_dprintf ("loader", "Loading segment at 0x%lx - 0x%lx\n", - (unsigned long) phdr->p_paddr, - (unsigned long) (phdr->p_paddr + phdr->p_memsz)); - - return GRUB_ERR_NONE; -} - -grub_err_t -grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr) -{ - int rc; - - /* XXX Will need to map on some firmwares. */ - rc = grub_ieee1275_claim (0, size, MULTIBOOT2_MOD_ALIGN, addr); - if (rc) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Firmware couldn't allocate memory (size 0x%lx)", size); - - return GRUB_ERR_NONE; -} - -grub_err_t -grub_mb2_arch_module_free (grub_addr_t addr, grub_size_t size) -{ - grub_ieee1275_release (addr, size); - return GRUB_ERR_NONE; -} - -grub_err_t -grub_mb2_tags_arch_create (void) -{ - /* Nothing special. */ - return GRUB_ERR_NONE; -} - -/* Release the memory we claimed from Open Firmware above. */ -void -grub_mb2_arch_unload (struct multiboot2_tag_header *tags) -{ - struct multiboot2_tag_header *tag; - - /* Free all module memory in the tag list. */ - for_each_tag (tag, tags) - { - if (tag->key == MULTIBOOT2_TAG_MODULE) - { - struct multiboot2_tag_module *module = - (struct multiboot2_tag_module *) tag; - grub_ieee1275_release (module->addr, module->size); - } - } -} - -void -grub_mb2_arch_boot (grub_addr_t entry_addr, void *tags) -{ -#if defined(__powerpc__) - kernel_entry_t entry = (kernel_entry_t) entry_addr; - entry (MULTIBOOT2_BOOTLOADER_MAGIC, tags, grub_ieee1275_entry_fn, 0, 0); -#elif defined(__i386__) - grub_multiboot2_real_boot (entry_addr, tags); -#else -#error -#endif -} diff --git a/loader/macho.c b/loader/macho.c index bd460b810..199d6f111 100644 --- a/loader/macho.c +++ b/loader/macho.c @@ -30,239 +30,6 @@ #include #include -#define min(a,b) (((a) < (b)) ? (a) : (b)) - -/* 32-bit. */ - -int -grub_macho_contains_macho32 (grub_macho_t macho) -{ - return macho->offset32 != -1; -} - -static void -grub_macho_parse32 (grub_macho_t macho) -{ - struct grub_macho_header32 head; - - /* Is there any candidate at all? */ - if (macho->offset32 == -1) - return; - - /* Read header and check magic*/ - if (grub_file_seek (macho->file, macho->offset32) == (grub_off_t) -1 - || grub_file_read (macho->file, &head, sizeof (head)) - != sizeof(head)) - { - grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header."); - macho->offset32 = -1; - return; - } - if (head.magic != GRUB_MACHO_MAGIC32) - { - grub_error (GRUB_ERR_BAD_OS, "Invalid Mach-O 32-bit header."); - macho->offset32 = -1; - return; - } - - /* Read commands. */ - macho->ncmds32 = head.ncmds; - macho->cmdsize32 = head.sizeofcmds; - macho->cmds32 = grub_malloc(macho->cmdsize32); - if (! macho->cmds32) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "not enough memory to read commands"); - return; - } - if (grub_file_read (macho->file, macho->cmds32, - (grub_size_t) macho->cmdsize32) - != (grub_ssize_t) macho->cmdsize32) - { - grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header."); - macho->offset32 = -1; - } -} - -typedef int NESTED_FUNC_ATTR (*grub_macho_iter_hook_t) -(grub_macho_t , struct grub_macho_cmd *, - void *); - -static grub_err_t -grub_macho32_cmds_iterate (grub_macho_t macho, - grub_macho_iter_hook_t hook, - void *hook_arg) -{ - grub_uint8_t *hdrs = macho->cmds32; - int i; - if (! macho->cmds32) - return grub_error (GRUB_ERR_BAD_OS, "Couldn't find 32-bit Mach-O"); - for (i = 0; i < macho->ncmds32; i++) - { - struct grub_macho_cmd *hdr = (struct grub_macho_cmd *) hdrs; - if (hook (macho, hdr, hook_arg)) - break; - hdrs += hdr->cmdsize; - } - - return grub_errno; -} - -grub_size_t -grub_macho32_filesize (grub_macho_t macho) -{ - if (grub_macho_contains_macho32 (macho)) - return macho->end32 - macho->offset32; - return 0; -} - -grub_err_t -grub_macho32_readfile (grub_macho_t macho, void *dest) -{ - grub_ssize_t read; - if (! grub_macho_contains_macho32 (macho)) - return grub_error (GRUB_ERR_BAD_OS, - "Couldn't read architecture-specific part"); - - if (grub_file_seek (macho->file, macho->offset32) == (grub_off_t) -1) - { - grub_error_push (); - return grub_error (GRUB_ERR_BAD_OS, - "Invalid offset in program header."); - } - - read = grub_file_read (macho->file, dest, - macho->end32 - macho->offset32); - if (read != (grub_ssize_t) (macho->end32 - macho->offset32)) - { - grub_error_push (); - return grub_error (GRUB_ERR_BAD_OS, - "Couldn't read architecture-specific part"); - } - return GRUB_ERR_NONE; -} - -/* Calculate the amount of memory spanned by the segments. */ -grub_err_t -grub_macho32_size (grub_macho_t macho, grub_addr_t *segments_start, - grub_addr_t *segments_end, int flags) -{ - int nr_phdrs = 0; - - /* Run through the program headers to calculate the total memory size we - should claim. */ - auto int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho, - struct grub_macho_cmd *phdr, void *_arg); - int NESTED_FUNC_ATTR calcsize (grub_macho_t UNUSED _macho, - struct grub_macho_cmd *hdr0, void UNUSED *_arg) - { - struct grub_macho_segment32 *hdr = (struct grub_macho_segment32 *) hdr0; - if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT32) - return 0; - if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS)) - return 0; - - nr_phdrs++; - if (hdr->vmaddr < *segments_start) - *segments_start = hdr->vmaddr; - if (hdr->vmaddr + hdr->vmsize > *segments_end) - *segments_end = hdr->vmaddr + hdr->vmsize; - return 0; - } - - *segments_start = (grub_uint32_t) -1; - *segments_end = 0; - - grub_macho32_cmds_iterate (macho, calcsize, 0); - - if (nr_phdrs == 0) - return grub_error (GRUB_ERR_BAD_OS, "No program headers present"); - - if (*segments_end < *segments_start) - /* Very bad addresses. */ - return grub_error (GRUB_ERR_BAD_OS, "Bad program header load addresses"); - - return GRUB_ERR_NONE; -} - -/* Load every loadable segment into memory specified by `_load_hook'. */ -grub_err_t -grub_macho32_load (grub_macho_t macho, char *offset, int flags) -{ - grub_err_t err = 0; - auto int NESTED_FUNC_ATTR do_load(grub_macho_t _macho, - struct grub_macho_cmd *hdr0, - void UNUSED *_arg); - int NESTED_FUNC_ATTR do_load(grub_macho_t _macho, - struct grub_macho_cmd *hdr0, - void UNUSED *_arg) - { - struct grub_macho_segment32 *hdr = (struct grub_macho_segment32 *) hdr0; - - if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT32) - return 0; - - if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS)) - return 0; - if (! hdr->vmsize) - return 0; - - if (grub_file_seek (_macho->file, hdr->fileoff - + _macho->offset32) == (grub_off_t) -1) - { - grub_error_push (); - grub_error (GRUB_ERR_BAD_OS, - "Invalid offset in program header."); - return 1; - } - - if (hdr->filesize) - { - grub_ssize_t read; - read = grub_file_read (_macho->file, offset + hdr->vmaddr, - min (hdr->filesize, hdr->vmsize)); - if (read != (grub_ssize_t) min (hdr->filesize, hdr->vmsize)) - { - /* XXX How can we free memory from `load_hook'? */ - grub_error_push (); - err=grub_error (GRUB_ERR_BAD_OS, - "Couldn't read segment from file: " - "wanted 0x%lx bytes; read 0x%lx bytes.", - hdr->filesize, read); - return 1; - } - } - - if (hdr->filesize < hdr->vmsize) - grub_memset (offset + hdr->vmaddr + hdr->filesize, - 0, hdr->vmsize - hdr->filesize); - return 0; - } - - grub_macho32_cmds_iterate (macho, do_load, 0); - - return err; -} - -grub_uint32_t -grub_macho32_get_entry_point (grub_macho_t macho) -{ - grub_uint32_t entry_point = 0; - auto int NESTED_FUNC_ATTR hook(grub_macho_t _macho, - struct grub_macho_cmd *hdr, - void UNUSED *_arg); - int NESTED_FUNC_ATTR hook(grub_macho_t UNUSED _macho, - struct grub_macho_cmd *hdr, - void UNUSED *_arg) - { - if (hdr->cmd == GRUB_MACHO_CMD_THREAD) - entry_point = ((struct grub_macho_thread32 *) hdr)->entry_point; - return 0; - } - grub_macho32_cmds_iterate (macho, hook, 0); - return entry_point; -} - - grub_err_t grub_macho_close (grub_macho_t macho) { @@ -304,7 +71,7 @@ grub_macho_file (grub_file_t file) != sizeof (filestart)) { grub_error_push (); - grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header."); + grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header"); goto fail; } @@ -328,7 +95,7 @@ grub_macho_file (grub_file_t file) { grub_free (archs); grub_error_push (); - grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header."); + grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header"); goto fail; } @@ -367,8 +134,7 @@ grub_macho_file (grub_file_t file) } grub_macho_parse32 (macho); - /* FIXME: implement 64-bit.*/ - /* grub_macho_parse64 (macho); */ + grub_macho_parse64 (macho); return macho; diff --git a/loader/macho32.c b/loader/macho32.c new file mode 100644 index 000000000..0d740eda7 --- /dev/null +++ b/loader/macho32.c @@ -0,0 +1,18 @@ +#include +#include + +#define SUFFIX(x) x ## 32 +typedef struct grub_macho_header32 grub_macho_header_t; +typedef struct grub_macho_segment32 grub_macho_segment_t; +typedef grub_uint32_t grub_macho_addr_t; +typedef struct grub_macho_thread32 grub_macho_thread_t; +#define offsetXX offset32 +#define ncmdsXX ncmds32 +#define cmdsizeXX cmdsize32 +#define cmdsXX cmds32 +#define endXX end32 +#define XX "32" +#define GRUB_MACHO_MAGIC GRUB_MACHO_MAGIC32 +#define GRUB_MACHO_CMD_SEGMENT GRUB_MACHO_CMD_SEGMENT32 +#include "machoXX.c" + diff --git a/loader/macho64.c b/loader/macho64.c new file mode 100644 index 000000000..17a8021e0 --- /dev/null +++ b/loader/macho64.c @@ -0,0 +1,18 @@ +#include +#include + +#define SUFFIX(x) x ## 64 +typedef struct grub_macho_header64 grub_macho_header_t; +typedef struct grub_macho_segment64 grub_macho_segment_t; +typedef grub_uint64_t grub_macho_addr_t; +typedef struct grub_macho_thread64 grub_macho_thread_t; +#define offsetXX offset64 +#define ncmdsXX ncmds64 +#define cmdsizeXX cmdsize64 +#define cmdsXX cmds64 +#define endXX end64 +#define XX "64" +#define GRUB_MACHO_MAGIC GRUB_MACHO_MAGIC64 +#define GRUB_MACHO_CMD_SEGMENT GRUB_MACHO_CMD_SEGMENT64 +#include "machoXX.c" + diff --git a/loader/machoXX.c b/loader/machoXX.c new file mode 100644 index 000000000..918ddbb20 --- /dev/null +++ b/loader/machoXX.c @@ -0,0 +1,239 @@ + +#include +#include +#include + +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +int +SUFFIX (grub_macho_contains_macho) (grub_macho_t macho) +{ + return macho->offsetXX != -1; +} + +void +SUFFIX (grub_macho_parse) (grub_macho_t macho) +{ + grub_macho_header_t head; + + /* Is there any candidate at all? */ + if (macho->offsetXX == -1) + return; + + /* Read header and check magic*/ + if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1 + || grub_file_read (macho->file, &head, sizeof (head)) + != sizeof(head)) + { + grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header"); + macho->offsetXX = -1; + return; + } + if (head.magic != GRUB_MACHO_MAGIC) + { + grub_error (GRUB_ERR_BAD_OS, "invalid Mach-O " XX "-bit header"); + macho->offsetXX = -1; + return; + } + + /* Read commands. */ + macho->ncmdsXX = head.ncmds; + macho->cmdsizeXX = head.sizeofcmds; + macho->cmdsXX = grub_malloc(macho->cmdsizeXX); + if (! macho->cmdsXX) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "not enough memory to read commands"); + return; + } + if (grub_file_read (macho->file, macho->cmdsXX, + (grub_size_t) macho->cmdsizeXX) + != (grub_ssize_t) macho->cmdsizeXX) + { + grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header"); + macho->offsetXX = -1; + } +} + +typedef int NESTED_FUNC_ATTR (*grub_macho_iter_hook_t) +(grub_macho_t , struct grub_macho_cmd *, + void *); + +static grub_err_t +grub_macho_cmds_iterate (grub_macho_t macho, + grub_macho_iter_hook_t hook, + void *hook_arg) +{ + grub_uint8_t *hdrs = macho->cmdsXX; + int i; + if (! macho->cmdsXX) + return grub_error (GRUB_ERR_BAD_OS, "couldn't find " XX "-bit Mach-O"); + for (i = 0; i < macho->ncmdsXX; i++) + { + struct grub_macho_cmd *hdr = (struct grub_macho_cmd *) hdrs; + if (hook (macho, hdr, hook_arg)) + break; + hdrs += hdr->cmdsize; + } + + return grub_errno; +} + +grub_size_t +SUFFIX (grub_macho_filesize) (grub_macho_t macho) +{ + if (SUFFIX (grub_macho_contains_macho) (macho)) + return macho->endXX - macho->offsetXX; + return 0; +} + +grub_err_t +SUFFIX (grub_macho_readfile) (grub_macho_t macho, void *dest) +{ + grub_ssize_t read; + if (! SUFFIX (grub_macho_contains_macho) (macho)) + return grub_error (GRUB_ERR_BAD_OS, + "couldn't read architecture-specific part"); + + if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1) + { + grub_error_push (); + return grub_error (GRUB_ERR_BAD_OS, + "invalid offset in program header"); + } + + read = grub_file_read (macho->file, dest, + macho->endXX - macho->offsetXX); + if (read != (grub_ssize_t) (macho->endXX - macho->offsetXX)) + { + grub_error_push (); + return grub_error (GRUB_ERR_BAD_OS, + "couldn't read architecture-specific part"); + } + return GRUB_ERR_NONE; +} + +/* Calculate the amount of memory spanned by the segments. */ +grub_err_t +SUFFIX (grub_macho_size) (grub_macho_t macho, grub_macho_addr_t *segments_start, + grub_macho_addr_t *segments_end, int flags) +{ + int nr_phdrs = 0; + + /* Run through the program headers to calculate the total memory size we + should claim. */ + auto int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho, + struct grub_macho_cmd *phdr, void *_arg); + int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho __attribute__ ((unused)), + struct grub_macho_cmd *hdr0, + void *_arg __attribute__ ((unused))) + { + grub_macho_segment_t *hdr = (grub_macho_segment_t *) hdr0; + if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT) + return 0; + + if (! hdr->vmsize) + return 0; + + if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS)) + return 0; + + nr_phdrs++; + if (hdr->vmaddr < *segments_start) + *segments_start = hdr->vmaddr; + if (hdr->vmaddr + hdr->vmsize > *segments_end) + *segments_end = hdr->vmaddr + hdr->vmsize; + return 0; + } + + *segments_start = (grub_macho_addr_t) -1; + *segments_end = 0; + + grub_macho_cmds_iterate (macho, calcsize, 0); + + if (nr_phdrs == 0) + return grub_error (GRUB_ERR_BAD_OS, "no program headers present"); + + if (*segments_end < *segments_start) + /* Very bad addresses. */ + return grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses"); + + return GRUB_ERR_NONE; +} + +/* Load every loadable segment into memory specified by `_load_hook'. */ +grub_err_t +SUFFIX (grub_macho_load) (grub_macho_t macho, char *offset, int flags) +{ + grub_err_t err = 0; + auto int NESTED_FUNC_ATTR do_load(grub_macho_t _macho, + struct grub_macho_cmd *hdr0, + void *_arg __attribute__ ((unused))); + int NESTED_FUNC_ATTR do_load(grub_macho_t _macho, + struct grub_macho_cmd *hdr0, + void *_arg __attribute__ ((unused))) + { + grub_macho_segment_t *hdr = (grub_macho_segment_t *) hdr0; + + if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT) + return 0; + + if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS)) + return 0; + if (! hdr->vmsize) + return 0; + + if (grub_file_seek (_macho->file, hdr->fileoff + + _macho->offsetXX) == (grub_off_t) -1) + { + grub_error_push (); + grub_error (GRUB_ERR_BAD_OS, + "invalid offset in program header"); + return 1; + } + + if (hdr->filesize) + { + grub_ssize_t read; + read = grub_file_read (_macho->file, offset + hdr->vmaddr, + min (hdr->filesize, hdr->vmsize)); + if (read != (grub_ssize_t) min (hdr->filesize, hdr->vmsize)) + { + /* XXX How can we free memory from `load_hook'? */ + grub_error_push (); + err=grub_error (GRUB_ERR_BAD_OS, + "couldn't read segment from file: " + "wanted 0x%lx bytes; read 0x%lx bytes", + hdr->filesize, read); + return 1; + } + } + + if (hdr->filesize < hdr->vmsize) + grub_memset (offset + hdr->vmaddr + hdr->filesize, + 0, hdr->vmsize - hdr->filesize); + return 0; + } + + grub_macho_cmds_iterate (macho, do_load, 0); + + return err; +} + +grub_macho_addr_t +SUFFIX (grub_macho_get_entry_point) (grub_macho_t macho) +{ + grub_macho_addr_t entry_point = 0; + auto int NESTED_FUNC_ATTR hook(grub_macho_t _macho, + struct grub_macho_cmd *hdr, + void *_arg __attribute__ ((unused))); + int NESTED_FUNC_ATTR hook(grub_macho_t _macho __attribute__ ((unused)), + struct grub_macho_cmd *hdr, + void *_arg __attribute__ ((unused))) + { + if (hdr->cmd == GRUB_MACHO_CMD_THREAD) + entry_point = ((grub_macho_thread_t *) hdr)->entry_point; + return 0; + } + grub_macho_cmds_iterate (macho, hook, 0); + return entry_point; +} diff --git a/loader/mips/linux.c b/loader/mips/linux.c new file mode 100644 index 000000000..64497f466 --- /dev/null +++ b/loader/mips/linux.c @@ -0,0 +1,398 @@ +/* linux.c - boot Linux */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,2005,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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* For frequencies. */ +#include +#include + +#define ELF32_LOADMASK (0x00000000UL) +#define ELF64_LOADMASK (0x0000000000000000ULL) + +static grub_dl_t my_mod; + +static int loaded; + +static grub_size_t linux_size; + +static grub_uint8_t *playground; +static grub_addr_t target_addr, entry_addr; +static int linux_argc; +static grub_off_t argv_off, envp_off; +static grub_off_t rd_addr_arg_off, rd_size_arg_off; +static int initrd_loaded = 0; + +static grub_err_t +grub_linux_boot (void) +{ + struct grub_relocator32_state state; + + /* Boot the kernel. */ + state.gpr[1] = entry_addr; + state.gpr[4] = linux_argc; + state.gpr[5] = target_addr + argv_off; + state.gpr[6] = target_addr + envp_off; + state.jumpreg = 1; + grub_relocator32_boot (playground, target_addr, state); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_linux_release_mem (void) +{ + grub_relocator32_free (playground); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_linux_unload (void) +{ + grub_err_t err; + + err = grub_linux_release_mem (); + grub_dl_unref (my_mod); + + loaded = 0; + + return err; +} + +static grub_err_t +grub_linux_load32 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) +{ + Elf32_Addr base; + int extraoff; + + /* Linux's entry point incorrectly contains a virtual address. */ + entry_addr = elf->ehdr.ehdr32.e_entry & ~ELF32_LOADMASK; + + linux_size = grub_elf32_size (elf, &base); + if (linux_size == 0) + return grub_errno; + target_addr = base; + /* Pad it; the kernel scribbles over memory beyond its load address. */ + linux_size += 0x100000; + linux_size = ALIGN_UP (base + linux_size, 4) - base; + extraoff = linux_size; + linux_size += extra_size; + + playground = grub_relocator32_alloc (linux_size); + if (!playground) + return grub_errno; + + *extra_mem = playground + extraoff; + + /* Now load the segments into the area we claimed. */ + auto grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load); + grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load) + { + if (phdr->p_type != PT_LOAD) + { + *do_load = 0; + return 0; + } + *do_load = 1; + + /* Linux's program headers incorrectly contain virtual addresses. + * Translate those to physical, and offset to the area we claimed. */ + *addr = (grub_addr_t) (phdr->p_paddr - base + playground); + return 0; + } + return grub_elf32_load (elf, offset_phdr, 0, 0); +} + +static grub_err_t +grub_linux_load64 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) +{ + Elf64_Addr base; + int extraoff; + + /* Linux's entry point incorrectly contains a virtual address. */ + entry_addr = elf->ehdr.ehdr64.e_entry & ~ELF64_LOADMASK; + + linux_size = grub_elf64_size (elf, &base); + if (linux_size == 0) + return grub_errno; + target_addr = base; + /* Pad it; the kernel scribbles over memory beyond its load address. */ + linux_size += 0x100000; + linux_size = ALIGN_UP (base + linux_size, 4) - base; + extraoff = linux_size; + linux_size += extra_size; + + playground = grub_relocator32_alloc (linux_size); + if (!playground) + return grub_errno; + + *extra_mem = playground + extraoff; + + /* Now load the segments into the area we claimed. */ + auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load); + grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load) + { + if (phdr->p_type != PT_LOAD) + { + *do_load = 0; + return 0; + } + *do_load = 1; + /* Linux's program headers incorrectly contain virtual addresses. + * Translate those to physical, and offset to the area we claimed. */ + *addr = (grub_addr_t) (phdr->p_paddr - base + playground); + return 0; + } + return grub_elf64_load (elf, offset_phdr, 0, 0); +} + +static grub_err_t +grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_elf_t elf = 0; + int i; + int size; + void *extra = NULL; + grub_uint32_t *linux_argv, *linux_envp; + char *linux_args, *linux_envs; + grub_err_t err; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); + + elf = grub_elf_open (argv[0]); + if (! elf) + return grub_errno; + + if (elf->ehdr.ehdr32.e_type != ET_EXEC) + { + grub_elf_close (elf); + return grub_error (GRUB_ERR_UNKNOWN_OS, + "this ELF file is not of the right type\n"); + } + + /* Release the previously used memory. */ + grub_loader_unset (); + loaded = 0; + + /* For arguments. */ + linux_argc = argc; + /* Main arguments. */ + size = (linux_argc) * sizeof (grub_uint32_t); + /* Initrd address and size. */ + size += 2 * sizeof (grub_uint32_t); + /* NULL terminator. */ + size += sizeof (grub_uint32_t); + + /* First argument is always "a0". */ + size += ALIGN_UP (sizeof ("a0"), 4); + /* Normal arguments. */ + for (i = 1; i < argc; i++) + size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); + + /* rd arguments. */ + size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); + size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); + + /* For the environment. */ + size += sizeof (grub_uint32_t); + size += 4 * sizeof (grub_uint32_t); + size += ALIGN_UP (sizeof ("memsize=XXXXXXXXXXXXXXXXXXXX"), 4) + + ALIGN_UP (sizeof ("highmemsize=XXXXXXXXXXXXXXXXXXXX"), 4) + + ALIGN_UP (sizeof ("busclock=XXXXXXXXXX"), 4) + + ALIGN_UP (sizeof ("cpuclock=XXXXXXXXXX"), 4); + + if (grub_elf_is_elf32 (elf)) + err = grub_linux_load32 (elf, &extra, size); + else + if (grub_elf_is_elf64 (elf)) + err = grub_linux_load64 (elf, &extra, size); + else + err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "unknown ELF class"); + + grub_elf_close (elf); + + if (err) + return err; + + linux_argv = extra; + argv_off = (grub_uint8_t *) linux_argv - (grub_uint8_t *) playground; + extra = linux_argv + (linux_argc + 1 + 2); + linux_args = extra; + + grub_memcpy (linux_args, "a0", sizeof ("a0")); + *linux_argv = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground + + target_addr; + linux_argv++; + linux_args += ALIGN_UP (sizeof ("a0"), 4); + + for (i = 1; i < argc; i++) + { + grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1); + *linux_argv = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground + + target_addr; + linux_argv++; + linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); + } + + /* Reserve space for rd arguments. */ + rd_addr_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground; + linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); + *linux_argv = 0; + linux_argv++; + + rd_size_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground; + linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); + *linux_argv = 0; + linux_argv++; + + *linux_argv = 0; + + extra = linux_args; + + linux_envp = extra; + envp_off = (grub_uint8_t *) linux_envp - (grub_uint8_t *) playground; + linux_envs = (char *) (linux_envp + 5); + grub_snprintf (linux_envs, sizeof ("memsize=XXXXXXXXXXXXXXXXXXXX"), + "memsize=%lld", + (unsigned long long) grub_mmap_get_lower () >> 20); + linux_envp[0] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground + + target_addr; + linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); + grub_snprintf (linux_envs, sizeof ("highmemsize=XXXXXXXXXXXXXXXXXXXX"), + "highmemsize=%lld", + (unsigned long long) grub_mmap_get_upper () >> 20); + linux_envp[1] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground + + target_addr; + linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); + + grub_snprintf (linux_envs, sizeof ("busclock=XXXXXXXXXX"), + "busclock=%d", grub_arch_busclock); + linux_envp[2] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground + + target_addr; + linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); + grub_snprintf (linux_envs, sizeof ("cpuclock=XXXXXXXXXX"), + "cpuclock=%d", grub_arch_cpuclock); + linux_envp[3] = (grub_uint8_t *) linux_envs - (grub_uint8_t *) playground + + target_addr; + linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); + + + linux_envp[4] = 0; + + grub_loader_set (grub_linux_boot, grub_linux_unload, 1); + initrd_loaded = 0; + loaded = 1; + grub_dl_ref (my_mod); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_ssize_t size; + grub_size_t overhead; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified"); + + if (!loaded) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load Linux first."); + + if (initrd_loaded) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd can be loaded."); + + file = grub_file_open (argv[0]); + if (! file) + return grub_errno; + + size = grub_file_size (file); + + overhead = ALIGN_UP (target_addr + linux_size + 0x10000, 0x10000) + - (target_addr + linux_size); + + playground = grub_relocator32_realloc (playground, + linux_size + overhead + size); + + if (!playground) + { + grub_file_close (file); + return grub_errno; + } + + if (grub_file_read (file, playground + linux_size + overhead, size) != size) + { + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); + grub_file_close (file); + + return grub_errno; + } + + grub_snprintf ((char *) playground + rd_addr_arg_off, + sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%llx", + (unsigned long long) target_addr + linux_size + overhead); + ((grub_uint32_t *) (playground + argv_off))[linux_argc] + = target_addr + rd_addr_arg_off; + linux_argc++; + + grub_snprintf ((char *) playground + rd_size_arg_off, + sizeof ("rd_size=0xXXXXXXXXXXXXXXXXX"), "rd_size=0x%llx", + (unsigned long long) size); + ((grub_uint32_t *) (playground + argv_off))[linux_argc] + = target_addr + rd_size_arg_off; + linux_argc++; + + initrd_loaded = 1; + + grub_file_close (file); + + return GRUB_ERR_NONE; +} + +static grub_command_t cmd_linux, cmd_initrd; + +GRUB_MOD_INIT(linux) +{ + cmd_linux = grub_register_command ("linux", grub_cmd_linux, + 0, N_("Load Linux.")); + cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, + 0, N_("Load initrd.")); + my_mod = mod; +} + +GRUB_MOD_FINI(linux) +{ + grub_unregister_command (cmd_linux); + grub_unregister_command (cmd_initrd); +} diff --git a/loader/multiboot.c b/loader/multiboot.c new file mode 100644 index 000000000..592289c45 --- /dev/null +++ b/loader/multiboot.c @@ -0,0 +1,356 @@ +/* multiboot.c - boot a multiboot OS image. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,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 . + */ + +/* + * FIXME: The following features from the Multiboot specification still + * need to be implemented: + * - VBE support + * - symbol table + * - drives table + * - ROM configuration table + * - APM table + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef GRUB_MACHINE_EFI +#include +#endif + +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) +#define DEFAULT_VIDEO_MODE "text" +#else +#define DEFAULT_VIDEO_MODE "auto" +#endif + +grub_size_t grub_multiboot_alloc_mbi; + +char *grub_multiboot_payload_orig; +grub_addr_t grub_multiboot_payload_dest; +grub_size_t grub_multiboot_pure_size; +grub_uint32_t grub_multiboot_payload_eip; +static int accepts_video; +static int accepts_ega_text; +static int console_required; +static grub_dl_t my_mod; + + +/* Return the length of the Multiboot mmap that will be needed to allocate + our platform's map. */ +grub_uint32_t +grub_get_multiboot_mmap_count (void) +{ + grub_size_t count = 0; + + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + grub_uint32_t type __attribute__ ((unused))) + { + count++; + return 0; + } + + grub_mmap_iterate (hook); + + return count; +} + +grub_err_t +grub_multiboot_set_video_mode (void) +{ + grub_err_t err; + const char *modevar; + + if (accepts_video || !GRUB_MACHINE_HAS_VGA_TEXT) + { + modevar = grub_env_get ("gfxpayload"); + if (! modevar || *modevar == 0) + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); + else + { + char *tmp; + tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); + if (! tmp) + return grub_errno; + err = grub_video_set_mode (tmp, 0, 0); + grub_free (tmp); + } + } + else + err = grub_video_set_mode ("text", 0, 0); + + return err; +} + +static grub_err_t +grub_multiboot_boot (void) +{ + grub_size_t mbi_size; + grub_err_t err; + struct grub_relocator32_state state = MULTIBOOT_INITIAL_STATE; + + state.MULTIBOOT_ENTRY_REGISTER = grub_multiboot_payload_eip; + + mbi_size = grub_multiboot_get_mbi_size (); + if (grub_multiboot_alloc_mbi < mbi_size) + { + grub_multiboot_payload_orig + = grub_relocator32_realloc (grub_multiboot_payload_orig, + grub_multiboot_pure_size + mbi_size); + if (!grub_multiboot_payload_orig) + return grub_errno; + grub_multiboot_alloc_mbi = mbi_size; + } + + state.MULTIBOOT_MBI_REGISTER = grub_multiboot_payload_dest + + grub_multiboot_pure_size; + err = grub_multiboot_make_mbi (grub_multiboot_payload_orig, + grub_multiboot_payload_dest, + grub_multiboot_pure_size, mbi_size); + if (err) + return err; + +#ifdef GRUB_MACHINE_EFI + if (! grub_efi_finish_boot_services ()) + grub_fatal ("cannot exit boot services"); +#endif + + grub_relocator32_boot (grub_multiboot_payload_orig, + grub_multiboot_payload_dest, + state); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_multiboot_unload (void) +{ + grub_multiboot_free_mbi (); + + grub_relocator32_free (grub_multiboot_payload_orig); + + grub_multiboot_alloc_mbi = 0; + + grub_multiboot_payload_orig = NULL; + grub_dl_unref (my_mod); + + return GRUB_ERR_NONE; +} + +#define MULTIBOOT_LOAD_ELF64 +#include "multiboot_elfxx.c" +#undef MULTIBOOT_LOAD_ELF64 + +#define MULTIBOOT_LOAD_ELF32 +#include "multiboot_elfxx.c" +#undef MULTIBOOT_LOAD_ELF32 + +/* Load ELF32 or ELF64. */ +grub_err_t +grub_multiboot_load_elf (grub_file_t file, void *buffer) +{ + if (grub_multiboot_is_elf32 (buffer)) + return grub_multiboot_load_elf32 (file, buffer); + else if (grub_multiboot_is_elf64 (buffer)) + return grub_multiboot_load_elf64 (file, buffer); + + return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class"); +} + +grub_err_t +grub_multiboot_set_console (int console_type, int accepted_consoles, + int width, int height, int depth, + int console_req) +{ + console_required = console_req; + if (!(accepted_consoles + & (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER + | (GRUB_MACHINE_HAS_VGA_TEXT ? GRUB_MULTIBOOT_CONSOLE_EGA_TEXT : 0)))) + { + if (console_required) + return grub_error (GRUB_ERR_BAD_OS, + "OS requires a console but none is available"); + grub_printf ("WARNING: no console will be available to OS"); + accepts_video = 0; + accepts_ega_text = 0; + return GRUB_ERR_NONE; + } + + if (console_type == GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER) + { + char *buf; + if (depth && width && height) + buf = grub_xasprintf ("%dx%dx%d,%dx%d,auto", width, + height, depth, width, height); + else if (width && height) + buf = grub_xasprintf ("%dx%d,auto", width, height); + else + buf = grub_strdup ("auto"); + + if (!buf) + return grub_errno; + grub_env_set ("gfxpayload", buf); + grub_free (buf); + } + else + grub_env_set ("gfxpayload", "text"); + + accepts_video = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER); + accepts_ega_text = !!(accepted_consoles & GRUB_MULTIBOOT_CONSOLE_EGA_TEXT); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_err_t err; + + grub_loader_unset (); + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); + + file = grub_gzfile_open (argv[0], 1); + if (! file) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file"); + + grub_dl_ref (my_mod); + + /* Skip filename. */ + grub_multiboot_init_mbi (argc - 1, argv + 1); + + grub_relocator32_free (grub_multiboot_payload_orig); + grub_multiboot_payload_orig = NULL; + + err = grub_multiboot_load (file); + if (err) + goto fail; + + grub_multiboot_set_bootdev (); + + grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0); + + fail: + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + { + grub_relocator32_free (grub_multiboot_payload_orig); + grub_multiboot_free_mbi (); + grub_dl_unref (my_mod); + } + + return grub_errno; +} + +static grub_err_t +grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_ssize_t size; + char *module = 0; + grub_err_t err; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); + + if (!grub_multiboot_payload_orig) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "you need to load the multiboot kernel first"); + + file = grub_gzfile_open (argv[0], 1); + if (! file) + return grub_errno; + + size = grub_file_size (file); + module = grub_memalign (MULTIBOOT_MOD_ALIGN, size); + if (! module) + { + grub_file_close (file); + return grub_errno; + } + + err = grub_multiboot_add_module ((grub_addr_t) module, size, + argc - 1, argv + 1); + if (err) + { + grub_file_close (file); + return err; + } + + if (grub_file_read (file, module, size) != size) + { + grub_file_close (file); + return grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); + } + + grub_file_close (file); + return GRUB_ERR_NONE;; +} + +static grub_command_t cmd_multiboot, cmd_module; + +GRUB_MOD_INIT(multiboot) +{ + cmd_multiboot = +#ifdef GRUB_USE_MULTIBOOT2 + grub_register_command ("multiboot2", grub_cmd_multiboot, + 0, N_("Load a multiboot 2 kernel.")); + cmd_module = + grub_register_command ("module2", grub_cmd_module, + 0, N_("Load a multiboot 2 module.")); +#else + grub_register_command ("multiboot", grub_cmd_multiboot, + 0, N_("Load a multiboot kernel.")); + cmd_module = + grub_register_command ("module", grub_cmd_module, + 0, N_("Load a multiboot module.")); +#endif + + my_mod = mod; +} + +GRUB_MOD_FINI(multiboot) +{ + grub_unregister_command (cmd_multiboot); + grub_unregister_command (cmd_module); +} diff --git a/loader/multiboot2.c b/loader/multiboot2.c deleted file mode 100644 index 976285b85..000000000 --- a/loader/multiboot2.c +++ /dev/null @@ -1,460 +0,0 @@ -/* multiboot2.c - boot a multiboot 2 OS image. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static grub_addr_t entry; -extern grub_dl_t my_mod; - -static char *grub_mb2_tags; -static char *grub_mb2_tags_pos; -static grub_size_t grub_mb2_tags_len; -static int grub_mb2_tags_count; - -static void -grub_mb2_tags_free (void) -{ - grub_dprintf ("loader", "Freeing all tags...\n"); - grub_free (grub_mb2_tags); - grub_mb2_tags = 0; - grub_mb2_tags_pos = 0; - grub_mb2_tags_len = 0; - grub_mb2_tags_count = 0; -} - -grub_err_t -grub_mb2_tag_alloc (grub_addr_t *addr, int key, grub_size_t len) -{ - struct multiboot2_tag_header *tag; - grub_size_t used; - grub_size_t needed; - - grub_dprintf ("loader", "Allocating tag: key 0x%x, size 0x%lx.\n", - key, (unsigned long) len); - - used = grub_mb2_tags_pos - grub_mb2_tags; - len = ALIGN_UP (len, sizeof (multiboot2_word)); - - needed = used + len; - - if (needed > grub_mb2_tags_len) - { - /* Allocate new buffer. */ - grub_size_t newsize = needed * 2; - char *newarea; - - grub_dprintf ("loader", "Reallocating tag buffer (new size 0x%lx).\n", - (unsigned long) newsize); - - newarea = grub_malloc (newsize); - if (! newarea) - return grub_errno; - grub_memcpy (newarea, grub_mb2_tags, grub_mb2_tags_len); - grub_free (grub_mb2_tags); - - grub_mb2_tags_len = newsize; - grub_mb2_tags = newarea; - grub_mb2_tags_pos = newarea + used; - } - - tag = (struct multiboot2_tag_header *) grub_mb2_tags_pos; - grub_mb2_tags_pos += len; - - tag->key = key; - tag->len = len; - - if (addr) - *addr = (grub_addr_t) tag; - - grub_mb2_tags_count++; - - grub_dprintf ("loader", "Allocated tag %u at %p.\n", grub_mb2_tags_count, tag); - - return 0; -} - -static grub_err_t -grub_mb2_tag_start_create (void) -{ - return grub_mb2_tag_alloc (0, MULTIBOOT2_TAG_START, - sizeof (struct multiboot2_tag_start)); -} - -static grub_err_t -grub_mb2_tag_name_create (void) -{ - struct multiboot2_tag_name *name; - grub_addr_t name_addr; - grub_err_t err; - const char *grub_version = PACKAGE_STRING; - - err = grub_mb2_tag_alloc (&name_addr, MULTIBOOT2_TAG_NAME, - sizeof (struct multiboot2_tag_name) + - sizeof (grub_version) + 1); - if (err) - return err; - - name = (struct multiboot2_tag_name *) name_addr; - grub_strcpy (name->name, grub_version); - - return GRUB_ERR_NONE; -} - -typedef grub_err_t (*tag_create_t) (void); -static tag_create_t grub_mb2_tag_creators[] = { - grub_mb2_tag_start_create, - grub_mb2_tag_name_create, - grub_mb2_tags_arch_create, - 0, -}; - -static grub_err_t -grub_mb2_tags_create (void) -{ - tag_create_t *creator; - grub_err_t err; - - for (creator = grub_mb2_tag_creators; *creator != 0; creator++) - { - err = (*creator) (); - if (err) - goto error; - } - - return GRUB_ERR_NONE; - -error: - grub_error_push (); - grub_mb2_tags_free (); - grub_error_pop (); - return err; -} - -static grub_err_t -grub_mb2_tags_finish (void) -{ - struct multiboot2_tag_start *start; - grub_err_t err; - - /* Create the `end' tag. */ - err = grub_mb2_tag_alloc (0, MULTIBOOT2_TAG_END, - sizeof (struct multiboot2_tag_end)); - if (err) - goto error; - - /* We created the `start' tag first. Update it now. */ - start = (struct multiboot2_tag_start *) grub_mb2_tags; - start->size = grub_mb2_tags_pos - grub_mb2_tags; - return GRUB_ERR_NONE; - -error: - grub_error_push (); - grub_mb2_tags_free (); - grub_error_pop (); - return err; -} - -static grub_err_t -grub_mb2_boot (void) -{ - grub_mb2_tags_finish (); - - grub_dprintf ("loader", "Tags at %p\n", grub_mb2_tags); - grub_mb2_arch_boot (entry, grub_mb2_tags); - - /* Not reached. */ - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_mb2_unload (void) -{ - struct multiboot2_tag_header *tag; - struct multiboot2_tag_header *tags = - (struct multiboot2_tag_header *) grub_mb2_tags; - - /* Free all module memory in the tag list. */ - for_each_tag (tag, tags) - { - if (tag->key == MULTIBOOT2_TAG_MODULE) - { - struct multiboot2_tag_module *module = - (struct multiboot2_tag_module *) tag; - grub_free ((void *) module->addr); - } - } - - /* Allow architecture to un-reserve memory. */ - grub_mb2_arch_unload (tags); - - /* Free the tags themselves. */ - grub_mb2_tags_free (); - - grub_dl_unref (my_mod); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_mb2_load_other (UNUSED grub_file_t file, UNUSED void *buffer) -{ - /* XXX Create module tag here. */ - return grub_error (GRUB_ERR_UNKNOWN_OS, "currently only ELF is supported"); -} - -/* Create the tag containing the cmdline and the address of the module data. */ -static grub_err_t -grub_mb2_tag_module_create (grub_addr_t modaddr, grub_size_t modsize, - char *type, int key, int argc, char *argv[]) -{ - struct multiboot2_tag_module *module; - grub_ssize_t argslen = 0; - grub_err_t err; - char *p; - grub_addr_t module_addr; - int i; - - /* Allocate enough space for the arguments and spaces between them. */ - for (i = 0; i < argc; i++) - argslen += grub_strlen (argv[i]) + 1; - - /* Note: includes implicit 1-byte cmdline. */ - err = grub_mb2_tag_alloc (&module_addr, key, - sizeof (struct multiboot2_tag_module) + argslen); - if (err) - return grub_errno; - - module = (struct multiboot2_tag_module *) module_addr; - module->addr = modaddr; - module->size = modsize; - grub_strcpy(module->type, type); - - /* Fill in the command line. */ - p = module->cmdline; - for (i = 0; i < argc; i++) - { - p = grub_stpcpy (p, argv[i]); - *p++ = ' '; - } - module->cmdline[argslen] = '\0'; - - return GRUB_ERR_NONE; -} - -/* Load ELF32 or ELF64. */ -static grub_err_t -grub_mb2_load_elf (grub_elf_t elf, int argc, char *argv[]) -{ - grub_addr_t kern_base; - grub_size_t kern_size; - grub_err_t err; - - if (grub_elf_is_elf32 (elf)) - { - entry = elf->ehdr.ehdr32.e_entry; - err = grub_elf32_load (elf, grub_mb2_arch_elf32_hook, &kern_base, - &kern_size); - } - else if (grub_elf_is_elf64 (elf)) - { - entry = elf->ehdr.ehdr64.e_entry; - err = grub_elf64_load (elf, grub_mb2_arch_elf64_hook, &kern_base, - &kern_size); - } - else - err = grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class"); - - if (err) - goto fail; - - grub_dprintf ("loader", "Entry point is 0x%lx.\n", (unsigned long) entry); - - grub_mb2_tag_module_create (kern_base, kern_size, "kernel", - MULTIBOOT2_TAG_MODULE, argc, argv); - -fail: - return err; -} - -void -grub_multiboot2 (int argc, char *argv[]) -{ - char *buffer; - grub_file_t file = 0; - grub_elf_t elf = 0; - struct multiboot2_header *header = 0; - char *p; - grub_ssize_t len; - grub_err_t err; - int header_found = 0; - - grub_loader_unset (); - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified"); - goto fail; - } - - file = grub_gzfile_open (argv[0], 1); - if (! file) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file"); - goto fail; - } - - buffer = grub_malloc (MULTIBOOT2_HEADER_SEARCH); - if (! buffer) - return; - - len = grub_file_read (file, buffer, MULTIBOOT2_HEADER_SEARCH); - if (len < 32) - { - grub_error (GRUB_ERR_BAD_OS, "File too small"); - goto fail; - } - - /* Look for the multiboot header in the buffer. The header should - be at least 8 bytes and aligned on a 8-byte boundary. */ - for (p = buffer; p <= buffer + len - 8; p += 8) - { - header = (struct multiboot2_header *) p; - if (header->magic == MULTIBOOT2_HEADER_MAGIC) - { - header_found = 1; - break; - } - } - - if (! header_found) - grub_dprintf ("loader", "No multiboot 2 header found.\n"); - - - /* Create the basic tags. */ - grub_dprintf ("loader", "Creating multiboot 2 tags\n"); - grub_mb2_tags_create (); - - /* Load the kernel and create its tag. */ - elf = grub_elf_file (file); - if (elf) - { - grub_dprintf ("loader", "Loading ELF multiboot 2 file.\n"); - err = grub_mb2_load_elf (elf, argc-1, &argv[1]); - grub_elf_close (elf); - } - else - { - grub_errno = 0; - grub_dprintf ("loader", "Loading non-ELF multiboot 2 file.\n"); - - if (header) - err = grub_mb2_load_other (file, header); - else - err = grub_error (GRUB_ERR_BAD_OS, - "Need multiboot 2 header to load non-ELF files."); - grub_file_close (file); - } - - grub_free (buffer); - - if (err) - goto fail; - - /* Good to go. */ - grub_loader_set (grub_mb2_boot, grub_mb2_unload, 1); - return; - -fail: - grub_mb2_tags_free (); - grub_dl_unref (my_mod); -} - -void -grub_module2 (int argc, char *argv[]) -{ - grub_file_t file; - grub_addr_t modaddr = 0; - grub_ssize_t modsize = 0; - grub_err_t err; - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); - return; - } - - if (argc == 1) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No module type specified"); - return; - } - - if (entry == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, - "You need to load the multiboot kernel first"); - return; - } - - /* Load module data. */ - file = grub_gzfile_open (argv[0], 1); - if (! file) - goto out; - - modsize = grub_file_size (file); - err = grub_mb2_arch_module_alloc (modsize, &modaddr); - if (err) - goto out; - - grub_dprintf ("loader", "Loading module at 0x%x - 0x%x\n", modaddr, - modaddr + modsize); - if (grub_file_read (file, (void *) modaddr, modsize) != modsize) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); - goto out; - } - - /* Create the module tag. */ - err = grub_mb2_tag_module_create (modaddr, modsize, - argv[1], MULTIBOOT2_TAG_MODULE, - argc-2, &argv[2]); - if (err) - goto out; - -out: - grub_error_push (); - - if (file) - grub_file_close (file); - - if (modaddr) - grub_mb2_arch_module_free (modaddr, modsize); - - grub_error_pop (); -} diff --git a/loader/i386/multiboot_elfxx.c b/loader/multiboot_elfxx.c similarity index 89% rename from loader/i386/multiboot_elfxx.c rename to loader/multiboot_elfxx.c index 77c47118c..92a52d3a8 100644 --- a/loader/i386/multiboot_elfxx.c +++ b/loader/multiboot_elfxx.c @@ -18,13 +18,13 @@ #if defined(MULTIBOOT_LOAD_ELF32) # define XX 32 -# define E_MACHINE EM_386 +# define E_MACHINE MULTIBOOT_ELF32_MACHINE # define ELFCLASSXX ELFCLASS32 # define Elf_Ehdr Elf32_Ehdr # define Elf_Phdr Elf32_Phdr #elif defined(MULTIBOOT_LOAD_ELF64) # define XX 64 -# define E_MACHINE EM_X86_64 +# define E_MACHINE MULTIBOOT_ELF64_MACHINE # define ELFCLASSXX ELFCLASS64 # define Elf_Ehdr Elf64_Ehdr # define Elf_Phdr Elf64_Phdr @@ -32,6 +32,8 @@ #error "I'm confused" #endif +#include + #define CONCAT(a,b) CONCAT_(a, b) #define CONCAT_(a,b) a ## b @@ -51,6 +53,7 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) char *phdr_base; int lowest_segment = -1, highest_segment = -1; int i; + grub_size_t code_size; if (ehdr->e_ident[EI_CLASS] != ELFCLASSXX) return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class"); @@ -98,12 +101,14 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) code_size = (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr; grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr; - grub_multiboot_payload_size += code_size; - playground = grub_malloc (RELOCATOR_SIZEOF(forward) + grub_multiboot_payload_size + RELOCATOR_SIZEOF(backward)); - if (! playground) - return grub_errno; + grub_multiboot_pure_size += code_size; - grub_multiboot_payload_orig = (long) playground + RELOCATOR_SIZEOF(forward); + grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; + grub_multiboot_payload_orig + = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); + + if (!grub_multiboot_payload_orig) + return grub_errno; /* Load every loadable segment in memory. */ for (i = 0; i < ehdr->e_phnum; i++) @@ -135,8 +140,8 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) if (phdr(i)->p_vaddr <= ehdr->e_entry && phdr(i)->p_vaddr + phdr(i)->p_memsz > ehdr->e_entry) { - grub_multiboot_payload_entry_offset = (ehdr->e_entry - phdr(i)->p_vaddr) - + (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr); + grub_multiboot_payload_eip = grub_multiboot_payload_dest + + (ehdr->e_entry - phdr(i)->p_vaddr) + (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr); break; } diff --git a/loader/multiboot_loader.c b/loader/multiboot_loader.c deleted file mode 100644 index 9078d0622..000000000 --- a/loader/multiboot_loader.c +++ /dev/null @@ -1,212 +0,0 @@ -/* multiboot_loader.c - boot multiboot 1 or 2 OS image */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007,2008 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -grub_dl_t my_mod; - -/* This tracks which version of multiboot to use when using - * the module command. By default use multiboot version 1. - * values: - * 1 - Multiboot version 1 - * 2 - Multiboot version 2 - */ - -static unsigned int module_version_status = 1; - -static int -find_multi_boot1_header (grub_file_t file) -{ - struct multiboot_header *header; - char buffer[MULTIBOOT_SEARCH]; - int found_status = 0; - grub_ssize_t len; - - len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); - if (len < 32) - return found_status; - - /* Look for the multiboot header in the buffer. The header should - be at least 12 bytes and aligned on a 4-byte boundary. */ - for (header = (struct multiboot_header *) buffer; - ((char *) header <= buffer + len - 12) || (header = 0); - header = (struct multiboot_header *) ((char *) header + 4)) - { - if (header->magic == MULTIBOOT_MAGIC - && !(header->magic + header->flags + header->checksum)) - { - found_status = 1; - break; - } - } - - return found_status; -} - -static int -find_multi_boot2_header (grub_file_t file) -{ - struct multiboot_header *header; - char buffer[MULTIBOOT_SEARCH]; - int found_status = 0; - grub_ssize_t len; - - len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); - if (len < 32) - return found_status; - - /* Look for the multiboot header in the buffer. The header should - be at least 8 bytes and aligned on a 8-byte boundary. */ - for (header = (struct multiboot_header *) buffer; - ((char *) header <= buffer + len - 8) || (header = 0); - header = (struct multiboot_header *) ((char *) header + 8)) - { - if (header->magic == MULTIBOOT2_HEADER_MAGIC) - { - found_status = 1; - break; - } - } - - return found_status; -} - -static grub_err_t -grub_cmd_multiboot_loader (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - grub_file_t file = 0; - int header_multi_ver_found = 0; - - grub_dl_ref (my_mod); - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified"); - goto fail; - } - - file = grub_gzfile_open (argv[0], 1); - if (! file) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file"); - goto fail; - } - - /* find which header is in the file */ - if (find_multi_boot1_header (file)) - header_multi_ver_found = 1; - else if (find_multi_boot2_header (file)) - header_multi_ver_found = 2; - else - { - grub_error (GRUB_ERR_BAD_OS, "Multiboot header not found"); - goto fail; - } - - /* close file before calling functions */ - if (file) - grub_file_close (file); - - /* Launch multi boot with header */ - - /* XXX Find a better way to identify this. - This is for i386-pc */ -#if defined(GRUB_MACHINE_PCBIOS) || defined(GRUB_MACHINE_COREBOOT) || \ - defined(GRUB_MACHINE_QEMU) - if (header_multi_ver_found == 1) - { - grub_dprintf ("multiboot_loader", - "Launching multiboot 1 grub_multiboot() function\n"); - grub_multiboot (argc, argv); - module_version_status = 1; - } -#endif - if (header_multi_ver_found == 0 || header_multi_ver_found == 2) - { - grub_dprintf ("multiboot_loader", - "Launching multiboot 2 grub_multiboot2() function\n"); - grub_multiboot2 (argc, argv); - module_version_status = 2; - } - - return grub_errno; - -fail: - if (file) - grub_file_close (file); - - grub_dl_unref (my_mod); - - return grub_errno; -} - -static grub_err_t -grub_cmd_module_loader (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - -#if defined(GRUB_MACHINE_PCBIOS) || defined(GRUB_MACHINE_COREBOOT) || \ - defined(GRUB_MACHINE_QEMU) - if (module_version_status == 1) - { - grub_dprintf("multiboot_loader", - "Launching multiboot 1 grub_module() function\n"); - grub_module (argc, argv); - } -#endif - if (module_version_status == 2) - { - grub_dprintf("multiboot_loader", - "Launching multiboot 2 grub_module2() function\n"); - grub_module2 (argc, argv); - } - - return grub_errno; -} - -static grub_command_t cmd_multiboot, cmd_module; - -GRUB_MOD_INIT(multiboot) -{ - cmd_multiboot = - grub_register_command ("multiboot", grub_cmd_multiboot_loader, - 0, "load a multiboot kernel"); - cmd_module = - grub_register_command ("module", grub_cmd_module_loader, - 0, "load a multiboot module"); - - my_mod = mod; -} - -GRUB_MOD_FINI(multiboot) -{ - grub_unregister_command (cmd_multiboot); - grub_unregister_command (cmd_module); -} diff --git a/loader/multiboot_mbi2.c b/loader/multiboot_mbi2.c new file mode 100644 index 000000000..7e9cebe49 --- /dev/null +++ b/loader/multiboot_mbi2.c @@ -0,0 +1,701 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009 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 . + */ + +#include +#include +#ifdef GRUB_MACHINE_PCBIOS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_QEMU) +#include +#define HAS_VGA_TEXT 1 +#else +#define HAS_VGA_TEXT 0 +#endif + +struct module +{ + struct module *next; + grub_addr_t start; + grub_size_t size; + char *cmdline; + int cmdline_size; +}; + +struct module *modules, *modules_last; +static grub_size_t cmdline_size; +static grub_size_t total_modcmd; +static unsigned modcnt; +static char *cmdline = NULL; +static int bootdev_set; +static grub_uint32_t biosdev, slice, part; + +grub_err_t +grub_multiboot_load (grub_file_t file) +{ + char *buffer; + grub_ssize_t len; + struct multiboot_header *header; + grub_err_t err; + struct multiboot_header_tag *tag; + struct multiboot_header_tag_address *addr_tag = NULL; + int entry_specified = 0; + grub_addr_t entry = 0; + grub_uint32_t console_required = 0; + struct multiboot_header_tag_framebuffer *fbtag = NULL; + int accepted_consoles = GRUB_MULTIBOOT_CONSOLE_EGA_TEXT; + + buffer = grub_malloc (MULTIBOOT_SEARCH); + if (!buffer) + return grub_errno; + + len = grub_file_read (file, buffer, MULTIBOOT_SEARCH); + if (len < 32) + { + grub_free (buffer); + return grub_error (GRUB_ERR_BAD_OS, "file too small"); + } + + /* Look for the multiboot header in the buffer. The header should + be at least 12 bytes and aligned on a 4-byte boundary. */ + for (header = (struct multiboot_header *) buffer; + ((char *) header <= buffer + len - 12) || (header = 0); + header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN)) + { + if (header->magic == MULTIBOOT_HEADER_MAGIC + && !(header->magic + header->architecture + + header->header_length + header->checksum) + && header->architecture == MULTIBOOT_ARCHITECTURE_CURRENT) + break; + } + + if (header == 0) + { + grub_free (buffer); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); + } + + for (tag = (struct multiboot_header_tag *) (header + 1); + tag->type != MULTIBOOT_TAG_TYPE_END; + tag = (struct multiboot_header_tag *) ((char *) tag + tag->size)) + switch (tag->type) + { + case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST: + { + unsigned i; + struct multiboot_header_tag_information_request *request_tag + = (struct multiboot_header_tag_information_request *) tag; + if (request_tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL) + break; + for (i = 0; i < (request_tag->size - sizeof (request_tag)) + / sizeof (request_tag->requests[0]); i++) + switch (request_tag->requests[i]) + { + case MULTIBOOT_TAG_TYPE_END: + case MULTIBOOT_TAG_TYPE_CMDLINE: + case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: + case MULTIBOOT_TAG_TYPE_MODULE: + case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: + case MULTIBOOT_TAG_TYPE_BOOTDEV: + case MULTIBOOT_TAG_TYPE_MMAP: + case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: + break; + + case MULTIBOOT_TAG_TYPE_VBE: + case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: + case MULTIBOOT_TAG_TYPE_APM: + default: + grub_free (buffer); + return grub_error (GRUB_ERR_UNKNOWN_OS, + "unsupported information tag: 0x%x", + request_tag->requests[i]); + } + break; + } + + case MULTIBOOT_HEADER_TAG_ADDRESS: + addr_tag = (struct multiboot_header_tag_address *) tag; + break; + + case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS: + entry_specified = 1; + entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr; + break; + + case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS: + if (!(((struct multiboot_header_tag_console_flags *) tag)->console_flags + & MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED)) + accepted_consoles &= ~GRUB_MULTIBOOT_CONSOLE_EGA_TEXT; + if (((struct multiboot_header_tag_console_flags *) tag)->console_flags + & MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED) + console_required = 1; + break; + + case MULTIBOOT_HEADER_TAG_FRAMEBUFFER: + fbtag = (struct multiboot_header_tag_framebuffer *) tag; + accepted_consoles |= GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER; + break; + + /* GRUB always page-aligns modules. */ + case MULTIBOOT_HEADER_TAG_MODULE_ALIGN: + break; + + default: + if (! (tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL)) + { + grub_free (buffer); + return grub_error (GRUB_ERR_UNKNOWN_OS, + "unsupported tag: 0x%x", tag->type); + } + break; + } + + if (addr_tag && !entry_specified) + { + grub_free (buffer); + return grub_error (GRUB_ERR_UNKNOWN_OS, + "load address tag without entry address tag"); + } + + if (addr_tag) + { + int offset = ((char *) header - buffer - + (addr_tag->header_addr - addr_tag->load_addr)); + int load_size = ((addr_tag->load_end_addr == 0) ? file->size - offset : + addr_tag->load_end_addr - addr_tag->load_addr); + grub_size_t code_size; + + if (addr_tag->bss_end_addr) + code_size = (addr_tag->bss_end_addr - addr_tag->load_addr); + else + code_size = load_size; + grub_multiboot_payload_dest = addr_tag->load_addr; + + grub_multiboot_pure_size += code_size; + + /* Allocate a bit more to avoid relocations in most cases. */ + grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; + grub_multiboot_payload_orig + = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); + + if (! grub_multiboot_payload_orig) + { + grub_free (buffer); + return grub_errno; + } + + if ((grub_file_seek (file, offset)) == (grub_off_t) -1) + { + grub_free (buffer); + return grub_errno; + } + + grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); + if (grub_errno) + { + grub_free (buffer); + return grub_errno; + } + + if (addr_tag->bss_end_addr) + grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, + addr_tag->bss_end_addr - addr_tag->load_addr - load_size); + } + else + { + err = grub_multiboot_load_elf (file, buffer); + if (err) + { + grub_free (buffer); + return err; + } + } + + if (entry_specified) + grub_multiboot_payload_eip = entry; + + if (fbtag) + err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER, + accepted_consoles, + fbtag->width, fbtag->height, + fbtag->depth, console_required); + else + err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, + accepted_consoles, + 0, 0, 0, console_required); + return err; +} + +grub_size_t +grub_multiboot_get_mbi_size (void) +{ + return 2 * sizeof (grub_uint32_t) + sizeof (struct multiboot_tag) + + (sizeof (struct multiboot_tag_string) + + ALIGN_UP (cmdline_size, MULTIBOOT_TAG_ALIGN)) + + (sizeof (struct multiboot_tag_string) + + ALIGN_UP (sizeof (PACKAGE_STRING), MULTIBOOT_TAG_ALIGN)) + + (modcnt * sizeof (struct multiboot_tag_module) + total_modcmd) + + sizeof (struct multiboot_tag_basic_meminfo) + + ALIGN_UP (sizeof (struct multiboot_tag_bootdev), MULTIBOOT_TAG_ALIGN) + + (sizeof (struct multiboot_tag_mmap) + grub_get_multiboot_mmap_count () + * sizeof (struct multiboot_mmap_entry)) + + sizeof (struct multiboot_tag_vbe) + MULTIBOOT_TAG_ALIGN - 1; +} + +/* Fill previously allocated Multiboot mmap. */ +static void +grub_fill_multiboot_mmap (struct multiboot_tag_mmap *tag) +{ + struct multiboot_mmap_entry *mmap_entry = tag->entries; + + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + { + mmap_entry->addr = addr; + mmap_entry->len = size; + switch (type) + { + case GRUB_MACHINE_MEMORY_AVAILABLE: + mmap_entry->type = MULTIBOOT_MEMORY_AVAILABLE; + break; + +#ifdef GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE + case GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE: + mmap_entry->type = MULTIBOOT_MEMORY_ACPI_RECLAIMABLE; + break; +#endif + +#ifdef GRUB_MACHINE_MEMORY_NVS + case GRUB_MACHINE_MEMORY_NVS: + mmap_entry->type = MULTIBOOT_MEMORY_NVS; + break; +#endif + + default: + mmap_entry->type = MULTIBOOT_MEMORY_RESERVED; + break; + } + mmap_entry++; + + return 0; + } + + tag->type = MULTIBOOT_TAG_TYPE_MMAP; + tag->size = sizeof (struct multiboot_tag_mmap) + + sizeof (struct multiboot_mmap_entry) * grub_get_multiboot_mmap_count (); + tag->entry_size = sizeof (struct multiboot_mmap_entry); + tag->entry_version = 0; + + grub_mmap_iterate (hook); +} + +static grub_err_t +retrieve_video_parameters (grub_uint8_t **ptrorig) +{ + grub_err_t err; + struct grub_video_mode_info mode_info; + void *framebuffer; + grub_video_driver_id_t driv_id; + struct grub_video_palette_data palette[256]; + struct multiboot_tag_framebuffer *tag + = (struct multiboot_tag_framebuffer *) *ptrorig; + + err = grub_multiboot_set_video_mode (); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + + grub_video_get_palette (0, ARRAY_SIZE (palette), palette); + + driv_id = grub_video_get_driver_id (); +#if HAS_VGA_TEXT + if (driv_id == GRUB_VIDEO_DRIVER_NONE) + { + struct grub_vbe_mode_info_block vbe_mode_info; + grub_uint32_t vbe_mode; + +#if defined (GRUB_MACHINE_PCBIOS) + { + grub_vbe_status_t status; + void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + status = grub_vbe_bios_get_mode (scratch); + vbe_mode = *(grub_uint32_t *) scratch; + if (status != GRUB_VBE_STATUS_OK) + return GRUB_ERR_NONE; + } +#else + vbe_mode = 3; +#endif + + /* get_mode_info isn't available for mode 3. */ + if (vbe_mode == 3) + { + grub_memset (&vbe_mode_info, 0, + sizeof (struct grub_vbe_mode_info_block)); + vbe_mode_info.memory_model = GRUB_VBE_MEMORY_MODEL_TEXT; + vbe_mode_info.x_resolution = 80; + vbe_mode_info.y_resolution = 25; + } +#if defined (GRUB_MACHINE_PCBIOS) + else + { + grub_vbe_status_t status; + void *scratch = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + status = grub_vbe_bios_get_mode_info (vbe_mode, scratch); + if (status != GRUB_VBE_STATUS_OK) + return GRUB_ERR_NONE; + grub_memcpy (&vbe_mode_info, scratch, + sizeof (struct grub_vbe_mode_info_block)); + } +#endif + + if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_TEXT) + { + tag = (struct multiboot_tag_framebuffer *) *ptrorig; + tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + tag->common.size = 0; + + tag->common.framebuffer_addr = 0xb8000; + + tag->common.framebuffer_pitch = 2 * vbe_mode_info.x_resolution; + tag->common.framebuffer_width = vbe_mode_info.x_resolution; + tag->common.framebuffer_height = vbe_mode_info.y_resolution; + + tag->common.framebuffer_bpp = 16; + + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; + tag->common.size = sizeof (tag->common); + tag->common.reserved = 0; + *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN); + } + return GRUB_ERR_NONE; + } +#else + if (driv_id == GRUB_VIDEO_DRIVER_NONE) + return GRUB_ERR_NONE; +#endif + + err = grub_video_get_info_and_fini (&mode_info, &framebuffer); + if (err) + return err; + + tag = (struct multiboot_tag_framebuffer *) *ptrorig; + tag->common.type = MULTIBOOT_TAG_TYPE_FRAMEBUFFER; + tag->common.size = 0; + + tag->common.framebuffer_addr = (grub_addr_t) framebuffer; + tag->common.framebuffer_pitch = mode_info.pitch; + + tag->common.framebuffer_width = mode_info.width; + tag->common.framebuffer_height = mode_info.height; + + tag->common.framebuffer_bpp = mode_info.bpp; + + tag->common.reserved = 0; + + if (mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) + { + unsigned i; + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED; + tag->framebuffer_palette_num_colors = mode_info.number_of_colors; + if (tag->framebuffer_palette_num_colors > ARRAY_SIZE (palette)) + tag->framebuffer_palette_num_colors = ARRAY_SIZE (palette); + tag->common.size = sizeof (struct multiboot_tag_framebuffer_common) + + sizeof (multiboot_uint16_t) + tag->framebuffer_palette_num_colors + * sizeof (struct multiboot_color); + for (i = 0; i < tag->framebuffer_palette_num_colors; i++) + { + tag->framebuffer_palette[i].red = palette[i].r; + tag->framebuffer_palette[i].green = palette[i].g; + tag->framebuffer_palette[i].blue = palette[i].b; + } + } + else + { + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_RGB; + tag->framebuffer_red_field_position = mode_info.green_field_pos; + tag->framebuffer_red_mask_size = mode_info.green_mask_size; + tag->framebuffer_green_field_position = mode_info.green_field_pos; + tag->framebuffer_green_mask_size = mode_info.green_mask_size; + tag->framebuffer_blue_field_position = mode_info.blue_field_pos; + tag->framebuffer_blue_mask_size = mode_info.blue_mask_size; + + tag->common.size = sizeof (struct multiboot_tag_framebuffer_common) + 6; + } + *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN); + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, + grub_size_t bufsize) +{ + grub_uint8_t *ptrorig; + grub_uint8_t *mbistart = (grub_uint8_t *) orig + buf_off + + (ALIGN_UP (dest + buf_off, MULTIBOOT_TAG_ALIGN) - (dest + buf_off)); + grub_err_t err; + + if (bufsize < grub_multiboot_get_mbi_size ()) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + + ptrorig = mbistart + 2 * sizeof (grub_uint32_t); + + { + struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_CMDLINE; + tag->size = sizeof (struct multiboot_tag_string) + cmdline_size; + grub_memcpy (tag->string, cmdline, cmdline_size); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + { + struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME; + tag->size = sizeof (struct multiboot_tag_string) + sizeof (PACKAGE_STRING); + grub_memcpy (tag->string, PACKAGE_STRING, sizeof (PACKAGE_STRING)); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + { + unsigned i; + struct module *cur; + + for (i = 0, cur = modules; i < modcnt; i++, cur = cur->next) + { + struct multiboot_tag_module *tag + = (struct multiboot_tag_module *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_MODULE; + tag->size = sizeof (struct multiboot_tag_module) + cur->cmdline_size; + tag->mod_start = dest + cur->start; + tag->mod_end = tag->mod_start + cur->size; + grub_memcpy (tag->cmdline, cur->cmdline, cur->cmdline_size); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + } + + { + struct multiboot_tag_mmap *tag = (struct multiboot_tag_mmap *) ptrorig; + grub_fill_multiboot_mmap (tag); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + { + struct multiboot_tag_basic_meminfo *tag + = (struct multiboot_tag_basic_meminfo *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_BASIC_MEMINFO; + tag->size = sizeof (struct multiboot_tag_basic_meminfo); + + /* Convert from bytes to kilobytes. */ + tag->mem_lower = grub_mmap_get_lower () / 1024; + tag->mem_upper = grub_mmap_get_upper () / 1024; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + if (bootdev_set) + { + struct multiboot_tag_bootdev *tag + = (struct multiboot_tag_bootdev *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_BOOTDEV; + tag->size = sizeof (struct multiboot_tag_bootdev); + + tag->biosdev = biosdev; + tag->slice = slice; + tag->part = part; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + { + err = retrieve_video_parameters (&ptrorig); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + } + + { + struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_END; + tag->size = sizeof (struct multiboot_tag); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + + ((grub_uint32_t *) mbistart)[0] = ptrorig - mbistart; + ((grub_uint32_t *) mbistart)[1] = 0; + + return GRUB_ERR_NONE; +} + +void +grub_multiboot_free_mbi (void) +{ + struct module *cur, *next; + + cmdline_size = 0; + total_modcmd = 0; + modcnt = 0; + grub_free (cmdline); + cmdline = NULL; + bootdev_set = 0; + + for (cur = modules; cur; cur = next) + { + next = cur->next; + grub_free (cur->cmdline); + grub_free (cur); + } + modules = NULL; + modules_last = NULL; +} + +grub_err_t +grub_multiboot_init_mbi (int argc, char *argv[]) +{ + grub_ssize_t len = 0; + char *p; + int i; + + grub_multiboot_free_mbi (); + + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + if (len == 0) + len = 1; + + cmdline = p = grub_malloc (len); + if (! cmdline) + return grub_errno; + cmdline_size = len; + + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + if (p != cmdline) + p--; + *p = '\0'; + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_multiboot_add_module (grub_addr_t start, grub_size_t size, + int argc, char *argv[]) +{ + struct module *newmod; + char *p; + grub_ssize_t len = 0; + int i; + + newmod = grub_malloc (sizeof (*newmod)); + if (!newmod) + return grub_errno; + newmod->start = start; + newmod->size = size; + + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + + if (len == 0) + len = 1; + + newmod->cmdline = p = grub_malloc (len); + if (! newmod->cmdline) + { + grub_free (newmod); + return grub_errno; + } + newmod->cmdline_size = len; + total_modcmd += ALIGN_UP (len, MULTIBOOT_TAG_ALIGN); + + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + if (p != newmod->cmdline) + p--; + *p = '\0'; + + if (modules_last) + modules_last->next = newmod; + else + { + modules = newmod; + modules_last->next = NULL; + } + modules_last = newmod; + + modcnt++; + + return GRUB_ERR_NONE; +} + +void +grub_multiboot_set_bootdev (void) +{ + grub_device_t dev; + + slice = ~0; + part = ~0; + +#ifdef GRUB_MACHINE_PCBIOS + biosdev = grub_get_root_biosnumber (); +#else + biosdev = 0xffffffff; +#endif + + if (biosdev == 0xffffffff) + return; + + dev = grub_device_open (0); + if (dev && dev->disk && dev->disk->partition) + { + if (dev->disk->partition->parent) + { + part = dev->disk->partition->number; + slice = dev->disk->partition->parent->number; + } + else + slice = dev->disk->partition->number; + } + if (dev) + grub_device_close (dev); + + bootdev_set = 1; +} diff --git a/loader/powerpc/ieee1275/linux.c b/loader/powerpc/ieee1275/linux.c index 79fbf0b02..930c0cb41 100644 --- a/loader/powerpc/ieee1275/linux.c +++ b/loader/powerpc/ieee1275/linux.c @@ -1,7 +1,7 @@ /* linux.c - boot Linux */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2007,2009 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 @@ -26,6 +26,7 @@ #include #include #include +#include #define ELF32_LOADMASK (0xc0000000UL) #define ELF64_LOADMASK (0xc000000000000000ULL) @@ -75,10 +76,10 @@ grub_linux_release_mem (void) linux_args = 0; if (linux_addr && grub_ieee1275_release (linux_addr, linux_size)) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not release memory"); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot release memory"); if (initrd_addr && grub_ieee1275_release (initrd_addr, initrd_size)) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not release memory"); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot release memory"); linux_addr = 0; initrd_addr = 0; @@ -110,7 +111,7 @@ grub_linux_load32 (grub_elf_t elf) if (entry == 0) entry = 0x01400000; - linux_size = grub_elf32_size (elf); + linux_size = grub_elf32_size (elf, 0); if (linux_size == 0) return grub_errno; /* Pad it; the kernel scribbles over memory beyond its load address. */ @@ -128,7 +129,7 @@ grub_linux_load32 (grub_elf_t elf) break; } if (found_addr == -1) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not claim memory."); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory"); /* Now load the segments into the area we claimed. */ auto grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load); @@ -160,7 +161,7 @@ grub_linux_load64 (grub_elf_t elf) if (entry == 0) entry = 0x01400000; - linux_size = grub_elf64_size (elf); + linux_size = grub_elf64_size (elf, 0); if (linux_size == 0) return grub_errno; /* Pad it; the kernel scribbles over memory beyond its load address. */ @@ -178,7 +179,7 @@ grub_linux_load64 (grub_elf_t elf) break; } if (found_addr == -1) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not claim memory."); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory"); /* Now load the segments into the area we claimed. */ auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load); @@ -222,7 +223,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (elf->ehdr.ehdr32.e_type != ET_EXEC) { grub_error (GRUB_ERR_UNKNOWN_OS, - "This ELF file is not of the right type\n"); + "this ELF file is not of the right type"); goto out; } @@ -236,7 +237,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_linux_load64 (elf); else { - grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unknown ELF class"); + grub_error (GRUB_ERR_BAD_FILE_TYPE, "unknown ELF class"); goto out; } @@ -297,7 +298,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (!loaded) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first."); + grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); goto fail; } @@ -321,7 +322,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (found_addr == -1) { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "Can not claim memory"); + grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot claim memory"); goto fail; } @@ -330,7 +331,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, (void *) addr, size) != size) { grub_ieee1275_release (addr, size); - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } @@ -349,9 +350,9 @@ static grub_command_t cmd_linux, cmd_initrd; GRUB_MOD_INIT(linux) { cmd_linux = grub_register_command ("linux", grub_cmd_linux, - 0, "load a linux kernel"); + 0, N_("Load Linux.")); cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, - 0, "load an initrd"); + 0, N_("Load initrd.")); my_mod = mod; } diff --git a/loader/sparc64/ieee1275/linux.c b/loader/sparc64/ieee1275/linux.c index df420d8a0..f55b4fa2a 100644 --- a/loader/sparc64/ieee1275/linux.c +++ b/loader/sparc64/ieee1275/linux.c @@ -27,6 +27,7 @@ #include #include #include +#include static grub_dl_t my_mod; @@ -57,9 +58,6 @@ static grub_size_t linux_size; static char *linux_args; -typedef void (*kernel_entry_t) (unsigned long, unsigned long, - unsigned long, unsigned long, int (void *)); - struct linux_bootstr_info { int len, valid; char buf[]; @@ -91,7 +89,6 @@ static grub_err_t grub_linux_boot (void) { struct linux_bootstr_info *bp; - kernel_entry_t linuxmain; struct linux_hdrs *hp; grub_addr_t addr; @@ -140,8 +137,17 @@ grub_linux_boot (void) grub_dprintf ("loader", "Jumping to Linux...\n"); /* Boot the kernel. */ - linuxmain = (kernel_entry_t) linux_addr; - linuxmain (0, 0, 0, 0, grub_ieee1275_entry_fn); + asm volatile ("sethi %hi(grub_ieee1275_entry_fn), %o1\n" + "ldx [%o1 + %lo(grub_ieee1275_entry_fn)], %o4\n" + "sethi %hi(grub_ieee1275_original_stack), %o1\n" + "ldx [%o1 + %lo(grub_ieee1275_original_stack)], %o6\n" + "sethi %hi(linux_addr), %o1\n" + "ldx [%o1 + %lo(linux_addr)], %o5\n" + "mov %g0, %o0\n" + "mov %g0, %o2\n" + "mov %g0, %o3\n" + "jmp %o5\n" + "mov %g0, %o1\n"); return GRUB_ERR_NONE; } @@ -172,12 +178,6 @@ grub_linux_unload (void) #define FOUR_MB (4 * 1024 * 1024) -static grub_addr_t -align_addr(grub_addr_t val, grub_addr_t align) -{ - return (val + (align - 1)) & ~(align - 1); -} - static grub_addr_t alloc_phys (grub_addr_t size) { @@ -191,39 +191,39 @@ alloc_phys (grub_addr_t size) if (type != 1) return 0; - addr = align_addr (addr, FOUR_MB); - if (addr >= end) + addr = ALIGN_UP (addr, FOUR_MB); + if (addr + size >= end) return 0; if (addr >= grub_phys_start && addr < grub_phys_end) { - addr = align_addr (grub_phys_end, FOUR_MB); - if (addr >= end) + addr = ALIGN_UP (grub_phys_end, FOUR_MB); + if (addr + size >= end) return 0; } if ((addr + size) >= grub_phys_start && (addr + size) < grub_phys_end) { - addr = align_addr (grub_phys_end, FOUR_MB); - if (addr >= end) + addr = ALIGN_UP (grub_phys_end, FOUR_MB); + if (addr + size >= end) return 0; } if (loaded) { - grub_addr_t linux_end = align_addr (linux_paddr + linux_size, FOUR_MB); + grub_addr_t linux_end = ALIGN_UP (linux_paddr + linux_size, FOUR_MB); if (addr >= linux_paddr && addr < linux_end) { addr = linux_end; - if (addr >= end) + if (addr + size >= end) return 0; } if ((addr + size) >= linux_paddr && (addr + size) < linux_end) { addr = linux_end; - if (addr >= end) + if (addr + size >= end) return 0; } } @@ -246,7 +246,7 @@ grub_linux_load64 (grub_elf_t elf) linux_entry = elf->ehdr.ehdr64.e_entry; linux_addr = 0x40004000; off = 0x4000; - linux_size = grub_elf64_size (elf); + linux_size = grub_elf64_size (elf, 0); if (linux_size == 0) return grub_errno; @@ -256,14 +256,14 @@ grub_linux_load64 (grub_elf_t elf) paddr = alloc_phys (linux_size + off); if (paddr == (grub_addr_t) -1) return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Could not allocate physical memory."); - ret = grub_ieee1275_map_physical (paddr, linux_addr - off, - linux_size + off, IEEE1275_MAP_DEFAULT); + "couldn't allocate physical memory"); + ret = grub_ieee1275_map (paddr, linux_addr - off, + linux_size + off, IEEE1275_MAP_DEFAULT); if (ret) return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Could not map physical memory."); + "couldn't map physical memory"); - grub_dprintf ("loader", "Loading linux at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n", + grub_dprintf ("loader", "Loading Linux at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n", linux_addr, paddr, linux_size); linux_paddr = paddr; @@ -317,7 +317,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (elf->ehdr.ehdr32.e_type != ET_EXEC) { grub_error (GRUB_ERR_UNKNOWN_OS, - "This ELF file is not of the right type\n"); + "this ELF file is not of the right type"); goto out; } @@ -328,7 +328,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_linux_load64 (elf); else { - grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unknown ELF class"); + grub_error (GRUB_ERR_BAD_FILE_TYPE, "unknown ELF class"); goto out; } @@ -390,7 +390,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (!loaded) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first."); + grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); goto fail; } @@ -405,14 +405,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (paddr == (grub_addr_t) -1) { grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Could not allocate physical memory."); + "couldn't allocate physical memory"); goto fail; } - ret = grub_ieee1275_map_physical (paddr, addr, size, IEEE1275_MAP_DEFAULT); + ret = grub_ieee1275_map (paddr, addr, size, IEEE1275_MAP_DEFAULT); if (ret) { grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Could not map physical memory."); + "couldn't map physical memory"); goto fail; } @@ -421,7 +421,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, (void *) addr, size) != size) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } @@ -516,9 +516,9 @@ GRUB_MOD_INIT(linux) fetch_translations (); cmd_linux = grub_register_command ("linux", grub_cmd_linux, - 0, "load a linux kernel"); + 0, N_("Load Linux.")); cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, - 0, "load an initrd"); + 0, N_("Load initrd.")); my_mod = mod; } diff --git a/loader/xnu.c b/loader/xnu.c index aac4ae372..8f1d0c641 100644 --- a/loader/xnu.c +++ b/loader/xnu.c @@ -31,10 +31,17 @@ #include #include #include +#include +#include +#include struct grub_xnu_devtree_key *grub_xnu_devtree_root = 0; static int driverspackagenum = 0; static int driversnum = 0; +int grub_xnu_is_64bit = 0; + +void *grub_xnu_heap_start = 0; +grub_size_t grub_xnu_heap_size = 0; /* Allocate heap by 32MB-blocks. */ #define GRUB_XNU_HEAP_ALLOC_BLOCK 0x2000000 @@ -46,12 +53,6 @@ void * grub_xnu_heap_malloc (int size) { void *val; - -#if 0 - /* This way booting is faster but less reliable. - Once we have advanced mm second way will be as fast as this one. */ - val = grub_xnu_heap_start = (char *) 0x100000; -#else int oldblknum, newblknum; /* The page after the heap is used for stack. Ensure it's usable. */ @@ -63,25 +64,21 @@ grub_xnu_heap_malloc (int size) newblknum = (grub_xnu_heap_size + size + GRUB_XNU_PAGESIZE + GRUB_XNU_HEAP_ALLOC_BLOCK - 1) / GRUB_XNU_HEAP_ALLOC_BLOCK; if (oldblknum != newblknum) - /* FIXME: instruct realloc to allocate at 1MB if possible once - advanced mm is ready. */ - val = grub_realloc (grub_xnu_heap_start, - newblknum * GRUB_XNU_HEAP_ALLOC_BLOCK); - else - val = grub_xnu_heap_start; - if (! val) { - grub_error (GRUB_ERR_OUT_OF_MEMORY, - "not enough space on xnu memory heap"); - return 0; + /* FIXME: instruct realloc to allocate at 1MB if possible once + advanced mm is ready. */ + grub_xnu_heap_start + = XNU_RELOCATOR (realloc) (grub_xnu_heap_start, + newblknum + * GRUB_XNU_HEAP_ALLOC_BLOCK); + if (!grub_xnu_heap_start) + return NULL; } - grub_xnu_heap_start = val; -#endif - val = (char *) grub_xnu_heap_start + grub_xnu_heap_size; + val = (grub_uint8_t *) grub_xnu_heap_start + grub_xnu_heap_size; grub_xnu_heap_size += size; grub_dprintf ("xnu", "val=%p\n", val); - return (char *) val; + return val; } /* Make sure next block of the heap will be aligned. @@ -251,7 +248,7 @@ grub_xnu_writetree_toheap (void **start, grub_size_t *size) - *size % GRUB_XNU_PAGESIZE); /* Put real data in the dummy. */ - extdesc->addr = (char *) *start - grub_xnu_heap_start + extdesc->addr = (grub_uint8_t *) *start - (grub_uint8_t *) grub_xnu_heap_start + grub_xnu_heap_will_be_at; extdesc->size = (grub_uint32_t) *size; @@ -333,6 +330,8 @@ grub_xnu_create_value (struct grub_xnu_devtree_key **parent, char *name) static grub_err_t grub_xnu_unload (void) { + grub_cpu_xnu_unload (); + grub_xnu_free_devtree (grub_xnu_devtree_root); grub_xnu_devtree_root = 0; @@ -352,7 +351,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), { grub_err_t err; grub_macho_t macho; - grub_addr_t startcode, endcode; + grub_uint32_t startcode, endcode; int i; char *ptr, *loadaddr; @@ -368,10 +367,10 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), { grub_macho_close (macho); return grub_error (GRUB_ERR_BAD_OS, - "Kernel doesn't contain suitable architecture"); + "kernel doesn't contain suitable 32-bit architecture"); } - err = grub_macho32_size (macho, &startcode, &endcode, GRUB_MACHO_NOBSS); + err = grub_macho_size32 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS); if (err) { grub_macho_close (macho); @@ -394,7 +393,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), } /* Load kernel. */ - err = grub_macho32_load (macho, loadaddr - startcode, GRUB_MACHO_NOBSS); + err = grub_macho_load32 (macho, loadaddr - startcode, GRUB_MACHO_NOBSS); if (err) { grub_macho_close (macho); @@ -402,7 +401,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), return err; } - grub_xnu_entry_point = grub_macho32_get_entry_point (macho); + grub_xnu_entry_point = grub_macho_get_entry_point32 (macho); if (! grub_xnu_entry_point) { grub_macho_close (macho); @@ -436,13 +435,112 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), if (ptr != grub_xnu_cmdline) *(ptr - 1) = 0; - err = grub_cpu_xnu_fill_devicetree (); + grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0); + + grub_xnu_lock (); + grub_xnu_is_64bit = 0; + + return 0; +} + +static grub_err_t +grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), + int argc, char *args[]) +{ + grub_err_t err; + grub_macho_t macho; + grub_uint64_t startcode, endcode; + int i; + char *ptr, *loadaddr; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + + grub_xnu_unload (); + + macho = grub_macho_open (args[0]); + if (! macho) + return grub_errno; + if (! grub_macho_contains_macho64 (macho)) + { + grub_macho_close (macho); + return grub_error (GRUB_ERR_BAD_OS, + "kernel doesn't contain suitable 64-bit architecture"); + } + + err = grub_macho_size64 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS); if (err) - return err; + { + grub_macho_close (macho); + grub_xnu_unload (); + return err; + } + + startcode &= 0x0fffffff; + endcode &= 0x0fffffff; + + grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n", + (unsigned long) endcode, (unsigned long) startcode); + + loadaddr = grub_xnu_heap_malloc (endcode - startcode); + grub_xnu_heap_will_be_at = startcode; + + if (! loadaddr) + { + grub_macho_close (macho); + grub_xnu_unload (); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "not enough memory to load kernel"); + } + + /* Load kernel. */ + err = grub_macho_load64 (macho, loadaddr - startcode, GRUB_MACHO_NOBSS); + if (err) + { + grub_macho_close (macho); + grub_xnu_unload (); + return err; + } + + grub_xnu_entry_point = grub_macho_get_entry_point64 (macho) & 0x0fffffff; + if (! grub_xnu_entry_point) + { + grub_macho_close (macho); + grub_xnu_unload (); + return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point"); + } + + grub_macho_close (macho); + + err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); + if (err) + { + grub_xnu_unload (); + return err; + } + + /* Copy parameters to kernel command line. */ + ptr = grub_xnu_cmdline; + for (i = 1; i < argc; i++) + { + if (ptr + grub_strlen (args[i]) + 1 + >= grub_xnu_cmdline + sizeof (grub_xnu_cmdline)) + break; + grub_memcpy (ptr, args[i], grub_strlen (args[i])); + ptr += grub_strlen (args[i]); + *ptr = ' '; + ptr++; + } + + /* Replace last space by '\0'. */ + if (ptr != grub_xnu_cmdline) + *(ptr - 1) = 0; grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0); grub_xnu_lock (); + grub_xnu_is_64bit = 1; + return 0; } @@ -472,10 +570,9 @@ grub_xnu_register_memory (char *prefix, int *suffix, return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register memory"); if (suffix) { - driverkey->name = grub_malloc (grub_strlen (prefix) + 10); + driverkey->name = grub_xasprintf ("%s%d", prefix, (*suffix)++); if (!driverkey->name) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register memory"); - grub_sprintf (driverkey->name, "%s%d", prefix, (*suffix)++); } else driverkey->name = grub_strdup (prefix); @@ -494,6 +591,34 @@ grub_xnu_register_memory (char *prefix, int *suffix, return GRUB_ERR_NONE; } +static inline char * +get_name_ptr (char *name) +{ + char *p = name, *p2; + /* Skip Info.plist. */ + p2 = grub_strrchr (p, '/'); + if (!p2) + return name; + if (p2 == name) + return name + 1; + p = p2 - 1; + + p2 = grub_strrchr (p, '/'); + if (!p2) + return name; + if (p2 == name) + return name + 1; + if (grub_memcmp (p2, "/Contents/", sizeof ("/Contents/") - 1) != 0) + return p2 + 1; + + p = p2 - 1; + + p2 = grub_strrchr (p, '/'); + if (!p2) + return name; + return p2 + 1; +} + /* Load .kext. */ static grub_err_t grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) @@ -503,8 +628,20 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) grub_file_t infoplist; struct grub_xnu_extheader *exthead; int neededspace = sizeof (*exthead); - char *buf; + grub_uint8_t *buf; grub_size_t infoplistsize = 0, machosize = 0; + char *name, *nameend; + int namelen; + + name = get_name_ptr (infoplistname); + nameend = grub_strchr (name, '/'); + + if (nameend) + namelen = nameend - name; + else + namelen = grub_strlen (name); + + neededspace += namelen + 1; if (! grub_xnu_heap_size) return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); @@ -518,9 +655,12 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) if (macho) grub_macho_close (macho); return grub_error (GRUB_ERR_BAD_OS, - "Extension doesn't contain suitable architecture"); + "extension doesn't contain suitable architecture"); } - machosize = grub_macho32_filesize (macho); + if (grub_xnu_is_64bit) + machosize = grub_macho_filesize64 (macho); + else + machosize = grub_macho_filesize32 (macho); neededspace += machosize; } else @@ -552,10 +692,14 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) /* Load the binary. */ if (macho) { - exthead->binaryaddr = (buf - grub_xnu_heap_start) + exthead->binaryaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) + grub_xnu_heap_will_be_at; exthead->binarysize = machosize; - if ((err = grub_macho32_readfile (macho, buf))) + if (grub_xnu_is_64bit) + err = grub_macho_readfile64 (macho, buf); + else + err = grub_macho_readfile32 (macho, buf); + if (err) { grub_macho_close (macho); return err; @@ -568,7 +712,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) /* Load the plist. */ if (infoplist) { - exthead->infoplistaddr = (buf - grub_xnu_heap_start) + exthead->infoplistaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) + grub_xnu_heap_will_be_at; exthead->infoplistsize = infoplistsize + 1; if (grub_file_read (infoplist, buf, infoplistsize) @@ -576,14 +720,22 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) { grub_file_close (infoplist); grub_error_push (); - return grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s: ", + return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s: ", infoplistname); } grub_file_close (infoplist); buf[infoplistsize] = 0; + buf += infoplistsize + 1; } grub_errno = GRUB_ERR_NONE; + exthead->nameaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) + + grub_xnu_heap_will_be_at; + exthead->namesize = namelen + 1; + grub_memcpy (buf, name, namelen); + buf[namelen] = 0; + buf += namelen + 1; + /* Announce to kernel */ return grub_xnu_register_memory ("Driver-", &driversnum, exthead, neededspace); @@ -612,7 +764,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), file = grub_gzfile_open (args[0], 1); if (! file) return grub_error (GRUB_ERR_FILE_NOT_FOUND, - "Couldn't load driver package"); + "couldn't load driver package"); /* Sometimes caches are fat binary. Errgh. */ if (grub_file_read (file, &head, sizeof (head)) @@ -622,7 +774,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), can hardly imagine a valid package shorter than 20 bytes. */ grub_file_close (file); grub_error_push (); - return grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", args[0]); + return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); } /* Find the corresponding architecture. */ @@ -635,7 +787,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), grub_file_close (file); grub_error_push (); return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Couldn't read file %s", args[0]); + "couldn't read file %s", args[0]); } if (grub_file_read (file, archs, @@ -644,11 +796,17 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), { grub_free (archs); grub_error_push (); - return grub_error (GRUB_ERR_READ_ERROR, "Cannot read fat header."); + return grub_error (GRUB_ERR_READ_ERROR, "cannot read fat header"); } for (i = 0; i < narchs; i++) { - if (GRUB_MACHO_CPUTYPE_IS_HOST32 + if (!grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST32 + (grub_be_to_cpu32 (archs[i].cputype))) + { + readoff = grub_be_to_cpu32 (archs[i].offset); + readlen = grub_be_to_cpu32 (archs[i].size); + } + if (grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST64 (grub_be_to_cpu32 (archs[i].cputype))) { readoff = grub_be_to_cpu32 (archs[i].offset); @@ -691,7 +849,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), { grub_file_close (file); grub_error_push (); - return grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", args[0]); + return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); } grub_file_close (file); @@ -718,7 +876,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), file = grub_gzfile_open (args[0], 1); if (! file) return grub_error (GRUB_ERR_FILE_NOT_FOUND, - "Couldn't load ramdisk"); + "couldn't load ramdisk"); err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); if (err) @@ -734,140 +892,11 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), { grub_file_close (file); grub_error_push (); - return grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", args[0]); + return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); } return grub_xnu_register_memory ("RAMDisk", 0, loadto, size); } -/* Parse a devtree file. It uses the following format: - valuename:valuedata; - keyname{ - contents - } - keyname, valuename and valuedata are in hex. - */ -static char * -grub_xnu_parse_devtree (struct grub_xnu_devtree_key **parent, - char *start, char *end) -{ - char *ptr, *ptr2; - char *name, *data; - int namelen, datalen, i; - for (ptr = start; ptr && ptr < end; ) - { - if (grub_isspace (*ptr)) - { - ptr++; - continue; - } - if (*ptr == '}') - return ptr + 1; - namelen = 0; - - /* Parse the name. */ - for (ptr2 = ptr; ptr2 < end && (grub_isspace (*ptr2) - || (*ptr2 >= '0' && *ptr2 <= '9') - || (*ptr2 >= 'a' && *ptr2 <= 'f') - || (*ptr2 >= 'A' && *ptr2 <= 'F')); - ptr2++) - if (! grub_isspace (*ptr2)) - namelen++; - if (ptr2 == end) - return 0; - namelen /= 2; - name = grub_malloc (namelen + 1); - if (!name) - return 0; - for (i = 0; i < 2 * namelen; i++) - { - int hex = 0; - while (grub_isspace (*ptr)) - ptr++; - if (*ptr >= '0' && *ptr <= '9') - hex = *ptr - '0'; - if (*ptr >= 'a' && *ptr <= 'f') - hex = *ptr - 'a' + 10; - if (*ptr >= 'A' && *ptr <= 'F') - hex = *ptr - 'A' + 10; - - if (i % 2 == 0) - name[i / 2] = hex << 4; - else - name[i / 2] |= hex; - ptr++; - } - name [namelen] = 0; - while (grub_isspace (*ptr)) - ptr++; - - /* If it describes a key recursively invoke the function. */ - if (*ptr == '{') - { - struct grub_xnu_devtree_key *newkey - = grub_xnu_create_key (parent, name); - grub_free (name); - if (! newkey) - return 0; - ptr = grub_xnu_parse_devtree (&(newkey->first_child), ptr + 1, end); - continue; - } - - /* Parse the data. */ - if (*ptr != ':') - return 0; - ptr++; - datalen = 0; - for (ptr2 = ptr; ptr2 < end && (grub_isspace (*ptr2) - || (*ptr2 >= '0' && *ptr2 <= '9') - || (*ptr2 >= 'a' && *ptr2 <= 'f') - || (*ptr2 >= 'A' && *ptr2 <= 'F')); - ptr2++) - if (! grub_isspace (*ptr2)) - datalen++; - if (ptr2 == end) - return 0; - datalen /= 2; - data = grub_malloc (datalen); - if (! data) - return 0; - for (i = 0; i < 2 * datalen; i++) - { - int hex = 0; - while (grub_isspace (*ptr)) - ptr++; - if (*ptr >= '0' && *ptr <= '9') - hex = *ptr - '0'; - if (*ptr >= 'a' && *ptr <= 'f') - hex = *ptr - 'a' + 10; - if (*ptr >= 'A' && *ptr <= 'F') - hex = *ptr - 'A' + 10; - - if (i % 2 == 0) - data[i / 2] = hex << 4; - else - data[i / 2] |= hex; - ptr++; - } - while (ptr < end && grub_isspace (*ptr)) - ptr++; - { - struct grub_xnu_devtree_key *newkey - = grub_xnu_create_value (parent, name); - grub_free (name); - if (! newkey) - return 0; - newkey->datasize = datalen; - newkey->data = data; - } - if (*ptr != ';') - return 0; - ptr++; - } - if (ptr >= end && *parent != grub_xnu_devtree_root) - return 0; - return ptr; -} - /* Returns true if the kext should be loaded according to plist and osbundlereq. Also fill BINNAME. */ static int @@ -889,7 +918,7 @@ grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq, { grub_file_close (file); grub_error_push (); - grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", plistname); + grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", plistname); return 0; } @@ -899,14 +928,14 @@ grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq, { grub_file_close (file); grub_error_push (); - grub_error (GRUB_ERR_OUT_OF_MEMORY, "Couldn't read file %s", plistname); + grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't read file %s", plistname); return 0; } if (grub_file_read (file, buf, size) != (grub_ssize_t) (size)) { grub_file_close (file); grub_error_push (); - grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", plistname); + grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", plistname); return 0; } grub_file_close (file); @@ -1164,53 +1193,6 @@ grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, return GRUB_ERR_NONE; } -/* Load devtree file. */ -static grub_err_t -grub_cmd_xnu_devtree (grub_command_t cmd __attribute__ ((unused)), - int argc, char *args[]) -{ - grub_file_t file; - char *data, *endret; - grub_size_t datalen; - - if (argc != 1) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "Filename required"); - - if (! grub_xnu_heap_size) - return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); - - /* Load the file. */ - file = grub_gzfile_open (args[0], 1); - if (! file) - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "Couldn't load device tree"); - datalen = grub_file_size (file); - data = grub_malloc (datalen + 1); - if (! data) - { - grub_file_close (file); - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "Could load device tree into memory"); - } - if (grub_file_read (file, data, datalen) != (grub_ssize_t) datalen) - { - grub_file_close (file); - grub_free (data); - grub_error_push (); - return grub_error (GRUB_ERR_BAD_OS, "Couldn't read file %s", args[0]); - } - grub_file_close (file); - data[datalen] = 0; - - /* Parse the file. */ - endret = grub_xnu_parse_devtree (&grub_xnu_devtree_root, - data, data + datalen); - grub_free (data); - - if (! endret) - return grub_error (GRUB_ERR_BAD_OS, "Couldn't parse devtree"); - - return GRUB_ERR_NONE; -} static int locked=0; static grub_dl_t my_mod; @@ -1271,24 +1253,144 @@ grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ ((unused)), } } +static inline int +hextoval (char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'z') + return c - 'a' + 10; + if (c >= 'A' && c <= 'Z') + return c - 'A' + 10; + return 0; +} + +static inline void +unescape (char *name, char *curdot, char *nextdot, int *len) +{ + char *ptr, *dptr; + dptr = name; + for (ptr = curdot; ptr < nextdot;) + if (ptr + 2 < nextdot && *ptr == '%') + { + *dptr = (hextoval (ptr[1]) << 4) | (hextoval (ptr[2])); + ptr += 3; + dptr++; + } + else + { + *dptr = *ptr; + ptr++; + dptr++; + } + *len = dptr - name; +} + +grub_err_t +grub_xnu_fill_devicetree (void) +{ + auto int iterate_env (struct grub_env_var *var); + int iterate_env (struct grub_env_var *var) + { + char *nextdot = 0, *curdot; + struct grub_xnu_devtree_key **curkey = &grub_xnu_devtree_root; + struct grub_xnu_devtree_key *curvalue; + char *name = 0, *data; + int len; + + if (grub_memcmp (var->name, "XNU.DeviceTree.", + sizeof ("XNU.DeviceTree.") - 1) != 0) + return 0; + + curdot = var->name + sizeof ("XNU.DeviceTree.") - 1; + nextdot = grub_strchr (curdot, '.'); + if (nextdot) + nextdot++; + while (nextdot) + { + name = grub_realloc (name, nextdot - curdot + 1); + + if (!name) + return 1; + + unescape (name, curdot, nextdot, &len); + name[len - 1] = 0; + + curkey = &(grub_xnu_create_key (curkey, name)->first_child); + + curdot = nextdot; + nextdot = grub_strchr (nextdot, '.'); + if (nextdot) + nextdot++; + } + + nextdot = curdot + grub_strlen (curdot) + 1; + + name = grub_realloc (name, nextdot - curdot + 1); + + if (!name) + return 1; + + unescape (name, curdot, nextdot, &len); + name[len] = 0; + + curvalue = grub_xnu_create_value (curkey, name); + grub_free (name); + + data = grub_malloc (grub_strlen (var->value) + 1); + if (!data) + return 1; + + unescape (data, var->value, var->value + grub_strlen (var->value), + &len); + curvalue->datasize = len; + curvalue->data = data; + + return 0; + } + + grub_env_iterate (iterate_env); + + return grub_errno; +} + struct grub_video_bitmap *grub_xnu_bitmap = 0; +grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode; + +/* Option array indices. */ +#define XNU_SPLASH_CMD_ARGINDEX_MODE 0 + +static const struct grub_arg_option xnu_splash_cmd_options[] = + { + {"mode", 'm', 0, "Background image mode.", "stretch|normal", + ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; static grub_err_t -grub_cmd_xnu_splash (grub_command_t cmd __attribute__ ((unused)), +grub_cmd_xnu_splash (grub_extcmd_t cmd, 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, + "stretch") == 0) + grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH; + else + grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_CENTER; + err = grub_video_bitmap_load (&grub_xnu_bitmap, args[0]); if (err) grub_xnu_bitmap = 0; + return err; } -#ifndef GRUB_UTIL +#ifndef GRUB_MACHINE_EMU static grub_err_t grub_cmd_xnu_resume (grub_command_t cmd __attribute__ ((unused)), int argc, char *args[]) @@ -1316,45 +1418,54 @@ grub_xnu_unlock () locked = 0; } -static grub_command_t cmd_kernel, cmd_mkext, cmd_kext, cmd_kextdir, - cmd_ramdisk, cmd_devtree, cmd_resume, cmd_splash; +static grub_command_t cmd_kernel64, cmd_kernel, cmd_mkext, cmd_kext; +static grub_command_t cmd_kextdir, cmd_ramdisk, cmd_resume; +static grub_extcmd_t cmd_splash; GRUB_MOD_INIT(xnu) { cmd_kernel = grub_register_command ("xnu_kernel", grub_cmd_xnu_kernel, 0, - "load a xnu kernel"); + N_("Load XNU image.")); + cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64, + 0, N_("Load 64-bit XNU image.")); cmd_mkext = grub_register_command ("xnu_mkext", grub_cmd_xnu_mkext, 0, - "Load XNU extension package."); + N_("Load XNU extension package.")); cmd_kext = grub_register_command ("xnu_kext", grub_cmd_xnu_kext, 0, - "Load XNU extension."); + N_("Load XNU extension.")); cmd_kextdir = grub_register_command ("xnu_kextdir", grub_cmd_xnu_kextdir, - "xnu_kextdir DIRECTORY [OSBundleRequired]", - "Load XNU extension directory"); + N_("DIRECTORY [OSBundleRequired]"), + N_("Load XNU extension directory.")); cmd_ramdisk = grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk, 0, "Load XNU ramdisk. " - "It will be seen as md0"); - cmd_devtree = grub_register_command ("xnu_devtree", grub_cmd_xnu_devtree, 0, - "Load XNU devtree"); - cmd_splash = grub_register_command ("xnu_splash", grub_cmd_xnu_splash, 0, - "Load a splash image for XNU"); + "It will be seen as md0."); + cmd_splash = grub_register_extcmd ("xnu_splash", + grub_cmd_xnu_splash, + GRUB_COMMAND_FLAG_BOTH, 0, + N_("Load a splash image for XNU."), + xnu_splash_cmd_options); -#ifndef GRUB_UTIL +#ifndef GRUB_MACHINE_EMU cmd_resume = grub_register_command ("xnu_resume", grub_cmd_xnu_resume, - 0, "Load XNU hibernate image."); + 0, N_("Load XNU hibernate image.")); #endif - my_mod=mod; + + grub_cpu_xnu_init (); + + my_mod = mod; } GRUB_MOD_FINI(xnu) { -#ifndef GRUB_UTIL +#ifndef GRUB_MACHINE_EMU grub_unregister_command (cmd_resume); #endif grub_unregister_command (cmd_mkext); grub_unregister_command (cmd_kext); grub_unregister_command (cmd_kextdir); - grub_unregister_command (cmd_devtree); grub_unregister_command (cmd_ramdisk); grub_unregister_command (cmd_kernel); - grub_unregister_command (cmd_splash); + grub_unregister_extcmd (cmd_splash); + grub_unregister_command (cmd_kernel64); + + grub_cpu_xnu_fini (); } diff --git a/loader/xnu_resume.c b/loader/xnu_resume.c index 77f688726..e6620e7b7 100644 --- a/loader/xnu_resume.c +++ b/loader/xnu_resume.c @@ -45,7 +45,7 @@ grub_xnu_resume (char *imagename) grub_file_t file; grub_size_t total_header_size; struct grub_xnu_hibernate_header hibhead; - char *buf, *codetmp; + grub_uint8_t *buf; grub_uint32_t codedest; grub_uint32_t codesize; @@ -94,40 +94,49 @@ grub_xnu_resume (char *imagename) /* Try to allocate necessary space. FIXME: mm isn't good enough yet to handle huge allocations. */ - grub_xnu_hibernate_image = buf = grub_malloc (hibhead.image_size); + grub_xnu_hibernate_image = buf = XNU_RELOCATOR (alloc) (hibhead.image_size + + codesize + + GRUB_XNU_PAGESIZE); if (! buf) { grub_file_close (file); - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "not enough memory to load image"); + return grub_errno; + } + + /* Read code part. */ + if (grub_file_seek (file, total_header_size) == (grub_off_t) -1 + || grub_file_read (file, buf, codesize) + != (grub_ssize_t) codesize) + { + grub_file_close (file); + return grub_error (GRUB_ERR_READ_ERROR, "cannot read resume image"); } /* Read image. */ - if (grub_file_seek (file, 0) == (grub_off_t)-1 - || grub_file_read (file, buf, hibhead.image_size) + if (grub_file_seek (file, 0) == (grub_off_t) -1 + || grub_file_read (file, buf + codesize + GRUB_XNU_PAGESIZE, + hibhead.image_size) != (grub_ssize_t) hibhead.image_size) { grub_file_close (file); - return grub_error (GRUB_ERR_READ_ERROR, "Cannot read resume image."); + return grub_error (GRUB_ERR_READ_ERROR, "cannot read resume image"); } grub_file_close (file); - codetmp = grub_memalign (GRUB_XNU_PAGESIZE, codesize + GRUB_XNU_PAGESIZE); /* Setup variables needed by asm helper. */ grub_xnu_heap_will_be_at = codedest; - grub_xnu_heap_start = codetmp; - grub_xnu_heap_size = codesize; + grub_xnu_heap_start = buf; + grub_xnu_heap_size = codesize + GRUB_XNU_PAGESIZE + hibhead.image_size; grub_xnu_stack = (codedest + hibhead.stack); grub_xnu_entry_point = (codedest + hibhead.entry_point); - grub_xnu_arg1 = (long) buf; + grub_xnu_arg1 = codedest + codesize + GRUB_XNU_PAGESIZE; - /* Prepare asm helper. */ - grub_memcpy (codetmp, ((grub_uint8_t *) buf) + total_header_size, codesize); - grub_memcpy (codetmp + codesize, grub_xnu_launcher_start, - grub_xnu_launcher_end - grub_xnu_launcher_start); + grub_dprintf ("xnu", "entry point 0x%x\n", codedest + hibhead.entry_point); + grub_dprintf ("xnu", "image at 0x%x\n", + codedest + codesize + GRUB_XNU_PAGESIZE); /* We're ready now. */ - grub_loader_set ((grub_err_t (*) (void)) (codetmp + codesize), + grub_loader_set (grub_xnu_boot_resume, grub_xnu_resume_unload, 0); /* Prevent module from unloading. */ diff --git a/mmap/i386/pc/mmap.c b/mmap/i386/pc/mmap.c index 0e2dfe6a6..7d5a43fec 100644 --- a/mmap/i386/pc/mmap.c +++ b/mmap/i386/pc/mmap.c @@ -179,7 +179,7 @@ malloc_hook (void) if (! hooktarget) { slots_available = 0; - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "No space for mmap hook"); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "no space for mmap hook"); } return GRUB_ERR_NONE; } diff --git a/mmap/i386/pc/mmap_helper.S b/mmap/i386/pc/mmap_helper.S index c6d12fd6c..743954574 100644 --- a/mmap/i386/pc/mmap_helper.S +++ b/mmap/i386/pc/mmap_helper.S @@ -19,32 +19,27 @@ #include -#define DS(x) ((x) - segstart) +#define DS(x) ((x) - LOCAL (segstart)) -segstart: +LOCAL (segstart): VARIABLE(grub_machine_mmaphook_start) .code16 VARIABLE(grub_machine_mmaphook_int12) push %ds push %cs pop %ds -#ifdef APPLE_CC - grub_machine_mmaphook_kblow_rel = DS (EXT_C (grub_machine_mmaphook_kblow)) - movw (grub_machine_mmaphook_kblow_rel), %ax -#else - movw DS (EXT_C (grub_machine_mmaphook_kblow)), %ax -#endif + movw DS (LOCAL (kblow)), %ax pop %ds iret VARIABLE(grub_machine_mmaphook_int15) pushf cmpw $0xe801, %ax - jz e801 + jz LOCAL (e801) cmpw $0xe820, %ax - jz e820 + jz LOCAL (e820) cmpb $0x88, %ah - jz h88 + jz LOCAL (h88) popf /* ljmp */ .byte 0xea @@ -53,67 +48,44 @@ VARIABLE (grub_machine_mmaphook_int15offset) VARIABLE (grub_machine_mmaphook_int15segment) .word 0 -e801: +LOCAL (e801): popf push %ds push %cs pop %ds -#ifdef APPLE_CC - grub_machine_mmaphook_kbin16mb_rel = DS (EXT_C (grub_machine_mmaphook_kbin16mb)) - grub_machine_mmaphook_64kbin4gb_rel = DS (EXT_C (grub_machine_mmaphook_64kbin4gb)) - movw (grub_machine_mmaphook_kbin16mb_rel), %ax - movw (grub_machine_mmaphook_64kbin4gb_rel), %bx -#else - movw DS (EXT_C (grub_machine_mmaphook_kbin16mb)), %ax - movw DS (EXT_C (grub_machine_mmaphook_64kbin4gb)), %bx -#endif + movw DS (LOCAL (kbin16mb)), %ax + movw DS (LOCAL (m64kbin4gb)), %bx movw %ax, %cx movw %bx, %dx pop %ds clc iret -h88: +LOCAL (h88): popf push %ds push %cs pop %ds -#ifdef APPLE_CC - movw (grub_machine_mmaphook_kbin16mb_rel), %ax -#else - movw DS (EXT_C (grub_machine_mmaphook_kbin16mb)), %ax -#endif + movw DS (LOCAL (kbin16mb)), %ax pop %ds clc iret -e820: -#ifdef APPLE_CC - mmaphook_mmap_rel = DS(mmaphook_mmap) - mmaphook_mmap_num_rel = DS(EXT_C(grub_machine_mmaphook_mmap_num)) -#endif +LOCAL (e820): popf push %ds push %cs pop %ds cmpw $20, %cx - jb errexit -#ifdef APPLE_CC - cmpw (mmaphook_mmap_num_rel), %bx -#else - cmpw DS (EXT_C (grub_machine_mmaphook_mmap_num)), %bx -#endif - jae errexit + jb LOCAL (errexit) + cmpw DS (LOCAL (mmap_num)), %bx + jae LOCAL (errexit) cmp $0x534d4150, %edx - jne errexit + jne LOCAL (errexit) push %si push %di movw $20, %cx -#ifdef APPLE_CC - movl $(mmaphook_mmap_rel), %esi -#else - movw $(DS(mmaphook_mmap)), %si -#endif + movw $(DS(LOCAL (mmaphook_mmap))), %si mov %bx, %ax imul $20, %ax add %ax, %si @@ -122,19 +94,15 @@ e820: pop %si movl $20, %ecx inc %bx -#ifdef APPLE_CC - cmpw (mmaphook_mmap_num_rel), %bx -#else - cmpw DS(EXT_C(grub_machine_mmaphook_mmap_num)), %bx -#endif - jb noclean + cmpw DS(LOCAL (mmap_num)), %bx + jb LOCAL (noclean) xor %bx, %bx -noclean: +LOCAL (noclean): mov $0x534d4150, %eax pop %ds clc iret -errexit: +LOCAL (errexit): mov $0x534d4150, %eax pop %ds stc @@ -142,13 +110,18 @@ errexit: iret VARIABLE(grub_machine_mmaphook_mmap_num) +LOCAL (mmap_num): .word 0 VARIABLE(grub_machine_mmaphook_kblow) +LOCAL (kblow): .word 0 VARIABLE (grub_machine_mmaphook_kbin16mb) +LOCAL (kbin16mb): .word 0 VARIABLE (grub_machine_mmaphook_64kbin4gb) +LOCAL (m64kbin4gb): .word 0 -mmaphook_mmap: +LOCAL (mmaphook_mmap): /* Memory map is placed just after the interrupt handlers. */ VARIABLE(grub_machine_mmaphook_end) + .byte 0 diff --git a/mmap/mips/yeeloong/uppermem.c b/mmap/mips/yeeloong/uppermem.c new file mode 100644 index 000000000..3c5f814de --- /dev/null +++ b/mmap/mips/yeeloong/uppermem.c @@ -0,0 +1,66 @@ +/* Compute amount of lower and upper memory till the first hole. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include +#include +#include + +grub_uint64_t +grub_mmap_get_lower (void) +{ + grub_uint64_t lower = 0; + + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, + grub_uint32_t type) + { + if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + return 0; + if (addr == 0) + lower = size; + return 0; + } + + grub_mmap_iterate (hook); + if (lower > GRUB_ARCH_LOWMEMMAXSIZE) + lower = GRUB_ARCH_LOWMEMMAXSIZE; + return lower; +} + +grub_uint64_t +grub_mmap_get_upper (void) +{ + grub_uint64_t upper = 0; + + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, + grub_uint32_t type) + { + if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + return 0; + if (addr <= GRUB_ARCH_HIGHMEMPSTART && addr + size + > GRUB_ARCH_HIGHMEMPSTART) + upper = addr + size - GRUB_ARCH_HIGHMEMPSTART; + return 0; + } + + grub_mmap_iterate (hook); + return upper; +} diff --git a/mmap/mmap.c b/mmap/mmap.c index 7598cf501..a1afc8b06 100644 --- a/mmap/mmap.c +++ b/mmap/mmap.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE @@ -52,7 +53,7 @@ grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, #ifdef GRUB_MACHINE_MEMORY_AVAILABLE [GRUB_MACHINE_MEMORY_AVAILABLE] = 1, #endif -#ifdef GRUB_MACHINE_MEMORY_RESERVED +#if defined (GRUB_MACHINE_MEMORY_RESERVED) && GRUB_MACHINE_MEMORY_RESERVED != GRUB_MACHINE_MEMORY_HOLE [GRUB_MACHINE_MEMORY_RESERVED] = 3, #endif #ifdef GRUB_MACHINE_MEMORY_ACPI @@ -414,8 +415,8 @@ static grub_command_t cmd; GRUB_MOD_INIT(mmap) { cmd = grub_register_command ("badram", grub_cmd_badram, - "badram ADDR1,MASK1[,ADDR2,MASK2[,...]]", - "declare memory regions as badram"); + N_("ADDR1,MASK1[,ADDR2,MASK2[,...]]"), + N_("Declare memory regions as badram.")); } GRUB_MOD_FINI(mmap) diff --git a/normal/auth.c b/normal/auth.c index c71262584..156b84c37 100644 --- a/normal/auth.c +++ b/normal/auth.c @@ -23,6 +23,7 @@ #include #include #include +#include struct grub_auth_user { @@ -35,58 +36,6 @@ struct grub_auth_user struct grub_auth_user *users = NULL; -int -grub_auth_strcmp (const char *s1, const char *s2) -{ - int ret; - grub_uint64_t end; - - end = grub_get_time_ms () + 100; - ret = grub_strcmp (s1, s2); - - /* This prevents an attacker from deriving information about the - password from the time it took to execute this function. */ - while (grub_get_time_ms () < end); - - return ret; -} - -static int -grub_iswordseparator (int c) -{ - return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&'); -} - -int -grub_auth_strword (const char *haystack, const char *needle) -{ - const char *n_pos = needle; - int found = 0; - - while (grub_iswordseparator (*haystack)) - haystack++; - - while (*haystack) - { - int ok = 1; - /* Crawl both the needle and the haystack word we're on. */ - while(*haystack && !grub_iswordseparator (*haystack)) - { - if (*haystack == *n_pos && ok) - n_pos++; - else - ok = 0; - - haystack++; - } - - if (ok) - found = 1; - } - - return found; -} - grub_err_t grub_auth_register_authentication (const char *user, grub_auth_callback_t callback, @@ -193,8 +142,8 @@ is_authenticated (const char *userlist) return 0; name = ((struct grub_auth_user *) item)->name; - return (userlist && grub_auth_strword (userlist, name)) - || grub_auth_strword (superusers, name); + return (userlist && grub_strword (userlist, name)) + || grub_strword (superusers, name); } superusers = grub_env_get ("superusers"); @@ -205,6 +154,49 @@ is_authenticated (const char *userlist) return grub_list_iterate (GRUB_AS_LIST (users), hook); } +static int +grub_username_get (char buf[], unsigned buf_size) +{ + unsigned cur_len = 0; + int key; + + while (1) + { + key = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + if (key == '\n' || key == '\r') + break; + + if (key == '\e') + { + cur_len = 0; + break; + } + + if (key == '\b') + { + cur_len--; + grub_printf ("\b"); + continue; + } + + if (!grub_isprint (key)) + continue; + + if (cur_len + 2 < buf_size) + { + buf[cur_len++] = key; + grub_putchar (key); + } + } + + grub_memset (buf + cur_len, 0, buf_size - cur_len); + + grub_putchar ('\n'); + grub_refresh (); + + return (key != '\e'); +} + grub_err_t grub_auth_check_authentication (const char *userlist) { @@ -212,11 +204,12 @@ grub_auth_check_authentication (const char *userlist) struct grub_auth_user *cur = NULL; grub_err_t err; static unsigned long punishment_delay = 1; + char entered[GRUB_AUTH_MAX_PASSLEN]; auto int hook (grub_list_t item); int hook (grub_list_t item) { - if (grub_auth_strcmp (login, ((struct grub_auth_user *) item)->name) == 0) + if (grub_strcmp (login, ((struct grub_auth_user *) item)->name) == 0) cur = (struct grub_auth_user *) item; return 0; } @@ -237,26 +230,22 @@ grub_auth_check_authentication (const char *userlist) return GRUB_ERR_NONE; } - if (!grub_cmdline_get ("Enter username: ", login, sizeof (login) - 1, - 0, 0, 0)) + grub_puts_ (N_("Enter username: ")); + + if (!grub_username_get (login, sizeof (login) - 1)) + goto access_denied; + + grub_puts_ (N_("Enter password: ")); + + if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN)) goto access_denied; grub_list_iterate (GRUB_AS_LIST (users), hook); if (!cur || ! cur->callback) - { - grub_list_iterate (GRUB_AS_LIST (users), hook_any); + goto access_denied; - /* No users present at all. */ - if (!cur) - goto access_denied; - - /* Display any of available authentication schemes. */ - err = cur->callback (login, 0); - - goto access_denied; - } - err = cur->callback (login, cur->arg); + err = cur->callback (login, entered, cur->arg); if (is_authenticated (userlist)) { punishment_delay = 1; diff --git a/normal/autofs.c b/normal/autofs.c index ce354a22c..e1d4c017c 100644 --- a/normal/autofs.c +++ b/normal/autofs.c @@ -38,6 +38,9 @@ autoload_fs_module (void) if (! grub_dl_get (p->name) && grub_dl_load (p->name)) return 1; + if (grub_errno) + grub_print_error (); + fs_module_list = p->next; grub_free (p->name); grub_free (p); @@ -48,30 +51,35 @@ autoload_fs_module (void) /* Read the file fs.lst for auto-loading. */ void -read_fs_list (void) +read_fs_list (const char *prefix) { - const char *prefix; - static int first_time = 1; - - /* Make sure that this function does not get executed twice. */ - if (! first_time) - return; - first_time = 0; - - prefix = grub_env_get ("prefix"); if (prefix) { char *filename; - filename = grub_malloc (grub_strlen (prefix) + sizeof ("/fs.lst")); + filename = grub_xasprintf ("%s/fs.lst", prefix); if (filename) { grub_file_t file; + grub_fs_autoload_hook_t tmp_autoload_hook; + + /* This rules out the possibility that read_fs_list() is invoked + recursively when we call grub_file_open() below. */ + tmp_autoload_hook = grub_fs_autoload_hook; + grub_fs_autoload_hook = NULL; - grub_sprintf (filename, "%s/fs.lst", prefix); file = grub_file_open (filename); if (file) { + /* Override previous fs.lst. */ + while (fs_module_list) + { + grub_named_list_t tmp; + tmp = fs_module_list->next; + grub_free (fs_module_list); + fs_module_list = tmp; + } + while (1) { char *buf; @@ -113,6 +121,7 @@ read_fs_list (void) } grub_file_close (file); + grub_fs_autoload_hook = tmp_autoload_hook; } grub_free (filename); diff --git a/normal/cmdline.c b/normal/cmdline.c index 7a5b6ec84..05d665411 100644 --- a/normal/cmdline.c +++ b/normal/cmdline.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2009 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 @@ -26,11 +26,13 @@ #include #include #include +#include +#include -static char *kill_buf; +static grub_uint32_t *kill_buf; static int hist_size; -static char **hist_lines = 0; +static grub_uint32_t **hist_lines = 0; static int hist_pos = 0; static int hist_end = 0; static int hist_used = 0; @@ -38,8 +40,8 @@ static int hist_used = 0; grub_err_t grub_set_history (int newsize) { - char **old_hist_lines = hist_lines; - hist_lines = grub_malloc (sizeof (char *) * newsize); + grub_uint32_t **old_hist_lines = hist_lines; + hist_lines = grub_malloc (sizeof (grub_uint32_t *) * newsize); /* Copy the old lines into the new buffer. */ if (old_hist_lines) @@ -66,16 +68,16 @@ grub_set_history (int newsize) if (hist_pos < hist_end) grub_memmove (hist_lines, old_hist_lines + hist_pos, - (hist_end - hist_pos) * sizeof (char *)); + (hist_end - hist_pos) * sizeof (grub_uint32_t *)); else if (hist_used) { /* Copy the older part. */ grub_memmove (hist_lines, old_hist_lines + hist_pos, - (hist_size - hist_pos) * sizeof (char *)); + (hist_size - hist_pos) * sizeof (grub_uint32_t *)); /* Copy the newer part. */ grub_memmove (hist_lines + hist_size - hist_pos, old_hist_lines, - hist_end * sizeof (char *)); + hist_end * sizeof (grub_uint32_t *)); } } @@ -89,17 +91,43 @@ grub_set_history (int newsize) /* Get the entry POS from the history where `0' is the newest entry. */ -static char * +static grub_uint32_t * grub_history_get (int pos) { pos = (hist_pos + pos) % hist_size; return hist_lines[pos]; } +static grub_size_t +strlen_ucs4 (const grub_uint32_t *s) +{ + const grub_uint32_t *p = s; + + while (*p) + p++; + + return p - s; +} + +/* Replace the history entry on position POS with the string S. */ +static void +grub_history_set (int pos, grub_uint32_t *s, grub_size_t len) +{ + grub_free (hist_lines[pos]); + hist_lines[pos] = grub_malloc ((len + 1) * sizeof (grub_uint32_t)); + if (!hist_lines[pos]) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return ; + } + grub_memcpy (hist_lines[pos], s, len * sizeof (grub_uint32_t)); + hist_lines[pos][len] = 0; +} /* Insert a new history line S on the top of the history. */ static void -grub_history_add (char *s) +grub_history_add (grub_uint32_t *s, grub_size_t len) { /* Remove the oldest entry in the history to make room for a new entry. */ @@ -120,16 +148,15 @@ grub_history_add (char *s) hist_pos = hist_size + hist_pos; /* Insert into history. */ - hist_lines[hist_pos] = grub_strdup (s); + hist_lines[hist_pos] = NULL; + grub_history_set (hist_pos, s, len); } /* Replace the history entry on position POS with the string S. */ static void -grub_history_replace (int pos, char *s) +grub_history_replace (int pos, grub_uint32_t *s, grub_size_t len) { - pos = (hist_pos + pos) % hist_size; - grub_free (hist_lines[pos]); - hist_lines[pos] = grub_strdup (s); + grub_history_set ((hist_pos + pos) % hist_size, s, len); } /* A completion hook to print items. */ @@ -139,31 +166,30 @@ print_completion (const char *item, grub_completion_type_t type, int count) if (count == 0) { /* If this is the first time, print a label. */ - const char *what; - + + grub_puts (""); switch (type) { case GRUB_COMPLETION_TYPE_COMMAND: - what = "commands"; + grub_puts_ (N_("Possible commands are:")); break; case GRUB_COMPLETION_TYPE_DEVICE: - what = "devices"; + grub_puts_ (N_("Possible devices are:")); break; case GRUB_COMPLETION_TYPE_FILE: - what = "files"; + grub_puts_ (N_("Possible files are:")); break; case GRUB_COMPLETION_TYPE_PARTITION: - what = "partitions"; + grub_puts_ (N_("Possible partitions are:")); break; case GRUB_COMPLETION_TYPE_ARGUMENT: - what = "arguments"; + grub_puts_ (N_("Possible arguments are:")); break; default: - what = "things"; + grub_puts_ (N_("Possible things are:")); break; } - - grub_printf ("\nPossible %s are:\n", what); + grub_puts (""); } if (type == GRUB_COMPLETION_TYPE_PARTITION) @@ -175,74 +201,113 @@ print_completion (const char *item, grub_completion_type_t type, int count) grub_printf (" %s", item); } -/* Get a command-line. If ECHO_CHAR is not zero, echo it instead of input - characters. If READLINE is non-zero, readline-like key bindings are - available. If ESC is pushed, return zero, otherwise return non-zero. */ -/* FIXME: The dumb interface is not supported yet. */ -int -grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, - int echo_char, int readline, int history) +struct cmdline_term +{ + unsigned xpos, ypos, ystart, width, height; + struct grub_term_output *term; +}; + +/* Get a command-line. If ESC is pushed, return zero, + otherwise return command line. */ +/* FIXME: The dumb interface is not supported yet. */ +char * +grub_cmdline_get (const char *prompt) { - unsigned xpos, ypos, ystart; grub_size_t lpos, llen; grub_size_t plen; - char buf[max_len]; + grub_uint32_t *buf; + grub_size_t max_len = 256; int key; int histpos = 0; - auto void cl_insert (const char *str); + auto void cl_insert (const grub_uint32_t *str); auto void cl_delete (unsigned len); - auto void cl_print (int pos, int c); - auto void cl_set_pos (void); + auto inline void __attribute__ ((always_inline)) cl_print (struct cmdline_term *cl_term, int pos, + grub_uint32_t c); + auto void cl_set_pos (struct cmdline_term *cl_term); + auto void cl_print_all (int pos, grub_uint32_t c); + auto void cl_set_pos_all (void); + auto void init_clterm (struct cmdline_term *cl_term_cur); + auto void init_clterm_all (void); + const char *prompt_translated = _(prompt); + struct cmdline_term *cl_terms; + char *ret; + unsigned nterms; - void cl_set_pos (void) + void cl_set_pos (struct cmdline_term *cl_term) + { + cl_term->xpos = (plen + lpos) % (cl_term->width - 1); + cl_term->ypos = cl_term->ystart + (plen + lpos) / (cl_term->width - 1); + grub_term_gotoxy (cl_term->term, cl_term->xpos, cl_term->ypos); + } + + void cl_set_pos_all () + { + unsigned i; + for (i = 0; i < nterms; i++) + cl_set_pos (&cl_terms[i]); + } + + inline void __attribute__ ((always_inline)) cl_print (struct cmdline_term *cl_term, int pos, grub_uint32_t c) { - xpos = (plen + lpos) % 79; - ypos = ystart + (plen + lpos) / 79; - grub_gotoxy (xpos, ypos); + grub_uint32_t *p; - grub_refresh (); - } - - void cl_print (int pos, int c) - { - char *p; - - for (p = buf + pos; *p; p++) + for (p = buf + pos; p < buf + llen; p++) { - if (xpos++ > 78) - { - grub_putchar ('\n'); - - xpos = 1; - if (ypos == (unsigned) (grub_getxy () & 0xFF)) - ystart--; - else - ypos++; - } - if (c) - grub_putchar (c); + grub_putcode (c, cl_term->term); else - grub_putchar (*p); + grub_putcode (*p, cl_term->term); + cl_term->xpos++; + if (cl_term->xpos >= cl_term->width - 1) + { + cl_term->xpos = 0; + if (cl_term->ypos >= (unsigned) (cl_term->height - 1)) + cl_term->ystart--; + else + cl_term->ypos++; + grub_putcode ('\n', cl_term->term); + } } } - void cl_insert (const char *str) + void cl_print_all (int pos, grub_uint32_t c) + { + unsigned i; + for (i = 0; i < nterms; i++) + cl_print (&cl_terms[i], pos, c); + } + + void cl_insert (const grub_uint32_t *str) { - grub_size_t len = grub_strlen (str); + grub_size_t len = strlen_ucs4 (str); + + if (len + llen >= max_len) + { + grub_uint32_t *nbuf; + max_len *= 2; + nbuf = grub_realloc (buf, sizeof (grub_uint32_t) * max_len); + if (nbuf) + buf = nbuf; + else + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + max_len /= 2; + } + } if (len + llen < max_len) { - grub_memmove (buf + lpos + len, buf + lpos, llen - lpos + 1); - grub_memmove (buf + lpos, str, len); + grub_memmove (buf + lpos + len, buf + lpos, + (llen - lpos + 1) * sizeof (grub_uint32_t)); + grub_memmove (buf + lpos, str, len * sizeof (grub_uint32_t)); llen += len; + cl_set_pos_all (); + cl_print_all (lpos, 0); lpos += len; - cl_print (lpos - len, echo_char); - cl_set_pos (); + cl_set_pos_all (); } - - grub_refresh (); } void cl_delete (unsigned len) @@ -252,182 +317,270 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, grub_size_t saved_lpos = lpos; lpos = llen - len; - cl_set_pos (); - cl_print (lpos, ' '); + cl_set_pos_all (); + cl_print_all (lpos, ' '); lpos = saved_lpos; - cl_set_pos (); + cl_set_pos_all (); - grub_memmove (buf + lpos, buf + lpos + len, llen - lpos + 1); + grub_memmove (buf + lpos, buf + lpos + len, + sizeof (grub_uint32_t) * (llen - lpos + 1)); llen -= len; - cl_print (lpos, echo_char); - cl_set_pos (); + cl_print_all (lpos, 0); + cl_set_pos_all (); } - - grub_refresh (); } - plen = grub_strlen (prompt); + void init_clterm (struct cmdline_term *cl_term_cur) + { + cl_term_cur->xpos = plen; + cl_term_cur->ypos = (grub_term_getxy (cl_term_cur->term) & 0xFF); + cl_term_cur->ystart = cl_term_cur->ypos; + cl_term_cur->width = grub_term_width (cl_term_cur->term); + cl_term_cur->height = grub_term_height (cl_term_cur->term); + } + + void init_clterm_all (void) + { + unsigned i; + for (i = 0; i < nterms; i++) + init_clterm (&cl_terms[i]); + } + + buf = grub_malloc (max_len * sizeof (grub_uint32_t)); + if (!buf) + return 0; + + plen = grub_strlen (prompt_translated) + sizeof (" ") - 1; lpos = llen = 0; buf[0] = '\0'; - if ((grub_getxy () >> 8) != 0) - grub_putchar ('\n'); + { + grub_term_output_t term; - grub_printf ("%s", prompt); + FOR_ACTIVE_TERM_OUTPUTS(term) + if ((grub_term_getxy (term) >> 8) != 0) + grub_putcode ('\n', term); + } + grub_printf ("%s ", prompt_translated); - xpos = plen; - ystart = ypos = (grub_getxy () & 0xFF); + { + struct cmdline_term *cl_term_cur; + struct grub_term_output *cur; + nterms = 0; + FOR_ACTIVE_TERM_OUTPUTS(cur) + nterms++; - cl_insert (cmdline); + cl_terms = grub_malloc (sizeof (cl_terms[0]) * nterms); + if (!cl_terms) + return 0; + cl_term_cur = cl_terms; + FOR_ACTIVE_TERM_OUTPUTS(cur) + { + cl_term_cur->term = cur; + init_clterm (cl_term_cur); + cl_term_cur++; + } + } - if (history && hist_used == 0) - grub_history_add (buf); + if (hist_used == 0) + grub_history_add (buf, llen); + + grub_refresh (); while ((key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && key != '\r') { - if (readline) - { - switch (key) - { - case 1: /* Ctrl-a */ - lpos = 0; - cl_set_pos (); - break; - - case 2: /* Ctrl-b */ - if (lpos > 0) - { - lpos--; - cl_set_pos (); - } - break; - - case 5: /* Ctrl-e */ - lpos = llen; - cl_set_pos (); - break; - - case 6: /* Ctrl-f */ - if (lpos < llen) - { - lpos++; - cl_set_pos (); - } - break; - - case 9: /* Ctrl-i or TAB */ - { - char *insert; - int restore; - - /* Backup the next character and make it 0 so it will - be easy to use string functions. */ - char backup = buf[lpos]; - buf[lpos] = '\0'; - - - insert = grub_normal_do_completion (buf, &restore, - print_completion); - /* Restore the original string. */ - buf[lpos] = backup; - - if (restore) - { - /* Restore the prompt. */ - grub_printf ("\n%s%s", prompt, buf); - xpos = plen; - ystart = ypos = (grub_getxy () & 0xFF); - } - - if (insert) - { - cl_insert (insert); - grub_free (insert); - } - } - break; - - case 11: /* Ctrl-k */ - if (lpos < llen) - { - if (kill_buf) - grub_free (kill_buf); - - kill_buf = grub_strdup (buf + lpos); - grub_errno = GRUB_ERR_NONE; - - cl_delete (llen - lpos); - } - break; - - case 14: /* Ctrl-n */ - { - char *hist; - - lpos = 0; - - if (histpos > 0) - { - grub_history_replace (histpos, buf); - histpos--; - } - - cl_delete (llen); - hist = grub_history_get (histpos); - cl_insert (hist); - - break; - } - case 16: /* Ctrl-p */ - { - char *hist; - - lpos = 0; - - if (histpos < hist_used - 1) - { - grub_history_replace (histpos, buf); - histpos++; - } - - cl_delete (llen); - hist = grub_history_get (histpos); - - cl_insert (hist); - } - break; - - case 21: /* Ctrl-u */ - if (lpos > 0) - { - grub_size_t n = lpos; - - if (kill_buf) - grub_free (kill_buf); - - kill_buf = grub_malloc (n + 1); - grub_errno = GRUB_ERR_NONE; - if (kill_buf) - { - grub_memcpy (kill_buf, buf, n); - kill_buf[n] = '\0'; - } - - lpos = 0; - cl_set_pos (); - cl_delete (n); - } - break; - - case 25: /* Ctrl-y */ - if (kill_buf) - cl_insert (kill_buf); - break; - } - } - switch (key) { + case 1: /* Ctrl-a */ + lpos = 0; + cl_set_pos_all (); + break; + + case 2: /* Ctrl-b */ + if (lpos > 0) + { + lpos--; + cl_set_pos_all (); + } + break; + + case 5: /* Ctrl-e */ + lpos = llen; + cl_set_pos_all (); + break; + + case 6: /* Ctrl-f */ + if (lpos < llen) + { + lpos++; + cl_set_pos_all (); + } + break; + + case 9: /* Ctrl-i or TAB */ + { + int restore; + char *insertu8; + char *bufu8; + grub_uint32_t c; + + c = buf[lpos]; + buf[lpos] = '\0'; + + bufu8 = grub_ucs4_to_utf8_alloc (buf, lpos); + buf[lpos] = c; + if (!bufu8) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + break; + } + + insertu8 = grub_normal_do_completion (bufu8, &restore, + print_completion); + grub_free (bufu8); + + if (restore) + { + /* Restore the prompt. */ + grub_printf ("\n%s ", prompt_translated); + init_clterm_all (); + cl_print_all (0, 0); + } + + if (insertu8) + { + grub_size_t insertlen; + grub_ssize_t t; + grub_uint32_t *insert; + + insertlen = grub_strlen (insertu8); + insert = grub_malloc ((insertlen + 1) * sizeof (grub_uint32_t)); + if (!insert) + { + grub_free (insertu8); + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + break; + } + t = grub_utf8_to_ucs4 (insert, insertlen, + (grub_uint8_t *) insertu8, + insertlen, 0); + if (t > 0) + { + if (insert[t-1] == ' ' && buf[lpos] == ' ') + { + insert[t-1] = 0; + if (t != 1) + cl_insert (insert); + lpos++; + } + else + { + insert[t] = 0; + cl_insert (insert); + } + } + + grub_free (insertu8); + grub_free (insert); + } + cl_set_pos_all (); + } + break; + + case 11: /* Ctrl-k */ + if (lpos < llen) + { + if (kill_buf) + grub_free (kill_buf); + + kill_buf = grub_malloc ((llen - lpos + 1) + * sizeof (grub_uint32_t)); + if (grub_errno) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + else + { + grub_memcpy (kill_buf, buf + lpos, + (llen - lpos + 1) * sizeof (grub_uint32_t)); + kill_buf[llen - lpos] = 0; + } + + cl_delete (llen - lpos); + } + break; + + case 14: /* Ctrl-n */ + { + grub_uint32_t *hist; + + lpos = 0; + + if (histpos > 0) + { + grub_history_replace (histpos, buf, llen); + histpos--; + } + + cl_delete (llen); + hist = grub_history_get (histpos); + cl_insert (hist); + + break; + } + case 16: /* Ctrl-p */ + { + grub_uint32_t *hist; + + lpos = 0; + + if (histpos < hist_used - 1) + { + grub_history_replace (histpos, buf, llen); + histpos++; + } + + cl_delete (llen); + hist = grub_history_get (histpos); + + cl_insert (hist); + } + break; + + case 21: /* Ctrl-u */ + if (lpos > 0) + { + grub_size_t n = lpos; + + if (kill_buf) + grub_free (kill_buf); + + kill_buf = grub_malloc (n + 1); + if (grub_errno) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + if (kill_buf) + { + grub_memcpy (kill_buf, buf, n); + kill_buf[n] = '\0'; + } + + lpos = 0; + cl_set_pos_all (); + cl_delete (n); + } + break; + + case 25: /* Ctrl-y */ + if (kill_buf) + cl_insert (kill_buf); + break; + case '\e': return 0; @@ -435,7 +588,7 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, if (lpos > 0) { lpos--; - cl_set_pos (); + cl_set_pos_all (); } else break; @@ -449,7 +602,7 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, default: if (grub_isprint (key)) { - char str[2]; + grub_uint32_t str[2]; str[0] = key; str[1] = '\0'; @@ -457,28 +610,27 @@ grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len, } break; } + + grub_refresh (); } grub_putchar ('\n'); grub_refresh (); - /* If ECHO_CHAR is NUL, remove leading spaces. */ + /* Remove leading spaces. */ lpos = 0; - if (! echo_char) - while (buf[lpos] == ' ') - lpos++; + while (buf[lpos] == ' ') + lpos++; - if (history) + histpos = 0; + if (strlen_ucs4 (buf) > 0) { - histpos = 0; - if (grub_strlen (buf) > 0) - { - grub_history_replace (histpos, buf); - grub_history_add (""); - } + grub_uint32_t empty[] = { 0 }; + grub_history_replace (histpos, buf, llen); + grub_history_add (empty, 0); } - grub_memcpy (cmdline, buf + lpos, llen - lpos + 1); - - return 1; + ret = grub_ucs4_to_utf8_alloc (buf + lpos, llen - lpos + 1); + grub_free (buf); + return ret; } diff --git a/normal/color.c b/normal/color.c index 340e43a02..bae082911 100644 --- a/normal/color.c +++ b/normal/color.c @@ -20,6 +20,7 @@ #include #include #include +#include /* Borrowed from GRUB Legacy */ static char *color_list[16] = @@ -76,7 +77,7 @@ grub_parse_color_name_pair (grub_uint8_t *ret, const char *name) bg_name = grub_strchr (fg_name, '/'); if (bg_name == NULL) { - grub_printf ("Warning: syntax error (missing slash) in `%s'\n", fg_name); + grub_printf_ (N_("Warning: syntax error (missing slash) in `%s'\n"), fg_name); grub_wait_after_message (); goto free_and_return; } @@ -85,13 +86,13 @@ grub_parse_color_name_pair (grub_uint8_t *ret, const char *name) if (parse_color_name (&fg, fg_name) == -1) { - grub_printf ("Warning: invalid foreground color `%s'\n", fg_name); + grub_printf_ (N_("Warning: invalid foreground color `%s'\n"), fg_name); grub_wait_after_message (); goto free_and_return; } if (parse_color_name (&bg, bg_name) == -1) { - grub_printf ("Warning: invalid background color `%s'\n", bg_name); + grub_printf_ (N_("Warning: invalid background color `%s'\n"), bg_name); grub_wait_after_message (); goto free_and_return; } @@ -102,23 +103,31 @@ free_and_return: grub_free (fg_name); } +static grub_uint8_t color_normal, color_highlight; + +static void +set_colors (void) +{ + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + /* Reloads terminal `normal' and `highlight' colors. */ + grub_term_setcolor (term, color_normal, color_highlight); + + /* Propagates `normal' color to terminal current color. */ + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); + } +} + /* Replace default `normal' colors with the ones specified by user (if any). */ char * grub_env_write_color_normal (struct grub_env_var *var __attribute__ ((unused)), const char *val) { - grub_uint8_t color_normal, color_highlight; - - /* Use old settings in case grub_parse_color_name_pair() has no effect. */ - grub_getcolor (&color_normal, &color_highlight); - grub_parse_color_name_pair (&color_normal, val); - /* Reloads terminal `normal' and `highlight' colors. */ - grub_setcolor (color_normal, color_highlight); - - /* Propagates `normal' color to terminal current color. */ - grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); + set_colors (); return grub_strdup (val); } @@ -128,21 +137,9 @@ char * grub_env_write_color_highlight (struct grub_env_var *var __attribute__ ((unused)), const char *val) { - grub_uint8_t color_normal, color_highlight; - - /* Use old settings in case grub_parse_color_name_pair() has no effect. */ - grub_getcolor (&color_normal, &color_highlight); - grub_parse_color_name_pair (&color_highlight, val); - /* Reloads terminal `normal' and `highlight' colors. */ - grub_setcolor (color_normal, color_highlight); - - /* Propagates `normal' color to terminal current color. - Note: Using GRUB_TERM_COLOR_NORMAL here rather than - GRUB_TERM_COLOR_HIGHLIGHT is intentional. We don't want to switch - to highlight state just because color was reloaded. */ - grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); + set_colors (); return grub_strdup (val); } diff --git a/normal/completion.c b/normal/completion.c index 4b38e334d..13e8f7a6b 100644 --- a/normal/completion.c +++ b/normal/completion.c @@ -1,7 +1,7 @@ /* completion.c - complete a command, a disk, a partition or a file */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009 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 @@ -107,17 +107,12 @@ iterate_partition (grub_disk_t disk, const grub_partition_t p) if (! partition_name) return 1; - name = grub_malloc (grub_strlen (disk_name) + 1 - + grub_strlen (partition_name) + 1); - if (! name) - { - grub_free (partition_name); - return 1; - } - - grub_sprintf (name, "%s,%s", disk_name, partition_name); + name = grub_xasprintf ("%s,%s", disk_name, partition_name); grub_free (partition_name); + if (! name) + return 1; + ret = add_completion (name, ")", GRUB_COMPLETION_TYPE_PARTITION); grub_free (name); return ret; @@ -141,11 +136,15 @@ iterate_dir (const char *filename, const struct grub_dirhook_info *info) } else if (grub_strcmp (filename, ".") && grub_strcmp (filename, "..")) { - char fname[grub_strlen (filename) + 2]; + char *fname; - grub_sprintf (fname, "%s/", filename); + fname = grub_xasprintf ("%s/", filename); if (add_completion (fname, "", GRUB_COMPLETION_TYPE_FILE)) - return 1; + { + grub_free (fname); + return 1; + } + grub_free (fname); } return 0; @@ -360,8 +359,9 @@ complete_arguments (char *command) if (!option->longarg) continue; - longarg = grub_malloc (grub_strlen (option->longarg)); - grub_sprintf (longarg, "--%s", option->longarg); + longarg = grub_xasprintf ("--%s", option->longarg); + if (!longarg) + return 1; if (add_completion (longarg, " ", GRUB_COMPLETION_TYPE_ARGUMENT)) { @@ -409,13 +409,16 @@ grub_normal_do_completion (char *buf, int *restore, if (grub_parser_split_cmdline (buf, 0, &argc, &argv)) return 0; - current_word = argv[argc]; + if (argc == 0) + current_word = ""; + else + current_word = argv[argc - 1]; /* Determine the state the command line is in, depending on the state, it can be determined how to complete. */ cmdline_state = get_state (buf); - if (argc == 0) + if (argc == 1 || argc == 0) { /* Complete a command. */ if (grub_command_iterate (iterate_command)) @@ -485,13 +488,15 @@ grub_normal_do_completion (char *buf, int *restore, goto fail; } - grub_free (argv[0]); + if (argc != 0) + grub_free (argv[0]); grub_free (match); return ret; } fail: - grub_free (argv[0]); + if (argc != 0) + grub_free (argv[0]); grub_free (match); grub_errno = GRUB_ERR_NONE; diff --git a/normal/context.c b/normal/context.c new file mode 100644 index 000000000..27adf287a --- /dev/null +++ b/normal/context.c @@ -0,0 +1,183 @@ +/* env.c - Environment variables */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2005,2006,2007,2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +struct menu_pointer +{ + grub_menu_t menu; + struct menu_pointer *prev; +}; + +struct menu_pointer initial_menu; +struct menu_pointer *current_menu = &initial_menu; + +void +grub_env_unset_menu (void) +{ + current_menu->menu = NULL; +} + +grub_menu_t +grub_env_get_menu (void) +{ + return current_menu->menu; +} + +void +grub_env_set_menu (grub_menu_t nmenu) +{ + current_menu->menu = nmenu; +} + +grub_err_t +grub_env_context_open (int export) +{ + struct grub_env_context *context; + int i; + struct menu_pointer *menu; + + context = grub_zalloc (sizeof (*context)); + if (! context) + return grub_errno; + menu = grub_zalloc (sizeof (*menu)); + if (! menu) + return grub_errno; + + context->prev = grub_current_context; + grub_current_context = context; + + menu->prev = current_menu; + current_menu = menu; + + /* Copy exported variables. */ + for (i = 0; i < HASHSZ; i++) + { + struct grub_env_var *var; + + for (var = context->prev->vars[i]; var; var = var->next) + { + if (export && var->global) + { + if (grub_env_set (var->name, var->value) != GRUB_ERR_NONE) + { + grub_env_context_close (); + return grub_errno; + } + grub_env_export (var->name); + grub_register_variable_hook (var->name, var->read_hook, var->write_hook); + } + } + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_env_context_close (void) +{ + struct grub_env_context *context; + int i; + struct menu_pointer *menu; + + if (! grub_current_context->prev) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "cannot close the initial context"); + + /* Free the variables associated with this context. */ + for (i = 0; i < HASHSZ; i++) + { + struct grub_env_var *p, *q; + + for (p = grub_current_context->vars[i]; p; p = q) + { + q = p->next; + grub_free (p->name); + grub_free (p->value); + grub_free (p); + } + } + + /* Restore the previous context. */ + context = grub_current_context->prev; + grub_free (grub_current_context); + grub_current_context = context; + + menu = current_menu->prev; + grub_free (current_menu); + current_menu = menu; + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_env_export (const char *name) +{ + struct grub_env_var *var; + + var = grub_env_find (name); + if (! var) + { + grub_err_t err; + + err = grub_env_set (name, ""); + if (err) + return err; + var = grub_env_find (name); + } + var->global = 1; + + return GRUB_ERR_NONE; +} + +static grub_command_t export_cmd; + +static grub_err_t +grub_cmd_export (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "no environment variable specified"); + + grub_env_export (args[0]); + return 0; +} + +void +grub_context_init (void) +{ + grub_env_export ("root"); + grub_env_export ("prefix"); + + export_cmd = grub_register_command ("export", grub_cmd_export, + N_("ENVVAR"), N_("Export a variable.")); +} + +void +grub_context_fini (void) +{ + grub_unregister_command (export_cmd); +} diff --git a/normal/crypto.c b/normal/crypto.c new file mode 100644 index 000000000..465c9f81d --- /dev/null +++ b/normal/crypto.c @@ -0,0 +1,151 @@ +/* crypto.c - support crypto autoload */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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 . + */ + +#include +#include +#include +#include +#include +#include + +struct load_spec +{ + struct load_spec *next; + char *name; + char *modname; +}; + +struct load_spec *crypto_specs = NULL; + +static void +grub_crypto_autoload (const char *name) +{ + struct load_spec *cur; + grub_dl_t mod; + + for (cur = crypto_specs; cur; cur = cur->next) + if (grub_strcasecmp (name, cur->name) == 0) + { + mod = grub_dl_load (cur->modname); + if (mod) + grub_dl_ref (mod); + grub_errno = GRUB_ERR_NONE; + } +} + +static void +grub_crypto_spec_free (void) +{ + struct load_spec *cur, *next; + for (cur = crypto_specs; cur; cur = next) + { + next = cur->next; + grub_free (cur->name); + grub_free (cur->modname); + grub_free (cur); + } + crypto_specs = NULL; +} + + +/* Read the file crypto.lst for auto-loading. */ +void +read_crypto_list (const char *prefix) +{ + char *filename; + grub_file_t file; + char *buf = NULL; + + if (!prefix) + { + grub_errno = GRUB_ERR_NONE; + return; + } + + filename = grub_xasprintf ("%s/crypto.lst", prefix); + if (!filename) + { + grub_errno = GRUB_ERR_NONE; + return; + } + + file = grub_file_open (filename); + grub_free (filename); + if (!file) + { + grub_errno = GRUB_ERR_NONE; + return; + } + + /* Override previous crypto.lst. */ + grub_crypto_spec_free (); + + for (;; grub_free (buf)) + { + char *p, *name; + struct load_spec *cur; + + buf = grub_file_getline (file); + + if (! buf) + break; + + name = buf; + + p = grub_strchr (name, ':'); + if (! p) + continue; + + *p = '\0'; + while (*++p == ' ') + ; + + cur = grub_malloc (sizeof (*cur)); + if (!cur) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + + cur->name = grub_strdup (name); + if (! name) + { + grub_errno = GRUB_ERR_NONE; + grub_free (cur); + continue; + } + + cur->modname = grub_strdup (p); + if (! cur->modname) + { + grub_errno = GRUB_ERR_NONE; + grub_free (cur); + grub_free (cur->name); + continue; + } + cur->next = crypto_specs; + crypto_specs = cur; + } + + grub_file_close (file); + + grub_errno = GRUB_ERR_NONE; + + grub_crypto_autoload_hook = grub_crypto_autoload; +} diff --git a/normal/dyncmd.c b/normal/dyncmd.c index dc530b07b..a3cafa514 100644 --- a/normal/dyncmd.c +++ b/normal/dyncmd.c @@ -23,6 +23,7 @@ #include #include #include +#include static grub_err_t grub_dyncmd_dispatcher (struct grub_command *cmd, @@ -59,31 +60,39 @@ grub_dyncmd_dispatcher (struct grub_command *cmd, /* Read the file command.lst for auto-loading. */ void -read_command_list (void) +read_command_list (const char *prefix) { - const char *prefix; - static int first_time = 1; - - /* Make sure that this function does not get executed twice. */ - if (! first_time) - return; - first_time = 0; - - prefix = grub_env_get ("prefix"); if (prefix) { char *filename; - filename = grub_malloc (grub_strlen (prefix) + sizeof ("/command.lst")); + filename = grub_xasprintf ("%s/command.lst", prefix); if (filename) { grub_file_t file; - grub_sprintf (filename, "%s/command.lst", prefix); file = grub_file_open (filename); if (file) { char *buf = NULL; + grub_command_t ptr, last = 0, next; + + /* Override previous commands.lst. */ + for (ptr = grub_command_list; ptr; ptr = next) + { + next = ptr->next; + if (ptr->func == grub_dyncmd_dispatcher) + { + if (last) + last->next = ptr->next; + else + grub_command_list = ptr->next; + grub_free (ptr); + } + else + last = ptr; + } + for (;; grub_free (buf)) { char *p, *name, *modname; @@ -132,7 +141,7 @@ read_command_list (void) cmd = grub_register_command_prio (name, grub_dyncmd_dispatcher, - 0, "not loaded", prio); + 0, N_("not loaded"), prio); if (! cmd) { grub_free (name); diff --git a/normal/handler.c b/normal/handler.c index eb19f912f..686626929 100644 --- a/normal/handler.c +++ b/normal/handler.c @@ -117,7 +117,7 @@ insert_handler (char *name, char *module) data = 0; item->cmd = grub_register_command (item->name, grub_handler_cmd, 0, - "Set active handler"); + "Set active handler."); if (! item->cmd) { grub_free (data); @@ -172,12 +172,11 @@ read_handler_list (void) { char *filename; - filename = grub_malloc (grub_strlen (prefix) + sizeof ("/handler.lst")); + filename = grub_xasprintf ("%s/handler.lst", prefix); if (filename) { grub_file_t file; - grub_sprintf (filename, "%s/handler.lst", prefix); file = grub_file_open (filename); if (file) { diff --git a/normal/main.c b/normal/main.c index f080a6971..4ed17e82c 100644 --- a/normal/main.c +++ b/normal/main.c @@ -30,9 +30,13 @@ #include #include #include +#include #define GRUB_DEFAULT_HISTORY_SIZE 50 +static int nested_level = 0; +int grub_normal_exit_level = 0; + /* Read a line from the file FILE. */ char * grub_file_getline (grub_file_t file) @@ -133,7 +137,7 @@ free_menu (grub_menu_t menu) } grub_free (menu); - grub_env_unset_data_slot ("menu"); + grub_env_unset_menu (); } static void @@ -151,6 +155,17 @@ free_menu_entry_classes (struct grub_menu_entry_class *head) } } +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. */ @@ -167,6 +182,7 @@ grub_normal_add_menu_entry (int argc, const char **args, 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)); @@ -174,7 +190,7 @@ grub_normal_add_menu_entry (int argc, const char **args, return grub_errno; classes_tail = classes_head; - menu = grub_env_get_data_slot ("menu"); + menu = grub_env_get_menu (); if (! menu) return grub_error (GRUB_ERR_MENU, "no menu context"); @@ -233,6 +249,32 @@ grub_normal_add_menu_entry (int argc, const char **args, 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. */ @@ -289,6 +331,7 @@ grub_normal_add_menu_entry (int argc, const char **args, } (*last)->title = menutitle; + (*last)->hotkey = hotkey; (*last)->classes = classes_head; if (users) (*last)->restricted = 1; @@ -357,14 +400,14 @@ read_config_file (const char *config) grub_menu_t newmenu; - newmenu = grub_env_get_data_slot ("menu"); + newmenu = grub_env_get_menu (); if (! newmenu) { newmenu = grub_zalloc (sizeof (*newmenu)); if (! newmenu) return 0; - grub_env_set_data_slot ("menu", newmenu); + grub_env_set_menu (newmenu); } /* Try to open the config file. */ @@ -372,7 +415,21 @@ read_config_file (const char *config) if (! file) return 0; - grub_reader_loop (getline); + while (1) + { + char *line; + + /* Print an error, if any. */ + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + + if ((getline (&line, 0)) || (! line)) + break; + + grub_parser_get_current ()->parse_line (line, getline); + grub_free (line); + } + grub_file_close (file); if (old_parser) @@ -383,27 +440,55 @@ read_config_file (const char *config) /* Initialize the screen. */ void -grub_normal_init_page (void) +grub_normal_init_page (struct grub_term_output *term) { - grub_uint8_t width, margin; + int msg_len; + int posx; + const char *msg = _("GNU GRUB version %s"); + char *msg_formatted; + grub_uint32_t *unicode_msg; + grub_uint32_t *last_position; + + grub_term_cls (term); -#define TITLE ("GNU GRUB version " PACKAGE_VERSION) + msg_formatted = grub_xasprintf (msg, PACKAGE_VERSION); + if (!msg_formatted) + return; + + msg_len = grub_utf8_to_ucs4_alloc (msg_formatted, + &unicode_msg, &last_position); + grub_free (msg_formatted); + + if (msg_len < 0) + { + return; + } - width = grub_getwh () >> 8; - margin = (width - (sizeof(TITLE) + 7)) / 2; + posx = grub_getstringwidth (unicode_msg, last_position, term); + posx = (grub_term_width (term) - posx) / 2; + grub_term_gotoxy (term, posx, 1); - grub_cls (); - grub_putchar ('\n'); - - while (margin--) - grub_putchar (' '); - - grub_printf ("%s\n\n", TITLE); - -#undef TITLE + grub_print_ucs4 (unicode_msg, last_position, term); + grub_printf("\n\n"); + grub_free (unicode_msg); } -static int reader_nested; +static void +read_lists (const char *val) +{ + read_command_list (val); + read_fs_list (val); + read_crypto_list (val); + read_terminal_list (val); +} + +static char * +read_lists_hook (struct grub_env_var *var __attribute__ ((unused)), + const char *val) +{ + read_lists (val); + return val ? grub_strdup (val) : NULL; +} /* Read the config file CONFIG and execute the menu interface or the command line interface if BATCH is false. */ @@ -411,14 +496,13 @@ void grub_normal_execute (const char *config, int nested, int batch) { grub_menu_t menu = 0; + const char *prefix = grub_env_get ("prefix"); - read_command_list (); - read_fs_list (); + read_lists (prefix); read_handler_list (); + grub_register_variable_hook ("prefix", NULL, read_lists_hook); grub_command_execute ("parser.grub", 0, 0); - reader_nested = nested; - if (config) { menu = read_config_file (config); @@ -431,7 +515,7 @@ grub_normal_execute (const char *config, int nested, int batch) { if (menu && menu->size) { - grub_menu_viewer_show_menu (menu, nested); + grub_show_menu (menu, nested); if (nested) free_menu (menu); } @@ -442,31 +526,33 @@ grub_normal_execute (const char *config, int nested, int batch) void grub_enter_normal_mode (const char *config) { + nested_level++; grub_normal_execute (config, 0, 0); + grub_cmdline_run (0); + nested_level--; + if (grub_normal_exit_level) + grub_normal_exit_level--; } /* Enter normal mode from rescue mode. */ static grub_err_t -grub_cmd_normal (struct grub_command *cmd, +grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), int argc, char *argv[]) { - grub_unregister_command (cmd); - if (argc == 0) { /* Guess the config filename. It is necessary to make CONFIG static, so that it won't get broken by longjmp. */ - static char *config; + char *config; const char *prefix; prefix = grub_env_get ("prefix"); if (prefix) { - config = grub_malloc (grub_strlen (prefix) + sizeof ("/grub.cfg")); + config = grub_xasprintf ("%s/grub.cfg", prefix); if (! config) goto quit; - grub_sprintf (config, "%s/grub.cfg", prefix); grub_enter_normal_mode (config); grub_free (config); } @@ -480,10 +566,89 @@ quit: return 0; } +/* Exit from normal mode to rescue mode. */ +static grub_err_t +grub_cmd_normal_exit (struct grub_command *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char *argv[] __attribute__ ((unused))) +{ + if (nested_level <= grub_normal_exit_level) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in normal environment"); + grub_normal_exit_level++; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_normal_reader_init (int nested) +{ + struct grub_term_output *term; + const char *msg = _("Minimal BASH-like line editing is supported. For " + "the first word, TAB lists possible command completions. Anywhere " + "else TAB lists possible device or file completions. %s"); + const char *msg_esc = _("ESC at any time exits."); + char *msg_formatted; + + msg_formatted = grub_xasprintf (msg, nested ? msg_esc : ""); + if (!msg_formatted) + return grub_errno; + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + grub_normal_init_page (term); + grub_term_setcursor (term, 1); + + grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term); + grub_puts ("\n"); + } + grub_free (msg_formatted); + + return 0; +} + + +static grub_err_t +grub_normal_read_line_real (char **line, int cont, int nested) +{ + grub_parser_t parser = grub_parser_get_current (); + char *prompt; + + if (cont) + prompt = grub_xasprintf (">"); + else + prompt = grub_xasprintf ("%s>", parser->name); + + if (!prompt) + return grub_errno; + + while (1) + { + *line = grub_cmdline_get (prompt); + if (*line) + break; + + if (cont || nested) + { + grub_free (*line); + grub_free (prompt); + *line = 0; + return grub_errno; + } + } + + grub_free (prompt); + + return 0; +} + +static grub_err_t +grub_normal_read_line (char **line, int cont) +{ + return grub_normal_read_line_real (line, cont, 0); +} + void grub_cmdline_run (int nested) { - grub_reader_t reader; grub_err_t err = GRUB_ERR_NONE; err = grub_auth_check_authentication (NULL); @@ -495,63 +660,28 @@ grub_cmdline_run (int nested) return; } - reader = grub_reader_get_current (); - - reader_nested = nested; - if (reader->init) - reader->init (); - grub_reader_loop (0); -} - -static grub_err_t -grub_normal_reader_init (void) -{ - grub_normal_init_page (); - grub_setcursor (1); - - grub_printf_ (N_("\ - [ Minimal BASH-like line editing is supported. For the first word, TAB\n\ - lists possible command completions. Anywhere else TAB lists possible\n\ - device/file completions.%s ]\n\n"), - reader_nested ? " ESC at any time exits." : ""); - - return 0; -} - -static char cmdline[GRUB_MAX_CMDLINE]; - -static grub_err_t -grub_normal_read_line (char **line, int cont) -{ - grub_parser_t parser = grub_parser_get_current (); - char prompt[sizeof("> ") + grub_strlen (parser->name)]; - - grub_sprintf (prompt, "%s> ", parser->name); + grub_normal_reader_init (nested); while (1) { - cmdline[0] = 0; - if (grub_cmdline_get (prompt, cmdline, sizeof (cmdline), 0, 1, 1)) + char *line; + + if (grub_normal_exit_level) break; - if ((reader_nested) || (cont)) - { - *line = 0; - return grub_errno; - } + /* Print an error, if any. */ + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + + grub_normal_read_line_real (&line, 0, nested); + if (! line) + break; + + grub_parser_get_current ()->parse_line (line, grub_normal_read_line); + grub_free (line); } - - *line = grub_strdup (cmdline); - return 0; } -static struct grub_reader grub_normal_reader = - { - .name = "normal", - .init = grub_normal_reader_init, - .read_line = grub_normal_read_line - }; - static char * grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)), const char *val) @@ -562,21 +692,22 @@ grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)), GRUB_MOD_INIT(normal) { + grub_context_init (); + /* Normal mode shouldn't be unloaded. */ if (mod) grub_dl_ref (mod); - grub_menu_viewer_register (&grub_normal_text_menu_viewer); - grub_set_history (GRUB_DEFAULT_HISTORY_SIZE); - grub_reader_register ("normal", &grub_normal_reader); - grub_reader_set_current (&grub_normal_reader); + grub_install_newline_hook (); grub_register_variable_hook ("pager", 0, grub_env_write_pager); /* Register a command "normal" for the rescue mode. */ - grub_register_command_prio ("normal", grub_cmd_normal, - 0, "Enter normal mode", 0); + grub_register_command ("normal", grub_cmd_normal, + 0, N_("Enter normal mode.")); + grub_register_command ("normal_exit", grub_cmd_normal_exit, + 0, N_("Exit from normal mode.")); /* Reload terminal colors when these variables are written to. */ grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal); @@ -589,8 +720,9 @@ GRUB_MOD_INIT(normal) GRUB_MOD_FINI(normal) { + grub_context_fini (); + grub_set_history (0); - grub_reader_unregister (&grub_normal_reader); grub_register_variable_hook ("pager", 0, 0); grub_fs_autoload_hook = 0; free_handler_list (); diff --git a/normal/menu.c b/normal/menu.c index 8ee7d1c22..09c5fd1eb 100644 --- a/normal/menu.c +++ b/normal/menu.c @@ -1,7 +1,7 @@ /* menu.c - General supporting functionality for menus. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2006,2007,2008,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 @@ -27,6 +27,26 @@ #include #include #include +#include +#include + +/* Time to delay after displaying an error message about a default/fallback + entry failing to boot. */ +#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500 + +grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu, + int nested) = NULL; + +/* Wait until the user pushes any key so that the user + can see what happened. */ +void +grub_wait_after_message (void) +{ + grub_putchar ('\n'); + grub_printf_ (N_("Press any key to continue...")); + (void) grub_getkey (); + grub_putchar ('\n'); +} /* Get a menu entry by its index in the entry list. */ grub_menu_entry_t @@ -78,7 +98,7 @@ grub_menu_set_timeout (int timeout) { char buf[16]; - grub_sprintf (buf, "%d", timeout); + grub_snprintf (buf, sizeof (buf), "%d", timeout); grub_env_set ("timeout", buf); } } @@ -137,6 +157,8 @@ grub_menu_execute_entry(grub_menu_entry_t entry) return; } + grub_env_set ("chosen", entry->title); + grub_parser_execute ((char *) entry->sourcecode); if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) @@ -178,3 +200,414 @@ grub_menu_execute_with_fallback (grub_menu_t menu, callback->notify_failure (callback_data); } + +static struct grub_menu_viewer *viewers; + +static void +menu_set_chosen_entry (int entry) +{ + struct grub_menu_viewer *cur; + for (cur = viewers; cur; cur = cur->next) + cur->set_chosen_entry (entry, cur->data); +} + +static void +menu_print_timeout (int timeout) +{ + struct grub_menu_viewer *cur; + for (cur = viewers; cur; cur = cur->next) + cur->print_timeout (timeout, cur->data); +} + +static void +menu_fini (void) +{ + struct grub_menu_viewer *cur, *next; + for (cur = viewers; cur; cur = next) + { + next = cur->next; + cur->fini (cur->data); + grub_free (cur); + } + viewers = NULL; +} + +static void +menu_init (int entry, grub_menu_t menu, int nested) +{ + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + grub_err_t err; + + if (grub_gfxmenu_try_hook && grub_strcmp (term->name, "gfxterm") == 0) + { + err = grub_gfxmenu_try_hook (entry, menu, nested); + if(!err) + continue; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + + err = grub_menu_try_text (term, entry, menu, nested); + if(!err) + continue; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } +} + +static void +clear_timeout (void) +{ + struct grub_menu_viewer *cur; + for (cur = viewers; cur; cur = cur->next) + cur->clear_timeout (cur->data); +} + +void +grub_menu_register_viewer (struct grub_menu_viewer *viewer) +{ + viewer->next = viewers; + viewers = viewer; +} + +/* Get the entry number from the variable NAME. */ +static int +get_entry_number (grub_menu_t menu, const char *name) +{ + char *val; + int entry; + + val = grub_env_get (name); + if (! val) + return -1; + + grub_error_push (); + + entry = (int) grub_strtoul (val, 0, 0); + + if (grub_errno == GRUB_ERR_BAD_NUMBER) + { + /* See if the variable matches the title of a menu entry. */ + grub_menu_entry_t e = menu->entry_list; + int i; + + grub_errno = GRUB_ERR_NONE; + + for (i = 0; e; i++) + { + if (grub_strcmp (e->title, val) == 0) + { + entry = i; + break; + } + e = e->next; + } + + if (! e) + entry = -1; + } + + if (grub_errno != GRUB_ERR_NONE) + { + grub_errno = GRUB_ERR_NONE; + entry = -1; + } + + grub_error_pop (); + + return entry; +} + +#define GRUB_MENU_PAGE_SIZE 10 + +/* Show the menu and handle menu entry selection. Returns the menu entry + index that should be executed or -1 if no entry should be executed (e.g., + Esc pressed to exit a sub-menu or switching menu viewers). + If the return value is not -1, then *AUTO_BOOT is nonzero iff the menu + entry to be executed is a result of an automatic default selection because + of the timeout. */ +static int +run_menu (grub_menu_t menu, int nested, int *auto_boot) +{ + grub_uint64_t saved_time; + int default_entry, current_entry; + int timeout; + + default_entry = get_entry_number (menu, "default"); + + /* If DEFAULT_ENTRY is not within the menu entries, fall back to + the first entry. */ + if (default_entry < 0 || default_entry >= menu->size) + default_entry = 0; + + /* If timeout is 0, drawing is pointless (and ugly). */ + if (grub_menu_get_timeout () == 0) + { + *auto_boot = 1; + return default_entry; + } + + current_entry = default_entry; + + /* Initialize the time. */ + saved_time = grub_get_time_ms (); + + refresh: + menu_init (current_entry, menu, nested); + + timeout = grub_menu_get_timeout (); + + if (timeout > 0) + menu_print_timeout (timeout); + else + clear_timeout (); + + while (1) + { + int c; + timeout = grub_menu_get_timeout (); + + if (grub_normal_exit_level) + return -1; + + if (timeout > 0) + { + grub_uint64_t current_time; + + current_time = grub_get_time_ms (); + if (current_time - saved_time >= 1000) + { + timeout--; + grub_menu_set_timeout (timeout); + saved_time = current_time; + menu_print_timeout (timeout); + } + } + + if (timeout == 0) + { + grub_env_unset ("timeout"); + *auto_boot = 1; + menu_fini (); + return default_entry; + } + + if (grub_checkkey () >= 0 || timeout < 0) + { + c = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + + if (timeout >= 0) + { + grub_env_unset ("timeout"); + grub_env_unset ("fallback"); + clear_timeout (); + } + + switch (c) + { + case GRUB_TERM_HOME: + current_entry = 0; + menu_set_chosen_entry (current_entry); + break; + + case GRUB_TERM_END: + current_entry = menu->size - 1; + menu_set_chosen_entry (current_entry); + break; + + case GRUB_TERM_UP: + case '^': + if (current_entry > 0) + current_entry--; + menu_set_chosen_entry (current_entry); + break; + + case GRUB_TERM_DOWN: + case 'v': + if (current_entry < menu->size - 1) + current_entry++; + menu_set_chosen_entry (current_entry); + break; + + case GRUB_TERM_PPAGE: + if (current_entry < GRUB_MENU_PAGE_SIZE) + current_entry = 0; + else + current_entry -= GRUB_MENU_PAGE_SIZE; + menu_set_chosen_entry (current_entry); + break; + + case GRUB_TERM_NPAGE: + if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size) + current_entry += GRUB_MENU_PAGE_SIZE; + else + current_entry = menu->size - 1; + menu_set_chosen_entry (current_entry); + break; + + case '\n': + case '\r': + case 6: + menu_fini (); + *auto_boot = 0; + return current_entry; + + case '\e': + if (nested) + { + menu_fini (); + return -1; + } + break; + + case 'c': + menu_fini (); + grub_cmdline_run (1); + goto refresh; + + case 'e': + menu_fini (); + { + grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry); + if (e) + grub_menu_entry_run (e); + } + goto refresh; + + default: + { + grub_menu_entry_t entry; + int i; + for (i = 0, entry = menu->entry_list; i < menu->size; + i++, entry = entry->next) + if (entry->hotkey == c) + { + menu_fini (); + *auto_boot = 0; + return i; + } + } + break; + } + } + } + + /* Never reach here. */ + return -1; +} + +/* Callback invoked immediately before a menu entry is executed. */ +static void +notify_booting (grub_menu_entry_t entry, + void *userdata __attribute__((unused))) +{ + grub_printf (" "); + grub_printf_ (N_("Booting \'%s\'"), entry->title); + grub_printf ("\n\n"); +} + +/* Callback invoked when a default menu entry executed because of a timeout + has failed and an attempt will be made to execute the next fallback + entry, ENTRY. */ +static void +notify_fallback (grub_menu_entry_t entry, + void *userdata __attribute__((unused))) +{ + grub_printf ("\n "); + grub_printf_ (N_("Falling back to \'%s\'"), entry->title); + grub_printf ("\n\n"); + grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS); +} + +/* Callback invoked when a menu entry has failed and there is no remaining + fallback entry to attempt. */ +static void +notify_execution_failure (void *userdata __attribute__((unused))) +{ + if (grub_errno != GRUB_ERR_NONE) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + grub_printf ("\n "); + grub_printf_ (N_("Failed to boot both default and fallback entries.\n")); + grub_wait_after_message (); +} + +/* Callbacks used by the text menu to provide user feedback when menu entries + are executed. */ +static struct grub_menu_execute_callback execution_callback = +{ + .notify_booting = notify_booting, + .notify_fallback = notify_fallback, + .notify_failure = notify_execution_failure +}; + +static grub_err_t +show_menu (grub_menu_t menu, int nested) +{ + while (1) + { + int boot_entry; + grub_menu_entry_t e; + int auto_boot; + + boot_entry = run_menu (menu, nested, &auto_boot); + if (boot_entry < 0) + break; + + e = grub_menu_get_entry (menu, boot_entry); + if (! e) + continue; /* Menu is empty. */ + + grub_cls (); + + if (auto_boot) + { + grub_menu_execute_with_fallback (menu, e, &execution_callback, 0); + } + else + { + int lines_before = grub_normal_get_line_counter (); + grub_errno = GRUB_ERR_NONE; + grub_menu_execute_entry (e); + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + + if (lines_before != grub_normal_get_line_counter ()) + grub_wait_after_message (); + } + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_show_menu (grub_menu_t menu, int nested) +{ + grub_err_t err1, err2; + + while (1) + { + err1 = show_menu (menu, nested); + grub_print_error (); + + if (grub_normal_exit_level) + break; + + err2 = grub_auth_check_authentication (NULL); + if (err2) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + continue; + } + + break; + } + + return err1; +} diff --git a/normal/menu_entry.c b/normal/menu_entry.c index 7a31c27af..644fe90fd 100644 --- a/normal/menu_entry.c +++ b/normal/menu_entry.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2005,2006,2007,2008,2009 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 @@ -43,6 +43,15 @@ struct line int max_len; }; +struct per_term_screen +{ + struct grub_term_output *term; + /* The X coordinate. */ + int x; + /* The Y coordinate. */ + int y; +}; + struct screen { /* The array of lines. */ @@ -55,18 +64,18 @@ struct screen int real_column; /* The current line. */ int line; - /* The X coordinate. */ - int x; - /* The Y coordinate. */ - int y; /* The kill buffer. */ char *killed_text; /* The flag of a completion window. */ int completion_shown; + + struct per_term_screen *terms; + unsigned nterms; }; /* Used for storing completion items temporarily. */ static struct line completion_buffer; +static int completion_type; /* Initialize a line. */ static int @@ -98,77 +107,95 @@ ensure_space (struct line *linep, int extra) /* Return the number of lines occupied by this line on the screen. */ static int -get_logical_num_lines (struct line *linep) +get_logical_num_lines (struct line *linep, struct per_term_screen *term_screen) { - return (linep->len / GRUB_TERM_ENTRY_WIDTH) + 1; + return (linep->len / grub_term_entry_width (term_screen->term)) + 1; } /* Print a line. */ static void -print_line (struct line *linep, int offset, int start, int y) +print_line (struct line *linep, int offset, int start, int y, + struct per_term_screen *term_screen) { - int i; - char *p; + grub_term_gotoxy (term_screen->term, + GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + start + 1, + y + GRUB_TERM_FIRST_ENTRY_Y); - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + start + 1, - y + GRUB_TERM_FIRST_ENTRY_Y); - - for (p = linep->buf + offset + start, i = start; - i < GRUB_TERM_ENTRY_WIDTH && offset + i < linep->len; - p++, i++) - grub_putchar (*p); - - for (; i < GRUB_TERM_ENTRY_WIDTH; i++) - grub_putchar (' '); - - if (linep->len >= offset + GRUB_TERM_ENTRY_WIDTH) - grub_putchar ('\\'); + if (linep->len >= offset + grub_term_entry_width (term_screen->term)) + { + char *p, c; + p = linep->buf + offset + grub_term_entry_width (term_screen->term); + c = *p; + *p = 0; + grub_puts_terminal (linep->buf + offset + start, term_screen->term); + *p = c; + grub_putcode ('\\', term_screen->term); + } else - grub_putchar (' '); + { + int i; + char *p, c; + + p = linep->buf + linep->len; + c = *p; + *p = 0; + grub_puts_terminal (linep->buf + offset + start, term_screen->term); + *p = c; + + for (i = 0; + i <= grub_term_entry_width (term_screen->term) - linep->len + offset; + i++) + grub_putcode (' ', term_screen->term); + } } /* Print an empty line. */ static void -print_empty_line (int y) +print_empty_line (int y, struct per_term_screen *term_screen) { int i; - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, - y + GRUB_TERM_FIRST_ENTRY_Y); + grub_term_gotoxy (term_screen->term, + GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, + y + GRUB_TERM_FIRST_ENTRY_Y); - for (i = 0; i < GRUB_TERM_ENTRY_WIDTH + 1; i++) - grub_putchar (' '); + for (i = 0; i < grub_term_entry_width (term_screen->term) + 1; i++) + grub_putcode (' ', term_screen->term); } /* Print an up arrow. */ static void -print_up (int flag) +print_up (int flag, struct per_term_screen *term_screen) { - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, - GRUB_TERM_FIRST_ENTRY_Y); + grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X + + grub_term_entry_width (term_screen->term), + GRUB_TERM_FIRST_ENTRY_Y); if (flag) - grub_putcode (GRUB_TERM_DISP_UP); + grub_putcode (GRUB_TERM_DISP_UP, term_screen->term); else - grub_putchar (' '); + grub_putcode (' ', term_screen->term); } /* Print a down arrow. */ static void -print_down (int flag) +print_down (int flag, struct per_term_screen *term_screen) { - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, - GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES); + grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X + + grub_term_border_width (term_screen->term), + GRUB_TERM_TOP_BORDER_Y + + grub_term_num_entries (term_screen->term)); if (flag) - grub_putcode (GRUB_TERM_DISP_DOWN); + grub_putcode (GRUB_TERM_DISP_DOWN, term_screen->term); else - grub_putchar (' '); + grub_putcode (' ', term_screen->term); } /* Draw the lines of the screen SCREEN. */ static void -update_screen (struct screen *screen, int region_start, int region_column, +update_screen (struct screen *screen, struct per_term_screen *term_screen, + int region_start, int region_column, int up, int down, enum update_mode mode) { int up_flag = 0; @@ -178,12 +205,13 @@ update_screen (struct screen *screen, int region_start, int region_column, struct line *linep; /* Check if scrolling is necessary. */ - if (screen->y < 0 || screen->y >= GRUB_TERM_NUM_ENTRIES) + if (term_screen->y < 0 || term_screen->y + >= grub_term_num_entries (term_screen->term)) { - if (screen->y < 0) - screen->y = 0; + if (term_screen->y < 0) + term_screen->y = 0; else - screen->y = GRUB_TERM_NUM_ENTRIES - 1; + term_screen->y = grub_term_num_entries (term_screen->term) - 1; region_start = 0; region_column = 0; @@ -196,14 +224,15 @@ update_screen (struct screen *screen, int region_start, int region_column, { /* Draw lines. This code is tricky, because this must calculate logical positions. */ - y = screen->y - screen->column / GRUB_TERM_ENTRY_WIDTH; + y = term_screen->y - screen->column + / grub_term_entry_width (term_screen->term); i = screen->line; linep = screen->lines + i; while (y > 0) { i--; linep--; - y -= get_logical_num_lines (linep); + y -= get_logical_num_lines (linep, term_screen); } if (y < 0 || i > 0) @@ -214,8 +243,9 @@ update_screen (struct screen *screen, int region_start, int region_column, int column; for (column = 0; - column <= linep->len && y < GRUB_TERM_NUM_ENTRIES; - column += GRUB_TERM_ENTRY_WIDTH, y++) + column <= linep->len + && y < grub_term_num_entries (term_screen->term); + column += grub_term_entry_width (term_screen->term), y++) { if (y < 0) continue; @@ -223,16 +253,19 @@ update_screen (struct screen *screen, int region_start, int region_column, if (i == region_start) { if (region_column >= column - && region_column < column + GRUB_TERM_ENTRY_WIDTH) - print_line (linep, column, region_column - column, y); + && region_column + < (column + + grub_term_entry_width (term_screen->term))) + print_line (linep, column, region_column - column, y, + term_screen); else if (region_column < column) - print_line (linep, column, 0, y); + print_line (linep, column, 0, y, term_screen); } else if (i > region_start && mode == ALL_LINES) - print_line (linep, column, 0, y); + print_line (linep, column, 0, y, term_screen); } - if (y == GRUB_TERM_NUM_ENTRIES) + if (y == grub_term_num_entries (term_screen->term)) { if (column <= linep->len || i + 1 < screen->num_lines) down_flag = 1; @@ -242,35 +275,53 @@ update_screen (struct screen *screen, int region_start, int region_column, i++; if (mode == ALL_LINES && i == screen->num_lines) - for (; y < GRUB_TERM_NUM_ENTRIES; y++) - print_empty_line (y); + for (; y < grub_term_num_entries (term_screen->term); y++) + print_empty_line (y, term_screen); } - while (y < GRUB_TERM_NUM_ENTRIES); + while (y < grub_term_num_entries (term_screen->term)); /* Draw up and down arrows. */ if (up) - print_up (up_flag); + print_up (up_flag, term_screen); if (down) - print_down (down_flag); + print_down (down_flag, term_screen); } /* Place the cursor. */ - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1 + screen->x, - GRUB_TERM_FIRST_ENTRY_Y + screen->y); + grub_term_gotoxy (term_screen->term, + GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1 + + term_screen->x, + GRUB_TERM_FIRST_ENTRY_Y + term_screen->y); - grub_refresh (); + grub_term_refresh (term_screen->term); +} + +static void +update_screen_all (struct screen *screen, + int region_start, int region_column, + int up, int down, enum update_mode mode) +{ + unsigned i; + for (i = 0; i < screen->nterms; i++) + update_screen (screen, &screen->terms[i], region_start, region_column, + up, down, mode); } -/* Insert the string S into the screen SCREEN. This updates the cursor - position and redraw the screen. Return zero if fails. */ static int insert_string (struct screen *screen, char *s, int update) { int region_start = screen->num_lines; int region_column = 0; - int down = 0; - enum update_mode mode = NO_LINE; + int down[screen->nterms]; + enum update_mode mode[screen->nterms]; + unsigned i; + + for (i = 0; i < screen->nterms; i++) + { + down[i] = 0; + mode[i] = NO_LINE; + } while (*s) { @@ -319,15 +370,20 @@ insert_string (struct screen *screen, char *s, int update) region_column = screen->column; } - mode = ALL_LINES; - down = 1; /* XXX not optimal. */ + for (i = 0; i < screen->nterms; i++) + { + mode[i] = ALL_LINES; + down[i] = 1; /* XXX not optimal. */ + } /* Move the cursor. */ screen->column = screen->real_column = 0; screen->line++; - screen->x = 0; - screen->y++; - + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x = 0; + screen->terms[i].y++; + } s++; } else @@ -336,7 +392,7 @@ insert_string (struct screen *screen, char *s, int update) char *p; struct line *current_linep; int size; - int orig_num, new_num; + int orig_num[screen->nterms], new_num[screen->nterms]; /* Find a string delimited by LF. */ p = grub_strchr (s, '\n'); @@ -355,9 +411,13 @@ insert_string (struct screen *screen, char *s, int update) grub_memmove (current_linep->buf + screen->column, s, size); - orig_num = get_logical_num_lines (current_linep); + for (i = 0; i < screen->nterms; i++) + orig_num[i] = get_logical_num_lines (current_linep, + &screen->terms[i]); current_linep->len += size; - new_num = get_logical_num_lines (current_linep); + for (i = 0; i < screen->nterms; i++) + new_num[i] = get_logical_num_lines (current_linep, + &screen->terms[i]); /* Update the dirty region. */ if (region_start > screen->line) @@ -366,27 +426,34 @@ insert_string (struct screen *screen, char *s, int update) region_column = screen->column; } - if (orig_num != new_num) - { - mode = ALL_LINES; - down = 1; /* XXX not optimal. */ - } - else if (mode != ALL_LINES) - mode = SINGLE_LINE; + for (i = 0; i < screen->nterms; i++) + if (orig_num[i] != new_num[i]) + { + mode[i] = ALL_LINES; + down[i] = 1; /* XXX not optimal. */ + } + else if (mode[i] != ALL_LINES) + mode[i] = SINGLE_LINE; /* Move the cursor. */ screen->column += size; screen->real_column = screen->column; - screen->x += size; - screen->y += screen->x / GRUB_TERM_ENTRY_WIDTH; - screen->x %= GRUB_TERM_ENTRY_WIDTH; - + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x += size; + screen->terms[i].y += screen->terms[i].x + / grub_term_entry_width (screen->terms[i].term); + screen->terms[i].x + %= grub_term_entry_width (screen->terms[i].term); + } s = p; } } if (update) - update_screen (screen, region_start, region_column, 0, down, mode); + for (i = 0; i < screen->nterms; i++) + update_screen (screen, &screen->terms[i], + region_start, region_column, 0, down[i], mode[i]); return 1; } @@ -408,6 +475,7 @@ destroy_screen (struct screen *screen) grub_free (screen->killed_text); grub_free (screen->lines); + grub_free (screen->terms); grub_free (screen); } @@ -416,6 +484,7 @@ static struct screen * make_screen (grub_menu_entry_t entry) { struct screen *screen; + unsigned i; /* Initialize the screen. */ screen = grub_zalloc (sizeof (*screen)); @@ -437,8 +506,11 @@ make_screen (grub_menu_entry_t entry) screen->column = 0; screen->real_column = 0; screen->line = 0; - screen->x = 0; - screen->y = 0; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x = 0; + screen->terms[i].y = 0; + } return screen; @@ -451,44 +523,58 @@ static int forward_char (struct screen *screen, int update) { struct line *linep; + unsigned i; linep = screen->lines + screen->line; if (screen->column < linep->len) { screen->column++; - screen->x++; - if (screen->x == GRUB_TERM_ENTRY_WIDTH) + for (i = 0; i < screen->nterms; i++) { - screen->x = 0; - screen->y++; + screen->terms[i].x++; + if (screen->terms[i].x + == grub_term_entry_width (screen->terms[i].term)) + { + screen->terms[i].x = 0; + screen->terms[i].y++; + } } } else if (screen->num_lines > screen->line + 1) { screen->column = 0; screen->line++; - screen->x = 0; - screen->y++; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x = 0; + screen->terms[i].y++; + } } screen->real_column = screen->column; if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } static int backward_char (struct screen *screen, int update) { + unsigned i; + if (screen->column > 0) { screen->column--; - screen->x--; - if (screen->x == -1) + for (i = 0; i < screen->nterms; i++) { - screen->x = GRUB_TERM_ENTRY_WIDTH - 1; - screen->y--; + screen->terms[i].x--; + if (screen->terms[i].x == -1) + { + screen->terms[i].x + = grub_term_entry_width (screen->terms[i].term) - 1; + screen->terms[i].y--; + } } } else if (screen->line > 0) @@ -498,14 +584,18 @@ backward_char (struct screen *screen, int update) screen->line--; linep = screen->lines + screen->line; screen->column = linep->len; - screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; - screen->y--; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x = screen->column + % grub_term_entry_width (screen->terms[i].term); + screen->terms[i].y--; + } } screen->real_column = screen->column; if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } @@ -513,14 +603,16 @@ backward_char (struct screen *screen, int update) static int previous_line (struct screen *screen, int update) { + unsigned i; + if (screen->line > 0) { struct line *linep; - int dy; + int col; /* How many physical lines from the current position to the first physical line? */ - dy = screen->column / GRUB_TERM_ENTRY_WIDTH; + col = screen->column; screen->line--; @@ -530,23 +622,35 @@ previous_line (struct screen *screen, int update) else screen->column = screen->real_column; - /* How many physical lines from the current position - to the last physical line? */ - dy += (linep->len / GRUB_TERM_ENTRY_WIDTH - - screen->column / GRUB_TERM_ENTRY_WIDTH); + for (i = 0; i < screen->nterms; i++) + { + int dy; + dy = col / grub_term_entry_width (screen->terms[i].term); - screen->y -= dy + 1; - screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + /* How many physical lines from the current position + to the last physical line? */ + dy += (linep->len / grub_term_entry_width (screen->terms[i].term) + - screen->column + / grub_term_entry_width (screen->terms[i].term)); + + screen->terms[i].y -= dy + 1; + screen->terms[i].x + = screen->column % grub_term_entry_width (screen->terms[i].term); + } } else { - screen->y -= screen->column / GRUB_TERM_ENTRY_WIDTH; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].y + -= screen->column / grub_term_entry_width (screen->terms[i].term); + screen->terms[i].x = 0; + } screen->column = 0; - screen->x = 0; } if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } @@ -554,16 +658,18 @@ previous_line (struct screen *screen, int update) static int next_line (struct screen *screen, int update) { + unsigned i; + if (screen->line < screen->num_lines - 1) { struct line *linep; - int dy; + int l1, c1; /* How many physical lines from the current position to the last physical line? */ linep = screen->lines + screen->line; - dy = (linep->len / GRUB_TERM_ENTRY_WIDTH - - screen->column / GRUB_TERM_ENTRY_WIDTH); + l1 = linep->len; + c1 = screen->column; screen->line++; @@ -573,26 +679,40 @@ next_line (struct screen *screen, int update) else screen->column = screen->real_column; - /* How many physical lines from the current position - to the first physical line? */ - dy += screen->column / GRUB_TERM_ENTRY_WIDTH; - - screen->y += dy + 1; - screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + for (i = 0; i < screen->nterms; i++) + { + int dy; + dy = l1 / grub_term_entry_width (screen->terms[i].term) + - c1 / grub_term_entry_width (screen->terms[i].term); + /* How many physical lines from the current position + to the first physical line? */ + dy += screen->column / grub_term_entry_width (screen->terms[i].term); + screen->terms[i].y += dy + 1; + screen->terms[i].x = screen->column + % grub_term_entry_width (screen->terms[i].term); + } } else { struct line *linep; - + int l, s; + linep = screen->lines + screen->line; - screen->y += (linep->len / GRUB_TERM_ENTRY_WIDTH - - screen->column / GRUB_TERM_ENTRY_WIDTH); + l = linep->len; + s = screen->column; screen->column = linep->len; - screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].y + += (l / grub_term_entry_width (screen->terms[i].term) + - s / grub_term_entry_width (screen->terms[i].term)); + screen->terms[i].x + = screen->column % grub_term_entry_width (screen->terms[i].term); + } } if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } @@ -600,12 +720,19 @@ next_line (struct screen *screen, int update) static int beginning_of_line (struct screen *screen, int update) { - screen->y -= screen->column / GRUB_TERM_ENTRY_WIDTH; + unsigned i; + int col; + + col = screen->column; screen->column = screen->real_column = 0; - screen->x = 0; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].x = 0; + screen->terms[i].y -= col / grub_term_entry_width (screen->terms[i].term); + } if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } @@ -614,15 +741,23 @@ static int end_of_line (struct screen *screen, int update) { struct line *linep; + unsigned i; + int col; linep = screen->lines + screen->line; - screen->y += (linep->len / GRUB_TERM_ENTRY_WIDTH - - screen->column / GRUB_TERM_ENTRY_WIDTH); + col = screen->column; screen->column = screen->real_column = linep->len; - screen->x = screen->column % GRUB_TERM_ENTRY_WIDTH; + for (i = 0; i < screen->nterms; i++) + { + screen->terms[i].y + += (linep->len / grub_term_entry_width (screen->terms->term) + - col / grub_term_entry_width (screen->terms->term)); + screen->terms[i].x + = screen->column % grub_term_entry_width (screen->terms->term); + } if (update) - update_screen (screen, screen->num_lines, 0, 0, 0, NO_LINE); + update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE); return 1; } @@ -631,32 +766,41 @@ static int delete_char (struct screen *screen, int update) { struct line *linep; - enum update_mode mode = NO_LINE; int start = screen->num_lines; int column = 0; - int down = 0; linep = screen->lines + screen->line; if (linep->len > screen->column) { - int orig_num, new_num; + int orig_num[screen->nterms], new_num; + unsigned i; - orig_num = get_logical_num_lines (linep); + for (i = 0; i < screen->nterms; i++) + orig_num[i] = get_logical_num_lines (linep, &screen->terms[i]); grub_memmove (linep->buf + screen->column, linep->buf + screen->column + 1, linep->len - screen->column - 1); linep->len--; - new_num = get_logical_num_lines (linep); - - if (orig_num != new_num) - mode = ALL_LINES; - else - mode = SINGLE_LINE; - start = screen->line; column = screen->column; + + screen->real_column = screen->column; + + if (update) + { + for (i = 0; i < screen->nterms; i++) + { + new_num = get_logical_num_lines (linep, &screen->terms[i]); + if (orig_num[i] != new_num) + update_screen (screen, &screen->terms[i], + start, column, 0, 0, ALL_LINES); + else + update_screen (screen, &screen->terms[i], + start, column, 0, 0, SINGLE_LINE); + } + } } else if (screen->num_lines > screen->line + 1) { @@ -676,17 +820,14 @@ delete_char (struct screen *screen, int update) * sizeof (struct line)); screen->num_lines--; - mode = ALL_LINES; start = screen->line; column = screen->column; - down = 1; + + screen->real_column = screen->column; + if (update) + update_screen_all (screen, start, column, 0, 1, ALL_LINES); } - screen->real_column = screen->column; - - if (update) - update_screen (screen, start, column, 0, down, mode); - return 1; } @@ -731,9 +872,8 @@ kill_line (struct screen *screen, int continuous, int update) if (size > 0) { - enum update_mode mode = SINGLE_LINE; - int down = 0; - int orig_num, new_num; + int orig_num[screen->nterms], new_num; + unsigned i; p = grub_realloc (p, offset + size + 1); if (! p) @@ -744,18 +884,23 @@ kill_line (struct screen *screen, int continuous, int update) screen->killed_text = p; - orig_num = get_logical_num_lines (linep); + for (i = 0; i < screen->nterms; i++) + orig_num[i] = get_logical_num_lines (linep, &screen->terms[i]); linep->len = screen->column; - new_num = get_logical_num_lines (linep); - - if (orig_num != new_num) - { - mode = ALL_LINES; - down = 1; - } if (update) - update_screen (screen, screen->line, screen->column, 0, down, mode); + { + new_num = get_logical_num_lines (linep, &screen->terms[i]); + for (i = 0; i < screen->nterms; i++) + { + if (orig_num[i] != new_num) + update_screen (screen, &screen->terms[i], + screen->line, screen->column, 0, 1, ALL_LINES); + else + update_screen (screen, &screen->terms[i], + screen->line, screen->column, 0, 0, SINGLE_LINE); + } + } } else if (screen->line + 1 < screen->num_lines) { @@ -786,7 +931,11 @@ yank (struct screen *screen, int update) static int open_line (struct screen *screen, int update) { - int saved_y = screen->y; + int saved_y[screen->nterms]; + unsigned i; + + for (i = 0; i < screen->nterms; i++) + saved_y[i] = screen->terms[i].y; if (! insert_string (screen, "\n", 0)) return 0; @@ -794,52 +943,23 @@ open_line (struct screen *screen, int update) if (! backward_char (screen, 0)) return 0; - screen->y = saved_y; + for (i = 0; i < screen->nterms; i++) + screen->terms[i].y = saved_y[i]; if (update) - update_screen (screen, screen->line, screen->column, 0, 1, ALL_LINES); + update_screen_all (screen, screen->line, screen->column, 0, 1, ALL_LINES); return 1; } /* A completion hook to print items. */ static void -store_completion (const char *item, grub_completion_type_t type, int count) +store_completion (const char *item, grub_completion_type_t type, + int count __attribute__ ((unused))) { char *p; - if (count == 0) - { - /* If this is the first time, print a label. */ - const char *what; - - switch (type) - { - case GRUB_COMPLETION_TYPE_COMMAND: - what = "commands"; - break; - case GRUB_COMPLETION_TYPE_DEVICE: - what = "devices"; - break; - case GRUB_COMPLETION_TYPE_FILE: - what = "files"; - break; - case GRUB_COMPLETION_TYPE_PARTITION: - what = "partitions"; - break; - case GRUB_COMPLETION_TYPE_ARGUMENT: - what = "arguments"; - break; - default: - what = "things"; - break; - } - - grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); - grub_printf (" "); - grub_printf_ (N_("Possible %s are:"), what); - grub_printf ("\n "); - } + completion_type = type; /* Make sure that the completion buffer has enough room. */ if (completion_buffer.max_len < (completion_buffer.len @@ -873,21 +993,21 @@ store_completion (const char *item, grub_completion_type_t type, int count) static int complete (struct screen *screen, int continuous, int update) { - grub_uint16_t pos; char saved_char; struct line *linep; int restore; char *insert; static int count = -1; + unsigned i; + grub_uint32_t *ucs4; + grub_size_t buflen; + grub_ssize_t ucs4len; if (continuous) count++; else count = 0; - pos = grub_getxy (); - grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); - completion_buffer.buf = 0; completion_buffer.len = 0; completion_buffer.max_len = 0; @@ -900,35 +1020,86 @@ complete (struct screen *screen, int continuous, int update) linep->buf[screen->column] = saved_char; - if (restore) + buflen = grub_strlen (completion_buffer.buf); + ucs4 = grub_malloc (sizeof (grub_uint32_t) * (buflen + 1)); + + if (!ucs4) { - char *p = completion_buffer.buf; - - screen->completion_shown = 1; - - if (p) - { - int num_sections = ((completion_buffer.len + GRUB_TERM_WIDTH - 8 - 1) - / (GRUB_TERM_WIDTH - 8)); - char *endp; - - p += (count % num_sections) * (GRUB_TERM_WIDTH - 8); - endp = p + (GRUB_TERM_WIDTH - 8); - - if (p != completion_buffer.buf) - grub_putcode (GRUB_TERM_DISP_LEFT); - else - grub_putchar (' '); - - while (*p && p < endp) - grub_putchar (*p++); - - if (*p) - grub_putcode (GRUB_TERM_DISP_RIGHT); - } + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return 1; } - grub_gotoxy (pos >> 8, pos & 0xFF); + ucs4len = grub_utf8_to_ucs4 (ucs4, buflen, + (grub_uint8_t *) completion_buffer.buf, + buflen, 0); + ucs4[ucs4len] = 0; + + if (restore) + for (i = 0; i < screen->nterms; i++) + { + int num_sections = ((completion_buffer.len + + grub_term_width (screen->terms[i].term) - 8 - 1) + / (grub_term_width (screen->terms[i].term) - 8)); + grub_uint32_t *endp; + grub_uint16_t pos; + grub_uint32_t *p = ucs4; + + pos = grub_term_getxy (screen->terms[i].term); + grub_term_gotoxy (screen->terms[i].term, 0, + grub_term_height (screen->terms[i].term) - 3); + + screen->completion_shown = 1; + + grub_term_gotoxy (screen->terms[i].term, 0, + grub_term_height (screen->terms[i].term) - 3); + grub_puts_terminal (" ", screen->terms[i].term); + switch (completion_type) + { + case GRUB_COMPLETION_TYPE_COMMAND: + grub_puts_terminal (_("Possible commands are:"), + screen->terms[i].term); + break; + case GRUB_COMPLETION_TYPE_DEVICE: + grub_puts_terminal (_("Possible devices are:"), + screen->terms[i].term); + break; + case GRUB_COMPLETION_TYPE_FILE: + grub_puts_terminal (_("Possible files are:"), + screen->terms[i].term); + break; + case GRUB_COMPLETION_TYPE_PARTITION: + grub_puts_terminal (_("Possible partitions are:"), + screen->terms[i].term); + break; + case GRUB_COMPLETION_TYPE_ARGUMENT: + grub_puts_terminal (_("Possible arguments are:"), + screen->terms[i].term); + break; + default: + grub_puts_terminal (_("Possible things are:"), + screen->terms[i].term); + break; + } + + grub_puts_terminal ("\n ", screen->terms[i].term); + + p += (count % num_sections) + * (grub_term_width (screen->terms[i].term) - 8); + endp = p + (grub_term_width (screen->terms[i].term) - 8); + + if (p != ucs4) + grub_putcode (GRUB_TERM_DISP_LEFT, screen->terms[i].term); + else + grub_putcode (' ', screen->terms[i].term); + + while (*p && p < endp) + grub_putcode (*p++, screen->terms[i].term); + + if (*p) + grub_putcode (GRUB_TERM_DISP_RIGHT, screen->terms[i].term); + grub_term_gotoxy (screen->terms[i].term, pos >> 8, pos & 0xFF); + } if (insert) { @@ -945,23 +1116,33 @@ complete (struct screen *screen, int continuous, int update) /* Clear displayed completions. */ static void -clear_completions (void) +clear_completions (struct per_term_screen *term_screen) { grub_uint16_t pos; - int i, j; + unsigned i, j; - pos = grub_getxy (); - grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); + pos = grub_term_getxy (term_screen->term); + grub_term_gotoxy (term_screen->term, 0, + grub_term_height (term_screen->term) - 3); for (i = 0; i < 2; i++) { - for (j = 0; j < GRUB_TERM_WIDTH - 1; j++) - grub_putchar (' '); - grub_putchar ('\n'); + for (j = 0; j < grub_term_width (term_screen->term) - 1; j++) + grub_putcode (' ', term_screen->term); + grub_putcode ('\n', term_screen->term); } - grub_gotoxy (pos >> 8, pos & 0xFF); - grub_refresh (); + grub_term_gotoxy (term_screen->term, pos >> 8, pos & 0xFF); + grub_term_refresh (term_screen->term); +} + +static void +clear_completions_all (struct screen *screen) +{ + unsigned i; + + for (i = 0; i < screen->nterms; i++) + clear_completions (&screen->terms[i]); } /* Execute the command list in the screen SCREEN. */ @@ -1033,6 +1214,8 @@ grub_menu_entry_run (grub_menu_entry_t entry) struct screen *screen; int prev_c; grub_err_t err = GRUB_ERR_NONE; + unsigned i; + grub_term_output_t term; err = grub_auth_check_authentication (NULL); @@ -1047,11 +1230,34 @@ grub_menu_entry_run (grub_menu_entry_t entry) if (! screen) return; + screen->terms = NULL; + refresh: + grub_free (screen->terms); + screen->nterms = 0; + FOR_ACTIVE_TERM_OUTPUTS(term) + screen->nterms++; + screen->terms = grub_malloc (screen->nterms * sizeof (screen->terms[0])); + if (!screen->terms) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return; + } + i = 0; + FOR_ACTIVE_TERM_OUTPUTS(term) + { + screen->terms[i].term = term; + screen->terms[i].x = 0; + screen->terms[i].y = 0; + i++; + } /* Draw the screen. */ - grub_menu_init_page (0, 1); - update_screen (screen, 0, 0, 1, 1, ALL_LINES); - grub_setcursor (1); + for (i = 0; i < screen->nterms; i++) + grub_menu_init_page (0, 1, screen->terms[i].term); + update_screen_all (screen, 0, 0, 1, 1, ALL_LINES); + for (i = 0; i < screen->nterms; i++) + grub_term_setcursor (screen->terms[i].term, 1); prev_c = '\0'; while (1) @@ -1060,10 +1266,16 @@ grub_menu_entry_run (grub_menu_entry_t entry) if (screen->completion_shown) { - clear_completions (); + clear_completions_all (screen); screen->completion_shown = 0; } + if (grub_normal_exit_level) + { + destroy_screen (screen); + return; + } + switch (c) { case 16: /* C-p */ diff --git a/normal/menu_text.c b/normal/menu_text.c index bb1f52203..bb0587502 100644 --- a/normal/menu_text.c +++ b/normal/menu_text.c @@ -26,97 +26,90 @@ #include #include #include - -/* Time to delay after displaying an error message about a default/fallback - entry failing to boot. */ -#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500 +#include static grub_uint8_t grub_color_menu_normal; static grub_uint8_t grub_color_menu_highlight; -/* Wait until the user pushes any key so that the user - can see what happened. */ -void -grub_wait_after_message (void) +struct menu_viewer_data { - grub_putchar ('\n'); - grub_printf_ (N_("Press any key to continue...")); - (void) grub_getkey (); - grub_putchar ('\n'); -} + int first, offset; + grub_menu_t menu; + struct grub_term_output *term; +}; static void -print_spaces (int number_spaces) +print_spaces (int number_spaces, struct grub_term_output *term) { int i; for (i = 0; i < number_spaces; i++) - grub_putchar (' '); + grub_putcode (' ', term); } -static void +void grub_print_ucs4 (const grub_uint32_t * str, - const grub_uint32_t * last_position) + const grub_uint32_t * last_position, + struct grub_term_output *term) { while (str < last_position) { - grub_putcode (*str); + grub_putcode (*str, term); str++; } } -static grub_ssize_t -getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position) +grub_ssize_t +grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position, + struct grub_term_output *term) { grub_ssize_t width = 0; while (str < last_position) { - width += grub_getcharwidth (*str); + width += grub_term_getcharwidth (term, *str); str++; } return width; } -static void -print_message_indented (const char *msg) +void +grub_print_message_indented (const char *msg, int margin_left, int margin_right, + struct grub_term_output *term) { - const int line_len = GRUB_TERM_WIDTH - grub_getcharwidth ('m') * 15; + int line_len; grub_uint32_t *unicode_msg; + grub_uint32_t *last_position; - grub_ssize_t msg_len = grub_strlen (msg); + int msg_len; - unicode_msg = grub_malloc (msg_len * sizeof (*unicode_msg)); + line_len = grub_term_width (term) - grub_term_getcharwidth (term, 'm') * + (margin_left + margin_right); - msg_len = grub_utf8_to_ucs4 (unicode_msg, msg_len, - (grub_uint8_t *) msg, -1, 0); - - if (!unicode_msg) - { - grub_printf ("print_message_indented ERROR1: %s", msg); - return; - } + msg_len = grub_utf8_to_ucs4_alloc (msg, &unicode_msg, &last_position); if (msg_len < 0) { - grub_printf ("print_message_indented ERROR2: %s", msg); - grub_free (unicode_msg); return; } - const grub_uint32_t *last_position = unicode_msg + msg_len; - grub_uint32_t *current_position = unicode_msg; grub_uint32_t *next_new_line = unicode_msg; + int first_loop = 1; + while (current_position < last_position) { + if (! first_loop) + grub_putcode ('\n', term); + next_new_line = (grub_uint32_t *) last_position; - while (getstringwidth (current_position, next_new_line) > line_len - || (*next_new_line != ' ' && next_new_line > current_position && - next_new_line != last_position)) + while (grub_getstringwidth (current_position, next_new_line,term) + > line_len + || (next_new_line != last_position && *next_new_line != ' ' + && next_new_line > current_position)) { next_new_line--; } @@ -127,92 +120,112 @@ print_message_indented (const char *msg) (grub_uint32_t *) last_position : next_new_line + line_len; } - print_spaces (6); - grub_print_ucs4 (current_position, next_new_line); - grub_putchar ('\n'); + print_spaces (margin_left, term); + grub_print_ucs4 (current_position, next_new_line, term); next_new_line++; current_position = next_new_line; + first_loop = 0; } grub_free (unicode_msg); } static void -draw_border (void) +draw_border (struct grub_term_output *term) { unsigned i; - grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); - grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y); - grub_putcode (GRUB_TERM_DISP_UL); - for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++) - grub_putcode (GRUB_TERM_DISP_HLINE); - grub_putcode (GRUB_TERM_DISP_UR); + grub_term_gotoxy (term, GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y); + grub_putcode (GRUB_TERM_DISP_UL, term); + for (i = 0; i < (unsigned) grub_term_border_width (term) - 2; i++) + grub_putcode (GRUB_TERM_DISP_HLINE, term); + grub_putcode (GRUB_TERM_DISP_UR, term); - for (i = 0; i < (unsigned) GRUB_TERM_NUM_ENTRIES; i++) + for (i = 0; i < (unsigned) grub_term_num_entries (term); i++) { - grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1); - grub_putcode (GRUB_TERM_DISP_VLINE); - grub_gotoxy (GRUB_TERM_MARGIN + GRUB_TERM_BORDER_WIDTH - 1, - GRUB_TERM_TOP_BORDER_Y + i + 1); - grub_putcode (GRUB_TERM_DISP_VLINE); + grub_term_gotoxy (term, GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1); + grub_putcode (GRUB_TERM_DISP_VLINE, term); + grub_term_gotoxy (term, GRUB_TERM_MARGIN + grub_term_border_width (term) + - 1, + GRUB_TERM_TOP_BORDER_Y + i + 1); + grub_putcode (GRUB_TERM_DISP_VLINE, term); } - grub_gotoxy (GRUB_TERM_MARGIN, - GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES + 1); - grub_putcode (GRUB_TERM_DISP_LL); - for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++) - grub_putcode (GRUB_TERM_DISP_HLINE); - grub_putcode (GRUB_TERM_DISP_LR); + grub_term_gotoxy (term, GRUB_TERM_MARGIN, + GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term) + 1); + grub_putcode (GRUB_TERM_DISP_LL, term); + for (i = 0; i < (unsigned) grub_term_border_width (term) - 2; i++) + grub_putcode (GRUB_TERM_DISP_HLINE, term); + grub_putcode (GRUB_TERM_DISP_LR, term); - grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); - grub_gotoxy (GRUB_TERM_MARGIN, - (GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES - + GRUB_TERM_MARGIN + 1)); + grub_term_gotoxy (term, GRUB_TERM_MARGIN, + (GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term) + + GRUB_TERM_MARGIN + 1)); } static void -print_message (int nested, int edit) +print_message (int nested, int edit, struct grub_term_output *term) { - grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); if (edit) { - grub_putchar ('\n'); - print_message_indented (_("Minimum Emacs-like screen editing is \ + grub_putcode ('\n', term); +#ifdef GRUB_MACHINE_EFI + grub_print_message_indented (_("Minimum Emacs-like screen editing is \ +supported. TAB lists completions. Press F1 to boot, F2=Ctrl-a, F3=Ctrl-e, \ +F4 for a command-line or ESC to discard edits and return to the GRUB menu."), + STANDARD_MARGIN, STANDARD_MARGIN, term); +#else + grub_print_message_indented (_("Minimum Emacs-like screen editing is \ supported. TAB lists completions. Press Ctrl-x to boot, Ctrl-c for a \ -command-line or ESC to return menu.")); +command-line or ESC to discard edits and return to the GRUB menu."), + STANDARD_MARGIN, STANDARD_MARGIN, term); +#endif } else { - const char *msg = _("Use the %C and %C keys to select which \ -entry is highlighted."); - char *msg_translated = - grub_malloc (sizeof (char) * grub_strlen (msg) + 1); + const char *msg = _("Use the %C and %C keys to select which " + "entry is highlighted.\n"); + char *msg_translated; - grub_sprintf (msg_translated, msg, (grub_uint32_t) GRUB_TERM_DISP_UP, - (grub_uint32_t) GRUB_TERM_DISP_DOWN); + msg_translated = grub_xasprintf (msg, (grub_uint32_t) GRUB_TERM_DISP_UP, + (grub_uint32_t) GRUB_TERM_DISP_DOWN); + if (!msg_translated) + return; grub_putchar ('\n'); - print_message_indented (msg_translated); + grub_print_message_indented (msg_translated, STANDARD_MARGIN, + STANDARD_MARGIN, term); grub_free (msg_translated); - print_message_indented (_("Press enter to boot the selected OS, \ -\'e\' to edit the commands before booting or \'c\' for a command-line.")); - if (nested) - { - grub_printf ("\n "); - grub_printf_ (N_("ESC to return previous menu.")); - } + { + grub_print_message_indented + (_("Press enter to boot the selected OS, " + "\'e\' to edit the commands before booting " + "or \'c\' for a command-line. ESC to return previous menu.\n"), + STANDARD_MARGIN, STANDARD_MARGIN, term); + } + else + { + grub_print_message_indented + (_("Press enter to boot the selected OS, " + "\'e\' to edit the commands before booting " + "or \'c\' for a command-line.\n"), + STANDARD_MARGIN, STANDARD_MARGIN, term); + } } } static void -print_entry (int y, int highlight, grub_menu_entry_t entry) +print_entry (int y, int highlight, grub_menu_entry_t entry, + struct grub_term_output *term) { int x; const char *title; @@ -238,478 +251,244 @@ print_entry (int y, int highlight, grub_menu_entry_t entry) return; } - grub_getcolor (&old_color_normal, &old_color_highlight); - grub_setcolor (grub_color_menu_normal, grub_color_menu_highlight); - grub_setcolorstate (highlight - ? GRUB_TERM_COLOR_HIGHLIGHT - : GRUB_TERM_COLOR_NORMAL); + grub_term_getcolor (term, &old_color_normal, &old_color_highlight); + grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight); + grub_term_setcolorstate (term, highlight + ? GRUB_TERM_COLOR_HIGHLIGHT + : GRUB_TERM_COLOR_NORMAL); - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y); + grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y); for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0; - x < GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN; + x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term) + - GRUB_TERM_MARGIN); i++) { if (i < len - && x <= (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - - GRUB_TERM_MARGIN - 1)) + && x <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term) + - GRUB_TERM_MARGIN - 1)) { grub_ssize_t width; - width = grub_getcharwidth (unicode_title[i]); + width = grub_term_getcharwidth (term, unicode_title[i]); - if (x + width > (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - - GRUB_TERM_MARGIN - 1)) - grub_putcode (GRUB_TERM_DISP_RIGHT); + if (x + width > (int) (GRUB_TERM_LEFT_BORDER_X + + grub_term_border_width (term) + - GRUB_TERM_MARGIN - 1)) + grub_putcode (GRUB_TERM_DISP_RIGHT, term); else - grub_putcode (unicode_title[i]); + grub_putcode (unicode_title[i], term); x += width; } else { - grub_putchar (' '); + grub_putcode (' ', term); x++; } } - grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); - grub_putchar (' '); + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); + grub_putcode (' ', term); - grub_gotoxy (GRUB_TERM_CURSOR_X, y); + grub_term_gotoxy (term, grub_term_cursor_x (term), y); - grub_setcolor (old_color_normal, old_color_highlight); - grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); + grub_term_setcolor (term, old_color_normal, old_color_highlight); + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); grub_free (unicode_title); } static void -print_entries (grub_menu_t menu, int first, int offset) +print_entries (grub_menu_t menu, int first, int offset, + struct grub_term_output *term) { grub_menu_entry_t e; int i; - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, - GRUB_TERM_FIRST_ENTRY_Y); + grub_term_gotoxy (term, + GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term), + GRUB_TERM_FIRST_ENTRY_Y); if (first) - grub_putcode (GRUB_TERM_DISP_UP); + grub_putcode (GRUB_TERM_DISP_UP, term); else - grub_putchar (' '); + grub_putcode (' ', term); e = grub_menu_get_entry (menu, first); - for (i = 0; i < GRUB_TERM_NUM_ENTRIES; i++) + for (i = 0; i < grub_term_num_entries (term); i++) { - print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e); + print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e, term); if (e) e = e->next; } - grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, - GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES); + grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + + grub_term_border_width (term), + GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term)); if (e) - grub_putcode (GRUB_TERM_DISP_DOWN); + grub_putcode (GRUB_TERM_DISP_DOWN, term); else - grub_putchar (' '); + grub_putcode (' ', term); - grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset); + grub_term_gotoxy (term, grub_term_cursor_x (term), + GRUB_TERM_FIRST_ENTRY_Y + offset); } /* Initialize the screen. If NESTED is non-zero, assume that this menu is run from another menu or a command-line. If EDIT is non-zero, show a message for the menu entry editor. */ void -grub_menu_init_page (int nested, int edit) +grub_menu_init_page (int nested, int edit, + struct grub_term_output *term) { grub_uint8_t old_color_normal, old_color_highlight; - grub_getcolor (&old_color_normal, &old_color_highlight); + grub_term_getcolor (term, &old_color_normal, &old_color_highlight); /* By default, use the same colors for the menu. */ grub_color_menu_normal = old_color_normal; grub_color_menu_highlight = old_color_highlight; /* Then give user a chance to replace them. */ - grub_parse_color_name_pair (&grub_color_menu_normal, grub_env_get ("menu_color_normal")); - grub_parse_color_name_pair (&grub_color_menu_highlight, grub_env_get ("menu_color_highlight")); + grub_parse_color_name_pair (&grub_color_menu_normal, + grub_env_get ("menu_color_normal")); + grub_parse_color_name_pair (&grub_color_menu_highlight, + grub_env_get ("menu_color_highlight")); - grub_normal_init_page (); - grub_setcolor (grub_color_menu_normal, grub_color_menu_highlight); - draw_border (); - grub_setcolor (old_color_normal, old_color_highlight); - print_message (nested, edit); -} - -/* Get the entry number from the variable NAME. */ -static int -get_entry_number (const char *name) -{ - char *val; - int entry; - - val = grub_env_get (name); - if (! val) - return -1; - - grub_error_push (); - - entry = (int) grub_strtoul (val, 0, 0); - - if (grub_errno != GRUB_ERR_NONE) - { - grub_errno = GRUB_ERR_NONE; - entry = -1; - } - - grub_error_pop (); - - return entry; + grub_normal_init_page (term); + grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight); + draw_border (term); + grub_term_setcolor (term, old_color_normal, old_color_highlight); + print_message (nested, edit, term); } static void -print_timeout (int timeout, int offset, int second_stage) +menu_text_print_timeout (int timeout, void *dataptr) { const char *msg = - _("The highlighted entry will be booted automatically in %ds."); - const int msg_localized_len = grub_strlen (msg); - const int number_spaces = GRUB_TERM_WIDTH - msg_localized_len - 3; + _("The highlighted entry will be executed automatically in %ds."); + struct menu_viewer_data *data = dataptr; + char *msg_translated; + int posx; - char *msg_end = grub_strchr (msg, '%'); + grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3); - grub_gotoxy (second_stage ? (msg_end - msg + 3) : 3, GRUB_TERM_HEIGHT - 3); - grub_printf (second_stage ? msg_end : msg, timeout); - print_spaces (second_stage ? number_spaces : 0); - - grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset); - grub_refresh (); -}; - -/* Show the menu and handle menu entry selection. Returns the menu entry - index that should be executed or -1 if no entry should be executed (e.g., - Esc pressed to exit a sub-menu or switching menu viewers). - If the return value is not -1, then *AUTO_BOOT is nonzero iff the menu - entry to be executed is a result of an automatic default selection because - of the timeout. */ -static int -run_menu (grub_menu_t menu, int nested, int *auto_boot) -{ - int first, offset; - grub_uint64_t saved_time; - int default_entry; - int timeout; - - first = 0; - - default_entry = get_entry_number ("default"); - - /* If DEFAULT_ENTRY is not within the menu entries, fall back to - the first entry. */ - if (default_entry < 0 || default_entry >= menu->size) - default_entry = 0; - - /* If timeout is 0, drawing is pointless (and ugly). */ - if (grub_menu_get_timeout () == 0) - { - *auto_boot = 1; - return default_entry; - } - - offset = default_entry; - if (offset > GRUB_TERM_NUM_ENTRIES - 1) - { - first = offset - (GRUB_TERM_NUM_ENTRIES - 1); - offset = GRUB_TERM_NUM_ENTRIES - 1; - } - - /* Initialize the time. */ - saved_time = grub_get_time_ms (); - - refresh: - grub_setcursor (0); - grub_menu_init_page (nested, 0); - print_entries (menu, first, offset); - grub_refresh (); - - timeout = grub_menu_get_timeout (); - - if (timeout > 0) - print_timeout (timeout, offset, 0); - - while (1) - { - int c; - timeout = grub_menu_get_timeout (); - - if (timeout > 0) - { - grub_uint64_t current_time; - - current_time = grub_get_time_ms (); - if (current_time - saved_time >= 1000) - { - timeout--; - grub_menu_set_timeout (timeout); - saved_time = current_time; - print_timeout (timeout, offset, 1); - } - } - - if (timeout == 0) - { - grub_env_unset ("timeout"); - *auto_boot = 1; - return default_entry; - } - - if (grub_checkkey () >= 0 || timeout < 0) - { - c = GRUB_TERM_ASCII_CHAR (grub_getkey ()); - - if (timeout >= 0) - { - grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); - print_spaces (GRUB_TERM_WIDTH - 1); - - grub_env_unset ("timeout"); - grub_env_unset ("fallback"); - grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset); - } - - switch (c) - { - case GRUB_TERM_HOME: - first = 0; - offset = 0; - print_entries (menu, first, offset); - break; - - case GRUB_TERM_END: - offset = menu->size - 1; - if (offset > GRUB_TERM_NUM_ENTRIES - 1) - { - first = offset - (GRUB_TERM_NUM_ENTRIES - 1); - offset = GRUB_TERM_NUM_ENTRIES - 1; - } - print_entries (menu, first, offset); - break; - - case GRUB_TERM_UP: - case '^': - if (offset > 0) - { - print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0, - grub_menu_get_entry (menu, first + offset)); - offset--; - print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1, - grub_menu_get_entry (menu, first + offset)); - } - else if (first > 0) - { - first--; - print_entries (menu, first, offset); - } - break; - - case GRUB_TERM_DOWN: - case 'v': - if (menu->size > first + offset + 1) - { - if (offset < GRUB_TERM_NUM_ENTRIES - 1) - { - print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0, - grub_menu_get_entry (menu, first + offset)); - offset++; - print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1, - grub_menu_get_entry (menu, first + offset)); - } - else - { - first++; - print_entries (menu, first, offset); - } - } - break; - - case GRUB_TERM_PPAGE: - if (first == 0) - { - offset = 0; - } - else - { - first -= GRUB_TERM_NUM_ENTRIES; - - if (first < 0) - { - offset += first; - first = 0; - } - } - print_entries (menu, first, offset); - break; - - case GRUB_TERM_NPAGE: - if (offset == 0) - { - offset += GRUB_TERM_NUM_ENTRIES - 1; - if (first + offset >= menu->size) - { - offset = menu->size - first - 1; - } - } - else - { - first += GRUB_TERM_NUM_ENTRIES; - - if (first + offset >= menu->size) - { - first -= GRUB_TERM_NUM_ENTRIES; - offset += GRUB_TERM_NUM_ENTRIES; - - if (offset > menu->size - 1 || - offset > GRUB_TERM_NUM_ENTRIES - 1) - { - offset = menu->size - first - 1; - } - if (offset > GRUB_TERM_NUM_ENTRIES) - { - first += offset - GRUB_TERM_NUM_ENTRIES + 1; - offset = GRUB_TERM_NUM_ENTRIES - 1; - } - } - } - print_entries (menu, first, offset); - break; - - case '\n': - case '\r': - case 6: - grub_setcursor (1); - *auto_boot = 0; - return first + offset; - - case '\e': - if (nested) - { - grub_setcursor (1); - return -1; - } - break; - - case 'c': - grub_cmdline_run (1); - goto refresh; - - case 'e': - { - grub_menu_entry_t e = grub_menu_get_entry (menu, first + offset); - if (e) - grub_menu_entry_run (e); - } - goto refresh; - - default: - break; - } - - grub_refresh (); - } - } - - /* Never reach here. */ - return -1; -} - -/* Callback invoked immediately before a menu entry is executed. */ -static void -notify_booting (grub_menu_entry_t entry, - void *userdata __attribute__((unused))) -{ - grub_printf (" "); - grub_printf_ (N_("Booting \'%s\'"), entry->title); - grub_printf ("\n\n"); -} - -/* Callback invoked when a default menu entry executed because of a timeout - has failed and an attempt will be made to execute the next fallback - entry, ENTRY. */ -static void -notify_fallback (grub_menu_entry_t entry, - void *userdata __attribute__((unused))) -{ - grub_printf ("\n "); - grub_printf_ (N_("Falling back to \'%s\'"), entry->title); - grub_printf ("\n\n"); - grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS); -} - -/* Callback invoked when a menu entry has failed and there is no remaining - fallback entry to attempt. */ -static void -notify_execution_failure (void *userdata __attribute__((unused))) -{ - if (grub_errno != GRUB_ERR_NONE) + msg_translated = grub_xasprintf (msg, timeout); + if (!msg_translated) { grub_print_error (); grub_errno = GRUB_ERR_NONE; + return; } - grub_printf ("\n "); - grub_printf_ (N_("Failed to boot default entries.\n")); - grub_wait_after_message (); + + grub_print_message_indented (msg_translated, 3, 0, data->term); + + posx = grub_term_getxy (data->term) >> 8; + print_spaces (grub_term_width (data->term) - posx - 1, data->term); + + grub_term_gotoxy (data->term, + grub_term_cursor_x (data->term), + GRUB_TERM_FIRST_ENTRY_Y + data->offset); + grub_term_refresh (data->term); } -/* Callbacks used by the text menu to provide user feedback when menu entries - are executed. */ -static struct grub_menu_execute_callback execution_callback = +static void +menu_text_set_chosen_entry (int entry, void *dataptr) { - .notify_booting = notify_booting, - .notify_fallback = notify_fallback, - .notify_failure = notify_execution_failure -}; + struct menu_viewer_data *data = dataptr; + int oldoffset = data->offset; + int complete_redraw = 0; -static grub_err_t -show_text_menu (grub_menu_t menu, int nested) -{ - while (1) + data->offset = entry - data->first; + if (data->offset > grub_term_num_entries (data->term) - 1) { - int boot_entry; - grub_menu_entry_t e; - int auto_boot; - - boot_entry = run_menu (menu, nested, &auto_boot); - if (boot_entry < 0) - break; - - e = grub_menu_get_entry (menu, boot_entry); - if (! e) - continue; /* Menu is empty. */ - - grub_cls (); - grub_setcursor (1); - - if (auto_boot) - { - grub_menu_execute_with_fallback (menu, e, &execution_callback, 0); - } - else - { - grub_errno = GRUB_ERR_NONE; - grub_menu_execute_entry (e); - if (grub_errno != GRUB_ERR_NONE) - { - grub_print_error (); - grub_errno = GRUB_ERR_NONE; - grub_wait_after_message (); - } - } + data->first = entry - (grub_term_num_entries (data->term) - 1); + data->offset = grub_term_num_entries (data->term) - 1; + complete_redraw = 1; } + if (data->offset < 0) + { + data->offset = 0; + data->first = entry; + complete_redraw = 1; + } + if (complete_redraw) + print_entries (data->menu, data->first, data->offset, data->term); + else + { + print_entry (GRUB_TERM_FIRST_ENTRY_Y + oldoffset, 0, + grub_menu_get_entry (data->menu, data->first + oldoffset), + data->term); + print_entry (GRUB_TERM_FIRST_ENTRY_Y + data->offset, 1, + grub_menu_get_entry (data->menu, data->first + data->offset), + data->term); + } + grub_term_refresh (data->term); +} + +static void +menu_text_fini (void *dataptr) +{ + struct menu_viewer_data *data = dataptr; + + grub_term_setcursor (data->term, 1); + grub_term_cls (data->term); + +} + +static void +menu_text_clear_timeout (void *dataptr) +{ + struct menu_viewer_data *data = dataptr; + + grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3); + print_spaces (grub_term_width (data->term) - 1, data->term); + grub_term_gotoxy (data->term, grub_term_cursor_x (data->term), + GRUB_TERM_FIRST_ENTRY_Y + data->offset); + grub_term_refresh (data->term); +} + +grub_err_t +grub_menu_try_text (struct grub_term_output *term, + int entry, grub_menu_t menu, int nested) +{ + struct menu_viewer_data *data; + struct grub_menu_viewer *instance; + + instance = grub_zalloc (sizeof (*instance)); + if (!instance) + return grub_errno; + + data = grub_zalloc (sizeof (*data)); + if (!data) + { + grub_free (instance); + return grub_errno; + } + + data->term = term; + instance->data = data; + instance->set_chosen_entry = menu_text_set_chosen_entry; + instance->print_timeout = menu_text_print_timeout; + instance->clear_timeout = menu_text_clear_timeout; + instance->fini = menu_text_fini; + + data->menu = menu; + + data->offset = entry; + data->first = 0; + if (data->offset > grub_term_num_entries (data->term) - 1) + { + data->first = data->offset - (grub_term_num_entries (data->term) - 1); + data->offset = grub_term_num_entries (data->term) - 1; + } + + grub_term_setcursor (data->term, 0); + grub_menu_init_page (nested, 0, data->term); + print_entries (menu, data->first, data->offset, data->term); + grub_term_refresh (data->term); + grub_menu_register_viewer (instance); return GRUB_ERR_NONE; } - -struct grub_menu_viewer grub_normal_text_menu_viewer = -{ - .name = "text", - .show_menu = show_text_menu -}; diff --git a/normal/menu_viewer.c b/normal/menu_viewer.c deleted file mode 100644 index 1bd271a21..000000000 --- a/normal/menu_viewer.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 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 . - */ - -#include -#include -#include -#include -#include -#include - -/* The list of menu viewers. */ -static grub_menu_viewer_t menu_viewer_list; - -void -grub_menu_viewer_register (grub_menu_viewer_t viewer) -{ - viewer->next = menu_viewer_list; - menu_viewer_list = viewer; -} - -static grub_menu_viewer_t get_current_menu_viewer (void) -{ - const char *selected_name = grub_env_get ("menuviewer"); - - /* If none selected, pick the last registered one. */ - if (selected_name == 0) - return menu_viewer_list; - - grub_menu_viewer_t cur; - for (cur = menu_viewer_list; cur; cur = cur->next) - { - if (grub_strcmp (cur->name, selected_name) == 0) - return cur; - } - - /* Fall back to the first entry (or null). */ - return menu_viewer_list; -} - -grub_err_t -grub_menu_viewer_show_menu (grub_menu_t menu, int nested) -{ - grub_menu_viewer_t cur = get_current_menu_viewer (); - grub_err_t err1, err2; - if (!cur) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available."); - - while (1) - { - err1 = cur->show_menu (menu, nested); - grub_print_error (); - - err2 = grub_auth_check_authentication (NULL); - if (err2) - { - grub_print_error (); - grub_errno = GRUB_ERR_NONE; - continue; - } - - break; - } - - return err1; -} - diff --git a/normal/misc.c b/normal/misc.c index 0a1a2f052..17ba372ce 100644 --- a/normal/misc.c +++ b/normal/misc.c @@ -1,7 +1,7 @@ /* misc.c - miscellaneous functions */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2005,2007,2008,2009 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 @@ -24,6 +24,8 @@ #include #include #include +#include +#include /* Print the information on the device NAME. */ grub_err_t @@ -34,13 +36,20 @@ grub_normal_print_device_info (const char *name) p = grub_strchr (name, ','); if (p) - grub_printf ("\tPartition %s: ", name); + { + grub_putchar ('\t'); + grub_printf_ (N_("Partition %s:"), name); + grub_putchar (' '); + } else - grub_printf ("Device %s: ", name); + { + grub_printf_ (N_("Device %s:"), name); + grub_putchar (' '); + } dev = grub_device_open (name); if (! dev) - grub_printf ("Filesystem cannot be accessed"); + grub_printf ("%s", _("Filesystem cannot be accessed")); else if (dev->disk) { grub_fs_t fs; @@ -51,7 +60,7 @@ grub_normal_print_device_info (const char *name) if (fs) { - grub_printf ("Filesystem type %s", fs->name); + grub_printf_ (N_("Filesystem type %s"), fs->name); if (fs->label) { char *label; @@ -59,7 +68,10 @@ grub_normal_print_device_info (const char *name) if (grub_errno == GRUB_ERR_NONE) { if (label && grub_strlen (label)) - grub_printf (", Label %s", label); + { + grub_putchar (' '); + grub_printf_ (N_("- Label \"%s\""), label); + } grub_free (label); } grub_errno = GRUB_ERR_NONE; @@ -72,8 +84,9 @@ grub_normal_print_device_info (const char *name) if (grub_errno == GRUB_ERR_NONE) { grub_unixtime2datetime (tm, &datetime); - grub_printf (", Last modification time %d-%02d-%02d " - "%02d:%02d:%02d %s", + grub_putchar (' '); + grub_printf_ (N_("- Last modification time %d-%02d-%02d " + "%02d:%02d:%02d %s"), datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second, grub_get_weekday_name (&datetime)); @@ -95,13 +108,13 @@ grub_normal_print_device_info (const char *name) } } else if (! dev->disk->has_partitions || dev->disk->partition) - grub_printf ("Unknown filesystem"); + grub_printf ("%s", _("Unknown filesystem")); else - grub_printf ("Partition table"); + grub_printf ("%s", _("Partition table")); grub_device_close (dev); } - grub_printf ("\n"); + grub_putchar ('\n'); return grub_errno; } diff --git a/normal/term.c b/normal/term.c new file mode 100644 index 000000000..688141dab --- /dev/null +++ b/normal/term.c @@ -0,0 +1,264 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2007,2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +/* The amount of lines counted by the pager. */ +static unsigned grub_more_lines; + +/* If the more pager is active. */ +static int grub_more; + +static int grub_normal_line_counter = 0; + +int +grub_normal_get_line_counter (void) +{ + return grub_normal_line_counter; +} + +static void +process_newline (void) +{ + struct grub_term_output *cur; + unsigned height = -1; + + FOR_ACTIVE_TERM_OUTPUTS(cur) + if (grub_term_height (cur) < height) + height = grub_term_height (cur); + grub_more_lines++; + + grub_normal_line_counter++; + + if (grub_more && grub_more_lines >= height - 1) + { + char key; + grub_uint16_t *pos; + + pos = grub_term_save_pos (); + + grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); + grub_printf ("--MORE--"); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + + key = grub_getkey (); + + /* Remove the message. */ + grub_term_restore_pos (pos); + grub_printf (" "); + grub_term_restore_pos (pos); + + /* Scroll one lines or an entire page, depending on the key. */ + if (key == '\r' || key =='\n') + grub_more_lines = height - 2; + else + grub_more_lines = 0; + } +} + +void +grub_set_more (int onoff) +{ + if (onoff == 1) + grub_more++; + else + grub_more--; + + grub_more_lines = 0; +} + +void +grub_install_newline_hook (void) +{ + grub_newline_hook = process_newline; +} + +void +grub_puts_terminal (const char *str, struct grub_term_output *term) +{ + grub_uint32_t code; + grub_ssize_t ret; + const grub_uint8_t *ptr = (const grub_uint8_t *) str; + const grub_uint8_t *end; + end = (const grub_uint8_t *) (str + grub_strlen (str)); + + while (*ptr) + { + ret = grub_utf8_to_ucs4 (&code, 1, ptr, end - ptr, &ptr); + grub_putcode (code, term); + } +} + +grub_uint16_t * +grub_term_save_pos (void) +{ + struct grub_term_output *cur; + unsigned cnt = 0; + grub_uint16_t *ret, *ptr; + + FOR_ACTIVE_TERM_OUTPUTS(cur) + cnt++; + + ret = grub_malloc (cnt * sizeof (ret[0])); + if (!ret) + return NULL; + + ptr = ret; + FOR_ACTIVE_TERM_OUTPUTS(cur) + *ptr++ = grub_term_getxy (cur); + + return ret; +} + +void +grub_term_restore_pos (grub_uint16_t *pos) +{ + struct grub_term_output *cur; + grub_uint16_t *ptr = pos; + + if (!pos) + return; + + FOR_ACTIVE_TERM_OUTPUTS(cur) + { + grub_term_gotoxy (cur, (*ptr & 0xff00) >> 8, *ptr & 0xff); + ptr++; + } +} + +static void +grub_terminal_autoload_free (void) +{ + struct grub_term_autoload *cur, *next; + unsigned i; + for (i = 0; i < 2; i++) + for (cur = i ? grub_term_input_autoload : grub_term_output_autoload; + cur; cur = next) + { + next = cur->next; + grub_free (cur->name); + grub_free (cur->modname); + grub_free (cur); + } + grub_term_input_autoload = NULL; + grub_term_output_autoload = NULL; +} + +/* Read the file terminal.lst for auto-loading. */ +void +read_terminal_list (const char *prefix) +{ + char *filename; + grub_file_t file; + char *buf = NULL; + + if (!prefix) + { + grub_errno = GRUB_ERR_NONE; + return; + } + + filename = grub_xasprintf ("%s/terminal.lst", prefix); + if (!filename) + { + grub_errno = GRUB_ERR_NONE; + return; + } + + file = grub_file_open (filename); + grub_free (filename); + if (!file) + { + grub_errno = GRUB_ERR_NONE; + return; + } + + /* Override previous terminal.lst. */ + grub_terminal_autoload_free (); + + for (;; grub_free (buf)) + { + char *p, *name; + struct grub_term_autoload *cur; + struct grub_term_autoload **target = NULL; + + buf = grub_file_getline (file); + + if (! buf) + break; + + switch (buf[0]) + { + case 'i': + target = &grub_term_input_autoload; + break; + + case 'o': + target = &grub_term_output_autoload; + break; + } + if (!target) + continue; + + name = buf + 1; + + p = grub_strchr (name, ':'); + if (! p) + continue; + + *p = '\0'; + while (*++p == ' ') + ; + + cur = grub_malloc (sizeof (*cur)); + if (!cur) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + + cur->name = grub_strdup (name); + if (! name) + { + grub_errno = GRUB_ERR_NONE; + grub_free (cur); + continue; + } + + cur->modname = grub_strdup (p); + if (! cur->modname) + { + grub_errno = GRUB_ERR_NONE; + grub_free (cur); + grub_free (cur->name); + continue; + } + cur->next = *target; + *target = cur; + } + + grub_file_close (file); + + grub_errno = GRUB_ERR_NONE; +} diff --git a/partmap/acorn.c b/partmap/acorn.c index e005975c0..677ec61d5 100644 --- a/partmap/acorn.c +++ b/partmap/acorn.c @@ -85,7 +85,7 @@ acorn_partition_map_find (grub_disk_t disk, struct linux_part *m, fail: return grub_error (GRUB_ERR_BAD_PART_TABLE, - "Linux/ADFS partition map not found."); + "Linux/ADFS partition map not found"); } @@ -96,17 +96,12 @@ acorn_partition_map_iterate (grub_disk_t disk, const grub_partition_t partition)) { struct grub_partition part; - struct grub_disk raw; struct linux_part map[LINUX_MAP_ENTRIES]; int i; - grub_disk_addr_t sector; + grub_disk_addr_t sector = 0; grub_err_t err; - /* Enforce raw disk access. */ - raw = *disk; - raw.partition = 0; - - err = acorn_partition_map_find (&raw, map, §or); + err = acorn_partition_map_find (disk, map, §or); if (err) return err; @@ -121,7 +116,7 @@ acorn_partition_map_iterate (grub_disk_t disk, part.start = sector + map[i].start; part.len = map[i].size; part.offset = 6; - part.index = i; + part.number = part.index = i; if (hook (disk, &part)) return grub_errno; @@ -130,77 +125,21 @@ acorn_partition_map_iterate (grub_disk_t disk, return GRUB_ERR_NONE; } - -static grub_partition_t -acorn_partition_map_probe (grub_disk_t disk, const char *str) -{ - struct linux_part map[LINUX_MAP_ENTRIES]; - struct grub_disk raw = *disk; - unsigned long partnum = grub_strtoul (str, 0, 10) - 1; - grub_disk_addr_t sector; - grub_err_t err; - grub_partition_t p; - - /* Enforce raw disk access. */ - raw.partition = 0; - - /* Get the partition number. */ - if (partnum > LINUX_MAP_ENTRIES) - goto fail; - - err = acorn_partition_map_find (&raw, map, §or); - if (err) - return 0; - - if (map[partnum].magic != LINUX_NATIVE_MAGIC - && map[partnum].magic != LINUX_SWAP_MAGIC) - goto fail; - - p = grub_malloc (sizeof (struct grub_partition)); - if (! p) - return 0; - - p->start = sector + map[partnum].start; - p->len = map[partnum].size; - p->offset = 6; - p->index = partnum; - return p; - -fail: - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - return 0; -} - - -static char * -acorn_partition_map_get_name (const grub_partition_t p) -{ - char *name; - - name = grub_malloc (13); - if (! name) - return 0; - - grub_sprintf (name, "%d", p->index + 1); - return name; -} /* Partition map type. */ static struct grub_partition_map grub_acorn_partition_map = { - .name = "part_acorn", + .name = "acorn", .iterate = acorn_partition_map_iterate, - .probe = acorn_partition_map_probe, - .get_name = acorn_partition_map_get_name }; -GRUB_MOD_INIT(acorn_partition_map) +GRUB_MOD_INIT(part_acorn) { grub_partition_map_register (&grub_acorn_partition_map); } -GRUB_MOD_FINI(acorn_partition_map) +GRUB_MOD_FINI(part_acorn) { grub_partition_map_unregister (&grub_acorn_partition_map); } diff --git a/partmap/amiga.c b/partmap/amiga.c index dce9f4f1f..f21c5b243 100644 --- a/partmap/amiga.c +++ b/partmap/amiga.c @@ -76,20 +76,15 @@ amiga_partition_map_iterate (grub_disk_t disk, { struct grub_partition part; struct grub_amiga_rdsk rdsk; - struct grub_disk raw; int partno = 0; int next = -1; unsigned pos; - /* Enforce raw disk access. */ - raw = *disk; - raw.partition = 0; - /* The RDSK block is one of the first 15 blocks. */ for (pos = 0; pos < 15; pos++) { /* Read the RDSK block which is a descriptor for the entire disk. */ - if (grub_disk_read (&raw, pos, 0, sizeof (rdsk), &rdsk)) + if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk)) return grub_errno; if (grub_strcmp ((char *) rdsk.magic, "RDSK") == 0) @@ -102,7 +97,7 @@ amiga_partition_map_iterate (grub_disk_t disk, if (next == -1) return grub_error (GRUB_ERR_BAD_PART_TABLE, - "Amiga partition map not found."); + "Amiga partition map not found"); /* The end of the partition list is marked using "-1". */ while (next != -1) @@ -110,7 +105,7 @@ amiga_partition_map_iterate (grub_disk_t disk, struct grub_amiga_partition apart; /* Read the RDSK block which is a descriptor for the entire disk. */ - if (grub_disk_read (&raw, next, 0, sizeof (apart), &apart)) + if (grub_disk_read (disk, next, 0, sizeof (apart), &apart)) return grub_errno; /* Calculate the first block and the size of the partition. */ @@ -123,7 +118,8 @@ amiga_partition_map_iterate (grub_disk_t disk, * grub_be_to_cpu32 (apart.block_per_track)); part.offset = (grub_off_t) next * 512; - part.index = partno; + part.number = partno; + part.index = 0; part.partmap = &grub_amiga_partition_map; if (hook (disk, &part)) @@ -136,80 +132,20 @@ amiga_partition_map_iterate (grub_disk_t disk, return 0; } - -static grub_partition_t -amiga_partition_map_probe (grub_disk_t disk, const char *str) -{ - grub_partition_t p = 0; - int partnum = 0; - char *s = (char *) str; - - auto int find_func (grub_disk_t d, const grub_partition_t partition); - - int find_func (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition) - { - if (partnum == partition->index) - { - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (! p) - return 1; - - grub_memcpy (p, partition, sizeof (*p)); - return 1; - } - - return 0; - } - - /* Get the partition number. */ - partnum = grub_strtoul (s, 0, 10) - 1; - if (grub_errno) - { - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - return 0; - } - - if (amiga_partition_map_iterate (disk, find_func)) - goto fail; - - return p; - - fail: - grub_free (p); - return 0; -} - - -static char * -amiga_partition_map_get_name (const grub_partition_t p) -{ - char *name; - - name = grub_malloc (13); - if (! name) - return 0; - - grub_sprintf (name, "%d", p->index + 1); - return name; -} - /* Partition map type. */ static struct grub_partition_map grub_amiga_partition_map = { - .name = "part_amiga", + .name = "amiga", .iterate = amiga_partition_map_iterate, - .probe = amiga_partition_map_probe, - .get_name = amiga_partition_map_get_name }; -GRUB_MOD_INIT(amiga_partition_map) +GRUB_MOD_INIT(part_amiga) { grub_partition_map_register (&grub_amiga_partition_map); } -GRUB_MOD_FINI(amiga_partition_map) +GRUB_MOD_FINI(part_amiga) { grub_partition_map_unregister (&grub_amiga_partition_map); } diff --git a/partmap/apple.c b/partmap/apple.c index 4dea55a32..e162d18d7 100644 --- a/partmap/apple.c +++ b/partmap/apple.c @@ -1,7 +1,7 @@ /* apple.c - Read macintosh partition tables. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2004,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2004,2005,2006,2007,2008,2009 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 @@ -105,17 +105,12 @@ apple_partition_map_iterate (grub_disk_t disk, struct grub_partition part; struct grub_apple_header aheader; struct grub_apple_part apart; - struct grub_disk raw; int partno = 0, partnum = 0; unsigned pos; - /* Enforce raw disk access. */ - raw = *disk; - raw.partition = 0; - part.partmap = &grub_apple_partition_map; - if (grub_disk_read (&raw, 0, 0, sizeof (aheader), &aheader)) + if (grub_disk_read (disk, 0, 0, sizeof (aheader), &aheader)) return grub_errno; if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC) @@ -131,8 +126,10 @@ apple_partition_map_iterate (grub_disk_t disk, do { - if (grub_disk_read (&raw, pos / GRUB_DISK_SECTOR_SIZE, - pos % GRUB_DISK_SECTOR_SIZE, + part.offset = pos / GRUB_DISK_SECTOR_SIZE; + part.index = pos % GRUB_DISK_SECTOR_SIZE; + + if (grub_disk_read (disk, part.offset, part.index, sizeof (struct grub_apple_part), &apart)) return grub_errno; @@ -156,6 +153,7 @@ apple_partition_map_iterate (grub_disk_t disk, / GRUB_DISK_SECTOR_SIZE; part.offset = pos; part.index = partno; + part.number = partno; grub_dprintf ("partition", "partition %d: name %s, type %s, start 0x%x, len 0x%x\n", @@ -176,83 +174,23 @@ apple_partition_map_iterate (grub_disk_t disk, fail: return grub_error (GRUB_ERR_BAD_PART_TABLE, - "Apple partition map not found."); -} - - -static grub_partition_t -apple_partition_map_probe (grub_disk_t disk, const char *str) -{ - grub_partition_t p = 0; - int partnum = 0; - char *s = (char *) str; - - auto int find_func (grub_disk_t d, const grub_partition_t partition); - - int find_func (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition) - { - if (partnum == partition->index) - { - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (! p) - return 1; - - grub_memcpy (p, partition, sizeof (*p)); - return 1; - } - - return 0; - } - - /* Get the partition number. */ - partnum = grub_strtoul (s, 0, 10) - 1; - if (grub_errno) - { - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - return 0; - } - - if (apple_partition_map_iterate (disk, find_func)) - goto fail; - - return p; - - fail: - grub_free (p); - return 0; -} - - -static char * -apple_partition_map_get_name (const grub_partition_t p) -{ - char *name; - - name = grub_malloc (13); - if (! name) - return 0; - - grub_sprintf (name, "%d", p->index + 1); - return name; + "Apple partition map not found"); } /* Partition map type. */ static struct grub_partition_map grub_apple_partition_map = { - .name = "part_apple", + .name = "apple", .iterate = apple_partition_map_iterate, - .probe = apple_partition_map_probe, - .get_name = apple_partition_map_get_name }; -GRUB_MOD_INIT(apple_partition_map) +GRUB_MOD_INIT(part_apple) { grub_partition_map_register (&grub_apple_partition_map); } -GRUB_MOD_FINI(apple_partition_map) +GRUB_MOD_FINI(part_apple) { grub_partition_map_unregister (&grub_apple_partition_map); } diff --git a/partmap/bsdlabel.c b/partmap/bsdlabel.c new file mode 100644 index 000000000..d28f36d07 --- /dev/null +++ b/partmap/bsdlabel.c @@ -0,0 +1,97 @@ +/* bsdlabel.c - Read BSD style partition tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2005,2006,2007,2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include + +static struct grub_partition_map grub_bsdlabel_partition_map; + + +static grub_err_t +bsdlabel_partition_map_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) +{ + struct grub_partition_bsd_disk_label label; + struct grub_partition p; + grub_disk_addr_t delta = 0; + unsigned pos; + + /* BSDLabel offsets are absolute even when it's embed inside partition. */ + delta = grub_partition_get_start (disk->partition); + + /* Read the BSD label. */ + if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, + 0, sizeof (label), &label)) + return grub_errno; + + /* Check if it is valid. */ + if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); + + pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR + * GRUB_DISK_SECTOR_SIZE; + + for (p.number = 0; + p.number < grub_cpu_to_le16 (label.num_partitions); + p.number++) + { + struct grub_partition_bsd_entry be; + + p.offset = pos / GRUB_DISK_SECTOR_SIZE; + p.index = pos % GRUB_DISK_SECTOR_SIZE; + + if (grub_disk_read (disk, p.offset, p.index, sizeof (be), &be)) + return grub_errno; + + p.start = grub_le_to_cpu32 (be.offset) - delta; + p.len = grub_le_to_cpu32 (be.size); + p.partmap = &grub_bsdlabel_partition_map; + + if (be.fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED) + if (hook (disk, &p)) + return grub_errno; + + pos += sizeof (struct grub_partition_bsd_entry); + } + + return GRUB_ERR_NONE; +} + + +/* Partition map type. */ +static struct grub_partition_map grub_bsdlabel_partition_map = + { + .name = "bsd", + .iterate = bsdlabel_partition_map_iterate, + }; + +GRUB_MOD_INIT(part_bsd) +{ + grub_partition_map_register (&grub_bsdlabel_partition_map); +} + +GRUB_MOD_FINI(part_bsd) +{ + grub_partition_map_unregister (&grub_bsdlabel_partition_map); +} diff --git a/partmap/gpt.c b/partmap/gpt.c index 4a4957437..9dd88bec1 100644 --- a/partmap/gpt.c +++ b/partmap/gpt.c @@ -44,18 +44,13 @@ gpt_partition_map_iterate (grub_disk_t disk, struct grub_partition part; struct grub_gpt_header gpt; struct grub_gpt_partentry entry; - struct grub_disk raw; struct grub_msdos_partition_mbr mbr; grub_uint64_t entries; unsigned int i; int last_offset = 0; - /* Enforce raw disk access. */ - raw = *disk; - raw.partition = 0; - /* Read the protective MBR. */ - if (grub_disk_read (&raw, 0, 0, sizeof (mbr), &mbr)) + if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr)) return grub_errno; /* Check if it is valid. */ @@ -67,7 +62,7 @@ gpt_partition_map_iterate (grub_disk_t disk, return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found"); /* Read the GPT header. */ - if (grub_disk_read (&raw, 1, 0, sizeof (gpt), &gpt)) + if (grub_disk_read (disk, 1, 0, sizeof (gpt), &gpt)) return grub_errno; if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic))) @@ -78,7 +73,7 @@ gpt_partition_map_iterate (grub_disk_t disk, entries = grub_le_to_cpu64 (gpt.partitions); for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++) { - if (grub_disk_read (&raw, entries, last_offset, + if (grub_disk_read (disk, entries, last_offset, sizeof (entry), &entry)) return grub_errno; @@ -90,16 +85,16 @@ gpt_partition_map_iterate (grub_disk_t disk, part.len = (grub_le_to_cpu64 (entry.end) - grub_le_to_cpu64 (entry.start) + 1); part.offset = entries; - part.index = i; + part.number = i; + part.index = last_offset; part.partmap = &grub_gpt_partition_map; - part.data = &entry; grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i, (unsigned long long) part.start, (unsigned long long) part.len); if (hook (disk, &part)) - return 1; + return grub_errno; } last_offset += grub_le_to_cpu32 (gpt.partentry_size); @@ -110,84 +105,23 @@ gpt_partition_map_iterate (grub_disk_t disk, } } - return 0; -} - - -static grub_partition_t -gpt_partition_map_probe (grub_disk_t disk, const char *str) -{ - grub_partition_t p = 0; - int partnum = 0; - char *s = (char *) str; - - auto int find_func (grub_disk_t d, const grub_partition_t partition); - - int find_func (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition) - { - if (partnum == partition->index) - { - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (! p) - return 1; - - grub_memcpy (p, partition, sizeof (*p)); - return 1; - } - - return 0; - } - - /* Get the partition number. */ - partnum = grub_strtoul (s, 0, 10) - 1; - if (grub_errno) - { - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - return 0; - } - - gpt_partition_map_iterate (disk, find_func); - if (grub_errno) - goto fail; - - return p; - - fail: - grub_free (p); - return 0; -} - - -static char * -gpt_partition_map_get_name (const grub_partition_t p) -{ - char *name; - - name = grub_malloc (13); - if (! name) - return 0; - - grub_sprintf (name, "%d", p->index + 1); - return name; + return GRUB_ERR_NONE; } /* Partition map type. */ static struct grub_partition_map grub_gpt_partition_map = { - .name = "part_gpt", + .name = "gpt", .iterate = gpt_partition_map_iterate, - .probe = gpt_partition_map_probe, - .get_name = gpt_partition_map_get_name }; -GRUB_MOD_INIT(gpt_partition_map) +GRUB_MOD_INIT(part_gpt) { grub_partition_map_register (&grub_gpt_partition_map); } -GRUB_MOD_FINI(gpt_partition_map) +GRUB_MOD_FINI(part_gpt) { grub_partition_map_unregister (&grub_gpt_partition_map); } diff --git a/partmap/msdos.c b/partmap/msdos.c index 6ba7fb927..3898d09fa 100644 --- a/partmap/msdos.c +++ b/partmap/msdos.c @@ -27,87 +27,20 @@ static struct grub_partition_map grub_msdos_partition_map; -/* Parse the partition representation in STR and return a partition. */ -static grub_partition_t -grub_partition_parse (const char *str) -{ - grub_partition_t p; - struct grub_msdos_partition *pcdata; - - char *s = (char *) str; - - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (! p) - return 0; - - pcdata = (struct grub_msdos_partition *) grub_malloc (sizeof (*pcdata)); - if (! pcdata) - goto fail; - - p->data = pcdata; - p->partmap = &grub_msdos_partition_map; - - /* Initialize some of the fields with invalid values. */ - pcdata->bsd_part = pcdata->dos_type = pcdata->bsd_type = p->index = -1; - - /* Get the DOS partition number. The number is counted from one for - the user interface, and from zero internally. */ - pcdata->dos_part = grub_strtoul (s, &s, 0) - 1; - - if (grub_errno) - { - /* Not found. Maybe only a BSD label is specified. */ - pcdata->dos_part = -1; - grub_errno = GRUB_ERR_NONE; - } - else if (*s == ',') - s++; - - if (*s) - { - if (*s >= 'a' && *s <= 'h') - { - pcdata->bsd_part = *s - 'a'; - s++; - } - - if (*s) - goto fail; - } - - if (pcdata->dos_part == -1 && pcdata->bsd_part == -1) - goto fail; - - return p; - - fail: - grub_free (p); - grub_free (pcdata); - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - return 0; -} - static grub_err_t pc_partition_map_iterate (grub_disk_t disk, int (*hook) (grub_disk_t disk, const grub_partition_t partition)) { struct grub_partition p; - struct grub_msdos_partition pcdata; struct grub_msdos_partition_mbr mbr; - struct grub_msdos_partition_disk_label label; - struct grub_disk raw; int labeln = 0; grub_disk_addr_t lastaddr; - - /* Enforce raw disk access. */ - raw = *disk; - raw.partition = 0; + grub_disk_addr_t ext_offset; p.offset = 0; - pcdata.ext_offset = 0; - pcdata.dos_part = -1; - p.data = &pcdata; + ext_offset = 0; + p.number = -1; p.partmap = &grub_msdos_partition_map; /* Any value different than `p.offset' will satisfy the check during @@ -120,7 +53,7 @@ pc_partition_map_iterate (grub_disk_t disk, struct grub_msdos_partition_entry *e; /* Read the MBR. */ - if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), &mbr)) + if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr)) goto finish; /* This is our loop-detection algorithm. It works the following way: @@ -150,13 +83,10 @@ pc_partition_map_iterate (grub_disk_t disk, p.start = p.offset + grub_le_to_cpu32 (e->start); p.len = grub_le_to_cpu32 (e->length); - pcdata.bsd_part = -1; - pcdata.dos_type = e->type; - pcdata.bsd_type = -1; grub_dprintf ("partition", "partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n", - p.index, e->flag, pcdata.dos_type, + p.index, e->flag, e->type, (unsigned long long) p.start, (unsigned long long) p.len); @@ -168,59 +98,15 @@ pc_partition_map_iterate (grub_disk_t disk, if (! grub_msdos_partition_is_empty (e->type) && ! grub_msdos_partition_is_extended (e->type)) { - pcdata.dos_part++; + p.number++; if (hook (disk, &p)) - return 1; - - /* Check if this is a BSD partition. */ - if (grub_msdos_partition_is_bsd (e->type)) - { - /* Check if the BSD label is within the DOS partition. */ - if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR) - { - grub_dprintf ("partition", "no space for disk label\n"); - continue; - } - /* Read the BSD label. */ - if (grub_disk_read (&raw, - (p.start - + GRUB_PC_PARTITION_BSD_LABEL_SECTOR), - 0, - sizeof (label), - &label)) - goto finish; - - /* Check if it is valid. */ - if (label.magic - != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC)) - { - grub_dprintf ("partition", - "invalid disk label magic 0x%x on partition %d\n", - label.magic, p.index); - continue; - } - for (pcdata.bsd_part = 0; - pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions); - pcdata.bsd_part++) - { - struct grub_msdos_partition_bsd_entry *be - = label.entries + pcdata.bsd_part; - - p.start = grub_le_to_cpu32 (be->offset); - p.len = grub_le_to_cpu32 (be->size); - pcdata.bsd_type = be->fs_type; - - if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED) - if (hook (disk, &p)) - return 1; - } - } + return grub_errno; } - else if (pcdata.dos_part < 4) + else if (p.number < 4) /* If this partition is a logical one, shouldn't increase the partition number. */ - pcdata.dos_part++; + p.number++; } /* Find an extended partition. */ @@ -230,9 +116,9 @@ pc_partition_map_iterate (grub_disk_t disk, if (grub_msdos_partition_is_extended (e->type)) { - p.offset = pcdata.ext_offset + grub_le_to_cpu32 (e->start); - if (! pcdata.ext_offset) - pcdata.ext_offset = p.offset; + p.offset = ext_offset + grub_le_to_cpu32 (e->start); + if (! ext_offset) + ext_offset = p.offset; break; } @@ -247,92 +133,20 @@ pc_partition_map_iterate (grub_disk_t disk, return grub_errno; } - -static grub_partition_t -pc_partition_map_probe (grub_disk_t disk, const char *str) -{ - grub_partition_t p; - struct grub_msdos_partition *pcdata; - - auto int find_func (grub_disk_t d, const grub_partition_t partition); - - int find_func (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition) - { - struct grub_msdos_partition *partdata = partition->data; - - if ((pcdata->dos_part == partdata->dos_part || pcdata->dos_part == -1) - && pcdata->bsd_part == partdata->bsd_part) - { - grub_memcpy (p, partition, sizeof (*p)); - p->data = pcdata; - grub_memcpy (pcdata, partdata, sizeof (*pcdata)); - return 1; - } - - return 0; - } - - p = grub_partition_parse (str); - if (! p) - return 0; - - pcdata = p->data; - pc_partition_map_iterate (disk, find_func); - if (grub_errno) - goto fail; - - if (p->index < 0) - { - grub_error (GRUB_ERR_BAD_DEVICE, "no such partition"); - goto fail; - } - - return p; - - fail: - grub_free (p); - grub_free (pcdata); - return 0; -} - - -static char * -pc_partition_map_get_name (const grub_partition_t p) -{ - char *name; - struct grub_msdos_partition *pcdata = p->data; - - name = grub_malloc (13); - if (! name) - return 0; - - if (pcdata->bsd_part < 0) - grub_sprintf (name, "%d", pcdata->dos_part + 1); - else if (pcdata->dos_part < 0) - grub_sprintf (name, "%c", pcdata->bsd_part + 'a'); - else - grub_sprintf (name, "%d,%c", pcdata->dos_part + 1, pcdata->bsd_part + 'a'); - - return name; -} - /* Partition map type. */ static struct grub_partition_map grub_msdos_partition_map = { - .name = "part_msdos", + .name = "msdos", .iterate = pc_partition_map_iterate, - .probe = pc_partition_map_probe, - .get_name = pc_partition_map_get_name }; -GRUB_MOD_INIT(pc_partition_map) +GRUB_MOD_INIT(part_msdos) { grub_partition_map_register (&grub_msdos_partition_map); } -GRUB_MOD_FINI(pc_partition_map) +GRUB_MOD_FINI(part_msdos) { grub_partition_map_unregister (&grub_msdos_partition_map); } diff --git a/partmap/sun.c b/partmap/sun.c index e816ec17a..7a7eaef27 100644 --- a/partmap/sun.c +++ b/partmap/sun.c @@ -88,48 +88,55 @@ sun_partition_map_iterate (grub_disk_t disk, const grub_partition_t partition)) { grub_partition_t p; - struct grub_disk raw; struct grub_sun_block block; int partnum; - - raw = *disk; - raw.partition = 0; + grub_err_t err; p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition)); if (! p) return grub_errno; p->partmap = &grub_sun_partition_map; - if (grub_disk_read (&raw, 0, 0, sizeof (struct grub_sun_block), - &block) == GRUB_ERR_NONE) + err = grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block), + &block); + if (err) { - if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic)) - grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun partition table"); + grub_free (p); + return err; + } - if (! grub_sun_is_valid (&block)) - grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum"); + if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic)) + { + grub_free (p); + return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun partition table"); + } - /* Maybe another error value would be better, because partition - table _is_ recognized but invalid. */ - for (partnum = 0; partnum < GRUB_PARTMAP_SUN_MAX_PARTS; partnum++) + if (! grub_sun_is_valid (&block)) + { + grub_free (p); + return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum"); + } + + /* Maybe another error value would be better, because partition + table _is_ recognized but invalid. */ + for (partnum = 0; partnum < GRUB_PARTMAP_SUN_MAX_PARTS; partnum++) + { + struct grub_sun_partition_descriptor *desc; + + if (block.infos[partnum].id == 0 + || block.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID) + continue; + + desc = &block.partitions[partnum]; + p->start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder) + * grub_be_to_cpu16 (block.ntrks) + * grub_be_to_cpu16 (block.nsect)); + p->len = grub_be_to_cpu32 (desc->num_sectors); + p->number = p->index = partnum; + if (p->len) { - struct grub_sun_partition_descriptor *desc; - - if (block.infos[partnum].id == 0 - || block.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID) - continue; - - desc = &block.partitions[partnum]; - p->start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder) - * grub_be_to_cpu16 (block.ntrks) - * grub_be_to_cpu16 (block.nsect)); - p->len = grub_be_to_cpu32 (desc->num_sectors); - p->index = partnum; - if (p->len) - { - if (hook (disk, p)) - partnum = GRUB_PARTMAP_SUN_MAX_PARTS; - } + if (hook (disk, p)) + partnum = GRUB_PARTMAP_SUN_MAX_PARTS; } } @@ -138,76 +145,19 @@ sun_partition_map_iterate (grub_disk_t disk, return grub_errno; } -static grub_partition_t -sun_partition_map_probe (grub_disk_t disk, const char *str) -{ - grub_partition_t p = 0; - int partnum = 0; - char *s = (char *) str; - - auto int find_func (grub_disk_t d, const grub_partition_t partition); - - int find_func (grub_disk_t d __attribute__ ((unused)), - const grub_partition_t partition) - { - if (partnum == partition->index) - { - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (p) - grub_memcpy (p, partition, sizeof (*p)); - - return 1; - } - - return 0; - } - - grub_errno = GRUB_ERR_NONE; - partnum = grub_strtoul (s, 0, 10) - 1; - if (grub_errno == GRUB_ERR_NONE) - { - if (sun_partition_map_iterate (disk, find_func)) - { - grub_free (p); - p = 0; - } - } - else - { - grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition"); - p = 0; - } - - return p; -} - -static char * -sun_partition_map_get_name (const grub_partition_t p) -{ - char *name; - - name = grub_malloc (13); - if (name) - grub_sprintf (name, "%d", p->index + 1); - - return name; -} - /* Partition map type. */ static struct grub_partition_map grub_sun_partition_map = { - .name = "part_sun", + .name = "sun", .iterate = sun_partition_map_iterate, - .probe = sun_partition_map_probe, - .get_name = sun_partition_map_get_name }; -GRUB_MOD_INIT(sun_partition_map) +GRUB_MOD_INIT(part_sun) { grub_partition_map_register (&grub_sun_partition_map); } -GRUB_MOD_FINI(sun_partition_map) +GRUB_MOD_FINI(part_sun) { grub_partition_map_unregister (&grub_sun_partition_map); } diff --git a/partmap/sunpc.c b/partmap/sunpc.c new file mode 100644 index 000000000..ea69c28b9 --- /dev/null +++ b/partmap/sunpc.c @@ -0,0 +1,144 @@ +/* sunpc.c - Read SUN PC style partition tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2006,2007,2009 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GRUB_PARTMAP_SUN_PC_MAGIC 0xDABE +#define GRUB_PARTMAP_SUN_PC_MAX_PARTS 16 +#define GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID 0x05 + +struct grub_sun_pc_partition_descriptor +{ + grub_uint16_t id; + grub_uint16_t unused; + grub_uint32_t start_sector; + grub_uint32_t num_sectors; +} __attribute__ ((packed)); + +struct grub_sun_pc_block +{ + grub_uint8_t unused[72]; + struct grub_sun_pc_partition_descriptor partitions[GRUB_PARTMAP_SUN_PC_MAX_PARTS]; + grub_uint8_t unused2[244]; + grub_uint16_t magic; /* Magic number. */ + grub_uint16_t csum; /* Label xor'd checksum. */ +} __attribute__ ((packed)); + +static struct grub_partition_map grub_sun_pc_partition_map; + +/* Verify checksum (true=ok). */ +static int +grub_sun_is_valid (struct grub_sun_pc_block *label) +{ + grub_uint16_t *pos; + grub_uint16_t sum = 0; + + for (pos = (grub_uint16_t *) label; + pos < (grub_uint16_t *) (label + 1); + pos++) + sum ^= *pos; + + return ! sum; +} + +static grub_err_t +sun_pc_partition_map_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) +{ + grub_partition_t p; + struct grub_sun_pc_block block; + int partnum; + grub_err_t err; + + p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition)); + if (! p) + return grub_errno; + + p->partmap = &grub_sun_pc_partition_map; + err = grub_disk_read (disk, 1, 0, sizeof (struct grub_sun_pc_block), &block); + if (err) + { + grub_free (p); + return err; + } + + if (GRUB_PARTMAP_SUN_PC_MAGIC != grub_le_to_cpu16 (block.magic)) + { + grub_free (p); + return grub_error (GRUB_ERR_BAD_PART_TABLE, + "not a sun_pc partition table"); + } + + if (! grub_sun_is_valid (&block)) + { + grub_free (p); + return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum"); + } + + /* Maybe another error value would be better, because partition + table _is_ recognized but invalid. */ + for (partnum = 0; partnum < GRUB_PARTMAP_SUN_PC_MAX_PARTS; partnum++) + { + struct grub_sun_pc_partition_descriptor *desc; + + if (block.partitions[partnum].id == 0 + || block.partitions[partnum].id == GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID) + continue; + + desc = &block.partitions[partnum]; + p->start = grub_le_to_cpu32 (desc->start_sector); + p->len = grub_le_to_cpu32 (desc->num_sectors); + p->number = partnum; + if (p->len) + { + if (hook (disk, p)) + partnum = GRUB_PARTMAP_SUN_PC_MAX_PARTS; + } + } + + grub_free (p); + + return grub_errno; +} + +/* Partition map type. */ +static struct grub_partition_map grub_sun_pc_partition_map = + { + .name = "sunpc", + .iterate = sun_pc_partition_map_iterate, + }; + +GRUB_MOD_INIT(part_sunpc) +{ + grub_partition_map_register (&grub_sun_pc_partition_map); +} + +GRUB_MOD_FINI(part_sunpc) +{ + grub_partition_map_unregister (&grub_sun_pc_partition_map); +} + diff --git a/parttool/msdospart.c b/parttool/msdospart.c index dbb25bc52..006a87def 100644 --- a/parttool/msdospart.c +++ b/parttool/msdospart.c @@ -49,7 +49,7 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev, index = dev->disk->partition->index; part = dev->disk->partition; - dev->disk->partition = 0; + dev->disk->partition = part->parent; /* Read the MBR. */ if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr)) @@ -96,7 +96,7 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev, index = dev->disk->partition->index; part = dev->disk->partition; - dev->disk->partition = 0; + dev->disk->partition = part->parent; /* Read the parttable. */ if (grub_disk_read (dev->disk, part->offset, 0, @@ -138,17 +138,17 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev, return GRUB_ERR_NONE; } -GRUB_MOD_INIT (pcpart) +GRUB_MOD_INIT (msdospart) { - activate_table_handle = grub_parttool_register ("part_msdos", + activate_table_handle = grub_parttool_register ("msdos", grub_pcpart_boot, grub_pcpart_bootargs); - type_table_handle = grub_parttool_register ("part_msdos", + type_table_handle = grub_parttool_register ("msdos", grub_pcpart_type, grub_pcpart_typeargs); } -GRUB_MOD_FINI(pcpart) +GRUB_MOD_FINI(msdospart) { grub_parttool_unregister (activate_table_handle); grub_parttool_unregister (type_table_handle); diff --git a/po/POTFILES b/po/POTFILES index 7d213c357..d2c579edb 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -1,15 +1,81 @@ # List of files which contain translatable strings. -util/i386/pc/grub-mkimage.c -util/i386/pc/grub-setup.c +commands/acpi.c +commands/blocklist.c +commands/boot.c +commands/cat.c +commands/cmp.c +commands/configfile.c +commands/crc.c +commands/date.c +commands/echo.c +commands/efi/fixvideo.c +commands/efi/loadbios.c +commands/gptsync.c +commands/halt.c +commands/handler.c +commands/hdparm.c +commands/help.c +commands/hexdump.c +commands/i386/cpuid.c +commands/i386/pc/drivemap.c +commands/i386/pc/halt.c +commands/i386/pc/play.c +commands/i386/pc/pxecmd.c +commands/i386/pc/vbeinfo.c +commands/i386/pc/vbetest.c +commands/ieee1275/suspend.c +commands/keystatus.c +commands/loadenv.c +commands/ls.c +commands/lsmmap.c +commands/lspci.c +commands/memrw.c +commands/minicmd.c +commands/parttool.c +commands/password.c +commands/probe.c +commands/read.c +commands/reboot.c +commands/search.c +commands/search_file.c +commands/search_label.c +commands/search_uuid.c +commands/sleep.c +commands/test.c +commands/true.c +commands/usbtest.c +commands/videotest.c +commands/xnu_uuid.c -util/mkisofs/eltorito.c -util/mkisofs/joliet.c -util/mkisofs/mkisofs.c -util/mkisofs/mkisofs.h -util/mkisofs/multi.c -util/mkisofs/rock.c -util/mkisofs/tree.c -util/mkisofs/write.c +disk/loopback.c +hello/hello.c + +lib/arg.c + +loader/efi/appleloader.c +loader/efi/chainloader.c +loader/i386/bsd.c +loader/i386/efi/linux.c +loader/i386/ieee1275/linux.c +loader/i386/linux.c +loader/i386/pc/chainloader.c +loader/i386/pc/linux.c +loader/i386/xnu.c +loader/multiboot.c +loader/powerpc/ieee1275/linux.c +loader/sparc64/ieee1275/linux.c +loader/xnu.c + +normal/auth.c +normal/color.c +normal/dyncmd.c +normal/main.c normal/menu_entry.c normal/menu_text.c +normal/misc.c + +term/serial.c + +util/grub-mkimage.c +util/i386/pc/grub-setup.c diff --git a/po/POTFILES-shell b/po/POTFILES-shell index cb28d331b..90d2b978c 100644 --- a/po/POTFILES-shell +++ b/po/POTFILES-shell @@ -2,3 +2,4 @@ # Shell language are included here. util/grub.d/10_kfreebsd.in util/grub.d/10_linux.in +util/grub.d/10_netbsd.in diff --git a/script/execute.c b/script/execute.c index e9064ad2f..40f161267 100644 --- a/script/execute.c +++ b/script/execute.c @@ -1,7 +1,7 @@ /* execute.c -- Execute a GRUB script. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2005,2007,2008,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 @@ -26,58 +26,169 @@ #include #include +/* 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. */ +#define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1) + static grub_err_t grub_script_execute_cmd (struct grub_script_cmd *cmd) { + int ret; + char errnobuf[ERRNO_DIGITS_MAX + 1]; + if (cmd == 0) return 0; - return cmd->exec (cmd); + ret = cmd->exec (cmd); + + grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret); + grub_env_set ("?", errnobuf); + return ret; } -/* Parse ARG and return the textual representation. Add strings are - concatenated and all values of the variables are filled in. */ -char * -grub_script_execute_argument_to_string (struct grub_script_arg *arg) +#define ARG_ALLOCATION_UNIT (32 * sizeof (char)) +#define ARGV_ALLOCATION_UNIT (8 * sizeof (void*)) + +/* Expand arguments in ARGLIST into multiple arguments. */ +char ** +grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *count) { - int size = 0; - char *val; - char *chararg; - struct grub_script_arg *argi; + int i; + int oom; + int argc; + int empty; + char *ptr; + char **argv; + char *value; + struct grub_script_arg *arg; - /* First determine the size of the argument. */ - for (argi = arg; argi; argi = argi->next) + auto void push (char *str); + void push (char *str) + { + char **p; + + if (oom) + return; + + p = grub_realloc (argv, ALIGN_UP (sizeof(char*) * (argc + 1), ARGV_ALLOCATION_UNIT)); + if (!p) + oom = 1; + else + { + p[argc++] = str; + argv = p; + } + } + + auto char* append (const char *str, grub_size_t nchar); + char* append (const char *str, grub_size_t nchar) + { + int len; + int old; + char *p; + + if (oom || !str) + return 0; + + len = nchar ?: grub_strlen (str); + old = argv[argc - 1] ? grub_strlen (argv[argc - 1]) : 0; + p = grub_realloc (argv[argc - 1], ALIGN_UP(old + len + 1, ARG_ALLOCATION_UNIT)); + + if (p) + { + grub_strncpy (p + old, str, len); + p[old + len] = '\0'; + } + else + { + oom = 1; + grub_free (argv[argc - 1]); + } + argv[argc - 1] = p; + return argv[argc - 1]; + } + + /* Move *STR to the begining of next word, but return current word. */ + auto char* move_to_next (char **str); + char* move_to_next (char **str) + { + char *end; + char *start; + + if (oom || !str || !*str) + return 0; + + start = *str; + while (*start && grub_isspace (*start)) start++; + if (*start == '\0') + return 0; + + end = start + 1; + while (*end && !grub_isspace (*end)) end++; + + *str = end; + return start; + } + + oom = 0; + argv = 0; + argc = 0; + push (0); + for (; arglist; arglist = arglist->next) { - if (argi->type == 1) + empty = 1; + arg = arglist->arg; + while (arg) { - val = grub_env_get (argi->str); - if (val) - size += grub_strlen (val); + switch (arg->type) + { + case GRUB_SCRIPT_ARG_TYPE_VAR: + value = grub_env_get (arg->str); + while (value && *value && (ptr = move_to_next(&value))) + { + empty = 0; + append (ptr, value - ptr); + if (*value) push(0); + } + break; + + case GRUB_SCRIPT_ARG_TYPE_TEXT: + if (grub_strlen (arg->str) > 0) + { + empty = 0; + append (arg->str, 0); + } + break; + + case GRUB_SCRIPT_ARG_TYPE_DQSTR: + case GRUB_SCRIPT_ARG_TYPE_SQSTR: + empty = 0; + append (arg->str, 0); + break; + + case GRUB_SCRIPT_ARG_TYPE_DQVAR: + empty = 0; + append (grub_env_get (arg->str), 0); + break; + } + arg = arg->next; } - else - size += grub_strlen (argi->str); + if (!empty) + push (0); } - /* Create the argument. */ - chararg = grub_malloc (size + 1); - if (! chararg) - return 0; - - *chararg = '\0'; - /* First determine the size of the argument. */ - for (argi = arg; argi; argi = argi->next) + if (oom) { - if (argi->type == 1) - { - val = grub_env_get (argi->str); - if (val) - grub_strcat (chararg, val); - } - else - grub_strcat (chararg, argi->str); + for (i = 0; i < argc; i++) + grub_free (argv[i]); + grub_free (argv); + argv = 0; } - return chararg; + if (argv) + *count = argc - 1; + + return argv; } /* Execute a single command line. */ @@ -85,22 +196,24 @@ grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd) { struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd; - struct grub_script_arglist *arglist; char **args = 0; int i = 0; grub_command_t grubcmd; grub_err_t ret = 0; int argcount = 0; grub_script_function_t func = 0; - char errnobuf[6]; + char errnobuf[18]; char *cmdname; /* Lookup the command. */ - cmdname = grub_script_execute_argument_to_string (cmdline->arglist->arg); + args = grub_script_execute_arglist_to_argv (cmdline->arglist, &argcount); + if (!args) + return grub_errno; + + cmdname = args[0]; grubcmd = grub_command_find (cmdname); if (! grubcmd) { - /* Ignore errors. */ grub_errno = GRUB_ERR_NONE; /* It's not a GRUB command, try all functions. */ @@ -113,50 +226,42 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) if (eq) { + /* This was set because the command was not found. */ + grub_errno = GRUB_ERR_NONE; + /* Create two strings and set the variable. */ *eq = '\0'; eq++; grub_env_set (assign, eq); - - /* This was set because the command was not found. */ - grub_errno = GRUB_ERR_NONE; } grub_free (assign); - grub_sprintf (errnobuf, "%d", grub_errno); + grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno); grub_env_set ("?", errnobuf); + grub_print_error (); + return 0; } } - grub_free (cmdname); - - if (cmdline->arglist->next) - { - argcount = cmdline->arglist->argcount - 1; - - /* Create argv from the arguments. */ - args = grub_malloc (sizeof (char *) * argcount); - for (arglist = cmdline->arglist->next; arglist; arglist = arglist->next) - { - char *str; - str = grub_script_execute_argument_to_string (arglist->arg); - args[i++] = str; - } - } /* Execute the GRUB command or function. */ if (grubcmd) - ret = (grubcmd->func) (grubcmd, argcount, args); + ret = (grubcmd->func) (grubcmd, argcount - 1, args + 1); else - ret = grub_script_function_call (func, argcount, args); + ret = grub_script_function_call (func, argcount - 1, args + 1); /* Free arguments. */ for (i = 0; i < argcount; i++) grub_free (args[i]); grub_free (args); - grub_sprintf (errnobuf, "%d", ret); + if (grub_errno == GRUB_ERR_TEST_FAILURE) + grub_errno = GRUB_ERR_NONE; + + grub_print_error (); + + grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret); grub_env_set ("?", errnobuf); return ret; @@ -166,13 +271,14 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) grub_err_t grub_script_execute_cmdblock (struct grub_script_cmd *cmd) { + int ret = 0; struct grub_script_cmdblock *cmdblock = (struct grub_script_cmdblock *) cmd; /* Loop over every command and execute it. */ for (cmd = cmdblock->cmdlist; cmd; cmd = cmd->next) - grub_script_execute_cmd (cmd); + ret = grub_script_execute_cmd (cmd); - return 0; + return ret; } /* Execute an if statement. */ @@ -197,12 +303,57 @@ grub_script_execute_cmdif (struct grub_script_cmd *cmd) return grub_script_execute_cmd (cmdif->exec_on_false); } +/* Execute a for statement. */ +grub_err_t +grub_script_execute_cmdfor (struct grub_script_cmd *cmd) +{ + int i; + int result; + char **args; + int argcount; + struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd; + + args = grub_script_execute_arglist_to_argv (cmdfor->words, &argcount); + if (!args) + return grub_errno; + + result = 0; + for (i = 0; i < argcount; i++) + { + grub_env_set (cmdfor->name->str, args[i]); + result = grub_script_execute_cmd (cmdfor->list); + grub_free (args[i]); + } + + grub_free (args); + return result; +} + +/* Execute a "while" or "until" command. */ +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; + + result = 0; + do { + cond = grub_script_execute_cmd (cmdwhile->cond); + if (cmdwhile->until ? !cond : cond) + break; + + result = grub_script_execute_cmd (cmdwhile->list); + } while (1); /* XXX Put a check for ^C here */ + + 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_arglist *arglist; char **args = 0; int argcount = 0; int i = 0; @@ -211,22 +362,9 @@ grub_script_execute_menuentry (struct grub_script_cmd *cmd) if (cmd_menuentry->arglist) { - argcount = cmd_menuentry->arglist->argcount; - - /* Create argv from the arguments. */ - args = grub_malloc (sizeof (char *) * argcount); - - if (! args) - { - return grub_errno; - } - - for (arglist = cmd_menuentry->arglist; arglist; arglist = arglist->next) - { - char *str; - str = grub_script_execute_argument_to_string (arglist->arg); - args[i++] = str; - } + args = grub_script_execute_arglist_to_argv (cmd_menuentry->arglist, &argcount); + if (!args) + return grub_errno; } grub_normal_add_menu_entry (argcount, (const char **) args, diff --git a/script/function.c b/script/function.c index a3950a8a0..ded470c4e 100644 --- a/script/function.c +++ b/script/function.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007,2009 Free Software Foundation, Inc. + * Copyright (C) 2005,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 @@ -34,7 +34,7 @@ grub_script_function_create (struct grub_script_arg *functionname_arg, if (! func) return 0; - func->name = grub_script_execute_argument_to_string (functionname_arg); + func->name = grub_strdup (functionname_arg->str); if (! func->name) { grub_free (func); diff --git a/script/lexer.c b/script/lexer.c index a30e3c005..42a570348 100644 --- a/script/lexer.c +++ b/script/lexer.c @@ -1,7 +1,7 @@ /* lexer.c - The scripting lexer. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2005,2006,2007,2008,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 @@ -23,42 +23,7 @@ #include #include "grub_script.tab.h" - -static int -check_varstate (grub_parser_state_t state) -{ - return (state == GRUB_PARSER_STATE_VARNAME - || state == GRUB_PARSER_STATE_VAR - || state == GRUB_PARSER_STATE_QVAR - || state == GRUB_PARSER_STATE_VARNAME2 - || state == GRUB_PARSER_STATE_QVARNAME - || state == GRUB_PARSER_STATE_QVARNAME2); -} - -static int -check_textstate (grub_parser_state_t state) -{ - return (state == GRUB_PARSER_STATE_TEXT - || state == GRUB_PARSER_STATE_ESC - || state == GRUB_PARSER_STATE_QUOTE - || state == GRUB_PARSER_STATE_DQUOTE); -} - -struct grub_lexer_param * -grub_script_lexer_init (char *script, grub_reader_getline_t getline) -{ - struct grub_lexer_param *param; - - param = grub_zalloc (sizeof (*param)); - if (! param) - return 0; - - param->state = GRUB_PARSER_STATE_TEXT; - param->getline = getline; - param->script = script; - - return param; -} +#include "grub_script.yy.h" void grub_script_lexer_ref (struct grub_lexer_param *state) @@ -74,360 +39,308 @@ grub_script_lexer_deref (struct grub_lexer_param *state) /* Start recording all characters passing through the lexer. */ void -grub_script_lexer_record_start (struct grub_lexer_param *state) +grub_script_lexer_record_start (struct grub_parser_param *parser) { - state->record = 1; - state->recordlen = 100; - state->recording = grub_malloc (state->recordlen); - state->recordpos = 0; + struct grub_lexer_param *lexer = parser->lexerstate; + + lexer->record = 1; + lexer->recordpos = 0; + if (lexer->recording) /* reuse last record */ + return; + + 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; + } } char * -grub_script_lexer_record_stop (struct grub_lexer_param *state) +grub_script_lexer_record_stop (struct grub_parser_param *parser) { - state->record = 0; + char *ptr; + char *result; + struct grub_lexer_param *lexer = parser->lexerstate; - /* Delete the last character, it is a `}'. */ - if (state->recordpos > 0) - { - if (state->recording[--state->recordpos] != '}') - { - grub_printf ("Internal error while parsing menu entry"); - for (;;); /* XXX */ - } - state->recording[state->recordpos] = '\0'; - } + 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++; - return state->recording; + 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) + return 0; + + /* XXX This is not necessary in BASH. */ + + ptr = compact (lexer->recording, lexer->recording + lexer->recordpos - 1); + lexer->record = 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; } -/* When recording is enabled, record the character C as the next item - in the character stream. */ -static void -recordchar (struct grub_lexer_param *state, char c) +#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) { - if (state->recordpos == state->recordlen) + int len; + char *old; + struct grub_lexer_param *lexer = parser->lexerstate; + + if (!lexer->record) + return; + + len = grub_strlen (str); + if (lexer->recordpos + len + 1 > lexer->recordlen) { - char *old = state->recording; - state->recordlen += 100; - state->recording = grub_realloc (state->recording, state->recordlen); - if (! state->recording) + old = lexer->recording; + lexer->recordlen = MAX (len, lexer->recordlen) * 2; + lexer->recording = grub_realloc (lexer->recording, lexer->recordlen); + if (!lexer->recording) { grub_free (old); - state->record = 0; + lexer->record = 0; + lexer->recordpos = 0; + lexer->recordlen /= 2; + grub_script_yyerror (parser, 0); + return; } } - state->recording[state->recordpos++] = c; + grub_strcpy (lexer->recording + lexer->recordpos, str); + lexer->recordpos += len; } -/* Fetch the next character for the lexer. */ -static void -nextchar (struct grub_lexer_param *state) +/* Append '\n' to SRC, before '\0' */ +static char * +append_newline (const char *src) { - if (state->record) - recordchar (state, *state->script); - state->script++; + 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_yylex (union YYSTYPE *yylval, struct grub_parser_param *parsestate) +grub_script_lexer_yywrap (struct grub_parser_param *parserstate) { - grub_parser_state_t newstate; - char use; - struct grub_lexer_param *state = parsestate->lexerstate; - int firstrun = 1; + int len; + char *line; + char *line2; + YY_BUFFER_STATE buffer; + struct grub_lexer_param *lexerstate = parserstate->lexerstate; - yylval->arg = 0; + if (!lexerstate->refs) + return 0; - if (state->tokenonhold) + if (!lexerstate->getline) { - int token = state->tokenonhold; - state->tokenonhold = 0; - return token; + grub_script_yyerror (parserstate, "unexpected end of file"); + return 0; } - for (;! state->done; firstrun = 0) + line = 0; + buffer = 0; + lexerstate->getline (&line, 1); + if (!line) { - if (! state->script || ! *state->script) + 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 + { + line2 = append_newline (line); + if (line2) { - /* Check if more tokens are requested by the parser. */ - if (((state->refs && ! parsestate->err) - || state->state == GRUB_PARSER_STATE_ESC - || state->state == GRUB_PARSER_STATE_QUOTE - || state->state == GRUB_PARSER_STATE_DQUOTE) - && state->getline) - { - int doexit = 0; - if (state->state != GRUB_PARSER_STATE_ESC - && state->state != GRUB_PARSER_STATE_QUOTE - && state->state != GRUB_PARSER_STATE_DQUOTE - && ! state->was_newline) - { - state->was_newline = 1; - state->tokenonhold = '\n'; - break; - } - while (! state->script || ! *state->script) - { - grub_free (state->newscript); - state->newscript = 0; - state->getline (&state->newscript, 1); - state->script = state->newscript; - if (! state->script) - { - doexit = 1; - break; - } - } - if (doexit) - break; - grub_dprintf ("scripting", "token=`\\n'\n"); - recordchar (state, '\n'); - if (state->state == GRUB_PARSER_STATE_VARNAME) - state->state = GRUB_PARSER_STATE_TEXT; - if (state->state == GRUB_PARSER_STATE_QVARNAME) - state->state = GRUB_PARSER_STATE_DQUOTE; - if (state->state == GRUB_PARSER_STATE_DQUOTE - || state->state == GRUB_PARSER_STATE_QUOTE) - yylval->arg = grub_script_arg_add (parsestate, yylval->arg, - GRUB_SCRIPT_ARG_TYPE_STR, - "\n"); - } - else - { - grub_free (state->newscript); - state->newscript = 0; - state->done = 1; - grub_dprintf ("scripting", "token=`\\n'\n"); - state->tokenonhold = '\n'; - break; - } - } - state->was_newline = 0; - - newstate = grub_parser_cmdline_state (state->state, *state->script, &use); - - /* Check if it is a text. */ - if (check_textstate (newstate)) - { - char *buffer = NULL; - int bufpos = 0; - /* Buffer is initially large enough to hold most commands - but extends automatically when needed. */ - int bufsize = 128; - - buffer = grub_malloc (bufsize); - - /* In case the string is not quoted, this can be a one char - length symbol. */ - if (newstate == GRUB_PARSER_STATE_TEXT) - { - int doexit = 0; - switch (*state->script) - { - case ' ': - while (*state->script) - { - newstate = grub_parser_cmdline_state (state->state, - *state->script, &use); - if (! (state->state == GRUB_PARSER_STATE_TEXT - && *state->script == ' ')) - { - grub_dprintf ("scripting", "token=` '\n"); - if (! firstrun) - doexit = 1; - break; - } - state->state = newstate; - nextchar (state); - } - grub_dprintf ("scripting", "token=` '\n"); - if (! firstrun) - doexit = 1; - break; - case '{': - case '}': - case ';': - case '\n': - { - char c; - grub_dprintf ("scripting", "token=`%c'\n", *state->script); - c = *state->script; - nextchar (state); - state->tokenonhold = c; - doexit = 1; - break; - } - } - if (doexit) - { - grub_free (buffer); - break; - } - } - - /* Read one token, possible quoted. */ - while (*state->script) - { - newstate = grub_parser_cmdline_state (state->state, - *state->script, &use); - - /* Check if a variable name starts. */ - if (check_varstate (newstate)) - break; - - /* If the string is not quoted or escaped, stop processing - when a special token was found. It will be recognized - next time when this function is called. */ - if (newstate == GRUB_PARSER_STATE_TEXT - && state->state != GRUB_PARSER_STATE_ESC - && state->state != GRUB_PARSER_STATE_QUOTE - && state->state != GRUB_PARSER_STATE_DQUOTE) - { - int breakout = 0; - - switch (use) - { - case ' ': - case '{': - case '}': - case ';': - case '\n': - breakout = 1; - } - if (breakout) - break; - } - - if (use) - { - if (bufsize <= bufpos + 1) - { - bufsize <<= 1; - buffer = grub_realloc (buffer, bufsize); - } - buffer[bufpos++] = use; - } - - state->state = newstate; - nextchar (state); - } - - /* A string of text was read in. */ - if (bufsize <= bufpos + 1) - { - bufsize <<= 1; - buffer = grub_realloc (buffer, bufsize); - } - - buffer[bufpos++] = 0; - - grub_dprintf ("scripting", "token=`%s'\n", buffer); - yylval->arg = grub_script_arg_add (parsestate, yylval->arg, - GRUB_SCRIPT_ARG_TYPE_STR, buffer); - - grub_free (buffer); - } - else if (newstate == GRUB_PARSER_STATE_VAR - || newstate == GRUB_PARSER_STATE_QVAR) - { - char *buffer = NULL; - int bufpos = 0; - /* Buffer is initially large enough to hold most commands - but extends automatically when needed. */ - int bufsize = 128; - - buffer = grub_malloc (bufsize); - - /* This is a variable, read the variable name. */ - while (*state->script) - { - newstate = grub_parser_cmdline_state (state->state, - *state->script, &use); - - /* Check if this character is not part of the variable name - anymore. */ - if (! (check_varstate (newstate))) - { - if (state->state == GRUB_PARSER_STATE_VARNAME2 - || state->state == GRUB_PARSER_STATE_QVARNAME2) - nextchar (state); - state->state = newstate; - break; - } - - if (use) - { - if (bufsize <= bufpos + 1) - { - bufsize <<= 1; - buffer = grub_realloc (buffer, bufsize); - } - buffer[bufpos++] = use; - } - - nextchar (state); - state->state = newstate; - } - - if (bufsize <= bufpos + 1) - { - bufsize <<= 1; - buffer = grub_realloc (buffer, bufsize); - } - - buffer[bufpos++] = 0; - - state->state = newstate; - yylval->arg = grub_script_arg_add (parsestate, yylval->arg, - GRUB_SCRIPT_ARG_TYPE_VAR, buffer); - grub_dprintf ("scripting", "vartoken=`%s'\n", buffer); - - grub_free (buffer); - } - else - { - /* There is either text or a variable name. In the case you - arrive here there is a serious problem with the lexer. */ - grub_error (GRUB_ERR_BAD_ARGUMENT, "Internal error\n"); - return 0; + buffer = yy_scan_string (line2, lexerstate->yyscanner); + grub_free (line2); } } - if (yylval->arg == 0) + grub_free (line); + if (!buffer) { - int token = state->tokenonhold; - state->tokenonhold = 0; - return token; + grub_script_yyerror (parserstate, 0); + return 0; } - if (yylval->arg->next == 0 && yylval->arg->type == GRUB_SCRIPT_ARG_TYPE_STR) + return 1; +} + +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)); + if (!lexerstate) + return 0; + + lexerstate->size = GRUB_LEXER_INITIAL_TEXT_SIZE; + lexerstate->text = grub_malloc (lexerstate->size); + if (!lexerstate->text) { - /* Detect some special tokens. */ - if (! grub_strcmp (yylval->arg->str, "while")) - return GRUB_PARSER_TOKEN_WHILE; - else if (! grub_strcmp (yylval->arg->str, "if")) - return GRUB_PARSER_TOKEN_IF; - else if (! grub_strcmp (yylval->arg->str, "function")) - return GRUB_PARSER_TOKEN_FUNCTION; - else if (! grub_strcmp (yylval->arg->str, "menuentry")) - return GRUB_PARSER_TOKEN_MENUENTRY; - else if (! grub_strcmp (yylval->arg->str, "@")) - return GRUB_PARSER_TOKEN_MENUENTRY; - else if (! grub_strcmp (yylval->arg->str, "else")) - return GRUB_PARSER_TOKEN_ELSE; - else if (! grub_strcmp (yylval->arg->str, "then")) - return GRUB_PARSER_TOKEN_THEN; - else if (! grub_strcmp (yylval->arg->str, "fi")) - return GRUB_PARSER_TOKEN_FI; + grub_free (lexerstate); + return 0; } - return GRUB_PARSER_TOKEN_ARG; + lexerstate->getline = getline; /* rest are all zeros already */ + if (yylex_init (&lexerstate->yyscanner)) + { + grub_free (lexerstate->text); + grub_free (lexerstate); + return 0; + } + + buffer = 0; + script = script ? : "\n"; + len = grub_strlen (script); + + if (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) + { + yylex_destroy (lexerstate->yyscanner); + grub_free (lexerstate->yyscanner); + + grub_free (lexerstate->text); + grub_free (lexerstate); + return 0; + } + yyset_extra (parser, lexerstate->yyscanner); + + return lexerstate; } void -grub_script_yyerror (struct grub_parser_param *lex __attribute__ ((unused)), - char const *err) +grub_script_lexer_fini (struct grub_lexer_param *lexerstate) { - grub_printf ("%s\n", err); + if (!lexerstate) + return; + + yylex_destroy (lexerstate->yyscanner); + + grub_free (lexerstate->recording); + grub_free (lexerstate->text); + grub_free (lexerstate); +} + +int +grub_script_yylex (union YYSTYPE *value, + struct grub_parser_param *parserstate) +{ + char *str; + int token; + grub_script_arg_type_t type; + struct grub_lexer_param *lexerstate = parserstate->lexerstate; + + value->arg = 0; + if (parserstate->err) + return GRUB_PARSER_TOKEN_BAD; + + if (lexerstate->eof) + return GRUB_PARSER_TOKEN_EOF; + + /* + * Words with environment variables, like foo${bar}baz needs + * multiple tokens to be merged into a single grub_script_arg. We + * use two variables to achieve this: lexerstate->merge_start and + * lexerstate->merge_end + */ + + lexerstate->merge_start = 0; + lexerstate->merge_end = 0; + do + { + /* Empty lexerstate->text. */ + lexerstate->used = 1; + lexerstate->text[0] = '\0'; + + token = yylex (value, lexerstate->yyscanner); + if (token == GRUB_PARSER_TOKEN_BAD) + break; + + /* Merging feature uses lexerstate->text instead of yytext. */ + if (lexerstate->merge_start) + { + str = lexerstate->text; + type = lexerstate->type; + } + else + { + str = yyget_text (lexerstate->yyscanner); + type = GRUB_SCRIPT_ARG_TYPE_TEXT; + } + grub_dprintf("lexer", "token %u text [%s]\n", token, str); + + value->arg = grub_script_arg_add (parserstate, value->arg, type, str); + } + while (lexerstate->merge_start && !lexerstate->merge_end); + + if (!value->arg || parserstate->err) + return GRUB_PARSER_TOKEN_BAD; + + return token; +} + +void +grub_script_yyerror (struct grub_parser_param *state, char const *err) +{ + if (err) + grub_error (GRUB_ERR_INVALID_COMMAND, err); + + grub_print_error (); + state->err++; } diff --git a/script/parser.y b/script/parser.y index 094a8856e..b5815ea8d 100644 --- a/script/parser.y +++ b/script/parser.y @@ -1,7 +1,7 @@ /* parser.y - The scripting parser. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2005,2006,2007,2008,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 @@ -21,10 +21,10 @@ #include #include -#define YYFREE grub_free -#define YYMALLOC grub_malloc +#define YYFREE grub_free +#define YYMALLOC grub_malloc #define YYLTYPE_IS_TRIVIAL 0 -#define YYENABLE_NLS 0 +#define YYENABLE_NLS 0 %} @@ -35,163 +35,252 @@ char *string; } -%token GRUB_PARSER_TOKEN_IF "if" -%token GRUB_PARSER_TOKEN_WHILE "while" -%token GRUB_PARSER_TOKEN_FUNCTION "function" -%token GRUB_PARSER_TOKEN_MENUENTRY "menuentry" -%token GRUB_PARSER_TOKEN_ELSE "else" -%token GRUB_PARSER_TOKEN_THEN "then" -%token GRUB_PARSER_TOKEN_FI "fi" -%token GRUB_PARSER_TOKEN_ARG -%type script_init script grubcmd command commands commandblock menuentry if -%type arguments; -%type GRUB_PARSER_TOKEN_ARG; +%token GRUB_PARSER_TOKEN_BAD +%token GRUB_PARSER_TOKEN_EOF 0 "end-of-input" + +%token GRUB_PARSER_TOKEN_NEWLINE "\n" +%token GRUB_PARSER_TOKEN_AND "&&" +%token GRUB_PARSER_TOKEN_OR "||" +%token GRUB_PARSER_TOKEN_SEMI2 ";;" +%token GRUB_PARSER_TOKEN_PIPE "|" +%token GRUB_PARSER_TOKEN_AMP "&" +%token GRUB_PARSER_TOKEN_SEMI ";" +%token GRUB_PARSER_TOKEN_LBR "{" +%token GRUB_PARSER_TOKEN_RBR "}" +%token GRUB_PARSER_TOKEN_NOT "!" +%token GRUB_PARSER_TOKEN_LSQBR2 "[" +%token GRUB_PARSER_TOKEN_RSQBR2 "]" +%token GRUB_PARSER_TOKEN_LT "<" +%token GRUB_PARSER_TOKEN_GT ">" + +%token GRUB_PARSER_TOKEN_CASE "case" +%token GRUB_PARSER_TOKEN_DO "do" +%token GRUB_PARSER_TOKEN_DONE "done" +%token GRUB_PARSER_TOKEN_ELIF "elif" +%token GRUB_PARSER_TOKEN_ELSE "else" +%token GRUB_PARSER_TOKEN_ESAC "esac" +%token GRUB_PARSER_TOKEN_FI "fi" +%token GRUB_PARSER_TOKEN_FOR "for" +%token GRUB_PARSER_TOKEN_IF "if" +%token GRUB_PARSER_TOKEN_IN "in" +%token GRUB_PARSER_TOKEN_SELECT "select" +%token GRUB_PARSER_TOKEN_THEN "then" +%token GRUB_PARSER_TOKEN_UNTIL "until" +%token GRUB_PARSER_TOKEN_WHILE "while" +%token GRUB_PARSER_TOKEN_TIME "time" +%token GRUB_PARSER_TOKEN_FUNCTION "function" +%token GRUB_PARSER_TOKEN_MENUENTRY "menuentry" +%token GRUB_PARSER_TOKEN_NAME "name" +%token GRUB_PARSER_TOKEN_WORD "word" + +%type word argument arguments0 arguments1 + +%type script_init script +%type grubcmd ifclause ifcmd forcmd whilecmd untilcmd +%type command commands1 menuentry statement %pure-parser -%lex-param { struct grub_parser_param *state }; +%lex-param { struct grub_parser_param *state }; %parse-param { struct grub_parser_param *state }; +%start script_init + %% /* It should be possible to do this in a clean way... */ -script_init: { state->err = 0; } script - { - state->parsed = $2; - } +script_init: { state->err = 0; } script { state->parsed = $2; state->err = 0; } ; -script: { $$ = 0; } - | '\n' { $$ = 0; } - | commands { $$ = $1; } - | function '\n' { $$ = 0; } - | menuentry '\n' { $$ = $1; } - | error - { - $$ = 0; - yyerror (state, "Incorrect command"); - state->err = 1; - yyerrok; - } +script: newlines0 + { + $$ = 0; + } + | script statement delimiter newlines0 + { + struct grub_script_cmdblock *cmdblock; + cmdblock = (struct grub_script_cmdblock *) $1; + $$ = grub_script_add_cmd (state, cmdblock, $2); + } + | error + { + $$ = 0; + yyerror (state, "Incorrect command"); + yyerrok; + } ; -delimiter: '\n' - | ';' - | delimiter '\n' +newlines0: /* Empty */ | newlines1 ; +newlines1: newlines0 "\n" ; + +delimiter: ";" + | "\n" +; +delimiters0: /* Empty */ | delimiters1 ; +delimiters1: delimiter + | delimiters1 "\n" ; -newlines: /* Empty */ - | newlines '\n' +word: GRUB_PARSER_TOKEN_NAME { $$ = grub_script_add_arglist (state, 0, $1); } + | GRUB_PARSER_TOKEN_WORD { $$ = grub_script_add_arglist (state, 0, $1); } ; +statement: command { $$ = $1; } + | function { $$ = 0; } + | menuentry { $$ = $1; } - -arguments: GRUB_PARSER_TOKEN_ARG - { - $$ = grub_script_add_arglist (state, 0, $1); - } - | arguments GRUB_PARSER_TOKEN_ARG - { - $$ = grub_script_add_arglist (state, $1, $2); - } +argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); } + | "do" { $$ = grub_script_add_arglist (state, 0, $1); } + | "done" { $$ = grub_script_add_arglist (state, 0, $1); } + | "elif" { $$ = grub_script_add_arglist (state, 0, $1); } + | "else" { $$ = grub_script_add_arglist (state, 0, $1); } + | "esac" { $$ = grub_script_add_arglist (state, 0, $1); } + | "fi" { $$ = grub_script_add_arglist (state, 0, $1); } + | "for" { $$ = grub_script_add_arglist (state, 0, $1); } + | "if" { $$ = grub_script_add_arglist (state, 0, $1); } + | "in" { $$ = grub_script_add_arglist (state, 0, $1); } + | "select" { $$ = grub_script_add_arglist (state, 0, $1); } + | "then" { $$ = 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; } ; -grubcmd: arguments - { - $$ = grub_script_create_cmdline (state, $1); - } +arguments0: /* Empty */ { $$ = 0; } + | arguments1 { $$ = $1; } +; +arguments1: argument arguments0 + { + if ($1 && $2) + { + $1->next = $2; + $1->argcount += $2->argcount; + $2->argcount = 0; + } + $$ = $1; + } +; + +grubcmd: word arguments0 + { + if ($1 && $2) { + $1->next = $2; + $1->argcount += $2->argcount; + $2->argcount = 0; + } + $$ = grub_script_create_cmdline (state, $1); + } ; /* A single command. */ -command: grubcmd delimiter { $$ = $1; } - | if delimiter { $$ = $1; } - | commandblock delimiter { $$ = $1; } +command: grubcmd { $$ = $1; } + | ifcmd { $$ = $1; } + | forcmd { $$ = $1; } + | whilecmd { $$ = $1; } + | untilcmd { $$ = $1; } ; -/* A block of commands. */ -commands: command - { - $$ = grub_script_add_cmd (state, 0, $1); - } - | command commands - { - struct grub_script_cmdblock *cmd; - cmd = (struct grub_script_cmdblock *) $2; - $$ = grub_script_add_cmd (state, cmd, $1); - } +/* A list of commands. */ +commands1: newlines0 command + { + $$ = grub_script_add_cmd (state, 0, $2); + } + | commands1 delimiters1 command + { + struct grub_script_cmdblock *cmdblock; + cmdblock = (struct grub_script_cmdblock *) $1; + $$ = grub_script_add_cmd (state, cmdblock, $3); + } ; -/* A function. Carefully save the memory that is allocated. Don't - change any stuff because it might seem like a fun thing to do! - Special care was take to make sure the mid-rule actions are - executed on the right moment. So the `commands' rule should be - recognized after executing the `grub_script_mem_record; and before - `grub_script_mem_record_stop'. */ -function: "function" GRUB_PARSER_TOKEN_ARG - { - grub_script_lexer_ref (state->lexerstate); - } newlines '{' - { - /* The first part of the function was recognized. - Now start recording the memory usage to store - this function. */ - state->func_mem = grub_script_mem_record (state); - } newlines commands '}' - { - struct grub_script *script; +function: "function" "name" + { + grub_script_lexer_ref (state->lexerstate); + state->func_mem = grub_script_mem_record (state); + } + delimiters0 "{" commands1 delimiters1 "}" + { + struct grub_script *script; + state->func_mem = grub_script_mem_record_stop (state, + state->func_mem); + script = grub_script_create ($6, state->func_mem); + if (script) + grub_script_function_create ($2, script); - /* All the memory usage for parsing this function - was recorded. */ - state->func_mem = grub_script_mem_record_stop (state, - state->func_mem); - script = grub_script_create ($8, state->func_mem); - if (script) - grub_script_function_create ($2, script); - grub_script_lexer_deref (state->lexerstate); - } + grub_script_lexer_deref (state->lexerstate); + } ; -/* Carefully designed, together with `menuentry' so everything happens - just in the expected order. */ -commandblock: '{' - { - grub_script_lexer_ref (state->lexerstate); - } - newlines commands '}' - { - grub_script_lexer_deref (state->lexerstate); - $$ = $4; - } +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); + } ; -/* A menu entry. Carefully save the memory that is allocated. */ -menuentry: "menuentry" - { - grub_script_lexer_ref (state->lexerstate); - } arguments newlines '{' - { - grub_script_lexer_record_start (state->lexerstate); - } newlines commands '}' - { - char *menu_entry; - menu_entry = grub_script_lexer_record_stop (state->lexerstate); - grub_script_lexer_deref (state->lexerstate); - $$ = grub_script_create_cmdmenu (state, $3, menu_entry, 0); - } +ifcmd: "if" + { + grub_script_lexer_ref (state->lexerstate); + } + ifclause "fi" + { + $$ = $3; + grub_script_lexer_deref (state->lexerstate); + } +; +ifclause: commands1 delimiters1 "then" commands1 delimiters1 + { + $$ = grub_script_create_cmdif (state, $1, $4, 0); + } + | commands1 delimiters1 "then" commands1 delimiters1 "else" commands1 delimiters1 + { + $$ = grub_script_create_cmdif (state, $1, $4, $7); + } + | commands1 delimiters1 "then" commands1 delimiters1 "elif" ifclause + { + $$ = grub_script_create_cmdif (state, $1, $4, $7); + } ; -/* The first part of the if statement. It's used to switch the lexer - to a state in which it demands more tokens. */ -if_statement: "if" { grub_script_lexer_ref (state->lexerstate); } +forcmd: "for" "name" + { + grub_script_lexer_ref (state->lexerstate); + } + "in" arguments0 delimiters1 "do" commands1 delimiters1 "done" + { + $$ = grub_script_create_cmdfor (state, $2, $5, $8); + grub_script_lexer_deref (state->lexerstate); + } ; -/* The if statement. */ -if: if_statement commands "then" newlines commands "fi" - { - $$ = grub_script_create_cmdif (state, $2, $5, 0); - grub_script_lexer_deref (state->lexerstate); - } - | if_statement commands "then" newlines commands "else" newlines commands "fi" - { - $$ = grub_script_create_cmdif (state, $2, $5, $8); - grub_script_lexer_deref (state->lexerstate); - } +whilecmd: "while" + { + grub_script_lexer_ref (state->lexerstate); + } + commands1 delimiters1 "do" commands1 delimiters1 "done" + { + $$ = grub_script_create_cmdwhile (state, $3, $6, 0); + grub_script_lexer_deref (state->lexerstate); + } +; + +untilcmd: "until" + { + grub_script_lexer_ref (state->lexerstate); + } + commands1 delimiters1 "do" commands1 delimiters1 "done" + { + $$ = grub_script_create_cmdwhile (state, $3, $6, 1); + grub_script_lexer_deref (state->lexerstate); + } ; diff --git a/script/script.c b/script/script.c index c04a44966..4c87d9491 100644 --- a/script/script.c +++ b/script/script.c @@ -1,7 +1,7 @@ /* script.c -- Functions to create an in memory description of the script. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2009 Free Software Foundation, Inc. + * Copyright (C) 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 @@ -24,12 +24,10 @@ /* It is not possible to deallocate the memory when a syntax error was found. Because of that it is required to keep track of all memory - allocations. The memory is freed in case of an error, or - assigned to the parsed script when parsing was successful. */ + allocations. The memory is freed in case of an error, or assigned + to the parsed script when parsing was successful. -/* XXX */ - -/* In case of the normal malloc, some additional bytes are allocated + In case of the normal malloc, some additional bytes are allocated for this datastructure. All reserved memory is stored in a linked list so it can be easily freed. The original memory can be found from &mem. */ @@ -46,6 +44,8 @@ grub_script_malloc (struct grub_parser_param *state, grub_size_t size) struct grub_script_mem *mem; mem = (struct grub_script_mem *) grub_malloc (size + sizeof (*mem) - sizeof (char)); + if (!mem) + return 0; grub_dprintf ("scripting", "malloc %p\n", mem); mem->next = state->memused; @@ -94,32 +94,40 @@ grub_script_mem_record_stop (struct grub_parser_param *state, void grub_script_free (struct grub_script *script) { - if (! script) + if (!script) return; grub_script_mem_free (script->mem); grub_free (script); } - + /* Extend the argument arg with a variable or string of text. If ARG is zero a new list is created. */ struct grub_script_arg * -grub_script_arg_add (struct grub_parser_param *state, struct grub_script_arg *arg, - grub_script_arg_type_t type, char *str) +grub_script_arg_add (struct grub_parser_param *state, + struct grub_script_arg *arg, grub_script_arg_type_t type, + char *str) { struct grub_script_arg *argpart; struct grub_script_arg *ll; int len; - argpart = (struct grub_script_arg *) grub_script_malloc (state, sizeof (*arg)); + argpart = + (struct grub_script_arg *) grub_script_malloc (state, sizeof (*arg)); + if (!argpart) + return arg; + argpart->type = type; len = grub_strlen (str) + 1; argpart->str = grub_script_malloc (state, len); + if (!argpart->str) + return arg; /* argpart is freed later, during grub_script_free. */ + grub_memcpy (argpart->str, str, len); argpart->next = 0; - if (! arg) + if (!arg) return argpart; for (ll = arg; ll->next; ll = ll->next); @@ -132,19 +140,24 @@ grub_script_arg_add (struct grub_parser_param *state, struct grub_script_arg *ar is zero, a new list will be created. */ struct grub_script_arglist * grub_script_add_arglist (struct grub_parser_param *state, - struct grub_script_arglist *list, struct grub_script_arg *arg) + struct grub_script_arglist *list, + struct grub_script_arg *arg) { struct grub_script_arglist *link; struct grub_script_arglist *ll; grub_dprintf ("scripting", "arglist\n"); - link = (struct grub_script_arglist *) grub_script_malloc (state, sizeof (*link)); + link = + (struct grub_script_arglist *) grub_script_malloc (state, sizeof (*link)); + if (!link) + return list; + link->next = 0; link->arg = arg; link->argcount = 0; - if (! list) + if (!list) { link->argcount++; return link; @@ -171,6 +184,9 @@ grub_script_create_cmdline (struct grub_parser_param *state, grub_dprintf ("scripting", "cmdline\n"); cmd = grub_script_malloc (state, sizeof (*cmd)); + if (!cmd) + return 0; + cmd->cmd.exec = grub_script_execute_cmdline; cmd->cmd.next = 0; cmd->arglist = arglist; @@ -193,6 +209,9 @@ grub_script_create_cmdif (struct grub_parser_param *state, grub_dprintf ("scripting", "cmdif\n"); cmd = grub_script_malloc (state, sizeof (*cmd)); + if (!cmd) + return 0; + cmd->cmd.exec = grub_script_execute_cmdif; cmd->cmd.next = 0; cmd->exec_to_evaluate = exec_to_evaluate; @@ -202,6 +221,52 @@ grub_script_create_cmdif (struct grub_parser_param *state, return (struct grub_script_cmd *) cmd; } +/* Create a command that functions as a for statement. */ +struct grub_script_cmd * +grub_script_create_cmdfor (struct grub_parser_param *state, + struct grub_script_arg *name, + struct grub_script_arglist *words, + struct grub_script_cmd *list) +{ + struct grub_script_cmdfor *cmd; + + grub_dprintf ("scripting", "cmdfor\n"); + + cmd = grub_script_malloc (state, sizeof (*cmd)); + if (! cmd) + return 0; + + cmd->cmd.exec = grub_script_execute_cmdfor; + cmd->cmd.next = 0; + cmd->name = name; + cmd->words = words; + cmd->list = list; + + return (struct grub_script_cmd *) cmd; +} + +/* Create a "while" or "until" command. */ +struct grub_script_cmd * +grub_script_create_cmdwhile (struct grub_parser_param *state, + struct grub_script_cmd *cond, + struct grub_script_cmd *list, + int is_an_until_loop) +{ + struct grub_script_cmdwhile *cmd; + + cmd = grub_script_malloc (state, sizeof (*cmd)); + if (! cmd) + return 0; + + cmd->cmd.exec = grub_script_execute_cmdwhile; + cmd->cmd.next = 0; + cmd->cond = cond; + cmd->list = list; + cmd->until = is_an_until_loop; + + 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. @@ -209,30 +274,16 @@ grub_script_create_cmdif (struct grub_parser_param *state, struct grub_script_cmd * grub_script_create_cmdmenu (struct grub_parser_param *state, struct grub_script_arglist *arglist, - char *sourcecode, - int options) + char *sourcecode, int options) { struct grub_script_cmd_menuentry *cmd; - int i; - - /* Skip leading newlines to make the sourcecode better readable when - using the editor. */ - while (*sourcecode == '\n') - sourcecode++; - - /* Having trailing returns can some some annoying conflicts, remove - them. XXX: Can the parser be improved to handle this? */ - for (i = grub_strlen (sourcecode) - 1; i > 0; i--) - { - if (sourcecode[i] != '\n') - break; - sourcecode[i] = '\0'; - } cmd = grub_script_malloc (state, sizeof (*cmd)); + if (!cmd) + return 0; + cmd->cmd.exec = grub_script_execute_menuentry; cmd->cmd.next = 0; - /* XXX: Check if this memory is properly freed. */ cmd->sourcecode = sourcecode; cmd->arglist = arglist; cmd->options = options; @@ -248,15 +299,19 @@ grub_script_add_cmd (struct grub_parser_param *state, struct grub_script_cmdblock *cmdblock, struct grub_script_cmd *cmd) { + struct grub_script_cmd *ptr; + grub_dprintf ("scripting", "cmdblock\n"); - if (! cmd) + if (!cmd) return (struct grub_script_cmd *) cmdblock; - if (! cmdblock) + if (!cmdblock) { - cmdblock = (struct grub_script_cmdblock *) grub_script_malloc (state, - sizeof (*cmdblock)); + cmdblock = grub_script_malloc (state, sizeof (*cmdblock)); + if (!cmdblock) + return 0; + cmdblock->cmd.exec = grub_script_execute_cmdblock; cmdblock->cmd.next = 0; cmdblock->cmdlist = cmd; @@ -264,22 +319,29 @@ grub_script_add_cmd (struct grub_parser_param *state, } else { - cmd->next = cmdblock->cmdlist; - cmdblock->cmdlist = cmd; + if (!cmdblock->cmdlist) + cmdblock->cmdlist = cmd; + else + { + ptr = cmdblock->cmdlist; + while (ptr->next) + ptr = ptr->next; + ptr->next = cmd; + } } return (struct grub_script_cmd *) cmdblock; } - + struct grub_script * grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem) { struct grub_script *parsed; parsed = grub_malloc (sizeof (*parsed)); - if (! parsed) + if (!parsed) { grub_script_mem_free (mem); grub_free (cmd); @@ -304,16 +366,16 @@ grub_script_parse (char *script, grub_reader_getline_t getline) struct grub_parser_param *parsestate; parsed = grub_malloc (sizeof (*parsed)); - if (! parsed) + if (!parsed) return 0; parsestate = grub_zalloc (sizeof (*parsestate)); - if (! parsestate) + if (!parsestate) return 0; /* Initialize the lexer. */ - lexstate = grub_script_lexer_init (script, getline); - if (! lexstate) + lexstate = grub_script_lexer_init (parsestate, script, getline); + if (!lexstate) { grub_free (parsed); grub_free (parsestate); @@ -330,7 +392,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline) struct grub_script_mem *memfree; memfree = grub_script_mem_record_stop (parsestate, membackup); grub_script_mem_free (memfree); - grub_free (lexstate); + grub_script_lexer_fini (lexstate); grub_free (parsestate); return 0; } @@ -338,7 +400,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline) parsed->mem = grub_script_mem_record_stop (parsestate, membackup); parsed->cmd = parsestate->parsed; - grub_free (lexstate); + grub_script_lexer_fini (lexstate); grub_free (parsestate); return parsed; diff --git a/script/yylex.l b/script/yylex.l new file mode 100644 index 000000000..7d4ea9e4e --- /dev/null +++ b/script/yylex.l @@ -0,0 +1,327 @@ +%{ +/* yylex.l The scripting lexer. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#include +#include +#include +#include +#include "grub_script.tab.h" + +#define yyfree grub_lexer_yyfree +#define yyalloc grub_lexer_yyalloc +#define yyrealloc grub_lexer_yyrealloc + +/* + * As we don't have access to yyscanner, we cannot do much except to + * print the fatal error. + */ +#define YY_FATAL_ERROR(msg) \ + do { \ + grub_printf ("fatal error: %s\n", msg); \ + } while (0) + +#define COPY(str, hint) \ + do { \ + copy_string (yyextra, str, hint); \ + } while (0) + + +#define RECORD \ + do { \ + grub_script_lexer_record (yyextra, yytext); \ + } while (0) + +#define ARG(t) \ + do { \ + yyextra->lexerstate->type = t; \ + return GRUB_PARSER_TOKEN_WORD; \ + } while (0) + +/* We don't need YY_INPUT, as we rely on yy_scan_strings */ +#define YY_INPUT(buf,res,max) do { res = 0; } while (0) + +/* forward declarations */ +static void grub_lexer_yyfree (void *, yyscan_t yyscanner); +static void* grub_lexer_yyalloc (yy_size_t, yyscan_t yyscanner); +static void* grub_lexer_yyrealloc (void*, yy_size_t, yyscan_t yyscanner); +static void copy_string (struct grub_parser_param *, const char *, + unsigned hint); + +%} + +%top{ + +#include + +typedef size_t yy_size_t; +#define YY_TYPEDEF_YY_SIZE_T 1 + +/* + * Some flex hacks for -nostdinc; XXX We need to fix these when libc + * support becomes availble in GRUB. + */ + +#ifndef GRUB_UTIL +#define stdin 0 +#define stdout 0 + +#define fprintf(...) 0 +#define exit(...) +#endif + +} + +%option ecs +%option meta-ecs + +%option warn +%option array +%option stack +%option reentrant +%option bison-bridge +%option never-interactive + +%option noyyfree noyyalloc noyyrealloc +%option nounistd nostdinit nodefault noyylineno noyywrap + +/* Reduce lexer size, by not defining these. */ +%option noyy_top_state +%option noinput nounput +%option noyyget_in noyyset_in +%option noyyget_out noyyset_out +%option noyyget_debug noyyset_debug +%option noyyget_lineno noyyset_lineno + +%option extra-type="struct grub_parser_param*" + +BLANK [ \t] +COMMENT #.*$ + +CHAR [^{}|&$;<> \t\n\'\"\\] +DIGITS [[:digit:]]+ +NAME [[:alpha:]_][[:alnum:][:digit:]_]* + +ESC \\. +VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|$\?|$\{\?\} +DQSTR \"([^\\\"]|{ESC})*\" +SQSTR \'[^\']*\' +WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ + +%x SPLIT +%x DQUOTE +%x SQUOTE +%x VAR + +%% + + /* White spaces */ +{BLANK}+ { RECORD; } +{COMMENT} { RECORD; } + + /* Special symbols */ +"\n" { RECORD; return GRUB_PARSER_TOKEN_NEWLINE; } +"||" { RECORD; return GRUB_PARSER_TOKEN_OR; } +"&&" { RECORD; return GRUB_PARSER_TOKEN_AND; } +";;" { RECORD; return GRUB_PARSER_TOKEN_SEMI2; } +"|" { RECORD; return GRUB_PARSER_TOKEN_PIPE; } +"&" { RECORD; return GRUB_PARSER_TOKEN_AMP; } +";" { RECORD; return GRUB_PARSER_TOKEN_SEMI; } +"<" { RECORD; return GRUB_PARSER_TOKEN_LT; } +">" { RECORD; return GRUB_PARSER_TOKEN_GT; } + + /* Reserved words */ +"!" { RECORD; return GRUB_PARSER_TOKEN_NOT; } +"{" { RECORD; return GRUB_PARSER_TOKEN_LBR; } +"}" { RECORD; return GRUB_PARSER_TOKEN_RBR; } +"[[" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; } +"]]" { RECORD; return GRUB_PARSER_TOKEN_LSQBR2; } +"time" { RECORD; return GRUB_PARSER_TOKEN_TIME; } +"case" { RECORD; return GRUB_PARSER_TOKEN_CASE; } +"do" { RECORD; return GRUB_PARSER_TOKEN_DO; } +"done" { RECORD; return GRUB_PARSER_TOKEN_DONE; } +"elif" { RECORD; return GRUB_PARSER_TOKEN_ELIF; } +"else" { RECORD; return GRUB_PARSER_TOKEN_ELSE; } +"esac" { RECORD; return GRUB_PARSER_TOKEN_ESAC; } +"fi" { RECORD; return GRUB_PARSER_TOKEN_FI; } +"for" { RECORD; return GRUB_PARSER_TOKEN_FOR; } +"if" { RECORD; return GRUB_PARSER_TOKEN_IF; } +"in" { RECORD; return GRUB_PARSER_TOKEN_IN; } +"select" { RECORD; return GRUB_PARSER_TOKEN_SELECT; } +"then" { RECORD; return GRUB_PARSER_TOKEN_THEN; } +"until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; } +"while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; } +"function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; } +"menuentry" { RECORD; return GRUB_PARSER_TOKEN_MENUENTRY; } + +{NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; } +{WORD} { + RECORD; + /* resplit yytext */ + grub_dprintf ("lexer", "word: [%s]\n", yytext); + yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner); + if (yy_scan_string (yytext, yyscanner)) + { + yyextra->lexerstate->merge_start = 1; + yy_push_state (SPLIT, yyscanner); + } + else + { + grub_script_yyerror (yyextra, 0); + yypop_buffer_state (yyscanner); + return GRUB_PARSER_TOKEN_WORD; + } + } + +.|\n { + grub_script_yyerror (yyextra, "unrecognized token"); + return GRUB_PARSER_TOKEN_BAD; + } + + /* Split word into multiple args */ + +{ + \\. { COPY (yytext + 1, yyleng - 1); } + \" { + yy_push_state (DQUOTE, yyscanner); + ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); + } + \' { + yy_push_state (SQUOTE, yyscanner); + ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); + } + \$ { + yy_push_state (VAR, yyscanner); + ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); + } + \\ | + [^\"\'\$\\]+ { COPY (yytext, yyleng); } + <> { + yy_pop_state (yyscanner); + yypop_buffer_state (yyscanner); + yyextra->lexerstate->merge_end = 1; + ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); + } +} + +{ + \? | + {DIGITS} | + {NAME} { + COPY (yytext, yyleng); + yy_pop_state (yyscanner); + if (YY_START == SPLIT) + ARG (GRUB_SCRIPT_ARG_TYPE_VAR); + else + ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR); + } + \{\?\} | + \{{DIGITS}\} | + \{{NAME}\} { + yytext[yyleng - 1] = '\0'; + COPY (yytext + 1, yyleng - 2); + yy_pop_state (yyscanner); + if (YY_START == SPLIT) + ARG (GRUB_SCRIPT_ARG_TYPE_VAR); + else + ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR); + } + .|\n { return GRUB_PARSER_TOKEN_BAD; } +} + +{ + \' { + yy_pop_state (yyscanner); + ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR); + } + [^\']+ { COPY (yytext, yyleng); } +} + +{ + \\\$ { COPY ("$", 1); } + \\\\ { COPY ("\\", 1); } + \\\" { COPY ("\"", 1); } + \\\n { /* ignore */ } + [^\"\$\\\n]+ { COPY (yytext, yyleng); } + \" { + yy_pop_state (yyscanner); + ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR); + } + \$ { + yy_push_state (VAR, yyscanner); + ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR); + } + (.|\n) { COPY (yytext, yyleng); } +} + +<> { + yypop_buffer_state (yyscanner); + if (! grub_script_lexer_yywrap (yyextra)) + { + yyextra->lexerstate->eof = 1; + return GRUB_PARSER_TOKEN_EOF; + } + } + +%% + +static void +grub_lexer_yyfree (void *ptr, yyscan_t yyscanner __attribute__ ((unused))) +{ + grub_free(ptr); +} + +static void* +grub_lexer_yyalloc (yy_size_t size, yyscan_t yyscanner __attribute__ ((unused))) +{ + return grub_malloc (size); +} + +static void* +grub_lexer_yyrealloc (void *ptr, yy_size_t size, + yyscan_t yyscanner __attribute__ ((unused))) +{ + return grub_realloc (ptr, size); +} + +#define MAX(a,b) ((a) < (b) ? (b) : (a)) + +static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint) +{ + int size; + char *ptr; + unsigned len; + + len = hint ? hint : grub_strlen (str); + if (parser->lexerstate->used + len >= parser->lexerstate->size) + { + size = MAX (len, parser->lexerstate->size) * 2; + ptr = grub_realloc (parser->lexerstate->text, size); + if (!ptr) + { + grub_script_yyerror (parser, 0); + return; + } + + parser->lexerstate->text = ptr; + parser->lexerstate->size = size; + } + grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str); + parser->lexerstate->used += len; +} diff --git a/term/i386/pc/at_keyboard.c b/term/at_keyboard.c similarity index 79% rename from term/i386/pc/at_keyboard.c rename to term/at_keyboard.c index cf30e7242..1f84ae71a 100644 --- a/term/i386/pc/at_keyboard.c +++ b/term/at_keyboard.c @@ -17,13 +17,14 @@ */ #include -#include -#include -#include +#include +#include +#include #include #include static short at_keyboard_status = 0; +static int pending_key = -1; #define KEYBOARD_STATUS_SHIFT_L (1 << 0) #define KEYBOARD_STATUS_SHIFT_R (1 << 1) @@ -32,6 +33,13 @@ static short at_keyboard_status = 0; #define KEYBOARD_STATUS_CTRL_L (1 << 4) #define KEYBOARD_STATUS_CTRL_R (1 << 5) #define KEYBOARD_STATUS_CAPS_LOCK (1 << 6) +#define KEYBOARD_STATUS_NUM_LOCK (1 << 7) + +static grub_uint8_t led_status; + +#define KEYBOARD_LED_SCROLL (1 << 0) +#define KEYBOARD_LED_NUM (1 << 1) +#define KEYBOARD_LED_CAPS (1 << 2) static char keyboard_map[128] = { @@ -65,9 +73,15 @@ static char keyboard_map_shift[128] = static grub_uint8_t grub_keyboard_controller_orig; static void -grub_keyboard_controller_write (grub_uint8_t c) +keyboard_controller_wait_until_ready (void) { while (! KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS))); +} + +static void +grub_keyboard_controller_write (grub_uint8_t c) +{ + keyboard_controller_wait_until_ready (); grub_outb (KEYBOARD_COMMAND_WRITE, KEYBOARD_REG_STATUS); grub_outb (c, KEYBOARD_REG_DATA); } @@ -75,11 +89,20 @@ grub_keyboard_controller_write (grub_uint8_t c) static grub_uint8_t grub_keyboard_controller_read (void) { - while (! KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS))); + keyboard_controller_wait_until_ready (); grub_outb (KEYBOARD_COMMAND_READ, KEYBOARD_REG_STATUS); return grub_inb (KEYBOARD_REG_DATA); } +static void +keyboard_controller_led (grub_uint8_t leds) +{ + keyboard_controller_wait_until_ready (); + grub_outb (0xed, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); + grub_outb (leds & 0x7, KEYBOARD_REG_DATA); +} + /* FIXME: This should become an interrupt service routine. For now it's just used to catch events from control keys. */ static void @@ -158,14 +181,37 @@ grub_at_keyboard_getkey_noblock (void) switch (code) { case CAPS_LOCK: - at_keyboard_status ^= KEYBOARD_STATUS_CAPS_LOCK; /* Caps lock sends scan code twice. Get the second one and discard it. */ while (grub_keyboard_getkey () == -1); + + at_keyboard_status ^= KEYBOARD_STATUS_CAPS_LOCK; + led_status ^= KEYBOARD_LED_CAPS; + keyboard_controller_led (led_status); + #ifdef DEBUG_AT_KEYBOARD grub_dprintf ("atkeyb", "caps_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK)); #endif key = -1; break; + case NUM_LOCK: + /* Num lock sends scan code twice. Get the second one and discard it. */ + while (grub_keyboard_getkey () == -1); + + at_keyboard_status ^= KEYBOARD_STATUS_NUM_LOCK; + led_status ^= KEYBOARD_LED_NUM; + keyboard_controller_led (led_status); + +#ifdef DEBUG_AT_KEYBOARD + grub_dprintf ("atkeyb", "num_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_NUM_LOCK)); +#endif + key = -1; + break; + case SCROLL_LOCK: + /* For scroll lock we don't keep track of status. Only update its led. */ + led_status ^= KEYBOARD_LED_SCROLL; + keyboard_controller_led (led_status); + key = -1; + break; default: if (at_keyboard_status & (KEYBOARD_STATUS_CTRL_L | KEYBOARD_STATUS_CTRL_R)) key = keyboard_map[code] - 'a' + 1; @@ -192,14 +238,27 @@ grub_at_keyboard_getkey_noblock (void) static int grub_at_keyboard_checkkey (void) { - /* FIXME: this will be triggered by BREAK events. */ - return KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS)) ? 1 : -1; + if (pending_key != -1) + return 1; + + pending_key = grub_at_keyboard_getkey_noblock (); + + if (pending_key != -1) + return 1; + + return -1; } static int grub_at_keyboard_getkey (void) { int key; + if (pending_key != -1) + { + key = pending_key; + pending_key = -1; + return key; + } do { key = grub_at_keyboard_getkey_noblock (); @@ -210,6 +269,8 @@ grub_at_keyboard_getkey (void) static grub_err_t grub_keyboard_controller_init (void) { + pending_key = -1; + at_keyboard_status = 0; grub_keyboard_controller_orig = grub_keyboard_controller_read (); grub_keyboard_controller_write (grub_keyboard_controller_orig | KEYBOARD_SCANCODE_SET1); return GRUB_ERR_NONE; diff --git a/term/efi/console.c b/term/efi/console.c index f3845089c..664861398 100644 --- a/term/efi/console.c +++ b/term/efi/console.c @@ -159,27 +159,27 @@ grub_console_checkkey (void) read_key = key.unicode_char; break; case 0x01: - read_key = 16; + read_key = GRUB_TERM_UP; break; case 0x02: - read_key = 14; + read_key = GRUB_TERM_DOWN; break; case 0x03: - read_key = 6; + read_key = GRUB_TERM_RIGHT; break; case 0x04: - read_key = 2; + read_key = GRUB_TERM_LEFT; break; case 0x05: - read_key = 1; + read_key = GRUB_TERM_HOME; break; case 0x06: - read_key = 5; + read_key = GRUB_TERM_END; break; case 0x07: break; case 0x08: - read_key = 4; + read_key = GRUB_TERM_DC; break; case 0x09: break; @@ -194,6 +194,9 @@ grub_console_checkkey (void) case 0x0d: read_key = 5; break; + case 0x0e: + read_key = 3; + break; case 0x17: read_key = '\e'; break; @@ -351,8 +354,7 @@ static struct grub_term_output grub_console_term_output = .setcolorstate = grub_console_setcolorstate, .setcolor = grub_console_setcolor, .getcolor = grub_console_getcolor, - .setcursor = grub_console_setcursor, - .flags = 0, + .setcursor = grub_console_setcursor }; void diff --git a/term/gfxterm.c b/term/gfxterm.c index f161499e6..ecfe4ff3b 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -24,10 +24,14 @@ #include #include #include +#include #include #include +#include +#include +#include -#define DEFAULT_VIDEO_MODE "1024x768,800x600,640x480" +#define DEFAULT_VIDEO_MODE "auto" #define DEFAULT_BORDER_WIDTH 10 #define DEFAULT_STANDARD_COLOR 0x07 @@ -95,15 +99,33 @@ struct grub_virtual_screen /* Color settings. */ grub_video_color_t fg_color; grub_video_color_t bg_color; + grub_video_color_t bg_color_display; /* Text buffer for virtual screen. Contains (columns * rows) number of entries. */ struct grub_colored_char *text_buffer; + + int total_scroll; }; -static struct grub_virtual_screen virtual_screen; +struct grub_gfxterm_window +{ + unsigned x; + unsigned y; + unsigned width; + unsigned height; + int double_repaint; +}; -static struct grub_video_mode_info mode_info; +static struct grub_video_render_target *render_target; +void (*grub_gfxterm_decorator_hook) (void) = NULL; +static struct grub_gfxterm_window window; +static struct grub_virtual_screen virtual_screen; +static grub_gfxterm_repaint_callback_t repaint_callback; +static int repaint_schedulded = 0; +static int repaint_was_schedulded = 0; + +static void destroy_window (void); static struct grub_video_render_target *text_layer; @@ -124,6 +146,8 @@ static unsigned int calculate_normal_character_width (grub_font_t font); static unsigned char calculate_character_width (struct grub_font_glyph *glyph); +static void grub_gfxterm_refresh (void); + static void set_term_color (grub_uint8_t term_color) { @@ -189,7 +213,7 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, virtual_screen.font = grub_font_get (font_name); if (!virtual_screen.font) return grub_error (GRUB_ERR_BAD_FONT, - "No font loaded."); + "no font loaded"); virtual_screen.width = width; virtual_screen.height = height; virtual_screen.offset_x = x; @@ -201,6 +225,7 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, virtual_screen.cursor_x = 0; virtual_screen.cursor_y = 0; virtual_screen.cursor_state = 1; + virtual_screen.total_scroll = 0; /* Calculate size of text buffer. */ virtual_screen.columns = virtual_screen.width / virtual_screen.normal_char_width; @@ -235,7 +260,9 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, set_term_color (virtual_screen.term_color); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_video_set_active_render_target (render_target); + + virtual_screen.bg_color_display = grub_video_map_rgba(0, 0, 0, 0); /* Clear out text buffer. */ for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++) @@ -244,75 +271,122 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, return grub_errno; } -static int NESTED_FUNC_ATTR video_hook (grub_video_adapter_t p __attribute__ ((unused)), - struct grub_video_mode_info *info) +void +grub_gfxterm_schedule_repaint (void) { - return ! (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT); + repaint_schedulded = 1; } -static grub_err_t -grub_gfxterm_init (void) +grub_err_t +grub_gfxterm_set_window (struct grub_video_render_target *target, + int x, int y, int width, int height, + int double_repaint, + const char *font_name, int border_width) { - char *font_name; - char *modevar; - char *tmp; - grub_video_color_t color; - int width; - int height; - grub_err_t err; + /* Clean up any prior instance. */ + destroy_window (); - /* Select the font to use. */ - font_name = grub_env_get ("gfxterm_font"); - if (! font_name) - font_name = ""; /* Allow fallback to any font. */ + /* Set the render target. */ + render_target = target; - /* Parse gfxmode environment variable if set. */ - modevar = grub_env_get ("gfxmode"); - if (! modevar || *modevar == 0) - err = grub_video_set_mode (DEFAULT_VIDEO_MODE, video_hook); - else + /* Create virtual screen. */ + if (grub_virtual_screen_setup (border_width, border_width, + width - 2 * border_width, + height - 2 * border_width, + font_name) + != GRUB_ERR_NONE) { - tmp = grub_malloc (grub_strlen (modevar) - + sizeof (DEFAULT_VIDEO_MODE) + 1); - grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); - err = grub_video_set_mode (tmp, video_hook); - grub_free (tmp); + return grub_errno; } - if (err) - return err; + /* Set window bounds. */ + window.x = x; + window.y = y; + window.width = width; + window.height = height; + window.double_repaint = double_repaint; + + dirty_region_reset (); + grub_gfxterm_schedule_repaint (); + + return grub_errno; +} + +grub_err_t +grub_gfxterm_fullscreen (void) +{ + const char *font_name; + struct grub_video_mode_info mode_info; + grub_video_color_t color; + grub_err_t err; + int double_redraw; err = grub_video_get_info (&mode_info); /* Figure out what mode we ended up. */ if (err) return err; + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + + double_redraw = mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); + /* Make sure screen is black. */ color = grub_video_map_rgb (0, 0, 0); grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height); + if (double_redraw) + { + grub_video_swap_buffers (); + grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height); + } bitmap = 0; - /* Leave borders for virtual screen. */ - width = mode_info.width - (2 * DEFAULT_BORDER_WIDTH); - height = mode_info.height - (2 * DEFAULT_BORDER_WIDTH); + /* Select the font to use. */ + font_name = grub_env_get ("gfxterm_font"); + if (! font_name) + font_name = ""; /* Allow fallback to any font. */ - /* Create virtual screen. */ - if (grub_virtual_screen_setup (DEFAULT_BORDER_WIDTH, DEFAULT_BORDER_WIDTH, - width, height, font_name) != GRUB_ERR_NONE) - { - grub_video_restore (); - return grub_errno; - } + grub_gfxterm_decorator_hook = NULL; - /* Mark whole screen as dirty. */ - dirty_region_reset (); - dirty_region_add (0, 0, mode_info.width, mode_info.height); - - return (grub_errno = GRUB_ERR_NONE); + return grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, + 0, 0, mode_info.width, mode_info.height, + double_redraw, + font_name, DEFAULT_BORDER_WIDTH); } static grub_err_t -grub_gfxterm_fini (void) +grub_gfxterm_term_init (void) +{ + char *tmp; + grub_err_t err; + const char *modevar; + + /* Parse gfxmode environment variable if set. */ + modevar = grub_env_get ("gfxmode"); + if (! modevar || *modevar == 0) + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); + else + { + tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); + if (!tmp) + return grub_errno; + err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); + grub_free (tmp); + } + + if (err) + return err; + + err = grub_gfxterm_fullscreen (); + if (err) + grub_video_restore (); + + return err; +} + +static void +destroy_window (void) { if (bitmap) { @@ -320,10 +394,18 @@ grub_gfxterm_fini (void) bitmap = 0; } + repaint_callback = 0; grub_virtual_screen_free (); +} +static grub_err_t +grub_gfxterm_term_fini (void) +{ + destroy_window (); grub_video_restore (); + /* Clear error state. */ + grub_errno = GRUB_ERR_NONE; return GRUB_ERR_NONE; } @@ -332,9 +414,15 @@ redraw_screen_rect (unsigned int x, unsigned int y, unsigned int width, unsigned int height) { grub_video_color_t color; + grub_video_rect_t saved_view; - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - + grub_video_set_active_render_target (render_target); + /* Save viewport and set it to our window. */ + grub_video_get_viewport ((unsigned *) &saved_view.x, + (unsigned *) &saved_view.y, + (unsigned *) &saved_view.width, + (unsigned *) &saved_view.height); + grub_video_set_viewport (window.x, window.y, window.width, window.height); if (bitmap) { @@ -345,7 +433,7 @@ redraw_screen_rect (unsigned int x, unsigned int y, /* If bitmap is smaller than requested blit area, use background color. */ - color = virtual_screen.bg_color; + color = virtual_screen.bg_color_display; /* Fill right side of the bitmap if needed. */ if ((x + width >= bitmap_width) && (y < bitmap_height)) @@ -392,7 +480,7 @@ redraw_screen_rect (unsigned int x, unsigned int y, else { /* Render background layer. */ - color = virtual_screen.bg_color; + color = virtual_screen.bg_color_display; grub_video_fill_rect (color, x, y, width, height); /* Render text layer as replaced (to get texts background color). */ @@ -401,6 +489,14 @@ redraw_screen_rect (unsigned int x, unsigned int y, y - virtual_screen.offset_y, width, height); } + + /* Restore saved viewport. */ + grub_video_set_viewport (saved_view.x, saved_view.y, + saved_view.width, saved_view.height); + grub_video_set_active_render_target (render_target); + + if (repaint_callback) + repaint_callback (x, y, width, height); } static void @@ -410,6 +506,7 @@ dirty_region_reset (void) dirty_region.top_left_y = -1; dirty_region.bottom_right_x = -1; dirty_region.bottom_right_y = -1; + repaint_was_schedulded = 0; } static int @@ -429,6 +526,16 @@ dirty_region_add (int x, int y, unsigned int width, unsigned int height) if ((width == 0) || (height == 0)) return; + if (repaint_schedulded) + { + x = virtual_screen.offset_x; + y = virtual_screen.offset_y; + width = virtual_screen.width; + height = virtual_screen.height; + repaint_schedulded = 0; + repaint_was_schedulded = 1; + } + if (dirty_region_is_empty ()) { dirty_region.top_left_x = x; @@ -475,13 +582,14 @@ dirty_region_redraw (void) width = dirty_region.bottom_right_x - x + 1; height = dirty_region.bottom_right_y - y + 1; - redraw_screen_rect (x, y, width, height); + if (repaint_was_schedulded && grub_gfxterm_decorator_hook) + grub_gfxterm_decorator_hook (); - dirty_region_reset (); + redraw_screen_rect (x, y, width, height); } -static void -write_char (void) +static inline void +paint_char (unsigned cx, unsigned cy) { struct grub_colored_char *p; struct grub_font_glyph *glyph; @@ -493,10 +601,12 @@ write_char (void) unsigned int height; unsigned int width; + if (cy + virtual_screen.total_scroll >= virtual_screen.rows) + return; + /* Find out active character. */ p = (virtual_screen.text_buffer - + virtual_screen.cursor_x - + (virtual_screen.cursor_y * virtual_screen.columns)); + + cx + (cy * virtual_screen.columns)); p -= p->index; @@ -510,68 +620,163 @@ write_char (void) color = p->fg_color; bgcolor = p->bg_color; - x = virtual_screen.cursor_x * virtual_screen.normal_char_width; - y = virtual_screen.cursor_y * virtual_screen.normal_char_height; + x = cx * virtual_screen.normal_char_width; + y = (cy + virtual_screen.total_scroll) * virtual_screen.normal_char_height; /* Render glyph to text layer. */ grub_video_set_active_render_target (text_layer); grub_video_fill_rect (bgcolor, x, y, width, height); grub_font_draw_glyph (glyph, color, x, y + ascent); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_video_set_active_render_target (render_target); /* Mark character to be drawn. */ dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y, width, height); } -static void +static inline void +write_char (void) +{ + paint_char (virtual_screen.cursor_x, virtual_screen.cursor_y); +} + +static inline void draw_cursor (int show) { + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + grub_video_color_t color; + write_char (); - if (show) + if (!show) + return; + + if (virtual_screen.cursor_y + virtual_screen.total_scroll + >= virtual_screen.rows) + return; + + /* Determine cursor properties and position on text layer. */ + x = virtual_screen.cursor_x * virtual_screen.normal_char_width; + width = virtual_screen.normal_char_width; + color = virtual_screen.fg_color; + y = ((virtual_screen.cursor_y + virtual_screen.total_scroll) + * virtual_screen.normal_char_height + + grub_font_get_ascent (virtual_screen.font)); + height = 2; + + /* Render cursor to text layer. */ + grub_video_set_active_render_target (text_layer); + grub_video_fill_rect (color, x, y, width, height); + grub_video_set_active_render_target (render_target); + + /* Mark cursor to be redrawn. */ + dirty_region_add (virtual_screen.offset_x + x, + virtual_screen.offset_y + y, + width, height); +} + +static void +real_scroll (void) +{ + unsigned int i, j, was_scroll; + grub_video_color_t color; + + if (!virtual_screen.total_scroll) + return; + + /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */ + if (bitmap) { - unsigned int x; - unsigned int y; - unsigned int width; - unsigned int height; - grub_video_color_t color; - - /* Determine cursor properties and position on text layer. */ - x = virtual_screen.cursor_x * virtual_screen.normal_char_width; - width = virtual_screen.normal_char_width; - color = virtual_screen.fg_color; - y = (virtual_screen.cursor_y * virtual_screen.normal_char_height - + grub_font_get_ascent (virtual_screen.font)); - height = 2; - - /* Render cursor to text layer. */ + /* Scroll physical screen. */ grub_video_set_active_render_target (text_layer); - grub_video_fill_rect (color, x, y, width, height); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + color = virtual_screen.bg_color; + grub_video_scroll (color, 0, -virtual_screen.normal_char_height + * virtual_screen.total_scroll); - /* Mark cursor to be redrawn. */ - dirty_region_add (virtual_screen.offset_x + x, - virtual_screen.offset_y + y, - width, height); + /* Mark virtual screen to be redrawn. */ + dirty_region_add_virtualscreen (); } + else + { + grub_video_rect_t saved_view; + + /* Remove cursor. */ + draw_cursor (0); + + grub_video_set_active_render_target (render_target); + /* Save viewport and set it to our window. */ + grub_video_get_viewport ((unsigned *) &saved_view.x, + (unsigned *) &saved_view.y, + (unsigned *) &saved_view.width, + (unsigned *) &saved_view.height); + grub_video_set_viewport (window.x, window.y, window.width, window.height); + + i = window.double_repaint ? 2 : 1; + + color = virtual_screen.bg_color; + + while (i--) + { + /* Clear new border area. */ + grub_video_fill_rect (color, + virtual_screen.offset_x, + virtual_screen.offset_y, + virtual_screen.width, + virtual_screen.normal_char_height + * virtual_screen.total_scroll); + + grub_video_set_active_render_target (render_target); + dirty_region_redraw (); + + /* Scroll physical screen. */ + grub_video_scroll (color, 0, -virtual_screen.normal_char_height + * virtual_screen.total_scroll); + + if (i) + grub_video_swap_buffers (); + } + dirty_region_reset (); + + /* Scroll physical screen. */ + grub_video_set_active_render_target (text_layer); + color = virtual_screen.bg_color; + grub_video_scroll (color, 0, -virtual_screen.normal_char_height + * virtual_screen.total_scroll); + + /* Restore saved viewport. */ + grub_video_set_viewport (saved_view.x, saved_view.y, + saved_view.width, saved_view.height); + grub_video_set_active_render_target (render_target); + + } + + was_scroll = virtual_screen.total_scroll; + virtual_screen.total_scroll = 0; + + if (was_scroll > virtual_screen.rows) + was_scroll = virtual_screen.rows; + + /* Draw shadow part. */ + for (i = virtual_screen.rows - was_scroll; + i < virtual_screen.rows; i++) + for (j = 0; j < virtual_screen.columns; j++) + paint_char (j, i); + + /* Draw cursor if visible. */ + if (virtual_screen.cursor_state) + draw_cursor (1); + + if (repaint_callback) + repaint_callback (window.x, window.y, window.width, window.height); } static void scroll_up (void) { unsigned int i; - grub_video_color_t color; - - /* If we don't have background bitmap, remove cursor. */ - if (!bitmap) - { - /* Remove cursor. */ - draw_cursor (0); - - /* Redraw only changed regions. */ - dirty_region_redraw (); - } /* Scroll text buffer with one line to up. */ grub_memmove (virtual_screen.text_buffer, @@ -586,32 +791,7 @@ scroll_up (void) i++) clear_char (&(virtual_screen.text_buffer[i])); - /* Scroll physical screen. */ - grub_video_set_active_render_target (text_layer); - color = virtual_screen.bg_color; - grub_video_scroll (color, 0, -virtual_screen.normal_char_height); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - - /* If we have bitmap, re-draw screen, otherwise scroll physical screen too. */ - if (bitmap) - { - /* Mark virtual screen to be redrawn. */ - dirty_region_add_virtualscreen (); - } - else - { - /* Clear new border area. */ - grub_video_fill_rect (color, - virtual_screen.offset_x, virtual_screen.offset_y, - virtual_screen.width, virtual_screen.normal_char_height); - - /* Scroll physical screen. */ - grub_video_scroll (color, 0, -virtual_screen.normal_char_height); - - /* Draw cursor if visible. */ - if (virtual_screen.cursor_state) - draw_cursor (1); - } + virtual_screen.total_scroll++; } static void @@ -814,11 +994,14 @@ grub_gfxterm_cls (void) /* Clear text layer. */ grub_video_set_active_render_target (text_layer); color = virtual_screen.bg_color; - grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height); - grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_video_fill_rect (color, 0, 0, + virtual_screen.width, virtual_screen.height); + grub_video_set_active_render_target (render_target); /* Mark virtual screen to be redrawn. */ dirty_region_add_virtualscreen (); + + grub_gfxterm_refresh (); } static void @@ -879,15 +1062,41 @@ grub_gfxterm_setcursor (int on) static void grub_gfxterm_refresh (void) { + real_scroll (); + /* Redraw only changed regions. */ dirty_region_redraw (); + + grub_video_swap_buffers (); + + if (window.double_repaint) + dirty_region_redraw (); + dirty_region_reset (); } +void +grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func) +{ + repaint_callback = func; +} + +/* Option array indices. */ +#define BACKGROUND_CMD_ARGINDEX_MODE 0 + +static const struct grub_arg_option background_image_cmd_options[] = + { + {"mode", 'm', 0, "Background image mode.", "stretch|normal", + ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + static grub_err_t -grub_gfxterm_background_image_cmd (grub_command_t cmd __attribute__ ((unused)), +grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)), int argc, char **args) { + struct grub_arg_list *state = cmd->state; + /* Check that we have video adapter active. */ if (grub_video_get_info(NULL) != GRUB_ERR_NONE) return grub_errno; @@ -899,8 +1108,7 @@ grub_gfxterm_background_image_cmd (grub_command_t cmd __attribute__ ((unused)), bitmap = 0; /* Mark whole screen as dirty. */ - dirty_region_reset (); - dirty_region_add (0, 0, mode_info.width, mode_info.height); + dirty_region_add (0, 0, window.width, window.height); } /* If filename was provided, try to load that. */ @@ -911,16 +1119,38 @@ grub_gfxterm_background_image_cmd (grub_command_t cmd __attribute__ ((unused)), if (grub_errno != GRUB_ERR_NONE) return grub_errno; + /* Determine if the bitmap should be scaled to fit the screen. */ + if (!state[BACKGROUND_CMD_ARGINDEX_MODE].set + || grub_strcmp (state[BACKGROUND_CMD_ARGINDEX_MODE].arg, + "stretch") == 0) + { + if (window.width != grub_video_bitmap_get_width (bitmap) + || window.height != grub_video_bitmap_get_height (bitmap)) + { + struct grub_video_bitmap *scaled_bitmap; + grub_video_bitmap_create_scaled (&scaled_bitmap, + window.width, + window.height, + bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + if (grub_errno == GRUB_ERR_NONE) + { + /* Replace the original bitmap with the scaled one. */ + grub_video_bitmap_destroy (bitmap); + bitmap = scaled_bitmap; + } + } + } + /* If bitmap was loaded correctly, display it. */ if (bitmap) { /* Determine bitmap dimensions. */ bitmap_width = grub_video_bitmap_get_width (bitmap); - bitmap_height = grub_video_bitmap_get_width (bitmap); + bitmap_height = grub_video_bitmap_get_height (bitmap); /* Mark whole screen as dirty. */ - dirty_region_reset (); - dirty_region_add (0, 0, mode_info.width, mode_info.height); + dirty_region_add (0, 0, window.width, window.height); } } @@ -932,8 +1162,8 @@ grub_gfxterm_background_image_cmd (grub_command_t cmd __attribute__ ((unused)), static struct grub_term_output grub_video_term = { .name = "gfxterm", - .init = grub_gfxterm_init, - .fini = grub_gfxterm_fini, + .init = grub_gfxterm_term_init, + .fini = grub_gfxterm_term_fini, .putchar = grub_gfxterm_putchar, .getcharwidth = grub_gfxterm_getcharwidth, .getwh = grub_virtual_screen_getwh, @@ -949,18 +1179,22 @@ static struct grub_term_output grub_video_term = .next = 0 }; -static grub_command_t cmd; +static grub_extcmd_t background_image_cmd_handle; -GRUB_MOD_INIT(term_gfxterm) +GRUB_MOD_INIT(gfxterm) { grub_term_register_output ("gfxterm", &grub_video_term); - cmd = grub_register_command ("background_image", - grub_gfxterm_background_image_cmd, - 0, "Load background image for active terminal"); + background_image_cmd_handle = + grub_register_extcmd ("background_image", + grub_gfxterm_background_image_cmd, + GRUB_COMMAND_FLAG_BOTH, + N_("[-m (stretch|normal)] FILE"), + N_("Load background image for active terminal."), + background_image_cmd_options); } -GRUB_MOD_FINI(term_gfxterm) +GRUB_MOD_FINI(gfxterm) { - grub_unregister_command (cmd); + grub_unregister_extcmd (background_image_cmd_handle); grub_term_unregister_output (&grub_video_term); } diff --git a/term/i386/pc/console.c b/term/i386/pc/console.c index 66475d456..43cfe2f2a 100644 --- a/term/i386/pc/console.c +++ b/term/i386/pc/console.c @@ -65,8 +65,7 @@ static struct grub_term_output grub_console_term_output = .setcolorstate = grub_console_setcolorstate, .setcolor = grub_console_setcolor, .getcolor = grub_console_getcolor, - .setcursor = grub_console_setcursor, - .flags = 0, + .setcursor = grub_console_setcursor }; void @@ -79,10 +78,6 @@ grub_console_init (void) void grub_console_fini (void) { - /* This is to make sure the console is restored to text mode before - we boot. */ - grub_term_set_current_output (&grub_console_term_output); - grub_term_unregister_input (&grub_console_term_input); grub_term_unregister_output (&grub_console_term_output); } diff --git a/term/i386/pc/vesafb.c b/term/i386/pc/vesafb.c deleted file mode 100644 index 52694ed10..000000000 --- a/term/i386/pc/vesafb.c +++ /dev/null @@ -1,606 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007,2009 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 . - */ - -// TODO: Deprecated and broken. Scheduled for removal as there is VBE driver in Video subsystem. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFAULT_CHAR_WIDTH 8 -#define DEFAULT_CHAR_HEIGHT 16 - -#define DEFAULT_FG_COLOR 0xa -#define DEFAULT_BG_COLOR 0x0 - -struct grub_colored_char -{ - /* An Unicode codepoint. */ - grub_uint32_t code; - - /* Color indexes. */ - unsigned char fg_color; - unsigned char bg_color; - - /* The width of this character minus one. */ - unsigned char width; - - /* The column index of this character. */ - unsigned char index; -}; - -struct grub_virtual_screen -{ - /* Dimensions of the virtual screen. */ - grub_uint32_t width; - grub_uint32_t height; - - /* Offset in the display. */ - grub_uint32_t offset_x; - grub_uint32_t offset_y; - - /* TTY Character sizes. */ - grub_uint32_t char_width; - grub_uint32_t char_height; - - /* Virtual screen TTY size. */ - grub_uint32_t columns; - grub_uint32_t rows; - - /* Current cursor details. */ - grub_uint32_t cursor_x; - grub_uint32_t cursor_y; - grub_uint8_t cursor_state; - grub_uint8_t fg_color; - grub_uint8_t bg_color; - - /* Text buffer for virtual screen. Contains (columns * rows) number - of entries. */ - struct grub_colored_char *text_buffer; -}; - -/* Make sure text buffer is not marked as allocated. */ -static struct grub_virtual_screen virtual_screen = - { - .text_buffer = 0 - }; - -static unsigned char *vga_font = 0; -static grub_uint32_t old_mode = 0; - -static struct grub_vbe_mode_info_block mode_info; -static grub_uint8_t *framebuffer = 0; -static grub_uint32_t bytes_per_scan_line = 0; - -static void -grub_virtual_screen_free (void) -{ - /* If virtual screen has been allocated, free it. */ - if (virtual_screen.text_buffer != 0) - grub_free (virtual_screen.text_buffer); - - /* Reset virtual screen data. */ - grub_memset (&virtual_screen, 0, sizeof (virtual_screen)); -} - -static grub_err_t -grub_virtual_screen_setup (grub_uint32_t width, - grub_uint32_t height) -{ - /* Free old virtual screen. */ - grub_virtual_screen_free (); - - /* Initialize with default data. */ - virtual_screen.width = width; - virtual_screen.height = height; - virtual_screen.offset_x = 0; - virtual_screen.offset_y = 0; - virtual_screen.char_width = DEFAULT_CHAR_WIDTH; - virtual_screen.char_height = DEFAULT_CHAR_HEIGHT; - virtual_screen.cursor_x = 0; - virtual_screen.cursor_y = 0; - virtual_screen.cursor_state = 1; - virtual_screen.fg_color = DEFAULT_FG_COLOR; - virtual_screen.bg_color = DEFAULT_BG_COLOR; - - /* Calculate size of text buffer. */ - virtual_screen.columns = virtual_screen.width / virtual_screen.char_width; - virtual_screen.rows = virtual_screen.height / virtual_screen.char_height; - - /* Allocate memory for text buffer. */ - virtual_screen.text_buffer = - (struct grub_colored_char *) grub_malloc (virtual_screen.columns - * virtual_screen.rows - * sizeof (*virtual_screen.text_buffer)); - - return grub_errno; -} - -static grub_err_t -grub_vesafb_mod_init (void) -{ - grub_uint32_t use_mode = GRUB_VBE_DEFAULT_VIDEO_MODE; - struct grub_vbe_info_block controller_info; - char *modevar; - - /* Use fonts from VGA bios. */ - vga_font = grub_vga_get_font (); - - /* Check if we have VESA BIOS installed. */ - if (grub_vbe_probe (&controller_info) != GRUB_ERR_NONE) - return grub_errno; - - /* Check existence of vbe_mode environment variable. */ - modevar = grub_env_get ("vbe_mode"); - - if (modevar != 0) - { - unsigned long value; - - value = grub_strtoul (modevar, 0, 0); - if (grub_errno == GRUB_ERR_NONE) - use_mode = value; - } - - /* Store initial video mode. */ - if (grub_vbe_get_video_mode (&old_mode) != GRUB_ERR_NONE) - return grub_errno; - - /* Setup desired graphics mode. */ - if (grub_vbe_set_video_mode (use_mode, &mode_info) != GRUB_ERR_NONE) - return grub_errno; - - /* Determine framebuffer and bytes per scan line. */ - framebuffer = (grub_uint8_t *) mode_info.phys_base_addr; - - if (controller_info.version >= 0x300) - bytes_per_scan_line = mode_info.lin_bytes_per_scan_line; - else - bytes_per_scan_line = mode_info.bytes_per_scan_line; - - /* Create virtual screen. */ - if (grub_virtual_screen_setup (mode_info.x_resolution, - mode_info.y_resolution) != GRUB_ERR_NONE) - { - grub_vbe_set_video_mode (old_mode, 0); - return grub_errno; - } - - /* Make sure frame buffer is black. */ - grub_memset (framebuffer, - 0, - bytes_per_scan_line * mode_info.y_resolution); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_vesafb_mod_fini (void) -{ - grub_virtual_screen_free (); - - grub_vbe_set_video_mode (old_mode, 0); - - return GRUB_ERR_NONE; -} - -static int -grub_virtual_screen_get_glyph (grub_uint32_t code, - unsigned char bitmap[32], - unsigned *width) -{ - if (code > 0x7f) - { - /* Map some unicode characters to the VGA font, if possible. */ - switch (code) - { - case 0x2190: /* left arrow */ - code = 0x1b; - break; - case 0x2191: /* up arrow */ - code = 0x18; - break; - case 0x2192: /* right arrow */ - code = 0x1a; - break; - case 0x2193: /* down arrow */ - code = 0x19; - break; - case 0x2501: /* horizontal line */ - code = 0xc4; - break; - case 0x2503: /* vertical line */ - code = 0xb3; - break; - case 0x250F: /* upper-left corner */ - code = 0xda; - break; - case 0x2513: /* upper-right corner */ - code = 0xbf; - break; - case 0x2517: /* lower-left corner */ - code = 0xc0; - break; - case 0x251B: /* lower-right corner */ - code = 0xd9; - break; - - default: - return grub_font_get_glyph_any (code, bitmap, width); - } - } - - /* TODO This is wrong for the new font module. Should it be fixed? */ - if (bitmap) - grub_memcpy (bitmap, - vga_font + code * virtual_screen.char_height, - virtual_screen.char_height); - *width = 1; - return 1; -} - -static void -grub_virtual_screen_invalidate_char (struct grub_colored_char *p) -{ - p->code = 0xFFFF; - - if (p->width) - { - struct grub_colored_char *q; - - for (q = p + 1; q <= p + p->width; q++) - { - q->code = 0xFFFF; - q->width = 0; - q->index = 0; - } - } - - p->width = 0; -} - -static void -write_char (void) -{ - struct grub_colored_char *p; - unsigned char bitmap[32]; - unsigned width; - unsigned y; - unsigned offset; - - p = (virtual_screen.text_buffer - + virtual_screen.cursor_x - + (virtual_screen.cursor_y * virtual_screen.columns)); - - p -= p->index; - - if (! grub_virtual_screen_get_glyph (p->code, bitmap, &width)) - { - grub_virtual_screen_invalidate_char (p); - width = 0; - } - - for (y = 0, offset = 0; - y < virtual_screen.char_height; - y++, offset++) - { - unsigned i; - - for (i = 0; - (i < width * virtual_screen.char_width) && (offset < 32); - i++) - { - unsigned char color; - - if (bitmap[offset] & (1 << (8-i))) - { - color = p->fg_color; - } - else - { - color = p->bg_color; - } - - grub_vbe_set_pixel_index(i + (virtual_screen.cursor_x - * virtual_screen.char_width), - y + (virtual_screen.cursor_y - * virtual_screen.char_height), - color); - } - } -} - -static void -write_cursor (void) -{ - grub_uint32_t x; - grub_uint32_t y; - - for (y = ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 3; - y < ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 1; - y++) - { - for (x = virtual_screen.cursor_x * virtual_screen.char_width; - x < (virtual_screen.cursor_x + 1) * virtual_screen.char_width; - x++) - { - grub_vbe_set_pixel_index(x, y, 10); - } - } -} - -static void -scroll_up (void) -{ - grub_uint32_t i; - - /* Scroll text buffer with one line to up. */ - grub_memmove (virtual_screen.text_buffer, - virtual_screen.text_buffer + virtual_screen.columns, - sizeof (*virtual_screen.text_buffer) - * virtual_screen.columns - * (virtual_screen.rows - 1)); - - /* Clear last line in text buffer. */ - for (i = virtual_screen.columns * (virtual_screen.rows - 1); - i < virtual_screen.columns * virtual_screen.rows; - i++) - { - virtual_screen.text_buffer[i].code = ' '; - virtual_screen.text_buffer[i].fg_color = 0; - virtual_screen.text_buffer[i].bg_color = 0; - virtual_screen.text_buffer[i].width = 0; - virtual_screen.text_buffer[i].index = 0; - } - - /* Scroll framebuffer with one line to up. */ - grub_memmove (framebuffer, - framebuffer - + bytes_per_scan_line * virtual_screen.char_height, - bytes_per_scan_line - * (mode_info.y_resolution - virtual_screen.char_height)); - - /* Clear last line in framebuffer. */ - grub_memset (framebuffer - + (bytes_per_scan_line - * (mode_info.y_resolution - virtual_screen.char_height)), - 0, - bytes_per_scan_line * virtual_screen.char_height); -} - -static void -grub_vesafb_putchar (grub_uint32_t c) -{ - if (c == '\a') - /* FIXME */ - return; - - if (c == '\b' || c == '\n' || c == '\r') - { - /* Erase current cursor, if any. */ - if (virtual_screen.cursor_state) - write_char (); - - switch (c) - { - case '\b': - if (virtual_screen.cursor_x > 0) - virtual_screen.cursor_x--; - break; - - case '\n': - if (virtual_screen.cursor_y >= virtual_screen.rows - 1) - scroll_up (); - else - virtual_screen.cursor_y++; - break; - - case '\r': - virtual_screen.cursor_x = 0; - break; - } - - if (virtual_screen.cursor_state) - write_cursor (); - } - else - { - unsigned width; - struct grub_colored_char *p; - - grub_virtual_screen_get_glyph (c, 0, &width); - - if (virtual_screen.cursor_x + width > virtual_screen.columns) - grub_putchar ('\n'); - - p = (virtual_screen.text_buffer + - virtual_screen.cursor_x + - virtual_screen.cursor_y * virtual_screen.columns); - p->code = c; - p->fg_color = virtual_screen.fg_color; - p->bg_color = virtual_screen.bg_color; - p->width = width - 1; - p->index = 0; - - if (width > 1) - { - unsigned i; - - for (i = 1; i < width; i++) - { - p[i].code = ' '; - p[i].width = width - 1; - p[i].index = i; - } - } - - write_char (); - - virtual_screen.cursor_x += width; - if (virtual_screen.cursor_x >= virtual_screen.columns) - { - virtual_screen.cursor_x = 0; - - if (virtual_screen.cursor_y >= virtual_screen.rows - 1) - scroll_up (); - else - virtual_screen.cursor_y++; - } - - if (virtual_screen.cursor_state) - write_cursor (); - } -} - -static grub_ssize_t -grub_vesafb_getcharwidth (grub_uint32_t c) -{ - unsigned width; - - if (! grub_virtual_screen_get_glyph (c, 0, &width)) - return 0; - - return width; -} - -static grub_uint16_t -grub_virtual_screen_getwh (void) -{ - return (virtual_screen.columns << 8) | virtual_screen.rows; -} - -static grub_uint16_t -grub_virtual_screen_getxy (void) -{ - return ((virtual_screen.cursor_x << 8) | virtual_screen.cursor_y); -} - -static void -grub_vesafb_gotoxy (grub_uint8_t x, grub_uint8_t y) -{ - if (x >= virtual_screen.columns || y >= virtual_screen.rows) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)", - (unsigned) x, (unsigned) y); - return; - } - - if (virtual_screen.cursor_state) - write_char (); - - virtual_screen.cursor_x = x; - virtual_screen.cursor_y = y; - - if (virtual_screen.cursor_state) - write_cursor (); -} - -static void -grub_virtual_screen_cls (void) -{ - grub_uint32_t i; - - for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++) - { - virtual_screen.text_buffer[i].code = ' '; - virtual_screen.text_buffer[i].fg_color = 0; - virtual_screen.text_buffer[i].bg_color = 0; - virtual_screen.text_buffer[i].width = 0; - virtual_screen.text_buffer[i].index = 0; - } - - virtual_screen.cursor_x = virtual_screen.cursor_y = 0; -} - -static void -grub_vesafb_cls (void) -{ - grub_virtual_screen_cls (); - - grub_memset (framebuffer, - 0, - mode_info.y_resolution * bytes_per_scan_line); -} - -static void -grub_virtual_screen_setcolorstate (grub_term_color_state state) -{ - switch (state) - { - case GRUB_TERM_COLOR_STANDARD: - case GRUB_TERM_COLOR_NORMAL: - virtual_screen.fg_color = DEFAULT_FG_COLOR; - virtual_screen.bg_color = DEFAULT_BG_COLOR; - break; - case GRUB_TERM_COLOR_HIGHLIGHT: - virtual_screen.fg_color = DEFAULT_BG_COLOR; - virtual_screen.bg_color = DEFAULT_FG_COLOR; - break; - default: - break; - } -} - -static void -grub_vesafb_setcursor (int on) -{ - if (virtual_screen.cursor_state != on) - { - if (virtual_screen.cursor_state) - write_char (); - else - write_cursor (); - - virtual_screen.cursor_state = on; - } -} - -static struct grub_term_output grub_vesafb_term = - { - .name = "vesafb", - .init = grub_vesafb_mod_init, - .fini = grub_vesafb_mod_fini, - .putchar = grub_vesafb_putchar, - .getcharwidth = grub_vesafb_getcharwidth, - .getwh = grub_virtual_screen_getwh, - .getxy = grub_virtual_screen_getxy, - .gotoxy = grub_vesafb_gotoxy, - .cls = grub_vesafb_cls, - .setcolorstate = grub_virtual_screen_setcolorstate, - .setcursor = grub_vesafb_setcursor, - .flags = 0, - }; - -GRUB_MOD_INIT(vesafb) -{ - grub_term_register_output ("vesafb", &grub_vesafb_term); -} - -GRUB_MOD_FINI(vesafb) -{ - grub_term_unregister_output (&grub_vesafb_term); -} diff --git a/term/i386/pc/vga.c b/term/i386/pc/vga.c deleted file mode 100644 index 9deb6a6d7..000000000 --- a/term/i386/pc/vga.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009 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 . - */ - -// TODO: Deprecated and broken. Needs to be converted to Video Driver! - -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG_VGA 0 - -#define VGA_WIDTH 640 -#define VGA_HEIGHT 350 -#define CHAR_WIDTH 8 -#define CHAR_HEIGHT 16 -#define TEXT_WIDTH (VGA_WIDTH / CHAR_WIDTH) -#define TEXT_HEIGHT (VGA_HEIGHT / CHAR_HEIGHT) -#define VGA_MEM ((grub_uint8_t *) GRUB_MEMORY_MACHINE_VGA_ADDR) -#define PAGE_OFFSET(x) ((x) * (VGA_WIDTH * VGA_HEIGHT / 8)) - -#define DEFAULT_FG_COLOR 0xa -#define DEFAULT_BG_COLOR 0x0 - -struct colored_char -{ - /* An Unicode codepoint. */ - grub_uint32_t code; - - /* Color indexes. */ - unsigned char fg_color; - unsigned char bg_color; - - /* The width of this character minus one. */ - unsigned char width; - - /* The column index of this character. */ - unsigned char index; -}; - -static unsigned char text_mode; -static unsigned xpos, ypos; -static int cursor_state; -static unsigned char fg_color, bg_color; -static struct colored_char text_buf[TEXT_WIDTH * TEXT_HEIGHT]; -static unsigned char saved_map_mask; -static int page = 0; -static grub_font_t font = 0; - -#define SEQUENCER_ADDR_PORT 0x3C4 -#define SEQUENCER_DATA_PORT 0x3C5 -#define MAP_MASK_REGISTER 0x02 - -#define CRTC_ADDR_PORT 0x3D4 -#define CRTC_DATA_PORT 0x3D5 -#define START_ADDR_HIGH_REGISTER 0x0C -#define START_ADDR_LOW_REGISTER 0x0D - -#define GRAPHICS_ADDR_PORT 0x3CE -#define GRAPHICS_DATA_PORT 0x3CF -#define READ_MAP_REGISTER 0x04 - -#define INPUT_STATUS1_REGISTER 0x3DA -#define INPUT_STATUS1_VERTR_BIT 0x08 - -static inline void -wait_vretrace (void) -{ - /* Wait until there is a vertical retrace. */ - while (! (grub_inb (INPUT_STATUS1_REGISTER) & INPUT_STATUS1_VERTR_BIT)); -} - -/* Get Map Mask Register. */ -static unsigned char -get_map_mask (void) -{ - unsigned char old_addr; - unsigned char old_data; - - old_addr = grub_inb (SEQUENCER_ADDR_PORT); - grub_outb (MAP_MASK_REGISTER, SEQUENCER_ADDR_PORT); - - old_data = grub_inb (SEQUENCER_DATA_PORT); - - grub_outb (old_addr, SEQUENCER_ADDR_PORT); - - return old_data; -} - -/* Set Map Mask Register. */ -static void -set_map_mask (unsigned char mask) -{ - unsigned char old_addr; - - old_addr = grub_inb (SEQUENCER_ADDR_PORT); - grub_outb (MAP_MASK_REGISTER, SEQUENCER_ADDR_PORT); - - grub_outb (mask, SEQUENCER_DATA_PORT); - - grub_outb (old_addr, SEQUENCER_ADDR_PORT); -} - -/* Set Read Map Register. */ -static void -set_read_map (unsigned char map) -{ - unsigned char old_addr; - - old_addr = grub_inb (GRAPHICS_ADDR_PORT); - - grub_outb (READ_MAP_REGISTER, GRAPHICS_ADDR_PORT); - grub_outb (map, GRAPHICS_DATA_PORT); - - grub_outb (old_addr, GRAPHICS_ADDR_PORT); -} - -/* Set start address. */ -static void -set_start_address (unsigned int start) -{ - unsigned char old_addr; - - old_addr = grub_inb (CRTC_ADDR_PORT); - - grub_outb (START_ADDR_LOW_REGISTER, CRTC_ADDR_PORT); - grub_outb (start & 0xFF, CRTC_DATA_PORT); - - grub_outb (START_ADDR_HIGH_REGISTER, CRTC_ADDR_PORT); - grub_outb (start >> 8, CRTC_DATA_PORT); - - grub_outb (old_addr, CRTC_ADDR_PORT); -} - -static grub_err_t -grub_vga_mod_init (void) -{ - text_mode = grub_vga_set_mode (0x10); - cursor_state = 1; - fg_color = DEFAULT_FG_COLOR; - bg_color = DEFAULT_BG_COLOR; - saved_map_mask = get_map_mask (); - set_map_mask (0x0f); - set_start_address (PAGE_OFFSET (page)); - font = grub_font_get (""); /* Choose any font, for now. */ - if (!font) - return grub_error (GRUB_ERR_BAD_FONT, "No font loaded."); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_vga_mod_fini (void) -{ - set_map_mask (saved_map_mask); - grub_vga_set_mode (text_mode); - return GRUB_ERR_NONE; -} - -static int -check_vga_mem (void *p) -{ - return (p >= (void *) (VGA_MEM + PAGE_OFFSET (page)) - && p <= (void *) (VGA_MEM + PAGE_OFFSET (page) - + VGA_WIDTH * VGA_HEIGHT / 8)); -} - -static void -write_char (void) -{ - struct colored_char *p = text_buf + xpos + ypos * TEXT_WIDTH; - struct grub_font_glyph *glyph; - unsigned char *mem_base; - unsigned plane; - - mem_base = (VGA_MEM + xpos + - ypos * CHAR_HEIGHT * TEXT_WIDTH + PAGE_OFFSET (page)) - p->index; - p -= p->index; - - /* Get glyph for character. */ - glyph = grub_font_get_glyph (font, p->code); - - for (plane = 0x01; plane <= 0x08; plane <<= 1) - { - unsigned y; - unsigned offset; - unsigned char *mem; - - set_map_mask (plane); - - for (y = 0, offset = 0, mem = mem_base; - y < CHAR_HEIGHT; - y++, mem += TEXT_WIDTH) - { - /* TODO Re-implement glyph drawing for vga module. */ -#if 0 - unsigned i; - - unsigned char_width = 1; /* TODO Figure out wide characters. */ - for (i = 0; i < char_width && offset < 32; i++) - { - unsigned char fg_mask, bg_mask; - - fg_mask = (p->fg_color & plane) ? glyph->bitmap[offset] : 0; - bg_mask = (p->bg_color & plane) ? ~(glyph->bitmap[offset]) : 0; - offset++; - - if (check_vga_mem (mem + i)) - mem[i] = (fg_mask | bg_mask); - } -#endif /* 0 */ - } - } - - set_map_mask (0x0f); -} - -static void -write_cursor (void) -{ - unsigned char *mem = (VGA_MEM + PAGE_OFFSET (page) + xpos - + (ypos * CHAR_HEIGHT + CHAR_HEIGHT - 3) * TEXT_WIDTH); - if (check_vga_mem (mem)) - *mem = 0xff; - - mem += TEXT_WIDTH; - if (check_vga_mem (mem)) - *mem = 0xff; -} - -static void -scroll_up (void) -{ - unsigned i; - unsigned plane; - - /* Do all the work in the other page. */ - grub_memmove (text_buf, text_buf + TEXT_WIDTH, - sizeof (struct colored_char) * TEXT_WIDTH * (TEXT_HEIGHT - 1)); - - for (i = TEXT_WIDTH * (TEXT_HEIGHT - 1); i < TEXT_WIDTH * TEXT_HEIGHT; i++) - { - text_buf[i].code = ' '; - text_buf[i].fg_color = 0; - text_buf[i].bg_color = 0; - text_buf[i].width = 0; - text_buf[i].index = 0; - } - - for (plane = 1; plane <= 4; plane++) - { - set_read_map (plane); - set_map_mask (1 << plane); - grub_memmove (VGA_MEM + PAGE_OFFSET (1 - page), VGA_MEM - + PAGE_OFFSET (page) + VGA_WIDTH * CHAR_HEIGHT / 8, - VGA_WIDTH * (VGA_HEIGHT - CHAR_HEIGHT) / 8); - } - - set_map_mask (0x0f); - grub_memset (VGA_MEM + PAGE_OFFSET (1 - page) - + VGA_WIDTH * (VGA_HEIGHT - CHAR_HEIGHT) / 8, 0, - VGA_WIDTH * CHAR_HEIGHT / 8); - - /* Activate the other page. */ - page = 1 - page; - wait_vretrace (); - set_start_address (PAGE_OFFSET (page)); -} - -static void -grub_vga_putchar (grub_uint32_t c) -{ -#if DEBUG_VGA - static int show = 1; -#endif - - if (c == '\a') - /* FIXME */ - return; - - if (c == '\b' || c == '\n' || c == '\r') - { - /* Erase current cursor, if any. */ - if (cursor_state) - write_char (); - - switch (c) - { - case '\b': - if (xpos > 0) - xpos--; - break; - - case '\n': - if (ypos >= TEXT_HEIGHT - 1) - scroll_up (); - else - ypos++; - break; - - case '\r': - xpos = 0; - break; - } - - if (cursor_state) - write_cursor (); - } - else - { - struct grub_font_glyph *glyph; - struct colored_char *p; - unsigned char_width = 1; - - glyph = grub_font_get_glyph(font, c); - - if (xpos + char_width > TEXT_WIDTH) - grub_putchar ('\n'); - - p = text_buf + xpos + ypos * TEXT_WIDTH; - p->code = c; - p->fg_color = fg_color; - p->bg_color = bg_color; - p->width = char_width - 1; - p->index = 0; - - if (char_width > 1) - { - unsigned i; - - for (i = 1; i < char_width; i++) - { - p[i].code = ' '; - p[i].width = char_width - 1; - p[i].index = i; - } - } - - write_char (); - - xpos += char_width; - if (xpos >= TEXT_WIDTH) - { - xpos = 0; - - if (ypos >= TEXT_HEIGHT - 1) - scroll_up (); - else - ypos++; - } - - if (cursor_state) - write_cursor (); - } - -#if DEBUG_VGA - if (show) - { - grub_uint16_t pos = grub_getxy (); - - show = 0; - grub_gotoxy (0, 0); - grub_printf ("[%u:%u]", (unsigned) (pos >> 8), (unsigned) (pos & 0xff)); - grub_gotoxy (pos >> 8, pos & 0xff); - show = 1; - } -#endif -} - -static grub_ssize_t -grub_vga_getcharwidth (grub_uint32_t c) -{ -#if 0 - struct grub_font_glyph glyph; - - glyph = grub_font_get_glyph (c); - - return glyph.char_width; -#else - (void) c; /* Prevent warning. */ - return 1; /* TODO Fix wide characters? */ -#endif -} - -static grub_uint16_t -grub_vga_getwh (void) -{ - return (TEXT_WIDTH << 8) | TEXT_HEIGHT; -} - -static grub_uint16_t -grub_vga_getxy (void) -{ - return ((xpos << 8) | ypos); -} - -static void -grub_vga_gotoxy (grub_uint8_t x, grub_uint8_t y) -{ - if (x >= TEXT_WIDTH || y >= TEXT_HEIGHT) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)", - (unsigned) x, (unsigned) y); - return; - } - - if (cursor_state) - write_char (); - - xpos = x; - ypos = y; - - if (cursor_state) - write_cursor (); -} - -static void -grub_vga_cls (void) -{ - unsigned i; - - wait_vretrace (); - for (i = 0; i < TEXT_WIDTH * TEXT_HEIGHT; i++) - { - text_buf[i].code = ' '; - text_buf[i].fg_color = 0; - text_buf[i].bg_color = 0; - text_buf[i].width = 0; - text_buf[i].index = 0; - } - - grub_memset (VGA_MEM + PAGE_OFFSET (page), 0, VGA_WIDTH * VGA_HEIGHT / 8); - - xpos = ypos = 0; -} - -static void -grub_vga_setcolorstate (grub_term_color_state state) -{ - switch (state) - { - case GRUB_TERM_COLOR_STANDARD: - case GRUB_TERM_COLOR_NORMAL: - fg_color = DEFAULT_FG_COLOR; - bg_color = DEFAULT_BG_COLOR; - break; - case GRUB_TERM_COLOR_HIGHLIGHT: - fg_color = DEFAULT_BG_COLOR; - bg_color = DEFAULT_FG_COLOR; - break; - default: - break; - } -} - -static void -grub_vga_setcursor (int on) -{ - if (cursor_state != on) - { - if (cursor_state) - write_char (); - else - write_cursor (); - - cursor_state = on; - } -} - -static struct grub_term_output grub_vga_term = - { - .name = "vga", - .init = grub_vga_mod_init, - .fini = grub_vga_mod_fini, - .putchar = grub_vga_putchar, - .getcharwidth = grub_vga_getcharwidth, - .getwh = grub_vga_getwh, - .getxy = grub_vga_getxy, - .gotoxy = grub_vga_gotoxy, - .cls = grub_vga_cls, - .setcolorstate = grub_vga_setcolorstate, - .setcursor = grub_vga_setcursor, - .flags = 0, - }; - -GRUB_MOD_INIT(vga) -{ - grub_term_register_output ("vga", &grub_vga_term); -} - -GRUB_MOD_FINI(vga) -{ - grub_term_unregister_output (&grub_vga_term); -} diff --git a/term/i386/pc/vga_text.c b/term/i386/pc/vga_text.c index 170f74de8..f954cab43 100644 --- a/term/i386/pc/vga_text.c +++ b/term/i386/pc/vga_text.c @@ -77,7 +77,7 @@ inc_y (void) static void inc_x (void) { - if (grub_curr_x >= COLS - 2) + if (grub_curr_x >= COLS - 1) inc_y (); else grub_curr_x++; diff --git a/term/ieee1275/ofconsole.c b/term/ieee1275/ofconsole.c index c61e16eb7..898f9ceab 100644 --- a/term/ieee1275/ofconsole.c +++ b/term/ieee1275/ofconsole.c @@ -1,7 +1,7 @@ /* ofconsole.c -- Open Firmware console for GRUB. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2007,2008,2009 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 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -43,17 +44,17 @@ struct color int blue; }; -#define MAX 0xff -static struct color colors[8] = +static struct color colors[] = { - { 0, 0, 0}, - { MAX, 0, 0}, - { 0, MAX, 0}, - { MAX, MAX, 0}, - { 0, 0, MAX}, - { MAX, 0, MAX}, - { 0, MAX, MAX}, - { MAX, MAX, MAX} + // {R, G, B} + {0x00, 0x00, 0x00}, + {0x00, 0x00, 0xA8}, // 1 = blue + {0x00, 0xA8, 0x00}, // 2 = green + {0x00, 0xA8, 0xA8}, // 3 = cyan + {0xA8, 0x00, 0x00}, // 4 = red + {0xA8, 0x00, 0xA8}, // 5 = magenta + {0xFE, 0xFE, 0x54}, // 6 = yellow + {0xFE, 0xFE, 0xFE} // 7 = white }; static grub_uint8_t grub_ofconsole_normal_color = 0x7; @@ -77,18 +78,68 @@ grub_ofconsole_writeesc (const char *str) static void grub_ofconsole_putchar (grub_uint32_t c) { - char chr = c; + char chr; + + if (c > 0x7F) + { + /* Better than nothing. */ + switch (c) + { + case GRUB_TERM_DISP_LEFT: + c = '<'; + break; + + case GRUB_TERM_DISP_UP: + c = '^'; + break; + + case GRUB_TERM_DISP_RIGHT: + c = '>'; + break; + + case GRUB_TERM_DISP_DOWN: + c = 'v'; + break; + + case GRUB_TERM_DISP_HLINE: + c = '-'; + break; + + case GRUB_TERM_DISP_VLINE: + c = '|'; + break; + + case GRUB_TERM_DISP_UL: + case GRUB_TERM_DISP_UR: + case GRUB_TERM_DISP_LL: + case GRUB_TERM_DISP_LR: + c = '+'; + break; + + default: + c = '?'; + break; + } + } + + chr = c; + if (c == '\n') { grub_curr_y++; grub_curr_x = 0; } + else if (c == '\r') + { + grub_curr_x = 0; + } else { grub_curr_x++; - if (grub_curr_x > grub_ofconsole_width) + if (grub_curr_x >= grub_ofconsole_width) { - grub_putcode ('\n'); + grub_ofconsole_putchar ('\n'); + grub_ofconsole_putchar ('\r'); grub_curr_x++; } } @@ -104,7 +155,7 @@ grub_ofconsole_getcharwidth (grub_uint32_t c __attribute__((unused))) static void grub_ofconsole_setcolorstate (grub_term_color_state state) { - char setcol[20]; + char setcol[256]; int fg; int bg; @@ -123,7 +174,7 @@ grub_ofconsole_setcolorstate (grub_term_color_state state) return; } - grub_sprintf (setcol, "\e[3%dm\e[4%dm", fg, bg); + grub_snprintf (setcol, sizeof (setcol), "\e[3%dm\e[4%dm", fg, bg); grub_ofconsole_writeesc (setcol); } @@ -131,8 +182,9 @@ static void grub_ofconsole_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color) { - grub_ofconsole_normal_color = normal_color; - grub_ofconsole_highlight_color = highlight_color; + /* Discard bright bit. */ + grub_ofconsole_normal_color = normal_color & 0x77; + grub_ofconsole_highlight_color = highlight_color & 0x77; } static void @@ -142,50 +194,95 @@ grub_ofconsole_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_col *highlight_color = grub_ofconsole_highlight_color; } +#define ANSI_C0 0x9b + static int grub_ofconsole_readkey (int *key) { - char c; + grub_uint8_t c; grub_ssize_t actual = 0; grub_ieee1275_read (stdin_ihandle, &c, 1, &actual); - - if (actual > 0 && c == '\e') - { - grub_ieee1275_read (stdin_ihandle, &c, 1, &actual); - if (actual <= 0) + if (actual > 0) + switch(c) + { + case 0x7f: + /* Backspace: Ctrl-h. */ + c = '\b'; + break; + case ANSI_C0: + case '\e': { - *key = '\e'; - return 1; + grub_uint64_t start; + + if (c == '\e') + { + grub_ieee1275_read (stdin_ihandle, &c, 1, &actual); + + /* On 9600 we have to wait up to 12 milliseconds. */ + start = grub_get_time_ms (); + while (actual <= 0 && grub_get_time_ms () - start < 12) + grub_ieee1275_read (stdin_ihandle, &c, 1, &actual); + + if (actual <= 0) + { + *key = '\e'; + return 1; + } + + if (c != '[') + return 0; + } + + grub_ieee1275_read (stdin_ihandle, &c, 1, &actual); + + /* On 9600 we have to wait up to 12 milliseconds. */ + start = grub_get_time_ms (); + while (actual <= 0 && grub_get_time_ms () - start < 12) + grub_ieee1275_read (stdin_ihandle, &c, 1, &actual); + if (actual <= 0) + return 0; + + switch (c) + { + case 'A': + /* Up: Ctrl-p. */ + c = GRUB_TERM_UP; + break; + case 'B': + /* Down: Ctrl-n. */ + c = GRUB_TERM_DOWN; + break; + case 'C': + /* Right: Ctrl-f. */ + c = GRUB_TERM_RIGHT; + break; + case 'D': + /* Left: Ctrl-b. */ + c = GRUB_TERM_LEFT; + break; + case '3': + { + grub_ieee1275_read (stdin_ihandle, &c, 1, &actual); + /* On 9600 we have to wait up to 12 milliseconds. */ + start = grub_get_time_ms (); + while (actual <= 0 && grub_get_time_ms () - start < 12) + grub_ieee1275_read (stdin_ihandle, &c, 1, &actual); + + if (actual <= 0) + return 0; + + /* Delete: Ctrl-d. */ + if (c == '~') + c = GRUB_TERM_DC; + else + return 0; + break; + } + break; + } } - - if (c != 91) - return 0; - - grub_ieee1275_read (stdin_ihandle, &c, 1, &actual); - if (actual <= 0) - return 0; - - switch (c) - { - case 65: - /* Up: Ctrl-p. */ - c = 16; - break; - case 66: - /* Down: Ctrl-n. */ - c = 14; - break; - case 67: - /* Right: Ctrl-f. */ - c = 6; - break; - case 68: - /* Left: Ctrl-b. */ - c = 2; - break; - } - } + } *key = c; return actual > 0; @@ -230,47 +327,35 @@ grub_ofconsole_getkey (void) static grub_uint16_t grub_ofconsole_getxy (void) { - return ((grub_curr_x - 1) << 8) | grub_curr_y; + return (grub_curr_x << 8) | grub_curr_y; } -static grub_uint16_t -grub_ofconsole_getwh (void) +static void +grub_ofconsole_dimensions (void) { grub_ieee1275_ihandle_t options; - char *val; grub_ssize_t lval; - if (grub_ofconsole_width && grub_ofconsole_height) - return (grub_ofconsole_width << 8) | grub_ofconsole_height; - if (! grub_ieee1275_finddevice ("/options", &options) && options != (grub_ieee1275_ihandle_t) -1) { if (! grub_ieee1275_get_property_length (options, "screen-#columns", - &lval) && lval != -1) + &lval) + && lval >= 0 && lval < 1024) { - val = grub_malloc (lval); - if (val) - { - if (! grub_ieee1275_get_property (options, "screen-#columns", - val, lval, 0)) - grub_ofconsole_width = (grub_uint8_t) grub_strtoul (val, 0, 10); + char val[lval]; - grub_free (val); - } + if (! grub_ieee1275_get_property (options, "screen-#columns", + val, lval, 0)) + grub_ofconsole_width = (grub_uint8_t) grub_strtoul (val, 0, 10); } - if (! grub_ieee1275_get_property_length (options, "screen-#rows", - &lval) && lval != -1) + if (! grub_ieee1275_get_property_length (options, "screen-#rows", &lval) + && lval >= 0 && lval < 1024) { - val = grub_malloc (lval); - if (val) - { - if (! grub_ieee1275_get_property (options, "screen-#rows", - val, lval, 0)) - grub_ofconsole_height = (grub_uint8_t) grub_strtoul (val, 0, 10); - - grub_free (val); - } + char val[lval]; + if (! grub_ieee1275_get_property (options, "screen-#rows", + val, lval, 0)) + grub_ofconsole_height = (grub_uint8_t) grub_strtoul (val, 0, 10); } } @@ -279,21 +364,24 @@ grub_ofconsole_getwh (void) grub_ofconsole_width = 80; if (! grub_ofconsole_height) grub_ofconsole_height = 24; +} +static grub_uint16_t +grub_ofconsole_getwh (void) +{ return (grub_ofconsole_width << 8) | grub_ofconsole_height; } static void grub_ofconsole_gotoxy (grub_uint8_t x, grub_uint8_t y) { - char s[11]; /* 5 + 3 + 3. */ - if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_ANSI)) { + char s[256]; grub_curr_x = x; grub_curr_y = y; - grub_sprintf (s, "\e[%d;%dH", y + 1, x + 1); + grub_snprintf (s, sizeof (s), "\e[%d;%dH", y + 1, x + 1); grub_ofconsole_writeesc (s); } else @@ -318,7 +406,7 @@ grub_ofconsole_cls (void) * ANSI escape sequence. Using video console, Apple Open Firmware (version * 3.1.1) only recognizes the literal ^L. So use both. */ grub_ofconsole_writeesc (" \e[2J"); - grub_gotoxy (0, 0); + grub_ofconsole_gotoxy (0, 0); } static void @@ -345,7 +433,7 @@ grub_ofconsole_init_input (void) if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen, "stdin", &stdin_ihandle, sizeof stdin_ihandle, &actual) || actual != sizeof stdin_ihandle) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Cannot find stdin"); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot find stdin"); return 0; } @@ -354,7 +442,6 @@ static grub_err_t grub_ofconsole_init_output (void) { grub_ssize_t actual; - int col; /* The latest PowerMacs don't actually initialize the screen for us, so we * use this trick to re-open the output device (but we avoid doing this on @@ -365,12 +452,13 @@ grub_ofconsole_init_output (void) if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen, "stdout", &stdout_ihandle, sizeof stdout_ihandle, &actual) || actual != sizeof stdout_ihandle) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Cannot find stdout"); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot find stdout"); /* Initialize colors. */ if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_SET_COLORS)) { - for (col = 0; col < 7; col++) + unsigned col; + for (col = 0; col < ARRAY_SIZE (colors); col++) grub_ieee1275_set_color (stdout_ihandle, col, colors[col].red, colors[col].green, colors[col].blue); @@ -378,6 +466,8 @@ grub_ofconsole_init_output (void) grub_ofconsole_setcolorstate (GRUB_TERM_COLOR_NORMAL); } + grub_ofconsole_dimensions (); + return 0; } @@ -413,8 +503,7 @@ static struct grub_term_output grub_ofconsole_term_output = .setcolor = grub_ofconsole_setcolor, .getcolor = grub_ofconsole_getcolor, .setcursor = grub_ofconsole_setcursor, - .refresh = grub_ofconsole_refresh, - .flags = 0, + .refresh = grub_ofconsole_refresh }; void diff --git a/term/i386/pc/serial.c b/term/serial.c similarity index 88% rename from term/i386/pc/serial.c rename to term/serial.c index 3f1c6d062..2347bb3ee 100644 --- a/term/i386/pc/serial.c +++ b/term/serial.c @@ -17,8 +17,7 @@ */ #include -#include -#include +#include #include #include #include @@ -26,9 +25,10 @@ #include #include #include +#include #define TEXT_WIDTH 80 -#define TEXT_HEIGHT 25 +#define TEXT_HEIGHT 24 static unsigned int xpos, ypos; static unsigned int keep_track = 1; @@ -38,22 +38,24 @@ static unsigned int registered = 0; static char input_buf[8]; static unsigned int npending = 0; +static struct grub_term_output grub_serial_term_output; + /* Argument options. */ static const struct grub_arg_option options[] = { - {"unit", 'u', 0, "Set the serial unit", 0, ARG_TYPE_INT}, - {"port", 'p', 0, "Set the serial port address", 0, ARG_TYPE_STRING}, - {"speed", 's', 0, "Set the serial port speed", 0, ARG_TYPE_INT}, - {"word", 'w', 0, "Set the serial port word length", 0, ARG_TYPE_INT}, - {"parity", 'r', 0, "Set the serial port parity", 0, ARG_TYPE_STRING}, - {"stop", 't', 0, "Set the serial port stop bits", 0, ARG_TYPE_INT}, + {"unit", 'u', 0, N_("Set the serial unit."), 0, ARG_TYPE_INT}, + {"port", 'p', 0, N_("Set the serial port address."), 0, ARG_TYPE_STRING}, + {"speed", 's', 0, N_("Set the serial port speed."), 0, ARG_TYPE_INT}, + {"word", 'w', 0, N_("Set the serial port word length."), 0, ARG_TYPE_INT}, + {"parity", 'r', 0, N_("Set the serial port parity."), 0, ARG_TYPE_STRING}, + {"stop", 't', 0, N_("Set the serial port stop bits."), 0, ARG_TYPE_INT}, {0, 0, 0, 0, 0, 0} }; /* Serial port settings. */ struct serial_port { - unsigned short port; + grub_port_t port; unsigned short divisor; unsigned short word_len; unsigned int parity; @@ -67,12 +69,13 @@ static struct serial_port serial_settings; static const unsigned short *serial_hw_io_addr = (const unsigned short *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR; #define GRUB_SERIAL_PORT_NUM 4 #else -static const unsigned short serial_hw_io_addr[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; +#include +static const grub_port_t serial_hw_io_addr[] = GRUB_MACHINE_SERIAL_PORTS; #define GRUB_SERIAL_PORT_NUM (ARRAY_SIZE(serial_hw_io_addr)) #endif /* Return the port number for the UNITth serial device. */ -static inline unsigned short +static inline grub_port_t serial_hw_get_port (const unsigned int unit) { if (unit < GRUB_SERIAL_PORT_NUM) @@ -148,7 +151,7 @@ serial_translate_key_sequence (void) if (input_buf[0] != '\e' || input_buf[1] != '[') return; - for (i = 0; ARRAY_SIZE (three_code_table); i++) + for (i = 0; i < ARRAY_SIZE (three_code_table); i++) if (three_code_table[i].key == input_buf[2]) { input_buf[0] = three_code_table[i].ascii; @@ -229,7 +232,12 @@ serial_get_divisor (unsigned int speed) /* Set the baud rate. */ for (i = 0; i < sizeof (divisor_tab) / sizeof (divisor_tab[0]); i++) if (divisor_tab[i].speed == speed) + /* UART in Yeeloong runs twice the usual rate. */ +#ifdef GRUB_MACHINE_MIPS_YEELOONG + return 2 * divisor_tab[i].div; +#else return divisor_tab[i].div; +#endif return 0; } @@ -253,6 +261,9 @@ grub_serial_getkey (void) ; c = input_buf[0]; + if (c == 0x7f) + c = GRUB_TERM_BACKSPACE; + grub_memmove (input_buf, input_buf + 1, --npending); return c; @@ -286,11 +297,14 @@ serial_hw_init (void) | serial_settings.stop_bits); grub_outb (status, serial_settings.port + UART_LCR); + /* In Yeeloong serial port has only 3 wires. */ +#ifndef GRUB_MACHINE_MIPS_YEELOONG /* Enable the FIFO. */ grub_outb (UART_ENABLE_FIFO, serial_settings.port + UART_FCR); /* Turn on DTR, RTS, and OUT2. */ grub_outb (UART_ENABLE_MODEM, serial_settings.port + UART_MCR); +#endif /* Drain the input buffer. */ while (grub_serial_checkkey () != -1) @@ -363,7 +377,7 @@ grub_serial_putchar (grub_uint32_t c) break; case '\n': - if (ypos < TEXT_HEIGHT) + if (ypos < TEXT_HEIGHT - 1) ypos++; break; @@ -413,7 +427,7 @@ grub_serial_gotoxy (grub_uint8_t x, grub_uint8_t y) else { keep_track = 0; - grub_terminfo_gotoxy (x, y); + grub_terminfo_gotoxy (x, y, &grub_serial_term_output); keep_track = 1; xpos = x; @@ -425,7 +439,7 @@ static void grub_serial_cls (void) { keep_track = 0; - grub_terminfo_cls (); + grub_terminfo_cls (&grub_serial_term_output); keep_track = 1; xpos = ypos = 0; @@ -439,10 +453,10 @@ grub_serial_setcolorstate (const grub_term_color_state state) { case GRUB_TERM_COLOR_STANDARD: case GRUB_TERM_COLOR_NORMAL: - grub_terminfo_reverse_video_off (); + grub_terminfo_reverse_video_off (&grub_serial_term_output); break; case GRUB_TERM_COLOR_HIGHLIGHT: - grub_terminfo_reverse_video_on (); + grub_terminfo_reverse_video_on (&grub_serial_term_output); break; default: break; @@ -454,9 +468,9 @@ static void grub_serial_setcursor (const int on) { if (on) - grub_terminfo_cursor_on (); + grub_terminfo_cursor_on (&grub_serial_term_output); else - grub_terminfo_cursor_off (); + grub_terminfo_cursor_off (&grub_serial_term_output); } static struct grub_term_input grub_serial_term_input = @@ -498,11 +512,11 @@ grub_cmd_serial (grub_extcmd_t cmd, unit = grub_strtoul (state[0].arg, 0, 0); serial_settings.port = serial_hw_get_port (unit); if (!serial_settings.port) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad unit number."); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad unit number"); } if (state[1].set) - serial_settings.port = (unsigned short) grub_strtoul (state[1].arg, 0, 0); + serial_settings.port = (grub_port_t) grub_strtoul (state[1].arg, 0, 0); if (state[2].set) { @@ -602,12 +616,16 @@ GRUB_MOD_INIT(serial) { cmd = grub_register_extcmd ("serial", grub_cmd_serial, GRUB_COMMAND_FLAG_BOTH, - "serial [OPTIONS...]", - "Configure serial port.", options); + N_("[OPTIONS...]"), + N_("Configure serial port."), options); /* Set default settings. */ serial_settings.port = serial_hw_get_port (0); +#ifdef GRUB_MACHINE_MIPS_YEELOONG + serial_settings.divisor = serial_get_divisor (115200); +#else serial_settings.divisor = serial_get_divisor (9600); +#endif serial_settings.word_len = UART_8BITS_WORD; serial_settings.parity = UART_NO_PARITY; serial_settings.stop_bits = UART_1_STOP_BIT; diff --git a/term/terminfo.c b/term/terminfo.c index 80ae9b100..7402d23db 100644 --- a/term/terminfo.c +++ b/term/terminfo.c @@ -31,6 +31,7 @@ #include #include #include +#include struct terminfo { @@ -103,57 +104,57 @@ grub_terminfo_set_current (const char *str) return grub_errno; } - return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminfo type."); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminfo type"); } /* Wrapper for grub_putchar to write strings. */ static void -putstr (const char *str) +putstr (const char *str, grub_term_output_t oterm) { while (*str) - grub_putchar (*str++); + grub_putcode (*str++, oterm); } /* Move the cursor to the given position starting with "0". */ void -grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y) +grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y, grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.gotoxy, y, x)); + putstr (grub_terminfo_tparm (term.gotoxy, y, x), oterm); } /* Clear the screen. */ void -grub_terminfo_cls (void) +grub_terminfo_cls (grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.cls)); + putstr (grub_terminfo_tparm (term.cls), oterm); } /* Set reverse video mode on. */ void -grub_terminfo_reverse_video_on (void) +grub_terminfo_reverse_video_on (grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.reverse_video_on)); + putstr (grub_terminfo_tparm (term.reverse_video_on), oterm); } /* Set reverse video mode off. */ void -grub_terminfo_reverse_video_off (void) +grub_terminfo_reverse_video_off (grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.reverse_video_off)); + putstr (grub_terminfo_tparm (term.reverse_video_off), oterm); } /* Show cursor. */ void -grub_terminfo_cursor_on (void) +grub_terminfo_cursor_on (grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.cursor_on)); + putstr (grub_terminfo_tparm (term.cursor_on), oterm); } /* Hide cursor. */ void -grub_terminfo_cursor_off (void) +grub_terminfo_cursor_off (grub_term_output_t oterm) { - putstr (grub_terminfo_tparm (term.cursor_off)); + putstr (grub_terminfo_tparm (term.cursor_off), oterm); } /* GRUB Command. */ @@ -168,7 +169,7 @@ grub_cmd_terminfo (grub_command_t cmd __attribute__ ((unused)), return GRUB_ERR_NONE; } else if (argc != 1) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many parameters."); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many parameters"); else return grub_terminfo_set_current (args[0]); } @@ -178,7 +179,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(terminfo) { cmd = grub_register_command ("terminfo", grub_cmd_terminfo, - "terminfo [TERM]", "Set terminfo type."); + N_("[TERM]"), N_("Set terminfo type.")); grub_terminfo_set_current ("vt100"); } diff --git a/term/tparm.c b/term/tparm.c index fa25bd32c..adf0b3a7c 100644 --- a/term/tparm.c +++ b/term/tparm.c @@ -167,7 +167,7 @@ save_text(const char *fmt, const char *s, int len) get_space(s_len + 1); - (void) grub_sprintf(out_buff + out_used, fmt, s); + (void) grub_snprintf(out_buff + out_used, s_len + 1, fmt, s); out_used += grub_strlen(out_buff + out_used); } @@ -179,7 +179,7 @@ save_number(const char *fmt, int number, int len) get_space((unsigned) len + 1); - (void) grub_sprintf(out_buff + out_used, fmt, number); + (void) grub_snprintf(out_buff + out_used, len + 1, fmt, number); out_used += grub_strlen(out_buff + out_used); } diff --git a/tests/example_functional_test.c b/tests/example_functional_test.c new file mode 100644 index 000000000..6802d2d53 --- /dev/null +++ b/tests/example_functional_test.c @@ -0,0 +1,35 @@ +/* + * 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 . + */ + +/* All tests need to include test.h for GRUB testing framework. */ +#include + +/* Functional test main method. */ +static void +example_test (void) +{ + /* Check if 1st argument is true and report with default error message. */ + grub_test_assert (1 == 1); + + /* Check if 1st argument is true and report with custom error message. */ + grub_test_assert (2 == 2, "2 equal 2 expected"); + grub_test_assert (2 != 3, "2 matches %d", 3); +} + +/* Register example_test method as a functional test. */ +GRUB_FUNCTIONAL_TEST ("example_functional_test", example_test); diff --git a/tests/example_grub_script_test.in b/tests/example_grub_script_test.in new file mode 100644 index 000000000..93a90a18e --- /dev/null +++ b/tests/example_grub_script_test.in @@ -0,0 +1,3 @@ +#! @builddir@/grub-shell-tester --modules=echo + +echo "hello world" diff --git a/tests/example_scripted_test.in b/tests/example_scripted_test.in new file mode 100644 index 000000000..9ac0424c0 --- /dev/null +++ b/tests/example_scripted_test.in @@ -0,0 +1,3 @@ +#!/bin/sh -e + +true diff --git a/tests/example_unit_test.c b/tests/example_unit_test.c new file mode 100644 index 000000000..d721a9d0a --- /dev/null +++ b/tests/example_unit_test.c @@ -0,0 +1,38 @@ +/* + * 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 . + */ + +/* Unit tests are normal programs, so they can include C library. */ +#include + +/* All tests need to include test.h for GRUB testing framework. */ +#include + +/* Unit test main method. */ +static void +example_test (void) +{ + /* Check if 1st argument is true and report with default error message. */ + grub_test_assert (1 == 1); + + /* Check if 1st argument is true and report with custom error message. */ + grub_test_assert (2 == 2, "2 equal 2 expected"); + grub_test_assert (2 != 3, "2 matches %d", 3); +} + +/* Register example_test method as a unit test. */ +GRUB_UNIT_TEST ("example_unit_test", example_test); diff --git a/tests/grub_script_blanklines.in b/tests/grub_script_blanklines.in new file mode 100644 index 000000000..71b869bd3 --- /dev/null +++ b/tests/grub_script_blanklines.in @@ -0,0 +1,14 @@ +#! /bin/sh -e + +@builddir@/grub-script-check <. + +echo a###b +echo a# #b + +echo # +echo \# + +echo '#' +echo "#" + +echo '\#' +echo "\#" diff --git a/tests/grub_script_dollar.in b/tests/grub_script_dollar.in new file mode 100644 index 000000000..3819b8bc9 --- /dev/null +++ b/tests/grub_script_dollar.in @@ -0,0 +1,5 @@ +#! /bin/sh -e + +@builddir@/grub-script-check << EOF +echo "\\\$" +EOF diff --git a/tests/grub_script_echo1.in b/tests/grub_script_echo1.in new file mode 100644 index 000000000..048907a76 --- /dev/null +++ b/tests/grub_script_echo1.in @@ -0,0 +1,32 @@ +#! @builddir@/grub-shell-tester + +# Run GRUB script in a Qemu instance +# 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 . + +foo=bar +echo $foo ${foo} +echo "$foo" "${foo}" +echo '$foo' '${foo}' +echo a$foob a${foo}b +echo ab"cd"ef$foo'gh'ij${foo}kl\ mn\"op\'qr\$st\(uv\yz\) + +foo=c +bar=h +echo e"$foo"${bar}o +e"$foo"${bar}o hello world + +foo=echo +$foo 1234 diff --git a/tests/grub_script_echo_keywords.in b/tests/grub_script_echo_keywords.in new file mode 100644 index 000000000..a6383f0e2 --- /dev/null +++ b/tests/grub_script_echo_keywords.in @@ -0,0 +1,3 @@ +#! @builddir@/grub-shell-tester + +echo if then else fi for do done diff --git a/tests/grub_script_final_semicolon.in b/tests/grub_script_final_semicolon.in new file mode 100644 index 000000000..99e55e545 --- /dev/null +++ b/tests/grub_script_final_semicolon.in @@ -0,0 +1,10 @@ +#! /bin/sh -e + +@builddir@/grub-script-check <. + +var=foo +echo $var +echo "$var" +echo ${var} +echo "${var}" + +echo $1 $2 $? + +foo=foo +echo "" $foo + +echo $bar $foo + +bar="" +echo $bar $foo + diff --git a/tests/grub_script_while1.in b/tests/grub_script_while1.in new file mode 100644 index 000000000..554247f76 --- /dev/null +++ b/tests/grub_script_while1.in @@ -0,0 +1,32 @@ +#! @builddir@/grub-shell-tester + +echo one +foo="" +while test "$foo" != "1111"; do foo="${foo}1"; echo "$foo"; done + +echo two +foo="" +while test "$foo" != "aaaa" +do + foo="${foo}a" + echo $foo +done + +foo="" +until test "$foo" = "1111"; do foo="${foo}1"; echo $foo; done +foo="" +until test "$foo" = "aaaa" +do + foo="${foo}a" + echo $foo +done + +# check "$?" in condition gets its value from while body commands +foo="" +false +while test "$?" != "0" +do + echo $foo + foo="${foo}1" + test "$foo" = "111111" +done diff --git a/tests/lib/functional_test.c b/tests/lib/functional_test.c new file mode 100644 index 000000000..8ff08cf8a --- /dev/null +++ b/tests/lib/functional_test.c @@ -0,0 +1,53 @@ +/* + * 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 . + */ + +#include +#include +#include +#include + +static grub_err_t +grub_functional_test (struct grub_extcmd *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + auto int run_test (grub_test_t test); + int run_test (grub_test_t test) + { + grub_test_run (test); + return 0; + } + + grub_list_iterate (GRUB_AS_LIST (grub_test_list), + (grub_list_hook_t) run_test); + return GRUB_ERR_NONE; +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT (functional_test) +{ + cmd = grub_register_extcmd ("functional_test", grub_functional_test, + GRUB_COMMAND_FLAG_CMDLINE, 0, + "Run all functional tests.", 0); +} + +GRUB_MOD_FINI (functional_test) +{ + grub_unregister_extcmd (cmd); +} diff --git a/tests/lib/test.c b/tests/lib/test.c new file mode 100644 index 000000000..b5c054370 --- /dev/null +++ b/tests/lib/test.c @@ -0,0 +1,161 @@ +/* + * 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 . + */ + +#include +#include +#include + +struct grub_test_failure +{ + /* The next failure. */ + struct grub_test_failure *next; + + /* The test source file name. */ + char *file; + + /* The test function name. */ + char *funp; + + /* The test call line number. */ + grub_uint32_t line; + + /* The test failure message. */ + char *message; +}; +typedef struct grub_test_failure *grub_test_failure_t; + +grub_test_t grub_test_list; +static grub_test_failure_t failure_list; + +static void +add_failure (const char *file, + const char *funp, + grub_uint32_t line, const char *fmt, va_list args) +{ + grub_test_failure_t failure; + + failure = (grub_test_failure_t) grub_malloc (sizeof (*failure)); + if (!failure) + return; + + failure->file = grub_strdup (file ? : ""); + failure->funp = grub_strdup (funp ? : ""); + failure->line = line; + failure->message = grub_xvasprintf (fmt, args); + + grub_list_push (GRUB_AS_LIST_P (&failure_list), GRUB_AS_LIST (failure)); +} + +static void +free_failures (void) +{ + grub_test_failure_t item; + + while ((item = grub_list_pop (GRUB_AS_LIST_P (&failure_list))) != 0) + { + if (item->message) + grub_free (item->message); + + if (item->funp) + grub_free (item->funp); + + if (item->file) + grub_free (item->file); + + grub_free (item); + } + failure_list = 0; +} + +void +grub_test_nonzero (int cond, + const char *file, + const char *funp, grub_uint32_t line, const char *fmt, ...) +{ + va_list ap; + + if (cond) + return; + + va_start (ap, fmt); + add_failure (file, funp, line, fmt, ap); + va_end (ap); +} + +void +grub_test_register (const char *name, void (*test_main) (void)) +{ + grub_test_t test; + + test = (grub_test_t) grub_malloc (sizeof (*test)); + if (!test) + return; + + test->name = grub_strdup (name); + test->main = test_main; + + grub_list_push (GRUB_AS_LIST_P (&grub_test_list), GRUB_AS_LIST (test)); +} + +void +grub_test_unregister (const char *name) +{ + grub_test_t test; + + test = (grub_test_t) grub_named_list_find + (GRUB_AS_NAMED_LIST (grub_test_list), name); + + if (test) + { + grub_list_remove (GRUB_AS_LIST_P (&grub_test_list), GRUB_AS_LIST (test)); + + if (test->name) + grub_free (test->name); + + grub_free (test); + } +} + +int +grub_test_run (grub_test_t test) +{ + auto int print_failure (grub_test_failure_t item); + int print_failure (grub_test_failure_t item) + { + grub_test_failure_t failure = (grub_test_failure_t) item; + + grub_printf (" %s:%s:%u: %s\n", + (failure->file ? : ""), + (failure->funp ? : ""), + failure->line, (failure->message ? : "")); + return 0; + } + + test->main (); + + grub_printf ("%s:\n", test->name); + grub_list_iterate (GRUB_AS_LIST (failure_list), + (grub_list_hook_t) print_failure); + if (!failure_list) + grub_printf ("%s: PASS\n", test->name); + else + grub_printf ("%s: FAIL\n", test->name); + + free_failures (); + return GRUB_ERR_NONE; +} diff --git a/tests/lib/unit_test.c b/tests/lib/unit_test.c new file mode 100644 index 000000000..e461150de --- /dev/null +++ b/tests/lib/unit_test.c @@ -0,0 +1,109 @@ +/* + * 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 . + */ + +#include +#include +#include +#include + +#include +#include +#include + +int +main (int argc __attribute__ ((unused)), + char *argv[] __attribute__ ((unused))) +{ + int status = 0; + + extern void grub_unit_test_init (void); + extern void grub_unit_test_fini (void); + + auto int run_test (grub_test_t test); + int run_test (grub_test_t test) + { + status = grub_test_run (test) ? : status; + return 0; + } + + grub_unit_test_init (); + grub_list_iterate (GRUB_AS_LIST (grub_test_list), + (grub_list_hook_t) run_test); + grub_unit_test_fini (); + + exit (status); +} + +/* Other misc. functions necessary for successful linking. */ + +void +grub_free (void *ptr) +{ + free (ptr); +} + +char * +grub_env_get (const char *name __attribute__ ((unused))) +{ + return NULL; +} + +grub_err_t +grub_error (grub_err_t n, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + + return n; +} + +void * +grub_malloc (grub_size_t size) +{ + return malloc (size); +} + +void +grub_refresh (void) +{ + fflush (stdout); +} + +void +grub_putchar (int c) +{ + putchar (c); +} + +int +grub_getkey (void) +{ + return -1; +} + +void +grub_exit (void) +{ + exit (1); +} + +struct grub_handler_class grub_term_input_class; +struct grub_handler_class grub_term_output_class; diff --git a/tests/util/grub-shell-tester.in b/tests/util/grub-shell-tester.in new file mode 100644 index 000000000..e9507c8f5 --- /dev/null +++ b/tests/util/grub-shell-tester.in @@ -0,0 +1,109 @@ +#! /bin/bash -e + +# Compares GRUB script output with BASH output. +# Copyright (C) 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 . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +builddir=@builddir@ +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_TARNAME=@PACKAGE_TARNAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +target_cpu=@target_cpu@ + +# Force build directory components +PATH=${builddir}:$PATH +export PATH + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +# Check the arguments. +for option in "$@"; do + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$0 (GNU GRUB ${PACKAGE_VERSION})" + exit 0 ;; + --modules=*) + ms=`echo "$option" | sed -e 's/--modules=//'` + modules="$modules,$ms" ;; + --qemu-opts=*) + qs=`echo "$option" | sed -e 's/--qemu-opts=//'` + qemuopts="$qemuopts $qs" ;; + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if [ "x${source}" != x ] ; then + echo "too many parameters at the end" 1>&2 + usage + exit 1 + fi + source="${option}" ;; + esac +done + +if [ "x${source}" = x ] ; then + tmpfile=`mktemp` + while read; do + echo $REPLY >> ${tmpfile} + done + source=${tmpfile} +fi + +outfile1=`mktemp` +@builddir@/grub-shell --qemu-opts="${qemuopts}" --modules=${modules} ${source} >${outfile1} + +outfile2=`mktemp` +bash ${source} >${outfile2} + +if ! diff -q ${outfile1} ${outfile2} >/dev/null +then + echo "${source}: GRUB and BASH outputs did not match (see diff -u ${outfile1} ${outfile2})" + status=1 +else + rm -f ${outfile1} ${outfile2} +fi + +exit $status + + diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in new file mode 100644 index 000000000..17da6c8c0 --- /dev/null +++ b/tests/util/grub-shell.in @@ -0,0 +1,146 @@ +#! /bin/bash -e + +# Run GRUB script in a Qemu instance +# Copyright (C) 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 . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +builddir=@builddir@ +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_TARNAME=@PACKAGE_TARNAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +target_cpu=@target_cpu@ + +# Force build directory components +PATH=${builddir}:$PATH +export PATH + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +# Check the arguments. +for option in "$@"; do + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$0 (GNU GRUB ${PACKAGE_VERSION})" + exit 0 ;; + --modules=*) + ms=`echo "$option" | sed -e 's/--modules=//' -e 's/,/ /g'` + modules="$modules $ms" ;; + --qemu-opts=*) + qs=`echo "$option" | sed -e 's/--qemu-opts=//'` + qemuopts="$qemuopts $qs" ;; + --boot=*) + dev=`echo "$option" | sed -e 's/--boot=//'` + if [ "$dev" = "fd" ] ; then bootdev=a; + elif [ "$dev" = "hd" ] ; then bootdev=c; + elif [ "$dev" = "cd" ] ; then bootdev=d; + else + echo "Unrecognized boot method \`$dev'" 1>&2 + usage + exit 1 + fi ;; + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 ;; + *) + if [ "x${source}" != x ] ; then + echo "too many parameters at the end" 1>&2 + usage + exit 1 + fi + source="${option}" ;; + esac +done + +if [ "x${source}" = x ] ; then + tmpfile=`mktemp` + while read; do + echo $REPLY >> ${tmpfile} + done + source=${tmpfile} +fi + +if [ "x${bootdev}" = x ] ; then + bootdev=c # default is boot as disk image +fi + +cfgfile=`mktemp` +cat <${cfgfile} +grubshell=yes +insmod serial +serial +terminal_input serial +terminal_output serial +EOF + +for mod in ${modules} +do + echo "insmod ${mod}" >> ${cfgfile} +done + +cat <>${cfgfile} +source /boot/grub/testcase.cfg +halt +EOF + +isofile=`mktemp` +grub-mkrescue --grub-mkimage=${builddir}/grub-mkimage --output=${isofile} \ + --override-directory=${builddir} \ + /boot/grub/grub.cfg=${cfgfile} /boot/grub/testcase.cfg=${source} \ + >/dev/null 2>&1 + +hdafile=`mktemp` +cp ${isofile} ${hdafile} + +fdafile=`mktemp` +cp ${isofile} ${fdafile} + +outfile=`mktemp` +qemu-system-i386 ${qemuopts} -nographic -hda ${hdafile} -fda ${fdafile} -cdrom ${isofile} -boot ${bootdev} | tr -d "\r" >${outfile} + +cat $outfile + +rm -f ${tmpfile} ${outfile} ${cfgfile} ${isofile} ${hdafile} ${fdafile} +exit 0 + + diff --git a/util/bin2h.c b/util/bin2h.c new file mode 100644 index 000000000..e81ede8c6 --- /dev/null +++ b/util/bin2h.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2008,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 . + */ + +#include +#include +#include + +#define _GNU_SOURCE 1 +#include + +#include "progname.h" + +static struct option options[] = + { + {"help", no_argument, 0, 'h' }, + {"version", no_argument, 0, 'V' }, + {0, 0, 0, 0 } + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, + "Try ``%s --help'' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTIONS] SYMBOL-NAME\n\ +\n\ +Convert a binary file to a C header.\n\ +\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ +\n\ +Report bugs to <%s>.\n\ +", program_name, PACKAGE_BUGREPORT); + + exit (status); +} + +int +main (int argc, char *argv[]) +{ + int b, i; + char *sym; + + set_program_name (argv[0]); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "snm:r:hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + default: + usage (1); + break; + } + } + + if (optind >= argc) + usage (1); + + if (optind + 1 != argc) + usage (1); + + sym = argv[optind]; + + b = getchar (); + if (b == EOF) + goto abort; + + printf ("/* THIS CHUNK OF BYTES IS AUTOMATICALY GENERATED */\n" + "unsigned char %s[] =\n{\n", sym); + + while (1) + { + printf ("0x%02x", b); + + b = getchar (); + if (b == EOF) + goto end; + + for (i = 0; i < 16 - 1; i++) + { + printf (", 0x%02x", b); + + b = getchar (); + if (b == EOF) + goto end; + } + + printf (",\n"); + } + +end: + printf ("\n};\n"); + +abort: + exit (0); +} diff --git a/util/deviceiter.c b/util/deviceiter.c index b0a9e1388..03813bc7d 100644 --- a/util/deviceiter.c +++ b/util/deviceiter.c @@ -31,6 +31,8 @@ #include #include +#include +#include #ifdef __linux__ # if !defined(__GLIBC__) || \ @@ -62,12 +64,23 @@ struct hd_geometry | ((unsigned int) (__dev >> 32) & ~0xfff); \ }) # endif /* ! MAJOR */ +# ifndef MINOR +# define MINOR(dev) \ + ({ \ + unsigned long long __dev = (dev); \ + (unsigned) (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff); \ + }) +# endif /* ! MINOR */ # ifndef CDROM_GET_CAPABILITY # define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */ # endif /* ! CDROM_GET_CAPABILITY */ # ifndef BLKGETSIZE # define BLKGETSIZE _IO(0x12,96) /* return device size */ # endif /* ! BLKGETSIZE */ + +#ifdef HAVE_DEVICE_MAPPER +# include +#endif #endif /* __linux__ */ /* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with @@ -411,6 +424,16 @@ check_device (const char *device) return 1; } +#ifdef __linux__ +# ifdef HAVE_DEVICE_MAPPER +struct dmraid_seen +{ + struct dmraid_seen *next; + const char *name; +}; +# endif /* HAVE_DEVICE_MAPPER */ +#endif /* __linux__ */ + void grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), int floppy_disks) @@ -643,6 +666,123 @@ grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), return; } } + +# ifdef HAVE_DEVICE_MAPPER +# define dmraid_check(cond, ...) \ + if (! (cond)) \ + { \ + grub_dprintf ("deviceiter", __VA_ARGS__); \ + goto dmraid_end; \ + } + + /* DM-RAID. */ + { + struct dm_tree *tree = NULL; + struct dm_task *task = NULL; + struct dm_names *names = NULL; + unsigned int next = 0; + void *top_handle, *second_handle; + struct dm_tree_node *root, *top, *second; + struct dmraid_seen *seen = NULL; + + /* Build DM tree for all devices. */ + tree = dm_tree_create (); + dmraid_check (tree, "dm_tree_create failed\n"); + task = dm_task_create (DM_DEVICE_LIST); + dmraid_check (task, "dm_task_create failed\n"); + dmraid_check (dm_task_run (task), "dm_task_run failed\n"); + names = dm_task_get_names (task); + dmraid_check (names, "dm_task_get_names failed\n"); + dmraid_check (names->dev, "No DM devices found\n"); + do + { + names = (void *) names + next; + dmraid_check (dm_tree_add_dev (tree, MAJOR (names->dev), + MINOR (names->dev)), + "dm_tree_add_dev (%s) failed\n", names->name); + next = names->next; + } + while (next); + + /* Walk the second-level children of the inverted tree; that is, devices + which are directly composed of non-DM devices such as hard disks. + This class includes all DM-RAID disks and excludes all DM-RAID + partitions. */ + root = dm_tree_find_node (tree, 0, 0); + top_handle = NULL; + top = dm_tree_next_child (&top_handle, root, 1); + while (top) + { + second_handle = NULL; + second = dm_tree_next_child (&second_handle, top, 1); + while (second) + { + const char *node_name, *node_uuid; + char *name; + struct dmraid_seen *seen_elt; + + node_name = dm_tree_node_get_name (second); + dmraid_check (node_name, "dm_tree_node_get_name failed\n"); + node_uuid = dm_tree_node_get_uuid (second); + dmraid_check (node_uuid, "dm_tree_node_get_uuid failed\n"); + if (strncmp (node_uuid, "DMRAID-", 7) != 0) + { + grub_dprintf ("deviceiter", "%s is not DM-RAID\n", node_name); + goto dmraid_next_child; + } + + /* Have we already seen this node? There are typically very few + DM-RAID disks, so a list should be fast enough. */ + if (grub_named_list_find (GRUB_AS_NAMED_LIST (seen), node_name)) + { + grub_dprintf ("deviceiter", "Already seen DM device %s\n", + node_name); + goto dmraid_next_child; + } + + name = xasprintf ("/dev/mapper/%s", node_name); + if (check_device (name)) + { + if (hook (name, 0)) + { + free (name); + while (seen) + { + struct dmraid_seen *seen_elt = + grub_list_pop (GRUB_AS_LIST_P (&seen)); + free (seen_elt); + } + if (task) + dm_task_destroy (task); + if (tree) + dm_tree_free (tree); + return; + } + } + free (name); + + seen_elt = xmalloc (sizeof *seen_elt); + seen_elt->name = node_name; + grub_list_push (GRUB_AS_LIST_P (&seen), GRUB_AS_LIST (seen_elt)); + +dmraid_next_child: + second = dm_tree_next_child (&second_handle, top, 1); + } + top = dm_tree_next_child (&top_handle, root, 1); + } + +dmraid_end: + while (seen) + { + struct dmraid_seen *seen_elt = grub_list_pop (GRUB_AS_LIST_P (&seen)); + free (seen_elt); + } + if (task) + dm_task_destroy (task); + if (tree) + dm_tree_free (tree); + } +# endif /* HAVE_DEVICE_MAPPER */ #endif /* __linux__ */ } diff --git a/util/elf/grub-mkimage.c b/util/elf/grub-mkimage.c deleted file mode 100644 index 5750543ad..000000000 --- a/util/elf/grub-mkimage.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2005,2006,2007,2008,2009 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 . - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "progname.h" - -#define GRUB_IEEE1275_NOTE_NAME "PowerPC" -#define GRUB_IEEE1275_NOTE_TYPE 0x1275 - -/* These structures are defined according to the CHRP binding to IEEE1275, - "Client Program Format" section. */ - -struct grub_ieee1275_note_hdr -{ - grub_uint32_t namesz; - grub_uint32_t descsz; - grub_uint32_t type; - char name[sizeof (GRUB_IEEE1275_NOTE_NAME)]; -}; - -struct grub_ieee1275_note_desc -{ - grub_uint32_t real_mode; - grub_uint32_t real_base; - grub_uint32_t real_size; - grub_uint32_t virt_base; - grub_uint32_t virt_size; - grub_uint32_t load_base; -}; - -struct grub_ieee1275_note -{ - struct grub_ieee1275_note_hdr header; - struct grub_ieee1275_note_desc descriptor; -}; - -void -load_note (Elf32_Phdr *phdr, FILE *out) -{ - struct grub_ieee1275_note note; - int note_size = sizeof (struct grub_ieee1275_note); - - grub_util_info ("adding CHRP NOTE segment"); - - note.header.namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME)); - note.header.descsz = grub_host_to_target32 (note_size); - note.header.type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE); - strcpy (note.header.name, GRUB_IEEE1275_NOTE_NAME); - note.descriptor.real_mode = grub_host_to_target32 (0xffffffff); - note.descriptor.real_base = grub_host_to_target32 (0x00c00000); - note.descriptor.real_size = grub_host_to_target32 (0xffffffff); - note.descriptor.virt_base = grub_host_to_target32 (0xffffffff); - note.descriptor.virt_size = grub_host_to_target32 (0xffffffff); - note.descriptor.load_base = grub_host_to_target32 (0x00004000); - - /* Write the note data to the new segment. */ - grub_util_write_image_at (¬e, note_size, - grub_target_to_host32 (phdr->p_offset), out); - - /* Fill in the rest of the segment header. */ - phdr->p_type = grub_host_to_target32 (PT_NOTE); - phdr->p_flags = grub_host_to_target32 (PF_R); - phdr->p_align = grub_host_to_target32 (GRUB_TARGET_SIZEOF_LONG); - phdr->p_vaddr = 0; - phdr->p_paddr = 0; - phdr->p_filesz = grub_host_to_target32 (note_size); - phdr->p_memsz = 0; -} - -void -load_modules (grub_addr_t modbase, Elf32_Phdr *phdr, const char *dir, - char *mods[], FILE *out, char *memdisk_path) -{ - char *module_img; - struct grub_util_path_list *path_list; - struct grub_util_path_list *p; - struct grub_module_info *modinfo; - size_t offset; - size_t total_module_size; - size_t memdisk_size = 0; - - path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); - - offset = sizeof (struct grub_module_info); - total_module_size = sizeof (struct grub_module_info); - - if (memdisk_path) - { - memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); - grub_util_info ("the size of memory disk is 0x%x", memdisk_size); - total_module_size += memdisk_size + sizeof (struct grub_module_header); - } - - for (p = path_list; p; p = p->next) - { - total_module_size += (grub_util_get_image_size (p->name) - + sizeof (struct grub_module_header)); - } - - grub_util_info ("the total module size is 0x%x", total_module_size); - - module_img = xmalloc (total_module_size); - modinfo = (struct grub_module_info *) module_img; - modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC); - modinfo->offset = grub_host_to_target32 (sizeof (struct grub_module_info)); - modinfo->size = grub_host_to_target32 (total_module_size); - - /* Load all the modules, with headers, into module_img. */ - for (p = path_list; p; p = p->next) - { - struct grub_module_header *header; - size_t mod_size; - - grub_util_info ("adding module %s", p->name); - - mod_size = grub_util_get_image_size (p->name); - - header = (struct grub_module_header *) (module_img + offset); - header->type = OBJ_TYPE_ELF; - header->size = grub_host_to_target32 (mod_size + sizeof (*header)); - - grub_util_load_image (p->name, module_img + offset + sizeof (*header)); - - offset += sizeof (*header) + mod_size; - } - - if (memdisk_path) - { - struct grub_module_header *header; - - header = (struct grub_module_header *) (module_img + offset); - header->type = OBJ_TYPE_MEMDISK; - header->size = grub_host_to_target32 (memdisk_size + sizeof (*header)); - offset += sizeof (*header); - - grub_util_load_image (memdisk_path, module_img + offset); - offset += memdisk_size; - } - - - /* Write the module data to the new segment. */ - grub_util_write_image_at (module_img, total_module_size, - grub_host_to_target32 (phdr->p_offset), out); - - /* Fill in the rest of the segment header. */ - phdr->p_type = grub_host_to_target32 (PT_LOAD); - phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); - phdr->p_align = grub_host_to_target32 (GRUB_TARGET_SIZEOF_LONG); - phdr->p_vaddr = grub_host_to_target32 (modbase); - phdr->p_paddr = grub_host_to_target32 (modbase); - phdr->p_filesz = grub_host_to_target32 (total_module_size); - phdr->p_memsz = grub_host_to_target32 (total_module_size); -} - -void -add_segments (char *dir, char *prefix, FILE *out, int chrp, char *mods[], char *memdisk_path) -{ - Elf32_Ehdr ehdr; - Elf32_Phdr *phdrs = NULL; - Elf32_Phdr *phdr; - FILE *in; - char *kernel_path; - grub_addr_t grub_end = 0; - off_t offset, first_segment; - int i, phdr_size; - - /* Read ELF header. */ - kernel_path = grub_util_get_path (dir, "kernel.img"); - in = fopen (kernel_path, "rb"); - if (! in) - grub_util_error ("cannot open %s", kernel_path); - - grub_util_read_at (&ehdr, sizeof (ehdr), 0, in); - - offset = ALIGN_UP (sizeof (ehdr), GRUB_TARGET_SIZEOF_LONG); - ehdr.e_phoff = grub_host_to_target32 (offset); - - phdr_size = (grub_target_to_host16 (ehdr.e_phentsize) * - grub_target_to_host16 (ehdr.e_phnum)); - - if (mods[0] != NULL) - phdr_size += grub_target_to_host16 (ehdr.e_phentsize); - - if (chrp) - phdr_size += grub_target_to_host16 (ehdr.e_phentsize); - - phdrs = xmalloc (phdr_size); - offset += ALIGN_UP (phdr_size, GRUB_TARGET_SIZEOF_LONG); - - first_segment = offset; - - /* Copy all existing segments. */ - for (i = 0; i < grub_target_to_host16 (ehdr.e_phnum); i++) - { - char *segment_img; - grub_size_t segment_end; - - phdr = phdrs + i; - - /* Read segment header. */ - grub_util_read_at (phdr, sizeof (Elf32_Phdr), - (grub_target_to_host32 (ehdr.e_phoff) - + (i * grub_target_to_host16 (ehdr.e_phentsize))), - in); - grub_util_info ("copying segment %d, type %d", i, - grub_target_to_host32 (phdr->p_type)); - - /* Locate _end. */ - segment_end = grub_target_to_host32 (phdr->p_paddr) - + grub_target_to_host32 (phdr->p_memsz); - grub_util_info ("segment %u end 0x%lx", i, segment_end); - if (segment_end > grub_end) - grub_end = segment_end; - - /* Read segment data and write it to new file. */ - segment_img = xmalloc (grub_target_to_host32 (phdr->p_filesz)); - - grub_util_read_at (segment_img, grub_target_to_host32 (phdr->p_filesz), - grub_target_to_host32 (phdr->p_offset), in); - - phdr->p_offset = grub_host_to_target32 (offset); - grub_util_write_image_at (segment_img, grub_target_to_host32 (phdr->p_filesz), - offset, out); - offset += ALIGN_UP (grub_target_to_host32 (phdr->p_filesz), - GRUB_TARGET_SIZEOF_LONG); - - free (segment_img); - } - - if (mods[0] != NULL) - { - grub_addr_t modbase; - - /* Place modules just after grub segment. */ - modbase = ALIGN_UP(grub_end + GRUB_MOD_GAP, GRUB_MOD_ALIGN); - - /* Construct new segment header for modules. */ - phdr = phdrs + grub_target_to_host16 (ehdr.e_phnum); - ehdr.e_phnum = grub_host_to_target16 (grub_target_to_host16 (ehdr.e_phnum) + 1); - - /* Fill in p_offset so the callees know where to write. */ - phdr->p_offset = grub_host_to_target32 (ALIGN_UP (grub_util_get_fp_size (out), - GRUB_TARGET_SIZEOF_LONG)); - - load_modules (modbase, phdr, dir, mods, out, memdisk_path); - } - - if (chrp) - { - /* Construct new segment header for the CHRP note. */ - phdr = phdrs + grub_target_to_host16 (ehdr.e_phnum); - ehdr.e_phnum = grub_host_to_target16 (grub_target_to_host16 (ehdr.e_phnum) + 1); - - /* Fill in p_offset so the callees know where to write. */ - phdr->p_offset = grub_host_to_target32 (ALIGN_UP (grub_util_get_fp_size (out), - GRUB_TARGET_SIZEOF_LONG)); - - load_note (phdr, out); - } - - /* Don't bother preserving the section headers. */ - ehdr.e_shoff = 0; - ehdr.e_shnum = 0; - ehdr.e_shstrndx = 0; - - /* Write entire segment table to the file. */ - grub_util_write_image_at (phdrs, phdr_size, grub_target_to_host32 (ehdr.e_phoff), out); - - /* Write ELF header. */ - grub_util_write_image_at (&ehdr, sizeof (ehdr), 0, out); - - if (prefix) - { - if (GRUB_KERNEL_CPU_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_CPU_DATA_END) - grub_util_error ("prefix too long"); - grub_util_write_image_at (prefix, strlen (prefix) + 1, first_segment + GRUB_KERNEL_CPU_PREFIX, out); - } - - free (phdrs); - free (kernel_path); -} - -static struct option options[] = - { - {"directory", required_argument, 0, 'd'}, - {"prefix", required_argument, 0, 'p'}, - {"memdisk", required_argument, 0, 'm'}, - {"output", required_argument, 0, 'o'}, - {"help", no_argument, 0, 'h'}, - {"note", no_argument, 0, 'n'}, - {"version", no_argument, 0, 'V'}, - {"verbose", no_argument, 0, 'v'}, - { 0, 0, 0, 0 }, - }; - -static void -usage (int status) -{ - if (status) - fprintf (stderr, "Try ``%s --help'' for more information.\n", program_name); - else - printf ("\ -Usage: %s -o FILE [OPTION]... [MODULES]\n\ -\n\ -Make a bootable image of GRUB.\n\ -\n\ - -d, --directory=DIR use images and modules under DIR [default=%s]\n\ - -p, --prefix=DIR set grub_prefix directory\n\ - -m, --memdisk=FILE embed FILE as a memdisk image\n\ - -o, --output=FILE output a generated image to FILE\n\ - -h, --help display this message and exit\n\ - -n, --note add NOTE segment for CHRP Open Firmware\n\ - -V, --version print version information and exit\n\ - -v, --verbose print verbose messages\n\ -\n\ -Report bugs to <%s>.\n\ -", program_name, GRUB_LIBDIR, PACKAGE_BUGREPORT); - - exit (status); -} - -int -main (int argc, char *argv[]) -{ - FILE *fp; - char *output = NULL; - char *dir = NULL; - char *prefix = NULL; - char *memdisk = NULL; - int chrp = 0; - - set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - while (1) - { - int c = getopt_long (argc, argv, "d:p:m:o:hVvn", options, 0); - if (c == -1) - break; - - switch (c) - { - case 'd': - if (dir) - free (dir); - dir = xstrdup (optarg); - break; - case 'p': - if (prefix) - free (prefix); - prefix = xstrdup (optarg); - break; - case 'm': - if (memdisk) - free (memdisk); - memdisk = xstrdup (optarg); - - if (prefix) - free (prefix); - prefix = xstrdup ("(memdisk)/boot/grub"); - - break; - case 'h': - usage (0); - break; - case 'n': - chrp = 1; - break; - case 'o': - if (output) - free (output); - output = xstrdup (optarg); - break; - case 'V': - printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); - return 0; - case 'v': - verbosity++; - break; - default: - usage (1); - break; - } - } - - if (!output) - usage (1); - - fp = fopen (output, "wb"); - if (! fp) - grub_util_error ("cannot open %s", output); - - add_segments (dir ? : GRUB_LIBDIR, prefix, fp, chrp, argv + optind, memdisk); - - fclose (fp); - - return 0; -} diff --git a/util/grub-editenv.c b/util/grub-editenv.c index 68fb23b15..f21042c97 100644 --- a/util/grub-editenv.c +++ b/util/grub-editenv.c @@ -1,7 +1,7 @@ /* grub-editenv.c - tool to edit environment block. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2008,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 @@ -46,9 +46,6 @@ grub_refresh (void) fflush (stdout); } -struct grub_handler_class grub_term_input_class; -struct grub_handler_class grub_term_output_class; - int grub_getkey (void) { @@ -72,10 +69,10 @@ static void usage (int status) { if (status) - fprintf (stderr, "Try ``grub-editenv --help'' for more information.\n"); + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); else printf ("\ -Usage: grub-editenv [OPTIONS] [FILENAME] COMMAND\n\ +Usage: %s [OPTIONS] [FILENAME] COMMAND\n\ \n\ Tool to edit environment block.\n\ \nCommands:\n\ @@ -91,7 +88,7 @@ Tool to edit environment block.\n\ If not given explicitly, FILENAME defaults to %s.\n\ \n\ Report bugs to <%s>.\n", -DEFAULT_DIRECTORY "/" GRUB_ENVBLK_DEFCFG, PACKAGE_BUGREPORT); +program_name, DEFAULT_DIRECTORY "/" GRUB_ENVBLK_DEFCFG, PACKAGE_BUGREPORT); exit (status); } @@ -256,9 +253,8 @@ main (int argc, char *argv[]) char *command; set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + + grub_util_init_nls (); /* Check for options. */ while (1) diff --git a/util/grub-fstest.c b/util/grub-fstest.c index fa54fe414..c03c43451 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -1,7 +1,7 @@ /* grub-fstest.c - debug tool for filesystem driver */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2008,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 @@ -71,7 +71,7 @@ execute_command (char *name, int n, char **args) cmd = grub_command_find (name); if (! cmd) - grub_util_error ("Can\'t find command %s", name); + grub_util_error ("can\'t find command %s", name); return (cmd->func) (cmd, n, args); } @@ -100,9 +100,9 @@ read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len)) dev = grub_device_open (0); if ((! dev) || (! dev->disk)) - grub_util_error ("Can\'t open device."); + grub_util_error ("can\'t open device"); - grub_util_info ("total sectors : %lld.", + grub_util_info ("total sectors : %lld", (unsigned long long) dev->disk->total_sectors); if (! leng) @@ -115,7 +115,7 @@ read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len)) len = (leng > BUF_SIZE) ? BUF_SIZE : leng; if (grub_disk_read (dev->disk, 0, skip, len, buf)) - grub_util_error ("Disk read fails at offset %lld, length %d.", + grub_util_error ("disk read fails at offset %lld, length %d", skip, len); if (hook (skip, buf, len)) @@ -132,15 +132,15 @@ read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len)) file = grub_file_open (pathname); if (!file) { - grub_util_error ("cannot open file %s.", pathname); + grub_util_error ("cannot open file %s", pathname); return; } - grub_util_info ("file size : %lld.", (unsigned long long) file->size); + grub_util_info ("file size : %lld", (unsigned long long) file->size); if (skip > file->size) { - grub_util_error ("invalid skip value %lld.", (unsigned long long) skip); + grub_util_error ("invalid skip value %lld", (unsigned long long) skip); return; } @@ -158,7 +158,7 @@ read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len)) sz = grub_file_read (file, buf, (len > BUF_SIZE) ? BUF_SIZE : len); if (sz < 0) { - grub_util_error ("read error at offset %llu.", ofs); + grub_util_error ("read error at offset %llu", ofs); break; } @@ -184,7 +184,7 @@ cmd_cp (char *src, char *dest) if ((int) fwrite (buf, 1, len, ff) != len) { - grub_util_error ("write error."); + grub_util_error ("write error"); return 1; } @@ -194,7 +194,7 @@ cmd_cp (char *src, char *dest) ff = fopen (dest, "wb"); if (ff == NULL) { - grub_util_error ("open error."); + grub_util_error ("open error"); return; } read_file (src, cp_hook); @@ -212,7 +212,7 @@ cmd_cmp (char *src, char *dest) { if ((int) fread (buf_1, 1, len, ff) != len) { - grub_util_error ("read error at offset %llu.", ofs); + grub_util_error ("read error at offset %llu", ofs); return 1; } @@ -223,7 +223,7 @@ cmd_cmp (char *src, char *dest) for (i = 0; i < len; i++, ofs++) if (buf_1[i] != buf[i]) { - grub_util_error ("compare fail at offset %llu.", ofs); + grub_util_error ("compare fail at offset %llu", ofs); return 1; } } @@ -233,12 +233,12 @@ cmd_cmp (char *src, char *dest) ff = fopen (dest, "rb"); if (ff == NULL) { - grub_util_error ("open error."); + grub_util_error ("open error"); return; } if ((skip) && (fseeko (ff, skip, SEEK_SET))) - grub_util_error ("seek error."); + grub_util_error ("seek error"); read_file (src, cmp_hook); fclose (ff); @@ -278,21 +278,31 @@ cmd_crc (char *pathname) static void fstest (char **images, int num_disks, int cmd, int n, char **args) { - char host_file[128]; - char loop_name[8]; - char *argv[3] = { "-p", loop_name, host_file}; + char *host_file; + char *loop_name; + char *argv[3]; int i; + argv[0] = "-p"; + for (i = 0; i < num_disks; i++) { - if (grub_strlen (images[i]) + 7 > sizeof (host_file)) - grub_util_error ("Pathname %s too long.", images[i]); + loop_name = grub_xasprintf ("loop%d", i); + if (!loop_name) + grub_util_error (grub_errmsg); - grub_sprintf (loop_name, "loop%d", i); - grub_sprintf (host_file, "(host)%s", images[i]); + host_file = grub_xasprintf ("(host)%s", images[i]); + if (!host_file) + grub_util_error (grub_errmsg); + + argv[1] = loop_name; + argv[2] = host_file; if (execute_command ("loopback", 3, argv)) - grub_util_error ("loopback command fails."); + grub_util_error ("loopback command fails"); + + grub_free (loop_name); + grub_free (host_file); } grub_lvm_fini (); @@ -328,8 +338,15 @@ fstest (char **images, int num_disks, int cmd, int n, char **args) for (i = 0; i < num_disks; i++) { - grub_sprintf (loop_name, "loop%d", i); + loop_name = grub_xasprintf ("loop%d", i); + if (!loop_name) + grub_util_error (grub_errmsg); + + argv[1] = loop_name; + execute_command ("loopback", 2, argv); + + grub_free (loop_name); } } @@ -349,7 +366,7 @@ static void usage (int status) { if (status) - fprintf (stderr, "Try ``%s --help'' for more information.\n", program_name); + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); else printf ("\ Usage: %s [OPTION]... IMAGE_PATH COMMANDS\n\ @@ -384,9 +401,8 @@ main (int argc, char *argv[]) int i, cmd, num_opts, image_index, num_disks = 1; set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + + grub_util_init_nls (); /* Find the first non option entry. */ for (num_opts = 1; num_opts < argc; num_opts++) diff --git a/util/grub-install.in b/util/grub-install.in index 4df620812..0db216fd5 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -29,16 +29,16 @@ PACKAGE_TARNAME=@PACKAGE_TARNAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ target_cpu=@target_cpu@ platform=@platform@ +host_os=@host_os@ +font=@datadir@/@PACKAGE_TARNAME@/ascii.pf2 pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` +localedir=@datadir@/locale grub_setup=${sbindir}/`echo grub-setup | sed ${transform}` -if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then - grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` -else - grub_mkimage=${bindir}/`echo grub-mkelfimage | sed ${transform}` -fi +grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}` grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` +grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` rootdir= grub_prefix=`echo /boot/grub | sed ${transform}` modules= @@ -51,6 +51,8 @@ debug=no if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then disk_module=biosdisk +elif [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then + disk_module= else disk_module=ata fi @@ -79,14 +81,21 @@ if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then cat <. EOF @@ -103,6 +112,8 @@ for option in "$@"; do exit 0 ;; --modules=*) modules=`echo "$option" | sed 's/--modules=//'` ;; + --font=*) + font=`echo "$option" | sed 's/--font=//'` ;; --root-directory=*) rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; --grub-setup=*) @@ -144,7 +155,7 @@ done # for make_system_path_relative_to_its_root() . ${libdir}/grub/grub-mkconfig_lib -if test "x$install_device" = x; then +if test "x$install_device" = x && test "${target_cpu}-${platform}" != "mips-yeeloong"; then echo "install_device not specified." 1>&2 usage exit 1 @@ -177,7 +188,7 @@ device_map=${grubdir}/device.map grub_probe="${grub_probe} --device-map=${device_map}" # Check if GRUB is installed. -if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then +if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then set $grub_setup dummy if test -f "$1"; then : @@ -204,8 +215,7 @@ else fi # Create the GRUB directory if it is not present. -test -d "$bootdir" || mkdir "$bootdir" || exit 1 -test -d "$grubdir" || mkdir "$grubdir" || exit 1 +mkdir -p "$grubdir" || exit 1 # If --recheck is specified, remove the device map, if present. if test $recheck = yes; then @@ -239,7 +249,7 @@ done for file in ${pkglibdir}/*.mod ${pkglibdir}/*.lst; do cp -f $file ${grubdir} || exit 1 done -if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then +if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then for file in ${pkglibdir}/*.img ${pkglibdir}/efiemu??.o; do if test -f $file; then cp -f $file ${grubdir} || exit 1 @@ -249,14 +259,18 @@ fi # Copy gettext files mkdir -p ${grubdir}/locale/ -for file in ${grubdir}/locale/*.mo ${pkglibdir}/locale/*.mo; do - if test -f "$file"; then - cp -f "$file" ${grubdir}/locale/ +for dir in ${localedir}/*; do + if test -f "$dir/LC_MESSAGES/grub.mo"; then + cp -f "$dir/LC_MESSAGES/grub.mo" "${grubdir}/locale/${dir##*/}.mo" fi done # Write device to a variable so we don't have to traverse /dev every time. -grub_device=`$grub_probe --target=device ${grubdir}` +grub_device=`$grub_probe --target=device ${grubdir}` || exit 1 + +if ! test -f ${grubdir}/grubenv; then + $grub_editenv ${grubdir}/grubenv create +fi # Create the core image. First, auto-detect the filesystem module. fs_module=`$grub_probe --target=fs --device ${grub_device}` @@ -269,7 +283,10 @@ fi # Then the partition map module. In order to support partition-less media, # this command is allowed to fail (--target=fs already grants us that the # filesystem will be accessible). -partmap_module=`$grub_probe --target=partmap --device ${grub_device} 2> /dev/null` +partmap_module= +for x in `$grub_probe --target=partmap --device ${grub_device} 2> /dev/null`; do + partmap_module="$partmap_module part_$x"; +done # Device abstraction module, if any (lvm, raid). devabstraction_module=`$grub_probe --target=abstraction --device ${grub_device}` @@ -278,17 +295,26 @@ devabstraction_module=`$grub_probe --target=abstraction --device ${grub_device}` modules="$modules $disk_module" modules="$modules $fs_module $partmap_module $devabstraction_module" +relative_grubdir=`make_system_path_relative_to_its_root ${grubdir}` || exit 1 +if [ "x${relative_grubdir}" = "x" ] ; then + relative_grubdir=/ +fi + prefix_drive= +config_opt= + if [ "x${devabstraction_module}" = "x" ] ; then - if echo "${install_device}" | grep -qx "(.*)" ; then - install_drive="${install_device}" - else - install_drive="`$grub_probe --target=drive --device ${install_device}`" + if [ x"${install_device}" != x ]; then + if echo "${install_device}" | grep -qx "(.*)" ; then + install_drive="${install_device}" + else + install_drive="`$grub_probe --target=drive --device ${install_device}`" || exit 1 + fi + install_drive="`echo ${install_drive} | sed -e s/,[0-9]*[a-z]*//g`" fi - grub_drive="`$grub_probe --target=drive --device ${grub_device}`" + grub_drive="`$grub_probe --target=drive --device ${grub_device}`" || exit 1 # Strip partition number - install_drive="`echo ${install_drive} | sed -e s/,[0-9]*[a-z]*//g`" grub_drive="`echo ${grub_drive} | sed -e s/,[0-9]*[a-z]*//g`" if [ "$disk_module" = ata ] ; then # generic method (used on coreboot and ata mod) @@ -297,34 +323,42 @@ if [ "x${devabstraction_module}" = "x" ] ; then echo "UUID needed with ata mod, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 exit 1 fi - prefix_drive="(UUID=${uuid})" - modules="$modules fs_uuid" + echo "search.fs_uuid ${uuid} root " > ${grubdir}/load.cfg + echo 'set prefix=($root)'"${relative_grubdir}" >> ${grubdir}/load.cfg + config_opt="-c ${grubdir}/load.cfg " + modules="$modules search_fs_uuid" elif [ "x${grub_drive}" != "x${install_drive}" ] ; then uuid="`$grub_probe --target=fs_uuid --device ${grub_device}`" if [ "x${uuid}" = "x" ] ; then echo "You attempted a cross-disk install, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 exit 1 fi - prefix_drive="(UUID=${uuid})" - modules="$modules fs_uuid" + echo "search.fs_uuid ${uuid} root " > ${grubdir}/load.cfg + echo 'set prefix=($root)'"${relative_grubdir}" >> ${grubdir}/load.cfg + config_opt="-c ${grubdir}/load.cfg " + modules="$modules search_fs_uuid" fi else - prefix_drive=`$grub_probe --target=drive --device ${grub_device}` + prefix_drive=`$grub_probe --target=drive --device ${grub_device}` || exit 1 fi -relative_grubdir=`make_system_path_relative_to_its_root ${grubdir}` || exit 1 -if [ "x${relative_grubdir}" = "x" ] ; then - relative_grubdir=/ -fi +case "${target_cpu}-${platform}" in + i386-pc) mkimage_target=i386-pc ;; + sparc64-ieee1275) mkimage_target=sparc64-ieee1275-raw ;; + mips-yeeloong) mkimage_target=mipsel-yeeloong-elf ;; + *) mkimage_target=i386-coreboot; +esac -if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then - $grub_mkimage --output=${grubdir}/core.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 +if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then + $grub_mkimage ${config_opt} -O ${mkimage_target} --output=${grubdir}/core.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 # Now perform the installation. $grub_setup ${setup_verbose} ${setup_force} --directory=${grubdir} --device-map=${device_map} \ ${install_device} || exit 1 +elif [ "${target_cpu}-${platform}" = "mips-yeeloong" ] ; then + $grub_mkimage ${config_opt} -f ${font} -d ${pkglibdir} -O ${mkimage_target} --output=/boot/grub.elf --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 else - $grub_mkimage -d ${pkglibdir} --output=/boot/multiboot.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 + $grub_mkimage -O ${mkimage_target} ${config_opt} -d ${pkglibdir} --output=/boot/multiboot.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 fi echo "Installation finished. No error reported." diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in index a8c267518..d1abfa36a 100644 --- a/util/grub-mkconfig.in +++ b/util/grub-mkconfig.in @@ -24,10 +24,10 @@ sbindir=@sbindir@ libdir=@libdir@ sysconfdir=@sysconfdir@ package_version=@PACKAGE_VERSION@ +host_os=@host_os@ datarootdir=@datarootdir@ datadir=@datadir@ pkgdatadir=${datadir}/`echo @PACKAGE_TARNAME@ | sed "${transform}"` -grub_prefix=`echo /boot/grub | sed ${transform}` grub_cfg="" grub_mkconfig_dir=${sysconfdir}/grub.d @@ -50,7 +50,13 @@ EOF } # Check the arguments. +next_grub_cfg=false for option in "$@"; do + if $next_grub_cfg; then + grub_cfg=$option + next_grub_cfg=false + continue + fi case "$option" in -h | --help) usage @@ -59,8 +65,7 @@ for option in "$@"; do echo "$0 (GNU GRUB ${package_version})" exit 0 ;; -o) - shift - grub_cfg=$1 + next_grub_cfg=: ;; --output=*) grub_cfg=`echo "$option" | sed 's/--output=//'` @@ -72,9 +77,26 @@ for option in "$@"; do ;; esac done +if $next_grub_cfg; then + echo "Missing argument to \`-o'" 1>&2 + usage + exit 1 +fi . ${libdir}/grub/grub-mkconfig_lib +case "$host_os" in +netbsd* | openbsd*) + # Because /boot is used for the boot block in NetBSD and OpenBSD, use /grub + # instead of /boot/grub. + grub_prefix=`echo /grub | sed ${transform}` + ;; +*) + # Use /boot/grub by default. + grub_prefix=`echo /boot/grub | sed ${transform}` + ;; +esac + if [ "x$EUID" = "x" ] ; then EUID=`id -u` fi @@ -140,64 +162,73 @@ if [ "x${GRUB_TERMINAL}" != "x" ] ; then GRUB_TERMINAL_OUTPUT="${GRUB_TERMINAL}" fi -case x${GRUB_TERMINAL_OUTPUT} in - x | xgfxterm) - # If this platform supports gfxterm, try to use it. - if test -e ${grub_prefix}/gfxterm.mod ; then - GRUB_VIDEO_BACKEND= - for i in vbe ; do - if test -e ${grub_prefix}/$i.mod ; then - GRUB_VIDEO_BACKEND=$i - break - fi - done - if [ -n "${GRUB_VIDEO_BACKEND}" ] ; then - GRUB_TERMINAL_OUTPUT=gfxterm - elif [ "${GRUB_TERMINAL_OUTPUT}" = "gfxterm" ] ; then - echo "No suitable backend could be found for gfxterm." >&2 ; exit 1 - fi - fi - ;; - xconsole | xserial | xofconsole) ;; - *) echo "Invalid output terminal \"${GRUB_TERMINAL_OUTPUT}\"" >&2 ; exit 1 ;; -esac +termoutdefault=0 +if [ "x${GRUB_TERMINAL_OUTPUT}" = "x" ]; then + GRUB_TERMINAL_OUTPUT=gfxterm; + termoutdefault=1; +fi -# check for terminals that require fonts -case ${GRUB_TERMINAL_OUTPUT} in - gfxterm) - if [ -n "$GRUB_FONT" ] ; then - if is_path_readable_by_grub ${GRUB_FONT} > /dev/null ; then - GRUB_FONT_PATH=${GRUB_FONT} - else - echo "No such font or not readable by grub: ${GRUB_FONT}" >&2 - exit 1 +for x in ${GRUB_TERMINAL_OUTPUT}; do + if [ "x${x}" = "xgfxterm" ]; then + # If this platform supports gfxterm, try to use it. + if ! test -e ${grub_prefix}/gfxterm.mod ; then + if [ "x$termoutdefault" != "x1" ]; then + echo "gfxterm isn't available on your platform" >&2 ; exit 1 + fi + GRUB_TERMINAL_OUTPUT= + break; + fi + # FIXME: this should do something smarter than just loading first + # video backend. + GRUB_VIDEO_BACKEND=$(head -n 1 ${grub_prefix}/video.lst || true) + if [ -z "${GRUB_VIDEO_BACKEND}" ] ; then + if [ "x$termoutdefault" != "x1" ]; then + echo "No suitable backend could be found for gfxterm." >&2 ; exit 1 + fi + GRUB_TERMINAL_OUTPUT= + fi + if [ -n "$GRUB_FONT" ] ; then + if is_path_readable_by_grub ${GRUB_FONT} > /dev/null ; then + GRUB_FONT_PATH=${GRUB_FONT} + else + echo "No such font or not readable by grub: ${GRUB_FONT}" >&2 + exit 1 + fi + else + for dir in ${pkgdatadir} /boot/grub /usr/share/grub ; do + for basename in unicode unifont ascii; do + path="${dir}/${basename}.pf2" + if is_path_readable_by_grub ${path} > /dev/null ; then + GRUB_FONT_PATH=${path} + else + continue + fi + if [ "${basename}" = "ascii" ] ; then + # make sure all our children behave in conformance with ascii.. + export LANG=C + fi + break 2 + done + done + fi + if [ -z "${GRUB_FONT_PATH}" ] ; then + if [ "x$termoutdefault" != "x1" ]; then + echo "No font for gfxterm found." >&2 ; exit 1 + fi + GRUB_TERMINAL_OUTPUT= fi - else - for dir in ${pkgdatadir} /boot/grub /usr/share/grub ; do - for basename in unicode unifont ascii; do - path="${dir}/${basename}.pf2" - if is_path_readable_by_grub ${path} > /dev/null ; then - GRUB_FONT_PATH=${path} - else - continue - fi - if [ "${basename}" = "ascii" ] ; then - # make sure all our children behave in conformance with ascii.. - export LANG=C - fi - break 2 - done - done fi - if [ -z "${GRUB_FONT_PATH}" ] ; then - # fallback to the native terminal for this platform - unset GRUB_TERMINAL_OUTPUT - fi - ;; - *) - # make sure all our children behave in conformance with ascii.. - export LANG=C -esac +done + +for x in ${GRUB_TERMINAL_OUTPUT}; do + case "x${x}" in + xgfxterm) ;; + xconsole | xserial | xofconsole) + # make sure all our children behave in conformance with ascii.. + export LANG=C;; + *) echo "Invalid output terminal \"${GRUB_TERMINAL_OUTPUT}\"" >&2 ; exit 1 ;; + esac +done # These are defined in this script, export them here so that user can # override them. @@ -218,13 +249,21 @@ export GRUB_DEFAULT \ GRUB_DISTRIBUTOR \ GRUB_CMDLINE_LINUX \ GRUB_CMDLINE_LINUX_DEFAULT \ + GRUB_CMDLINE_NETBSD \ + GRUB_CMDLINE_NETBSD_DEFAULT \ GRUB_TERMINAL_INPUT \ GRUB_TERMINAL_OUTPUT \ GRUB_SERIAL_COMMAND \ GRUB_DISABLE_LINUX_UUID \ GRUB_DISABLE_LINUX_RECOVERY \ + GRUB_DISABLE_NETBSD_RECOVERY \ GRUB_GFXMODE \ - GRUB_DISABLE_OS_PROBER + GRUB_BACKGROUND \ + GRUB_THEME \ + GRUB_GFXPAYLOAD_LINUX \ + GRUB_DISABLE_OS_PROBER \ + GRUB_INIT_TUNE \ + GRUB_SAVEDEFAULT if test "x${grub_cfg}" != "x"; then rm -f ${grub_cfg}.new diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in index 8caf4f154..f4674b257 100644 --- a/util/grub-mkconfig_lib.in +++ b/util/grub-mkconfig_lib.in @@ -1,5 +1,5 @@ # Helper library for grub-mkconfig -# Copyright (C) 2007,2008,2009 Free Software Foundation, Inc. +# Copyright (C) 2007,2008,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 @@ -31,6 +31,12 @@ if test "x$grub_mkrelpath" = x; then grub_mkrelpath=${bindir}/`echo grub-mkrelpath | sed ${transform}` fi +if $(which gettext >/dev/null 2>/dev/null) ; then + gettext="gettext" +else + gettext="echo" +fi + grub_warn () { echo "Warning: $@" >&2 @@ -38,21 +44,7 @@ grub_warn () make_system_path_relative_to_its_root () { - path="`${grub_mkrelpath} $1`" - - case "`uname 2>/dev/null`" in - CYGWIN*) - # Cygwin: Check if regular or emulated mount. - if [ -z "$dir" ] || [ "`stat -c %D "$dir/.."`" != 620000 ] ; then - # Reached some mount point not below /cygdrive. - # GRUB does not know Cygwin's emulated mounts, - # convert to Win32 path and remove drive letter. - path=`cygpath -m "$path" | sed -n 's,^[A-Za-z]:,,p'` - test ! -z "$path" || return 1 - fi ;; - esac - - echo "$path" + ${grub_mkrelpath} $1 } is_path_readable_by_grub () @@ -94,13 +86,22 @@ convert_system_path_to_grub_path () echo ${drive}${relative_path} } +save_default_entry () +{ + if [ "x${GRUB_SAVEDEFAULT}" = "xtrue" ] ; then + cat << EOF +savedefault +EOF + fi +} + prepare_grub_to_access_device () { device=$1 # Abstraction modules aren't auto-loaded. abstraction="`${grub_probe} --device ${device} --target=abstraction`" - for module in ${abstraction} ; do + for module in ${abstraction} ; do echo "insmod ${module}" done @@ -111,7 +112,7 @@ prepare_grub_to_access_device () # If there's a filesystem UUID that GRUB is capable of identifying, use it; # otherwise set root as per value in device.map. - echo "set root=`${grub_probe} --device ${device} --target=drive`" + echo "set root='`${grub_probe} --device ${device} --target=drive`'" if fs_uuid="`${grub_probe} --device ${device} --target=fs_uuid 2> /dev/null`" ; then echo "search --no-floppy --fs-uuid --set ${fs_uuid}" fi @@ -179,3 +180,7 @@ version_find_latest () done echo "$a" } + +gettext_quoted () { + $gettext "$@" | sed "s/'/'\\\\''/g" +} diff --git a/util/grub-mkdevicemap.c b/util/grub-mkdevicemap.c index 2b69f905e..db37f99e6 100644 --- a/util/grub-mkdevicemap.c +++ b/util/grub-mkdevicemap.c @@ -1,7 +1,7 @@ /* grub-mkdevicemap.c - make a device map file automatically */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,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 @@ -31,6 +31,7 @@ #include #include +#include #include #define _GNU_SOURCE 1 @@ -38,6 +39,24 @@ #include "progname.h" +void +grub_putchar (int c) +{ + putchar (c); +} + +int +grub_getkey (void) +{ + return -1; +} + +void +grub_refresh (void) +{ + fflush (stdout); +} + static void make_device_map (const char *device_map, int floppy_disks) { @@ -84,7 +103,7 @@ usage (int status) { if (status) fprintf (stderr, - "Try ``%s --help'' for more information.\n", program_name); + "Try `%s --help' for more information.\n", program_name); else printf ("\ Usage: %s [OPTION]...\n\ @@ -112,9 +131,8 @@ main (int argc, char *argv[]) int floppy_disks = 1; set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + + grub_util_init_nls (); /* Check for options. */ while (1) @@ -159,6 +177,9 @@ main (int argc, char *argv[]) } } + if (verbosity > 1) + grub_env_set ("debug", "all"); + make_device_map (dev_map ? : DEFAULT_DEVICE_MAP, floppy_disks); free (dev_map); diff --git a/util/grub-mkfont.c b/util/grub-mkfont.c index 9775e0803..51e2e494c 100644 --- a/util/grub-mkfont.c +++ b/util/grub-mkfont.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 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 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,12 @@ struct grub_glyph_info grub_uint8_t bitmap[0]; }; +enum file_formats +{ + PF2, + ASCII_BITMAPS +}; + #define GRUB_FONT_FLAG_BOLD 1 #define GRUB_FONT_FLAG_NOBITMAP 2 #define GRUB_FONT_FLAG_NOHINTING 4 @@ -59,10 +66,12 @@ struct grub_font_info char* name; int style; int desc; + int asce; int size; int max_width; int max_height; int min_y; + int max_y; int flags; int num_range; grub_uint32_t *ranges; @@ -77,6 +86,7 @@ static struct option options[] = {"range", required_argument, 0, 'r'}, {"size", required_argument, 0, 's'}, {"desc", required_argument, 0, 'd'}, + {"asce", required_argument, 0, 'c'}, {"bold", no_argument, 0, 'b'}, {"no-bitmap", no_argument, 0, 0x100}, {"no-hinting", no_argument, 0, 0x101}, @@ -84,6 +94,7 @@ static struct option options[] = {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, + {"ascii-bitmaps", no_argument, 0, 0x102}, {0, 0, 0, 0} }; @@ -93,17 +104,19 @@ static void usage (int status) { if (status) - fprintf (stderr, "Try ``%s --help'' for more information.\n", program_name); + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); else printf ("\ Usage: %s [OPTIONS] FONT_FILES\n\ \nOptions:\n\ -o, --output=FILE_NAME set output file name\n\ + --ascii-bitmaps save only the ASCII bitmaps\n\ -i, --index=N set face index\n\ -r, --range=A-B[,C-D] set font range\n\ -n, --name=S set font family name\n\ -s, --size=N set font size\n\ -d, --desc=N set font descent\n\ + -c, --asce=N set font ascent\n\ -b, --bold convert to bold font\n\ -a, --force-autohint force autohint\n\ --no-hinting disable hinting\n\ @@ -193,9 +206,12 @@ add_char (struct grub_font_info *font_info, FT_Face face, if (height > font_info->max_height) font_info->max_height = height; - if (glyph_info->y_ofs < font_info->min_y) + if (glyph_info->y_ofs < font_info->min_y && glyph_info->y_ofs > -font_info->size) font_info->min_y = glyph_info->y_ofs; + if (glyph_info->y_ofs + height > font_info->max_y) + font_info->max_y = glyph_info->y_ofs + height; + mask = 0; data = &glyph_info->bitmap[0] - 1; for (j = 0; j < height; j++) @@ -284,8 +300,8 @@ print_glyphs (struct grub_font_info *font_info) xmin = 0; ymax = glyph->y_ofs + glyph->height; - if (ymax < font_info->size - font_info->desc) - ymax = font_info->size - font_info->desc; + if (ymax < font_info->asce) + ymax = font_info->asce; ymin = glyph->y_ofs; if (ymin > - font_info->desc) @@ -316,7 +332,7 @@ print_glyphs (struct grub_font_info *font_info) else if ((x >= 0) && (x < glyph->device_width) && (y >= - font_info->desc) && - (y < font_info->size - font_info->desc)) + (y < font_info->asce)) { line[line_pos++] = ((x == 0) || (y == 0)) ? '+' : '.'; } @@ -330,7 +346,39 @@ print_glyphs (struct grub_font_info *font_info) } void -write_font (struct grub_font_info *font_info, char *output_file) +write_font_ascii_bitmap (struct grub_font_info *font_info, char *output_file) +{ + FILE *file; + struct grub_glyph_info *glyph; + int num; + + file = fopen (output_file, "wb"); + if (! file) + grub_util_error ("Can\'t write to file %s.", output_file); + + int correct_size; + for (glyph = font_info->glyph, num = 0; glyph; glyph = glyph->next, num++) + { + correct_size = 1; + if (glyph->width != 8 || glyph->height != 16) + { + /* printf ("Width or height from glyph U+%04x not supported, skipping.\n", glyph->char_code); */ + correct_size = 0; + } + int row; + for (row = 0; row < glyph->height; row++) + { + if (correct_size) + fwrite (&glyph->bitmap[row], sizeof(glyph->bitmap[row]), 1, file); + else + fwrite (&correct_size, 1, 1, file); + } + } + fclose (file); +} + +void +write_font_pf2 (struct grub_font_info *font_info, char *output_file) { FILE *file; grub_uint32_t leng, data; @@ -340,14 +388,15 @@ write_font (struct grub_font_info *font_info, char *output_file) file = fopen (output_file, "wb"); if (! file) - grub_util_error ("Can\'t write to file %s.", output_file); + grub_util_error ("can\'t write to file %s.", output_file); offset = 0; leng = grub_cpu_to_be32 (4); - grub_util_write_image ("FILE", 4, file); + grub_util_write_image (FONT_FORMAT_SECTION_NAMES_FILE, + sizeof(FONT_FORMAT_SECTION_NAMES_FILE) - 1, file); grub_util_write_image ((char *) &leng, 4, file); - grub_util_write_image ("PFF2", 4, file); + grub_util_write_image (FONT_FORMAT_PFF2_MAGIC, 4, file); offset += 12; if (! font_info->name) @@ -369,20 +418,25 @@ write_font (struct grub_font_info *font_info, char *output_file) font_name = xasprintf ("%s %s %d", font_info->name, &style_name[1], font_info->size); - write_string_section ("NAME", font_name, &offset, file); - write_string_section ("FAMI", font_info->name, &offset, file); - write_string_section ("WEIG", + write_string_section (FONT_FORMAT_SECTION_NAMES_FONT_NAME, + font_name, &offset, file); + write_string_section (FONT_FORMAT_SECTION_NAMES_FAMILY, + font_info->name, &offset, file); + write_string_section (FONT_FORMAT_SECTION_NAMES_WEIGHT, (font_info->style & FT_STYLE_FLAG_BOLD) ? "bold" : "normal", &offset, file); - write_string_section ("SLAN", + write_string_section (FONT_FORMAT_SECTION_NAMES_SLAN, (font_info->style & FT_STYLE_FLAG_ITALIC) ? "italic" : "normal", &offset, file); - write_be16_section ("PTSZ", font_info->size, &offset, file); - write_be16_section ("MAXW", font_info->max_width, &offset, file); - write_be16_section ("MAXH", font_info->max_height, &offset, file); + write_be16_section (FONT_FORMAT_SECTION_NAMES_POINT_SIZE, + font_info->size, &offset, file); + write_be16_section (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH, + font_info->max_width, &offset, file); + write_be16_section (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT, + font_info->max_height, &offset, file); if (! font_info->desc) { @@ -392,15 +446,25 @@ write_font (struct grub_font_info *font_info, char *output_file) font_info->desc = - font_info->min_y; } - write_be16_section ("ASCE", font_info->size - font_info->desc, &offset, file); - write_be16_section ("DESC", font_info->desc, &offset, file); + if (! font_info->asce) + { + if (font_info->max_y <= 0) + font_info->asce = 1; + else + font_info->asce = font_info->max_y; + } + + write_be16_section (FONT_FORMAT_SECTION_NAMES_ASCENT, + font_info->asce, &offset, file); + write_be16_section (FONT_FORMAT_SECTION_NAMES_DESCENT, + font_info->desc, &offset, file); if (font_verbosity > 0) { printf ("Font name: %s\n", font_name); printf ("Max width: %d\n", font_info->max_width); printf ("Max height: %d\n", font_info->max_height); - printf ("Font ascent: %d\n", font_info->size - font_info->desc); + printf ("Font ascent: %d\n", font_info->asce); printf ("Font descent: %d\n", font_info->desc); } @@ -424,7 +488,9 @@ write_font (struct grub_font_info *font_info, char *output_file) printf ("Number of glyph: %d\n", num); leng = grub_cpu_to_be32 (num * 9); - grub_util_write_image ("CHIX", 4, file); + grub_util_write_image (FONT_FORMAT_SECTION_NAMES_CHAR_INDEX, + sizeof(FONT_FORMAT_SECTION_NAMES_CHAR_INDEX) - 1, + file); grub_util_write_image ((char *) &leng, 4, file); offset += 8 + num * 9 + 8; @@ -440,7 +506,8 @@ write_font (struct grub_font_info *font_info, char *output_file) } leng = 0xffffffff; - grub_util_write_image ("DATA", 4, file); + grub_util_write_image (FONT_FORMAT_SECTION_NAMES_DATA, + sizeof(FONT_FORMAT_SECTION_NAMES_DATA) - 1, file); grub_util_write_image ((char *) &leng, 4, file); for (cur = font_info->glyph; cur; cur = cur->next) @@ -458,9 +525,6 @@ write_font (struct grub_font_info *font_info, char *output_file) grub_util_write_image ((char *) &cur->bitmap[0], cur->bitmap_size, file); } - if (font_verbosity > 1) - print_glyphs (font_info); - fclose (file); } @@ -472,13 +536,13 @@ main (int argc, char *argv[]) int font_index = 0; int font_size = 0; char *output_file = NULL; + enum file_formats file_format = PF2; memset (&font_info, 0, sizeof (font_info)); set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + + grub_util_init_nls (); /* Check for options. */ while (1) @@ -532,13 +596,13 @@ main (int argc, char *argv[]) a = strtoul (p, &p, 0); if (*p != '-') - grub_util_error ("Invalid font range"); + grub_util_error ("invalid font range"); b = strtoul (p + 1, &p, 0); if ((font_info.num_range & (GRUB_FONT_RANGE_BLOCK - 1)) == 0) font_info.ranges = xrealloc (font_info.ranges, (font_info.num_range + GRUB_FONT_RANGE_BLOCK) * - sizeof (int) * 2); + sizeof (grub_uint32_t) * 2); font_info.ranges[font_info.num_range * 2] = a; font_info.ranges[font_info.num_range * 2 + 1] = b; @@ -547,7 +611,7 @@ main (int argc, char *argv[]) if (*p) { if (*p != ',') - grub_util_error ("Invalid font range"); + grub_util_error ("invalid font range"); else p++; } @@ -561,6 +625,10 @@ main (int argc, char *argv[]) font_info.desc = strtoul (optarg, NULL, 0); break; + case 'e': + font_info.asce = strtoul (optarg, NULL, 0); + break; + case 'h': usage (0); break; @@ -573,14 +641,35 @@ main (int argc, char *argv[]) font_verbosity++; break; + case 0x102: + file_format = ASCII_BITMAPS; + break; + default: usage (1); break; } } + if (file_format == ASCII_BITMAPS && font_info.num_range > 0) + { + grub_util_error ("Option --ascii-bitmaps doesn't accept ranges (use ASCII)."); + return 1; + } + + else if (file_format == ASCII_BITMAPS) + { + font_info.ranges = xrealloc (font_info.ranges, + GRUB_FONT_RANGE_BLOCK * + sizeof (grub_uint32_t) * 2); + + font_info.ranges[0] = (grub_uint32_t) 0x00; + font_info.ranges[1] = (grub_uint32_t) 0x7f; + font_info.num_range = 1; + } + if (! output_file) - grub_util_error ("No output file is specified."); + grub_util_error ("no output file is specified"); if (FT_Init_FreeType (&ft_lib)) grub_util_error ("FT_Init_FreeType fails"); @@ -592,7 +681,7 @@ main (int argc, char *argv[]) if (FT_New_Face (ft_lib, argv[optind], font_index, &ft_face)) { - grub_util_info ("Can't open file %s, index %d\n", argv[optind], + grub_util_info ("can't open file %s, index %d", argv[optind], font_index); continue; } @@ -620,7 +709,13 @@ main (int argc, char *argv[]) FT_Done_FreeType (ft_lib); - write_font (&font_info, output_file); + if (file_format == PF2) + write_font_pf2 (&font_info, output_file); + else if (file_format == ASCII_BITMAPS) + write_font_ascii_bitmap (&font_info, output_file); + + if (font_verbosity > 1) + print_glyphs (&font_info); return 0; } diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c new file mode 100644 index 000000000..6366a9803 --- /dev/null +++ b/util/grub-mkimage.c @@ -0,0 +1,1364 @@ +/* grub-mkimage.c - make a bootable image */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define _GNU_SOURCE 1 +#include + +#include "progname.h" + +#define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof)) + +#define TARGET_NO_FIELD 0xffffffff +struct image_target_desc +{ + const char *name; + grub_size_t voidp_sizeof; + int bigendian; + enum { + IMAGE_I386_PC, IMAGE_EFI, IMAGE_COREBOOT, + IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_I386_IEEE1275, + IMAGE_YEELOONG_ELF, IMAGE_QEMU, IMAGE_PPC + } id; + enum + { + PLATFORM_FLAGS_NONE = 0, + PLATFORM_FLAGS_LZMA = 1 + } flags; + unsigned prefix; + unsigned data_end; + unsigned raw_size; + unsigned total_module_size; + unsigned kernel_image_size; + unsigned compressed_size; + unsigned link_align; + grub_uint16_t elf_target; + unsigned section_align; + signed vaddr_offset; + unsigned install_dos_part, install_bsd_part; + grub_uint64_t link_addr; + unsigned mod_gap, mod_align; +}; + +struct image_target_desc image_targets[] = + { + { + .name = "i386-coreboot", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_I386_COREBOOT_PREFIX, + .data_end = GRUB_KERNEL_I386_COREBOOT_DATA_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR, + .elf_target = EM_386, + .link_align = 4, + .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN + }, + { + .name = "i386-multiboot", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_I386_COREBOOT_PREFIX, + .data_end = GRUB_KERNEL_I386_COREBOOT_DATA_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR, + .elf_target = EM_386, + .link_align = 4, + .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN + }, + { + .name = "i386-pc", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_PC, + .flags = PLATFORM_FLAGS_LZMA, + .prefix = GRUB_KERNEL_I386_PC_PREFIX, + .data_end = GRUB_KERNEL_I386_PC_DATA_END, + .raw_size = GRUB_KERNEL_I386_PC_RAW_SIZE, + .total_module_size = GRUB_KERNEL_I386_PC_TOTAL_MODULE_SIZE, + .kernel_image_size = GRUB_KERNEL_I386_PC_KERNEL_IMAGE_SIZE, + .compressed_size = GRUB_KERNEL_I386_PC_COMPRESSED_SIZE, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = GRUB_KERNEL_I386_PC_INSTALL_DOS_PART, + .install_bsd_part = GRUB_KERNEL_I386_PC_INSTALL_BSD_PART, + .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR + }, + { + .name = "i386-efi", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_I386_EFI_PREFIX, + .data_end = GRUB_KERNEL_I386_EFI_DATA_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE + + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header) + + sizeof (struct grub_pe32_optional_header) + + 4 * sizeof (struct grub_pe32_section_table), + GRUB_PE32_SECTION_ALIGNMENT), + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + }, + { + .name = "i386-ieee1275", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_IEEE1275, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_I386_IEEE1275_PREFIX, + .data_end = GRUB_KERNEL_I386_IEEE1275_DATA_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_I386_IEEE1275_LINK_ADDR, + .elf_target = EM_386, + .mod_gap = GRUB_KERNEL_I386_IEEE1275_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN, + .link_align = 4, + }, + { + .name = "i386-qemu", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_QEMU, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_I386_QEMU_PREFIX, + .data_end = GRUB_KERNEL_I386_QEMU_DATA_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .kernel_image_size = GRUB_KERNEL_I386_QEMU_KERNEL_IMAGE_SIZE, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_I386_QEMU_LINK_ADDR + }, + { + .name = "x86_64-efi", + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_X86_64_EFI_PREFIX, + .data_end = GRUB_KERNEL_X86_64_EFI_DATA_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE + + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header) + + sizeof (struct grub_pe64_optional_header) + + 4 * sizeof (struct grub_pe32_section_table), + GRUB_PE32_SECTION_ALIGNMENT), + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + }, + { + .name = "mipsel-yeeloong-elf", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_YEELOONG_ELF, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_MIPS_YEELOONG_PREFIX, + .data_end = GRUB_KERNEL_MIPS_YEELOONG_DATA_END, + .raw_size = GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE, + .total_module_size = GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE, + .compressed_size = GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE, + .kernel_image_size = GRUB_KERNEL_MIPS_YEELOONG_KERNEL_IMAGE_SIZE, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_MIPS_YEELOONG_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN + }, + { + .name = "powerpc-ieee1275", + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_PPC, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_POWERPC_IEEE1275_PREFIX, + .data_end = GRUB_KERNEL_POWERPC_IEEE1275_DATA_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR, + .elf_target = EM_PPC, + .mod_gap = GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP, + .mod_align = GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN, + .link_align = 4 + }, + { + .name = "sparc64-ieee1275-raw", + .voidp_sizeof = 8, + .bigendian = 1, + .id = IMAGE_SPARC64_RAW, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX, + .data_end = GRUB_KERNEL_SPARC64_IEEE1275_DATA_END, + .raw_size = GRUB_KERNEL_SPARC64_IEEE1275_RAW_SIZE, + .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, + .kernel_image_size = GRUB_KERNEL_SPARC64_IEEE1275_KERNEL_IMAGE_SIZE, + .compressed_size = GRUB_KERNEL_SPARC64_IEEE1275_COMPRESSED_SIZE, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR + }, + { + .name = "sparc64-ieee1275-aout", + .voidp_sizeof = 8, + .bigendian = 1, + .id = IMAGE_SPARC64_AOUT, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX, + .data_end = GRUB_KERNEL_SPARC64_IEEE1275_DATA_END, + .raw_size = GRUB_KERNEL_SPARC64_IEEE1275_RAW_SIZE, + .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, + .kernel_image_size = GRUB_KERNEL_SPARC64_IEEE1275_KERNEL_IMAGE_SIZE, + .compressed_size = GRUB_KERNEL_SPARC64_IEEE1275_COMPRESSED_SIZE, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR + }, + }; + +#define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x))) +#define grub_host_to_target32(x) (grub_host_to_target32_real (image_target, (x))) +#define grub_target_to_host64(x) (grub_target_to_host64_real (image_target, (x))) +#define grub_host_to_target64(x) (grub_host_to_target64_real (image_target, (x))) +#define grub_host_to_target_addr(x) (grub_host_to_target_addr_real (image_target, (x))) +#define grub_target_to_host16(x) (grub_target_to_host16_real (image_target, (x))) +#define grub_host_to_target16(x) (grub_host_to_target16_real (image_target, (x))) + +static inline grub_uint32_t +grub_target_to_host32_real (struct image_target_desc *image_target, grub_uint32_t in) +{ + if (image_target->bigendian) + return grub_be_to_cpu32 (in); + else + return grub_le_to_cpu32 (in); +} + +static inline grub_uint64_t +grub_target_to_host64_real (struct image_target_desc *image_target, grub_uint64_t in) +{ + if (image_target->bigendian) + return grub_be_to_cpu64 (in); + else + return grub_le_to_cpu64 (in); +} + +static inline grub_uint64_t +grub_host_to_target64_real (struct image_target_desc *image_target, grub_uint64_t in) +{ + if (image_target->bigendian) + return grub_cpu_to_be64 (in); + else + return grub_cpu_to_le64 (in); +} + +static inline grub_uint32_t +grub_host_to_target32_real (struct image_target_desc *image_target, grub_uint32_t in) +{ + if (image_target->bigendian) + return grub_cpu_to_be32 (in); + else + return grub_cpu_to_le32 (in); +} + +static inline grub_uint16_t +grub_target_to_host16_real (struct image_target_desc *image_target, grub_uint16_t in) +{ + if (image_target->bigendian) + return grub_be_to_cpu16 (in); + else + return grub_le_to_cpu16 (in); +} + +static inline grub_uint16_t +grub_host_to_target16_real (struct image_target_desc *image_target, grub_uint16_t in) +{ + if (image_target->bigendian) + return grub_cpu_to_be16 (in); + else + return grub_cpu_to_le16 (in); +} + +static inline grub_uint64_t +grub_host_to_target_addr_real (struct image_target_desc *image_target, grub_uint64_t in) +{ + if (image_target->voidp_sizeof == 8) + return grub_host_to_target64_real (image_target, in); + else + return grub_host_to_target32_real (image_target, in); +} + +static inline grub_uint64_t +grub_target_to_host_real (struct image_target_desc *image_target, grub_uint64_t in) +{ + if (image_target->voidp_sizeof == 8) + return grub_target_to_host64_real (image_target, in); + else + return grub_target_to_host32_real (image_target, in); +} + +#define GRUB_IEEE1275_NOTE_NAME "PowerPC" +#define GRUB_IEEE1275_NOTE_TYPE 0x1275 + +/* These structures are defined according to the CHRP binding to IEEE1275, + "Client Program Format" section. */ + +struct grub_ieee1275_note_hdr +{ + grub_uint32_t namesz; + grub_uint32_t descsz; + grub_uint32_t type; + char name[sizeof (GRUB_IEEE1275_NOTE_NAME)]; +}; + +struct grub_ieee1275_note_desc +{ + grub_uint32_t real_mode; + grub_uint32_t real_base; + grub_uint32_t real_size; + grub_uint32_t virt_base; + grub_uint32_t virt_size; + grub_uint32_t load_base; +}; + +struct grub_ieee1275_note +{ + struct grub_ieee1275_note_hdr header; + struct grub_ieee1275_note_desc descriptor; +}; + +#define grub_target_to_host(val) grub_target_to_host_real(image_target, (val)) + +#include + +static void *SzAlloc(void *p, size_t size) { p = p; return xmalloc(size); } +static void SzFree(void *p, void *address) { p = p; free(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +static void +compress_kernel_lzma (char *kernel_img, size_t kernel_size, + char **core_img, size_t *core_size, size_t raw_size) +{ + CLzmaEncProps props; + unsigned char out_props[5]; + size_t out_props_size = 5; + + LzmaEncProps_Init(&props); + props.dictSize = 1 << 16; + props.lc = 3; + props.lp = 0; + props.pb = 2; + props.numThreads = 1; + + if (kernel_size < raw_size) + grub_util_error (_("the core image is too small")); + + *core_img = xmalloc (kernel_size); + memcpy (*core_img, kernel_img, raw_size); + + *core_size = kernel_size - raw_size; + if (LzmaEncode ((unsigned char *) *core_img + raw_size, core_size, + (unsigned char *) kernel_img + raw_size, + kernel_size - raw_size, + &props, out_props, &out_props_size, + 0, NULL, &g_Alloc, &g_Alloc) != SZ_OK) + grub_util_error (_("cannot compress the kernel image")); + + *core_size += raw_size; +} + +static void +compress_kernel (struct image_target_desc *image_target, char *kernel_img, + size_t kernel_size, char **core_img, size_t *core_size) +{ + if (image_target->flags & PLATFORM_FLAGS_LZMA) + { + compress_kernel_lzma (kernel_img, kernel_size, core_img, + core_size, image_target->raw_size); + return; + } + + *core_img = xmalloc (kernel_size); + memcpy (*core_img, kernel_img, kernel_size); + *core_size = kernel_size; +} + +struct fixup_block_list +{ + struct fixup_block_list *next; + int state; + struct grub_pe32_fixup_block b; +}; + +#define MKIMAGE_ELF32 1 +#include "grub-mkimagexx.c" +#undef MKIMAGE_ELF32 + +#define MKIMAGE_ELF64 1 +#include "grub-mkimagexx.c" +#undef MKIMAGE_ELF64 + +static void +generate_image (const char *dir, char *prefix, FILE *out, char *mods[], + char *memdisk_path, char *font_path, char *config_path, + struct image_target_desc *image_target, int note) +{ + char *kernel_img, *core_img; + size_t kernel_size, total_module_size, core_size, exec_size; + size_t memdisk_size = 0, font_size = 0, config_size = 0, config_size_pure = 0; + char *kernel_path; + size_t offset; + struct grub_util_path_list *path_list, *p, *next; + grub_size_t bss_size; + grub_uint64_t start_address; + void *rel_section; + grub_size_t reloc_size, align; + path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); + + kernel_path = grub_util_get_path (dir, "kernel.img"); + + if (image_target->voidp_sizeof == 8) + total_module_size = sizeof (struct grub_module_info64); + else + total_module_size = sizeof (struct grub_module_info32); + + if (memdisk_path) + { + memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); + grub_util_info ("the size of memory disk is 0x%x", memdisk_size); + total_module_size += memdisk_size + sizeof (struct grub_module_header); + } + + if (font_path) + { + font_size = ALIGN_ADDR (grub_util_get_image_size (font_path)); + total_module_size += font_size + sizeof (struct grub_module_header); + } + + if (config_path) + { + config_size_pure = grub_util_get_image_size (config_path) + 1; + config_size = ALIGN_ADDR (config_size_pure); + grub_util_info ("the size of config file is 0x%x", config_size); + total_module_size += config_size + sizeof (struct grub_module_header); + } + + for (p = path_list; p; p = p->next) + total_module_size += (ALIGN_ADDR (grub_util_get_image_size (p->name)) + + sizeof (struct grub_module_header)); + + grub_util_info ("the total module size is 0x%x", total_module_size); + + if (image_target->voidp_sizeof == 4) + kernel_img = load_image32 (kernel_path, &exec_size, &kernel_size, &bss_size, + total_module_size, &start_address, &rel_section, + &reloc_size, &align, image_target); + else + kernel_img = load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size, + total_module_size, &start_address, &rel_section, + &reloc_size, &align, image_target); + + if (image_target->prefix + strlen (prefix) + 1 > image_target->data_end) + grub_util_error (_("prefix is too long")); + strcpy (kernel_img + image_target->prefix, prefix); + + if (image_target->voidp_sizeof == 8) + { + /* Fill in the grub_module_info structure. */ + struct grub_module_info64 *modinfo; + modinfo = (struct grub_module_info64 *) (kernel_img + kernel_size); + memset (modinfo, 0, sizeof (struct grub_module_info64)); + modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC); + modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info64)); + modinfo->size = grub_host_to_target_addr (total_module_size); + offset = kernel_size + sizeof (struct grub_module_info64); + } + else + { + /* Fill in the grub_module_info structure. */ + struct grub_module_info32 *modinfo; + modinfo = (struct grub_module_info32 *) (kernel_img + kernel_size); + memset (modinfo, 0, sizeof (struct grub_module_info32)); + modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC); + modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info32)); + modinfo->size = grub_host_to_target_addr (total_module_size); + offset = kernel_size + sizeof (struct grub_module_info32); + } + + for (p = path_list; p; p = p->next) + { + struct grub_module_header *header; + size_t mod_size, orig_size; + + orig_size = grub_util_get_image_size (p->name); + mod_size = ALIGN_ADDR (orig_size); + + header = (struct grub_module_header *) (kernel_img + offset); + memset (header, 0, sizeof (struct grub_module_header)); + header->type = grub_host_to_target32 (OBJ_TYPE_ELF); + header->size = grub_host_to_target32 (mod_size + sizeof (*header)); + offset += sizeof (*header); + memset (kernel_img + offset + orig_size, 0, mod_size - orig_size); + + grub_util_load_image (p->name, kernel_img + offset); + offset += mod_size; + } + + if (memdisk_path) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + memset (header, 0, sizeof (struct grub_module_header)); + header->type = grub_host_to_target32 (OBJ_TYPE_MEMDISK); + header->size = grub_host_to_target32 (memdisk_size + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (memdisk_path, kernel_img + offset); + offset += memdisk_size; + } + + if (font_path) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + memset (header, 0, sizeof (struct grub_module_header)); + header->type = grub_host_to_target32 (OBJ_TYPE_FONT); + header->size = grub_host_to_target32 (font_size + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (font_path, kernel_img + offset); + offset += font_size; + } + + if (config_path) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + memset (header, 0, sizeof (struct grub_module_header)); + header->type = grub_host_to_target32 (OBJ_TYPE_CONFIG); + header->size = grub_host_to_target32 (config_size + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (config_path, kernel_img + offset); + *(kernel_img + offset + config_size_pure - 1) = 0; + offset += config_size; + } + + grub_util_info ("kernel_img=%p, kernel_size=0x%x", kernel_img, kernel_size); + compress_kernel (image_target, kernel_img, kernel_size + total_module_size, + &core_img, &core_size); + + grub_util_info ("the core size is 0x%x", core_size); + + if (image_target->total_module_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (core_img + image_target->total_module_size)) + = grub_host_to_target32 (total_module_size); + if (image_target->kernel_image_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (core_img + image_target->kernel_image_size)) + = grub_host_to_target32 (kernel_size); + if (image_target->compressed_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (core_img + image_target->compressed_size)) + = grub_host_to_target32 (core_size - image_target->raw_size); + + /* If we included a drive in our prefix, let GRUB know it doesn't have to + prepend the drive told by BIOS. */ + if (image_target->install_dos_part != TARGET_NO_FIELD + && image_target->install_bsd_part != TARGET_NO_FIELD && prefix[0] == '(') + { + *((grub_int32_t *) (core_img + image_target->install_dos_part)) + = grub_host_to_target32 (-2); + *((grub_int32_t *) (core_img + image_target->install_bsd_part)) + = grub_host_to_target32 (-2); + } + + switch (image_target->id) + { + case IMAGE_I386_PC: + { + unsigned num; + char *boot_path, *boot_img; + size_t boot_size; + + if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > GRUB_MEMORY_I386_PC_UPPER) + grub_util_error (_("core image is too big (%p > %p)"), + GRUB_KERNEL_I386_PC_LINK_ADDR + core_size, + GRUB_MEMORY_I386_PC_UPPER); + + num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); + if (num > 0xffff) + grub_util_error (_("the core image is too big")); + + boot_path = grub_util_get_path (dir, "diskboot.img"); + boot_size = grub_util_get_image_size (boot_path); + if (boot_size != GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("diskboot.img size must be %u bytes"), + GRUB_DISK_SECTOR_SIZE); + + boot_img = grub_util_read_image (boot_path); + + { + struct grub_pc_bios_boot_blocklist *block; + block = (struct grub_pc_bios_boot_blocklist *) (boot_img + + GRUB_DISK_SECTOR_SIZE + - sizeof (*block)); + block->len = grub_host_to_target16 (num); + + /* This is filled elsewhere. Verify it just in case. */ + assert (block->segment + == grub_host_to_target16 (GRUB_BOOT_I386_PC_KERNEL_SEG + + (GRUB_DISK_SECTOR_SIZE >> 4))); + } + + grub_util_write_image (boot_img, boot_size, out); + free (boot_img); + free (boot_path); + } + break; + case IMAGE_EFI: + { + void *pe_img; + grub_uint8_t *header; + void *sections; + size_t pe_size; + struct grub_pe32_coff_header *c; + struct grub_pe32_section_table *text_section, *data_section; + struct grub_pe32_section_table *mods_section, *reloc_section; + static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; + int header_size; + int reloc_addr; + + if (image_target->voidp_sizeof == 4) + header_size = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE + + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header) + + sizeof (struct grub_pe32_optional_header) + + 4 * sizeof (struct grub_pe32_section_table), + GRUB_PE32_SECTION_ALIGNMENT); + else + header_size = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE + + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header) + + sizeof (struct grub_pe64_optional_header) + + 4 * sizeof (struct grub_pe32_section_table), + GRUB_PE32_SECTION_ALIGNMENT); + + reloc_addr = ALIGN_UP (header_size + core_size, + image_target->section_align); + + pe_size = ALIGN_UP (reloc_addr + reloc_size, + image_target->section_align); + pe_img = xmalloc (reloc_addr + reloc_size); + memset (pe_img, 0, header_size); + memcpy (pe_img + header_size, core_img, core_size); + memcpy (pe_img + reloc_addr, rel_section, reloc_size); + header = pe_img; + + /* The magic. */ + memcpy (header, stub, GRUB_PE32_MSDOS_STUB_SIZE); + memcpy (header + GRUB_PE32_MSDOS_STUB_SIZE, "PE\0\0", + GRUB_PE32_SIGNATURE_SIZE); + + /* The COFF file header. */ + c = (struct grub_pe32_coff_header *) (header + GRUB_PE32_MSDOS_STUB_SIZE + + GRUB_PE32_SIGNATURE_SIZE); + if (image_target->voidp_sizeof == 4) + c->machine = grub_host_to_target16 (GRUB_PE32_MACHINE_I386); + else + c->machine = grub_host_to_target16 (GRUB_PE32_MACHINE_X86_64); + + c->num_sections = grub_host_to_target16 (4); + c->time = grub_host_to_target32 (time (0)); + c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE + | GRUB_PE32_LINE_NUMS_STRIPPED + | ((image_target->voidp_sizeof == 4) + ? GRUB_PE32_32BIT_MACHINE + : 0) + | GRUB_PE32_LOCAL_SYMS_STRIPPED + | GRUB_PE32_DEBUG_STRIPPED); + + /* The PE Optional header. */ + if (image_target->voidp_sizeof == 4) + { + struct grub_pe32_optional_header *o; + + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe32_optional_header)); + + o = (struct grub_pe32_optional_header *) + (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header)); + o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); + o->code_size = grub_host_to_target32 (exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size + - header_size); + o->bss_size = grub_cpu_to_le32 (bss_size); + o->entry_addr = grub_cpu_to_le32 (start_address); + o->code_base = grub_cpu_to_le32 (header_size); + + o->data_base = grub_host_to_target32 (header_size + exec_size); + + o->image_base = 0; + o->section_alignment = grub_host_to_target32 (image_target->section_align); + o->file_alignment = grub_host_to_target32 (image_target->section_align); + o->image_size = grub_host_to_target32 (pe_size); + o->header_size = grub_host_to_target32 (header_size); + o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); + + /* Do these really matter? */ + o->stack_reserve_size = grub_host_to_target32 (0x10000); + o->stack_commit_size = grub_host_to_target32 (0x10000); + o->heap_reserve_size = grub_host_to_target32 (0x10000); + o->heap_commit_size = grub_host_to_target32 (0x10000); + + o->num_data_directories = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); + + o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); + o->base_relocation_table.size = grub_host_to_target32 (reloc_size); + sections = o + 1; + } + else + { + struct grub_pe64_optional_header *o; + + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header)); + + o = (struct grub_pe64_optional_header *) + (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header)); + o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); + o->code_size = grub_host_to_target32 (exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size + - header_size); + o->bss_size = grub_cpu_to_le32 (bss_size); + o->entry_addr = grub_cpu_to_le32 (start_address); + o->code_base = grub_cpu_to_le32 (header_size); + o->image_base = 0; + o->section_alignment = grub_host_to_target32 (image_target->section_align); + o->file_alignment = grub_host_to_target32 (image_target->section_align); + o->image_size = grub_host_to_target32 (pe_size); + o->header_size = grub_host_to_target32 (header_size); + o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); + + /* Do these really matter? */ + o->stack_reserve_size = grub_host_to_target32 (0x10000); + o->stack_commit_size = grub_host_to_target32 (0x10000); + o->heap_reserve_size = grub_host_to_target32 (0x10000); + o->heap_commit_size = grub_host_to_target32 (0x10000); + + o->num_data_directories + = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); + + o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); + o->base_relocation_table.size = grub_host_to_target32 (reloc_size); + sections = o + 1; + } + /* The sections. */ + text_section = sections; + strcpy (text_section->name, ".text"); + text_section->virtual_size = grub_cpu_to_le32 (exec_size); + text_section->virtual_address = grub_cpu_to_le32 (header_size); + text_section->raw_data_size = grub_cpu_to_le32 (exec_size); + text_section->raw_data_offset = grub_cpu_to_le32 (header_size); + text_section->characteristics = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_CODE + | GRUB_PE32_SCN_MEM_EXECUTE + | GRUB_PE32_SCN_MEM_READ); + + data_section = text_section + 1; + strcpy (data_section->name, ".data"); + data_section->virtual_size = grub_cpu_to_le32 (kernel_size - exec_size); + data_section->virtual_address = grub_cpu_to_le32 (header_size + exec_size); + data_section->raw_data_size = grub_cpu_to_le32 (kernel_size - exec_size); + data_section->raw_data_offset = grub_cpu_to_le32 (header_size + exec_size); + data_section->characteristics + = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE); + +#if 0 + bss_section = data_section + 1; + strcpy (bss_section->name, ".bss"); + bss_section->virtual_size = grub_cpu_to_le32 (bss_size); + bss_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size); + bss_section->raw_data_size = 0; + bss_section->raw_data_offset = 0; + bss_section->characteristics + = grub_cpu_to_le32 (GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE + | GRUB_PE32_SCN_ALIGN_64BYTES + | GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | 0x80); +#endif + + mods_section = data_section + 1; + strcpy (mods_section->name, "mods"); + mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size); + mods_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size + bss_size); + mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size); + mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + kernel_size); + mods_section->characteristics + = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE); + + reloc_section = mods_section + 1; + strcpy (reloc_section->name, ".reloc"); + reloc_section->virtual_size = grub_cpu_to_le32 (reloc_size); + reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + bss_size); + reloc_section->raw_data_size = grub_cpu_to_le32 (reloc_size); + reloc_section->raw_data_offset = grub_cpu_to_le32 (reloc_addr); + reloc_section->characteristics + = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_DISCARDABLE + | GRUB_PE32_SCN_MEM_READ); + free (core_img); + core_img = pe_img; + core_size = pe_size; + } + break; + case IMAGE_QEMU: + { + char *rom_img; + size_t rom_size; + char *boot_path, *boot_img; + size_t boot_size; + + boot_path = grub_util_get_path (dir, "boot.img"); + boot_size = grub_util_get_image_size (boot_path); + boot_img = grub_util_read_image (boot_path); + + /* Rom sizes must be 64k-aligned. */ + rom_size = ALIGN_UP (core_size + boot_size, 64 * 1024); + + rom_img = xmalloc (rom_size); + memset (rom_img, 0, rom_size); + + *((grub_int32_t *) (core_img + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR)) + = grub_host_to_target32 ((grub_uint32_t) -rom_size); + + memcpy (rom_img, core_img, core_size); + + *((grub_int32_t *) (boot_img + GRUB_BOOT_I386_QEMU_CORE_ENTRY_ADDR)) + = grub_host_to_target32 ((grub_uint32_t) -rom_size); + + memcpy (rom_img + rom_size - boot_size, boot_img, boot_size); + + free (core_img); + core_img = rom_img; + core_size = rom_size; + + free (boot_img); + free (boot_path); + } + break; + case IMAGE_SPARC64_AOUT: + { + void *aout_img; + size_t aout_size; + struct grub_aout32_header *aout_head; + + aout_size = core_size + sizeof (*aout_head); + aout_img = xmalloc (aout_size); + aout_head = aout_img; + aout_head->a_midmag = grub_host_to_target32 ((AOUT_MID_SUN << 16) + | AOUT32_OMAGIC); + aout_head->a_text = grub_host_to_target32 (core_size); + aout_head->a_entry + = grub_host_to_target32 (GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS); + memcpy (aout_img + sizeof (*aout_head), core_img, core_size); + + free (core_img); + core_img = aout_img; + core_size = aout_size; + } + break; + case IMAGE_SPARC64_RAW: + { + unsigned int num; + char *boot_path, *boot_img; + size_t boot_size; + + num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); + num <<= GRUB_DISK_SECTOR_BITS; + + boot_path = grub_util_get_path (dir, "diskboot.img"); + boot_size = grub_util_get_image_size (boot_path); + if (boot_size != GRUB_DISK_SECTOR_SIZE) + grub_util_error ("diskboot.img is not one sector size"); + + boot_img = grub_util_read_image (boot_path); + + *((grub_uint32_t *) (boot_img + GRUB_DISK_SECTOR_SIZE + - GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE + 8)) + = grub_host_to_target32 (num); + + grub_util_write_image (boot_img, boot_size, out); + free (boot_img); + free (boot_path); + } + break; + case IMAGE_YEELOONG_ELF: + case IMAGE_PPC: + case IMAGE_COREBOOT: + case IMAGE_I386_IEEE1275: + { + char *elf_img; + size_t program_size; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + grub_uint32_t target_addr; + int header_size, footer_size = 0; + int phnum = 1; + + if (image_target->id != IMAGE_YEELOONG_ELF) + phnum += 2; + + if (note) + { + phnum++; + footer_size += sizeof (struct grub_ieee1275_note); + } + header_size = ALIGN_ADDR (sizeof (*ehdr) + phnum * sizeof (*phdr)); + + program_size = ALIGN_ADDR (core_size); + + elf_img = xmalloc (program_size + header_size + footer_size); + memset (elf_img, 0, program_size + header_size); + memcpy (elf_img + header_size, core_img, core_size); + ehdr = (void *) elf_img; + phdr = (void *) (elf_img + sizeof (*ehdr)); + memcpy (ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = ELFCLASS32; + if (!image_target->bigendian) + ehdr->e_ident[EI_DATA] = ELFDATA2LSB; + else + ehdr->e_ident[EI_DATA] = ELFDATA2MSB; + ehdr->e_ident[EI_VERSION] = EV_CURRENT; + ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE; + ehdr->e_type = grub_host_to_target16 (ET_EXEC); + ehdr->e_machine = grub_host_to_target16 (image_target->elf_target); + ehdr->e_version = grub_host_to_target32 (EV_CURRENT); + + ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr); + ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr)); + ehdr->e_phnum = grub_host_to_target16 (phnum); + + /* No section headers. */ + ehdr->e_shoff = grub_host_to_target32 (0); + if (image_target->id == IMAGE_YEELOONG_ELF) + ehdr->e_shentsize = grub_host_to_target16 (0); + else + ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf32_Shdr)); + ehdr->e_shnum = grub_host_to_target16 (0); + ehdr->e_shstrndx = grub_host_to_target16 (0); + + ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr)); + + phdr->p_type = grub_host_to_target32 (PT_LOAD); + phdr->p_offset = grub_host_to_target32 (header_size); + phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); + + if (image_target->id == IMAGE_YEELOONG_ELF) + target_addr = ALIGN_UP (image_target->link_addr + + kernel_size + total_module_size, 32); + else + target_addr = image_target->link_addr; + ehdr->e_entry = grub_host_to_target32 (target_addr); + phdr->p_vaddr = grub_host_to_target32 (target_addr); + phdr->p_paddr = grub_host_to_target32 (target_addr); + phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align); + if (image_target->id == IMAGE_YEELOONG_ELF) + ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER + | EF_MIPS_PIC | EF_MIPS_CPIC); + else + ehdr->e_flags = 0; + if (image_target->id == IMAGE_YEELOONG_ELF) + { + phdr->p_filesz = grub_host_to_target32 (core_size); + phdr->p_memsz = grub_host_to_target32 (core_size); + } + else + { + grub_uint32_t target_addr_mods; + phdr->p_filesz = grub_host_to_target32 (kernel_size); + phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_GNU_STACK); + phdr->p_offset = grub_host_to_target32 (header_size + kernel_size); + phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0; + phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); + phdr->p_align = grub_host_to_target32 (image_target->link_align); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_LOAD); + phdr->p_offset = grub_host_to_target32 (header_size + kernel_size); + phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); + phdr->p_filesz = phdr->p_memsz + = grub_host_to_target32 (core_size - kernel_size); + + target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size + + image_target->mod_gap, + image_target->mod_align); + phdr->p_vaddr = grub_host_to_target32 (target_addr_mods); + phdr->p_paddr = grub_host_to_target32 (target_addr_mods); + phdr->p_align = grub_host_to_target32 (image_target->link_align); + } + + if (note) + { + int note_size = sizeof (struct grub_ieee1275_note); + struct grub_ieee1275_note *note = (struct grub_ieee1275_note *) + (elf_img + program_size + header_size); + + grub_util_info ("adding CHRP NOTE segment"); + + note->header.namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME)); + note->header.descsz = grub_host_to_target32 (note_size); + note->header.type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE); + strcpy (note->header.name, GRUB_IEEE1275_NOTE_NAME); + note->descriptor.real_mode = grub_host_to_target32 (0xffffffff); + note->descriptor.real_base = grub_host_to_target32 (0x00c00000); + note->descriptor.real_size = grub_host_to_target32 (0xffffffff); + note->descriptor.virt_base = grub_host_to_target32 (0xffffffff); + note->descriptor.virt_size = grub_host_to_target32 (0xffffffff); + note->descriptor.load_base = grub_host_to_target32 (0x00004000); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_NOTE); + phdr->p_flags = grub_host_to_target32 (PF_R); + phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); + phdr->p_vaddr = 0; + phdr->p_paddr = 0; + phdr->p_filesz = grub_host_to_target32 (note_size); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); + } + + free (core_img); + core_img = elf_img; + core_size = program_size + header_size + footer_size; + } + break; + } + + grub_util_write_image (core_img, core_size, out); + free (kernel_img); + free (core_img); + free (kernel_path); + + while (path_list) + { + next = path_list->next; + free ((void *) path_list->name); + free (path_list); + path_list = next; + } +} + + + +static struct option options[] = + { + {"directory", required_argument, 0, 'd'}, + {"prefix", required_argument, 0, 'p'}, + {"memdisk", required_argument, 0, 'm'}, + {"font", required_argument, 0, 'f'}, + {"config", required_argument, 0, 'c'}, + {"output", required_argument, 0, 'o'}, + {"note", no_argument, 0, 'n'}, + {"format", required_argument, 0, 'O'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name); + else + { + int format_len = 0; + char *formats; + char *ptr; + unsigned i; + for (i = 0; i < ARRAY_SIZE (image_targets); i++) + format_len += strlen (image_targets[i].name) + 2; + ptr = formats = xmalloc (format_len); + for (i = 0; i < ARRAY_SIZE (image_targets); i++) + { + strcpy (ptr, image_targets[i].name); + ptr += strlen (image_targets[i].name); + *ptr++ = ','; + *ptr++ = ' '; + } + ptr[-2] = 0; + + printf (_("\ +Usage: %s [OPTION]... [MODULES]\n\ +\n\ +Make a bootable image of GRUB.\n\ +\n\ + -d, --directory=DIR use images and modules under DIR [default=%s/@platform@]\n\ + -p, --prefix=DIR set grub_prefix directory [default=%s]\n\ + -m, --memdisk=FILE embed FILE as a memdisk image\n\ + -f, --font=FILE embed FILE as a boot font\n\ + -c, --config=FILE embed FILE as boot config\n\ + -n, --note add NOTE segment for CHRP Open Firmware\n\ + -o, --output=FILE output a generated image to FILE [default=stdout]\n\ + -O, --format=FORMAT generate an image in format\n\ + available formats: %s\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print verbose messages\n\ +\n\ +Report bugs to <%s>.\n\ +"), + program_name, GRUB_PKGLIBROOTDIR, DEFAULT_DIRECTORY, + formats, + PACKAGE_BUGREPORT); + free (formats); + } + exit (status); +} + +int +main (int argc, char *argv[]) +{ + char *output = NULL; + char *dir = NULL; + char *prefix = NULL; + char *memdisk = NULL; + char *font = NULL; + char *config = NULL; + FILE *fp = stdout; + int note = 0; + struct image_target_desc *image_target = NULL; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + while (1) + { + int c = getopt_long (argc, argv, "d:p:m:c:o:O:f:hVvn", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'o': + if (output) + free (output); + + output = xstrdup (optarg); + break; + + case 'O': + { + unsigned i; + for (i = 0; i < ARRAY_SIZE (image_targets); i++) + if (strcmp (optarg, image_targets[i].name) == 0) + image_target = &image_targets[i]; + if (!image_target) + { + printf ("unknown target %s\n", optarg); + usage (1); + } + break; + } + case 'd': + if (dir) + free (dir); + + dir = xstrdup (optarg); + break; + + case 'n': + note = 1; + break; + + case 'm': + if (memdisk) + free (memdisk); + + memdisk = xstrdup (optarg); + + if (prefix) + free (prefix); + + prefix = xstrdup ("(memdisk)/boot/grub"); + break; + + case 'f': + if (font) + free (font); + + font = xstrdup (optarg); + break; + + case 'c': + if (config) + free (config); + + config = xstrdup (optarg); + break; + + case 'h': + usage (0); + break; + + case 'p': + if (prefix) + free (prefix); + + prefix = xstrdup (optarg); + break; + + case 'V': + printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + if (!image_target) + { + printf ("Target not specified.\n"); + usage (1); + } + + if (output) + { + fp = fopen (output, "wb"); + if (! fp) + grub_util_error (_("cannot open %s"), output); + free (output); + } + + if (!dir) + { + const char *last; + last = strchr (image_target->name, '-'); + if (last) + last = strchr (last + 1, '-'); + if (!last) + last = image_target->name + strlen (image_target->name); + dir = xmalloc (sizeof (GRUB_PKGLIBROOTDIR) + (last - image_target->name) + + 1); + memcpy (dir, GRUB_PKGLIBROOTDIR, sizeof (GRUB_PKGLIBROOTDIR) - 1); + *(dir + sizeof (GRUB_PKGLIBROOTDIR) - 1) = '/'; + memcpy (dir + sizeof (GRUB_PKGLIBROOTDIR), image_target->name, + last - image_target->name); + *(dir + sizeof (GRUB_PKGLIBROOTDIR) + (last - image_target->name)) = 0; + } + + generate_image (dir, prefix ? : DEFAULT_DIRECTORY, fp, + argv + optind, memdisk, font, config, + image_target, note); + + fclose (fp); + + if (dir) + free (dir); + + return 0; +} diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c new file mode 100644 index 000000000..4a257e329 --- /dev/null +++ b/util/grub-mkimagexx.c @@ -0,0 +1,756 @@ +/* grub-mkimage.c - make a bootable image */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,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 . + */ + +#undef ELF_R_SYM +#undef ELF_R_TYPE + +#if defined(MKIMAGE_ELF32) +# define SUFFIX(x) x ## 32 +# define ELFCLASSXX ELFCLASS32 +# define Elf_Ehdr Elf32_Ehdr +# define Elf_Phdr Elf32_Phdr +# define Elf_Addr Elf32_Addr +# define Elf_Sym Elf32_Sym +# define Elf_Off Elf32_Off +# define Elf_Shdr Elf32_Shdr +# define Elf_Rela Elf32_Rela +# define Elf_Rel Elf32_Rel +# define ELF_R_SYM(val) ELF32_R_SYM(val) +# define ELF_R_TYPE(val) ELF32_R_TYPE(val) +#elif defined(MKIMAGE_ELF64) +# define SUFFIX(x) x ## 64 +# define ELFCLASSXX ELFCLASS64 +# define Elf_Ehdr Elf64_Ehdr +# define Elf_Phdr Elf64_Phdr +# define Elf_Addr Elf64_Addr +# define Elf_Sym Elf64_Sym +# define Elf_Off Elf64_Off +# define Elf_Shdr Elf64_Shdr +# define Elf_Rela Elf64_Rela +# define Elf_Rel Elf64_Rel +# define ELF_R_SYM(val) ELF64_R_SYM(val) +# define ELF_R_TYPE(val) ELF64_R_TYPE(val) +#else +#error "I'm confused" +#endif + +/* Relocate symbols; note that this function overwrites the symbol table. + Return the address of a start symbol. */ +static Elf_Addr +SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, + Elf_Shdr *symtab_section, Elf_Addr *section_addresses, + Elf_Half section_entsize, Elf_Half num_sections, + struct image_target_desc *image_target) +{ + Elf_Word symtab_size, sym_size, num_syms; + Elf_Off symtab_offset; + Elf_Addr start_address = 0; + Elf_Sym *sym; + Elf_Word i; + Elf_Shdr *strtab_section; + const char *strtab; + + strtab_section + = (Elf_Shdr *) ((char *) sections + + (grub_target_to_host32 (symtab_section->sh_link) + * section_entsize)); + strtab = (char *) e + grub_target_to_host (strtab_section->sh_offset); + + symtab_size = grub_target_to_host (symtab_section->sh_size); + sym_size = grub_target_to_host (symtab_section->sh_entsize); + symtab_offset = grub_target_to_host (symtab_section->sh_offset); + num_syms = symtab_size / sym_size; + + for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset); + i < num_syms; + i++, sym = (Elf_Sym *) ((char *) sym + sym_size)) + { + Elf_Section index; + const char *name; + + name = strtab + grub_target_to_host32 (sym->st_name); + + index = grub_target_to_host16 (sym->st_shndx); + if (index == STN_ABS) + { + continue; + } + else if ((index == STN_UNDEF)) + { + if (sym->st_name) + grub_util_error ("undefined symbol %s", name); + else + continue; + } + else if (index >= num_sections) + grub_util_error ("section %d does not exist", index); + + sym->st_value = (grub_target_to_host32 (sym->st_value) + + section_addresses[index]); + grub_util_info ("locating %s at 0x%x", name, sym->st_value); + + if (! start_address) + if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0) + start_address = sym->st_value; + } + + return start_address; +} + +/* Return the address of a symbol at the index I in the section S. */ +static Elf_Addr +SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i, + struct image_target_desc *image_target) +{ + Elf_Sym *sym; + + sym = (Elf_Sym *) ((char *) e + + grub_target_to_host32 (s->sh_offset) + + i * grub_target_to_host32 (s->sh_entsize)); + return sym->st_value; +} + +/* Return the address of a modified value. */ +static Elf_Addr * +SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset, + struct image_target_desc *image_target) +{ + return (Elf_Addr *) ((char *) e + grub_target_to_host32 (s->sh_offset) + offset); +} + +/* Deal with relocation information. This function relocates addresses + within the virtual address space starting from 0. So only relative + addresses can be fully resolved. Absolute addresses must be relocated + again by a PE32 relocator when loaded. */ +static void +SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, + Elf_Addr *section_addresses, + Elf_Half section_entsize, Elf_Half num_sections, + const char *strtab, struct image_target_desc *image_target) +{ + Elf_Half i; + Elf_Shdr *s; + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if ((s->sh_type == grub_host_to_target32 (SHT_REL)) || + (s->sh_type == grub_host_to_target32 (SHT_RELA))) + { + Elf_Rela *r; + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Shdr *symtab_section; + Elf_Word target_section_index; + Elf_Addr target_section_addr; + Elf_Shdr *target_section; + Elf_Word j; + + symtab_section = (Elf_Shdr *) ((char *) sections + + (grub_target_to_host32 (s->sh_link) + * section_entsize)); + target_section_index = grub_target_to_host32 (s->sh_info); + target_section_addr = section_addresses[target_section_index]; + target_section = (Elf_Shdr *) ((char *) sections + + (target_section_index + * section_entsize)); + + grub_util_info ("dealing with the relocation section %s for %s", + strtab + grub_target_to_host32 (s->sh_name), + strtab + grub_target_to_host32 (target_section->sh_name)); + + rtab_size = grub_target_to_host32 (s->sh_size); + r_size = grub_target_to_host32 (s->sh_entsize); + rtab_offset = grub_target_to_host32 (s->sh_offset); + num_rs = rtab_size / r_size; + + for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); + j < num_rs; + j++, r = (Elf_Rela *) ((char *) r + r_size)) + { + Elf_Addr info; + Elf_Addr offset; + Elf_Addr sym_addr; + Elf_Addr *target; + Elf_Addr addend; + + offset = grub_target_to_host (r->r_offset); + target = SUFFIX (get_target_address) (e, target_section, + offset, image_target); + info = grub_target_to_host (r->r_info); + sym_addr = SUFFIX (get_symbol_address) (e, symtab_section, + ELF_R_SYM (info), image_target); + + addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? + r->r_addend : 0; + + if (image_target->voidp_sizeof == 4) + switch (ELF_R_TYPE (info)) + { + case R_386_NONE: + break; + + case R_386_32: + /* This is absolute. */ + *target = grub_host_to_target32 (grub_target_to_host32 (*target) + + addend + sym_addr); + grub_util_info ("relocating an R_386_32 entry to 0x%x at the offset 0x%x", + *target, offset); + break; + + case R_386_PC32: + /* This is relative. */ + *target = grub_host_to_target32 (grub_target_to_host32 (*target) + + addend + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + grub_util_info ("relocating an R_386_PC32 entry to 0x%x at the offset 0x%x", + *target, offset); + break; + default: + grub_util_error ("unknown relocation type %d", + ELF_R_TYPE (info)); + break; + } + else + switch (ELF_R_TYPE (info)) + { + + case R_X86_64_NONE: + break; + + case R_X86_64_64: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr); + grub_util_info ("relocating an R_X86_64_64 entry to 0x%llx at the offset 0x%llx", + *target, offset); + break; + + case R_X86_64_PC32: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) + + addend + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%llx", + *t32, offset); + break; + } + + case R_X86_64_32: + case R_X86_64_32S: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) + + addend + sym_addr); + grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%llx", + *t32, offset); + break; + } + + default: + grub_util_error ("unknown relocation type %d", + ELF_R_TYPE (info)); + break; + } + } + } +} + +/* Add a PE32's fixup entry for a relocation. Return the resulting address + after having written to the file OUT. */ +static Elf_Addr +SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type, + Elf_Addr addr, int flush, Elf_Addr current_address, + struct image_target_desc *image_target) +{ + struct grub_pe32_fixup_block *b; + + b = &((*cblock)->b); + + /* First, check if it is necessary to write out the current block. */ + if ((*cblock)->state) + { + if (flush || addr < b->page_rva || b->page_rva + 0x1000 <= addr) + { + grub_uint32_t size; + + if (flush) + { + /* Add as much padding as necessary to align the address + with a section boundary. */ + Elf_Addr next_address; + unsigned padding_size; + size_t index; + + next_address = current_address + b->block_size; + padding_size = ((ALIGN_UP (next_address, image_target->section_align) + - next_address) + >> 1); + index = ((b->block_size - sizeof (*b)) >> 1); + grub_util_info ("adding %d padding fixup entries", padding_size); + while (padding_size--) + { + b->entries[index++] = 0; + b->block_size += 2; + } + } + else if (b->block_size & (8 - 1)) + { + /* If not aligned with a 32-bit boundary, add + a padding entry. */ + size_t index; + + grub_util_info ("adding a padding fixup entry"); + index = ((b->block_size - sizeof (*b)) >> 1); + b->entries[index] = 0; + b->block_size += 2; + } + + /* Flush it. */ + grub_util_info ("writing %d bytes of a fixup block starting at 0x%x", + b->block_size, b->page_rva); + size = b->block_size; + current_address += size; + b->page_rva = grub_host_to_target32 (b->page_rva); + b->block_size = grub_host_to_target32 (b->block_size); + (*cblock)->next = xmalloc (sizeof (**cblock) + 2 * 0x1000); + memset ((*cblock)->next, 0, sizeof (**cblock) + 2 * 0x1000); + *cblock = (*cblock)->next; + } + } + + b = &((*cblock)->b); + + if (! flush) + { + grub_uint16_t entry; + size_t index; + + /* If not allocated yet, allocate a block with enough entries. */ + if (! (*cblock)->state) + { + (*cblock)->state = 1; + + /* The spec does not mention the requirement of a Page RVA. + Here, align the address with a 4K boundary for safety. */ + b->page_rva = (addr & ~(0x1000 - 1)); + b->block_size = sizeof (*b); + } + + /* Sanity check. */ + if (b->block_size >= sizeof (*b) + 2 * 0x1000) + grub_util_error ("too many fixup entries"); + + /* Add a new entry. */ + index = ((b->block_size - sizeof (*b)) >> 1); + entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva); + b->entries[index] = grub_host_to_target16 (entry); + b->block_size += 2; + } + + return current_address; +} + +/* Make a .reloc section. */ +static Elf_Addr +SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, + Elf_Addr *section_addresses, Elf_Shdr *sections, + Elf_Half section_entsize, Elf_Half num_sections, + const char *strtab, struct image_target_desc *image_target) +{ + Elf_Half i; + Elf_Shdr *s; + struct fixup_block_list *lst, *lst0; + Elf_Addr current_address = 0; + + lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000); + memset (lst, 0, sizeof (*lst) + 2 * 0x1000); + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) || + (s->sh_type == grub_cpu_to_le32 (SHT_RELA))) + { + Elf_Rel *r; + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Addr section_address; + Elf_Word j; + + grub_util_info ("translating the relocation section %s", + strtab + grub_le_to_cpu32 (s->sh_name)); + + rtab_size = grub_le_to_cpu32 (s->sh_size); + r_size = grub_le_to_cpu32 (s->sh_entsize); + rtab_offset = grub_le_to_cpu32 (s->sh_offset); + num_rs = rtab_size / r_size; + + section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)]; + + for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset); + j < num_rs; + j++, r = (Elf_Rel *) ((char *) r + r_size)) + { + Elf_Addr info; + Elf_Addr offset; + + offset = grub_le_to_cpu32 (r->r_offset); + info = grub_le_to_cpu32 (r->r_info); + + /* Necessary to relocate only absolute addresses. */ + if (image_target->voidp_sizeof == 4) + { + if (ELF_R_TYPE (info) == R_386_32) + { + Elf_Addr addr; + + addr = section_address + offset; + grub_util_info ("adding a relocation entry for 0x%x", addr); + current_address + = SUFFIX (add_fixup_entry) (&lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, current_address, + image_target); + } + } + else + { + if ((ELF_R_TYPE (info) == R_X86_64_32) || + (ELF_R_TYPE (info) == R_X86_64_32S)) + { + grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)"); + } + else if (ELF_R_TYPE (info) == R_X86_64_64) + { + Elf_Addr addr; + + addr = section_address + offset; + grub_util_info ("adding a relocation entry for 0x%llx", addr); + current_address + = SUFFIX (add_fixup_entry) (&lst, + GRUB_PE32_REL_BASED_DIR64, + addr, + 0, current_address, + image_target); + } + } + } + } + + current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target); + + { + grub_uint8_t *ptr; + ptr = *out = xmalloc (current_address); + for (lst = lst0; lst; lst = lst->next) + if (lst->state) + { + memcpy (ptr, &lst->b, grub_target_to_host32 (lst->b.block_size)); + ptr += grub_target_to_host32 (lst->b.block_size); + } + if (current_address + *out != ptr) + { + grub_util_error ("Bug detected %d != %d\n", ptr - (grub_uint8_t *) *out, + current_address); + } + } + + return current_address; +} + +/* Determine if this section is a text section. Return false if this + section is not allocated. */ +static int +SUFFIX (is_text_section) (Elf_Shdr *s, struct image_target_desc *image_target) +{ + if (image_target->id != IMAGE_EFI + && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) + return 0; + return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) + == (SHF_EXECINSTR | SHF_ALLOC)); +} + +/* Determine if this section is a data section. This assumes that + BSS is also a data section, since the converter initializes BSS + when producing PE32 to avoid a bug in EFI implementations. */ +static int +SUFFIX (is_data_section) (Elf_Shdr *s, struct image_target_desc *image_target) +{ + if (image_target->id != IMAGE_EFI + && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) + return 0; + return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) + == SHF_ALLOC); +} + +/* Return if the ELF header is valid. */ +static int +SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, struct image_target_desc *image_target) +{ + if (size < sizeof (*e) + || e->e_ident[EI_MAG0] != ELFMAG0 + || e->e_ident[EI_MAG1] != ELFMAG1 + || e->e_ident[EI_MAG2] != ELFMAG2 + || e->e_ident[EI_MAG3] != ELFMAG3 + || e->e_ident[EI_VERSION] != EV_CURRENT + || e->e_ident[EI_CLASS] != ELFCLASSXX + || e->e_version != grub_host_to_target32 (EV_CURRENT)) + return 0; + + return 1; +} + +/* Locate section addresses by merging code sections and data sections + into .text and .data, respectively. Return the array of section + addresses. */ +static Elf_Addr * +SUFFIX (locate_sections) (Elf_Shdr *sections, Elf_Half section_entsize, + Elf_Half num_sections, const char *strtab, + grub_size_t *exec_size, grub_size_t *kernel_sz, + grub_size_t *all_align, + struct image_target_desc *image_target) +{ + int i; + Elf_Addr current_address; + Elf_Addr *section_addresses; + Elf_Shdr *s; + + *all_align = 1; + + section_addresses = xmalloc (sizeof (*section_addresses) * num_sections); + memset (section_addresses, 0, sizeof (*section_addresses) * num_sections); + + current_address = 0; + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC) + && grub_host_to_target32 (s->sh_addralign) > *all_align) + *all_align = grub_host_to_target32 (s->sh_addralign); + + + /* .text */ + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (SUFFIX (is_text_section) (s, image_target)) + { + Elf_Word align = grub_host_to_target32 (s->sh_addralign); + const char *name = strtab + grub_host_to_target32 (s->sh_name); + if (align) + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + align) - image_target->vaddr_offset; + grub_util_info ("locating the section %s at 0x%x", + name, current_address); + section_addresses[i] = current_address; + current_address += grub_host_to_target_addr (s->sh_size); + } + + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + image_target->section_align) + - image_target->vaddr_offset; + *exec_size = current_address; + + /* .data */ + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (SUFFIX (is_data_section) (s, image_target)) + { + Elf_Word align = grub_host_to_target32 (s->sh_addralign); + const char *name = strtab + grub_host_to_target32 (s->sh_name); + + if (align) + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + align) + - image_target->vaddr_offset; + + grub_util_info ("locating the section %s at 0x%x", + name, current_address); + section_addresses[i] = current_address; + current_address += grub_host_to_target_addr (s->sh_size); + } + + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + image_target->section_align) - image_target->vaddr_offset; + *kernel_sz = current_address; + return section_addresses; +} + +static char * +SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size, + grub_size_t *kernel_sz, grub_size_t *bss_size, + grub_size_t total_module_size, grub_uint64_t *start, + void **reloc_section, grub_size_t *reloc_size, + grub_size_t *align, + struct image_target_desc *image_target) +{ + char *kernel_img, *out_img; + const char *strtab; + Elf_Ehdr *e; + Elf_Shdr *sections; + Elf_Addr *section_addresses; + Elf_Addr *section_vaddresses; + int i; + Elf_Shdr *s; + Elf_Half num_sections; + Elf_Off section_offset; + Elf_Half section_entsize; + grub_size_t kernel_size; + Elf_Shdr *symtab_section; + + *start = 0; + + kernel_size = grub_util_get_image_size (kernel_path); + kernel_img = xmalloc (kernel_size); + grub_util_load_image (kernel_path, kernel_img); + + e = (Elf_Ehdr *) kernel_img; + if (! SUFFIX (check_elf_header) (e, kernel_size, image_target)) + grub_util_error ("invalid ELF header"); + + section_offset = grub_target_to_host (e->e_shoff); + section_entsize = grub_target_to_host16 (e->e_shentsize); + num_sections = grub_target_to_host16 (e->e_shnum); + + if (kernel_size < section_offset + section_entsize * num_sections) + grub_util_error ("invalid ELF format"); + + sections = (Elf_Shdr *) (kernel_img + section_offset); + + /* Relocate sections then symbols in the virtual address space. */ + s = (Elf_Shdr *) ((char *) sections + + grub_host_to_target16 (e->e_shstrndx) * section_entsize); + strtab = (char *) e + grub_host_to_target32 (s->sh_offset); + + section_addresses = SUFFIX (locate_sections) (sections, section_entsize, + num_sections, strtab, + exec_size, kernel_sz, align, + image_target); + + section_vaddresses = xmalloc (sizeof (*section_addresses) * num_sections); + + for (i = 0; i < num_sections; i++) + section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset; + + if (image_target->id != IMAGE_EFI) + { + Elf_Addr current_address = *kernel_sz; + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) + { + Elf_Word align = grub_host_to_target32 (s->sh_addralign); + const char *name = strtab + grub_host_to_target32 (s->sh_name); + + if (align) + current_address = ALIGN_UP (current_address + + image_target->vaddr_offset, align) + - image_target->vaddr_offset; + + grub_util_info ("locating the section %s at 0x%x", + name, current_address); + section_vaddresses[i] = current_address + + image_target->vaddr_offset; + current_address += grub_host_to_target_addr (s->sh_size); + } + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + image_target->section_align) + - image_target->vaddr_offset; + *bss_size = current_address - *kernel_sz; + } + else + *bss_size = 0; + + if (image_target->id == IMAGE_EFI) + { + symtab_section = NULL; + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB)) + { + symtab_section = s; + break; + } + + if (! symtab_section) + grub_util_error ("no symbol table"); + + *start = SUFFIX (relocate_symbols) (e, sections, symtab_section, + section_vaddresses, section_entsize, + num_sections, image_target); + if (*start == 0) + grub_util_error ("start symbol is not defined"); + + /* Resolve addresses in the virtual address space. */ + SUFFIX (relocate_addresses) (e, sections, section_addresses, section_entsize, + num_sections, strtab, image_target); + + *reloc_size = SUFFIX (make_reloc_section) (e, reloc_section, + section_vaddresses, sections, + section_entsize, num_sections, + strtab, image_target); + } + else + { + *reloc_size = 0; + *reloc_section = NULL; + } + + out_img = xmalloc (*kernel_sz + total_module_size); + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (SUFFIX (is_data_section) (s, image_target) + || SUFFIX (is_text_section) (s, image_target)) + { + if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) + memset (out_img + section_addresses[i], 0, + grub_host_to_target_addr (s->sh_size)); + else + memcpy (out_img + section_addresses[i], + kernel_img + grub_host_to_target_addr (s->sh_offset), + grub_host_to_target_addr (s->sh_size)); + } + free (kernel_img); + + return out_img; +} + + +#undef SUFFIX +#undef ELFCLASSXX +#undef Elf_Ehdr +#undef Elf_Phdr +#undef Elf_Shdr +#undef Elf_Addr +#undef Elf_Sym +#undef Elf_Off +#undef Elf_Rela +#undef Elf_Rel +#undef ELF_R_TYPE +#undef ELF_R_SYM diff --git a/util/grub-mkpasswd-pbkdf2.c b/util/grub-mkpasswd-pbkdf2.c new file mode 100644 index 000000000..a00b1e990 --- /dev/null +++ b/util/grub-mkpasswd-pbkdf2.c @@ -0,0 +1,341 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1992-1999,2001,2003,2004,2005,2009 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 . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "progname.h" + +/* Few functions to make crypto happy. */ +void * +grub_memmove (void *dest, const void *src, grub_size_t n) +{ + return memmove (dest, src, n); +} + +void * +grub_memset (void *s, int c, grub_size_t n) +{ + return memset (s, c, n); +} + +int +grub_vprintf (const char *fmt, va_list args) +{ + return vprintf (fmt, args); +} + +int +grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list args) +{ + return vsnprintf (str, n, fmt, args); +} + +void +grub_abort (void) +{ + abort (); +} + +static struct option options[] = + { + {"iteration_count", required_argument, 0, 'c'}, + {"buflen", required_argument, 0, 'l'}, + {"saltlen", required_argument, 0, 's'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTIONS]\n\ +\nOptions:\n\ + -c number, --iteration-count=number Number of PBKDF2 iterations\n\ + -l number, --buflen=number Length of generated hash\n\ + -s number, --salt=number Length of salt\n\ +\n\ +Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); + + exit (status); +} + +static void +hexify (char *hex, grub_uint8_t *bin, grub_size_t n) +{ + while (n--) + { + if (((*bin & 0xf0) >> 4) < 10) + *hex = ((*bin & 0xf0) >> 4) + '0'; + else + *hex = ((*bin & 0xf0) >> 4) + 'A' - 10; + hex++; + + if ((*bin & 0xf) < 10) + *hex = (*bin & 0xf) + '0'; + else + *hex = (*bin & 0xf) + 'A' - 10; + hex++; + bin++; + } + *hex = 0; +} + +int +main (int argc, char *argv[]) +{ + unsigned int c = 10000, buflen = 64, saltlen = 64; + char *pass1, *pass2; + char *bufhex, *salthex; + gcry_err_code_t gcry_err; + grub_uint8_t *buf, *salt; + ssize_t nr; + FILE *in, *out; + struct termios s, t; + int tty_changed; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "c:l:s:hvV", options, 0); + + if (c == -1) + break; + + switch (c) + { + case 'c': + c = strtoul (optarg, NULL, 0); + break; + + case 'l': + buflen = strtoul (optarg, NULL, 0); + break; + + case 's': + saltlen = strtoul (optarg, NULL, 0); + break; + + case 'h': + usage (0); + return 0; + + case 'V': + printf ("%s (%s) %s\n", program_name, + PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + default: + usage (1); + return 1; + } + } + + bufhex = malloc (buflen * 2 + 1); + if (!bufhex) + grub_util_error ("out of memory"); + buf = malloc (buflen); + if (!buf) + { + free (bufhex); + grub_util_error ("out of memory"); + } + + salt = malloc (saltlen); + if (!salt) + { + free (bufhex); + free (buf); + grub_util_error ("out of memory"); + } + salthex = malloc (saltlen * 2 + 1); + if (!salthex) + { + free (salt); + free (bufhex); + free (buf); + grub_util_error ("out of memory"); + } + + /* Disable echoing. Based on glibc. */ + in = fopen ("/dev/tty", "w+c"); + if (in == NULL) + { + in = stdin; + out = stderr; + } + else + out = in; + + if (tcgetattr (fileno (in), &t) == 0) + { + /* Save the old one. */ + s = t; + /* Tricky, tricky. */ + t.c_lflag &= ~(ECHO|ISIG); + tty_changed = (tcsetattr (fileno (in), TCSAFLUSH, &t) == 0); + } + else + tty_changed = 0; + + printf ("Enter password: "); + pass1 = NULL; + { + grub_size_t n; + nr = getline (&pass1, &n, stdin); + } + if (nr < 0 || !pass1) + { + free (buf); + free (bufhex); + free (salthex); + free (salt); + /* Restore the original setting. */ + if (tty_changed) + (void) tcsetattr (fileno (in), TCSAFLUSH, &s); + grub_util_error ("failure to read password"); + } + if (nr >= 1 && pass1[nr-1] == '\n') + pass1[nr-1] = 0; + + printf ("\nReenter password: "); + pass2 = NULL; + { + grub_size_t n; + nr = getline (&pass2, &n, stdin); + } + /* Restore the original setting. */ + if (tty_changed) + (void) tcsetattr (fileno (in), TCSAFLUSH, &s); + printf ("\n"); + + if (nr < 0 || !pass2) + { + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + grub_util_error ("failure to read password"); + } + if (nr >= 1 && pass2[nr-1] == '\n') + pass2[nr-1] = 0; + + if (strcmp (pass1, pass2) != 0) + { + memset (pass1, 0, strlen (pass1)); + memset (pass2, 0, strlen (pass2)); + free (pass1); + free (pass2); + free (buf); + free (bufhex); + free (salthex); + free (salt); + grub_util_error ("passwords don't match"); + } + memset (pass2, 0, strlen (pass2)); + free (pass2); + +#if ! defined (__linux__) && ! defined (__FreeBSD__) + printf ("WARNING: your random generator isn't known to be secure\n"); +#endif + + { + FILE *f; + size_t rd; + f = fopen ("/dev/random", "rb"); + if (!f) + { + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + fclose (f); + grub_util_error ("couldn't retrieve random data for salt"); + } + rd = fread (salt, 1, saltlen, f); + if (rd != saltlen) + { + fclose (f); + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + fclose (f); + grub_util_error ("couldn't retrieve random data for salt"); + } + fclose (f); + } + + gcry_err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, + (grub_uint8_t *) pass1, strlen (pass1), + salt, saltlen, + c, buf, buflen); + memset (pass1, 0, strlen (pass1)); + free (pass1); + + if (gcry_err) + { + memset (buf, 0, buflen); + memset (bufhex, 0, 2 * buflen); + free (buf); + free (bufhex); + memset (salt, 0, saltlen); + memset (salthex, 0, 2 * saltlen); + free (salt); + free (salthex); + grub_util_error ("cryptographic error number %d", gcry_err); + } + + hexify (bufhex, buf, buflen); + hexify (salthex, salt, saltlen); + + printf ("Your PBKDF2 is grub.pbkdf2.sha512.%d.%s.%s\n", c, salthex, bufhex); + memset (buf, 0, buflen); + memset (bufhex, 0, 2 * buflen); + free (buf); + free (bufhex); + memset (salt, 0, saltlen); + memset (salthex, 0, 2 * saltlen); + free (salt); + free (salthex); + + return 0; +} diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c index a20109628..eccb49cdc 100644 --- a/util/grub-mkrelpath.c +++ b/util/grub-mkrelpath.c @@ -1,7 +1,7 @@ /* grub-mkrelpath.c - make a system path relative to its root */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 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 @@ -17,7 +17,9 @@ * along with GRUB. If not, see . */ +#include #include +#include #include #include @@ -27,18 +29,19 @@ static struct option options[] = { {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, + {0, 0, 0, 0}, }; static void usage (int status) { if (status) - fprintf (stderr, "Try ``%s --help'' for more information.\n", program_name); + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); else printf ("\ Usage: %s [OPTIONS] PATH\n\ \n\ -Make a system path relative to it's root.\n\ +Make a system path relative to its root.\n\ \n\ Options:\n\ -h, --help display this message and exit\n\ @@ -55,9 +58,8 @@ main (int argc, char *argv[]) char *argument, *relpath; set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + + grub_util_init_nls (); /* Check for options. */ while (1) @@ -97,7 +99,7 @@ main (int argc, char *argv[]) argument = argv[optind]; - relpath = make_system_path_relative_to_its_root (argument); + relpath = grub_make_system_path_relative_to_its_root (argument); printf ("%s\n", relpath); free (relpath); diff --git a/util/grub-mkrescue.in b/util/grub-mkrescue.in index 8e4a77f58..7e7253006 100644 --- a/util/grub-mkrescue.in +++ b/util/grub-mkrescue.in @@ -28,9 +28,16 @@ PACKAGE_TARNAME=@PACKAGE_TARNAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ target_cpu=@target_cpu@ native_platform=@platform@ +pkglib_DATA="@pkglib_DATA@" -coreboot_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/${target_cpu}-coreboot -pc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/${target_cpu}-pc +multiboot_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-multiboot +coreboot_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-coreboot +qemu_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-qemu +pc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-pc +efi32_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-efi +efi64_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/x86_64-efi +rom_directory= +grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` # Usage: usage # Print the usage. @@ -41,8 +48,10 @@ Make GRUB rescue image. -h, --help print this message and exit -v, --version print the version information and exit - --modules=MODULES pre-load specified modules MODULES --output=FILE save output in FILE [required] + --modules=MODULES pre-load specified modules MODULES + --rom-directory=DIR save rom images in DIR [optional] + --grub-mkimage=FILE use FILE as grub-mkimage $0 generates a bootable rescue image with specified source files or directories. @@ -63,12 +72,16 @@ for option in "$@"; do modules=`echo "$option" | sed 's/--modules=//'` ;; --output=*) output_image=`echo "$option" | sed 's/--output=//'` ;; + --rom-directory=*) + rom_directory=`echo "$option" | sed 's/--rom-directory=//'` ;; # Intentionally undocumented --override-directory=*) override_dir=`echo "${option}/" | sed 's/--override-directory=//'` PATH=${override_dir}:$PATH export PATH ;; + --grub-mkimage=*) + grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; -*) echo "Unrecognized option \`$option'" 1>&2 usage @@ -85,21 +98,40 @@ if [ "x${output_image}" = x ] ; then exit 1 fi -iso9660_dir=`mktemp -d` +set $grub_mkimage dummy +if test -f "$1"; then + : +else + echo "$1: Not found." 1>&2 + exit 1 +fi + +if test "x$TMP" != x; then + MKTEMP_TEMPLATE="$TMP/grub-mkrescue.XXXXXXXXXX" +elif test "x$TEMP" != x; then + MKTEMP_TEMPLATE="$TEMP/grub-mkrescue.XXXXXXXXXX" +else + MKTEMP_TEMPLATE="/tmp/grub-mkrescue.XXXXXXXXXX" +fi + +iso9660_dir=`mktemp -d "$MKTEMP_TEMPLATE"` mkdir -p ${iso9660_dir}/boot/grub process_input_dir () { input_dir="$1" platform="$2" - mkdir -p ${iso9660_dir}/boot/grub/${target_cpu}-${platform} - for file in ${input_dir}/*.mod ${input_dir}/efiemu??.o \ - ${input_dir}/command.lst ${input_dir}/moddep.lst ${input_dir}/fs.lst \ - ${input_dir}/handler.lst ${input_dir}/parttool.lst; do + mkdir -p ${iso9660_dir}/boot/grub/${platform} + for file in ${input_dir}/*.mod; do if test -f "$file"; then - cp -f "$file" ${iso9660_dir}/boot/grub/${target_cpu}-${platform}/ + cp -f "$file" ${iso9660_dir}/boot/grub/${platform}/ fi done + for file in ${pkglib_DATA}; do + if test -f "${input_dir}/${file}"; then + cp -f "${input_dir}/${file}" ${iso9660_dir}/boot/grub/${platform}/ + fi + done mkdir -p ${iso9660_dir}/boot/grub/locale for file in ${input_dir}/po/*.mo; do @@ -109,60 +141,91 @@ process_input_dir () done } -if [ "${override_dir}" = "" ] ; then - if test -e "${coreboot_dir}" ; then - process_input_dir ${coreboot_dir} coreboot +make_image () +{ + source_directory="$1" + platform=$2 + if ! test -e "${source_directory}"; then + return; fi - if test -e "${pc_dir}" ; then - process_input_dir ${pc_dir} pc - fi -else - process_input_dir ${override_dir} ${native_platform} - coreboot_dir= - pc_dir= - case "${native_platform}" in - coreboot) coreboot_dir=${override_dir} ;; - pc) pc_dir=${override_dir} ;; - esac -fi -# build coreboot core.img -if test -e "${coreboot_dir}" ; then - echo "Generates coreboot" - memdisk_img=`mktemp` - memdisk_dir=`mktemp -d` + echo "Enabling $2 support ..." + + memdisk_img=`mktemp "$MKTEMP_TEMPLATE"` + memdisk_dir=`mktemp -d "$MKTEMP_TEMPLATE"` mkdir -p ${memdisk_dir}/boot/grub - # obtain date-based UUID - iso_uuid=$(date +%Y-%m-%d-%H-%M-%S-00) - modules="$(cat ${coreboot_dir}/partmap.lst) ${modules}" + modules="$(cat ${source_directory}/partmap.lst) ${modules}" cat << EOF > ${memdisk_dir}/boot/grub/grub.cfg search --fs-uuid --set ${iso_uuid} -set prefix=(\${root})/boot/grub/${target_cpu}-coreboot +set prefix=(\${root})/boot/grub/${platform} +source \$prefix/grub.cfg EOF (for i in ${modules} ; do echo "insmod $i" done ; \ echo "source /boot/grub/grub.cfg") \ - > ${iso9660_dir}/boot/grub/i386-pc/grub.cfg + > ${iso9660_dir}/boot/grub/${platform}/grub.cfg tar -C ${memdisk_dir} -cf ${memdisk_img} boot rm -rf ${memdisk_dir} - grub-mkelfimage -d ${coreboot_dir}/ -m ${memdisk_img} -o ${iso9660_dir}/boot/multiboot.img \ - memdisk tar search iso9660 configfile sh \ - ata at_keyboard - rm -f ${memdisk_img} - grub_mkisofs_arguments="${grub_mkisofs_arguments} --modification-date=$(echo ${iso_uuid} | sed -e s/-//g)" + $grub_mkimage -O ${platform} -d "${source_directory}" -m "${memdisk_img}" -o "$3" --prefix='(memdisk)/boot/grub' \ + search iso9660 configfile normal sh memdisk tar $4 + rm -rf ${memdisk_img} +} + +if [ "${override_dir}" = "" ] ; then + if test -e "${multiboot_dir}" ; then + process_input_dir ${multiboot_dir} i386-multiboot + fi + if test -e "${coreboot_dir}" ; then + process_input_dir ${coreboot_dir} i386-coreboot + fi + if test -e "${qemu_dir}" ; then + process_input_dir ${qemu_dir} i386-qemu + fi + if test -e "${pc_dir}" ; then + process_input_dir ${pc_dir} i386-pc + fi + if test -e "${efi32_dir}" ; then + process_input_dir ${efi32_dir} i386-efi + fi + if test -e "${efi64_dir}" ; then + process_input_dir ${efi64_dir} x86_64-efi + fi +else + process_input_dir ${override_dir} ${target_cpu}-${native_platform} + multiboot_dir= + pc_dir= + efi32_dir= + efi64_dir= + coreboot_dir= + qemu_dir= + case "${target_cpu}-${native_platform}" in + i386-multiboot) multiboot_dir=${override_dir} ;; + i386-coreboot) coreboot_dir=${override_dir} ;; + i386-qemu) qemu_dir=${override_dir} ;; + i386-pc) pc_dir=${override_dir} ;; + i386-efi) efi32_dir=${override_dir} ;; + x86_64-efi) efi64_dir=${override_dir} ;; + esac fi -# build eltorito core.img +# obtain date-based UUID +iso_uuid=$(date -u +%Y-%m-%d-%H-%M-%S-00) +grub_mkisofs_arguments="${grub_mkisofs_arguments} --modification-date=$(echo ${iso_uuid} | sed -e s/-//g)" + +# build BIOS core.img if test -e "${pc_dir}" ; then - echo "Generates eltorito" - core_img=`mktemp` - grub-mkimage -d ${pc_dir}/ -o ${core_img} --prefix=/boot/grub/i386-pc \ - memdisk tar search iso9660 configfile sh \ - biosdisk + echo "Enabling BIOS support ..." + core_img=`mktemp "$MKTEMP_TEMPLATE"` + $grub_mkimage -O i386-pc -d ${pc_dir}/ -o ${core_img} --prefix=/boot/grub/i386-pc \ + iso9660 biosdisk cat ${pc_dir}/cdboot.img ${core_img} > ${iso9660_dir}/boot/grub/i386-pc/eltorito.img + + embed_img=`mktemp "$MKTEMP_TEMPLATE"` + cat ${pc_dir}/boot.img ${core_img} > ${embed_img} + rm -f ${core_img} modules="$(cat ${pc_dir}/partmap.lst) ${modules}" @@ -172,11 +235,40 @@ if test -e "${pc_dir}" ; then echo "source /boot/grub/grub.cfg") \ > ${iso9660_dir}/boot/grub/i386-pc/grub.cfg - grub_mkisofs_arguments="${grub_mkisofs_arguments} -b boot/grub/i386-pc/eltorito.img -boot-info-table" + grub_mkisofs_arguments="${grub_mkisofs_arguments} -b boot/grub/i386-pc/eltorito.img -no-emul-boot -boot-info-table \ + --embedded-boot ${embed_img}" +fi + +# build multiboot core.img +make_image "${multiboot_dir}" i386-multiboot "${iso9660_dir}/boot/multiboot.img" "ata at_keyboard" + +if test -e "${efi64_dir}" || test -e "${efi32_dir}"; then + efi_dir=`mktemp -d "$MKTEMP_TEMPLATE"` + mkdir -p "${efi_dir}/efi/boot" + + # build bootx64.efi + make_image "${efi64_dir}" x86_64-efi "${efi_dir}"/efi/boot/bootx64.efi "" + # build bootia32.efi + make_image "${efi32_dir}" i386-efi "${efi_dir}"/efi/boot/bootia32.efi "" + + mformat -C -f 2880 -L 16 -i "${iso9660_dir}"/efi.img :: + mcopy -s -i "${iso9660_dir}"/efi.img ${efi_dir}/efi ::/ + grub_mkisofs_arguments="${grub_mkisofs_arguments} --efi-boot efi.img" +fi + +make_image "${qemu_dir}" i386-qemu "${iso9660_dir}/boot/qemu.img" "ata at_keyboard" +if [ -e "${iso9660_dir}/boot/qemu.img" ] && [ -d "${rom_directory}" ]; then + cp "${iso9660_dir}/boot/qemu.img" "${rom_directory}/qemu.img" +fi +make_image "${coreboot_dir}" i386-coreboot "${iso9660_dir}/boot/coreboot.elf" "ata at_keyboard" +if [ -e "${iso9660_dir}/boot/coreboot.elf" ] && [ -d "${rom_directory}" ]; then + cp "${iso9660_dir}/boot/coreboot.elf" "${rom_directory}/coreboot.elf" fi # build iso image -grub-mkisofs ${grub_mkisofs_arguments} -o ${output_image} -r ${iso9660_dir} ${source} +xorriso -pathspecs on -as mkisofs ${grub_mkisofs_arguments} --protective-msdos-label -o ${output_image} -r ${iso9660_dir} ${source} rm -rf ${iso9660_dir} +rm -f ${embed_img} + exit 0 diff --git a/util/grub-pe2elf.c b/util/grub-pe2elf.c index fb370d9ec..f370bbfa8 100644 --- a/util/grub-pe2elf.c +++ b/util/grub-pe2elf.c @@ -29,6 +29,8 @@ #include #include +#include "progname.h" + static struct option options[] = { {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, @@ -40,7 +42,7 @@ static void usage (int status) { if (status) - fprintf (stderr, "Try ``%s --help'' for more information.\n", program_name); + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); else printf ("\ Usage: %s [OPTIONS] input [output]\n\ @@ -182,7 +184,7 @@ write_section_data (FILE* fp, char *image, char name[5 + strlen (pe_shdr->name)]; if (num_sections >= MAX_SECTIONS) - grub_util_error ("Too many sections"); + grub_util_error ("too many sections"); sprintf (name, ".rel%s", pe_shdr->name); @@ -230,14 +232,14 @@ write_reloc_section (FILE* fp, char *image, if ((pe_rel->symtab_index >= pe_chdr->num_symbols) || (symtab_map[pe_rel->symtab_index] == -1)) - grub_util_error ("Invalid symbol"); + grub_util_error ("invalid symbol"); if (pe_rel->type == GRUB_PE32_REL_I386_DIR32) type = R_386_32; else if (pe_rel->type == GRUB_PE32_REL_I386_REL32) type = R_386_PC32; else - grub_util_error ("Unknown pe relocation type %d\n", pe_rel->type); + grub_util_error ("unknown pe relocation type %d\n", pe_rel->type); ofs = pe_rel->offset - pe_sec->virtual_address; addr = (grub_uint32_t *)(image + pe_sec->raw_data_offset + ofs); @@ -248,14 +250,14 @@ write_reloc_section (FILE* fp, char *image, code = image[pe_sec->raw_data_offset + ofs - 1]; if (((code != 0xe8) && (code != 0xe9)) || (*addr)) - grub_util_error ("Invalid relocation (%x %x)", code, *addr); + grub_util_error ("invalid relocation (%x %x)", code, *addr); modified = 1; if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx) { if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx != shdr[i].sh_info) - grub_util_error ("Cross section call is not allowed"); + grub_util_error ("cross section call is not allowed"); *addr = (symtab[symtab_map[pe_rel->symtab_index]].st_value - ofs - 4); @@ -440,7 +442,7 @@ convert_pe (FILE* fp, char *image) pe_chdr = (struct grub_pe32_coff_header *) image; if (grub_le_to_cpu16 (pe_chdr->machine) != GRUB_PE32_MACHINE_I386) - grub_util_error ("Invalid coff image"); + grub_util_error ("invalid coff image"); strtab = xmalloc (STRTAB_BLOCK); strtab_max = STRTAB_BLOCK; diff --git a/util/grub-probe.c b/util/grub-probe.c index 6d421445c..1f956efb7 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -1,7 +1,7 @@ /* grub-probe.c - probe device information for a given path */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2005,2006,2007,2008,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 @@ -20,14 +20,15 @@ #include #include #include +#include #include #include #include #include #include #include -#include -#include +#include +#include #include #include #include @@ -82,18 +83,26 @@ grub_refresh (void) static void probe_partmap (grub_disk_t disk) { + grub_partition_t part; + if (disk->partition == NULL) { - grub_util_info ("No partition map found for %s", disk->name); + grub_util_info ("no partition map found for %s", disk->name); return; } - printf ("%s\n", disk->partition->partmap->name); + for (part = disk->partition; part; part = part->parent) + printf ("%s\n", part->partmap->name); } static int probe_raid_level (grub_disk_t disk) { + /* disk might be NULL in the case of a LVM physical volume with no LVM + signature. Ignore such cases here. */ + if (!disk) + return -1; + if (disk->dev->id != GRUB_DISK_DEVICE_RAID_ID) return -1; @@ -111,19 +120,19 @@ probe (const char *path, char *device_name) if (path == NULL) { -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) if (! grub_util_check_char_device (device_name)) - grub_util_error ("%s is not a character device.\n", device_name); + grub_util_error ("%s is not a character device", device_name); #else if (! grub_util_check_block_device (device_name)) - grub_util_error ("%s is not a block device.\n", device_name); + grub_util_error ("%s is not a block device", device_name); #endif } else device_name = grub_guess_root_device (path); if (! device_name) - grub_util_error ("cannot find a device for %s.\n", path); + grub_util_error ("cannot find a device for %s (is /dev mounted?)", path); if (print == PRINT_DEVICE) { @@ -133,7 +142,7 @@ probe (const char *path, char *device_name) drive_name = grub_util_get_grub_dev (device_name); if (! drive_name) - grub_util_error ("Cannot find a GRUB drive for %s. Check your device.map.\n", device_name); + grub_util_error ("cannot find a GRUB drive for %s. Check your device.map", device_name); if (print == PRINT_DRIVE) { @@ -253,13 +262,13 @@ probe (const char *path, char *device_name) grub_util_info ("reading %s via OS facilities", path); filebuf_via_sys = grub_util_read_image (path); - rel_path = make_system_path_relative_to_its_root (path); + rel_path = grub_make_system_path_relative_to_its_root (path); grub_path = xasprintf ("(%s)%s", drive_name, rel_path); free (rel_path); grub_util_info ("reading %s via GRUB facilities", grub_path); file = grub_file_open (grub_path); if (! file) - grub_util_error ("can not open %s via GRUB facilities", grub_path); + grub_util_error ("cannot open %s via GRUB facilities", grub_path); filebuf_via_grub = xmalloc (file->size); grub_file_read (file, filebuf_via_grub, file->size); @@ -309,7 +318,7 @@ usage (int status) { if (status) fprintf (stderr, - "Try ``%s --help'' for more information.\n", program_name); + "Try `%s --help' for more information.\n", program_name); else printf ("\ Usage: %s [OPTION]... [PATH|DEVICE]\n\ @@ -338,9 +347,8 @@ main (int argc, char *argv[]) char *argument; set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + + grub_util_init_nls (); /* Check for options. */ while (1) diff --git a/util/grub-reboot.in b/util/grub-reboot.in new file mode 100644 index 000000000..20f2b10bc --- /dev/null +++ b/util/grub-reboot.in @@ -0,0 +1,108 @@ +#! /bin/sh +# +# Set a default boot entry for GRUB, for the next boot only. +# Copyright (C) 2004,2009 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 . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ + +grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` +rootdir= + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +# Check the arguments. +for option in "$@"; do + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "grub-reboot (GNU GRUB ${PACKAGE_VERSION})" + exit 0 ;; + --root-directory=*) + rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if test "x$entry" != x; then + echo "More than one entry?" 1>&2 + usage + exit 1 + fi + entry="${option}" ;; + esac +done + +if test "x$entry" = x; then + echo "entry not specified." 1>&2 + usage + exit 1 +fi + +# Initialize these directories here, since ROOTDIR was initialized. +case "$host_os" in +netbsd* | openbsd*) + # Because /boot is used for the boot block in NetBSD and OpenBSD, use /grub + # instead of /boot/grub. + grub_prefix=`echo /grub | sed ${transform}` + bootdir=${rootdir} + ;; +*) + # Use /boot/grub by default. + bootdir=${rootdir}/boot + ;; +esac + +grubdir=${bootdir}/`echo grub | sed ${transform}` + +prev_saved_entry=`$grub_editenv ${grubdir}/grubenv list | sed -n 's/^saved_entry=//p'` +if [ "$prev_saved_entry" ]; then + $grub_editenv ${grubdir}/grubenv set prev_saved_entry="$prev_saved_entry" +else + # We need some non-empty value for prev_saved_entry so that GRUB will + # recognise that grub-reboot has been used and restore the previous + # saved entry. "0" is the same as an empty value, i.e. the first menu + # entry. + $grub_editenv ${grubdir}/grubenv set prev_saved_entry=0 +fi +$grub_editenv ${grubdir}/grubenv set saved_entry="$entry" + +# Bye. +exit 0 diff --git a/util/grub-script-check.c b/util/grub-script-check.c new file mode 100644 index 000000000..dc732aa01 --- /dev/null +++ b/util/grub-script-check.c @@ -0,0 +1,266 @@ +/* grub-script-check.c - check grub script file for syntax errors */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define _GNU_SOURCE 1 + +#include +#include +#include +#include +#include +#include + +#include "progname.h" + +void +grub_putchar (int c) +{ + putchar (c); +} + +int +grub_getkey (void) +{ + return -1; +} + +void +grub_refresh (void) +{ + fflush (stdout); +} + +char * +grub_script_execute_argument_to_string (struct grub_script_arg *arg __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_cmdline (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_cmdblock (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_cmdif (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_cmdfor (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_cmdwhile (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_menuentry (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute (struct grub_script *script) +{ + if (script == 0 || script->cmd == 0) + return 0; + + return script->cmd->exec (script->cmd); +} + +static struct option options[] = + { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, + "Try ``%s --help'' for more information.\n", program_name); + else + printf ("\ +Usage: %s [PATH]\n\ +\n\ +Checks GRUB script configuration file for syntax errors.\n\ +\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print the script as it is being processed\n\ +\n\ +Report bugs to <%s>.\n\ +", program_name, + PACKAGE_BUGREPORT); + exit (status); +} + +int +main (int argc, char *argv[]) +{ + char *argument; + char *input; + FILE *file = 0; + int verbose = 0; + struct grub_script *script; + + auto grub_err_t get_config_line (char **line, int cont); + grub_err_t get_config_line (char **line, int cont __attribute__ ((unused))) + { + int i; + char *cmdline = 0; + size_t len = 0; + ssize_t read; + + read = getline(&cmdline, &len, (file ?: stdin)); + if (read == -1) + { + *line = 0; + grub_errno = GRUB_ERR_READ_ERROR; + + if (cmdline) + free (cmdline); + return grub_errno; + } + + if (verbose) + grub_printf("%s", cmdline); + + for (i = 0; cmdline[i] != '\0'; i++) + { + /* Replace tabs and carriage returns with spaces. */ + if (cmdline[i] == '\t' || cmdline[i] == '\r') + cmdline[i] = ' '; + + /* Replace '\n' with '\0'. */ + if (cmdline[i] == '\n') + cmdline[i] = '\0'; + } + + *line = grub_strdup (cmdline); + + free (cmdline); + return 0; + } + + set_program_name (argv[0]); + grub_util_init_nls (); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "hvV", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbose = 1; + break; + + default: + usage (1); + break; + } + } + + /* Obtain ARGUMENT. */ + if (optind >= argc) + { + file = 0; /* read from stdin */ + } + else if (optind + 1 != argc) + { + fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); + usage (1); + } + else + { + argument = argv[optind]; + file = fopen (argument, "r"); + if (! file) + { + fprintf (stderr, "%s: %s: %s\n", program_name, argument, strerror(errno)); + usage (1); + } + } + + /* Initialize all modules. */ + grub_init_all (); + + do + { + input = 0; + get_config_line(&input, 0); + if (! input) + break; + + script = grub_script_parse (input, get_config_line); + if (script) + { + grub_script_execute (script); + grub_script_free (script); + } + + grub_free (input); + } while (script != 0); + + /* Free resources. */ + grub_fini_all (); + if (file) fclose (file); + + return (script == 0); +} diff --git a/util/grub-set-default.in b/util/grub-set-default.in new file mode 100644 index 000000000..4d7c10e8e --- /dev/null +++ b/util/grub-set-default.in @@ -0,0 +1,99 @@ +#! /bin/sh +# +# Set a default boot entry for GRUB. +# Copyright (C) 2004,2009 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 . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ + +grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` +rootdir= + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +# Check the arguments. +for option in "$@"; do + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "grub-set-default (GNU GRUB ${PACKAGE_VERSION})" + exit 0 ;; + --root-directory=*) + rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if test "x$entry" != x; then + echo "More than one entry?" 1>&2 + usage + exit 1 + fi + entry="${option}" ;; + esac +done + +if test "x$entry" = x; then + echo "entry not specified." 1>&2 + usage + exit 1 +fi + +# Initialize these directories here, since ROOTDIR was initialized. +case "$host_os" in +netbsd* | openbsd*) + # Because /boot is used for the boot block in NetBSD and OpenBSD, use /grub + # instead of /boot/grub. + grub_prefix=`echo /grub | sed ${transform}` + bootdir=${rootdir} + ;; +*) + # Use /boot/grub by default. + bootdir=${rootdir}/boot + ;; +esac + +grubdir=${bootdir}/`echo grub | sed ${transform}` + +$grub_editenv ${grubdir}/grubenv unset prev_saved_entry +$grub_editenv ${grubdir}/grubenv set saved_entry="$entry" + +# Bye. +exit 0 diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in index 96352cdae..d181fdffc 100644 --- a/util/grub.d/00_header.in +++ b/util/grub.d/00_header.in @@ -1,7 +1,7 @@ #! /bin/sh -e # grub-mkconfig helper script. -# Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. +# Copyright (C) 2006,2007,2008,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 @@ -34,26 +34,117 @@ for i in ${GRUB_PRELOAD_MODULES} ; do done if [ "x${GRUB_DEFAULT}" = "x" ] ; then GRUB_DEFAULT=0 ; fi +if [ "x${GRUB_DEFAULT}" = "xsaved" ] ; then GRUB_DEFAULT='${saved_entry}' ; fi if [ "x${GRUB_TIMEOUT}" = "x" ] ; then GRUB_TIMEOUT=5 ; fi if [ "x${GRUB_GFXMODE}" = "x" ] ; then GRUB_GFXMODE=640x480 ; fi cat << EOF -set default=${GRUB_DEFAULT} +if [ -s \$prefix/grubenv ]; then + load_env +fi +set default="${GRUB_DEFAULT}" +if [ \${prev_saved_entry} ]; then + set saved_entry=\${prev_saved_entry} + save_env saved_entry + set prev_saved_entry= + save_env prev_saved_entry + set boot_once=true +fi + +function savedefault { + if [ -z \${boot_once} ]; then + saved_entry=\${chosen} + save_env saved_entry + fi +} EOF -case ${GRUB_TERMINAL_INPUT}:${GRUB_TERMINAL_OUTPUT} in - serial:* | *:serial) +serial=0; +gfxterm=0; +for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do + if [ xserial = "x$x" ]; then + serial=1; + fi + if [ xgfxterm = "x$x" ]; then + gfxterm=1; + fi +done + +if [ "x$serial" = x1 ]; then if ! test -e ${grub_prefix}/serial.mod ; then - echo "Serial terminal not available on this platform." >&2 ; exit 1 + echo "Serial terminal not available on this platform." >&2 ; exit 1 fi if [ "x${GRUB_SERIAL_COMMAND}" = "x" ] ; then - grub_warn "Requested serial terminal but GRUB_SERIAL_COMMAND is unspecified. Default parameters will be used." - GRUB_SERIAL_COMMAND=serial + grub_warn "Requested serial terminal but GRUB_SERIAL_COMMAND is unspecified. Default parameters will be used." + GRUB_SERIAL_COMMAND=serial fi echo "${GRUB_SERIAL_COMMAND}" - ;; -esac +fi + +if [ "x$gfxterm" = x1 ]; then + # Make the font accessible + prepare_grub_to_access_device `${grub_probe} --target=device "${GRUB_FONT_PATH}"` + + cat << EOF +if loadfont `make_system_path_relative_to_its_root "${GRUB_FONT_PATH}"` ; then + set gfxmode=${GRUB_GFXMODE} + insmod gfxterm + insmod ${GRUB_VIDEO_BACKEND} +EOF + if [ "x$GRUB_THEME" != x ] && [ -f "$GRUB_THEME" ] \ + && is_path_readable_by_grub "$GRUB_THEME"; then + echo "Found theme: $GRUB_THEME" >&2 + prepare_grub_to_access_device `${grub_probe} --target=device "$GRUB_THEME"` | sed -e "s/^/ /" + cat << EOF + insmod gfxmenu +EOF + themedir="`dirname "$GRUB_THEME"`" + for x in "$themedir"/*.pf2 "$themedir"/f/*.pf2; do + if [ -f "$x" ]; then + cat << EOF + loadfont (\$root)`make_system_path_relative_to_its_root $x` +EOF + fi + done + if [ x"`echo "$themedir"/*.jpg`" != x"$themedir/*.jpg" ] || [ x"`echo "$themedir"/*.jpeg`" != x"$themedir/*.jpeg" ]; then + cat << EOF + insmod jpeg +EOF + fi + if [ x"`echo "$themedir"/*.png`" != x"$themedir/*.png" ]; then + cat << EOF + insmod png +EOF + fi + if [ x"`echo "$themedir"/*.tga`" != x"$themedir/*.tga" ]; then + cat << EOF + insmod tga +EOF + fi + + cat << EOF + set theme=(\$root)`make_system_path_relative_to_its_root $GRUB_THEME` +EOF + elif [ "x$GRUB_BACKGROUND" != x ] && [ -f "$GRUB_BACKGROUND" ] \ + && is_path_readable_by_grub "$GRUB_BACKGROUND"; then + echo "Found background: $GRUB_BACKGROUND" >&2 + case "$GRUB_BACKGROUND" in + *.png) reader=png ;; + *.tga) reader=tga ;; + *.jpg|*.jpeg) reader=jpeg ;; + *) echo "Unsupported image format" >&2; exit 1 ;; + esac + prepare_grub_to_access_device `${grub_probe} --target=device "$GRUB_BACKGROUND"` | sed -e "s/^/ /" + cat << EOF + insmod $reader + background_image -m stretch `make_system_path_relative_to_its_root "$GRUB_BACKGROUND"` +EOF + fi + cat << EOF +fi +EOF +fi case x${GRUB_TERMINAL_INPUT} in x) @@ -71,23 +162,6 @@ EOF esac case x${GRUB_TERMINAL_OUTPUT} in - xgfxterm) - # Make the font accessible - prepare_grub_to_access_device `${grub_probe} --target=device ${GRUB_FONT_PATH}` - - cat << EOF -if loadfont `make_system_path_relative_to_its_root ${GRUB_FONT_PATH}` ; then - set gfxmode=${GRUB_GFXMODE} - insmod gfxterm - insmod ${GRUB_VIDEO_BACKEND} - if terminal_output gfxterm ; then true ; else - # For backward compatibility with versions of terminal.mod that don't - # understand terminal_output - terminal gfxterm - fi -fi -EOF - ;; x) # Just use the native terminal ;; @@ -104,15 +178,16 @@ esac # Gettext variables and module if [ "x${LANG}" != "xC" ] ; then + prepare_grub_to_access_device $(${grub_probe} --target=device ${locale_dir}) cat << EOF -set locale_dir=${locale_dir} +set locale_dir=(\$root)$(make_system_path_relative_to_its_root ${locale_dir}) set lang=${grub_lang} -insmod gettext +insmod gettext EOF fi if [ "x${GRUB_HIDDEN_TIMEOUT}" != "x" ] ; then - if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then + if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then verbose= else verbose=" --verbose" @@ -127,3 +202,11 @@ else set timeout=${GRUB_TIMEOUT} EOF fi + +# Play an initial tune +if [ "x${GRUB_INIT_TUNE}" != "x" ] ; then + cat << EOF +insmod play +play ${GRUB_INIT_TUNE} +EOF +fi diff --git a/util/grub.d/10_hurd.in b/util/grub.d/10_hurd.in index e693c7dfa..e446f10e8 100644 --- a/util/grub.d/10_hurd.in +++ b/util/grub.d/10_hurd.in @@ -1,7 +1,7 @@ #! /bin/sh -e # grub-mkconfig helper script. -# Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. +# Copyright (C) 2006,2007,2008,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 @@ -21,10 +21,13 @@ exec_prefix=@exec_prefix@ libdir=@libdir@ . ${libdir}/grub/grub-mkconfig_lib +CLASS="--class gnu --class os" + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU else OS="${GRUB_DISTRIBUTOR} GNU/Hurd" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]' | cut -d' ' -f1) ${CLASS}" fi at_least_one=false @@ -32,13 +35,13 @@ all_of_them=true # FIXME: add l4 here? kernel= -for i in /boot/gnumach.gz /boot/gnumach ; do +for i in /boot/gnumach* ; do if test -e $i ; then basename=`basename $i` dirname=`dirname $i` rel_dirname=`make_system_path_relative_to_its_root $dirname` echo "Found GNU Mach: $i" >&2 - kernel=${rel_dirname}/${basename} + kernels="${kernels} ${rel_dirname}/${basename}" at_least_one=true fi done @@ -68,21 +71,53 @@ if ${all_of_them} && test -e /lib/ld.so.1 ; then : ; else exit 1 fi -cat << EOF -menuentry "${OS}" { +for kernel in ${kernels} +do + kernel_base="`basename "${kernel}"`" + KERNEL="using ${kernel_base}" + + cat << EOF +menuentry "${OS} ${KERNEL}" ${CLASS} { EOF -prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" -cat << EOF - multiboot ${kernel} root=device:${GRUB_DEVICE#/dev/} + prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" + cat << EOF + echo '$(gettext_quoted "Loading GNU Mach ...")' + multiboot ${kernel} root=device:${GRUB_DEVICE#/dev/} EOF -prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/" -cat << EOF - module /hurd/${hurd_fs}.static ${hurd_fs} --readonly \\ + save_default_entry | sed -e "s/^/\t/" + prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/" + cat << EOF + echo '$(gettext_quoted "Loading the Hurd ...")' + module /hurd/${hurd_fs}.static ${hurd_fs} --readonly \\ --multiboot-command-line='\${kernel-command-line}' \\ --host-priv-port='\${host-port}' \\ --device-master-port='\${device-port}' \\ --exec-server-task='\${exec-task}' -T typed '\${root}' \\ '\$(task-create)' '\$(task-resume)' - module /lib/ld.so.1 exec /hurd/exec '\$(exec-task=task-create)' + module /lib/ld.so.1 exec /hurd/exec '\$(exec-task=task-create)' } EOF + + cat << EOF +menuentry "${OS} ${KERNEL} (recovery mode)" ${CLASS} { +EOF + prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" + cat << EOF + echo '$(gettext_quoted "Loading GNU Mach ...")' + multiboot ${kernel} root=device:${GRUB_DEVICE#/dev/} -s +EOF + save_default_entry | sed -e "s/^/\t/" + prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/" + cat << EOF + echo '$(gettext_quoted "Loading the Hurd ...")' + module /hurd/${hurd_fs}.static ${hurd_fs} \\ + --multiboot-command-line='\${kernel-command-line}' \\ + --host-priv-port='\${host-port}' \\ + --device-master-port='\${device-port}' \\ + --exec-server-task='\${exec-task}' -T typed '\${root}' \\ + '\$(task-create)' '\$(task-resume)' + module /lib/ld.so.1 exec /hurd/exec '\$(exec-task=task-create)' +} +EOF + +done diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in index 1329bba1f..f63421617 100644 --- a/util/grub.d/10_kfreebsd.in +++ b/util/grub.d/10_kfreebsd.in @@ -1,7 +1,7 @@ #! /bin/sh -e # grub-mkconfig helper script. -# Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. +# Copyright (C) 2006,2007,2008,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 @@ -22,13 +22,20 @@ bindir=@bindir@ libdir=@libdir@ . ${libdir}/grub/grub-mkconfig_lib -. ${bindir}/gettext.sh export TEXTDOMAIN=@PACKAGE@ export TEXTDOMAINDIR=@localedir@ +CLASS="--class os" + case "${GRUB_DISTRIBUTOR}" in - Debian) OS="${GRUB_DISTRIBUTOR} GNU/kFreeBSD" ;; - *) OS="FreeBSD" ;; + Debian) + OS="${GRUB_DISTRIBUTOR} GNU/kFreeBSD" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]' | cut -d' ' -f1) --class gnu-kfreebsd --class gnu ${CLASS}" + ;; + *) + OS="FreeBSD" + CLASS="--class freebsd --class bsd ${CLASS}" + ;; esac kfreebsd_entry () @@ -37,19 +44,21 @@ kfreebsd_entry () version="$2" recovery="$3" # not used yet args="$4" # not used yet - title="$(gettext "%s, with kFreeBSD %s")" - printf "menuentry \"${title}\" {\n" "${os}" "${version}" + title="$(gettext_quoted "%s, with kFreeBSD %s")" + printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}" + save_default_entry | sed -e "s/^/\t/" if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" fi printf '%s\n' "${prepare_boot_cache}" cat << EOF - kfreebsd ${rel_dirname}/${basename} + echo '$(printf "$(gettext_quoted "Loading kernel of FreeBSD %s ...")" ${version})' + kfreebsd ${rel_dirname}/${basename} EOF if test -n "${devices}" ; then cat << EOF - kfreebsd_loadenv ${devices_rel_dirname}/${devices_basename} + kfreebsd_loadenv ${devices_rel_dirname}/${devices_basename} EOF fi diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in index 5fea5338e..802d59f51 100644 --- a/util/grub.d/10_linux.in +++ b/util/grub.d/10_linux.in @@ -1,7 +1,7 @@ #! /bin/sh -e # grub-mkconfig helper script. -# Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. +# Copyright (C) 2006,2007,2008,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 @@ -22,14 +22,16 @@ bindir=@bindir@ libdir=@libdir@ . ${libdir}/grub/grub-mkconfig_lib -. ${bindir}/gettext.sh export TEXTDOMAIN=@PACKAGE@ export TEXTDOMAINDIR=@localedir@ +CLASS="--class gnu-linux --class gnu --class os" + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU/Linux else OS="${GRUB_DISTRIBUTOR} GNU/Linux" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]' | cut -d' ' -f1) ${CLASS}" fi # loop-AES arranges things so that /dev/loop/X can be our root device, but @@ -54,20 +56,39 @@ linux_entry () recovery="$3" args="$4" if ${recovery} ; then - title="$(gettext "%s, with Linux %s (recovery mode)")" + title="$(gettext_quoted "%s, with Linux %s (recovery mode)")" else - title="$(gettext "%s, with Linux %s")" + title="$(gettext_quoted "%s, with Linux %s")" fi - printf "menuentry \"${title}\" {\n" "${os}" "${version}" + printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}" + save_default_entry | sed -e "s/^/\t/" + + # Use ELILO's generic "efifb" when it's known to be available. + # FIXME: We need an interface to select vesafb in case efifb can't be used. + if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then + if grep -qx "CONFIG_FB_EFI=y" /boot/config-${version} 2> /dev/null \ + && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" /boot/config-${version} 2> /dev/null; then + cat << EOF + set gfxpayload=keep +EOF + fi + else + cat << EOF + set gfxpayload=$GRUB_GFXPAYLOAD_LINUX +EOF + fi + if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" fi printf '%s\n' "${prepare_boot_cache}" cat << EOF + echo '$(printf "$(gettext_quoted "Loading Linux %s ...")" ${version})' linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args} EOF if test -n "${initrd}" ; then cat << EOF + echo '$(gettext_quoted "Loading initial ramdisk ...")' initrd ${rel_dirname}/${initrd} EOF fi diff --git a/util/grub.d/10_netbsd.in b/util/grub.d/10_netbsd.in new file mode 100644 index 000000000..7e5fb34ad --- /dev/null +++ b/util/grub.d/10_netbsd.in @@ -0,0 +1,86 @@ +#! /bin/sh -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,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 . + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +. ${libdir}/grub/grub-mkconfig_lib + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR=@localedir@ + +if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=NetBSD +else + OS="${GRUB_DISTRIBUTOR} NetBSD" +fi + +netbsd_entry () +{ + loader="$1" # "knetbsd" or "multiboot" + kernel="$2" # absolute path to the kernel file + recovery="$3" # is this is a recovery entry? + args="$4" # extra arguments appended to loader command + + kroot_device="$(echo ${GRUB_DEVICE} | sed -e 's,^/dev/r,,')" + if ${recovery} ; then + title="$(gettext_quoted "%s, with kernel %s (via %s, recovery mode)")" + else + title="$(gettext_quoted "%s, with kernel %s (via %s)")" + fi + + printf "menuentry \"${title}\" {\n" \ + "${OS}" "$(echo ${kernel} | sed -e 's,^.*/,,')" "${loader}" + printf "%s\n" "${prepare_boot_cache}" + case "${loader}" in + knetbsd) + printf "\tknetbsd %s -r %s %s\n" \ + "${kernel}" "${kroot_device}" "${GRUB_CMDLINE_NETBSD} ${args}" + ;; + multiboot) + printf "\tmultiboot %s %s root=%s %s\n" \ + "${kernel}" "${kernel}" "${kroot_device}" "${GRUB_CMDLINE_NETBSD} ${args}" + ;; + esac + printf "}\n" +} + +prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e 's,^, ,')" + +# We look for NetBSD kernels in / but not in subdirectories. We simply +# pick all statically linked ELF executable files (or links) in / with a +# name that starts with `netbsd'. +pattern="^ELF[^,]*executable.*statically linked" +for k in $(ls -t /netbsd*) ; do + if ! grub_file_is_not_garbage "$k" ; then + continue + fi + if ! ((file -bL "$k" | grep -q "${pattern}") || + (zcat "$k" | file -bL - | grep -q "${pattern}")) 2>/dev/null ; then + continue + fi + + echo "Found NetBSD kernel: $k" >&2 + netbsd_entry "knetbsd" "$k" false "${GRUB_CMDLINE_NETBSD_DEFAULT}" + netbsd_entry "multiboot" "$k" false "${GRUB_CMDLINE_NETBSD_DEFAULT}" + if [ "x${GRUB_DISABLE_NETBSD_RECOVERY}" != "xtrue" ]; then + netbsd_entry "knetbsd" "$k" true "-s" + netbsd_entry "multiboot" "$k" true "-s" + fi +done diff --git a/util/grub.d/10_windows.in b/util/grub.d/10_windows.in index 055258e29..7d221eac9 100644 --- a/util/grub.d/10_windows.in +++ b/util/grub.d/10_windows.in @@ -1,7 +1,7 @@ #! /bin/sh -e # grub-mkconfig helper script. -# Copyright (C) 2008 Free Software Foundation, Inc. +# Copyright (C) 2008,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 @@ -28,8 +28,8 @@ esac # Try C: even if current system is on other partition. case "$SYSTEMDRIVE" in - [Cc]:) dirlist="C:" ;; - [D-Zd-z]:) dirlist="C: $SYSTEMDRIVE" ;; + [Cc]:) drives="C:" ;; + [D-Zd-z]:) drives="C: $SYSTEMDRIVE" ;; *) exit 0 ;; esac @@ -51,7 +51,13 @@ get_os_name_from_boot_ini () } -for dir in $dirlist ; do +for drv in $drives ; do + + # Convert to Cygwin path. + dir=`cygpath "$drv"` + test -n "$dir" || continue + + needmap= # Check for Vista bootmgr. if [ -f "$dir"/bootmgr -a -f "$dir"/boot/bcd ] ; then @@ -60,6 +66,7 @@ for dir in $dirlist ; do # Check for NTLDR. elif [ -f "$dir"/ntldr -a -f "$dir"/ntdetect.com -a -f "$dir"/boot.ini ] ; then OS=`get_os_name_from_boot_ini "$dir"/boot.ini` || OS="Windows NT/2000/XP loader" + needmap=t else continue @@ -68,13 +75,16 @@ for dir in $dirlist ; do # Get boot /dev/ice. dev=`${grub_probe} -t device "$dir" 2>/dev/null` || continue - echo "Found $OS on $dir ($dev)" >&2 + echo "Found $OS on $drv ($dev)" >&2 cat << EOF menuentry "$OS" { EOF + save_default_entry | sed -e 's,^,\t,' prepare_grub_to_access_device "$dev" | sed 's,^,\t,' - + test -z "$needmap" || cat <. -hexify() -{ - echo -n "$@" | od -A n -t x1 - | sed -e 's/ //g' | tr '\n' '\0' -} +if [ "x$1" = "x" ]; then + echo "Filename required". +fi -echo "`hexify efi`{ `hexify device-properties`:" -ioreg -lw0 -p IODeviceTree -n efi -r -x |grep device-properties | sed 's/.*.*//;' -echo ";}" +ioreg -lw0 -p IODeviceTree -n efi -r -x |grep device-properties | sed 's/.*.*//;' | xxd -r -p > $1 diff --git a/util/i386/efi/grub-install.in b/util/i386/efi/grub-install.in index a5f97e346..9b4270ff6 100644 --- a/util/i386/efi/grub-install.in +++ b/util/i386/efi/grub-install.in @@ -29,11 +29,14 @@ PACKAGE_TARNAME=@PACKAGE_TARNAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ target_cpu=@target_cpu@ platform=@platform@ +host_os=@host_os@ pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` +localedir=@datadir@/locale grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}` grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` +grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` rootdir= grub_prefix=`echo /boot/grub | sed ${transform}` modules= @@ -142,8 +145,7 @@ else fi # Create the GRUB directory if it is not present. -test -d "$bootdir" || mkdir "$bootdir" || exit 1 -test -d "$grubdir" || mkdir "$grubdir" || exit 1 +mkdir -p "$grubdir" || exit 1 # If --recheck is specified, remove the device map, if present. if test $recheck = yes; then @@ -178,6 +180,18 @@ for file in ${pkglibdir}/*.mod ${pkglibdir}/*.lst; do cp -f $file ${grubdir} || exit 1 done +# Copy gettext files +mkdir -p ${grubdir}/locale/ +for dir in ${localedir}/*; do + if test -f "$dir/LC_MESSAGES/grub.mo"; then + cp -f "$dir/LC_MESSAGES/grub.mo" "${grubdir}/locale/${dir##*/}.mo" + fi +done + +if ! test -f ${grubdir}/grubenv; then + $grub_editenv ${grubdir}/grubenv create +fi + # Create the core image. First, auto-detect the filesystem module. fs_module=`$grub_probe --target=fs --device-map=${device_map} ${grubdir}` if test "x$fs_module" = xfat; then :; else @@ -188,7 +202,10 @@ fi # Then the partition map module. In order to support partition-less media, # this command is allowed to fail (--target=fs already grants us that the # filesystem will be accessible). -partmap_module=`$grub_probe --target=partmap --device-map=${device_map} ${grubdir} 2> /dev/null` +partmap_module= +for x in `$grub_probe --target=partmap --device ${grub_device} 2> /dev/null`; do + partmap_module="$partmap_module part_$x"; +done # Device abstraction module, if any (lvm, raid). devabstraction_module=`$grub_probe --target=abstraction --device-map=${device_map} ${grubdir}` @@ -196,7 +213,7 @@ devabstraction_module=`$grub_probe --target=abstraction --device-map=${device_ma # The order in this list is critical. Be careful when modifying it. modules="$modules $fs_module $partmap_module $devabstraction_module" -$grub_mkimage --output=${grubdir}/grub.efi $modules || exit 1 +$grub_mkimage -O ${target_cpu}-efi --output=${grubdir}/grub.efi $modules || exit 1 # Prompt the user to check if the device map is correct. echo "Installation finished. No error reported." diff --git a/util/i386/efi/grub-mkimage.c b/util/i386/efi/grub-mkimage.c deleted file mode 100644 index 7f5141531..000000000 --- a/util/i386/efi/grub-mkimage.c +++ /dev/null @@ -1,1112 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2005,2006,2007,2008,2009 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "progname.h" - -#if GRUB_TARGET_WORDSIZE == 32 -# define grub_le_to_cpu(val) grub_le_to_cpu32(val) -#elif GRUB_TARGET_WORDSIZE == 64 -# define grub_le_to_cpu(val) grub_le_to_cpu64(val) -#endif - -static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; - -static inline Elf_Addr -align_address (Elf_Addr addr, unsigned alignment) -{ - return (addr + alignment - 1) & ~(alignment - 1); -} - -static inline Elf_Addr -align_pe32_section (Elf_Addr addr) -{ - return align_address (addr, GRUB_PE32_SECTION_ALIGNMENT); -} - -/* Read the whole kernel image. Return the pointer to a read image, - and store the size in bytes in *SIZE. */ -static char * -read_kernel_image (const char *dir, size_t *size) -{ - char *kernel_image; - char *kernel_path; - - kernel_path = grub_util_get_path (dir, "kernel.img"); - *size = grub_util_get_image_size (kernel_path); - kernel_image = grub_util_read_image (kernel_path); - free (kernel_path); - - return kernel_image; -} - -/* Return if the ELF header is valid. */ -static int -check_elf_header (Elf_Ehdr *e, size_t size) -{ - if (size < sizeof (*e) - || e->e_ident[EI_MAG0] != ELFMAG0 - || e->e_ident[EI_MAG1] != ELFMAG1 - || e->e_ident[EI_MAG2] != ELFMAG2 - || e->e_ident[EI_MAG3] != ELFMAG3 - || e->e_ident[EI_VERSION] != EV_CURRENT - || e->e_version != grub_cpu_to_le32 (EV_CURRENT) - || ((e->e_ident[EI_CLASS] != ELFCLASS32) && - (e->e_ident[EI_CLASS] != ELFCLASS64)) - || e->e_ident[EI_DATA] != ELFDATA2LSB - || ((e->e_machine != grub_cpu_to_le16 (EM_386)) && - (e->e_machine != grub_cpu_to_le16 (EM_X86_64)))) - return 0; - - return 1; -} - -/* Return the starting address right after the header, - aligned by the section alignment. Allocate 4 section tables for - .text, .data, .reloc, and mods. */ -static Elf_Addr -get_starting_section_address (void) -{ - return align_pe32_section (sizeof (struct grub_pe32_header) - + 4 * sizeof (struct grub_pe32_section_table)); -} - -/* Determine if this section is a text section. Return false if this - section is not allocated. */ -static int -is_text_section (Elf_Shdr *s) -{ - return ((s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC)) - == grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC)); -} - -/* Determine if this section is a data section. This assumes that - BSS is also a data section, since the converter initializes BSS - when producing PE32 to avoid a bug in EFI implementations. */ -static int -is_data_section (Elf_Shdr *s) -{ - return (s->sh_flags & grub_cpu_to_le32 (SHF_ALLOC) - && ! (s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR))); -} - -/* Locate section addresses by merging code sections and data sections - into .text and .data, respectively. Return the array of section - addresses. */ -static Elf_Addr * -locate_sections (Elf_Shdr *sections, Elf_Half section_entsize, - Elf_Half num_sections, const char *strtab) -{ - int i; - Elf_Addr current_address; - Elf_Addr *section_addresses; - Elf_Shdr *s; - - section_addresses = xmalloc (sizeof (*section_addresses) * num_sections); - memset (section_addresses, 0, sizeof (*section_addresses) * num_sections); - - current_address = get_starting_section_address (); - - /* .text */ - for (i = 0, s = sections; - i < num_sections; - i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) - if (is_text_section (s)) - { - Elf_Word align = grub_le_to_cpu32 (s->sh_addralign); - const char *name = strtab + grub_le_to_cpu32 (s->sh_name); - - if (align) - current_address = align_address (current_address, align); - - grub_util_info ("locating the section %s at 0x%x", - name, current_address); - section_addresses[i] = current_address; - current_address += grub_le_to_cpu32 (s->sh_size); - } - - current_address = align_pe32_section (current_address); - - /* .data */ - for (i = 0, s = sections; - i < num_sections; - i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) - if (is_data_section (s)) - { - Elf_Word align = grub_le_to_cpu32 (s->sh_addralign); - const char *name = strtab + grub_le_to_cpu32 (s->sh_name); - - if (align) - current_address = align_address (current_address, align); - - grub_util_info ("locating the section %s at 0x%x", - name, current_address); - section_addresses[i] = current_address; - current_address += grub_le_to_cpu32 (s->sh_size); - } - - return section_addresses; -} - -/* Return the symbol table section, if any. */ -static Elf_Shdr * -find_symtab_section (Elf_Shdr *sections, - Elf_Half section_entsize, Elf_Half num_sections) -{ - int i; - Elf_Shdr *s; - - for (i = 0, s = sections; - i < num_sections; - i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) - if (s->sh_type == grub_cpu_to_le32 (SHT_SYMTAB)) - return s; - - return 0; -} - -/* Return the address of the string table. */ -static const char * -find_strtab (Elf_Ehdr *e, Elf_Shdr *sections, Elf_Half section_entsize) -{ - Elf_Shdr *s; - char *strtab; - - s = (Elf_Shdr *) ((char *) sections - + grub_le_to_cpu16 (e->e_shstrndx) * section_entsize); - strtab = (char *) e + grub_le_to_cpu32 (s->sh_offset); - return strtab; -} - -/* Relocate symbols; note that this function overwrites the symbol table. - Return the address of a start symbol. */ -static Elf_Addr -relocate_symbols (Elf_Ehdr *e, Elf_Shdr *sections, - Elf_Shdr *symtab_section, Elf_Addr *section_addresses, - Elf_Half section_entsize, Elf_Half num_sections) -{ - Elf_Word symtab_size, sym_size, num_syms; - Elf_Off symtab_offset; - Elf_Addr start_address = 0; - Elf_Sym *sym; - Elf_Word i; - Elf_Shdr *strtab_section; - const char *strtab; - - strtab_section - = (Elf_Shdr *) ((char *) sections - + (grub_le_to_cpu32 (symtab_section->sh_link) - * section_entsize)); - strtab = (char *) e + grub_le_to_cpu32 (strtab_section->sh_offset); - - symtab_size = grub_le_to_cpu32 (symtab_section->sh_size); - sym_size = grub_le_to_cpu32 (symtab_section->sh_entsize); - symtab_offset = grub_le_to_cpu32 (symtab_section->sh_offset); - num_syms = symtab_size / sym_size; - - for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset); - i < num_syms; - i++, sym = (Elf_Sym *) ((char *) sym + sym_size)) - { - Elf_Section index; - const char *name; - - name = strtab + grub_le_to_cpu32 (sym->st_name); - - index = grub_le_to_cpu16 (sym->st_shndx); - if (index == STN_ABS) - { - continue; - } - else if ((index == STN_UNDEF)) - { - if (sym->st_name) - grub_util_error ("undefined symbol %s", name); - else - continue; - } - else if (index >= num_sections) - grub_util_error ("section %d does not exist", index); - - sym->st_value = (grub_le_to_cpu32 (sym->st_value) - + section_addresses[index]); - grub_util_info ("locating %s at 0x%x", name, sym->st_value); - - if (! start_address) - if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0) - start_address = sym->st_value; - } - - return start_address; -} - -/* Return the address of a symbol at the index I in the section S. */ -static Elf_Addr -get_symbol_address (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i) -{ - Elf_Sym *sym; - - sym = (Elf_Sym *) ((char *) e - + grub_le_to_cpu32 (s->sh_offset) - + i * grub_le_to_cpu32 (s->sh_entsize)); - return sym->st_value; -} - -/* Return the address of a modified value. */ -static Elf_Addr * -get_target_address (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset) -{ - return (Elf_Addr *) ((char *) e + grub_le_to_cpu32 (s->sh_offset) + offset); -} - -/* Deal with relocation information. This function relocates addresses - within the virtual address space starting from 0. So only relative - addresses can be fully resolved. Absolute addresses must be relocated - again by a PE32 relocator when loaded. */ -static void -relocate_addresses (Elf_Ehdr *e, Elf_Shdr *sections, - Elf_Addr *section_addresses, - Elf_Half section_entsize, Elf_Half num_sections, - const char *strtab) -{ - Elf_Half i; - Elf_Shdr *s; - - for (i = 0, s = sections; - i < num_sections; - i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) - if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) || - (s->sh_type == grub_cpu_to_le32 (SHT_RELA))) - { - Elf_Rela *r; - Elf_Word rtab_size, r_size, num_rs; - Elf_Off rtab_offset; - Elf_Shdr *symtab_section; - Elf_Word target_section_index; - Elf_Addr target_section_addr; - Elf_Shdr *target_section; - Elf_Word j; - - symtab_section = (Elf_Shdr *) ((char *) sections - + (grub_le_to_cpu32 (s->sh_link) - * section_entsize)); - target_section_index = grub_le_to_cpu32 (s->sh_info); - target_section_addr = section_addresses[target_section_index]; - target_section = (Elf_Shdr *) ((char *) sections - + (target_section_index - * section_entsize)); - - grub_util_info ("dealing with the relocation section %s for %s", - strtab + grub_le_to_cpu32 (s->sh_name), - strtab + grub_le_to_cpu32 (target_section->sh_name)); - - rtab_size = grub_le_to_cpu32 (s->sh_size); - r_size = grub_le_to_cpu32 (s->sh_entsize); - rtab_offset = grub_le_to_cpu32 (s->sh_offset); - num_rs = rtab_size / r_size; - - for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); - j < num_rs; - j++, r = (Elf_Rela *) ((char *) r + r_size)) - { - Elf_Addr info; - Elf_Addr offset; - Elf_Addr sym_addr; - Elf_Addr *target; - Elf_Addr addend; - - offset = grub_le_to_cpu (r->r_offset); - target = get_target_address (e, target_section, offset); - info = grub_le_to_cpu (r->r_info); - sym_addr = get_symbol_address (e, symtab_section, - ELF_R_SYM (info)); - - addend = (s->sh_type == grub_cpu_to_le32 (SHT_RELA)) ? - r->r_addend : 0; - - switch (ELF_R_TYPE (info)) - { -#if GRUB_TARGET_SIZEOF_VOID_P == 4 - case R_386_NONE: - break; - - case R_386_32: - /* This is absolute. */ - *target = grub_cpu_to_le32 (grub_le_to_cpu32 (*target) - + addend + sym_addr); - grub_util_info ("relocating an R_386_32 entry to 0x%x at the offset 0x%x", - *target, offset); - break; - - case R_386_PC32: - /* This is relative. */ - *target = grub_cpu_to_le32 (grub_le_to_cpu32 (*target) - + addend + sym_addr - - target_section_addr - offset); - grub_util_info ("relocating an R_386_PC32 entry to 0x%x at the offset 0x%x", - *target, offset); - break; - -#else - - case R_X86_64_NONE: - break; - - case R_X86_64_64: - *target = grub_cpu_to_le64 (grub_le_to_cpu64 (*target) - + addend + sym_addr); - grub_util_info ("relocating an R_X86_64_64 entry to 0x%llx at the offset 0x%llx", - *target, offset); - break; - - case R_X86_64_PC32: - { - grub_uint32_t *t32 = (grub_uint32_t *) target; - *t32 = grub_cpu_to_le64 (grub_le_to_cpu32 (*t32) - + addend + sym_addr - - target_section_addr - offset); - grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%llx", - *t32, offset); - break; - } - - case R_X86_64_32: - case R_X86_64_32S: - { - grub_uint32_t *t32 = (grub_uint32_t *) target; - *t32 = grub_cpu_to_le64 (grub_le_to_cpu32 (*t32) - + addend + sym_addr); - grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%llx", - *t32, offset); - break; - } - -#endif - default: - grub_util_error ("unknown relocation type %d", - ELF_R_TYPE (info)); - break; - } - } - } -} - -void -write_padding (FILE *out, size_t size) -{ - size_t i; - - for (i = 0; i < size; i++) - if (fputc (0, out) == EOF) - grub_util_error ("padding failed"); -} - -/* Add a PE32's fixup entry for a relocation. Return the resulting address - after having written to the file OUT. */ -Elf_Addr -add_fixup_entry (struct grub_pe32_fixup_block **block, grub_uint16_t type, - Elf_Addr addr, int flush, Elf_Addr current_address, - FILE *out) -{ - struct grub_pe32_fixup_block *b = *block; - - /* First, check if it is necessary to write out the current block. */ - if (b) - { - if (flush || addr < b->page_rva || b->page_rva + 0x1000 <= addr) - { - grub_uint32_t size; - - if (flush) - { - /* Add as much padding as necessary to align the address - with a section boundary. */ - Elf_Addr next_address; - unsigned padding_size; - size_t index; - - next_address = current_address + b->block_size; - padding_size = ((align_pe32_section (next_address) - - next_address) - >> 1); - index = ((b->block_size - sizeof (*b)) >> 1); - grub_util_info ("adding %d padding fixup entries", padding_size); - while (padding_size--) - { - b->entries[index++] = 0; - b->block_size += 2; - } - } - else if (b->block_size & (8 - 1)) - { - /* If not aligned with a 32-bit boundary, add - a padding entry. */ - size_t index; - - grub_util_info ("adding a padding fixup entry"); - index = ((b->block_size - sizeof (*b)) >> 1); - b->entries[index] = 0; - b->block_size += 2; - } - - /* Flush it. */ - grub_util_info ("writing %d bytes of a fixup block starting at 0x%x", - b->block_size, b->page_rva); - size = b->block_size; - current_address += size; - b->page_rva = grub_cpu_to_le32 (b->page_rva); - b->block_size = grub_cpu_to_le32 (b->block_size); - if (fwrite (b, size, 1, out) != 1) - grub_util_error ("write failed"); - free (b); - *block = b = 0; - } - } - - if (! flush) - { - grub_uint16_t entry; - size_t index; - - /* If not allocated yet, allocate a block with enough entries. */ - if (! b) - { - *block = b = xmalloc (sizeof (*b) + 2 * 0x1000); - - /* The spec does not mention the requirement of a Page RVA. - Here, align the address with a 4K boundary for safety. */ - b->page_rva = (addr & ~(0x1000 - 1)); - b->block_size = sizeof (*b); - } - - /* Sanity check. */ - if (b->block_size >= sizeof (*b) + 2 * 0x1000) - grub_util_error ("too many fixup entries"); - - /* Add a new entry. */ - index = ((b->block_size - sizeof (*b)) >> 1); - entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva); - b->entries[index] = grub_cpu_to_le16 (entry); - b->block_size += 2; - } - - return current_address; -} - -/* Write out zeros to make space for the header. */ -static Elf_Addr -make_header_space (FILE *out) -{ - Elf_Addr addr; - - addr = get_starting_section_address (); - write_padding (out, addr); - - return addr; -} - -/* Write text sections. */ -static Elf_Addr -write_text_sections (FILE *out, Elf_Addr current_address, - Elf_Ehdr *e, Elf_Shdr *sections, - Elf_Half section_entsize, Elf_Half num_sections, - const char *strtab) -{ - Elf_Half i; - Elf_Shdr *s; - Elf_Addr addr; - - for (i = 0, s = sections; - i < num_sections; - i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) - if (is_text_section (s)) - { - Elf_Word align = grub_le_to_cpu32 (s->sh_addralign); - Elf_Off offset = grub_le_to_cpu32 (s->sh_offset); - Elf_Word size = grub_le_to_cpu32 (s->sh_size); - const char *name = strtab + grub_le_to_cpu32 (s->sh_name); - - if (align) - { - addr = align_address (current_address, align); - if (current_address != addr) - { - grub_util_info ("padding %d bytes for the ELF section alignment", - addr - current_address); - write_padding (out, addr - current_address); - current_address = addr; - } - } - - grub_util_info ("writing the text section %s at 0x%x", - name, current_address); - - if (fwrite ((char *) e + offset, size, 1, out) != 1) - grub_util_error ("write failed"); - - current_address += size; - } - - addr = align_pe32_section (current_address); - if (addr != current_address) - { - grub_util_info ("padding %d bytes for the PE32 section alignment", - addr - current_address); - write_padding (out, addr - current_address); - } - - return addr; -} - -/* Write data sections. */ -static Elf_Addr -write_data_sections (FILE *out, Elf_Addr current_address, - Elf_Ehdr *e, Elf_Shdr *sections, - Elf_Half section_entsize, Elf_Half num_sections, - const char *strtab) -{ - Elf_Half i; - Elf_Shdr *s; - Elf_Addr addr; - - for (i = 0, s = sections; - i < num_sections; - i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) - if (is_data_section (s)) - { - Elf_Word align = grub_le_to_cpu32 (s->sh_addralign); - Elf_Off offset = grub_le_to_cpu32 (s->sh_offset); - Elf_Word size = grub_le_to_cpu32 (s->sh_size); - const char *name = strtab + grub_le_to_cpu32 (s->sh_name); - - if (align) - { - addr = align_address (current_address, align); - if (current_address != addr) - { - grub_util_info ("padding %d bytes for the ELF section alignment", - addr - current_address); - write_padding (out, addr - current_address); - current_address = addr; - } - } - - grub_util_info ("writing the data section %s at 0x%x", - name, current_address); - - if (s->sh_type == grub_cpu_to_le32 (SHT_NOBITS)) - write_padding (out, size); - else - if (fwrite ((char *) e + offset, size, 1, out) != 1) - grub_util_error ("write failed"); - - current_address += size; - } - - addr = align_pe32_section (current_address); - if (addr != current_address) - { - grub_util_info ("padding %d bytes for the PE32 section alignment", - addr - current_address); - write_padding (out, addr - current_address); - } - - return addr; -} - -/* Write modules. */ -static Elf_Addr -make_mods_section (FILE *out, Elf_Addr current_address, - const char *dir, char *mods[]) -{ - struct grub_util_path_list *path_list; - grub_size_t total_module_size; - struct grub_util_path_list *p; - struct grub_module_info modinfo; - Elf_Addr addr; - - memset (&modinfo, 0, sizeof (modinfo)); - - path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); - - total_module_size = sizeof (struct grub_module_info); - for (p = path_list; p; p = p->next) - { - total_module_size += (grub_util_get_image_size (p->name) - + sizeof (struct grub_module_header)); - } - - grub_util_info ("the total module size is 0x%x", total_module_size); - - modinfo.magic = grub_cpu_to_le32 (GRUB_MODULE_MAGIC); - modinfo.offset = grub_cpu_to_le32 (sizeof (modinfo)); - modinfo.size = grub_cpu_to_le32 (total_module_size); - - if (fwrite (&modinfo, sizeof (modinfo), 1, out) != 1) - grub_util_error ("write failed"); - - for (p = path_list; p; p = p->next) - { - struct grub_module_header header; - size_t mod_size; - char *mod_image; - - memset (&header, 0, sizeof (header)); - - grub_util_info ("adding module %s", p->name); - - mod_size = grub_util_get_image_size (p->name); - header.type = OBJ_TYPE_ELF; - header.size = grub_host_to_target32 (mod_size + sizeof (header)); - - mod_image = grub_util_read_image (p->name); - - if (fwrite (&header, sizeof (header), 1, out) != 1 - || fwrite (mod_image, mod_size, 1, out) != 1) - grub_util_error ("write failed"); - - free (mod_image); - } - - for (p = path_list; p; ) - { - struct grub_util_path_list *q; - - q = p->next; - free (p); - p = q; - } - - current_address += total_module_size; - - addr = align_pe32_section (current_address); - if (addr != current_address) - { - grub_util_info ("padding %d bytes for the PE32 section alignment", - addr - current_address); - write_padding (out, addr - current_address); - } - - return addr; -} - -/* Make a .reloc section. */ -static Elf_Addr -make_reloc_section (FILE *out, Elf_Addr current_address, Elf_Ehdr *e, - Elf_Addr *section_addresses, Elf_Shdr *sections, - Elf_Half section_entsize, Elf_Half num_sections, - const char *strtab) -{ - Elf_Half i; - Elf_Shdr *s; - struct grub_pe32_fixup_block *fixup_block = 0; - - for (i = 0, s = sections; - i < num_sections; - i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) - if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) || - (s->sh_type == grub_cpu_to_le32 (SHT_RELA))) - { - Elf_Rel *r; - Elf_Word rtab_size, r_size, num_rs; - Elf_Off rtab_offset; - Elf_Addr section_address; - Elf_Word j; - - grub_util_info ("translating the relocation section %s", - strtab + grub_le_to_cpu32 (s->sh_name)); - - rtab_size = grub_le_to_cpu32 (s->sh_size); - r_size = grub_le_to_cpu32 (s->sh_entsize); - rtab_offset = grub_le_to_cpu32 (s->sh_offset); - num_rs = rtab_size / r_size; - - section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)]; - - for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset); - j < num_rs; - j++, r = (Elf_Rel *) ((char *) r + r_size)) - { - Elf_Addr info; - Elf_Addr offset; - - offset = grub_le_to_cpu32 (r->r_offset); - info = grub_le_to_cpu32 (r->r_info); - - /* Necessary to relocate only absolute addresses. */ -#if GRUB_TARGET_SIZEOF_VOID_P == 4 - if (ELF_R_TYPE (info) == R_386_32) - { - Elf_Addr addr; - - addr = section_address + offset; - grub_util_info ("adding a relocation entry for 0x%x", addr); - current_address = add_fixup_entry (&fixup_block, - GRUB_PE32_REL_BASED_HIGHLOW, - addr, 0, current_address, - out); - } -#else - if ((ELF_R_TYPE (info) == R_X86_64_32) || - (ELF_R_TYPE (info) == R_X86_64_32S)) - { - grub_util_error ("Can\'t add fixup entry for R_X86_64_32(S)"); - } - else if (ELF_R_TYPE (info) == R_X86_64_64) - { - Elf_Addr addr; - - addr = section_address + offset; - grub_util_info ("adding a relocation entry for 0x%llx", addr); - current_address = add_fixup_entry (&fixup_block, - GRUB_PE32_REL_BASED_DIR64, - addr, - 0, current_address, - out); - } -#endif - } - } - - current_address = add_fixup_entry (&fixup_block, 0, 0, 1, - current_address, out); - - return current_address; -} - -/* Create the header. */ -static void -make_header (FILE *out, Elf_Addr text_address, Elf_Addr data_address, - Elf_Addr mods_address, Elf_Addr reloc_address, - Elf_Addr end_address, Elf_Addr start_address) -{ - struct grub_pe32_header header; - struct grub_pe32_coff_header *c; - struct grub_pe32_optional_header *o; - struct grub_pe32_section_table text_section, data_section; - struct grub_pe32_section_table mods_section, reloc_section; - - /* The magic. */ - memset (&header, 0, sizeof (header)); - memcpy (header.msdos_stub, stub, sizeof (header.msdos_stub)); - memcpy (header.signature, "PE\0\0", sizeof (header.signature)); - - /* The COFF file header. */ - c = &header.coff_header; -#if GRUB_TARGET_SIZEOF_VOID_P == 4 - c->machine = grub_cpu_to_le16 (GRUB_PE32_MACHINE_I386); -#else - c->machine = grub_cpu_to_le16 (GRUB_PE32_MACHINE_X86_64); -#endif - - c->num_sections = grub_cpu_to_le16 (4); - c->time = grub_cpu_to_le32 (time (0)); - c->optional_header_size = grub_cpu_to_le16 (sizeof (header.optional_header)); - c->characteristics = grub_cpu_to_le16 (GRUB_PE32_EXECUTABLE_IMAGE - | GRUB_PE32_LINE_NUMS_STRIPPED -#if GRUB_TARGET_SIZEOF_VOID_P == 4 - | GRUB_PE32_32BIT_MACHINE -#endif - | GRUB_PE32_LOCAL_SYMS_STRIPPED - | GRUB_PE32_DEBUG_STRIPPED); - - /* The PE Optional header. */ - o = &header.optional_header; - o->magic = grub_cpu_to_le16 (GRUB_PE32_PE32_MAGIC); - o->code_size = grub_cpu_to_le32 (data_address - text_address); - o->data_size = grub_cpu_to_le32 (reloc_address - data_address); - o->bss_size = 0; - o->entry_addr = grub_cpu_to_le32 (start_address); - o->code_base = grub_cpu_to_le32 (text_address); -#if GRUB_TARGET_SIZEOF_VOID_P == 4 - o->data_base = grub_cpu_to_le32 (data_address); -#endif - o->image_base = 0; - o->section_alignment = grub_cpu_to_le32 (GRUB_PE32_SECTION_ALIGNMENT); - o->file_alignment = grub_cpu_to_le32 (GRUB_PE32_FILE_ALIGNMENT); - o->image_size = grub_cpu_to_le32 (end_address); - o->header_size = grub_cpu_to_le32 (text_address); - o->subsystem = grub_cpu_to_le16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); - - /* Do these really matter? */ - o->stack_reserve_size = grub_cpu_to_le32 (0x10000); - o->stack_commit_size = grub_cpu_to_le32 (0x10000); - o->heap_reserve_size = grub_cpu_to_le32 (0x10000); - o->heap_commit_size = grub_cpu_to_le32 (0x10000); - - o->num_data_directories = grub_cpu_to_le32 (GRUB_PE32_NUM_DATA_DIRECTORIES); - - o->base_relocation_table.rva = grub_cpu_to_le32 (reloc_address); - o->base_relocation_table.size = grub_cpu_to_le32 (end_address - - reloc_address); - - /* The sections. */ - memset (&text_section, 0, sizeof (text_section)); - strcpy (text_section.name, ".text"); - text_section.virtual_size = grub_cpu_to_le32 (data_address - text_address); - text_section.virtual_address = grub_cpu_to_le32 (text_address); - text_section.raw_data_size = grub_cpu_to_le32 (data_address - text_address); - text_section.raw_data_offset = grub_cpu_to_le32 (text_address); - text_section.characteristics = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_CODE - | GRUB_PE32_SCN_MEM_EXECUTE - | GRUB_PE32_SCN_MEM_READ); - - memset (&data_section, 0, sizeof (data_section)); - strcpy (data_section.name, ".data"); - data_section.virtual_size = grub_cpu_to_le32 (mods_address - data_address); - data_section.virtual_address = grub_cpu_to_le32 (data_address); - data_section.raw_data_size = grub_cpu_to_le32 (mods_address - data_address); - data_section.raw_data_offset = grub_cpu_to_le32 (data_address); - data_section.characteristics - = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA - | GRUB_PE32_SCN_MEM_READ - | GRUB_PE32_SCN_MEM_WRITE); - - memset (&mods_section, 0, sizeof (mods_section)); - strcpy (mods_section.name, "mods"); - mods_section.virtual_size = grub_cpu_to_le32 (reloc_address - mods_address); - mods_section.virtual_address = grub_cpu_to_le32 (mods_address); - mods_section.raw_data_size = grub_cpu_to_le32 (reloc_address - mods_address); - mods_section.raw_data_offset = grub_cpu_to_le32 (mods_address); - mods_section.characteristics - = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA - | GRUB_PE32_SCN_MEM_READ - | GRUB_PE32_SCN_MEM_WRITE); - - memset (&reloc_section, 0, sizeof (reloc_section)); - strcpy (reloc_section.name, ".reloc"); - reloc_section.virtual_size = grub_cpu_to_le32 (end_address - reloc_address); - reloc_section.virtual_address = grub_cpu_to_le32 (reloc_address); - reloc_section.raw_data_size = grub_cpu_to_le32 (end_address - reloc_address); - reloc_section.raw_data_offset = grub_cpu_to_le32 (reloc_address); - reloc_section.characteristics - = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA - | GRUB_PE32_SCN_MEM_DISCARDABLE - | GRUB_PE32_SCN_MEM_READ); - - /* Write them out. */ - if (fseeko (out, 0, SEEK_SET) < 0) - grub_util_error ("seek failed"); - - if (fwrite (&header, sizeof (header), 1, out) != 1 - || fwrite (&text_section, sizeof (text_section), 1, out) != 1 - || fwrite (&data_section, sizeof (data_section), 1, out) != 1 - || fwrite (&mods_section, sizeof (mods_section), 1, out) != 1 - || fwrite (&reloc_section, sizeof (reloc_section), 1, out) != 1) - grub_util_error ("write failed"); -} - -/* Convert an ELF relocatable object into an EFI Application (PE32). */ -void -convert_elf (const char *dir, char *prefix, FILE *out, char *mods[]) -{ - char *kernel_image; - size_t kernel_size; - const char *strtab; - Elf_Ehdr *e; - Elf_Shdr *sections; - Elf_Off section_offset; - Elf_Half section_entsize; - Elf_Half num_sections; - Elf_Addr *section_addresses; - Elf_Shdr *symtab_section; - Elf_Addr start_address; - Elf_Addr text_address, data_address, reloc_address, mods_address; - Elf_Addr end_address; - Elf_Shdr *s; - int i; - - /* Get the kernel image and check the format. */ - kernel_image = read_kernel_image (dir, &kernel_size); - e = (Elf_Ehdr *) kernel_image; - if (! check_elf_header (e, kernel_size)) - grub_util_error ("invalid ELF header"); - - section_offset = grub_cpu_to_le32 (e->e_shoff); - section_entsize = grub_cpu_to_le16 (e->e_shentsize); - num_sections = grub_cpu_to_le16 (e->e_shnum); - - if (kernel_size < section_offset + section_entsize * num_sections) - grub_util_error ("invalid ELF format"); - - sections = (Elf_Shdr *) (kernel_image + section_offset); - strtab = find_strtab (e, sections, section_entsize); - - for (i = 0, s = sections; - i < num_sections; - i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) - if (is_text_section (s)) - { - Elf_Off offset = grub_le_to_cpu32 (s->sh_offset); - - if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END) - grub_util_error ("prefix too long"); - - strcpy (kernel_image + offset + GRUB_KERNEL_MACHINE_PREFIX, prefix); - break; - } - - /* Relocate sections then symbols in the virtual address space. */ - section_addresses = locate_sections (sections, section_entsize, - num_sections, strtab); - - symtab_section = find_symtab_section (sections, - section_entsize, num_sections); - if (! symtab_section) - grub_util_error ("no symbol table"); - - start_address = relocate_symbols (e, sections, symtab_section, - section_addresses, section_entsize, - num_sections); - if (start_address == 0) - grub_util_error ("start symbol is not defined"); - - /* Resolve addresses in the virtual address space. */ - relocate_addresses (e, sections, section_addresses, section_entsize, - num_sections, strtab); - - /* Generate a PE32 image file. The strategy is to dump binary data first, - then fill up the header. */ - text_address = make_header_space (out); - data_address = write_text_sections (out, text_address, e, sections, - section_entsize, num_sections, - strtab); - mods_address = write_data_sections (out, data_address, e, sections, - section_entsize, num_sections, - strtab); - reloc_address = make_mods_section (out, mods_address, dir, mods); - end_address = make_reloc_section (out, reloc_address, e, section_addresses, - sections, section_entsize, num_sections, - strtab); - make_header (out, text_address, data_address, mods_address, - reloc_address, end_address, start_address); - - /* Clean up. */ - free (section_addresses); - free (kernel_image); -} - -static struct option options[] = - { - {"directory", required_argument, 0, 'd'}, - {"prefix", required_argument, 0, 'p'}, - {"output", required_argument, 0, 'o'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {"verbose", no_argument, 0, 'v'}, - { 0, 0, 0, 0 } - }; - -static void -usage (int status) -{ - if (status) - fprintf (stderr, "Try ``grub-mkimage --help'' for more information.\n"); - else - printf ("\ -Usage: grub-mkimage -o FILE [OPTION]... [MODULES]\n\ -\n\ -Make a bootable image of GRUB.\n\ -\n\ - -d, --directory=DIR use images and modules under DIR [default=%s]\n\ - -p, --prefix=DIR set grub_prefix directory [default=%s]\n\ - -o, --output=FILE output a generated image to FILE\n\ - -h, --help display this message and exit\n\ - -V, --version print version information and exit\n\ - -v, --verbose print verbose messages\n\ -\n\ -Report bugs to <%s>.\n\ -", GRUB_LIBDIR, DEFAULT_DIRECTORY, PACKAGE_BUGREPORT); - - exit (status); -} - -int -main (int argc, char *argv[]) -{ - FILE *fp; - char *output = NULL; - char *dir = NULL; - char *prefix = NULL; - - program_name = "grub-mkimage"; - - while (1) - { - int c = getopt_long (argc, argv, "d:p:o:hVv", options, 0); - if (c == -1) - break; - - switch (c) - { - case 'd': - if (dir) - free (dir); - dir = xstrdup (optarg); - break; - case 'h': - usage (0); - break; - case 'o': - if (output) - free (output); - output = xstrdup (optarg); - break; - case 'p': - if (prefix) - free (prefix); - prefix = xstrdup (optarg); - break; - case 'V': - printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); - return 0; - case 'v': - verbosity++; - break; - default: - usage (1); - break; - } - } - - if (! output) - usage (1); - - fp = fopen (output, "wb"); - if (! fp) - grub_util_error ("cannot open %s", output); - - convert_elf (dir ? : GRUB_LIBDIR, prefix ? : DEFAULT_DIRECTORY, fp, argv + optind); - - fclose (fp); - - return 0; -} diff --git a/util/i386/pc/grub-mkfloppy.in b/util/i386/pc/grub-mkfloppy.in deleted file mode 100644 index 3b5518690..000000000 --- a/util/i386/pc/grub-mkfloppy.in +++ /dev/null @@ -1,116 +0,0 @@ -#! /bin/sh -e - -# Make GRUB rescue floppy -# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008 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 . - -# Initialize some variables. -transform="@program_transform_name@" - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -bindir=@bindir@ -libdir=@libdir@ -PACKAGE_NAME=@PACKAGE_NAME@ -PACKAGE_TARNAME=@PACKAGE_TARNAME@ -PACKAGE_VERSION=@PACKAGE_VERSION@ -target_cpu=@target_cpu@ -platform=@platform@ -pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` - -# Usage: usage -# Print the usage. -usage () { - cat <. -EOF -} - -input_dir=${pkglibdir} - -# Check the arguments. -for option in "$@"; do - case "$option" in - -h | --help) - usage - exit 0 ;; - -v | --version) - echo "$0 (GNU GRUB ${PACKAGE_VERSION})" - exit 0 ;; - --modules=*) - modules=`echo "$option" | sed 's/--modules=//'` ;; - --output=*) - output_image=`echo "$option" | sed 's/--output=//'` ;; - -*) - echo "Unrecognized option \`$option'" 1>&2 - usage - exit 1 - ;; - *) - if test "x$output_image" != x; then - echo "Unrecognized option \`$option'" 1>&2 - usage - exit 1 - fi - output_image="${option}" ;; - esac -done - -if test "x$output_image" = x; then - usage - exit 1 -fi - -aux_dir=`mktemp -d` -mkdir -p ${aux_dir}/boot/grub - -for file in ${input_dir}/*.mod ${input_dir}/efiemu??.o \ - ${input_dir}/command.lst ${input_dir}/moddep.lst ${input_dir}/fs.lst \ - ${input_dir}/handler.lst ${input_dir}/parttool.lst; do - if test -f "$file"; then - cp -f "$file" ${aux_dir}/boot/grub/ - fi -done - -modules="$(cat ${input_dir}/partmap.lst) ${modules}" -for i in ${modules} ; do - echo "insmod $i" -done > ${aux_dir}/boot/grub/grub.cfg - -# build memdisk -memdisk_img=`mktemp` -tar -C ${aux_dir} -cf ${memdisk_img} boot -rm -rf ${aux_dir} - -# build core.img -core_img=`mktemp` -grub-mkimage -d ${input_dir}/ -m ${memdisk_img} -o ${core_img} memdisk tar biosdisk -rm -f ${memdisk_img} - -# build floppy image -cat ${input_dir}/boot.img ${core_img} /dev/zero | dd bs=1024 count=1440 > ${output_image} -rm -f ${core_img} - -exit 0 diff --git a/util/i386/pc/grub-mkimage.c b/util/i386/pc/grub-mkimage.c deleted file mode 100644 index 785ea8c71..000000000 --- a/util/i386/pc/grub-mkimage.c +++ /dev/null @@ -1,442 +0,0 @@ -/* grub-mkimage.c - make a bootable image */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define _GNU_SOURCE 1 -#include - -#include "progname.h" - -#ifdef ENABLE_LZMA -#include - -static void *SzAlloc(void *p, size_t size) { p = p; return xmalloc(size); } -static void SzFree(void *p, void *address) { p = p; free(address); } -static ISzAlloc g_Alloc = { SzAlloc, SzFree }; - -static void -compress_kernel (char *kernel_img, size_t kernel_size, - char **core_img, size_t *core_size) -{ - CLzmaEncProps props; - unsigned char out_props[5]; - size_t out_props_size = 5; - - LzmaEncProps_Init(&props); - props.dictSize = 1 << 16; - props.lc = 3; - props.lp = 0; - props.pb = 2; - props.numThreads = 1; - - if (kernel_size < GRUB_KERNEL_MACHINE_RAW_SIZE) - grub_util_error (_("the core image is too small")); - - *core_img = xmalloc (kernel_size); - memcpy (*core_img, kernel_img, GRUB_KERNEL_MACHINE_RAW_SIZE); - - *core_size = kernel_size - GRUB_KERNEL_MACHINE_RAW_SIZE; - if (LzmaEncode((unsigned char *) *core_img + GRUB_KERNEL_MACHINE_RAW_SIZE, - core_size, - (unsigned char *) kernel_img + GRUB_KERNEL_MACHINE_RAW_SIZE, - kernel_size - GRUB_KERNEL_MACHINE_RAW_SIZE, - &props, out_props, &out_props_size, - 0, NULL, &g_Alloc, &g_Alloc) != SZ_OK) - grub_util_error (_("cannot compress the kernel image")); - - *core_size += GRUB_KERNEL_MACHINE_RAW_SIZE; -} - -#else /* No lzma compression */ - -static void -compress_kernel (char *kernel_img, size_t kernel_size, - char **core_img, size_t *core_size) -{ - *core_img = xmalloc (kernel_size); - memcpy (*core_img, kernel_img, kernel_size); - *core_size = kernel_size; -} - -#endif /* No lzma compression */ - -static void -generate_image (const char *dir, char *prefix, FILE *out, char *mods[], - char *memdisk_path, char *config_path) -{ - char *kernel_img, *boot_img, *core_img; - size_t kernel_size, boot_size, total_module_size, core_size; - size_t memdisk_size = 0, config_size = 0; - char *kernel_path, *boot_path; - size_t offset; - struct grub_util_path_list *path_list, *p, *next; - struct grub_module_info *modinfo; - - path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); - - kernel_path = grub_util_get_path (dir, "kernel.img"); - kernel_size = grub_util_get_image_size (kernel_path); - - total_module_size = sizeof (struct grub_module_info); - - if (memdisk_path) - { - memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); - grub_util_info ("the size of memory disk is 0x%x", memdisk_size); - total_module_size += memdisk_size + sizeof (struct grub_module_header); - } - - if (config_path) - { - config_size = grub_util_get_image_size (config_path) + 1; - grub_util_info ("the size of config file is 0x%x", config_size); - total_module_size += config_size + sizeof (struct grub_module_header); - } - - for (p = path_list; p; p = p->next) - total_module_size += (grub_util_get_image_size (p->name) - + sizeof (struct grub_module_header)); - - grub_util_info ("the total module size is 0x%x", total_module_size); - - kernel_img = xmalloc (kernel_size + total_module_size); - grub_util_load_image (kernel_path, kernel_img); - - if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END) - grub_util_error (_("prefix is too long")); - strcpy (kernel_img + GRUB_KERNEL_MACHINE_PREFIX, prefix); - - /* Fill in the grub_module_info structure. */ - modinfo = (struct grub_module_info *) (kernel_img + kernel_size); - memset (modinfo, 0, sizeof (struct grub_module_info)); - modinfo->magic = GRUB_MODULE_MAGIC; - modinfo->offset = sizeof (struct grub_module_info); - modinfo->size = total_module_size; - - offset = kernel_size + sizeof (struct grub_module_info); - for (p = path_list; p; p = p->next) - { - struct grub_module_header *header; - size_t mod_size; - - mod_size = grub_util_get_image_size (p->name); - - header = (struct grub_module_header *) (kernel_img + offset); - memset (header, 0, sizeof (struct grub_module_header)); - header->type = OBJ_TYPE_ELF; - header->size = grub_host_to_target32 (mod_size + sizeof (*header)); - offset += sizeof (*header); - - grub_util_load_image (p->name, kernel_img + offset); - offset += mod_size; - } - - if (memdisk_path) - { - struct grub_module_header *header; - - header = (struct grub_module_header *) (kernel_img + offset); - memset (header, 0, sizeof (struct grub_module_header)); - header->type = OBJ_TYPE_MEMDISK; - header->size = grub_host_to_target32 (memdisk_size + sizeof (*header)); - offset += sizeof (*header); - - grub_util_load_image (memdisk_path, kernel_img + offset); - offset += memdisk_size; - } - - if (config_path) - { - struct grub_module_header *header; - - header = (struct grub_module_header *) (kernel_img + offset); - memset (header, 0, sizeof (struct grub_module_header)); - header->type = OBJ_TYPE_CONFIG; - header->size = grub_host_to_target32 (config_size + sizeof (*header)); - offset += sizeof (*header); - - grub_util_load_image (config_path, kernel_img + offset); - offset += config_size; - *(kernel_img + offset - 1) = 0; - } - - grub_util_info ("kernel_img=%p, kernel_size=0x%x", kernel_img, kernel_size); - compress_kernel (kernel_img, kernel_size + total_module_size, - &core_img, &core_size); - - grub_util_info ("the core size is 0x%x", core_size); - -#if defined(GRUB_MACHINE_PCBIOS) - { - unsigned num; - num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); - if (num > 0xffff) - grub_util_error (_("the core image is too big")); - - boot_path = grub_util_get_path (dir, "diskboot.img"); - boot_size = grub_util_get_image_size (boot_path); - if (boot_size != GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("diskboot.img size must be %u bytes"), GRUB_DISK_SECTOR_SIZE); - - boot_img = grub_util_read_image (boot_path); - - /* i386 is a little endian architecture. */ - *((grub_uint16_t *) (boot_img + GRUB_DISK_SECTOR_SIZE - - GRUB_BOOT_MACHINE_LIST_SIZE + 8)) - = grub_cpu_to_le16 (num); - - grub_util_write_image (boot_img, boot_size, out); - free (boot_img); - free (boot_path); - } -#elif defined(GRUB_MACHINE_QEMU) - { - char *rom_img; - size_t rom_size; - - boot_path = grub_util_get_path (dir, "boot.img"); - boot_size = grub_util_get_image_size (boot_path); - boot_img = grub_util_read_image (boot_path); - - /* Rom sizes must be 64k-aligned. */ - rom_size = ALIGN_UP (core_size + boot_size, 64 * 1024); - - rom_img = xmalloc (rom_size); - memset (rom_img, 0, rom_size); - - *((grub_int32_t *) (core_img + GRUB_KERNEL_MACHINE_CORE_ENTRY_ADDR)) - = grub_cpu_to_le32 ((grub_uint32_t) -rom_size); - - memcpy (rom_img, core_img, core_size); - - *((grub_int32_t *) (boot_img + GRUB_BOOT_MACHINE_CORE_ENTRY_ADDR)) - = grub_cpu_to_le32 ((grub_uint32_t) -rom_size); - - memcpy (rom_img + rom_size - boot_size, boot_img, boot_size); - - free (core_img); - core_img = rom_img; - core_size = rom_size; - - free (boot_img); - free (boot_path); - } - -#endif - -#ifdef GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE - *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE)) - = grub_cpu_to_le32 (total_module_size); -#endif - *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE)) - = grub_cpu_to_le32 (kernel_size); -#ifdef GRUB_KERNEL_MACHINE_COMPRESSED_SIZE - *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE)) - = grub_cpu_to_le32 (core_size - GRUB_KERNEL_MACHINE_RAW_SIZE); -#endif - -#if defined(GRUB_KERNEL_MACHINE_INSTALL_DOS_PART) && defined(GRUB_KERNEL_MACHINE_INSTALL_BSD_PART) - /* If we included a drive in our prefix, let GRUB know it doesn't have to - prepend the drive told by BIOS. */ - if (prefix[0] == '(') - { - *((grub_int32_t *) (core_img + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART)) - = grub_cpu_to_le32 (-2); - *((grub_int32_t *) (core_img + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART)) - = grub_cpu_to_le32 (-2); - } -#endif - -#ifdef GRUB_MACHINE_PCBIOS - if (GRUB_KERNEL_MACHINE_LINK_ADDR + core_size > GRUB_MEMORY_MACHINE_UPPER) - grub_util_error (_("Core image is too big (%p > %p)\n"), - GRUB_KERNEL_MACHINE_LINK_ADDR + core_size, GRUB_MEMORY_MACHINE_UPPER); -#endif - - grub_util_write_image (core_img, core_size, out); - free (kernel_img); - free (core_img); - free (kernel_path); - - while (path_list) - { - next = path_list->next; - free ((void *) path_list->name); - free (path_list); - path_list = next; - } -} - - - -static struct option options[] = - { - {"directory", required_argument, 0, 'd'}, - {"prefix", required_argument, 0, 'p'}, - {"memdisk", required_argument, 0, 'm'}, - {"config", required_argument, 0, 'c'}, - {"output", required_argument, 0, 'o'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {"verbose", no_argument, 0, 'v'}, - {0, 0, 0, 0} - }; - -static void -usage (int status) -{ - if (status) - fprintf (stderr, _("Try ``%s --help'' for more information.\n"), program_name); - else - printf (_("\ -Usage: grub-mkimage [OPTION]... [MODULES]\n\ -\n\ -Make a bootable image of GRUB.\n\ -\n\ - -d, --directory=DIR use images and modules under DIR [default=%s]\n\ - -p, --prefix=DIR set grub_prefix directory [default=%s]\n\ - -m, --memdisk=FILE embed FILE as a memdisk image\n\ - -c, --config=FILE embed FILE as boot config\n\ - -o, --output=FILE output a generated image to FILE [default=stdout]\n\ - -h, --help display this message and exit\n\ - -V, --version print version information and exit\n\ - -v, --verbose print verbose messages\n\ -\n\ -Report bugs to <%s>.\n\ -"), GRUB_LIBDIR, DEFAULT_DIRECTORY, PACKAGE_BUGREPORT); - - exit (status); -} - -int -main (int argc, char *argv[]) -{ - char *output = NULL; - char *dir = NULL; - char *prefix = NULL; - char *memdisk = NULL; - char *config = NULL; - FILE *fp = stdout; - - set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - while (1) - { - int c = getopt_long (argc, argv, "d:p:m:c:o:hVv", options, 0); - - if (c == -1) - break; - else - switch (c) - { - case 'o': - if (output) - free (output); - - output = xstrdup (optarg); - break; - - case 'd': - if (dir) - free (dir); - - dir = xstrdup (optarg); - break; - - case 'm': - if (memdisk) - free (memdisk); - - memdisk = xstrdup (optarg); - - if (prefix) - free (prefix); - - prefix = xstrdup ("(memdisk)/boot/grub"); - break; - - case 'c': - if (config) - free (config); - - config = xstrdup (optarg); - break; - - case 'h': - usage (0); - break; - - case 'p': - if (prefix) - free (prefix); - - prefix = xstrdup (optarg); - break; - - case 'V': - printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); - return 0; - - case 'v': - verbosity++; - break; - - default: - usage (1); - break; - } - } - - if (output) - { - fp = fopen (output, "wb"); - if (! fp) - grub_util_error (_("cannot open %s"), output); - free (output); - } - - generate_image (dir ? : GRUB_LIBDIR, prefix ? : DEFAULT_DIRECTORY, fp, - argv + optind, memdisk, config); - - fclose (fp); - - if (dir) - free (dir); - - return 0; -} diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 1c7e8452f..6e6b2e878 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -1,7 +1,7 @@ /* grub-setup.c - make GRUB usable */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,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 @@ -28,14 +28,14 @@ #include #include #include -#include +#include #include #include #include #include #include #include -#include +#include static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT; @@ -48,6 +48,7 @@ static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_P #include #include #include +#include #include "progname.h" #define _GNU_SOURCE 1 @@ -56,13 +57,12 @@ static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_P #define DEFAULT_BOOT_FILE "boot.img" #define DEFAULT_CORE_FILE "core.img" -/* This is the blocklist used in the diskboot image. */ -struct boot_blocklist -{ - grub_uint64_t start; - grub_uint16_t len; - grub_uint16_t segment; -} __attribute__ ((packed)); +#define grub_target_to_host16(x) grub_le_to_cpu16(x) +#define grub_target_to_host32(x) grub_le_to_cpu32(x) +#define grub_target_to_host64(x) grub_le_to_cpu64(x) +#define grub_host_to_target16(x) grub_cpu_to_le16(x) +#define grub_host_to_target32(x) grub_cpu_to_le32(x) +#define grub_host_to_target64(x) grub_cpu_to_le64(x) void grub_putchar (int c) @@ -99,7 +99,7 @@ setup (const char *dir, grub_uint8_t *boot_drive; grub_disk_addr_t *kernel_sector; grub_uint16_t *boot_drive_check; - struct boot_blocklist *first_block, *block; + struct grub_boot_blocklist *first_block, *block; grub_int32_t *install_dos_part, *install_bsd_part; grub_int32_t dos_part, bsd_part; char *tmp_img; @@ -123,15 +123,10 @@ setup (const char *dir, int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk __attribute__ ((unused)), const grub_partition_t p) { - struct grub_msdos_partition *pcdata = p->data; - /* There's always an embed region, and it starts right after the MBR. */ embed_region.start = 1; - /* For its end offset, include as many dummy partitions as we can. */ - if (! grub_msdos_partition_is_empty (pcdata->dos_type) - && ! grub_msdos_partition_is_bsd (pcdata->dos_type) - && embed_region.end > p->start) + if (embed_region.end > p->start) embed_region.end = p->start; return 0; @@ -142,17 +137,21 @@ setup (const char *dir, int NESTED_FUNC_ATTR find_usable_region_gpt (grub_disk_t disk __attribute__ ((unused)), const grub_partition_t p) { - struct grub_gpt_partentry *gptdata = p->data; + struct grub_gpt_partentry gptdata; + + disk->partition = p->parent; + if (grub_disk_read (disk, p->offset, p->index, + sizeof (gptdata), &gptdata)) + return 0; /* If there's an embed region, it is in a dedicated partition. */ - if (! memcmp (&gptdata->type, &grub_gpt_partition_type_bios_boot, 16)) + if (! memcmp (&gptdata.type, &grub_gpt_partition_type_bios_boot, 16)) { embed_region.start = p->start; embed_region.end = p->start + p->len; return 1; } - return 0; } @@ -163,7 +162,7 @@ setup (const char *dir, sector, offset, length); if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("The first sector of the core file is not sector-aligned")); + grub_util_error (_("the first sector of the core file is not sector-aligned")); first_sector = sector; } @@ -171,13 +170,13 @@ setup (const char *dir, void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length) { - struct boot_blocklist *prev = block + 1; + struct grub_boot_blocklist *prev = block + 1; grub_util_info ("saving <%llu,%u,%u> with the segment 0x%x", sector, offset, length, (unsigned) current_segment); if (offset != 0 || last_length != GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("Non-sector-aligned data is found in the core file")); + grub_util_error (_("non-sector-aligned data is found in the core file")); if (block != first_block && (grub_le_to_cpu64 (prev->start) @@ -191,7 +190,7 @@ setup (const char *dir, block--; if (block->len) - grub_util_error (_("The sectors of the core file are too fragmented")); + grub_util_error (_("the sectors of the core file are too fragmented")); } last_length = length; @@ -202,7 +201,7 @@ setup (const char *dir, boot_path = grub_util_get_path (dir, boot_file); boot_size = grub_util_get_image_size (boot_path); if (boot_size != GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("The size of `%s' is not %u"), + grub_util_error (_("the size of `%s' is not %u"), boot_path, GRUB_DISK_SECTOR_SIZE); boot_img = grub_util_read_image (boot_path); free (boot_path); @@ -219,16 +218,16 @@ setup (const char *dir, core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); if (core_size < GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("The size of `%s' is too small"), core_path); + grub_util_error (_("the size of `%s' is too small"), core_path); else if (core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("The size of `%s' is too large"), core_path); + grub_util_error (_("the size of `%s' is too large"), core_path); core_img = grub_util_read_image (core_path); /* Have FIRST_BLOCK to point to the first blocklist. */ - first_block = (struct boot_blocklist *) (core_img - + GRUB_DISK_SECTOR_SIZE - - sizeof (*block)); + first_block = (struct grub_boot_blocklist *) (core_img + + GRUB_DISK_SECTOR_SIZE + - sizeof (*block)); install_dos_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART); @@ -258,7 +257,7 @@ setup (const char *dir, grub_fs_t fs; fs = grub_fs_probe (dest_dev); if (! fs) - grub_util_error (_("Unable to identify a filesystem in %s; safety check can't be performed"), + grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"), dest_dev->disk->name); if (! fs->reserved_first_sector) @@ -296,22 +295,19 @@ setup (const char *dir, /* Embed information about the installed location. */ if (root_dev->disk->partition) { - if (strcmp (root_dev->disk->partition->partmap->name, - "part_msdos") == 0) - { - struct grub_msdos_partition *pcdata = - root_dev->disk->partition->data; - dos_part = pcdata->dos_part; - bsd_part = pcdata->bsd_part; - } - else if (strcmp (root_dev->disk->partition->partmap->name, - "part_gpt") == 0) - { - dos_part = root_dev->disk->partition->index; - bsd_part = -1; - } + if (root_dev->disk->partition->parent) + { + if (root_dev->disk->partition->parent->parent) + grub_util_error ("Installing on doubly nested partitions is " + "not supported"); + dos_part = root_dev->disk->partition->parent->number; + bsd_part = root_dev->disk->partition->number; + } else - grub_util_error (_("No DOS-style partitions found")); + { + dos_part = root_dev->disk->partition->number; + bsd_part = -1; + } } else dos_part = bsd_part = -1; @@ -344,6 +340,8 @@ setup (const char *dir, int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)), const grub_partition_t p) { + if (p->parent) + return 0; dest_partmap = p->partmap->name; return 1; } @@ -356,12 +354,16 @@ setup (const char *dir, goto unable_to_embed; } - grub_partition_iterate (dest_dev->disk, (strcmp (dest_partmap, "part_msdos") ? - find_usable_region_gpt : find_usable_region_msdos)); + if (strcmp (dest_partmap, "msdos") == 0) + grub_partition_iterate (dest_dev->disk, find_usable_region_msdos); + else if (strcmp (dest_partmap, "gpt") == 0) + grub_partition_iterate (dest_dev->disk, find_usable_region_gpt); + else + grub_util_error (_("No DOS-style partitions found")); if (embed_region.end == embed_region.start) { - if (! strcmp (dest_partmap, "part_msdos")) + if (! strcmp (dest_partmap, "msdos")) grub_util_warn (_("This msdos-style partition label has no post-MBR gap; embedding won't be possible!")); else grub_util_warn (_("This GPT partition label has no BIOS Boot Partition; embedding won't be possible!")); @@ -385,10 +387,11 @@ setup (const char *dir, /* The first blocklist contains the whole sectors. */ first_block->start = grub_cpu_to_le64 (embed_region.start + 1); - first_block->len = grub_cpu_to_le16 (core_sectors - 1); - first_block->segment - = grub_cpu_to_le16 (GRUB_BOOT_MACHINE_KERNEL_SEG - + (GRUB_DISK_SECTOR_SIZE >> 4)); + + /* These are filled elsewhere. Verify them just in case. */ + assert (first_block->len == grub_host_to_target16 (core_sectors - 1)); + assert (first_block->segment == grub_host_to_target16 (GRUB_BOOT_MACHINE_KERNEL_SEG + + (GRUB_DISK_SECTOR_SIZE >> 4))); /* Make sure that the second blocklist is a terminator. */ block = first_block - 1; @@ -415,19 +418,19 @@ setup (const char *dir, unable_to_embed: if (must_embed) - grub_util_error (_("Embedding is not possible, but this is required when " - "the root device is on a RAID array or LVM volume.")); + grub_util_error (_("embedding is not possible, but this is required when " + "the root device is on a RAID array or LVM volume")); grub_util_warn (_("Embedding is not possible. GRUB can only be installed in this " "setup by using blocklists. However, blocklists are UNRELIABLE and " - "its use is discouraged.")); + "their use is discouraged.")); if (! force) - grub_util_error (_("If you really want blocklists, use --force.")); + grub_util_error (_("if you really want blocklists, use --force")); /* Make sure that GRUB reads the identical image as the OS. */ tmp_img = xmalloc (core_size); core_path_dev_full = grub_util_get_path (dir, core_file); - core_path_dev = make_system_path_relative_to_its_root (core_path_dev_full); + core_path_dev = grub_make_system_path_relative_to_its_root (core_path_dev_full); free (core_path_dev_full); /* It is a Good Thing to sync two times. */ @@ -497,7 +500,7 @@ unable_to_embed: } if (i == MAX_TRIES) - grub_util_error (_("Cannot read `%s' correctly"), core_path_dev); + grub_util_error (_("cannot read `%s' correctly"), core_path_dev); /* Clean out the blocklists. */ block = first_block; @@ -510,7 +513,7 @@ unable_to_embed: block--; if ((char *) block <= core_img) - grub_util_error (_("No terminator in the core image")); + grub_util_error (_("no terminator in the core image")); } /* Now read the core image to determine where the sectors are. */ @@ -521,13 +524,13 @@ unable_to_embed: file->read_hook = save_first_sector; if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("Failed to read the first sector of the core image")); + grub_util_error (_("failed to read the first sector of the core image")); block = first_block; file->read_hook = save_blocklists; if (grub_file_read (file, tmp_img, core_size - GRUB_DISK_SECTOR_SIZE) != (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE) - grub_util_error (_("Failed to read the rest sectors of the core image")); + grub_util_error (_("failed to read the rest sectors of the core image")); grub_file_close (file); @@ -546,7 +549,7 @@ unable_to_embed: grub_util_info ("opening the core image `%s'", core_path); fp = fopen (core_path, "r+b"); if (! fp) - grub_util_error (_("Cannot open `%s'"), core_path); + grub_util_error (_("cannot open `%s'"), core_path); grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp); fclose (fp); @@ -586,13 +589,13 @@ static void usage (int status) { if (status) - fprintf (stderr, _("Try ``%s --help'' for more information.\n"), program_name); + fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name); else printf (_("\ -Usage: grub-setup [OPTION]... DEVICE\n\ +Usage: %s [OPTION]... DEVICE\n\ \n\ Set up images to boot from DEVICE.\n\ -DEVICE must be a GRUB device (e.g. ``(hd0,1)'').\n\ +DEVICE must be a GRUB device (e.g. `(hd0,1)').\n\ \n\ -b, --boot-image=FILE use FILE as the boot image [default=%s]\n\ -c, --core-image=FILE use FILE as the core image [default=%s]\n\ @@ -607,6 +610,7 @@ DEVICE must be a GRUB device (e.g. ``(hd0,1)'').\n\ \n\ Report bugs to <%s>.\n\ "), + program_name, DEFAULT_BOOT_FILE, DEFAULT_CORE_FILE, DEFAULT_DIRECTORY, DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT); @@ -637,9 +641,8 @@ main (int argc, char *argv[]) int must_embed = 0, force = 0, fs_probe = 1; set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + + grub_util_init_nls (); /* Check for options. */ while (1) @@ -754,7 +757,7 @@ main (int argc, char *argv[]) char *tmp = get_device_name (root_dev); if (! tmp) - grub_util_error (_("Invalid root device `%s'"), root_dev); + grub_util_error (_("invalid root device `%s'"), root_dev); tmp = xstrdup (tmp); free (root_dev); @@ -767,7 +770,7 @@ main (int argc, char *argv[]) { grub_util_info ("guessing the root device failed, because of `%s'", grub_errmsg); - grub_util_error (_("Cannot guess the root device. Specify the option ``--root-device''.")); + grub_util_error (_("cannot guess the root device. Specify the option `--root-device'")); } } diff --git a/util/ieee1275/devicemap.c b/util/ieee1275/devicemap.c index bddfc17e7..19ab746ef 100644 --- a/util/ieee1275/devicemap.c +++ b/util/ieee1275/devicemap.c @@ -35,8 +35,10 @@ escape_of_path (const char *orig_path) } void -grub_util_emit_devicemap_entry (FILE *fp, char *name, int is_floppy UNUSED, - int *num_fd UNUSED, int *num_hd UNUSED) +grub_util_emit_devicemap_entry (FILE *fp, char *name, + int is_floppy __attribute__((unused)), + int *num_fd __attribute__((unused)), + int *num_hd __attribute__((unused))) { const char *orig_path = grub_util_devname_to_ofpath (name); char *ofpath = escape_of_path (orig_path); diff --git a/util/ieee1275/grub-install.in b/util/ieee1275/grub-install.in index 710ed125b..4d00cc217 100644 --- a/util/ieee1275/grub-install.in +++ b/util/ieee1275/grub-install.in @@ -34,9 +34,10 @@ target_cpu=@target_cpu@ platform=@platform@ pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` -grub_mkimage=${bindir}/`echo grub-mkelfimage | sed ${transform}` +grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}` grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` +grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` rootdir= grub_prefix=`echo /boot/grub | sed ${transform}` modules= @@ -45,8 +46,8 @@ install_device= debug=no update_nvram=yes -ofpathname=/usr/sbin/ofpathname -nvsetenv=/sbin/nvsetenv +ofpathname=`which ofpathname` +nvsetenv=`which nvsetenv` # Usage: usage # Print the usage. @@ -140,8 +141,7 @@ fi # XXX warn on firmware-unreadable filesystems? # Create the GRUB directory if it is not present. -test -d "$bootdir" || mkdir "$bootdir" || exit 1 -test -d "$grubdir" || mkdir "$grubdir" || exit 1 +mkdir -p "$grubdir" || exit 1 # Create the device map file if it is not present. if test -f "$device_map"; then @@ -163,6 +163,10 @@ for file in ${pkglibdir}/*.mod ${pkglibdir}/*.lst ; do cp -f $file ${grubdir} || exit 1 done +if ! test -f ${grubdir}/grubenv; then + $grub_editenv ${grubdir}/grubenv create +fi + # Create the core image. First, auto-detect the filesystem module. fs_module=`$grub_probe --target=fs --device-map=${device_map} ${grubdir}` if test "x$fs_module" = x -a "x$modules" = x; then @@ -174,7 +178,10 @@ fi # Then the partition map module. In order to support partition-less media, # this command is allowed to fail (--target=fs already grants us that the # filesystem will be accessible). -partmap_module=`$grub_probe --target=partmap --device-map=${device_map} ${grubdir} 2> /dev/null` +partmap_module= +for x in `$grub_probe --target=partmap --device ${grub_device} 2> /dev/null`; do + partmap_module="$partmap_module part_$x"; +done # Device abstraction module, if any (lvm, raid). devabstraction_module=`$grub_probe --target=abstraction --device-map=${device_map} ${grubdir}` @@ -182,7 +189,7 @@ devabstraction_module=`$grub_probe --target=abstraction --device-map=${device_ma modules="$modules $fs_module $partmap_module $devabstraction_module" # Now perform the installation. -"$grub_mkimage" --directory=${pkglibdir} --output=${grubdir}/grub $modules || exit 1 +"$grub_mkimage" -O ${target_cpu}-ieee1275 --directory=${pkglibdir} --output=${grubdir}/grub $modules || exit 1 if test $update_nvram = yes; then set $ofpathname dummy @@ -211,11 +218,11 @@ if test $update_nvram = yes; then } # Point boot-device at the new grub install - boot_device="boot-device $ofpath:$partno,\\grub" - "$nvsetenv" "$boot_device" || { + boot_device="$ofpath:$partno,\\grub" + "$nvsetenv" boot-device "$boot_device" || { echo "$nvsetenv failed." echo "You will have to set boot-device manually. At the Open Firmware prompt, type:" - echo " setenv $boot_device" + echo " setenv boot-device $boot_device" exit 1 } fi diff --git a/util/sparc64/ieee1275/grub-ofpathname.c b/util/ieee1275/grub-ofpathname.c similarity index 88% rename from util/sparc64/ieee1275/grub-ofpathname.c rename to util/ieee1275/grub-ofpathname.c index 166ce4cbe..3ac6fce8b 100644 --- a/util/sparc64/ieee1275/grub-ofpathname.c +++ b/util/ieee1275/grub-ofpathname.c @@ -1,7 +1,7 @@ /* grub-ofpathname.c - Find OpenBOOT path for a given device */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 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 @@ -29,9 +29,8 @@ int main(int argc, char **argv) char *of_path; set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + + grub_util_init_nls (); if (argc != 2) { diff --git a/util/ieee1275/ofpath.c b/util/ieee1275/ofpath.c index 7b464bf09..fa0d48cf9 100644 --- a/util/ieee1275/ofpath.c +++ b/util/ieee1275/ofpath.c @@ -39,7 +39,6 @@ #include #ifdef OFPATH_STANDALONE -#define UNUSED __attribute__((unused)) #define xmalloc malloc void grub_util_error (const char *fmt, ...) @@ -132,12 +131,12 @@ block_device_get_sysfs_path_and_link(const char *devicenode, snprintf(sysfs_path, sysfs_path_len, "/sys/block/%s", devicenode); if (!realpath (sysfs_path, rpath)) - grub_util_error ("Cannot get the real path of `%s'", sysfs_path); + grub_util_error ("cannot get the real path of `%s'", sysfs_path); strcat(rpath, "/device"); if (!realpath (rpath, sysfs_path)) - grub_util_error ("Cannot get the real path of `%s'", rpath); + grub_util_error ("cannot get the real path of `%s'", rpath); free (rpath); } @@ -199,8 +198,10 @@ get_basename(char *p) static void of_path_of_vdisk(char *of_path, - const char *devname UNUSED, const char *device, - const char *devnode UNUSED, const char *devicenode) + const char *devname __attribute__((unused)), + const char *device, + const char *devnode __attribute__((unused)), + const char *devicenode) { char *sysfs_path, *p; int devno, junk; @@ -217,8 +218,9 @@ of_path_of_vdisk(char *of_path, static void of_path_of_ide(char *of_path, - const char *devname UNUSED, const char *device, - const char *devnode UNUSED, const char *devicenode) + const char *devname __attribute__((unused)), const char *device, + const char *devnode __attribute__((unused)), + const char *devicenode) { char *sysfs_path, *p; int chan, devno; @@ -245,12 +247,12 @@ vendor_is_ATA(const char *path) snprintf(buf, PATH_MAX, "%s/vendor", path); fd = open(buf, O_RDONLY); if (fd < 0) - grub_util_error ("Cannot open 'vendor' node of `%s'", path); + grub_util_error ("cannot open 'vendor' node of `%s'", path); memset(buf, 0, PATH_MAX); err = read(fd, buf, PATH_MAX); if (err < 0) - grub_util_error ("Cannot read 'vendor' node of `%s'", path); + grub_util_error ("cannot read 'vendor' node of `%s'", path); close(fd); @@ -286,7 +288,7 @@ check_sas (char *sysfs_path, int *tgt) fd = open(path, O_RDONLY); if (fd < 0) - grub_util_error("Cannot open SAS PHY ID '%s'\n", path); + grub_util_error("cannot open SAS PHY ID `%s'\n", path); memset (phy, 0, sizeof (phy)); read (fd, phy, sizeof (phy)); @@ -299,8 +301,9 @@ check_sas (char *sysfs_path, int *tgt) static void of_path_of_scsi(char *of_path, - const char *devname UNUSED, const char *device, - const char *devnode UNUSED, const char *devicenode) + const char *devname __attribute__((unused)), const char *device, + const char *devnode __attribute__((unused)), + const char *devicenode) { const char *p, *digit_string, *disk_name; int host, bus, tgt, lun; @@ -365,14 +368,14 @@ strip_trailing_digits (const char *p) } char * -grub_util_devname_to_ofpath (char *devname) +grub_util_devname_to_ofpath (const char *devname) { char *name_buf, *device, *devnode, *devicenode, *ofpath; name_buf = xmalloc (PATH_MAX); name_buf = realpath (devname, name_buf); if (! name_buf) - grub_util_error ("Cannot get the real path of `%s'", devname); + grub_util_error ("cannot get the real path of `%s'", devname); device = get_basename (devname); devnode = strip_trailing_digits (devname); diff --git a/util/import_gcry.py b/util/import_gcry.py index 698e6cffe..b9c3edcde 100644 --- a/util/import_gcry.py +++ b/util/import_gcry.py @@ -61,14 +61,34 @@ mdblocksizes = {"_gcry_digest_spec_crc32" : 64, "_gcry_digest_spec_tiger" : 64, "_gcry_digest_spec_whirlpool" : 64} +cryptolist = open (os.path.join (cipher_dir_out, "crypto.lst"), "w") +conf.write ("MAINTAINER_CLEANFILES += $(srcdir)/conf/gcry.rmk $(srcdir)/lib/libgcrypt-grub/cipher/ChangeLog $(srcdir)/lib/libgcrypt-grub/cipher/cipher.h $(srcdir)/lib/libgcrypt-grub/cipher/crypto.lst $(srcdir)/lib/libgcrypt-grub/cipher/g10lib.h $(srcdir)/lib/libgcrypt-grub/cipher/memory.h $(srcdir)/lib/libgcrypt-grub/cipher/types.h\n"); + +# rijndael is the only cipher using aliases. So no need for mangling, just +# hardcode it +cryptolist.write ("RIJNDAEL: gcry_rijndael\n"); +cryptolist.write ("RIJNDAEL192: gcry_rijndael\n"); +cryptolist.write ("RIJNDAEL256: gcry_rijndael\n"); +cryptolist.write ("AES128: gcry_rijndael\n"); +cryptolist.write ("AES-128: gcry_rijndael\n"); +cryptolist.write ("AES-192: gcry_rijndael\n"); +cryptolist.write ("AES-256: gcry_rijndael\n"); + for cipher_file in cipher_files: infile = os.path.join (cipher_dir_in, cipher_file) outfile = os.path.join (cipher_dir_out, cipher_file) if cipher_file == "ChangeLog": continue chlognew = " * %s" % cipher_file + if re.match ("(Manifest|Makefile\.am|ac\.c|cipher\.c|hash-common\.c|hmac-tests\.c|md\.c|pubkey\.c)$", cipher_file): + chlog = "%s%s: Removed\n" % (chlog, chlognew) + continue + # Autogenerated files. Not even worth mentionning in ChangeLog + if re.match ("Makefile\.in$", cipher_file): + continue nch = False if re.match (".*\.[ch]$", cipher_file): + conf.write ("MAINTAINER_CLEANFILES += $(srcdir)/lib/libgcrypt-grub/cipher/" + cipher_file + "\n"); isc = re.match (".*\.c$", cipher_file) f = open (infile, "r") fw = open (outfile, "w") @@ -80,8 +100,21 @@ for cipher_file in cipher_files: skip = False skip2 = False ismd = False + iscryptostart = False iscomma = False + isglue = False + skip_statement = False + if isc: + modname = cipher_file [0:len(cipher_file) - 2] + if re.match (".*-glue$", modname): + modname = modname.replace ("-glue", "") + isglue = True + modname = "gcry_%s" % modname for line in f: + if skip_statement: + if not re.search (";", line) is None: + skip_statement = False + continue if skip: if line[0] == "}": skip = False @@ -90,6 +123,12 @@ for cipher_file in cipher_files: if not re.search (" *};", line) is None: skip2 = False continue + if iscryptostart: + s = re.search (" *\"([A-Z0-9_a-z]*)\"", line) + if not s is None: + sg = s.groups()[0] + cryptolist.write (("%s: %s\n") % (sg, modname)) + iscryptostart = False if ismd: if not re.search (" *};", line) is None: if not mdblocksizes.has_key (mdname): @@ -100,10 +139,22 @@ for cipher_file in cipher_files: fw.write (" .blocksize = %s\n" % mdblocksizes [mdname]) ismd = False iscomma = not re.search (",$", line) is None + # Used only for selftests. + m = re.match ("(static byte|static unsigned char) (weak_keys_chksum)\[[0-9]*\] =", line) + if not m is None: + skip = True + fname = m.groups ()[1] + chmsg = "(%s): Removed." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue if hold: hold = False # We're optimising for size. - if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer)", line) is None: + if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer|tripledes_set2keys|do_tripledes_set_extra_info)", line) is None: skip = True fname = re.match ("[a-zA-Z0-9_]*", line).group () chmsg = "(%s): Removed." % fname @@ -127,16 +178,20 @@ for cipher_file in cipher_files: continue m = re.match ("gcry_cipher_spec_t", line) if isc and not m is None: + assert (not iscryptostart) ciphername = line [len ("gcry_cipher_spec_t"):].strip () ciphername = re.match("[a-zA-Z0-9_]*",ciphername).group () ciphernames.append (ciphername) + iscryptostart = True m = re.match ("gcry_md_spec_t", line) if isc and not m is None: assert (not ismd) + assert (not iscryptostart) mdname = line [len ("gcry_md_spec_t"):].strip () mdname = re.match("[a-zA-Z0-9_]*",mdname).group () mdnames.append (mdname) ismd = True + iscryptostart = True m = re.match ("static const char \*selftest.*;$", line) if not m is None: fname = line[len ("static const char \*"):] @@ -148,11 +203,18 @@ for cipher_file in cipher_files: chlognew = "%s %s" % (chlognew, chmsg) nch = True continue - m = re.match ("(static const char( |)\*|static gpg_err_code_t|void)$", line) + m = re.match ("(static const char( |)\*|static gpg_err_code_t|void|static int|static gcry_err_code_t)$", line) if not m is None: hold = True holdline = line continue + m = re.match ("static int tripledes_set2keys \(.*\);", line) + if not m is None: + continue + m = re.match ("static int tripledes_set2keys \(", line) + if not m is None: + skip_statement = True + continue m = re.match ("cipher_extra_spec_t", line) if isc and not m is None: skip2 = True @@ -179,14 +241,11 @@ for cipher_file in cipher_files: continue fw.write (line) if len (ciphernames) > 0 or len (mdnames) > 0: - modname = cipher_file [0:len(cipher_file) - 2] - if re.match (".*-glue$", modname): - modfiles = "libgcrypt-grub/cipher/%s libgcrypt-grub/cipher/%s" \ + if isglue: + modfiles = "lib/libgcrypt-grub/cipher/%s lib/libgcrypt-grub/cipher/%s" \ % (cipher_file, cipher_file.replace ("-glue.c", ".c")) - modname = modname.replace ("-glue", "") else: - modfiles = "libgcrypt-grub/cipher/%s" % cipher_file - modname = "gcry_%s" % modname + modfiles = "lib/libgcrypt-grub/cipher/%s" % cipher_file chmsg = "(GRUB_MOD_INIT(%s)): New function\n" % modname if nch: chlognew = "%s\n %s" % (chlognew, chmsg) @@ -220,7 +279,7 @@ for cipher_file in cipher_files: conf.write ("pkglib_MODULES += %s.mod\n" % modname) conf.write ("%s_mod_SOURCES = %s\n" %\ (modname, modfiles)) - conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-missing-field-initializers -Wno-error\n" % modname) + conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap\n" % modname) conf.write ("%s_mod_LDFLAGS = $(COMMON_LDFLAGS)\n\n" % modname) elif isc and cipher_file != "camellia.c": print ("WARNING: C file isn't a module: %s" % cipher_file) @@ -229,26 +288,22 @@ for cipher_file in cipher_files: if nch: chlog = "%s%s\n" % (chlog, chlognew) continue - if re.match ("(Manifest|Makefile\.am)$", cipher_file): - chlog = "%s%sRemoved\n" % (chlog, chlognew) - continue - # Autogenerated files. Not even worth mentionning in ChangeLog - if re.match ("Makefile\.in$", cipher_file): - chlog = "%s%sRemoved\n" % (chlog, chlognew) - continue chlog = "%s%sSkipped unknown file\n" % (chlog, chlognew) print ("WARNING: unknown file %s" % cipher_file) +cryptolist.close () +chlog = "%s * crypto.lst: New file.\n" % chlog + outfile = os.path.join (cipher_dir_out, "types.h") fw=open (outfile, "w") fw.write ("#include \n") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * types.h: New file.\n" % chlog fw.close () outfile = os.path.join (cipher_dir_out, "memory.h") fw=open (outfile, "w") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * memory.h: New file.\n" % chlog fw.close () @@ -256,13 +311,13 @@ fw.close () outfile = os.path.join (cipher_dir_out, "cipher.h") fw=open (outfile, "w") fw.write ("#include \n") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * cipher.h: Likewise.\n" % chlog fw.close () outfile = os.path.join (cipher_dir_out, "g10lib.h") fw=open (outfile, "w") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * g10lib.h: Likewise.\n" % chlog fw.close () diff --git a/util/lvm.c b/util/lvm.c index 8a8ed1e4c..0a0916344 100644 --- a/util/lvm.c +++ b/util/lvm.c @@ -26,6 +26,8 @@ #include #include +#define LVM_DEV_MAPPER_STRING "/dev/mapper/" + int grub_util_lvm_isvolume (char *name) { @@ -33,10 +35,10 @@ grub_util_lvm_isvolume (char *name) struct stat st; int err; - devname = xmalloc (strlen (name) + 13); + devname = xmalloc (strlen (name) + sizeof (LVM_DEV_MAPPER_STRING)); - strcpy (devname, "/dev/mapper/"); - strcpy (devname+12, name); + strcpy (devname, LVM_DEV_MAPPER_STRING); + strcpy (devname + sizeof(LVM_DEV_MAPPER_STRING) - 1, name); err = stat (devname, &st); free (devname); diff --git a/util/misc.c b/util/misc.c index d75aa0952..91bc25a55 100644 --- a/util/misc.c +++ b/util/misc.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2005,2006,2007,2008,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 @@ -30,16 +30,18 @@ #include #include #include -#include #include +#include #include #include #include #include #include #include +#include +#define ENABLE_RELOCATABLE 0 #include "progname.h" /* Include malloc.h, only if memalign is available. It is known that @@ -53,50 +55,7 @@ #include #endif -int verbosity = 0; - -void -grub_util_warn (const char *fmt, ...) -{ - va_list ap; - - fprintf (stderr, "%s: warn: ", program_name); - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - fputc ('\n', stderr); - fflush (stderr); -} - -void -grub_util_info (const char *fmt, ...) -{ - if (verbosity > 0) - { - va_list ap; - - fprintf (stderr, "%s: info: ", program_name); - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - fputc ('\n', stderr); - fflush (stderr); - } -} - -void -grub_util_error (const char *fmt, ...) -{ - va_list ap; - - fprintf (stderr, "%s: error: ", program_name); - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); - fputc ('\n', stderr); - exit (1); -} - +#ifdef GRUB_UTIL int grub_err_printf (const char *fmt, ...) { @@ -109,41 +68,7 @@ grub_err_printf (const char *fmt, ...) return ret; } - -void * -xmalloc (size_t size) -{ - void *p; - - p = malloc (size); - if (! p) - grub_util_error ("out of memory"); - - return p; -} - -void * -xrealloc (void *ptr, size_t size) -{ - ptr = realloc (ptr, size); - if (! ptr) - grub_util_error ("out of memory"); - - return ptr; -} - -char * -xstrdup (const char *str) -{ - size_t len; - char *dup; - - len = strlen (str); - dup = (char *) xmalloc (len + 1); - memcpy (dup, str, len + 1); - - return dup; -} +#endif char * grub_util_get_path (const char *dir, const char *file) @@ -253,56 +178,6 @@ grub_util_write_image (const char *img, size_t size, FILE *out) grub_util_error ("write failed"); } -void * -grub_malloc (grub_size_t size) -{ - return xmalloc (size); -} - -void * -grub_zalloc (grub_size_t size) -{ - void *ret; - - ret = xmalloc (size); - memset (ret, 0, size); - return ret; -} - -void -grub_free (void *ptr) -{ - free (ptr); -} - -void * -grub_realloc (void *ptr, grub_size_t size) -{ - return xrealloc (ptr, size); -} - -void * -grub_memalign (grub_size_t align, grub_size_t size) -{ - void *p; - -#if defined(HAVE_POSIX_MEMALIGN) - if (posix_memalign (&p, align, size) != 0) - p = 0; -#elif defined(HAVE_MEMALIGN) - p = memalign (align, size); -#else - (void) align; - (void) size; - grub_util_error ("grub_memalign is not supported"); -#endif - - if (! p) - grub_util_error ("out of memory"); - - return p; -} - /* Some functions that we don't use. */ void grub_mm_init_region (void *addr __attribute__ ((unused)), @@ -310,38 +185,12 @@ grub_mm_init_region (void *addr __attribute__ ((unused)), { } +#if GRUB_NO_MODULES void grub_register_exported_symbols (void) { } - -void -grub_exit (void) -{ - exit (1); -} - -grub_uint32_t -grub_get_rtc (void) -{ - struct timeval tv; - - gettimeofday (&tv, 0); - - return (tv.tv_sec * GRUB_TICKS_PER_SECOND - + (((tv.tv_sec % GRUB_TICKS_PER_SECOND) * 1000000 + tv.tv_usec) - * GRUB_TICKS_PER_SECOND / 1000000)); -} - -grub_uint64_t -grub_get_time_ms (void) -{ - struct timeval tv; - - gettimeofday (&tv, 0); - - return (tv.tv_sec * 1000 + tv.tv_usec / 1000); -} +#endif #ifdef __MINGW32__ @@ -365,59 +214,14 @@ grub_millisleep (grub_uint32_t ms) #endif +#if !(defined (__i386__) || defined (__x86_64__)) && GRUB_NO_MODULES void grub_arch_sync_caches (void *address __attribute__ ((unused)), grub_size_t len __attribute__ ((unused))) { } - -#ifndef HAVE_VASPRINTF - -int -vasprintf (char **buf, const char *fmt, va_list ap) -{ - /* Should be large enough. */ - *buf = xmalloc (512); - - return vsprintf (*buf, fmt, ap); -} - #endif -#ifndef HAVE_ASPRINTF - -int -asprintf (char **buf, const char *fmt, ...) -{ - int status; - va_list ap; - - va_start (ap, fmt); - status = vasprintf (*buf, fmt, ap); - va_end (ap); - - return status; -} - -#endif - -char * -xasprintf (const char *fmt, ...) -{ - va_list ap; - char *result; - - va_start (ap, fmt); - if (vasprintf (&result, fmt, ap) < 0) - { - if (errno == ENOMEM) - grub_util_error ("out of memory"); - return NULL; - } - - return result; -} - #ifdef __MINGW32__ void sync (void) @@ -479,91 +283,28 @@ fail: #endif /* __MINGW32__ */ -/* This function never prints trailing slashes (so that its output - can be appended a slash unconditionally). */ -char * -make_system_path_relative_to_its_root (const char *path) +#ifdef GRUB_UTIL +void +grub_util_init_nls (void) { - struct stat st; - char *p, *buf, *buf2, *buf3; - uintptr_t offset = 0; - dev_t num; - size_t len; - - /* canonicalize. */ - p = realpath (path, NULL); - - if (p == NULL) - { - if (errno != EINVAL) - grub_util_error ("failed to get realpath of %s", path); - else - grub_util_error ("realpath not supporting (path, NULL)"); - } - len = strlen (p) + 1; - buf = strdup (p); - free (p); - - if (stat (buf, &st) < 0) - grub_util_error ("can not stat %s: %s", buf, strerror (errno)); - - buf2 = strdup (buf); - num = st.st_dev; - - /* This loop sets offset to the number of chars of the root - directory we're inspecting. */ - while (1) - { - p = strrchr (buf, '/'); - if (p == NULL) - /* This should never happen. */ - grub_util_error ("FIXME: no / in buf. (make_system_path_relative_to_its_root)"); - if (p != buf) - *p = 0; - else - *++p = 0; - - if (stat (buf, &st) < 0) - grub_util_error ("can not stat %s: %s", buf, strerror (errno)); - - /* buf is another filesystem; we found it. */ - if (st.st_dev != num) - { - /* offset == 0 means path given is the mount point. */ - if (offset == 0) - { - free (buf); - free (buf2); - return strdup ("/"); - } - else - break; - } - - offset = p - buf; - /* offset == 1 means root directory. */ - if (offset == 1) - { - free (buf); - len = strlen (buf2); - while (buf2[len - 1] == '/' && len > 1) - { - buf2[len - 1] = '\0'; - len--; - } - return buf2; - } - } - free (buf); - buf3 = strdup (buf2 + offset); - free (buf2); - - len = strlen (buf3); - while (buf3[len - 1] == '/' && len > 1) - { - buf3[len - 1] = '\0'; - len--; - } - - return buf3; +#if (defined(ENABLE_NLS) && ENABLE_NLS) + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); +#endif /* (defined(ENABLE_NLS) && ENABLE_NLS) */ +} +#endif + +int +grub_dl_ref (grub_dl_t mod) +{ + (void) mod; + return 0; +} + +int +grub_dl_unref (grub_dl_t mod) +{ + (void) mod; + return 0; } diff --git a/util/mkisofs/defaults.h b/util/mkisofs/defaults.h deleted file mode 100644 index dc9ad380c..000000000 --- a/util/mkisofs/defaults.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Header file defaults.h - assorted default values for character strings in - * the volume descriptor. - * - * $Id: defaults.h,v 1.8 1999/03/02 03:41:25 eric Exp $ - */ - -#define PREPARER_DEFAULT NULL -#define PUBLISHER_DEFAULT NULL -#ifndef APPID_DEFAULT -#define APPID_DEFAULT "MKISOFS ISO 9660 FILESYSTEM BUILDER" -#endif -#define COPYRIGHT_DEFAULT NULL -#define BIBLIO_DEFAULT NULL -#define ABSTRACT_DEFAULT NULL -#define VOLSET_ID_DEFAULT NULL -#define VOLUME_ID_DEFAULT "CDROM" -#define BOOT_CATALOG_DEFAULT "boot.catalog" -#define BOOT_IMAGE_DEFAULT NULL -#ifdef __QNX__ -#define SYSTEM_ID_DEFAULT "QNX" -#endif - -#ifdef __osf__ -#define SYSTEM_ID_DEFAULT "OSF" -#endif - -#ifdef __sun -#ifdef __SVR4 -#define SYSTEM_ID_DEFAULT "Solaris" -#else -#define SYSTEM_ID_DEFAULT "SunOS" -#endif -#endif - -#ifdef __hpux -#define SYSTEM_ID_DEFAULT "HP-UX" -#endif - -#ifdef __sgi -#define SYSTEM_ID_DEFAULT "SGI" -#endif - -#ifdef _AIX -#define SYSTEM_ID_DEFAULT "AIX" -#endif - -#ifdef _WIN -#define SYSTEM_ID_DEFAULT "Win32" -#endif /* _WIN */ - -#ifndef SYSTEM_ID_DEFAULT -#define SYSTEM_ID_DEFAULT "LINUX" -#endif diff --git a/util/mkisofs/eltorito.c b/util/mkisofs/eltorito.c deleted file mode 100644 index 05a9040d6..000000000 --- a/util/mkisofs/eltorito.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Program eltorito.c - Handle El Torito specific extensions to iso9660. - * - - Written by Michael Fulbright (1996). - - Copyright 1996 RedHat Software, Incorporated - - Copyright (C) 2009 Free Software Foundation, Inc. - - Boot Info Table generation based on code from genisoimage.c - (from cdrkit 1.1.9), which was originally licensed under GPLv2+. - - This program 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, or (at your option) - any later version. - - This program 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 this program; if not, see . - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "mkisofs.h" -#include "iso9660.h" - -/* used by Win32 for opening binary file - not used by Unix */ -#ifndef O_BINARY -#define O_BINARY 0 -#endif /* O_BINARY */ - -#undef MIN -#define MIN(a, b) (((a) < (b))? (a): (b)) - -static struct eltorito_validation_entry valid_desc; -static struct eltorito_defaultboot_entry default_desc; -static struct eltorito_boot_descriptor gboot_desc; - -static int tvd_write __PR((FILE * outfile)); - -/* - * Check for presence of boot catalog. If it does not exist then make it - */ -void FDECL1(init_boot_catalog, const char *, path) -{ - FILE *bcat; - char * bootpath; /* filename of boot catalog */ - char * buf; - struct stat statbuf; - - bootpath = (char *) e_malloc(strlen(boot_catalog)+strlen(path)+2); - strcpy(bootpath, path); - if (bootpath[strlen(bootpath)-1] != '/') - { - strcat(bootpath,"/"); - } - - strcat(bootpath, boot_catalog); - - /* - * check for the file existing - */ -#ifdef DEBUG_TORITO - fprintf(stderr,"Looking for boot catalog file %s\n",bootpath); -#endif - - if (!stat_filter(bootpath, &statbuf)) - { - /* - * make sure its big enough to hold what we want - */ - if (statbuf.st_size == 2048) - { - /* - * printf("Boot catalog exists, so we do nothing\n"); - */ - free(bootpath); - return; - } - else - { - fprintf (stderr, _("A boot catalog exists and appears corrupted.\n")); - fprintf (stderr, _("Please check the following file: %s.\n"), bootpath); - fprintf (stderr, _("This file must be removed before a bootable CD can be done.\n")); - free (bootpath); - exit (1); - } - } - - /* - * file does not exist, so we create it - * make it one CD sector long - */ - bcat = fopen (bootpath, "wb"); - if (bcat == NULL) - error (1, errno, _("Error creating boot catalog (%s)"), bootpath); - - buf = (char *) e_malloc( 2048 ); - if (fwrite (buf, 1, 2048, bcat) != 2048) - error (1, errno, _("Error writing to boot catalog (%s)"), bootpath); - fclose (bcat); - chmod (bootpath, S_IROTH | S_IRGRP | S_IRWXU); - - free(bootpath); -} /* init_boot_catalog(... */ - -void FDECL1(get_torito_desc, struct eltorito_boot_descriptor *, boot_desc) -{ - FILE *bootcat; - int checksum; - unsigned char * checksum_ptr; - struct directory_entry * de; - struct directory_entry * de2; - unsigned int i; - int nsectors; - - memset(boot_desc, 0, sizeof(*boot_desc)); - boot_desc->id[0] = 0; - memcpy(boot_desc->id2, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID)); - boot_desc->version[0] = 1; - - memcpy(boot_desc->system_id, EL_TORITO_ID, sizeof(EL_TORITO_ID)); - - /* - * search from root of iso fs to find boot catalog - */ - de2 = search_tree_file(root, boot_catalog); - if (!de2) - { - fprintf (stderr, _("Boot catalog cannot be found!\n")); - exit (1); - } - - set_731(boot_desc->bootcat_ptr, - (unsigned int) get_733(de2->isorec.extent)); - - /* - * now adjust boot catalog - * lets find boot image first - */ - de=search_tree_file(root, boot_image); - if (!de) - { - fprintf (stderr, _("Boot image cannot be found!\n")); - exit (1); - } - - /* - * we have the boot image, so write boot catalog information - * Next we write out the primary descriptor for the disc - */ - memset(&valid_desc, 0, sizeof(valid_desc)); - valid_desc.headerid[0] = 1; - valid_desc.arch[0] = EL_TORITO_ARCH_x86; - - /* - * we'll shove start of publisher id into id field, may get truncated - * but who really reads this stuff! - */ - if (publisher) - memcpy_max(valid_desc.id, publisher, MIN(23, strlen(publisher))); - - valid_desc.key1[0] = 0x55; - valid_desc.key2[0] = 0xAA; - - /* - * compute the checksum - */ - checksum=0; - checksum_ptr = (unsigned char *) &valid_desc; - for (i=0; isize + 511) & ~(511))/512; - fprintf (stderr, _("\nSize of boot image is %d sectors"), nsectors); - fprintf (stderr, " -> "); - - if (! use_eltorito_emul_floppy) - { - default_desc.boot_media[0] = EL_TORITO_MEDIA_NOEMUL; - fprintf (stderr, _("No emulation\n")); - } - else if (nsectors == 2880 ) - /* - * choose size of emulated floppy based on boot image size - */ - { - default_desc.boot_media[0] = EL_TORITO_MEDIA_144FLOP; - fprintf (stderr, _("Emulating a 1.44 meg floppy\n")); - } - else if (nsectors == 5760 ) - { - default_desc.boot_media[0] = EL_TORITO_MEDIA_288FLOP; - fprintf (stderr, _("Emulating a 2.88 meg floppy\n")); - } - else if (nsectors == 2400 ) - { - default_desc.boot_media[0] = EL_TORITO_MEDIA_12FLOP; - fprintf (stderr, _("Emulating a 1.2 meg floppy\n")); - } - else - { - fprintf (stderr, _("\nError - boot image is not the an allowable size.\n")); - exit (1); - } - - /* - * FOR NOW LOAD 1 SECTOR, JUST LIKE FLOPPY BOOT!!! - */ - nsectors = 1; - set_721(default_desc.nsect, (unsigned int) nsectors ); -#ifdef DEBUG_TORITO - fprintf(stderr,"Extent of boot images is %d\n",get_733(de->isorec.extent)); -#endif - set_731(default_desc.bootoff, - (unsigned int) get_733(de->isorec.extent)); - - /* - * now write it to disk - */ - bootcat = fopen (de2->whole_name, "r+b"); - if (bootcat == NULL) - error (1, errno, _("Error opening boot catalog for update")); - - /* - * write out - */ - if (fwrite (&valid_desc, 1, 32, bootcat) != 32) - error (1, errno, _("Error writing to boot catalog")); - if (fwrite (&default_desc, 1, 32, bootcat) != 32) - error (1, errno, _("Error writing to boot catalog")); - fclose (bootcat); - - /* If the user has asked for it, patch the boot image */ - if (use_boot_info_table) - { - FILE *bootimage; - uint32_t bi_checksum; - unsigned int total_len; - static char csum_buffer[SECTOR_SIZE]; - int len; - struct eltorito_boot_info bi_table; - bootimage = fopen (de->whole_name, "r+b"); - if (bootimage == NULL) - error (1, errno, _("Error opening boot image file '%s' for update"), - de->whole_name); - /* Compute checksum of boot image, sans 64 bytes */ - total_len = 0; - bi_checksum = 0; - while ((len = fread (csum_buffer, 1, SECTOR_SIZE, bootimage)) > 0) - { - if (total_len & 3) - error (1, 0, _("Odd alignment at non-end-of-file in boot image '%s'"), - de->whole_name); - if (total_len < 64) - memset (csum_buffer, 0, 64 - total_len); - if (len < SECTOR_SIZE) - memset (csum_buffer + len, 0, SECTOR_SIZE - len); - for (i = 0; i < SECTOR_SIZE; i += 4) - bi_checksum += get_731 (&csum_buffer[i]); - total_len += len; - } - - if (total_len != de->size) - error (1, 0, _("Boot image file '%s' changed unexpectedly"), - de->whole_name); - /* End of file, set position to byte 8 */ - fseeko (bootimage, (off_t) 8, SEEK_SET); - memset (&bi_table, 0, sizeof (bi_table)); - /* Is it always safe to assume PVD is at session_start+16? */ - set_731 (bi_table.pvd_addr, session_start + 16); - set_731 (bi_table.file_addr, de->starting_block); - set_731 (bi_table.file_length, de->size); - set_731 (bi_table.file_checksum, bi_checksum); - - if (fwrite (&bi_table, 1, sizeof (bi_table), bootimage) != sizeof (bi_table)) - error (1, errno, _("Error writing to boot image (%s)"), bootimage); - fclose (bootimage); - } - -} /* get_torito_desc(... */ - -/* - * Function to write the EVD for the disc. - */ -static int FDECL1(tvd_write, FILE *, outfile) -{ - /* - * Next we write out the boot volume descriptor for the disc - */ - get_torito_desc(&gboot_desc); - xfwrite(&gboot_desc, 1, 2048, outfile); - last_extent_written ++; - return 0; -} - -struct output_fragment torito_desc = {NULL, oneblock_size, NULL, tvd_write}; diff --git a/util/mkisofs/exclude.h b/util/mkisofs/exclude.h deleted file mode 100644 index 87cd6948a..000000000 --- a/util/mkisofs/exclude.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 9-Dec-93 R.-D. Marzusch, marzusch@odiehh.hanse.de: - * added 'exclude' option (-x) to specify pathnames NOT to be included in - * CD image. - * - * $Id: exclude.h,v 1.2 1999/03/02 03:41:25 eric Exp $ - */ - -void exclude __PR((char * fn)); -int is_excluded __PR((char * fn)); diff --git a/util/mkisofs/hash.c b/util/mkisofs/hash.c deleted file mode 100644 index 4d26e4dba..000000000 --- a/util/mkisofs/hash.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * File hash.c - generate hash tables for iso9660 filesystem. - - Written by Eric Youngdale (1993). - - Copyright 1993 Yggdrasil Computing, Incorporated - - This program 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 2, or (at your option) - any later version. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include -#include "config.h" -#include "mkisofs.h" - -#define NR_HASH 1024 - -#define HASH_FN(DEV, INO) ((DEV + INO + (INO >> 2) + (INO << 8)) % NR_HASH) - -static struct file_hash * hash_table[NR_HASH] = {0,}; - -void FDECL1(add_hash, struct directory_entry *, spnt){ - struct file_hash * s_hash; - unsigned int hash_number; - - if(spnt->size == 0 || spnt->starting_block == 0) - if(spnt->size != 0 || spnt->starting_block != 0) { - fprintf(stderr,"Non zero-length file assigned zero extent.\n"); - exit(1); - }; - - if (spnt->dev == (dev_t) UNCACHED_DEVICE || spnt->inode == UNCACHED_INODE) return; - hash_number = HASH_FN((unsigned int) spnt->dev, (unsigned int) spnt->inode); - -#if 0 - if (verbose > 1) fprintf(stderr,"%s ",spnt->name); -#endif - s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash)); - s_hash->next = hash_table[hash_number]; - s_hash->inode = spnt->inode; - s_hash->dev = spnt->dev; - s_hash->starting_block = spnt->starting_block; - s_hash->size = spnt->size; - hash_table[hash_number] = s_hash; -} - -struct file_hash * FDECL2(find_hash, dev_t, dev, ino_t, inode){ - unsigned int hash_number; - struct file_hash * spnt; - hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode); - if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL; - - spnt = hash_table[hash_number]; - while(spnt){ - if(spnt->inode == inode && spnt->dev == dev) return spnt; - spnt = spnt->next; - }; - return NULL; -} - - -static struct file_hash * directory_hash_table[NR_HASH] = {0,}; - -void FDECL2(add_directory_hash, dev_t, dev, ino_t, inode){ - struct file_hash * s_hash; - unsigned int hash_number; - - if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return; - hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode); - - s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash)); - s_hash->next = directory_hash_table[hash_number]; - s_hash->inode = inode; - s_hash->dev = dev; - directory_hash_table[hash_number] = s_hash; -} - -struct file_hash * FDECL2(find_directory_hash, dev_t, dev, ino_t, inode){ - unsigned int hash_number; - struct file_hash * spnt; - hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode); - if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL; - - spnt = directory_hash_table[hash_number]; - while(spnt){ - if(spnt->inode == inode && spnt->dev == dev) return spnt; - spnt = spnt->next; - }; - return NULL; -} - -struct name_hash -{ - struct name_hash * next; - struct directory_entry * de; -}; - -#define NR_NAME_HASH 128 - -static struct name_hash * name_hash_table[NR_NAME_HASH] = {0,}; - -/* - * Find the hash bucket for this name. - */ -static unsigned int FDECL1(name_hash, const char *, name) -{ - unsigned int hash = 0; - const char * p; - - p = name; - - while (*p) - { - /* - * Don't hash the iso9660 version number. This way - * we can detect duplicates in cases where we have - * directories (i.e. foo) and non-directories - * (i.e. foo;1). - */ - if( *p == ';' ) - { - break; - } - hash = (hash << 15) + (hash << 3) + (hash >> 3) + *p++; - } - return hash % NR_NAME_HASH; -} - -void FDECL1(add_file_hash, struct directory_entry *, de){ - struct name_hash * new; - int hash; - - new = (struct name_hash *) e_malloc(sizeof(struct name_hash)); - new->de = de; - new->next = NULL; - hash = name_hash(de->isorec.name); - - /* Now insert into the hash table */ - new->next = name_hash_table[hash]; - name_hash_table[hash] = new; -} - -struct directory_entry * FDECL1(find_file_hash, char *, name) -{ - struct name_hash * nh; - char * p1; - char * p2; - - for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next) - { - p1 = name; - p2 = nh->de->isorec.name; - - /* - * Look for end of string, or a mismatch. - */ - while(1==1) - { - if( (*p1 == '\0' || *p1 == ';') - || (*p2 == '\0' || *p2 == ';') - || (*p1 != *p2) ) - { - break; - } - p1++; - p2++; - } - - /* - * If we are at the end of both strings, then - * we have a match. - */ - if( (*p1 == '\0' || *p1 == ';') - && (*p2 == '\0' || *p2 == ';') ) - { - return nh->de; - } - } - return NULL; -} - -int FDECL1(delete_file_hash, struct directory_entry *, de){ - struct name_hash * nh, *prev; - int hash; - - prev = NULL; - hash = name_hash(de->isorec.name); - for(nh = name_hash_table[hash]; nh; nh = nh->next) { - if(nh->de == de) break; - prev = nh; - } - if(!nh) return 1; - if(!prev) - name_hash_table[hash] = nh->next; - else - prev->next = nh->next; - free(nh); - return 0; -} - -void flush_file_hash(){ - struct name_hash * nh, *nh1; - int i; - - for(i=0; inext; - free(nh); - nh = nh1; - } - name_hash_table[i] = NULL; - - } -} diff --git a/util/mkisofs/include/fctldefs.h b/util/mkisofs/include/fctldefs.h deleted file mode 100644 index de6b6a394..000000000 --- a/util/mkisofs/include/fctldefs.h +++ /dev/null @@ -1,57 +0,0 @@ -/* @(#)fctldefs.h 1.2 98/10/08 Copyright 1996 J. Schilling */ -/* - * Generic header for users of open(), creat() and chmod() - * - * Copyright (c) 1996 J. Schilling - */ -/* - * This program 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 2, or (at your option) - * any later version. - * - * This program 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 this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _FCTLDEFS_H -#define _FCTLDEFS_H - -#ifndef _MCONFIG_H -#include -#endif - -#include -#include - -#ifdef HAVE_FCNTL_H - -# include - -#else /* HAVE_FCNTL_H */ - -# include - -#endif /* HAVE_FCNTL_H */ - -/* - * Do not define more than O_RDONLY / O_WRONLY / O_RDWR - * The values may differ. - */ -#ifndef O_RDONLY -#define O_RDONLY 0 -#endif -#ifndef O_WRONLY -#define O_WRONLY 1 -#endif -#ifndef O_RDWR -#define O_RDWR 2 -#endif - -#endif /* _FCTLDEFS_H */ diff --git a/util/mkisofs/include/mconfig.h b/util/mkisofs/include/mconfig.h deleted file mode 100644 index 1891d7ded..000000000 --- a/util/mkisofs/include/mconfig.h +++ /dev/null @@ -1,253 +0,0 @@ -/* @(#)mconfig.h 1.24 98/12/14 Copyright 1995 J. Schilling */ -/* - * definitions for machine configuration - * - * Copyright (c) 1995 J. Schilling - * - * This file must be included before any other file. - * Use only cpp instructions. - * - * NOTE: SING: (Schily Is Not Gnu) - */ -/* - * This program 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 2, or (at your option) - * any later version. - * - * This program 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 this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _MCONFIG_H -#define _MCONFIG_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(unix) || defined(__unix) || defined(__unix__) -# define IS_UNIX -#endif - -#ifdef __MSDOS__ -# define IS_MSDOS -#endif - -#if defined(tos) || defined(__tos) -# define IS_TOS -#endif - -#ifdef THINK_C -# define IS_MAC -#endif - -#if defined(sun) || defined(__sun) || defined(__sun__) -# define IS_SUN -#endif - -#if defined(__CYGWIN32__) -# define IS_GCC_WIN32 -#endif - -/*--------------------------------------------------------------------------*/ -/* - * Some magic that cannot (yet) be figured out with autoconf. - */ - -#ifdef sparc -# ifndef HAVE_LDSTUB -# define HAVE_LDSTUB -# endif -# ifndef HAVE_SCANSTACK -# define HAVE_SCANSTACK -# endif -#endif -#if defined(__i386_) || defined(i386) -# ifndef HAVE_XCHG -# define HAVE_XCHG -# endif -# ifndef HAVE_SCANSTACK -# define HAVE_SCANSTACK -# endif -#endif - -#if defined(SOL2) || defined(SOL2) || defined(S5R4) || defined(__S5R4) \ - || defined(SVR4) -# ifndef __SVR4 -# define __SVR4 -# endif -#endif - -#ifdef __SVR4 -# ifndef SVR4 -# define SVR4 -# endif -#endif - -/* - * SunOS 4.x / SunOS 5.x - */ -#if defined(IS_SUN) -# define HAVE_GETAV0 -#endif - -/* - * AIX - */ -#if defined(_IBMR2) || defined(_AIX) -# define IS_UNIX /* ??? really ??? */ -#endif - -/* - * Silicon Graphics (must be before SVR4) - */ -#if defined(sgi) || defined(__sgi) -# define __NOT_SVR4__ /* Not a real SVR4 implementation */ -#endif - -/* - * Data General - */ -#if defined(__DGUX__) -#ifdef XXXXXXX -# undef HAVE_MTGET_DSREG -# undef HAVE_MTGET_RESID -# undef HAVE_MTGET_FILENO -# undef HAVE_MTGET_BLKNO -#endif -# define mt_type mt_model -# define mt_dsreg mt_status1 -# define mt_erreg mt_status2 - /* - * DGUX hides its flock as dg_flock. - */ -# define HAVE_FLOCK -# define flock dg_flock - /* - * Use the BSD style wait on DGUX to get the resource usages of child - * processes. - */ -# define _BSD_WAIT_FLAVOR -#endif - -/* - * Apple Rhapsody - */ -#if defined(__NeXT__) && defined(__TARGET_OSNAME) && __TARGET_OSNAME == rhapsody -# define HAVE_OSDEF /* prevent later definitions to overwrite current */ -#endif - -/* - * NextStep - */ -#if defined(__NeXT__) && !defined(HAVE_OSDEF) -#define NO_PRINT_OVR -#undef HAVE_USG_STDIO /* - * NeXT Step 3.x uses __flsbuf(unsigned char , FILE *) - * instead of __flsbuf(int, FILE *) - */ -#endif - -/* - * NextStep 3.x has a broken linker that does not allow us to override - * these functions. - */ -#ifndef __OPRINTF__ - -#ifdef NO_PRINT_OVR -# define printf Xprintf -# define fprintf Xfprintf -# define sprintf Xsprintf -#endif - -#endif /* __OPRINTF__ */ - -/*--------------------------------------------------------------------------*/ -/* - * If there is no flock defined by the system, use emulation - * through fcntl record locking. - */ -#ifndef HAVE_FLOCK -#define LOCK_SH 1 /* shared lock */ -#define LOCK_EX 2 /* exclusive lock */ -#define LOCK_NB 4 /* don't block when locking */ -#define LOCK_UN 8 /* unlock */ -#endif - -#include - -/* - * gcc 2.x generally implements the long long type. - */ -#ifdef __GNUC__ -# if __GNUC__ > 1 -# ifndef HAVE_LONGLONG -# define HAVE_LONGLONG -# endif -# endif -#endif - -/* - * Convert to GNU name - */ -#ifdef HAVE_STDC_HEADERS -# ifndef STDC_HEADERS -# define STDC_HEADERS -# endif -#endif -/* - * Convert to SCHILY name - */ -#ifdef STDC_HEADERS -# ifndef HAVE_STDC_HEADERS -# define HAVE_STDC_HEADERS -# endif -#endif - -#ifdef IS_UNIX -# define PATH_DELIM '/' -# define PATH_DELIM_STR "/" -# define far -# define near -#endif - -#ifdef IS_GCC_WIN32 -# define PATH_DELIM '/' -# define PATH_DELIM_STR "/" -# define far -# define near -#endif - -#ifdef IS_MSDOS -# define PATH_DELIM '\\' -# define PATH_DELIM_STR "\\" -#endif - -#ifdef IS_TOS -# define PATH_DELIM '\\' -# define PATH_DELIM_STR "\\" -# define far -# define near -#endif - -#ifdef IS_MAC -# define PATH_DELIM ':' -# define PATH_DELIM_STR ":" -# define far -# define near -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* _MCONFIG_H */ diff --git a/util/mkisofs/include/prototyp.h b/util/mkisofs/include/prototyp.h deleted file mode 100644 index c74ae0af8..000000000 --- a/util/mkisofs/include/prototyp.h +++ /dev/null @@ -1,74 +0,0 @@ -/* @(#)prototyp.h 1.7 98/10/08 Copyright 1995 J. Schilling */ -/* - * Definitions for dealing with ANSI / KR C-Compilers - * - * Copyright (c) 1995 J. Schilling - */ -/* - * This program 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 2, or (at your option) - * any later version. - * - * This program 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 this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _PROTOTYP_H -#define _PROTOTYP_H - -#ifndef PROTOTYPES - /* - * If this has already been defined, - * someone else knows better than us... - */ -# ifdef __STDC__ -# if __STDC__ /* ANSI C */ -# define PROTOTYPES -# endif -# if defined(sun) && __STDC__ - 0 == 0 /* Sun C */ -# define PROTOTYPES -# endif -# endif -#endif /* PROTOTYPES */ - -/* - * If we have prototypes, we should have stdlib.h string.h stdarg.h - */ -#ifdef PROTOTYPES -#if !(defined(SABER) && defined(sun)) -# ifndef HAVE_STDARG_H -# define HAVE_STDARG_H -# endif -#endif -# ifndef HAVE_STDLIB_H -# define HAVE_STDLIB_H -# endif -# ifndef HAVE_STRING_H -# define HAVE_STRING_H -# endif -# ifndef HAVE_STDC_HEADERS -# define HAVE_STDC_HEADERS -# endif -# ifndef STDC_HEADERS -# define STDC_HEADERS /* GNU name */ -# endif -#endif - -#ifdef NO_PROTOTYPES /* Force not to use prototypes */ -# undef PROTOTYPES -#endif - -#ifdef PROTOTYPES -# define __PR(a) a -#else -# define __PR(a) () -#endif - -#endif /* _PROTOTYP_H */ diff --git a/util/mkisofs/include/statdefs.h b/util/mkisofs/include/statdefs.h deleted file mode 100644 index 0e34805ce..000000000 --- a/util/mkisofs/include/statdefs.h +++ /dev/null @@ -1,139 +0,0 @@ -/* @(#)statdefs.h 1.1 98/11/22 Copyright 1998 J. Schilling */ -/* - * Definitions for stat() file mode - * - * Copyright (c) 1998 J. Schilling - */ -/* - * This program 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 2, or (at your option) - * any later version. - * - * This program 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 this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _STATDEFS_H -#define _STATDEFS_H - -#ifndef _MCONFIG_H -#include -#endif - -#ifdef STAT_MACROS_BROKEN -#undef S_ISFIFO /* Named pipe */ -#undef S_ISCHR /* Character special */ -#undef S_ISMPC /* UNUSED multiplexed c */ -#undef S_ISDIR /* Directory */ -#undef S_ISNAM /* Named file (XENIX) */ -#undef S_ISBLK /* Block special */ -#undef S_ISMPB /* UNUSED multiplexed b */ -#undef S_ISREG /* Regular file */ -#undef S_ISCNT /* Contiguous file */ -#undef S_ISLNK /* Symbolic link */ -#undef S_ISSHAD /* Solaris shadow inode */ -#undef S_ISSOCK /* UNIX domain socket */ -#undef S_ISDOOR /* Solaris DOOR */ -#endif - -#ifndef S_ISFIFO /* Named pipe */ -# ifdef S_IFIFO -# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -# else -# define S_ISFIFO(m) (0) -# endif -#endif -#ifndef S_ISCHR /* Character special */ -# ifdef S_IFCHR -# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -# else -# define S_ISCHR(m) (0) -# endif -#endif -#ifndef S_ISMPC /* UNUSED multiplexed c */ -# ifdef S_IFMPC -# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) -# else -# define S_ISMPC(m) (0) -# endif -#endif -#ifndef S_ISDIR /* Directory */ -# ifdef S_IFDIR -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -# else -# define S_ISDIR(m) (0) -# endif -#endif -#ifndef S_ISNAM /* Named file (XENIX) */ -# ifdef S_IFNAM -# define S_ISNAM(m) (((m) & S_IFMT) == S_IFNAM) -# else -# define S_ISNAM(m) (0) -# endif -#endif -#ifndef S_ISBLK /* Block special */ -# ifdef S_IFBLK -# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -# else -# define S_ISBLK(m) (0) -# endif -#endif -#ifndef S_ISMPB /* UNUSED multiplexed b */ -# ifdef S_IFMPB -# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) -# else -# define S_ISMPB(m) (0) -# endif -#endif -#ifndef S_ISREG /* Regular file */ -# ifdef S_IFREG -# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -# else -# define S_ISREG(m) (0) -# endif -#endif -#ifndef S_ISCNT /* Contiguous file */ -# ifdef S_IFCNT -# define S_ISCNT(m) (((m) & S_IFMT) == S_IFCNT) -# else -# define S_ISCNT(m) (0) -# endif -#endif -#ifndef S_ISLNK /* Symbolic link */ -# ifdef S_IFLNK -# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -# else -# define S_ISLNK(m) (0) -# endif -#endif -#ifndef S_ISSHAD /* Solaris shadow inode */ -# ifdef S_IFSHAD -# define S_ISSHAD(m) (((m) & S_IFMT) == S_IFSHAD) -# else -# define S_ISSHAD(m) (0) -# endif -#endif -#ifndef S_ISSOCK /* UNIX domain socket */ -# ifdef S_IFSOCK -# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) -# else -# define S_ISSOCK(m) (0) -# endif -#endif -#ifndef S_ISDOOR /* Solaris DOOR */ -# ifdef S_IFDOOR -# define S_ISDOOR(m) (((m) & S_IFMT) == S_IFDOOR) -# else -# define S_ISDOOR(m) (0) -# endif -#endif - -#endif /* _STATDEFS_H */ - diff --git a/util/mkisofs/iso9660.h b/util/mkisofs/iso9660.h deleted file mode 100644 index 5818ee81c..000000000 --- a/util/mkisofs/iso9660.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Header file iso9660.h - assorted structure definitions and typecasts. - * specific to iso9660 filesystem. - - Written by Eric Youngdale (1993). - - Copyright 1993 Yggdrasil Computing, Incorporated - - Copyright (C) 2009 Free Software Foundation, Inc. - - This program 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, or (at your option) - any later version. - - This program 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 this program; if not, see . - */ - -/* - * $Id: iso9660.h,v 1.2 1997/05/17 15:46:44 eric Exp $ - */ - -#ifndef _ISOFS_FS_H -#define _ISOFS_FS_H - -/* - * The isofs filesystem constants/structures - */ - -/* This part borrowed from the bsd386 isofs */ -#define ISODCL(from, to) (to - from + 1) - -struct iso_volume_descriptor { - char type[ISODCL(1,1)]; /* 711 */ - char id[ISODCL(2,6)]; - char version[ISODCL(7,7)]; - char data[ISODCL(8,2048)]; -}; - -/* volume descriptor types */ -#define ISO_VD_PRIMARY 1 -#define ISO_VD_SUPPLEMENTARY 2 /* Used by Joliet */ -#define ISO_VD_END 255 - -#define ISO_STANDARD_ID "CD001" - -#define EL_TORITO_ID "EL TORITO SPECIFICATION" -#define EL_TORITO_ARCH_x86 0 -#define EL_TORITO_ARCH_PPC 1 -#define EL_TORITO_ARCH_MAC 2 -#define EL_TORITO_BOOTABLE 0x88 -#define EL_TORITO_MEDIA_NOEMUL 0 -#define EL_TORITO_MEDIA_12FLOP 1 -#define EL_TORITO_MEDIA_144FLOP 2 -#define EL_TORITO_MEDIA_288FLOP 3 -#define EL_TORITO_MEDIA_HD 4 - -struct iso_primary_descriptor { - char type [ISODCL ( 1, 1)]; /* 711 */ - char id [ISODCL ( 2, 6)]; - char version [ISODCL ( 7, 7)]; /* 711 */ - char unused1 [ISODCL ( 8, 8)]; - char system_id [ISODCL ( 9, 40)]; /* achars */ - char volume_id [ISODCL ( 41, 72)]; /* dchars */ - char unused2 [ISODCL ( 73, 80)]; - char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ - char escape_sequences [ISODCL ( 89, 120)]; - char volume_set_size [ISODCL (121, 124)]; /* 723 */ - char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ - char logical_block_size [ISODCL (129, 132)]; /* 723 */ - char path_table_size [ISODCL (133, 140)]; /* 733 */ - char type_l_path_table [ISODCL (141, 144)]; /* 731 */ - char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ - char type_m_path_table [ISODCL (149, 152)]; /* 732 */ - char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ - char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ - char volume_set_id [ISODCL (191, 318)]; /* dchars */ - char publisher_id [ISODCL (319, 446)]; /* achars */ - char preparer_id [ISODCL (447, 574)]; /* achars */ - char application_id [ISODCL (575, 702)]; /* achars */ - char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ - char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ - char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ - char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ - char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ - char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ - char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ - char file_structure_version [ISODCL (882, 882)]; /* 711 */ - char unused4 [ISODCL (883, 883)]; - char application_data [ISODCL (884, 1395)]; - char unused5 [ISODCL (1396, 2048)]; -}; - -/* El Torito Boot Record Volume Descriptor */ -struct eltorito_boot_descriptor { - char id [ISODCL ( 1, 1)]; /* 711 */ - char id2 [ISODCL ( 2, 6)]; - char version [ISODCL ( 7, 7)]; /* 711 */ - char system_id [ISODCL ( 8, 39)]; - char unused2 [ISODCL ( 40, 71)]; - char bootcat_ptr [ISODCL ( 72 , 75)]; - char unused5 [ISODCL ( 76, 2048)]; -}; - -/* Validation entry for El Torito */ -struct eltorito_validation_entry { - char headerid [ISODCL ( 1, 1)]; /* 711 */ - char arch [ISODCL ( 2, 2)]; - char pad1 [ISODCL ( 3, 4)]; /* 711 */ - char id [ISODCL ( 5, 28)]; - char cksum [ISODCL ( 29, 30)]; - char key1 [ISODCL ( 31, 31)]; - char key2 [ISODCL ( 32, 32)]; -}; - -/* El Torito initial/default entry in boot catalog */ -struct eltorito_defaultboot_entry { - char boot_id [ISODCL ( 1, 1)]; /* 711 */ - char boot_media [ISODCL ( 2, 2)]; - char loadseg [ISODCL ( 3, 4)]; /* 711 */ - char arch [ISODCL ( 5, 5)]; - char pad1 [ISODCL ( 6, 6)]; - char nsect [ISODCL ( 7, 8)]; - char bootoff [ISODCL ( 9, 12)]; - char pad2 [ISODCL ( 13, 32)]; -}; - -/* El Torito boot information table */ -struct eltorito_boot_info -{ - /* Address of Primary Volume Descriptor. */ - char pvd_addr[ISODCL (1, 4)]; - /* Boot file address. */ - char file_addr[ISODCL (5, 8)]; - /* Boot file length. */ - char file_length[ISODCL (9, 12)]; - /* Boot file checksum. */ - char file_checksum[ISODCL (13, 16)]; - char dummy[ISODCL (17, 56)]; -}; - - -/* We use this to help us look up the parent inode numbers. */ - -struct iso_path_table{ - unsigned char name_len[2]; /* 721 */ - char extent[4]; /* 731 */ - char parent[2]; /* 721 */ - char name[1]; -}; - -struct iso_directory_record { - unsigned char length [ISODCL (1, 1)]; /* 711 */ - char ext_attr_length [ISODCL (2, 2)]; /* 711 */ - char extent [ISODCL (3, 10)]; /* 733 */ - char size [ISODCL (11, 18)]; /* 733 */ - char date [ISODCL (19, 25)]; /* 7 by 711 */ - char flags [ISODCL (26, 26)]; - char file_unit_size [ISODCL (27, 27)]; /* 711 */ - char interleave [ISODCL (28, 28)]; /* 711 */ - char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ - unsigned char name_len [ISODCL (33, 33)]; /* 711 */ - char name [34]; /* Not really, but we need something here */ -}; -#endif - - - diff --git a/util/mkisofs/joliet.c b/util/mkisofs/joliet.c deleted file mode 100644 index 736037df9..000000000 --- a/util/mkisofs/joliet.c +++ /dev/null @@ -1,1023 +0,0 @@ -/* - * File joliet.c - handle Win95/WinNT long file/unicode extensions for iso9660. - - Copyright 1997 Eric Youngdale. - - Copyright (C) 2009 Free Software Foundation, Inc. - - This program 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, or (at your option) - any later version. - - This program 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 this program; if not, see . - */ - -/* - * Joliet extensions for ISO9660. These are spottily documented by - * Microsoft. In their infinite stupidity, they completely ignored - * the possibility of using an SUSP record with the long filename - * in it, and instead wrote out a duplicate directory tree with the - * long filenames in it. - * - * I am not sure why they did this. One reason is that they get the path - * tables with the long filenames in them. - * - * There are two basic principles to Joliet, and the non-Unicode variant - * known as Romeo. Long filenames seem to be the main one, and the second - * is that the character set and a few other things is substantially relaxed. - * - * The SVD is identical to the PVD, except: - * - * Id is 2, not 1 (indicates SVD). - * escape_sequences contains UCS-2 indicator (levels 1, 2 or 3). - * The root directory record points to a different extent (with different - * size). - * There are different path tables for the two sets of directory trees. - * - * The following fields are recorded in Unicode: - * system_id - * volume_id - * volume_set_id - * publisher_id - * preparer_id - * application_id - * copyright_file_id - * abstract_file_id - * bibliographic_file_id - * - * Unicode strings are always encoded in big-endian format. - * - * In a directory record, everything is the same as with iso9660, except - * that the name is recorded in unicode. The name length is specified in - * total bytes, not in number of unicode characters. - * - * The character set used for the names is different with UCS - the - * restrictions are that the following are not allowed: - * - * Characters (00)(00) through (00)(1f) (control chars) - * (00)(2a) '*' - * (00)(2f) '/' - * (00)(3a) ':' - * (00)(3b) ';' - * (00)(3f) '?' - * (00)(5c) '\' - */ -#include "config.h" -#include "mkisofs.h" -#include "iso9660.h" - -#include -#include -#include - -static unsigned int jpath_table_index; -static struct directory ** jpathlist; -static int next_jpath_index = 1; -static int sort_goof; - -static int generate_joliet_path_tables __PR((void)); -static int DECL(joliet_sort_directory, (struct directory_entry ** sort_dir)); -static void DECL(assign_joliet_directory_addresses, (struct directory * node)); -static int jroot_gen __PR((void)); - -/* - * Function: convert_to_unicode - * - * Purpose: Perform a 1/2 assed unicode conversion on a text - * string. - * - * Notes: - */ -static void FDECL3(convert_to_unicode, unsigned char *, buffer, int, size, char *, source ) -{ - unsigned char * tmpbuf; - int i; - int j; - - /* - * If we get a NULL pointer for the source, it means we have an inplace - * copy, and we need to make a temporary working copy first. - */ - if( source == NULL ) - { - tmpbuf = (uint8_t *) e_malloc(size); - memcpy( tmpbuf, buffer, size); - } - else - { - tmpbuf = (uint8_t *)source; - } - - /* - * Now start copying characters. If the size was specified to be 0, then - * assume the input was 0 terminated. - */ - j = 0; - for(i=0; i < size ; i += 2, j++) - { - buffer[i] = 0; - /* - * JS integrated from: Achim_Kaiser@t-online.de - * - * Let all valid unicode characters pass through (assuming ISO-8859-1). - * Others are set to '_' . - */ - if( tmpbuf[j] != 0 && - (tmpbuf[j] <= 0x1f || (tmpbuf[j] >= 0x7F && tmpbuf[j] <= 0xA0)) ) - { - buffer[i+1] = '_'; - } - else - { - switch(tmpbuf[j]) - { - case '*': - case '/': - case ':': - case ';': - case '?': - case '\\': - /* - * Even Joliet has some standards as to what is allowed in a pathname. - * Pretty tame in comparison to what DOS restricts you to. - */ - buffer[i+1] = '_'; - break; - default: - buffer[i+1] = tmpbuf[j]; - break; - } - } - } - - if( source == NULL ) - { - free(tmpbuf); - } -} - -/* - * Function: joliet_strlen - * - * Purpose: Return length in bytes of string after conversion to unicode. - * - * Notes: This is provided mainly as a convenience so that when more intelligent - * Unicode conversion for either Multibyte or 8-bit codes is available that - * we can easily adapt. - */ -static int FDECL1(joliet_strlen, const char *, string) -{ - int rtn; - - rtn = strlen(string) << 1; - - /* - * We do clamp the maximum length of a Joliet string to be the - * maximum path size. This helps to ensure that we don't completely - * bolix things up with very long paths. The Joliet specs say - * that the maximum length is 128 bytes, or 64 unicode characters. - */ - if( rtn > 0x80) - { - rtn = 0x80; - } - return rtn; -} - -/* - * Function: get_joliet_vol_desc - * - * Purpose: generate a Joliet compatible volume desc. - * - * Notes: Assume that we have the non-joliet vol desc - * already present in the buffer. Just modifiy the - * appropriate fields. - */ -static void FDECL1(get_joliet_vol_desc, struct iso_primary_descriptor *, jvol_desc) -{ - jvol_desc->type[0] = ISO_VD_SUPPLEMENTARY; - - /* - * For now, always do Unicode level 3. I don't really know what 1 and 2 - * are - perhaps a more limited Unicode set. - * - * FIXME(eric) - how does Romeo fit in here? As mkisofs just - * "expands" 8 bit character codes to 16 bits and does nothing - * special with the Unicode characters, therefore shouldn't mkisofs - * really be stating that it's using UCS-2 Level 1, not Level 3 for - * the Joliet directory tree. - */ - strcpy(jvol_desc->escape_sequences, "%/@"); - - /* - * Until we have Unicode path tables, leave these unset. - */ - set_733((char *) jvol_desc->path_table_size, jpath_table_size); - set_731(jvol_desc->type_l_path_table, jpath_table[0]); - set_731(jvol_desc->opt_type_l_path_table, jpath_table[1]); - set_732(jvol_desc->type_m_path_table, jpath_table[2]); - set_732(jvol_desc->opt_type_m_path_table, jpath_table[3]); - - /* - * Set this one up. - */ - memcpy(jvol_desc->root_directory_record, &jroot_record, - sizeof(struct iso_directory_record)); - - /* - * Finally, we have a bunch of strings to convert to Unicode. - * FIXME(eric) - I don't know how to do this in general, so we will - * just be really lazy and do a char -> short conversion. We probably - * will want to filter any characters >= 0x80. - */ - convert_to_unicode((uint8_t *)jvol_desc->system_id, sizeof(jvol_desc->system_id), NULL); - convert_to_unicode((uint8_t *)jvol_desc->volume_id, sizeof(jvol_desc->volume_id), NULL); - convert_to_unicode((uint8_t *)jvol_desc->volume_set_id, sizeof(jvol_desc->volume_set_id), NULL); - convert_to_unicode((uint8_t *)jvol_desc->publisher_id, sizeof(jvol_desc->publisher_id), NULL); - convert_to_unicode((uint8_t *)jvol_desc->preparer_id, sizeof(jvol_desc->preparer_id), NULL); - convert_to_unicode((uint8_t *)jvol_desc->application_id, sizeof(jvol_desc->application_id), NULL); - convert_to_unicode((uint8_t *)jvol_desc->copyright_file_id, sizeof(jvol_desc->copyright_file_id), NULL); - convert_to_unicode((uint8_t *)jvol_desc->abstract_file_id, sizeof(jvol_desc->abstract_file_id), NULL); - convert_to_unicode((uint8_t *)jvol_desc->bibliographic_file_id, sizeof(jvol_desc->bibliographic_file_id), NULL); - - -} - -static void FDECL1(assign_joliet_directory_addresses, struct directory *, node) -{ - int dir_size; - struct directory * dpnt; - - dpnt = node; - - while (dpnt) - { - if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ) - { - /* - * If we already have an extent for this (i.e. it came from - * a multisession disc), then don't reassign a new extent. - */ - dpnt->jpath_index = next_jpath_index++; - if( dpnt->jextent == 0 ) - { - dpnt->jextent = last_extent; - dir_size = (dpnt->jsize + (SECTOR_SIZE - 1)) >> 11; - last_extent += dir_size; - } - } - - /* skip if hidden - but not for the rr_moved dir */ - if(dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir)) - { - assign_joliet_directory_addresses(dpnt->subdir); - } - dpnt = dpnt->next; - } -} - -static -void FDECL1(build_jpathlist, struct directory *, node) -{ - struct directory * dpnt; - - dpnt = node; - - while (dpnt) - - { - if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ) - { - jpathlist[dpnt->jpath_index] = dpnt; - } - if(dpnt->subdir) build_jpathlist(dpnt->subdir); - dpnt = dpnt->next; - } -} /* build_jpathlist(... */ - -static int FDECL2(joliet_compare_paths, void const *, r, void const *, l) -{ - struct directory const *ll = *(struct directory * const *)l; - struct directory const *rr = *(struct directory * const *)r; - int rparent, lparent; - - rparent = rr->parent->jpath_index; - lparent = ll->parent->jpath_index; - if( rr->parent == reloc_dir ) - { - rparent = rr->self->parent_rec->filedir->jpath_index; - } - - if( ll->parent == reloc_dir ) - { - lparent = ll->self->parent_rec->filedir->jpath_index; - } - - if (rparent < lparent) - { - return -1; - } - - if (rparent > lparent) - { - return 1; - } - - return strcmp(rr->self->name, ll->self->name); - -} /* compare_paths(... */ - -static int generate_joliet_path_tables() -{ - struct directory_entry * de; - struct directory * dpnt; - int fix; - int j; - int namelen; - char * npnt; - char * npnt1; - int tablesize; - - /* - * First allocate memory for the tables and initialize the memory - */ - tablesize = jpath_blocks << 11; - jpath_table_m = (char *) e_malloc(tablesize); - jpath_table_l = (char *) e_malloc(tablesize); - memset(jpath_table_l, 0, tablesize); - memset(jpath_table_m, 0, tablesize); - - if( next_jpath_index > 0xffff ) - { - fprintf (stderr, _("Unable to generate sane path tables - too many directories (%d)\n"), - next_jpath_index); - exit (1); - } - /* - * Now start filling in the path tables. Start with root directory - */ - jpath_table_index = 0; - jpathlist = (struct directory **) e_malloc(sizeof(struct directory *) - * next_jpath_index); - memset(jpathlist, 0, sizeof(struct directory *) * next_jpath_index); - build_jpathlist(root); - - do - { - fix = 0; -#ifdef __STDC__ - qsort(&jpathlist[1], next_jpath_index-1, sizeof(struct directory *), - (int (*)(const void *, const void *))joliet_compare_paths); -#else - qsort(&jpathlist[1], next_jpath_index-1, sizeof(struct directory *), - joliet_compare_paths); -#endif - - for(j=1; jjpath_index != j) - { - jpathlist[j]->jpath_index = j; - fix++; - } - } - } while(fix); - - for(j=1; jde_name; - - npnt1 = strrchr(npnt, PATH_SEPARATOR); - if(npnt1) - { - npnt = npnt1 + 1; - } - - de = dpnt->self; - if(!de) - { - fprintf (stderr, _("Fatal goof - directory has amnesia\n")); - exit (1); - } - - namelen = joliet_strlen(de->name); - - if( dpnt == root ) - { - jpath_table_l[jpath_table_index] = 1; - jpath_table_m[jpath_table_index] = 1; - } - else - { - jpath_table_l[jpath_table_index] = namelen; - jpath_table_m[jpath_table_index] = namelen; - } - jpath_table_index += 2; - - set_731(jpath_table_l + jpath_table_index, dpnt->jextent); - set_732(jpath_table_m + jpath_table_index, dpnt->jextent); - jpath_table_index += 4; - - if( dpnt->parent != reloc_dir ) - { - set_721(jpath_table_l + jpath_table_index, - dpnt->parent->jpath_index); - set_722(jpath_table_m + jpath_table_index, - dpnt->parent->jpath_index); - } - else - { - set_721(jpath_table_l + jpath_table_index, - dpnt->self->parent_rec->filedir->jpath_index); - set_722(jpath_table_m + jpath_table_index, - dpnt->self->parent_rec->filedir->jpath_index); - } - - jpath_table_index += 2; - - /* - * The root directory is still represented in non-unicode fashion. - */ - if( dpnt == root ) - { - jpath_table_l[jpath_table_index] = 0; - jpath_table_m[jpath_table_index] = 0; - jpath_table_index ++; - } - else - { - convert_to_unicode((uint8_t *)jpath_table_l + jpath_table_index, - namelen, de->name); - convert_to_unicode((uint8_t *)jpath_table_m + jpath_table_index, - namelen, de->name); - jpath_table_index += namelen; - } - - if(jpath_table_index & 1) - { - jpath_table_index++; /* For odd lengths we pad */ - } - } - - free(jpathlist); - if(jpath_table_index != jpath_table_size) - { - fprintf(stderr, _("Joliet path table lengths do not match %d %d\n"), - jpath_table_index, - jpath_table_size); - } - return 0; -} /* generate_path_tables(... */ - -static void FDECL2(generate_one_joliet_directory, struct directory *, dpnt, FILE *, outfile) -{ - unsigned int dir_index; - char * directory_buffer; - int new_reclen; - struct directory_entry * s_entry; - struct directory_entry * s_entry1; - struct iso_directory_record jrec; - unsigned int total_size; - int cvt_len; - struct directory * finddir; - - total_size = (dpnt->jsize + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1); - directory_buffer = (char *) e_malloc(total_size); - memset(directory_buffer, 0, total_size); - dir_index = 0; - - s_entry = dpnt->jcontents; - while(s_entry) - { - if(s_entry->de_flags & INHIBIT_JOLIET_ENTRY) { - s_entry = s_entry->jnext; - continue; - } - - /* - * If this entry was a directory that was relocated, we have a bit - * of trouble here. We need to dig out the real thing and put it - * back here. In the Joliet tree, there is no relocated rock - * ridge, as there are no depth limits to a directory tree. - */ - if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 ) - { - for(s_entry1 = reloc_dir->contents; s_entry1; s_entry1 = s_entry1->next) - { - if( s_entry1->parent_rec == s_entry ) - { - break; - } - } - if( s_entry1 == NULL ) - { - /* - * We got trouble. - */ - fprintf (stderr, _("Unable to locate relocated directory\n")); - exit (1); - } - } - else - { - s_entry1 = s_entry; - } - - /* - * We do not allow directory entries to cross sector boundaries. - * Simply pad, and then start the next entry at the next sector - */ - new_reclen = s_entry1->jreclen; - if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE ) - { - dir_index = (dir_index + (SECTOR_SIZE - 1)) & - ~(SECTOR_SIZE - 1); - } - - memcpy(&jrec, &s_entry1->isorec, sizeof(struct iso_directory_record) - - sizeof(s_entry1->isorec.name)); - - cvt_len = joliet_strlen(s_entry1->name); - - /* - * Fix the record length - this was the non-Joliet version we - * were seeing. - */ - jrec.name_len[0] = cvt_len; - jrec.length[0] = s_entry1->jreclen; - - /* - * If this is a directory, fix the correct size and extent - * number. - */ - if( (jrec.flags[0] & 2) != 0 ) - { - if(strcmp(s_entry1->name,".") == 0) - { - jrec.name_len[0] = 1; - set_733((char *) jrec.extent, dpnt->jextent); - set_733((char *) jrec.size, ROUND_UP(dpnt->jsize)); - } - else if(strcmp(s_entry1->name,"..") == 0) - { - jrec.name_len[0] = 1; - if( dpnt->parent == reloc_dir ) - { - set_733((char *) jrec.extent, dpnt->self->parent_rec->filedir->jextent); - set_733((char *) jrec.size, ROUND_UP(dpnt->self->parent_rec->filedir->jsize)); - } - else - - { - set_733((char *) jrec.extent, dpnt->parent->jextent); - set_733((char *) jrec.size, ROUND_UP(dpnt->parent->jsize)); - } - } - else - { - if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 ) - { - finddir = reloc_dir->subdir; - } - else - { - finddir = dpnt->subdir; - } - while(1==1) - { - if(finddir->self == s_entry1) break; - finddir = finddir->next; - if(!finddir) - { - fprintf (stderr, _("Fatal goof - unable to find directory location\n")); - exit (1); - } - } - set_733((char *) jrec.extent, finddir->jextent); - set_733((char *) jrec.size, ROUND_UP(finddir->jsize)); - } - } - - memcpy(directory_buffer + dir_index, &jrec, - sizeof(struct iso_directory_record) - - sizeof(s_entry1->isorec.name)); - - - dir_index += sizeof(struct iso_directory_record) - - sizeof (s_entry1->isorec.name); - - /* - * Finally dump the Unicode version of the filename. - * Note - . and .. are the same as with non-Joliet discs. - */ - if( (jrec.flags[0] & 2) != 0 - && strcmp(s_entry1->name, ".") == 0 ) - { - directory_buffer[dir_index++] = 0; - } - else if( (jrec.flags[0] & 2) != 0 - && strcmp(s_entry1->name, "..") == 0 ) - { - directory_buffer[dir_index++] = 1; - } - else - { - convert_to_unicode((uint8_t *)directory_buffer + dir_index, - cvt_len, - s_entry1->name); - dir_index += cvt_len; - } - - if(dir_index & 1) - { - directory_buffer[dir_index++] = 0; - } - - s_entry = s_entry->jnext; - } - - if(dpnt->jsize != dir_index) - { - fprintf (stderr, _("Unexpected joliet directory length %d %d %s\n"), - dpnt->jsize, dir_index, dpnt->de_name); - } - - xfwrite(directory_buffer, 1, total_size, outfile); - last_extent_written += total_size >> 11; - free(directory_buffer); -} /* generate_one_joliet_directory(... */ - -static int FDECL1(joliet_sort_n_finish, struct directory *, this_dir) -{ - struct directory_entry * s_entry; - int status = 0; - - /* don't want to skip this directory if it's the reloc_dir at the moment */ - if(this_dir != reloc_dir && this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) - { - return 0; - } - - for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) - { - /* skip hidden entries */ - if( (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0 ) - { - continue; - } - - /* - * First update the path table sizes for directories. - * - * Finally, set the length of the directory entry if Joliet is used. - * The name is longer, but no Rock Ridge is ever used here, so - * depending upon the options the entry size might turn out to be about - * the same. The Unicode name is always a multiple of 2 bytes, so - * we always add 1 to make it an even number. - */ - if(s_entry->isorec.flags[0] == 2) - { - if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) - { - jpath_table_size += joliet_strlen(s_entry->name) + sizeof(struct iso_path_table) - 1; - if (jpath_table_size & 1) - { - jpath_table_size++; - } - } - else - { - if (this_dir == root && strlen(s_entry->name) == 1) - { - jpath_table_size += sizeof(struct iso_path_table); - if (jpath_table_size & 1) jpath_table_size++; - } - } - } - - if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) - { - s_entry->jreclen = sizeof(struct iso_directory_record) - - sizeof(s_entry->isorec.name) - + joliet_strlen(s_entry->name) - + 1; - } - else - { - /* - * Special - for '.' and '..' we generate the same records we - * did for non-Joliet discs. - */ - s_entry->jreclen = sizeof(struct iso_directory_record) - - sizeof(s_entry->isorec.name) - + 1; - } - - - } - - if( (this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) != 0 ) - { - return 0; - } - - this_dir->jcontents = this_dir->contents; - status = joliet_sort_directory(&this_dir->jcontents); - - /* - * Now go through the directory and figure out how large this one will be. - * Do not split a directory entry across a sector boundary - */ - s_entry = this_dir->jcontents; -/* - * XXX Is it ok to comment this out? - */ -/*XXX JS this_dir->ce_bytes = 0;*/ - for(s_entry = this_dir->jcontents; s_entry; s_entry = s_entry->jnext) - { - int jreclen; - - if( (s_entry->de_flags & INHIBIT_JOLIET_ENTRY) != 0 ) - { - continue; - } - - jreclen = s_entry->jreclen; - - if ((this_dir->jsize & (SECTOR_SIZE - 1)) + jreclen >= SECTOR_SIZE) - { - this_dir->jsize = (this_dir->jsize + (SECTOR_SIZE - 1)) & - ~(SECTOR_SIZE - 1); - } - this_dir->jsize += jreclen; - } - return status; -} - -/* - * Similar to the iso9660 case, except here we perform a full sort based upon the - * regular name of the file, not the 8.3 version. - */ -static int FDECL2(joliet_compare_dirs, const void *, rr, const void *, ll) -{ - char * rpnt, *lpnt; - struct directory_entry ** r, **l; - - r = (struct directory_entry **) rr; - l = (struct directory_entry **) ll; - rpnt = (*r)->name; - lpnt = (*l)->name; - - /* - * If the entries are the same, this is an error. - */ - if( strcmp(rpnt, lpnt) == 0 ) - { - sort_goof++; - } - - /* - * Put the '.' and '..' entries on the head of the sorted list. - * For normal ASCII, this always happens to be the case, but out of - * band characters cause this not to be the case sometimes. - */ - if( strcmp(rpnt, ".") == 0 ) return -1; - if( strcmp(lpnt, ".") == 0 ) return 1; - - if( strcmp(rpnt, "..") == 0 ) return -1; - if( strcmp(lpnt, "..") == 0 ) return 1; - - while(*rpnt && *lpnt) - { - if(*rpnt == ';' && *lpnt != ';') return -1; - if(*rpnt != ';' && *lpnt == ';') return 1; - - if(*rpnt == ';' && *lpnt == ';') return 0; - - /* - * Extensions are not special here. Don't treat the dot as something that - * must be bumped to the start of the list. - */ -#if 0 - if(*rpnt == '.' && *lpnt != '.') return -1; - if(*rpnt != '.' && *lpnt == '.') return 1; -#endif - - if(*rpnt < *lpnt) return -1; - if(*rpnt > *lpnt) return 1; - rpnt++; lpnt++; - } - if(*rpnt) return 1; - if(*lpnt) return -1; - return 0; -} - - -/* - * Function: sort_directory - * - * Purpose: Sort the directory in the appropriate ISO9660 - * order. - * - * Notes: Returns 0 if OK, returns > 0 if an error occurred. - */ -static int FDECL1(joliet_sort_directory, struct directory_entry **, sort_dir) -{ - int dcount = 0; - int i; - struct directory_entry * s_entry; - struct directory_entry ** sortlist; - - s_entry = *sort_dir; - while(s_entry) - { - /* skip hidden entries */ - if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY)) - dcount++; - s_entry = s_entry->next; - } - - /* - * OK, now we know how many there are. Build a vector for sorting. - */ - sortlist = (struct directory_entry **) - e_malloc(sizeof(struct directory_entry *) * dcount); - - dcount = 0; - s_entry = *sort_dir; - while(s_entry) - { - /* skip hidden entries */ - if (!(s_entry->de_flags & INHIBIT_JOLIET_ENTRY)) { - sortlist[dcount] = s_entry; - dcount++; - } - s_entry = s_entry->next; - } - - sort_goof = 0; -#ifdef __STDC__ - qsort(sortlist, dcount, sizeof(struct directory_entry *), - (int (*)(const void *, const void *))joliet_compare_dirs); -#else - qsort(sortlist, dcount, sizeof(struct directory_entry *), - joliet_compare_dirs); -#endif - - /* - * Now reassemble the linked list in the proper sorted order - */ - for(i=0; ijnext = sortlist[i+1]; - } - - sortlist[dcount-1]->jnext = NULL; - *sort_dir = sortlist[0]; - - free(sortlist); - return sort_goof; -} - -int FDECL1(joliet_sort_tree, struct directory *, node) -{ - struct directory * dpnt; - int ret = 0; - - dpnt = node; - - while (dpnt){ - ret = joliet_sort_n_finish(dpnt); - if( ret ) - { - break; - } - if(dpnt->subdir) ret = joliet_sort_tree(dpnt->subdir); - if( ret ) - { - break; - } - dpnt = dpnt->next; - } - return ret; -} - -static void FDECL2(generate_joliet_directories, struct directory *, node, FILE*, outfile){ - struct directory * dpnt; - - dpnt = node; - - while (dpnt) - { - if( (dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) == 0 ) - { - /* - * In theory we should never reuse a directory, so this doesn't - * make much sense. - */ - if( dpnt->jextent > session_start ) - { - generate_one_joliet_directory(dpnt, outfile); - } - } - /* skip if hidden - but not for the rr_moved dir */ - if(dpnt->subdir && (!(dpnt->dir_flags & INHIBIT_JOLIET_ENTRY) || dpnt == reloc_dir)) - generate_joliet_directories(dpnt->subdir, outfile); - dpnt = dpnt->next; - } -} - - -/* - * Function to write the EVD for the disc. - */ -static int FDECL1(jpathtab_write, FILE *, outfile) -{ - /* - * Next we write the path tables - */ - xfwrite(jpath_table_l, 1, jpath_blocks << 11, outfile); - xfwrite(jpath_table_m, 1, jpath_blocks << 11, outfile); - last_extent_written += 2*jpath_blocks; - free(jpath_table_l); - free(jpath_table_m); - jpath_table_l = NULL; - jpath_table_m = NULL; - return 0; -} - -static int FDECL1(jdirtree_size, int, starting_extent) -{ - assign_joliet_directory_addresses(root); - return 0; -} - -static int jroot_gen() -{ - jroot_record.length[0] = 1 + sizeof(struct iso_directory_record) - - sizeof(jroot_record.name); - jroot_record.ext_attr_length[0] = 0; - set_733((char *) jroot_record.extent, root->jextent); - set_733((char *) jroot_record.size, ROUND_UP(root->jsize)); - iso9660_date(jroot_record.date, root_statbuf.st_mtime); - jroot_record.flags[0] = 2; - jroot_record.file_unit_size[0] = 0; - jroot_record.interleave[0] = 0; - set_723(jroot_record.volume_sequence_number, volume_sequence_number); - jroot_record.name_len[0] = 1; - return 0; -} - -static int FDECL1(jdirtree_write, FILE *, outfile) -{ - generate_joliet_directories(root, outfile); - return 0; -} - -/* - * Function to write the EVD for the disc. - */ -static int FDECL1(jvd_write, FILE *, outfile) -{ - struct iso_primary_descriptor jvol_desc; - - /* - * Next we write out the boot volume descriptor for the disc - */ - jvol_desc = vol_desc; - get_joliet_vol_desc(&jvol_desc); - xfwrite(&jvol_desc, 1, 2048, outfile); - last_extent_written ++; - return 0; -} - -/* - * Functions to describe padding block at the start of the disc. - */ -static int FDECL1(jpathtab_size, int, starting_extent) -{ - jpath_table[0] = starting_extent; - jpath_table[1] = 0; - jpath_table[2] = jpath_table[0] + jpath_blocks; - jpath_table[3] = 0; - - last_extent += 2*jpath_blocks; - return 0; -} - -struct output_fragment joliet_desc = {NULL, oneblock_size, jroot_gen,jvd_write}; -struct output_fragment jpathtable_desc= {NULL, jpathtab_size, generate_joliet_path_tables, jpathtab_write}; -struct output_fragment jdirtree_desc = {NULL, jdirtree_size, NULL, jdirtree_write}; diff --git a/util/mkisofs/match.c b/util/mkisofs/match.c deleted file mode 100644 index 0072b504e..000000000 --- a/util/mkisofs/match.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2009 Free Software Foundation, Inc. - * - * This program 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. - * - * This program 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 this program. If not, see . - */ - -#include "config.h" - -#include -#include -#include "fnmatch.h" - -#include "match.h" - -struct pattern -{ - char *str; - struct pattern *next; -}; - -static struct pattern *patlist = NULL; -static struct pattern *i_patlist = NULL; /* ISO9660/RR */ -static struct pattern *j_patlist = NULL; /* Joliet */ - -#define DECL_ADD_MATCH(function, list) \ -void \ -function (char *pattern) \ -{ \ - struct pattern *new; \ - new = malloc (sizeof (*new)); \ - new->str = strdup (pattern); \ - new->next = list; \ - list = new; \ -} - -DECL_ADD_MATCH (add_match, patlist) -DECL_ADD_MATCH (i_add_match, i_patlist) -DECL_ADD_MATCH (j_add_match, j_patlist) - -#define DECL_MATCHES(function, list) \ -int \ -function (char *str) \ -{ \ - struct pattern *i; \ - for (i = list; i != NULL; i = i->next) \ - if (fnmatch (i->str, str, FNM_FILE_NAME) != FNM_NOMATCH) \ - return 1; \ - return 0; \ -} - -DECL_MATCHES (matches, patlist) -DECL_MATCHES (i_matches, i_patlist) -DECL_MATCHES (j_matches, j_patlist) - -int -i_ishidden() -{ - return (i_patlist != NULL); -} - - -int j_ishidden() -{ - return (j_patlist != NULL); -} diff --git a/util/mkisofs/match.h b/util/mkisofs/match.h deleted file mode 100644 index ee346a24c..000000000 --- a/util/mkisofs/match.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2009 Free Software Foundation, Inc. - * - * This program 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. - * - * This program 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 this program. If not, see . - */ - -#include "config.h" - -extern void add_match (char *); -extern void i_add_match (char *); -extern void j_add_match (char *); - -extern int matches (char *); -extern int i_matches (char *); -extern int j_matches (char *); - -extern int i_ishidden (); -extern int j_ishidden (); diff --git a/util/mkisofs/mkisofs.c b/util/mkisofs/mkisofs.c deleted file mode 100644 index 803317ba0..000000000 --- a/util/mkisofs/mkisofs.c +++ /dev/null @@ -1,1410 +0,0 @@ -/* - * Program mkisofs.c - generate iso9660 filesystem based upon directory - * tree on hard disk. - - Written by Eric Youngdale (1993). - - Copyright 1993 Yggdrasil Computing, Incorporated - - Copyright (C) 2009 Free Software Foundation, Inc. - - This program 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, or (at your option) - any later version. - - This program 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 this program; if not, see . - */ - -#include -#include "config.h" -#include "mkisofs.h" -#include "match.h" - -#ifdef linux -#include -#else -#include "getopt.h" -#endif - -#include "iso9660.h" -#include - -#ifndef VMS -#include -#else -#include -#include "vms.h" -#endif - -#include -#include - -#ifndef VMS -#ifdef HAVE_UNISTD_H -#include -#endif -#endif -#include - -#include "exclude.h" - -#ifdef __NetBSD__ -#include -#include -#endif - -struct directory * root = NULL; - -static char version_string[] = "mkisofs 1.12b5"; - -#include "progname.h" - -char * outfile; -FILE * discimage; -uint64_t next_extent = 0; -uint64_t last_extent = 0; -uint64_t session_start = 0; -unsigned int path_table_size = 0; -unsigned int path_table[4] = {0,}; -unsigned int path_blocks = 0; - - -unsigned int jpath_table_size = 0; -unsigned int jpath_table[4] = {0,}; -unsigned int jpath_blocks = 0; - -struct iso_directory_record root_record; -struct iso_directory_record jroot_record; - -char * extension_record = NULL; -int extension_record_extent = 0; -int extension_record_size = 0; - -/* These variables are associated with command line options */ -int use_eltorito = 0; -int use_eltorito_emul_floppy = 0; -int use_boot_info_table = 0; -int use_RockRidge = 0; -int use_Joliet = 0; -int verbose = 1; -int all_files = 0; -int follow_links = 0; -int rationalize = 0; -int generate_tables = 0; -int print_size = 0; -int split_output = 0; -char * preparer = PREPARER_DEFAULT; -char * publisher = PUBLISHER_DEFAULT; -char * appid = APPID_DEFAULT; -char * copyright = COPYRIGHT_DEFAULT; -char * biblio = BIBLIO_DEFAULT; -char * abstract = ABSTRACT_DEFAULT; -char * volset_id = VOLSET_ID_DEFAULT; -char * volume_id = VOLUME_ID_DEFAULT; -char * system_id = SYSTEM_ID_DEFAULT; -char * boot_catalog = BOOT_CATALOG_DEFAULT; -char * boot_image = BOOT_IMAGE_DEFAULT; -int volume_set_size = 1; -int volume_sequence_number = 1; - -int omit_period = 0; /* Violates iso9660, but these are a pain */ -int transparent_compression = 0; /* So far only works with linux */ -int omit_version_number = 0; /* May violate iso9660, but noone uses vers*/ -unsigned int RR_relocation_depth = 6; /* Violates iso9660, but most systems work */ -int full_iso9660_filenames = 0; /* Used with Amiga. Disc will not work with - DOS */ -int allow_leading_dots = 0; /* DOS cannot read names with leading dots */ -int split_SL_component = 1; /* circumvent a bug in the SunOS driver */ -int split_SL_field = 1; /* circumvent a bug in the SunOS */ - -struct rcopts{ - char * tag; - char ** variable; -}; - -struct rcopts rcopt[] = { - {"PREP", &preparer}, - {"PUBL", &publisher}, - {"APPI", &appid}, - {"COPY", ©right}, - {"BIBL", &biblio}, - {"ABST", &abstract}, - {"VOLS", &volset_id}, - {"VOLI", &volume_id}, - {"SYSI", &system_id}, - {NULL, NULL} -}; - -/* - * In case it isn't obvious, the option handling code was ripped off from GNU-ld. - */ -struct ld_option -{ - /* The long option information. */ - struct option opt; - /* The short option with the same meaning ('\0' if none). */ - char shortopt; - /* The name of the argument (NULL if none). */ - const char *arg; - /* The documentation string. If this is NULL, this is a synonym for - the previous option. */ - const char *doc; - enum - { - /* Use one dash before long option name. */ - ONE_DASH, - /* Use two dashes before long option name. */ - TWO_DASHES, - /* Don't mention this option in --help output. */ - NO_HELP - } control; -}; - -/* Codes used for the long options with no short synonyms. 150 isn't - special; it's just an arbitrary non-ASCII char value. */ -#define OPTION_HELP 150 -#define OPTION_QUIET 151 -#define OPTION_NOSPLIT_SL_COMPONENT 152 -#define OPTION_NOSPLIT_SL_FIELD 153 -#define OPTION_PRINT_SIZE 154 -#define OPTION_SPLIT_OUTPUT 155 -#define OPTION_ABSTRACT 156 -#define OPTION_BIBLIO 157 -#define OPTION_COPYRIGHT 158 -#define OPTION_SYSID 159 -#define OPTION_VOLSET 160 -#define OPTION_VOLSET_SIZE 161 -#define OPTION_VOLSET_SEQ_NUM 162 -#define OPTION_I_HIDE 163 -#define OPTION_J_HIDE 164 -#define OPTION_LOG_FILE 165 - -#define OPTION_CREAT_DATE 166 -#define OPTION_MODIF_DATE 167 -#define OPTION_EXPIR_DATE 168 -#define OPTION_EFFEC_DATE 169 - -#define OPTION_BOOT_INFO_TABLE 170 -#define OPTION_NO_EMUL_BOOT 171 -#define OPTION_ELTORITO_EMUL_FLOPPY 172 - -#define OPTION_VERSION 173 - -static const struct ld_option ld_options[] = -{ - { {"all-files", no_argument, NULL, 'a'}, - 'a', NULL, N_("Process all files (don't skip backup files)"), ONE_DASH }, - { {"abstract", required_argument, NULL, OPTION_ABSTRACT}, - '\0', N_("FILE"), N_("Set Abstract filename"), ONE_DASH }, - { {"appid", required_argument, NULL, 'A'}, - 'A', N_("ID"), N_("Set Application ID"), ONE_DASH }, - { {"biblio", required_argument, NULL, OPTION_BIBLIO}, - '\0', N_("FILE"), N_("Set Bibliographic filename"), ONE_DASH }, - { {"copyright", required_argument, NULL, OPTION_COPYRIGHT}, - '\0', N_("FILE"), N_("Set Copyright filename"), ONE_DASH }, - { {"eltorito-boot", required_argument, NULL, 'b'}, - 'b', N_("FILE"), N_("Set El Torito boot image name"), ONE_DASH }, - { {"eltorito-catalog", required_argument, NULL, 'c'}, - 'c', N_("FILE"), N_("Set El Torito boot catalog name"), ONE_DASH }, - { {"boot-info-table", no_argument, NULL, OPTION_BOOT_INFO_TABLE }, - '\0', NULL, N_("Patch Boot Info Table in El Torito boot image"), ONE_DASH }, - { {"no-emul-boot", no_argument, NULL, OPTION_NO_EMUL_BOOT }, - '\0', NULL, N_("Dummy option for backward compatibility"), ONE_DASH }, - { {"eltorito-emul-floppy", no_argument, NULL, OPTION_ELTORITO_EMUL_FLOPPY }, - '\0', NULL, N_("Enable floppy drive emulation for El Torito"), TWO_DASHES }, - { {"cdwrite-params", required_argument, NULL, 'C'}, - 'C', N_("PARAMS"), N_("Magic parameters from cdrecord"), ONE_DASH }, - { {"omit-period", no_argument, NULL, 'd'}, - 'd', NULL, N_("Omit trailing periods from filenames"), ONE_DASH }, - { {"disable-deep-relocation", no_argument, NULL, 'D'}, - 'D', NULL, N_("Disable deep directory relocation"), ONE_DASH }, - { {"follow-links", no_argument, NULL, 'f'}, - 'f', NULL, N_("Follow symbolic links"), ONE_DASH }, - { {"help", no_argument, NULL, OPTION_HELP}, - '\0', NULL, N_("Print option help"), ONE_DASH }, - { {"help", no_argument, NULL, OPTION_HELP}, - '\0', NULL, N_("Print option help"), TWO_DASHES }, - { {"version", no_argument, NULL, OPTION_VERSION}, - '\0', NULL, N_("Print version information and exit"), TWO_DASHES }, - { {"hide", required_argument, NULL, OPTION_I_HIDE}, - '\0', N_("GLOBFILE"), N_("Hide ISO9660/RR file"), ONE_DASH }, - { {"hide-joliet", required_argument, NULL, OPTION_J_HIDE}, - '\0', N_("GLOBFILE"), N_("Hide Joliet file"), ONE_DASH }, - { {NULL, required_argument, NULL, 'i'}, - 'i', N_("ADD_FILES"), N_("No longer supported"), TWO_DASHES }, - { {"joliet", no_argument, NULL, 'J'}, - 'J', NULL, N_("Generate Joliet directory information"), ONE_DASH }, - { {"full-iso9660-filenames", no_argument, NULL, 'l'}, - 'l', NULL, N_("Allow full 32 character filenames for iso9660 names"), ONE_DASH }, - { {"allow-leading-dots", no_argument, NULL, 'L'}, - 'L', NULL, N_("Allow iso9660 filenames to start with '.'"), ONE_DASH }, - { {"log-file", required_argument, NULL, OPTION_LOG_FILE}, - '\0', N_("LOG_FILE"), N_("Re-direct messages to LOG_FILE"), ONE_DASH }, - { {"exclude", required_argument, NULL, 'm'}, - 'm', N_("GLOBFILE"), N_("Exclude file name"), ONE_DASH }, - { {"prev-session", required_argument, NULL, 'M'}, - 'M', N_("FILE"), N_("Set path to previous session to merge"), ONE_DASH }, - { {"omit-version-number", no_argument, NULL, 'N'}, - 'N', NULL, N_("Omit version number from iso9660 filename"), ONE_DASH }, - { {"no-split-symlink-components", no_argument, NULL, 0}, - 0, NULL, N_("Inhibit splitting symlink components"), ONE_DASH }, - { {"no-split-symlink-fields", no_argument, NULL, 0}, - 0, NULL, N_("Inhibit splitting symlink fields"), ONE_DASH }, - { {"output", required_argument, NULL, 'o'}, - 'o', N_("FILE"), N_("Set output file name"), ONE_DASH }, - { {"preparer", required_argument, NULL, 'p'}, - 'p', N_("PREP"), N_("Set Volume preparer"), ONE_DASH }, - { {"print-size", no_argument, NULL, OPTION_PRINT_SIZE}, - '\0', NULL, N_("Print estimated filesystem size and exit"), ONE_DASH }, - { {"publisher", required_argument, NULL, 'P'}, - 'P', N_("PUB"), N_("Set Volume publisher"), ONE_DASH }, - { {"quiet", no_argument, NULL, OPTION_QUIET}, - '\0', NULL, N_("Run quietly"), ONE_DASH }, - { {"rational-rock", no_argument, NULL, 'r'}, - 'r', NULL, N_("Generate rationalized Rock Ridge directory information"), ONE_DASH }, - { {"rock", no_argument, NULL, 'R'}, - 'R', NULL, N_("Generate Rock Ridge directory information"), ONE_DASH }, - { {"split-output", no_argument, NULL, OPTION_SPLIT_OUTPUT}, - '\0', NULL, N_("Split output into files of approx. 1GB size"), ONE_DASH }, - { {"sysid", required_argument, NULL, OPTION_SYSID}, - '\0', N_("ID"), N_("Set System ID"), ONE_DASH }, - { {"translation-table", no_argument, NULL, 'T'}, - 'T', NULL, N_("Generate translation tables for systems that don't understand long filenames"), ONE_DASH }, - { {"verbose", no_argument, NULL, 'v'}, - 'v', NULL, N_("Verbose"), ONE_DASH }, - { {"volid", required_argument, NULL, 'V'}, - 'V', N_("ID"), N_("Set Volume ID"), ONE_DASH }, - { {"volset", required_argument, NULL, OPTION_VOLSET}, - '\0', N_("ID"), N_("Set Volume set ID"), ONE_DASH }, - { {"volset-size", required_argument, NULL, OPTION_VOLSET_SIZE}, - '\0', "#", N_("Set Volume set size"), ONE_DASH }, - { {"volset-seqno", required_argument, NULL, OPTION_VOLSET_SEQ_NUM}, - '\0', "#", N_("Set Volume set sequence number"), ONE_DASH }, - { {"old-exclude", required_argument, NULL, 'x'}, - 'x', N_("FILE"), N_("Exclude file name (deprecated)"), ONE_DASH }, -#ifdef ERIC_neverdef - { {"transparent-compression", no_argument, NULL, 'z'}, - 'z', NULL, "Enable transparent compression of files", ONE_DASH }, -#endif - { {"creation-date", required_argument, NULL, OPTION_CREAT_DATE }, - '\0', NULL, N_("Override creation date"), TWO_DASHES }, - { {"modification-date", required_argument, NULL, OPTION_MODIF_DATE }, - '\0', NULL, N_("Override modification date"), TWO_DASHES }, - { {"expiration-date", required_argument, NULL, OPTION_EXPIR_DATE }, - '\0', NULL, N_("Override expiration date"), TWO_DASHES }, - { {"effective-date", required_argument, NULL, OPTION_EFFEC_DATE }, - '\0', NULL, N_("Override effective date"), TWO_DASHES }, -}; - -#define OPTION_COUNT (sizeof ld_options / sizeof ld_options[0]) - -#if defined(ultrix) || defined(_AUX_SOURCE) -char *strdup(s) -char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;} -#endif - - void read_rcfile __PR((char * appname)); - void usage __PR((void)); -static void hide_reloc_dir __PR((void)); - -void FDECL1(read_rcfile, char *, appname) -{ - FILE * rcfile; - struct rcopts * rco; - char * pnt, *pnt1; - char linebuffer[256]; - static char rcfn[] = ".mkisofsrc"; - char filename[1000]; - int linum; - - strcpy(filename, rcfn); - rcfile = fopen(filename, "r"); - if (!rcfile && errno != ENOENT) - perror(filename); - - if (!rcfile) - { - pnt = getenv("MKISOFSRC"); - if (pnt && strlen(pnt) <= sizeof(filename)) - { - strcpy(filename, pnt); - rcfile = fopen(filename, "r"); - if (!rcfile && errno != ENOENT) - perror(filename); - } - } - - if (!rcfile) - { - pnt = getenv("HOME"); - if (pnt && strlen(pnt) + strlen(rcfn) + 2 <= sizeof(filename)) - { - strcpy(filename, pnt); - strcat(filename, "/"); - strcat(filename, rcfn); - rcfile = fopen(filename, "r"); - if (!rcfile && errno != ENOENT) - perror(filename); - } - } - if (!rcfile && strlen(appname)+sizeof(rcfn)+2 <= sizeof(filename)) - { - strcpy(filename, appname); - pnt = strrchr(filename, '/'); - if (pnt) - { - strcpy(pnt + 1, rcfn); - rcfile = fopen(filename, "r"); - if (!rcfile && errno != ENOENT) - perror(filename); - } - } - if (!rcfile) - return; - if ( verbose > 0 ) - { - fprintf (stderr, _("Using \"%s\"\n"), filename); - } - - /* OK, we got it. Now read in the lines and parse them */ - linum = 0; - while (fgets(linebuffer, sizeof(linebuffer), rcfile)) - { - char *name; - char *name_end; - ++linum; - /* skip any leading white space */ - pnt = linebuffer; - while (*pnt == ' ' || *pnt == '\t') - ++pnt; - /* If we are looking at a # character, this line is a comment. */ - if (*pnt == '#') - continue; - /* The name should begin in the left margin. Make sure it is in - upper case. Stop when we see white space or a comment. */ - name = pnt; - while (*pnt && isalpha((unsigned char)*pnt)) - { - if(islower((unsigned char)*pnt)) - *pnt = toupper((unsigned char)*pnt); - pnt++; - } - if (name == pnt) - { - fprintf(stderr, _("%s:%d: name required\n"), filename, linum); - continue; - } - name_end = pnt; - /* Skip past white space after the name */ - while (*pnt == ' ' || *pnt == '\t') - pnt++; - /* silently ignore errors in the rc file. */ - if (*pnt != '=') - { - fprintf (stderr, _("%s:%d: equals sign required\n"), filename, linum); - continue; - } - /* Skip pas the = sign, and any white space following it */ - pnt++; /* Skip past '=' sign */ - while (*pnt == ' ' || *pnt == '\t') - pnt++; - - /* now it is safe to NUL terminate the name */ - - *name_end = 0; - - /* Now get rid of trailing newline */ - - pnt1 = pnt; - while (*pnt1) - { - if (*pnt1 == '\n') - { - *pnt1 = 0; - break; - } - pnt1++; - }; - /* OK, now figure out which option we have */ - for(rco = rcopt; rco->tag; rco++) { - if(strcmp(rco->tag, name) == 0) - { - *rco->variable = strdup(pnt); - break; - }; - } - if (rco->tag == NULL) - { - fprintf (stderr, _("%s:%d: field name \"%s\" unknown\n"), filename, linum, - name); - } - } - if (ferror(rcfile)) - perror(filename); - fclose(rcfile); -} - -char * path_table_l = NULL; -char * path_table_m = NULL; - -char * jpath_table_l = NULL; -char * jpath_table_m = NULL; - -int goof = 0; - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -void usage(){ - unsigned int i; -/* const char **targets, **pp;*/ - - printf (_("Usage: %s [options] file...\n"), program_name); - - printf (_("Options:\n")); - for (i = 0; i < OPTION_COUNT; i++) - { - if (ld_options[i].doc != NULL) - { - int comma; - int len; - unsigned int j; - char *arg; - - printf (" "); - - comma = FALSE; - len = 2; - - j = i; - do - { - if (ld_options[j].shortopt != '\0' - && ld_options[j].control != NO_HELP) - { - printf ("%s-%c", comma ? ", " : "", ld_options[j].shortopt); - len += (comma ? 2 : 0) + 2; - if (ld_options[j].arg != NULL) - { - if (ld_options[j].opt.has_arg != optional_argument) - { - putchar (' '); - ++len; - } - arg = gettext (ld_options[j].arg); - printf ("%s", arg); - len += strlen (arg); - } - comma = TRUE; - } - ++j; - } - while (j < OPTION_COUNT && ld_options[j].doc == NULL); - - j = i; - do - { - if (ld_options[j].opt.name != NULL - && ld_options[j].control != NO_HELP) - { - printf ("%s-%s%s", - comma ? ", " : "", - ld_options[j].control == TWO_DASHES ? "-" : "", - ld_options[j].opt.name); - len += ((comma ? 2 : 0) - + 1 - + (ld_options[j].control == TWO_DASHES ? 1 : 0) - + strlen (ld_options[j].opt.name)); - if (ld_options[j].arg != NULL) - { - arg = gettext (ld_options[j].arg); - printf (" %s", arg); - len += 1 + strlen (arg); - } - comma = TRUE; - } - ++j; - } - while (j < OPTION_COUNT && ld_options[j].doc == NULL); - - if (len >= 30) - { - printf ("\n"); - len = 0; - } - - for (; len < 30; len++) - putchar (' '); - - printf ("%s\n", gettext (ld_options[i].doc)); - } - } - exit(1); -} - - -/* - * Fill in date in the iso9660 format - * - * The standards state that the timezone offset is in multiples of 15 - * minutes, and is what you add to GMT to get the localtime. The U.S. - * is always at a negative offset, from -5h to -8h (can vary a little - * with DST, I guess). The Linux iso9660 filesystem has had the sign - * of this wrong for ages (mkisofs had it wrong too for the longest time). - */ -int FDECL2(iso9660_date,char *, result, time_t, crtime){ - struct tm *local; - local = localtime(&crtime); - result[0] = local->tm_year; - result[1] = local->tm_mon + 1; - result[2] = local->tm_mday; - result[3] = local->tm_hour; - result[4] = local->tm_min; - result[5] = local->tm_sec; - - /* - * Must recalculate proper timezone offset each time, - * as some files use daylight savings time and some don't... - */ - result[6] = local->tm_yday; /* save yday 'cause gmtime zaps it */ - local = gmtime(&crtime); - local->tm_year -= result[0]; - local->tm_yday -= result[6]; - local->tm_hour -= result[3]; - local->tm_min -= result[4]; - if (local->tm_year < 0) - { - local->tm_yday = -1; - } - else - { - if (local->tm_year > 0) local->tm_yday = 1; - } - - result[6] = -(local->tm_min + 60*(local->tm_hour + 24*local->tm_yday)) / 15; - - return 0; -} - -/* hide "./rr_moved" if all its contents are hidden */ -static void -hide_reloc_dir() -{ - struct directory_entry * s_entry; - - for (s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next) { - if(strcmp(s_entry->name,".")==0 || strcmp(s_entry->name,"..")==0) - continue; - - if((s_entry->de_flags & INHIBIT_ISO9660_ENTRY) == 0) - return; - } - - /* all entries are hidden, so hide this directory */ - reloc_dir->dir_flags |= INHIBIT_ISO9660_ENTRY; - reloc_dir->self->de_flags |= INHIBIT_ISO9660_ENTRY; -} - -extern char * cdwrite_data; - -int FDECL2(main, int, argc, char **, argv){ - struct directory_entry de; -#ifdef HAVE_SBRK - unsigned long mem_start; -#endif - struct stat statbuf; - char * scan_tree; - char * merge_image = NULL; - struct iso_directory_record * mrootp = NULL; - struct output_fragment * opnt; - int longind; - char shortopts[OPTION_COUNT * 3 + 2]; - struct option longopts[OPTION_COUNT + 1]; - int c; - char *log_file = 0; - - set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - if (argc < 2) - usage(); - - /* Get the defaults from the .mkisofsrc file */ - read_rcfile(argv[0]); - - outfile = NULL; - - /* - * Copy long option initialization from GNU-ld. - */ - /* Starting the short option string with '-' is for programs that - expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. */ - { - unsigned int i; - int is, il; - shortopts[0] = '-'; - is = 1; - il = 0; - for (i = 0; i < OPTION_COUNT; i++) - { - if (ld_options[i].shortopt != '\0') - { - shortopts[is] = ld_options[i].shortopt; - ++is; - if (ld_options[i].opt.has_arg == required_argument - || ld_options[i].opt.has_arg == optional_argument) - { - shortopts[is] = ':'; - ++is; - if (ld_options[i].opt.has_arg == optional_argument) - { - shortopts[is] = ':'; - ++is; - } - } - } - if (ld_options[i].opt.name != NULL) - { - longopts[il] = ld_options[i].opt; - ++il; - } - } - shortopts[is] = '\0'; - longopts[il].name = NULL; - } - - while ((c = getopt_long_only (argc, argv, shortopts, longopts, &longind)) != EOF) - switch (c) - { - case 1: - /* - * A filename that we take as input. - */ - optind--; - goto parse_input_files; - case 'C': - /* - * This is a temporary hack until cdwrite gets the proper hooks in - * it. - */ - cdwrite_data = optarg; - break; - case 'i': - fprintf (stderr, _("-i option no longer supported.\n")); - exit(1); - break; - case 'J': - use_Joliet++; - break; - case 'a': - all_files++; - break; - case 'b': - use_eltorito++; - boot_image = optarg; /* pathname of the boot image on cd */ - if (boot_image == NULL) - { - fprintf (stderr, _("Required boot image pathname missing\n")); - exit (1); - } - break; - case 'c': - use_eltorito++; - boot_catalog = optarg; /* pathname of the boot image on cd */ - if (boot_catalog == NULL) - { - fprintf (stderr, _("Required boot catalog pathname missing\n")); - exit (1); - } - break; - case OPTION_BOOT_INFO_TABLE: - use_boot_info_table = 1; - break; - case OPTION_NO_EMUL_BOOT: - fprintf (stderr, _("Ignoring -no-emul-boot (no-emulation is the default behaviour)\n")); - break; - case OPTION_ELTORITO_EMUL_FLOPPY: - use_eltorito_emul_floppy = 1; - break; - case OPTION_ABSTRACT: - abstract = optarg; - if(strlen(abstract) > 37) - { - fprintf (stderr, _("Abstract filename string too long\n")); - exit (1); - }; - break; - case 'A': - appid = optarg; - if(strlen(appid) > 128) - { - fprintf (stderr, _("Application-id string too long\n")); - exit (1); - }; - break; - case OPTION_BIBLIO: - biblio = optarg; - if(strlen(biblio) > 37) - { - fprintf (stderr, _("Bibliographic filename string too long\n")); - exit (1); - }; - break; - case OPTION_COPYRIGHT: - copyright = optarg; - if(strlen(copyright) > 37) - { - fprintf (stderr, _("Copyright filename string too long\n")); - exit (1); - }; - break; - case 'd': - omit_period++; - break; - case 'D': - RR_relocation_depth = 32767; - break; - case 'f': - follow_links++; - break; - case 'l': - full_iso9660_filenames++; - break; - case 'L': - allow_leading_dots++; - break; - case OPTION_LOG_FILE: - log_file = optarg; - break; - case 'M': - merge_image = optarg; - break; - case 'N': - omit_version_number++; - break; - case 'o': - outfile = optarg; - break; - case 'p': - preparer = optarg; - if(strlen(preparer) > 128) - { - fprintf (stderr, _("Preparer string too long\n")); - exit (1); - }; - break; - case OPTION_PRINT_SIZE: - print_size++; - break; - case 'P': - publisher = optarg; - if(strlen(publisher) > 128) - { - fprintf (stderr, _("Publisher string too long\n")); - exit (1); - }; - break; - case OPTION_QUIET: - verbose = 0; - break; - case 'R': - use_RockRidge++; - break; - case 'r': - rationalize++; - use_RockRidge++; - break; - case OPTION_SPLIT_OUTPUT: - split_output++; - break; - case OPTION_SYSID: - system_id = optarg; - if(strlen(system_id) > 32) - { - fprintf (stderr, _("System ID string too long\n")); - exit (1); - }; - break; - case 'T': - generate_tables++; - break; - case 'V': - volume_id = optarg; - if(strlen(volume_id) > 32) - { - fprintf (stderr, _("Volume ID string too long\n")); - exit (1); - }; - break; - case OPTION_VOLSET: - volset_id = optarg; - if(strlen(volset_id) > 128) - { - fprintf (stderr, _("Volume set ID string too long\n")); - exit (1); - }; - break; - case OPTION_VOLSET_SIZE: - volume_set_size = atoi(optarg); - break; - case OPTION_VOLSET_SEQ_NUM: - volume_sequence_number = atoi(optarg); - if (volume_sequence_number > volume_set_size) - { - fprintf (stderr, _("Volume set sequence number too big\n")); - exit (1); - } - break; - case 'v': - verbose++; - break; - case 'z': - transparent_compression++; - break; - case 'x': - case 'm': - /* - * Somehow two options to do basically the same thing got added somewhere along - * the way. The 'match' code supports limited globbing, so this is the one - * that got selected. Unfortunately the 'x' switch is probably more intuitive. - */ - add_match(optarg); - break; - case OPTION_I_HIDE: - i_add_match(optarg); - break; - case OPTION_J_HIDE: - j_add_match(optarg); - break; - case OPTION_HELP: - usage (); - exit (0); - break; - case OPTION_VERSION: - printf ("%s (%s %s)\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); - exit (0); - break; - case OPTION_NOSPLIT_SL_COMPONENT: - split_SL_component = 0; - break; - case OPTION_NOSPLIT_SL_FIELD: - split_SL_field = 0; - break; - case OPTION_CREAT_DATE: - if (strlen (optarg) != 16) - { - fprintf (stderr, _("date string must be 16 characters.\n")); - exit (1); - } - if (creation_date) - free(creation_date); - creation_date = strdup(optarg); - break; - case OPTION_MODIF_DATE: - if (strlen (optarg) != 16) - { - fprintf (stderr, _("date string must be 16 characters.\n")); - exit (1); - } - if (modification_date) - free(modification_date); - modification_date = strdup(optarg); - break; - case OPTION_EXPIR_DATE: - if (strlen (optarg) != 16) - { - fprintf (stderr, _("date string must be 16 characters.\n")); - exit (1); - } - if (expiration_date) - free(expiration_date); - expiration_date = strdup(optarg); - break; - case OPTION_EFFEC_DATE: - if (strlen (optarg) != 16) - { - fprintf (stderr, _("date string must be 16 characters.\n")); - exit (1); - } - if (effective_date) - free(effective_date); - effective_date = strdup(optarg); - break; - default: - usage(); - exit(1); - } - -parse_input_files: - -#ifdef __NetBSD__ - { - int resource; - struct rlimit rlp; - if (getrlimit(RLIMIT_DATA,&rlp) == -1) - perror (_("Warning: getrlimit")); - else { - rlp.rlim_cur=33554432; - if (setrlimit(RLIMIT_DATA,&rlp) == -1) - perror (_("Warning: setrlimit")); - } - } -#endif -#ifdef HAVE_SBRK - mem_start = (unsigned long) sbrk(0); -#endif - - /* if the -hide-joliet option has been given, set the Joliet option */ - if (!use_Joliet && j_ishidden()) - use_Joliet++; - - if(verbose > 1) fprintf(stderr,"%s\n", version_string); - - if(cdwrite_data == NULL && merge_image != NULL) - { - fprintf (stderr, _("Multisession usage bug: Must specify -C if -M is used.\n")); - exit (0); - } - - if(cdwrite_data != NULL && merge_image == NULL) - { - fprintf (stderr, _("Warning: -C specified without -M: old session data will not be merged.\n")); - } - - /* The first step is to scan the directory tree, and take some notes */ - - scan_tree = argv[optind]; - - - if(!scan_tree){ - usage(); - exit(1); - }; - -#ifndef VMS - if(scan_tree[strlen(scan_tree)-1] != '/') { - scan_tree = (char *) e_malloc(strlen(argv[optind])+2); - strcpy(scan_tree, argv[optind]); - strcat(scan_tree, "/"); - }; -#endif - - if(use_RockRidge){ -#if 1 - extension_record = generate_rr_extension_record("RRIP_1991A", - "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", - "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size); -#else - extension_record = generate_rr_extension_record("IEEE_P1282", - "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS", - "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size); -#endif - } - - if (log_file) { - FILE *lfp; - int i; - - /* open log file - test that we can open OK */ - if ((lfp = fopen(log_file, "w")) == NULL) - error (1, errno, _("can't open logfile: %s"), log_file); - fclose(lfp); - - /* redirect all stderr message to log_file */ - fprintf (stderr, _("re-directing all messages to %s\n"), log_file); - fflush(stderr); - - /* associate stderr with the log file */ - if (freopen(log_file, "w", stderr) == NULL) - error (1, errno, _("can't open logfile: %s\n"), log_file); - if(verbose > 1) { - for (i=0;iextent, 8); - } - - /* - * Create an empty root directory. If we ever scan it for real, we will fill in the - * contents. - */ - find_or_create_directory(NULL, "", &de, TRUE); - - /* - * Scan the actual directory (and any we find below it) - * for files to write out to the output image. Note - we - * take multiple source directories and keep merging them - * onto the image. - */ - while(optind < argc) - { - char * node; - struct directory * graft_dir; - struct stat st; - char * short_name; - int status; - char graft_point[1024]; - - /* - * We would like a syntax like: - * - * /tmp=/usr/tmp/xxx - * - * where the user can specify a place to graft each - * component of the tree. To do this, we may have to create - * directories along the way, of course. - * Secondly, I would like to allow the user to do something - * like: - * - * /home/baz/RMAIL=/u3/users/baz/RMAIL - * - * so that normal files could also be injected into the tree - * at an arbitrary point. - * - * The idea is that the last component of whatever is being - * entered would take the name from the last component of - * whatever the user specifies. - * - * The default will be that the file is injected at the - * root of the image tree. - */ - node = strchr(argv[optind], '='); - short_name = NULL; - - if( node != NULL ) - { - char * pnt; - char * xpnt; - - *node = '\0'; - strcpy(graft_point, argv[optind]); - *node = '='; - node++; - - graft_dir = root; - xpnt = graft_point; - if( *xpnt == PATH_SEPARATOR ) - { - xpnt++; - } - - /* - * Loop down deeper and deeper until we - * find the correct insertion spot. - */ - while(1==1) - { - pnt = strchr(xpnt, PATH_SEPARATOR); - if( pnt == NULL ) - { - if( *xpnt != '\0' ) - { - short_name = xpnt; - } - break; - } - *pnt = '\0'; - graft_dir = find_or_create_directory(graft_dir, - graft_point, - NULL, TRUE); - *pnt = PATH_SEPARATOR; - xpnt = pnt + 1; - } - } - else - { - graft_dir = root; - node = argv[optind]; - } - - /* - * Now see whether the user wants to add a regular file, - * or a directory at this point. - */ - status = stat_filter(node, &st); - if( status != 0 ) - { - /* - * This is a fatal error - the user won't be getting what - * they want if we were to proceed. - */ - error (1, 0, _("Invalid node - %s\n"), node); - } - else - { - if( S_ISDIR(st.st_mode) ) - { - if (!scan_directory_tree(graft_dir, node, &de)) - { - exit(1); - } - } - else - { - if( short_name == NULL ) - { - short_name = strrchr(node, PATH_SEPARATOR); - if( short_name == NULL || short_name < node ) - { - short_name = node; - } - else - { - short_name++; - } - } - if( !insert_file_entry(graft_dir, node, short_name) ) - { - exit(1); - } - } - } - - optind++; - } - - - /* - * Now merge in any previous sessions. This is driven on the source - * side, since we may need to create some additional directories. - */ - if( merge_image != NULL ) - { - merge_previous_session(root, mrootp); - } - - /* hide "./rr_moved" if all its contents have been hidden */ - if (reloc_dir && i_ishidden()) - hide_reloc_dir(); - - /* - * Sort the directories in the required order (by ISO9660). Also, - * choose the names for the 8.3 filesystem if required, and do - * any other post-scan work. - */ - goof += sort_tree(root); - - if( use_Joliet ) - { - goof += joliet_sort_tree(root); - } - - if (goof) - error (1, 0, _("Joliet tree sort failed.\n")); - - /* - * Fix a couple of things in the root directory so that everything - * is self consistent. - */ - root->self = root->contents; /* Fix this up so that the path - tables get done right */ - - /* - * OK, ready to write the file. Open it up, and generate the thing. - */ - if (print_size){ - discimage = fopen("/dev/null", "wb"); - if (!discimage) - error (1, errno, _("Unable to open /dev/null\n")); - } else if (outfile){ - discimage = fopen(outfile, "wb"); - if (!discimage) - error (1, errno, _("Unable to open disc image file\n")); - } else { - discimage = stdout; - -#if defined(__CYGWIN32__) - setmode(fileno(stdout), O_BINARY); -#endif - } - - /* Now assign addresses on the disc for the path table. */ - - path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11; - if (path_blocks & 1) path_blocks++; - - jpath_blocks = (jpath_table_size + (SECTOR_SIZE - 1)) >> 11; - if (jpath_blocks & 1) jpath_blocks++; - - /* - * Start to set up the linked list that we use to track the - * contents of the disc. - */ - outputlist_insert(&padblock_desc); - - /* - * PVD for disc. - */ - outputlist_insert(&voldesc_desc); - - /* - * SVD for El Torito. MUST be immediately after the PVD! - */ - if( use_eltorito) - { - outputlist_insert(&torito_desc); - } - - /* - * SVD for Joliet. - */ - if( use_Joliet) - { - outputlist_insert(&joliet_desc); - } - - /* - * Finally the last volume desctiptor. - */ - outputlist_insert(&end_vol); - - - outputlist_insert(&pathtable_desc); - if( use_Joliet) - { - outputlist_insert(&jpathtable_desc); - } - - outputlist_insert(&dirtree_desc); - if( use_Joliet) - { - outputlist_insert(&jdirtree_desc); - } - - outputlist_insert(&dirtree_clean); - - if(extension_record) - { - outputlist_insert(&extension_desc); - } - - outputlist_insert(&files_desc); - - /* - * Allow room for the various headers we will be writing. There - * will always be a primary and an end volume descriptor. - */ - last_extent = session_start; - - /* - * Calculate the size of all of the components of the disc, and assign - * extent numbers. - */ - for(opnt = out_list; opnt; opnt = opnt->of_next ) - { - if( opnt->of_size != NULL ) - { - (*opnt->of_size)(last_extent); - } - } - - /* - * Generate the contents of any of the sections that we want to generate. - * Not all of the fragments will do anything here - most will generate the - * data on the fly when we get to the write pass. - */ - for(opnt = out_list; opnt; opnt = opnt->of_next ) - { - if( opnt->of_generate != NULL ) - { - (*opnt->of_generate)(); - } - } - - if( in_image != NULL ) - { - fclose(in_image); - } - - /* - * Now go through the list of fragments and write the data that corresponds to - * each one. - */ - for(opnt = out_list; opnt; opnt = opnt->of_next ) - { - if( opnt->of_write != NULL ) - { - (*opnt->of_write)(discimage); - } - } - - if( verbose > 0 ) - { -#ifdef HAVE_SBRK - fprintf (stderr, _("Max brk space used %x\n"), - (unsigned int)(((unsigned long)sbrk(0)) - mem_start)); -#endif - fprintf (stderr, _("%llu extents written (%llu MiB)\n"), last_extent, last_extent >> 9); - } - -#ifdef VMS - return 1; -#else - return 0; -#endif -} - -void * -FDECL1(e_malloc, size_t, size) -{ - void* pt = 0; - if( (size > 0) && ((pt = malloc (size)) == NULL)) - error (1, errno, "malloc"); -return pt; -} diff --git a/util/mkisofs/mkisofs.h b/util/mkisofs/mkisofs.h deleted file mode 100644 index a1638d80e..000000000 --- a/util/mkisofs/mkisofs.h +++ /dev/null @@ -1,514 +0,0 @@ -/* - * Header file mkisofs.h - assorted structure definitions and typecasts. - - Written by Eric Youngdale (1993). - - Copyright 1993 Yggdrasil Computing, Incorporated - - Copyright (C) 2009 Free Software Foundation, Inc. - - This program 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, or (at your option) - any later version. - - This program 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 this program; if not, see . - */ - -/* - * $Id: mkisofs.h,v 1.20 1999/03/02 04:16:41 eric Exp $ - */ - -#include -#include -#include -#include - -#include -#include -#define _(str) gettext(str) -#define N_(str) str - -/* This symbol is used to indicate that we do not have things like - symlinks, devices, and so forth available. Just files and dirs */ - -#ifdef VMS -#define NON_UNIXFS -#endif - -#ifdef DJGPP -#define NON_UNIXFS -#endif - -#ifdef VMS -#include -#define dirent direct -#endif - -#ifdef _WIN32 -#define NON_UNIXFS -#endif /* _WIN32 */ - -#ifndef S_IROTH -#define S_IROTH 0 -#endif - -#ifndef S_IRGRP -#define S_IRGRP 0 -#endif - -#ifndef HAVE_GETUID -static inline int -getuid () -{ - return 0; -} -#endif - -#ifndef HAVE_GETGID -static inline int -getgid () -{ - return 0; -} -#endif - -#ifndef HAVE_LSTAT -static inline int -lstat (const char *filename, struct stat *buf) -{ - return stat (filename, buf); -} -#endif - -#include -#include -#include - -#if defined(HAVE_DIRENT_H) -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# if defined(HAVE_SYS_NDIR_H) -# include -# endif -# if defined(HAVE_SYS_DIR_H) -# include -# endif -# if defined(HAVE_NDIR_H) -# include -# endif -#endif - -#if defined(HAVE_STRING_H) -#include -#else -#if defined(HAVE_STRINGS_H) -#include -#endif -#endif - -#ifdef ultrix -extern char *strdup(); -#endif - -#ifdef __STDC__ -#define DECL(NAME,ARGS) NAME ARGS -#define FDECL1(NAME,TYPE0, ARG0) \ - NAME(TYPE0 ARG0) -#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) \ - NAME(TYPE0 ARG0, TYPE1 ARG1) -#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \ - NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2) -#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \ - NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3) -#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \ - NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4) -#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \ - NAME(TYPE0 ARG0, TYPE1 ARG1, TYPE2 ARG2, TYPE3 ARG3, TYPE4 ARG4, TYPE5 ARG5) -#else -#define DECL(NAME,ARGS) NAME() -#define FDECL1(NAME,TYPE0, ARG0) NAME(ARG0) TYPE0 ARG0; -#define FDECL2(NAME,TYPE0, ARG0,TYPE1, ARG1) NAME(ARG0, ARG1) TYPE0 ARG0; TYPE1 ARG1; -#define FDECL3(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2) \ - NAME(ARG0, ARG1, ARG2) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; -#define FDECL4(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3) \ - NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; -#define FDECL5(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4) \ - NAME(ARG0, ARG1, ARG2, ARG3, ARG4) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4; -#define FDECL6(NAME,TYPE0, ARG0,TYPE1, ARG1, TYPE2, ARG2, TYPE3, ARG3, TYPE4, ARG4, TYPE5, ARG5) \ - NAME(ARG0, ARG1, ARG2, ARG3, ARG4, ARG5) TYPE0 ARG0; TYPE1 ARG1; TYPE2 ARG2; TYPE3 ARG3; TYPE4 ARG4; TYPE5 ARG5; -#define const -#endif - - -#ifdef __SVR4 -#include -#else -extern int optind; -extern char *optarg; -/* extern int getopt (int __argc, char **__argv, char *__optstring); */ -#endif - -#include "iso9660.h" -#include "defaults.h" - -struct directory_entry{ - struct directory_entry * next; - struct directory_entry * jnext; - struct iso_directory_record isorec; - uint64_t starting_block; - uint64_t size; - unsigned short priority; - unsigned char jreclen; /* Joliet record len */ - char * name; - char * table; - char * whole_name; - struct directory * filedir; - struct directory_entry * parent_rec; - unsigned int de_flags; - ino_t inode; /* Used in the hash table */ - dev_t dev; /* Used in the hash table */ - unsigned char * rr_attributes; - unsigned int rr_attr_size; - unsigned int total_rr_attr_size; - unsigned int got_rr_name; -}; - -struct file_hash{ - struct file_hash * next; - ino_t inode; /* Used in the hash table */ - dev_t dev; /* Used in the hash table */ - unsigned int starting_block; - unsigned int size; -}; - - -/* - * This structure is used to control the output of fragments to the cdrom - * image. Everything that will be written to the output image will eventually - * go through this structure. There are two pieces - first is the sizing where - * we establish extent numbers for everything, and the second is when we actually - * generate the contents and write it to the output image. - * - * This makes it trivial to extend mkisofs to write special things in the image. - * All you need to do is hook an additional structure in the list, and the rest - * works like magic. - * - * The three passes each do the following: - * - * The 'size' pass determines the size of each component and assigns the extent number - * for that component. - * - * The 'generate' pass will adjust the contents and pointers as required now that extent - * numbers are assigned. In some cases, the contents of the record are also generated. - * - * The 'write' pass actually writes the data to the disc. - */ -struct output_fragment -{ - struct output_fragment * of_next; -#ifdef __STDC__ - int (*of_size)(int); - int (*of_generate)(void); - int (*of_write)(FILE *); -#else - int (*of_size)(); - int (*of_generate)(); - int (*of_write)(); -#endif -}; - -extern struct output_fragment * out_list; -extern struct output_fragment * out_tail; - -extern struct output_fragment padblock_desc; -extern struct output_fragment voldesc_desc; -extern struct output_fragment joliet_desc; -extern struct output_fragment torito_desc; -extern struct output_fragment end_vol; -extern struct output_fragment pathtable_desc; -extern struct output_fragment jpathtable_desc; -extern struct output_fragment dirtree_desc; -extern struct output_fragment dirtree_clean; -extern struct output_fragment jdirtree_desc; -extern struct output_fragment extension_desc; -extern struct output_fragment files_desc; - -/* - * This structure describes one complete directory. It has pointers - * to other directories in the overall tree so that it is clear where - * this directory lives in the tree, and it also must contain pointers - * to the contents of the directory. Note that subdirectories of this - * directory exist twice in this stucture. Once in the subdir chain, - * and again in the contents chain. - */ -struct directory{ - struct directory * next; /* Next directory at same level as this one */ - struct directory * subdir; /* First subdirectory in this directory */ - struct directory * parent; - struct directory_entry * contents; - struct directory_entry * jcontents; - struct directory_entry * self; - char * whole_name; /* Entire path */ - char * de_name; /* Entire path */ - unsigned int ce_bytes; /* Number of bytes of CE entries reqd for this dir */ - unsigned int depth; - unsigned int size; - unsigned int extent; - unsigned int jsize; - unsigned int jextent; - unsigned short path_index; - unsigned short jpath_index; - unsigned short dir_flags; - unsigned short dir_nlink; -}; - -extern int goof; -extern struct directory * root; -extern struct directory * reloc_dir; -extern uint64_t next_extent; -extern uint64_t last_extent; -extern uint64_t last_extent_written; -extern uint64_t session_start; - -extern unsigned int path_table_size; -extern unsigned int path_table[4]; -extern unsigned int path_blocks; -extern char * path_table_l; -extern char * path_table_m; - -extern unsigned int jpath_table_size; -extern unsigned int jpath_table[4]; -extern unsigned int jpath_blocks; -extern char * jpath_table_l; -extern char * jpath_table_m; - -extern struct iso_directory_record root_record; -extern struct iso_directory_record jroot_record; - -extern int use_eltorito; -extern int use_eltorito_emul_floppy; -extern int use_boot_info_table; -extern int use_RockRidge; -extern int use_Joliet; -extern int rationalize; -extern int follow_links; -extern int verbose; -extern int all_files; -extern int generate_tables; -extern int print_size; -extern int split_output; -extern int omit_period; -extern int omit_version_number; -extern int transparent_compression; -extern unsigned int RR_relocation_depth; -extern int full_iso9660_filenames; -extern int split_SL_component; -extern int split_SL_field; - -/* tree.c */ -extern int DECL(stat_filter, (char *, struct stat *)); -extern int DECL(lstat_filter, (char *, struct stat *)); -extern int DECL(sort_tree,(struct directory *)); -extern struct directory * - DECL(find_or_create_directory,(struct directory *, const char *, - struct directory_entry * self, int)); -extern void DECL (finish_cl_pl_entries, (void)); -extern int DECL(scan_directory_tree,(struct directory * this_dir, - char * path, - struct directory_entry * self)); -extern int DECL(insert_file_entry,(struct directory *, char *, - char *)); - -extern void DECL(generate_iso9660_directories,(struct directory *, FILE*)); -extern void DECL(dump_tree,(struct directory * node)); -extern struct directory_entry * DECL(search_tree_file, (struct - directory * node,char * filename)); -extern void DECL(update_nlink_field,(struct directory * node)); -extern void DECL (init_fstatbuf, (void)); -extern struct stat root_statbuf; - -/* eltorito.c */ -extern void DECL(init_boot_catalog, (const char * path )); -extern void DECL(get_torito_desc, (struct eltorito_boot_descriptor * path )); - -/* write.c */ -extern int DECL(get_731,(char *)); -extern int DECL(get_733,(char *)); -extern int DECL(isonum_733,(unsigned char *)); -extern void DECL(set_723,(char *, unsigned int)); -extern void DECL(set_731,(char *, unsigned int)); -extern void DECL(set_721,(char *, unsigned int)); -extern void DECL(set_733,(char *, unsigned int)); -extern int DECL(sort_directory,(struct directory_entry **)); -extern void DECL(generate_one_directory,(struct directory *, FILE*)); -extern void DECL(memcpy_max, (char *, char *, int)); -extern int DECL(oneblock_size, (int starting_extent)); -extern struct iso_primary_descriptor vol_desc; -extern void DECL(xfwrite, (void * buffer, uint64_t count, uint64_t size, FILE * file)); -extern void DECL(set_732, (char * pnt, unsigned int i)); -extern void DECL(set_722, (char * pnt, unsigned int i)); -extern void DECL(outputlist_insert, (struct output_fragment * frag)); - -/* - * Set by user command-line to override default date values - */ - -extern char *creation_date; -extern char *modification_date; -extern char *expiration_date; -extern char *effective_date; - -/* multi.c */ - -extern FILE * in_image; -extern struct iso_directory_record * - DECL(merge_isofs,(char * path)); - -extern int DECL(free_mdinfo, (struct directory_entry **, int len)); - -extern struct directory_entry ** - DECL(read_merging_directory,(struct iso_directory_record *, int*)); -extern void - DECL(merge_remaining_entries, (struct directory *, - struct directory_entry **, int)); -extern int - DECL(merge_previous_session, (struct directory *, - struct iso_directory_record *)); - -extern int DECL(get_session_start, (int *)); - -/* joliet.c */ -int DECL(joliet_sort_tree, (struct directory * node)); - -/* match.c */ -extern int DECL(matches, (char *)); -extern void DECL(add_match, (char *)); - -/* files.c */ -struct dirent * DECL(readdir_add_files, (char **, char *, DIR *)); - -/* */ - -extern int DECL(iso9660_file_length,(const char* name, - struct directory_entry * sresult, int flag)); -extern int DECL(iso9660_date,(char *, time_t)); -extern void DECL(add_hash,(struct directory_entry *)); -extern struct file_hash * DECL(find_hash,(dev_t, ino_t)); -extern void DECL(add_directory_hash,(dev_t, ino_t)); -extern struct file_hash * DECL(find_directory_hash,(dev_t, ino_t)); -extern void DECL (flush_file_hash, (void)); -extern int DECL(delete_file_hash,(struct directory_entry *)); -extern struct directory_entry * DECL(find_file_hash,(char *)); -extern void DECL(add_file_hash,(struct directory_entry *)); -extern int DECL(generate_rock_ridge_attributes,(char *, char *, - struct directory_entry *, - struct stat *, struct stat *, - int deep_flag)); -extern char * DECL(generate_rr_extension_record,(char * id, char * descriptor, - char * source, int * size)); - -extern int DECL(check_prev_session, (struct directory_entry **, int len, - struct directory_entry *, - struct stat *, - struct stat *, - struct directory_entry **)); - -#ifdef USE_SCG -/* scsi.c */ -#ifdef __STDC__ -extern int readsecs(int startsecno, void *buffer, int sectorcount); -extern int scsidev_open(char *path); -#else -extern int readsecs(); -extern int scsidev_open(); -#endif -#endif - -extern char * extension_record; -extern int extension_record_extent; -extern int n_data_extents; - -/* These are a few goodies that can be specified on the command line, and are - filled into the root record */ - -extern char * preparer; -extern char * publisher; -extern char * copyright; -extern char * biblio; -extern char * abstract; -extern char * appid; -extern char * volset_id; -extern char * system_id; -extern char * volume_id; -extern char * boot_catalog; -extern char * boot_image; -extern int volume_set_size; -extern int volume_sequence_number; - -extern void * DECL(e_malloc,(size_t)); - - -#define SECTOR_SIZE (2048) -#define ROUND_UP(X) ((X + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1)) - -#define NEED_RE 1 -#define NEED_PL 2 -#define NEED_CL 4 -#define NEED_CE 8 -#define NEED_SP 16 - -#define PREV_SESS_DEV (sizeof(dev_t) >= 4 ? 0x7ffffffd : 0x7ffd) -#define TABLE_INODE (sizeof(ino_t) >= 4 ? 0x7ffffffe : 0x7ffe) -#define UNCACHED_INODE (sizeof(ino_t) >= 4 ? 0x7fffffff : 0x7fff) -#define UNCACHED_DEVICE (sizeof(dev_t) >= 4 ? 0x7fffffff : 0x7fff) - -#ifdef VMS -#define STAT_INODE(X) (X.st_ino[0]) -#define PATH_SEPARATOR ']' -#define SPATH_SEPARATOR "" -#else -#define STAT_INODE(X) (X.st_ino) -#define PATH_SEPARATOR '/' -#define SPATH_SEPARATOR "/" -#endif - -/* - * When using multi-session, indicates that we can reuse the - * TRANS.TBL information for this directory entry. If this flag - * is set for all entries in a directory, it means we can just - * reuse the TRANS.TBL and not generate a new one. - */ -#define SAFE_TO_REUSE_TABLE_ENTRY 0x01 -#define DIR_HAS_DOT 0x02 -#define DIR_HAS_DOTDOT 0x04 -#define INHIBIT_JOLIET_ENTRY 0x08 -#define INHIBIT_RR_ENTRY 0x10 -#define RELOCATED_DIRECTORY 0x20 -#define INHIBIT_ISO9660_ENTRY 0x40 - -/* - * Volume sequence number to use in all of the iso directory records. - */ -#define DEF_VSN 1 - -/* - * Make sure we have a definition for this. If not, take a very conservative - * guess. From what I can tell SunOS is the only one with this trouble. - */ -#ifndef NAME_MAX -#ifdef FILENAME_MAX -#define NAME_MAX FILENAME_MAX -#else -#define NAME_MAX 128 -#endif -#endif diff --git a/util/mkisofs/multi.c b/util/mkisofs/multi.c deleted file mode 100644 index 1e7f62aac..000000000 --- a/util/mkisofs/multi.c +++ /dev/null @@ -1,1201 +0,0 @@ -/* - * File multi.c - scan existing iso9660 image and merge into - * iso9660 filesystem. Used for multisession support. - * - * Written by Eric Youngdale (1996). - * - * Copyright (C) 2009 Free Software Foundation, Inc. - * - * This program 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, or (at your option) - * any later version. - * - * This program 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 this program; if not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "config.h" - -#ifndef VMS - -#ifdef HAVE_UNISTD_H -#include -#endif - -#else -#include -#include -#include "vms.h" -extern char * strdup(const char *); -#endif - -#include "mkisofs.h" -#include "iso9660.h" - -#define TF_CREATE 1 -#define TF_MODIFY 2 -#define TF_ACCESS 4 -#define TF_ATTRIBUTES 8 - -static int isonum_711 __PR((unsigned char * p)); -static int isonum_721 __PR((unsigned char * p)); -static int isonum_723 __PR((unsigned char * p)); -static int isonum_731 __PR((unsigned char * p)); - -static int DECL(merge_old_directory_into_tree, (struct directory_entry *, - struct directory *)); - -#ifdef __STDC__ -static int -isonum_711 (unsigned char * p) -#else -static int -isonum_711 (p) - unsigned char * p; -#endif -{ - return (*p & 0xff); -} - -#ifdef __STDC__ -static int -isonum_721 (unsigned char * p) -#else -static int -isonum_721 (p) - unsigned char * p; -#endif -{ - return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); -} - -#ifdef __STDC__ -static int -isonum_723 (unsigned char * p) -#else -static int -isonum_723 (p) - unsigned char * p; -#endif -{ -#if 0 - if (p[0] != p[3] || p[1] != p[2]) { - fprintf (stderr, "invalid format 7.2.3 number\n"); - exit (1); - } -#endif - return (isonum_721 (p)); -} - -#ifdef __STDC__ -static int -isonum_731 (unsigned char * p) -#else -static int -isonum_731 (p) - unsigned char * p; -#endif -{ - return ((p[0] & 0xff) - | ((p[1] & 0xff) << 8) - | ((p[2] & 0xff) << 16) - | ((p[3] & 0xff) << 24)); -} - -#ifdef __STDC__ -int -isonum_733 (unsigned char * p) -#else -int -isonum_733 (p) - unsigned char * p; -#endif -{ - return (isonum_731 (p)); -} - -FILE * in_image = NULL; - -#ifndef USE_SCG -/* - * Don't define readsecs if mkisofs is linked with - * the SCSI library. - * readsecs() will be implemented as SCSI command in this case. - * - * Use global var in_image directly in readsecs() - * the SCSI equivalent will not use a FILE* for I/O. - * - * The main point of this pointless abstraction is that Solaris won't let - * you read 2K sectors from the cdrom driver. The fact that 99.9% of the - * discs out there have a 2K sectorsize doesn't seem to matter that much. - * Anyways, this allows the use of a scsi-generics type of interface on - * Solaris. - */ -#ifdef __STDC__ -static int -readsecs(int startsecno, void *buffer, int sectorcount) -#else -static int -readsecs(startsecno, buffer, sectorcount) - int startsecno; - void *buffer; - int sectorcount; -#endif -{ - int f = fileno(in_image); - - if (lseek(f, (off_t)startsecno * SECTOR_SIZE, 0) == (off_t)-1) - error (10, errno, _("Seek error on old image\n")); - return (read(f, buffer, sectorcount * SECTOR_SIZE)); -} -#endif - -/* - * Parse the RR attributes so we can find the file name. - */ -static int -FDECL3(parse_rr, unsigned char *, pnt, int, len, struct directory_entry *,dpnt) -{ - int cont_extent, cont_offset, cont_size; - char name_buf[256]; - - cont_extent = cont_offset = cont_size = 0; - - while(len >= 4){ - if(pnt[3] != 1) { - fprintf (stderr, _("**Bad RR version attribute")); - return -1; - }; - if(strncmp((char *) pnt, "NM", 2) == 0) { - strncpy(name_buf, (char *) pnt+5, pnt[2] - 5); - name_buf[pnt[2] - 5] = 0; - dpnt->name = strdup(name_buf); - dpnt->got_rr_name = 1; - return 0; - } - - if(strncmp((char *) pnt, "CE", 2) == 0) { - cont_extent = isonum_733(pnt+4); - cont_offset = isonum_733(pnt+12); - cont_size = isonum_733(pnt+20); - }; - - len -= pnt[2]; - pnt += pnt[2]; - if(len <= 3 && cont_extent) { - unsigned char sector[SECTOR_SIZE]; - readsecs(cont_extent, sector, 1); - parse_rr(§or[cont_offset], cont_size, dpnt); - }; - }; - - /* Fall back to the iso name if no RR name found */ - if (dpnt->name == NULL) { - char *cp; - - strcpy(name_buf, dpnt->isorec.name); - cp = strchr(name_buf, ';'); - if (cp != NULL) { - *cp = '\0'; - } - - dpnt->name = strdup(name_buf); - } - - return 0; -} /* parse_rr */ - - -static int -FDECL4(check_rr_dates, struct directory_entry *, dpnt, - struct directory_entry *, current, - struct stat *, statbuf, - struct stat *,lstatbuf) -{ - int cont_extent, cont_offset, cont_size; - int offset; - unsigned char * pnt; - int len; - int same_file; - int same_file_type; - mode_t mode; - char time_buf[7]; - - - cont_extent = cont_offset = cont_size = 0; - same_file = 1; - same_file_type = 1; - - pnt = dpnt->rr_attributes; - len = dpnt->rr_attr_size; - /* - * We basically need to parse the rr attributes again, and - * dig out the dates and file types. - */ - while(len >= 4){ - if(pnt[3] != 1) { - fprintf (stderr, _("**Bad RR version attribute")); - return -1; - }; - - /* - * If we have POSIX file modes, make sure that the file type - * is the same. If it isn't, then we must always - * write the new file. - */ - if(strncmp((char *) pnt, "PX", 2) == 0) { - mode = isonum_733(pnt + 4); - if( (lstatbuf->st_mode & S_IFMT) != (mode & S_IFMT) ) - { - same_file_type = 0; - same_file = 0; - } - } - - if(strncmp((char *) pnt, "TF", 2) == 0) { - offset = 5; - if( pnt[4] & TF_CREATE ) - { - iso9660_date((char *) time_buf, lstatbuf->st_ctime); - if(memcmp(time_buf, pnt+offset, 7) == 0) - same_file = 0; - offset += 7; - } - if( pnt[4] & TF_MODIFY ) - { - iso9660_date((char *) time_buf, lstatbuf->st_mtime); - if(memcmp(time_buf, pnt+offset, 7) == 0) - same_file = 0; - offset += 7; - } - } - - if(strncmp((char *) pnt, "CE", 2) == 0) { - cont_extent = isonum_733(pnt+4); - cont_offset = isonum_733(pnt+12); - cont_size = isonum_733(pnt+20); - }; - - len -= pnt[2]; - pnt += pnt[2]; - if(len <= 3 && cont_extent) { - unsigned char sector[SECTOR_SIZE]; - - readsecs(cont_extent, sector, 1); - parse_rr(§or[cont_offset], cont_size, dpnt); - }; - }; - - /* - * If we have the same fundamental file type, then it is clearly - * safe to reuse the TRANS.TBL entry. - */ - if( same_file_type ) - { - current->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; - } - - return same_file; -} - -struct directory_entry ** -FDECL2(read_merging_directory, struct iso_directory_record *, mrootp, - int *, nent) -{ - unsigned char * cpnt; - unsigned char * cpnt1; - char * dirbuff; - int i; - struct iso_directory_record * idr; - int len; - struct directory_entry **pnt; - int rlen; - struct directory_entry **rtn; - int seen_rockridge; - unsigned char * tt_buf; - int tt_extent; - int tt_size; - - static int warning_given = 0; - - /* - * First, allocate a buffer large enough to read in the entire - * directory. - */ - dirbuff = (char *) e_malloc(isonum_733((unsigned char *)mrootp->size)); - - readsecs(isonum_733((unsigned char *)mrootp->extent), dirbuff, - isonum_733((unsigned char *)mrootp->size)/SECTOR_SIZE); - - /* - * Next look over the directory, and count up how many entries we - * have. - */ - len = isonum_733((unsigned char *)mrootp->size); - i = 0; - *nent = 0; - while(i < len ) - { - idr = (struct iso_directory_record *) &dirbuff[i]; - if(idr->length[0] == 0) - { - i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); - continue; - } - (*nent)++; - i += idr->length[0]; - } - - /* - * Now allocate the buffer which will hold the array we are - * about to return. - */ - rtn = (struct directory_entry **) e_malloc(*nent * sizeof(*rtn)); - - /* - * Finally, scan the directory one last time, and pick out the - * relevant bits of information, and store it in the relevant - * bits of the structure. - */ - i = 0; - pnt = rtn; - tt_extent = 0; - seen_rockridge = 0; - tt_size = 0; - while(i < len ) - { - idr = (struct iso_directory_record *) &dirbuff[i]; - if(idr->length[0] == 0) - { - i = (i + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); - continue; - } - *pnt = (struct directory_entry *) e_malloc(sizeof(**rtn)); - (*pnt)->next = NULL; - (*pnt)->isorec = *idr; - (*pnt)->starting_block = isonum_733((unsigned char *)idr->extent); - (*pnt)->size = isonum_733((unsigned char *)idr->size); - (*pnt)->priority = 0; - (*pnt)->name = NULL; - (*pnt)->got_rr_name = 0; - (*pnt)->table = NULL; - (*pnt)->whole_name = NULL; - (*pnt)->filedir = NULL; - (*pnt)->parent_rec = NULL; - /* - * Set this information so that we correctly cache previous - * session bits of information. - */ - (*pnt)->inode = (*pnt)->starting_block; - (*pnt)->dev = PREV_SESS_DEV; - (*pnt)->rr_attributes = NULL; - (*pnt)->rr_attr_size = 0; - (*pnt)->total_rr_attr_size = 0; - (*pnt)->de_flags = SAFE_TO_REUSE_TABLE_ENTRY; - - /* - * Check for and parse any RR attributes for the file. - * All we are really looking for here is the original name - * of the file. - */ - rlen = idr->length[0] & 0xff; - cpnt = (unsigned char *) idr; - - rlen -= sizeof(struct iso_directory_record); - cpnt += sizeof(struct iso_directory_record); - - rlen += sizeof(idr->name); - cpnt -= sizeof(idr->name); - - rlen -= idr->name_len[0]; - cpnt += idr->name_len[0]; - - if((idr->name_len[0] & 1) == 0){ - cpnt++; - rlen--; - }; - - if( rlen != 0 ) - { - (*pnt)->total_rr_attr_size = (*pnt)->rr_attr_size = rlen; - (*pnt)->rr_attributes = e_malloc(rlen); - memcpy((*pnt)->rr_attributes, cpnt, rlen); - seen_rockridge = 1; - } - - /* - * Now zero out the remainder of the name field. - */ - cpnt = (unsigned char *) &(*pnt)->isorec.name; - cpnt += idr->name_len[0]; - memset(cpnt, 0, sizeof((*pnt)->isorec.name) - idr->name_len[0]); - - parse_rr((*pnt)->rr_attributes, rlen, *pnt); - - if( ((*pnt)->isorec.name_len[0] == 1) - && ( ((*pnt)->isorec.name[0] == 0) - || ((*pnt)->isorec.name[0] == 1)) ) - { - if( (*pnt)->name != NULL ) - { - free((*pnt)->name); - } - if( (*pnt)->whole_name != NULL ) - { - free((*pnt)->whole_name); - } - if( (*pnt)->isorec.name[0] == 0 ) - { - (*pnt)->name = strdup("."); - } - else - { - (*pnt)->name = strdup(".."); - } - } - -#ifdef DEBUG - fprintf(stderr, "got DE name: %s\n", (*pnt)->name); -#endif - - if( strncmp(idr->name, "TRANS.TBL", 9) == 0) - { - if( (*pnt)->name != NULL ) - { - free((*pnt)->name); - } - if( (*pnt)->whole_name != NULL ) - { - free((*pnt)->whole_name); - } - (*pnt)->name = strdup(""); - tt_extent = isonum_733((unsigned char *)idr->extent); - tt_size = isonum_733((unsigned char *)idr->size); - } - - pnt++; - i += idr->length[0]; - } - - /* - * If there was a TRANS.TBL;1 entry, then grab it, read it, and use it - * to get the filenames of the files. Also, save the table info, just - * in case we need to use it. - */ - if( tt_extent != 0 && tt_size != 0 ) - { - tt_buf = (unsigned char *) e_malloc(tt_size); - readsecs(tt_extent, tt_buf, tt_size/SECTOR_SIZE); - - /* - * Loop through the file, examine each entry, and attempt to - * attach it to the correct entry. - */ - cpnt = tt_buf; - cpnt1 = tt_buf; - while( cpnt - tt_buf < tt_size ) - { - while(*cpnt1 != '\n' && *cpnt1 != '\0') cpnt1++; - *cpnt1 = '\0'; - - for(pnt = rtn, i = 0; i <*nent; i++, pnt++) - { - rlen = isonum_711((*pnt)->isorec.name_len); - if( strncmp((char *) cpnt + 2, (*pnt)->isorec.name, - rlen) == 0 - && cpnt[2+rlen] == ' ') - { - (*pnt)->table = e_malloc(strlen((char*)cpnt) - 33); - sprintf((*pnt)->table, "%c\t%s\n", - *cpnt, cpnt+37); - if( !(*pnt)->got_rr_name ) - { - if ((*pnt)->name != NULL) { - free((*pnt)->name); - } - (*pnt)->name = strdup((char *) cpnt+37); - } - break; - } - } - cpnt = cpnt1 + 1; - cpnt1 = cpnt; - } - - free(tt_buf); - } - else if( !seen_rockridge && !warning_given ) - { - /* - * Warn the user that iso (8.3) names were used because neither - * Rock Ridge (-R) nor TRANS.TBL (-T) name translations were found. - */ - fprintf (stderr, _("Warning: Neither Rock Ridge (-R) nor TRANS.TBL (-T) " - "name translations were found on previous session. " - "ISO (8.3) file names have been used instead.\n")); - warning_given = 1; - } - - if( dirbuff != NULL ) - { - free(dirbuff); - } - - return rtn; -} /* read_merging_directory */ - -/* - * Free any associated data related to the structures. - */ -int -FDECL2(free_mdinfo, struct directory_entry ** , ptr, int, len ) -{ - int i; - struct directory_entry **p; - - p = ptr; - for(i=0; iname != NULL ) - { - free((*p)->name); - } - - if( (*p)->whole_name != NULL ) - { - free((*p)->whole_name); - } - - if( (*p)->rr_attributes != NULL ) - { - free((*p)->rr_attributes); - } - - if( (*p)->table != NULL ) - { - free((*p)->table); - } - - free(*p); - - } - - free(ptr); - return 0; -} - -/* - * Search the list to see if we have any entries from the previous - * session that match this entry. If so, copy the extent number - * over so we don't bother to write it out to the new session. - */ - -int -FDECL6(check_prev_session, struct directory_entry ** , ptr, int, len, - struct directory_entry *, curr_entry, - struct stat *, statbuf, struct stat *, lstatbuf, - struct directory_entry **, odpnt) -{ - int i; - - for( i=0; i < len; i++ ) - { - if( ptr[i] == NULL ) - { - continue; - } - -#if 0 - if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 - && ptr[i]->name[0] == '\0' ) - { - continue; - } - if( ptr[i]->name != NULL && ptr[i]->isorec.name_len[0] == 1 - && ptr[i]->name[0] == 1) - { - continue; - } -#else - if( ptr[i]->name != NULL && strcmp(ptr[i]->name, ".") == 0 ) - { - continue; - } - if( ptr[i]->name != NULL && strcmp(ptr[i]->name, "..") == 0 ) - { - continue; - } -#endif - - if( ptr[i]->name != NULL - && strcmp(ptr[i]->name, curr_entry->name) != 0 ) - { - continue; - } - - /* - * We know that the files have the same name. If they also have - * the same file type (i.e. file, dir, block, etc), then we - * can safely reuse the TRANS.TBL entry for this file. - * The check_rr_dates function will do this for us. - * - * Verify that the file type and dates are consistent. - * If not, we probably have a different file, and we need - * to write it out again. - */ - if( (ptr[i]->rr_attributes != NULL) - && (check_rr_dates(ptr[i], curr_entry, statbuf, lstatbuf)) ) - { - goto found_it; - } - - - /* - * Verify size and timestamp. If rock ridge is in use, we need - * to compare dates from RR too. Directories are special, we - * calculate their size later. - */ - if( (curr_entry->isorec.flags[0] & 2) == 0 - && ptr[i]->size != curr_entry->size ) - { - goto found_it; - } - - if( memcmp(ptr[i]->isorec.date, curr_entry->isorec.date,7) != 0 ) - { - goto found_it; - } - - /* - * Never ever reuse directory extents. See comments in - * tree.c for an explaination of why this must be the case. - */ - if( (curr_entry->isorec.flags[0] & 2) != 0 ) - { - goto found_it; - } - - memcpy(curr_entry->isorec.extent, ptr[i]->isorec.extent, 8); - curr_entry->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; - goto found_it; - } - return 0; - -found_it: - if( odpnt != NULL ) - { - *odpnt = ptr[i]; - } - else - { - free(ptr[i]); - } - ptr[i] = NULL; - return 0; -} - -/* - * merge_isofs: Scan an existing image, and return a pointer - * to the root directory for this image. - */ -struct iso_directory_record * FDECL1(merge_isofs, char *, path) -{ - char buffer[SECTOR_SIZE]; - int file_addr; - int i; - struct iso_primary_descriptor * pri = NULL; - struct iso_directory_record * rootp; - struct iso_volume_descriptor * vdp; - - /* - * Start by opening up the image and searching for the volume header. - * Ultimately, we need to search for volume headers in multiple places - * because we might be starting with a multisession image. - * FIXME(eric). - */ - -#ifndef USE_SCG - in_image = fopen(path, "rb"); - if( in_image == NULL ) - { - return NULL; - } -#else - if (strchr(path, '/')) { - in_image = fopen(path, "rb"); - if( in_image == NULL ) { - return NULL; - } - } else { - if (scsidev_open(path) < 0) - return NULL; - } -#endif - - get_session_start(&file_addr); - - for(i = 0; i< 100; i++) - { - if (readsecs(file_addr/SECTOR_SIZE, &buffer, - sizeof(buffer)/SECTOR_SIZE) != sizeof(buffer)) - error (10, errno, _("Read error on old image %s\n"), path); - - vdp = (struct iso_volume_descriptor *)buffer; - - if( (strncmp(vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) - && (isonum_711((unsigned char *) vdp->type) == ISO_VD_PRIMARY) ) - { - break; - } - file_addr += SECTOR_SIZE; - } - - if( i == 100 ) - { - return NULL; - } - - pri = (struct iso_primary_descriptor *)vdp; - - /* - * Check the blocksize of the image to make sure it is compatible. - */ - if( (isonum_723 ((unsigned char *) pri->logical_block_size) != SECTOR_SIZE) - || (isonum_723 ((unsigned char *) pri->volume_set_size) != 1) ) - { - return NULL; - } - - /* - * Get the location and size of the root directory. - */ - rootp = (struct iso_directory_record *) - malloc(sizeof(struct iso_directory_record)); - - memcpy(rootp, pri->root_directory_record, sizeof(*rootp)); - - return rootp; -} - -void FDECL3(merge_remaining_entries, struct directory *, this_dir, - struct directory_entry **, pnt, - int, n_orig) -{ - int i; - struct directory_entry * s_entry; - unsigned int ttbl_extent = 0; - unsigned int ttbl_index = 0; - char whole_path[1024]; - - /* - * Whatever is leftover in the list needs to get merged back - * into the directory. - */ - for( i=0; i < n_orig; i++ ) - { - if( pnt[i] == NULL ) - { - continue; - } - - if( pnt[i]->name != NULL && pnt[i]->whole_name == NULL) - { - /* - * Set the name for this directory. - */ - strcpy(whole_path, this_dir->de_name); - strcat(whole_path, SPATH_SEPARATOR); - strcat(whole_path, pnt[i]->name); - - pnt[i]->whole_name = strdup(whole_path); - } - - if( pnt[i]->name != NULL - && strcmp(pnt[i]->name, "") == 0 ) - { - ttbl_extent = isonum_733((unsigned char *) pnt[i]->isorec.extent); - ttbl_index = i; - continue; - } - /* - * Skip directories for now - these need to be treated - * differently. - */ - if( (pnt[i]->isorec.flags[0] & 2) != 0 ) - { - /* - * FIXME - we need to insert this directory into the - * tree, so that the path tables we generate will - * be correct. - */ - if( (strcmp(pnt[i]->name, ".") == 0) - || (strcmp(pnt[i]->name, "..") == 0) ) - { - free(pnt[i]); - pnt[i] = NULL; - continue; - } - else - { - merge_old_directory_into_tree(pnt[i], this_dir); - } - } - pnt[i]->next = this_dir->contents; - pnt[i]->filedir = this_dir; - this_dir->contents = pnt[i]; - pnt[i] = NULL; - } - - - /* - * If we don't have an entry for the translation table, then - * don't bother trying to copy the starting extent over. - * Note that it is possible that if we are copying the entire - * directory, the entry for the translation table will have already - * been inserted into the linked list and removed from the old - * entries list, in which case we want to leave the extent number - * as it was before. - */ - if( ttbl_extent == 0 ) - { - return; - } - - /* - * Finally, check the directory we are creating to see whether - * there are any new entries in it. If there are not, we can - * reuse the same translation table. - */ - for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) - { - /* - * Don't care about '.' or '..'. They are never in the table - * anyways. - */ - if( s_entry->name != NULL && strcmp(s_entry->name, ".") == 0 ) - { - continue; - } - if( s_entry->name != NULL && strcmp(s_entry->name, "..") == 0 ) - { - continue; - } - if( strcmp(s_entry->name, "") == 0) - { - continue; - } - if( (s_entry->de_flags & SAFE_TO_REUSE_TABLE_ENTRY) == 0 ) - { - return; - } - } - - /* - * Locate the translation table, and re-use the same extent. - * It isn't clear that there should ever be one in there already - * so for now we try and muddle through the best we can. - */ - for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) - { - if( strcmp(s_entry->name, "") == 0) - { - fprintf (stderr, "Should never get here\n"); - set_733(s_entry->isorec.extent, ttbl_extent); - return; - } - } - - pnt[ttbl_index]->next = this_dir->contents; - pnt[ttbl_index]->filedir = this_dir; - this_dir->contents = pnt[ttbl_index]; - pnt[ttbl_index] = NULL; -} - - -/* - * Here we have a case of a directory that has completely disappeared from - * the face of the earth on the tree we are mastering from. Go through and - * merge it into the tree, as well as everything beneath it. - * - * Note that if a directory has been moved for some reason, this will - * incorrectly pick it up and attempt to merge it back into the old - * location. FIXME(eric). - */ -static int -FDECL2(merge_old_directory_into_tree, struct directory_entry *, dpnt, - struct directory *, parent) -{ - struct directory_entry **contents = NULL; - int i; - int n_orig; - struct directory * this_dir, *next_brother; - char whole_path[1024]; - - this_dir = (struct directory *) e_malloc(sizeof(struct directory)); - memset(this_dir, 0, sizeof(struct directory)); - this_dir->next = NULL; - this_dir->subdir = NULL; - this_dir->self = dpnt; - this_dir->contents = NULL; - this_dir->size = 0; - this_dir->extent = 0; - this_dir->depth = parent->depth + 1; - this_dir->parent = parent; - if(!parent->subdir) - parent->subdir = this_dir; - else { - next_brother = parent->subdir; - while(next_brother->next) next_brother = next_brother->next; - next_brother->next = this_dir; - } - - /* - * Set the name for this directory. - */ - strcpy(whole_path, parent->de_name); - strcat(whole_path, SPATH_SEPARATOR); - strcat(whole_path, dpnt->name); - this_dir->de_name = strdup(whole_path); - this_dir->whole_name = strdup(whole_path); - - /* - * Now fill this directory using information from the previous - * session. - */ - contents = read_merging_directory(&dpnt->isorec, &n_orig); - /* - * Start by simply copying the '.', '..' and non-directory - * entries to this directory. Technically we could let - * merge_remaining_entries handle this, but it gets rather confused - * by the '.' and '..' entries. - */ - for(i=0; i < n_orig; i ++ ) - { - /* - * We can always reuse the TRANS.TBL in this particular case. - */ - contents[i]->de_flags |= SAFE_TO_REUSE_TABLE_ENTRY; - - if( ((contents[i]->isorec.flags[0] & 2) != 0) - && (i >= 2) ) - { - continue; - } - - /* - * If we have a directory, don't reuse the extent number. - */ - if( (contents[i]->isorec.flags[0] & 2) != 0 ) - { - memset(contents[i]->isorec.extent, 0, 8); - - if( strcmp(contents[i]->name, ".") == 0 ) - this_dir->dir_flags |= DIR_HAS_DOT; - - if( strcmp(contents[i]->name, "..") == 0 ) - this_dir->dir_flags |= DIR_HAS_DOTDOT; - } - - /* - * Set the whole name for this file. - */ - strcpy(whole_path, this_dir->whole_name); - strcat(whole_path, SPATH_SEPARATOR); - strcat(whole_path, contents[i]->name); - - contents[i]->whole_name = strdup(whole_path); - - contents[i]->next = this_dir->contents; - contents[i]->filedir = this_dir; - this_dir->contents = contents[i]; - contents[i] = NULL; - } - - /* - * Zero the extent number for ourselves. - */ - memset(dpnt->isorec.extent, 0, 8); - - /* - * Anything that is left are other subdirectories that need to be merged. - */ - merge_remaining_entries(this_dir, contents, n_orig); - free_mdinfo(contents, n_orig); -#if 0 - /* - * This is no longer required. The post-scan sort will handle - * all of this for us. - */ - sort_n_finish(this_dir); -#endif - - return 0; -} - - -char * cdwrite_data = NULL; - -int -FDECL1(get_session_start, int *, file_addr) -{ - char * pnt; - -#ifdef CDWRITE_DETERMINES_FIRST_WRITABLE_ADDRESS - /* - * FIXME(eric). We need to coordinate with cdwrite to obtain - * the parameters. For now, we assume we are writing the 2nd session, - * so we start from the session that starts at 0. - */ - - *file_addr = (16 << 11); - - /* - * We need to coordinate with cdwrite to get the next writable address - * from the device. Here is where we use it. - */ - session_start = last_extent = last_extent_written = cdwrite_result(); - -#else - - if( cdwrite_data == NULL ) - error (1, 0, _("Special parameters for cdwrite not specified with -C\n")); - - /* - * Next try and find the ',' in there which delimits the two numbers. - */ - pnt = strchr(cdwrite_data, ','); - if( pnt == NULL ) - error (1, 0, _("Malformed cdwrite parameters\n")); - - *pnt = '\0'; - if (file_addr != NULL) { - *file_addr = atol(cdwrite_data) * SECTOR_SIZE; - } - pnt++; - - session_start = last_extent = last_extent_written = atol(pnt); - - pnt--; - *pnt = ','; - -#endif - return 0; -} - -/* - * This function scans the directory tree, looking for files, and it makes - * note of everything that is found. We also begin to construct the ISO9660 - * directory entries, so that we can determine how large each directory is. - */ - -int -FDECL2(merge_previous_session,struct directory *, this_dir, - struct iso_directory_record *, mrootp) -{ - struct directory_entry **orig_contents = NULL; - struct directory_entry * odpnt = NULL; - int n_orig; - struct directory_entry * s_entry; - int status, lstatus; - struct stat statbuf, lstatbuf; - - /* - * Parse the same directory in the image that we are merging - * for multisession stuff. - */ - orig_contents = read_merging_directory(mrootp, &n_orig); - if( orig_contents == NULL ) - { - return 0; - } - - -/* Now we scan the directory itself, and look at what is inside of it. */ - - for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) - { - status = stat_filter(s_entry->whole_name, &statbuf); - lstatus = lstat_filter(s_entry->whole_name, &lstatbuf); - - /* - * We always should create an entirely new directory tree whenever - * we generate a new session, unless there were *no* changes whatsoever - * to any of the directories, in which case it would be kind of pointless - * to generate a new session. - * - * I believe it is possible to rigorously prove that any change anywhere - * in the filesystem will force the entire tree to be regenerated - * because the modified directory will get a new extent number. Since - * each subdirectory of the changed directory has a '..' entry, all of - * them will need to be rewritten too, and since the parent directory - * of the modified directory will have an extent pointer to the directory - * it too will need to be rewritten. Thus we will never be able to reuse - * any directory information when writing new sessions. - * - * We still check the previous session so we can mark off the equivalent - * entry in the list we got from the original disc, however. - */ - - /* - * The check_prev_session function looks for an identical entry in - * the previous session. If we see it, then we copy the extent - * number to s_entry, and cross it off the list. - */ - check_prev_session(orig_contents, n_orig, s_entry, - &statbuf, &lstatbuf, &odpnt); - - if(S_ISDIR(statbuf.st_mode) && odpnt != NULL) - { - int dflag; - - if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) - { - struct directory * child; - - child = find_or_create_directory(this_dir, - s_entry->whole_name, - s_entry, 1); - dflag = merge_previous_session(child, - &odpnt->isorec); - /* If unable to scan directory, mark this as a non-directory */ - if(!dflag) - lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG; - free(odpnt); - odpnt = NULL; - } - } - } - - /* - * Whatever is left over, are things which are no longer in the tree - * on disk. We need to also merge these into the tree. - */ - merge_remaining_entries(this_dir, orig_contents, n_orig); - free_mdinfo(orig_contents, n_orig); - - return 1; -} - diff --git a/util/mkisofs/name.c b/util/mkisofs/name.c deleted file mode 100644 index 13f81870a..000000000 --- a/util/mkisofs/name.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * File name.c - map full Unix file names to unique 8.3 names that - * would be valid on DOS. - * - - Written by Eric Youngdale (1993). - - Copyright 1993 Yggdrasil Computing, Incorporated - - This program 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 2, or (at your option) - any later version. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "config.h" -#include "mkisofs.h" - -#include - -extern int allow_leading_dots; - -/* - * Function: iso9660_file_length - * - * Purpose: Map file name to 8.3 format, return length - * of result. - * - * Arguments: name file name we need to map. - * sresult directory entry structure to contain mapped name. - * dirflag flag indicating whether this is a directory or not. - * - * Notes: This procedure probably needs to be rationalized somehow. - * New options to affect the behavior of this function - * would also be nice to have. - */ -int FDECL3(iso9660_file_length, - const char*, name, - struct directory_entry *, sresult, - int, dirflag) -{ - char * c; - int chars_after_dot = 0; - int chars_before_dot = 0; - int current_length = 0; - int extra = 0; - int ignore = 0; - char * last_dot; - const char * pnt; - int priority = 32767; - char * result; - int seen_dot = 0; - int seen_semic = 0; - int tildes = 0; - - result = sresult->isorec.name; - - /* - * For the '.' entry, generate the correct record, and return - * 1 for the length. - */ - if(strcmp(name,".") == 0) - { - if(result) - { - *result = 0; - } - return 1; - } - - /* - * For the '..' entry, generate the correct record, and return - * 1 for the length. - */ - if(strcmp(name,"..") == 0) - { - if(result) - { - *result++ = 1; - *result++ = 0; - } - return 1; - } - - /* - * Now scan the directory one character at a time, and figure out - * what to do. - */ - pnt = name; - - /* - * Find the '.' that we intend to use for the extension. Usually this - * is the last dot, but if we have . followed by nothing or a ~, we - * would consider this to be unsatisfactory, and we keep searching. - */ - last_dot = strrchr (pnt,'.'); - if( (last_dot != NULL) - && ( (last_dot[1] == '~') - || (last_dot[1] == '\0')) ) - { - c = last_dot; - *c = '\0'; - last_dot = strrchr (pnt,'.'); - *c = '.'; - } - - while(*pnt) - { -#ifdef VMS - if( strcmp(pnt,".DIR;1") == 0 ) - { - break; - } -#endif - - /* - * This character indicates a Unix style of backup file - * generated by some editors. Lower the priority of - * the file. - */ - if(*pnt == '#') - { - priority = 1; - pnt++; - continue; - } - - /* - * This character indicates a Unix style of backup file - * generated by some editors. Lower the priority of - * the file. - */ - if(*pnt == '~') - { - priority = 1; - tildes++; - pnt++; - continue; - } - - /* - * This might come up if we had some joker already try and put - * iso9660 version numbers into the file names. This would be - * a silly thing to do on a Unix box, but we check for it - * anyways. If we see this, then we don't have to add our - * own version number at the end. - * UNLESS the ';' is part of the filename and no version - * number is following. [VK] - */ - if(*pnt == ';') - { - /* [VK] */ - if (pnt[1] != '\0' && (pnt[1] < '0' || pnt[1] > '9')) - { - pnt++; - ignore++; - continue; - } - } - - /* - * If we have a name with multiple '.' characters, we ignore everything - * after we have gotten the extension. - */ - if(ignore) - { - pnt++; - continue; - } - - /* - * Spin past any iso9660 version number we might have. - */ - if(seen_semic) - { - if(*pnt >= '0' && *pnt <= '9') - { - *result++ = *pnt; - } - extra++; - pnt++; - continue; - } - - /* - * If we have full names, the names we generate will not - * work on a DOS machine, since they are not guaranteed - * to be 8.3. Nonetheless, in many cases this is a useful - * option. We still only allow one '.' character in the - * name, however. - */ - if(full_iso9660_filenames) - { - /* Here we allow a more relaxed syntax. */ - if(*pnt == '.') - { - if (seen_dot) - { - ignore++; - continue; - } - seen_dot++; - } - if(current_length < 30) - { - if( !isascii (*pnt)) - { - *result++ = '_'; - } - else - { - *result++ = (islower((unsigned char)*pnt) ? toupper((unsigned char)*pnt) : *pnt); - } - } - } - else - { - /* - * Dos style filenames. We really restrict the - * names here. - */ - /* It would be nice to have .tar.gz transform to .tgz, - * .ps.gz to .psz, ... - */ - if(*pnt == '.') - { - if (!chars_before_dot && !allow_leading_dots) - { - /* DOS can't read files with dot first */ - chars_before_dot++; - if (result) - { - *result++ = '_'; /* Substitute underscore */ - } - } - else if( pnt != last_dot ) - { - /* - * If this isn't the dot that we use for the extension, - * then change the character into a '_' instead. - */ - if(chars_before_dot < 8) - { - chars_before_dot++; - if(result) - { - *result++ = '_'; - } - } - } - else - { - if (seen_dot) - { - ignore++; continue; - } - if(result) - { - *result++ = '.'; - } - seen_dot++; - } - } - else - { - if( (seen_dot && (chars_after_dot < 3) && ++chars_after_dot) - || (!seen_dot && (chars_before_dot < 8) && ++chars_before_dot) ) - { - if(result) - { - switch (*pnt) - { - default: - if( !isascii (*pnt) ) - { - *result++ = '_'; - } - else - { - *result++ = islower((unsigned char)*pnt) ? toupper((unsigned char)*pnt) : *pnt; - } - break; - - /* - * Descriptions of DOS's 'Parse Filename' - * (function 29H) describes V1 and V2.0+ - * separator and terminator characters. - * These characters in a DOS name make - * the file visible but un-manipulable - * (all useful operations error off. - */ - /* separators */ - case '+': - case '=': - case '%': /* not legal DOS filename */ - case ':': - case ';': /* already handled */ - case '.': /* already handled */ - case ',': /* already handled */ - case '\t': - case ' ': - /* V1 only separators */ - case '/': - case '"': - case '[': - case ']': - /* terminators */ - case '>': - case '<': - case '|': - /* Hmm - what to do here? Skip? - * Win95 looks like it substitutes '_' - */ - *result++ = '_'; - break; - } /* switch (*pnt) */ - } /* if (result) */ - } /* if (chars_{after,before}_dot) ... */ - } /* else *pnt == '.' */ - } /* else DOS file names */ - current_length++; - pnt++; - } /* while (*pnt) */ - - /* - * OK, that wraps up the scan of the name. Now tidy up a few other - * things. - */ - - /* - * Look for emacs style of numbered backups, like foo.c.~3~. If - * we see this, convert the version number into the priority - * number. In case of name conflicts, this is what would end - * up being used as the 'extension'. - */ - if(tildes == 2) - { - int prio1 = 0; - pnt = name; - while (*pnt && *pnt != '~') - { - pnt++; - } - if (*pnt) - { - pnt++; - } - while(*pnt && *pnt != '~') - { - prio1 = 10*prio1 + *pnt - '0'; - pnt++; - } - priority = prio1; - } - - /* - * If this is not a directory, force a '.' in case we haven't - * seen one, and add a version number if we haven't seen one - * of those either. - */ - if (!dirflag) - { - if (!seen_dot && !omit_period) - { - if (result) *result++ = '.'; - extra++; - } - if(!omit_version_number && !seen_semic) - { - if(result) - { - *result++ = ';'; - *result++ = '1'; - }; - extra += 2; - } - } - - if(result) - { - *result++ = 0; - } - sresult->priority = priority; - - return (chars_before_dot + chars_after_dot + seen_dot + extra); -} diff --git a/util/mkisofs/rock.c b/util/mkisofs/rock.c deleted file mode 100644 index 224488af5..000000000 --- a/util/mkisofs/rock.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * File rock.c - generate RRIP records for iso9660 filesystems. - - Written by Eric Youngdale (1993). - - Copyright 1993 Yggdrasil Computing, Incorporated - - Copyright (C) 2009 Free Software Foundation, Inc. - - This program 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, or (at your option) - any later version. - - This program 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 this program; if not, see . - */ - -#include - -#include "config.h" - -#ifndef VMS -#if defined(MAJOR_IN_SYSMACROS) -#include -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif - -#endif -#if defined(MAJOR_IN_MKDEV) -#include -#include -#endif - -#include "mkisofs.h" -#include "iso9660.h" -#include -#include - -#ifdef DOESNT_WORK - -#ifdef NON_UNIXFS -#define S_ISLNK(m) (0) -#else -#ifndef S_ISLNK -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif -#endif - -#else -#include -#endif - -#define SU_VERSION 1 - -#define SL_ROOT 8 -#define SL_PARENT 4 -#define SL_CURRENT 2 -#define SL_CONTINUE 1 - -#define CE_SIZE 28 -#define CL_SIZE 12 -#define ER_SIZE 8 -#define NM_SIZE 5 -#define PL_SIZE 12 -#define PN_SIZE 20 -#define PX_SIZE 36 -#define RE_SIZE 4 -#define SL_SIZE 20 -#define ZZ_SIZE 15 -#ifdef __QNX__ -#define TF_SIZE (5 + 4 * 7) -#else -#define TF_SIZE (5 + 3 * 7) -#endif - -/* If we need to store this number of bytes, make sure we - do not box ourselves in so that we do not have room for - a CE entry for the continuation record */ - -#define MAYBE_ADD_CE_ENTRY(BYTES) \ - ((unsigned) ((BYTES) + CE_SIZE + currlen + ipnt) > (unsigned) (recstart + reclimit) ? 1 : 0) - -/* - * Buffer to build RR attributes - */ - -static unsigned char Rock[16384]; -static unsigned char symlink_buff[256]; -static int ipnt = 0; -static int recstart = 0; -static int currlen = 0; -static int mainrec = 0; -static int reclimit; - -static void add_CE_entry __PR((void)); - -static void add_CE_entry(){ - if(recstart) - set_733((char*)Rock + recstart - 8, ipnt + 28 - recstart); - Rock[ipnt++] ='C'; - Rock[ipnt++] ='E'; - Rock[ipnt++] = CE_SIZE; - Rock[ipnt++] = SU_VERSION; - set_733((char*)Rock + ipnt, 0); - ipnt += 8; - set_733((char*)Rock + ipnt, 0); - ipnt += 8; - set_733((char*)Rock + ipnt, 0); - ipnt += 8; - recstart = ipnt; - currlen = 0; - if(!mainrec) mainrec = ipnt; - reclimit = SECTOR_SIZE - 8; /* Limit to one sector */ -} - -#ifdef __STDC__ -int generate_rock_ridge_attributes (char * whole_name, char * name, - struct directory_entry * s_entry, - struct stat * statbuf, - struct stat * lstatbuf, - int deep_opt) -#else -int generate_rock_ridge_attributes (whole_name, name, - s_entry, - statbuf, - lstatbuf, - deep_opt) -char * whole_name; char * name; struct directory_entry * s_entry; -struct stat * statbuf, *lstatbuf; -int deep_opt; -#endif -{ - int flagpos, flagval; - int need_ce; - - statbuf = statbuf; /* this shuts up unreferenced compiler warnings */ - mainrec = recstart = ipnt = 0; - reclimit = 0xf8; - - /* no need to fill in the RR stuff if we won't see the file */ - if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) - return 0; - - /* Obtain the amount of space that is currently used for the directory - record. Assume max for name, since name conflicts may cause us - to rename the file later on */ - currlen = sizeof(s_entry->isorec); - - /* Identify that we are using the SUSP protocol */ - if(deep_opt & NEED_SP){ - Rock[ipnt++] ='S'; - Rock[ipnt++] ='P'; - Rock[ipnt++] = 7; - Rock[ipnt++] = SU_VERSION; - Rock[ipnt++] = 0xbe; - Rock[ipnt++] = 0xef; - Rock[ipnt++] = 0; - }; - - /* First build the posix name field */ - Rock[ipnt++] ='R'; - Rock[ipnt++] ='R'; - Rock[ipnt++] = 5; - Rock[ipnt++] = SU_VERSION; - flagpos = ipnt; - flagval = 0; - Rock[ipnt++] = 0; /* We go back and fix this later */ - - if(strcmp(name,".") && strcmp(name,"..")){ - char * npnt; - int remain, use; - - remain = strlen(name); - npnt = name; - - while(remain){ - use = remain; - need_ce = 0; - /* Can we fit this SUSP and a CE entry? */ - if(use + currlen + CE_SIZE + (ipnt - recstart) > reclimit) { - use = reclimit - currlen - CE_SIZE - (ipnt - recstart); - need_ce++; - } - - /* Only room for 256 per SUSP field */ - if(use > 0xf8) use = 0xf8; - - /* First build the posix name field */ - Rock[ipnt++] ='N'; - Rock[ipnt++] ='M'; - Rock[ipnt++] = NM_SIZE + use; - Rock[ipnt++] = SU_VERSION; - Rock[ipnt++] = (remain != use ? 1 : 0); - flagval |= (1<<3); - strncpy((char *)&Rock[ipnt], npnt, use); - npnt += use; - ipnt += use; - remain -= use; - if(remain && need_ce) add_CE_entry(); - }; - }; - - /* - * Add the posix modes - */ - if(MAYBE_ADD_CE_ENTRY(PX_SIZE)) add_CE_entry(); - Rock[ipnt++] ='P'; - Rock[ipnt++] ='X'; - Rock[ipnt++] = PX_SIZE; - Rock[ipnt++] = SU_VERSION; - flagval |= (1<<0); - set_733((char*)Rock + ipnt, lstatbuf->st_mode); - ipnt += 8; - set_733((char*)Rock + ipnt, lstatbuf->st_nlink); - ipnt += 8; - set_733((char*)Rock + ipnt, lstatbuf->st_uid); - ipnt += 8; - set_733((char*)Rock + ipnt, lstatbuf->st_gid); - ipnt += 8; - - /* - * Check for special devices - */ -#ifndef NON_UNIXFS - if (S_ISCHR(lstatbuf->st_mode) || S_ISBLK(lstatbuf->st_mode)) { - if(MAYBE_ADD_CE_ENTRY(PN_SIZE)) add_CE_entry(); - Rock[ipnt++] ='P'; - Rock[ipnt++] ='N'; - Rock[ipnt++] = PN_SIZE; - Rock[ipnt++] = SU_VERSION; - flagval |= (1<<1); -#if defined(MAJOR_IN_SYSMACROS) || defined(MAJOR_IN_MKDEV) - set_733((char*)Rock + ipnt, major(lstatbuf->st_rdev )); - ipnt += 8; - set_733((char*)Rock + ipnt, minor(lstatbuf->st_rdev)); - ipnt += 8; -#else - /* - * If we don't have sysmacros.h, then we have to guess as to how - * best to pick apart the device number for major/minor. - * Note: this may very well be wrong for many systems, so - * it is always best to use the major/minor macros if the - * system supports it. - */ - if(sizeof(dev_t) <= 2) { - set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8)); - ipnt += 8; - set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xff); - ipnt += 8; - } - else if(sizeof(dev_t) <= 4) { - set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 8) >> 8); - ipnt += 8; - set_733((char*)Rock + ipnt, lstatbuf->st_rdev & 0xffff); - ipnt += 8; - } - else { - set_733((char*)Rock + ipnt, (lstatbuf->st_rdev >> 16) >> 16); - ipnt += 8; - set_733((char*)Rock + ipnt, lstatbuf->st_rdev); - ipnt += 8; - } -#endif - }; -#endif - /* - * Check for and symbolic links. VMS does not have these. - */ - if (S_ISLNK(lstatbuf->st_mode)){ - int lenpos, lenval, j0, j1; - int nchar; - unsigned char * cpnt, *cpnt1; - nchar = readlink(whole_name, (char *)symlink_buff, sizeof(symlink_buff)); - symlink_buff[nchar < 0 ? 0 : nchar] = 0; - nchar = strlen((char *) symlink_buff); - set_733(s_entry->isorec.size, 0); - cpnt = &symlink_buff[0]; - flagval |= (1<<2); - - if (! split_SL_field) - { - int sl_bytes = 0; - for (cpnt1 = cpnt; *cpnt1 != '\0'; cpnt1++) - { - if (*cpnt1 == '/') - { - sl_bytes += 4; - } - else - { - sl_bytes += 1; - } - } - if (sl_bytes > 250) - { - /* - * the symbolic link won't fit into one SL System Use Field - * print an error message and continue with splited one - */ - fprintf(stderr, _("symbolic link ``%s'' to long for one SL System Use Field, splitting"), cpnt); - } - if(MAYBE_ADD_CE_ENTRY(SL_SIZE + sl_bytes)) add_CE_entry(); - } - - while(nchar){ - if(MAYBE_ADD_CE_ENTRY(SL_SIZE)) add_CE_entry(); - Rock[ipnt++] ='S'; - Rock[ipnt++] ='L'; - lenpos = ipnt; - Rock[ipnt++] = SL_SIZE; - Rock[ipnt++] = SU_VERSION; - Rock[ipnt++] = 0; /* Flags */ - lenval = 5; - while(*cpnt){ - cpnt1 = (unsigned char *) strchr((char *) cpnt, '/'); - if(cpnt1) { - nchar--; - *cpnt1 = 0; - }; - - /* We treat certain components in a special way. */ - if(cpnt[0] == '.' && cpnt[1] == '.' && cpnt[2] == 0){ - if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry(); - Rock[ipnt++] = SL_PARENT; - Rock[ipnt++] = 0; /* length is zero */ - lenval += 2; - nchar -= 2; - } else if(cpnt[0] == '.' && cpnt[1] == 0){ - if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry(); - Rock[ipnt++] = SL_CURRENT; - Rock[ipnt++] = 0; /* length is zero */ - lenval += 2; - nchar -= 1; - } else if(cpnt[0] == 0){ - if(MAYBE_ADD_CE_ENTRY(2)) add_CE_entry(); - Rock[ipnt++] = SL_ROOT; - Rock[ipnt++] = 0; /* length is zero */ - lenval += 2; - } else { - /* If we do not have enough room for a component, start - a new continuations segment now */ - if(split_SL_component ? MAYBE_ADD_CE_ENTRY(6) : - MAYBE_ADD_CE_ENTRY(6 + strlen ((char *) cpnt))) - { - add_CE_entry(); - if(cpnt1) - { - *cpnt1 = '/'; - nchar++; - cpnt1 = NULL; /* A kluge so that we can restart properly */ - } - break; - } - j0 = strlen((char *) cpnt); - while(j0) { - j1 = j0; - if(j1 > 0xf8) j1 = 0xf8; - need_ce = 0; - if(j1 + currlen + CE_SIZE + (ipnt - recstart) > reclimit) { - j1 = reclimit - currlen - CE_SIZE - (ipnt - recstart); - need_ce++; - } - Rock[ipnt++] = (j1 != j0 ? SL_CONTINUE : 0); - Rock[ipnt++] = j1; - strncpy((char *) Rock + ipnt, (char *) cpnt, j1); - ipnt += j1; - lenval += j1 + 2; - cpnt += j1; - nchar -= j1; /* Number we processed this time */ - j0 -= j1; - if(need_ce) { - add_CE_entry(); - if(cpnt1) { - *cpnt1 = '/'; - nchar++; - cpnt1 = NULL; /* A kluge so that we can restart properly */ - } - break; - } - } - }; - if(cpnt1) { - cpnt = cpnt1 + 1; - } else - break; - } - Rock[lenpos] = lenval; - if(nchar) Rock[lenpos + 2] = SL_CONTINUE; /* We need another SL entry */ - } /* while nchar */ - } /* Is a symbolic link */ - /* - * Add in the Rock Ridge TF time field - */ - if(MAYBE_ADD_CE_ENTRY(TF_SIZE)) add_CE_entry(); - Rock[ipnt++] ='T'; - Rock[ipnt++] ='F'; - Rock[ipnt++] = TF_SIZE; - Rock[ipnt++] = SU_VERSION; -#ifdef __QNX__ - Rock[ipnt++] = 0x0f; -#else - Rock[ipnt++] = 0x0e; -#endif - flagval |= (1<<7); -#ifdef __QNX__ - iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ftime); - ipnt += 7; -#endif - iso9660_date((char *) &Rock[ipnt], lstatbuf->st_mtime); - ipnt += 7; - iso9660_date((char *) &Rock[ipnt], lstatbuf->st_atime); - ipnt += 7; - iso9660_date((char *) &Rock[ipnt], lstatbuf->st_ctime); - ipnt += 7; - - /* - * Add in the Rock Ridge RE time field - */ - if(deep_opt & NEED_RE){ - if(MAYBE_ADD_CE_ENTRY(RE_SIZE)) add_CE_entry(); - Rock[ipnt++] ='R'; - Rock[ipnt++] ='E'; - Rock[ipnt++] = RE_SIZE; - Rock[ipnt++] = SU_VERSION; - flagval |= (1<<6); - }; - /* - * Add in the Rock Ridge PL record, if required. - */ - if(deep_opt & NEED_PL){ - if(MAYBE_ADD_CE_ENTRY(PL_SIZE)) add_CE_entry(); - Rock[ipnt++] ='P'; - Rock[ipnt++] ='L'; - Rock[ipnt++] = PL_SIZE; - Rock[ipnt++] = SU_VERSION; - set_733((char*)Rock + ipnt, 0); - ipnt += 8; - flagval |= (1<<5); - }; - - /* - * Add in the Rock Ridge CL field, if required. - */ - if(deep_opt & NEED_CL){ - if(MAYBE_ADD_CE_ENTRY(CL_SIZE)) add_CE_entry(); - Rock[ipnt++] ='C'; - Rock[ipnt++] ='L'; - Rock[ipnt++] = CL_SIZE; - Rock[ipnt++] = SU_VERSION; - set_733((char*)Rock + ipnt, 0); - ipnt += 8; - flagval |= (1<<4); - }; - -#ifndef VMS - /* If transparent compression was requested, fill in the correct - field for this file */ - if(transparent_compression && - S_ISREG(lstatbuf->st_mode) && - strlen(name) > 3 && - strcmp(name + strlen(name) - 3,".gZ") == 0){ - FILE * zipfile; - char * checkname; - unsigned int file_size; - unsigned char header[8]; - int OK_flag; - - /* First open file and verify that the correct algorithm was used */ - file_size = 0; - OK_flag = 1; - - zipfile = fopen(whole_name, "rb"); - if (fread (header, 1, sizeof (header), zipfile) != sizeof(header)) - error (1, errno, "fread"); - - /* Check some magic numbers from gzip. */ - if(header[0] != 0x1f || header[1] != 0x8b || header[2] != 8) OK_flag = 0; - /* Make sure file was blocksized. */ - if(((header[3] & 0x40) == 0)) OK_flag = 0; - /* OK, now go to the end of the file and get some more info */ - if(OK_flag){ - int status; - status = (long)lseek(fileno(zipfile), (off_t)(-8), SEEK_END); - if(status == -1) OK_flag = 0; - } - if(OK_flag){ - if(read(fileno(zipfile), (char*)header, sizeof(header)) != sizeof(header)) - OK_flag = 0; - else { - int blocksize; - blocksize = (header[3] << 8) | header[2]; - file_size = ((unsigned int)header[7] << 24) | - ((unsigned int)header[6] << 16) | - ((unsigned int)header[5] << 8) | header[4]; -#if 0 - fprintf(stderr,"Blocksize = %d %d\n", blocksize, file_size); -#endif - if(blocksize != SECTOR_SIZE) OK_flag = 0; - } - } - fclose(zipfile); - - checkname = strdup(whole_name); - checkname[strlen(whole_name)-3] = 0; - zipfile = fopen(checkname, "rb"); - if(zipfile) { - OK_flag = 0; - fprintf (stderr, _("Unable to insert transparent compressed file - name conflict\n")); - fclose(zipfile); - } - - free(checkname); - - if(OK_flag){ - if(MAYBE_ADD_CE_ENTRY(ZZ_SIZE)) add_CE_entry(); - Rock[ipnt++] ='Z'; - Rock[ipnt++] ='Z'; - Rock[ipnt++] = ZZ_SIZE; - Rock[ipnt++] = SU_VERSION; - Rock[ipnt++] = 'g'; /* Identify compression technique used */ - Rock[ipnt++] = 'z'; - Rock[ipnt++] = 3; - set_733((char*)Rock + ipnt, file_size); /* Real file size */ - ipnt += 8; - }; - } -#endif - /* - * Add in the Rock Ridge CE field, if required. We use this for the - * extension record that is stored in the root directory. - */ - if(deep_opt & NEED_CE) add_CE_entry(); - /* - * Done filling in all of the fields. Now copy it back to a buffer for the - * file in question. - */ - - /* Now copy this back to the buffer for the file */ - Rock[flagpos] = flagval; - - /* If there was a CE, fill in the size field */ - if(recstart) - set_733((char*)Rock + recstart - 8, ipnt - recstart); - - s_entry->rr_attributes = (unsigned char *) e_malloc(ipnt); - s_entry->total_rr_attr_size = ipnt; - s_entry->rr_attr_size = (mainrec ? mainrec : ipnt); - memcpy(s_entry->rr_attributes, Rock, ipnt); - return ipnt; -} - -/* Guaranteed to return a single sector with the relevant info */ - -char * FDECL4(generate_rr_extension_record, char *, id, char *, descriptor, - char *, source, int *, size){ - int lipnt = 0; - char * pnt; - int len_id, len_des, len_src; - - len_id = strlen(id); - len_des = strlen(descriptor); - len_src = strlen(source); - Rock[lipnt++] ='E'; - Rock[lipnt++] ='R'; - Rock[lipnt++] = ER_SIZE + len_id + len_des + len_src; - Rock[lipnt++] = 1; - Rock[lipnt++] = len_id; - Rock[lipnt++] = len_des; - Rock[lipnt++] = len_src; - Rock[lipnt++] = 1; - - memcpy(Rock + lipnt, id, len_id); - lipnt += len_id; - - memcpy(Rock + lipnt, descriptor, len_des); - lipnt += len_des; - - memcpy(Rock + lipnt, source, len_src); - lipnt += len_src; - - if(lipnt > SECTOR_SIZE) - error (1, 0, _("Extension record too long\n")); - pnt = (char *) e_malloc(SECTOR_SIZE); - memset(pnt, 0, SECTOR_SIZE); - memcpy(pnt, Rock, lipnt); - *size = lipnt; - return pnt; -} diff --git a/util/mkisofs/tree.c b/util/mkisofs/tree.c deleted file mode 100644 index d11fdc2cd..000000000 --- a/util/mkisofs/tree.c +++ /dev/null @@ -1,1865 +0,0 @@ -/* - * File tree.c - scan directory tree and build memory structures for iso9660 - * filesystem - - Written by Eric Youngdale (1993). - - Copyright 1993 Yggdrasil Computing, Incorporated - - Copyright (C) 2009 Free Software Foundation, Inc. - - This program 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, or (at your option) - any later version. - - This program 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 this program; if not, see . - */ - -/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */ - -#include -#include -#include -#include - -#include "config.h" - -#ifndef VMS -#if defined(MAJOR_IN_SYSMACROS) -#include -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif -#include - -#if defined(MAJOR_IN_MKDEV) -#include -#include -#endif -#else -#include -#include -#include "vms.h" -extern char * strdup(const char *); -#endif - -/* - * Autoconf should be able to figure this one out for us and let us know - * whether the system has memmove or not. - */ -# ifndef HAVE_MEMMOVE -# define memmove(d, s, n) bcopy ((s), (d), (n)) -# endif - -#include "mkisofs.h" -#include "iso9660.h" -#include "match.h" - -#include - -#include "exclude.h" - -#ifdef DOESNT_WORK - -#ifdef NON_UNIXFS -#define S_ISLNK(m) (0) -#define S_ISSOCK(m) (0) -#define S_ISFIFO(m) (0) -#else -#ifndef S_ISLNK -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif -#ifndef S_ISSOCK -# ifdef S_IFSOCK -# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) -# else -# define S_ISSOCK(m) (0) -# endif -#endif -#endif - -#else -#include -#endif - - -#ifdef __SVR4 -extern char * strdup(const char *); -#endif - -static unsigned char symlink_buff[256]; - -static void stat_fix __PR((struct stat * st)); -static void generate_reloc_directory __PR((void)); - -static void DECL(attach_dot_entries, (struct directory * dirnode, - struct stat * parent_stat)); -static void DECL(delete_directory, (struct directory * parent, struct directory * child)); - -extern int verbose; - -struct stat fstatbuf; /* We use this for the artificial entries we create */ - -struct stat root_statbuf; /* Stat buffer for root directory */ - -struct directory * reloc_dir = NULL; - -static void -FDECL1(stat_fix, struct stat *, st) -{ - /* Remove the uid and gid, they will only be useful on the author's - system. */ - st->st_uid = 0; - st->st_gid = 0; - - /* - * Make sure the file modes make sense. Turn on all read bits. Turn - * on all exec/search bits if any exec/search bit is set. Turn off - * all write bits, and all special mode bits (on a r/o fs lock bits - * are useless, and with uid+gid 0 don't want set-id bits, either). - */ - st->st_mode |= 0444; -#ifndef _WIN32 /* make all file "executable" */ - if (st->st_mode & 0111) -#endif /* _WIN32 */ - st->st_mode |= 0111; - st->st_mode &= ~07222; -} - -int -FDECL2(stat_filter, char *, path, struct stat *, st) -{ - int result = stat(path, st); - if (result >= 0 && rationalize) - stat_fix(st); - - if ((unsigned) st->st_size > UINT32_MAX) - result = -1; - - return result; -} - -int -FDECL2(lstat_filter, char *, path, struct stat *, st) -{ - int result = lstat(path, st); - if (result >= 0 && rationalize) - stat_fix(st); - - if ((unsigned) st->st_size > UINT32_MAX) - result = -1; - - return result; -} - -static int FDECL1(sort_n_finish, struct directory *, this_dir) -{ - struct directory_entry * s_entry; - struct directory_entry * s_entry1; - struct directory_entry * table; - int count; - int d1; - int d2; - int d3; - int new_reclen; - char * c; - int status = 0; - int tablesize = 0; - char newname[34]; - char rootname[34]; - - /* Here we can take the opportunity to toss duplicate entries from the - directory. */ - - /* ignore if it's hidden */ - if(this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) - { - return 0; - } - - table = NULL; - - init_fstatbuf(); - - /* - * If we had artificially created this directory, then we might be - * missing the required '.' entries. Create these now if we need - * them. - */ - if( (this_dir->dir_flags & (DIR_HAS_DOT | DIR_HAS_DOTDOT)) != - (DIR_HAS_DOT | DIR_HAS_DOTDOT) ) - { - attach_dot_entries(this_dir, &fstatbuf); - } - - flush_file_hash(); - s_entry = this_dir->contents; - while(s_entry) - { - /* ignore if it's hidden */ - if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) - { - s_entry = s_entry->next; - continue; - } - - /* - * First assume no conflict, and handle this case - */ - if(!(s_entry1 = find_file_hash(s_entry->isorec.name))) - { - add_file_hash(s_entry); - s_entry = s_entry->next; - continue; - } - - if(s_entry1 == s_entry) - error (1, 0, _("Fatal goof\n")); - - /* - * OK, handle the conflicts. Try substitute names until we come - * up with a winner - */ - strcpy(rootname, s_entry->isorec.name); - if(full_iso9660_filenames) - { - if(strlen(rootname) > 27) rootname[27] = 0; - } - - /* - * Strip off the non-significant part of the name so that we are left - * with a sensible root filename. If we don't find a '.', then try - * a ';'. - */ - c = strchr(rootname, '.'); - if (c) - *c = 0; - else - { - c = strchr(rootname, ';'); - if (c) *c = 0; - } - for(d1 = 0; d1 < 36; d1++) - { - for(d2 = 0; d2 < 36; d2++) - { - for(d3 = 0; d3 < 36; d3++) - { - sprintf(newname,"%s.%c%c%c%s", rootname, - (d1 <= 9 ? '0' + d1 : 'A' + d1 - 10), - (d2 <= 9 ? '0' + d2 : 'A' + d2 - 10), - (d3 <= 9 ? '0' + d3 : 'A' + d3 - 10), - (s_entry->isorec.flags[0] == 2 || - omit_version_number ? "" : ";1")); - -#ifdef VMS - /* Sigh. VAXCRTL seems to be broken here */ - { - int ijk = 0; - while(newname[ijk]) - { - if(newname[ijk] == ' ') newname[ijk] = '0'; - ijk++; - } - } -#endif - - if(!find_file_hash(newname)) goto got_valid_name; - } - } - } - - /* - * If we fell off the bottom here, we were in real trouble. - */ - error (1, 0, _("Unable to generate unique name for file %s\n"), s_entry->name); - -got_valid_name: - /* - * OK, now we have a good replacement name. Now decide which one - * of these two beasts should get the name changed - */ - if(s_entry->priority < s_entry1->priority) - { - if( verbose > 0 ) - { - fprintf (stderr, _("Using %s for %s%s%s (%s)\n"), newname, - this_dir->whole_name, SPATH_SEPARATOR, - s_entry->name, s_entry1->name); - } - s_entry->isorec.name_len[0] = strlen(newname); - new_reclen = sizeof(struct iso_directory_record) - - sizeof(s_entry->isorec.name) + - strlen(newname); - if(use_RockRidge) - { - if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ - new_reclen += s_entry->rr_attr_size; - } - if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ - s_entry->isorec.length[0] = new_reclen; - strcpy(s_entry->isorec.name, newname); - } - else - { - delete_file_hash(s_entry1); - if( verbose > 0 ) - { - fprintf(stderr, _("Using %s for %s%s%s (%s)\n"), newname, - this_dir->whole_name, SPATH_SEPARATOR, - s_entry1->name, s_entry->name); - } - s_entry1->isorec.name_len[0] = strlen(newname); - new_reclen = sizeof(struct iso_directory_record) - - sizeof(s_entry1->isorec.name) + - strlen(newname); - if(use_RockRidge) - { - if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ - new_reclen += s_entry1->rr_attr_size; - } - if (new_reclen & 1) new_reclen++; /* Pad to an even byte */ - s_entry1->isorec.length[0] = new_reclen; - strcpy(s_entry1->isorec.name, newname); - add_file_hash(s_entry1); - } - add_file_hash(s_entry); - s_entry = s_entry->next; - } - - if(generate_tables - && !find_file_hash("TRANS.TBL") - && (reloc_dir != this_dir) - && (this_dir->extent == 0) ) - { - /* - * First we need to figure out how big this table is - */ - for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) - { - if(strcmp(s_entry->name, ".") == 0 || - strcmp(s_entry->name, "..") == 0) continue; - if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) continue; - if(s_entry->table) tablesize += 35 + strlen(s_entry->table); - } - } - - if( tablesize > 0 ) - { - table = (struct directory_entry *) - e_malloc(sizeof (struct directory_entry)); - memset(table, 0, sizeof(struct directory_entry)); - table->table = NULL; - table->next = this_dir->contents; - this_dir->contents = table; - - table->filedir = root; - table->isorec.flags[0] = 0; - table->priority = 32768; - iso9660_date(table->isorec.date, fstatbuf.st_mtime); - table->inode = TABLE_INODE; - table->dev = (dev_t) UNCACHED_DEVICE; - set_723(table->isorec.volume_sequence_number, volume_sequence_number); - set_733((char *) table->isorec.size, tablesize); - table->size = tablesize; - table->filedir = this_dir; -#ifdef ERIC_neverdef - table->de_flags |= INHIBIT_JOLIET_ENTRY; -#endif - table->name = strdup(""); - table->table = (char *) e_malloc(ROUND_UP(tablesize)); - memset(table->table, 0, ROUND_UP(tablesize)); - iso9660_file_length ("TRANS.TBL", table, 0); - - if(use_RockRidge) - { - fstatbuf.st_mode = 0444 | S_IFREG; - fstatbuf.st_nlink = 1; - generate_rock_ridge_attributes("", - "TRANS.TBL", table, - &fstatbuf, &fstatbuf, 0); - } - } - - /* - * We have now chosen the 8.3 names and we should now know the length - * of every entry in the directory. - */ - for(s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) - { - /* skip if it's hidden */ - if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) - { - continue; - } - - new_reclen = strlen(s_entry->isorec.name); - - /* - * First update the path table sizes for directories. - */ - if(s_entry->isorec.flags[0] == 2) - { - if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..")) - { - path_table_size += new_reclen + sizeof(struct iso_path_table) - 1; - if (new_reclen & 1) path_table_size++; - } - else - { - new_reclen = 1; - if (this_dir == root && strlen(s_entry->name) == 1) - { - path_table_size += sizeof(struct iso_path_table); - } - } - } - if(path_table_size & 1) path_table_size++; /* For odd lengths we pad */ - s_entry->isorec.name_len[0] = new_reclen; - - new_reclen += - sizeof(struct iso_directory_record) - - sizeof(s_entry->isorec.name); - - if (new_reclen & 1) - new_reclen++; - - new_reclen += s_entry->rr_attr_size; - - if (new_reclen & 1) new_reclen++; - - if(new_reclen > 0xff) - error (1, 0, _("Fatal error - RR overflow for file %s\n"), - s_entry->name); - s_entry->isorec.length[0] = new_reclen; - } - - status = sort_directory(&this_dir->contents); - if( status > 0 ) - { - fprintf (stderr, _("Unable to sort directory %s\n"), - this_dir->whole_name); - } - - /* - * If we are filling out a TRANS.TBL, generate the entries that will - * go in the thing. - */ - if(table) - { - count = 0; - for (s_entry = this_dir->contents; s_entry; s_entry = s_entry->next){ - if(s_entry == table) continue; - if(!s_entry->table) continue; - if(strcmp(s_entry->name, ".") == 0 || - strcmp(s_entry->name, "..") == 0) continue; - if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) continue; - /* - * Warning: we cannot use the return value of sprintf because - * old BSD based sprintf() implementations will return - * a pointer to the result instead of a count. - */ - sprintf(table->table + count, "%c %-34s%s", - s_entry->table[0], - s_entry->isorec.name, s_entry->table+1); - count += strlen(table->table + count); - free(s_entry->table); - s_entry->table = NULL; - } - - if(count != tablesize) - error (1, 0, _("Translation table size mismatch %d %d\n"), - count, tablesize); - } - - /* - * Now go through the directory and figure out how large this one will be. - * Do not split a directory entry across a sector boundary - */ - s_entry = this_dir->contents; - this_dir->ce_bytes = 0; - while(s_entry) - { - /* skip if it's hidden */ - if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) { - s_entry = s_entry->next; - continue; - } - - new_reclen = s_entry->isorec.length[0]; - if ((this_dir->size & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE) - this_dir->size = (this_dir->size + (SECTOR_SIZE - 1)) & - ~(SECTOR_SIZE - 1); - this_dir->size += new_reclen; - - /* See if continuation entries were used on disc */ - if(use_RockRidge && - s_entry->rr_attr_size != s_entry->total_rr_attr_size) - { - unsigned char * pnt; - int len; - int nbytes; - - pnt = s_entry->rr_attributes; - len = s_entry->total_rr_attr_size; - - /* - * We make sure that each continuation entry record is not - * split across sectors, but each file could in theory have more - * than one CE, so we scan through and figure out what we need. - */ - while(len > 3) - { - if(pnt[0] == 'C' && pnt[1] == 'E') - { - nbytes = get_733((char *) pnt+20); - - if((this_dir->ce_bytes & (SECTOR_SIZE - 1)) + nbytes >= - SECTOR_SIZE) this_dir->ce_bytes = - ROUND_UP(this_dir->ce_bytes); - /* Now store the block in the ce buffer */ - this_dir->ce_bytes += nbytes; - if(this_dir->ce_bytes & 1) this_dir->ce_bytes++; - } - len -= pnt[2]; - pnt += pnt[2]; - } - } - s_entry = s_entry->next; - } - return status; -} - -static void generate_reloc_directory() -{ - time_t current_time; - struct directory_entry *s_entry; - - /* Create an entry for our internal tree */ - time (¤t_time); - reloc_dir = (struct directory *) - e_malloc(sizeof(struct directory)); - memset(reloc_dir, 0, sizeof(struct directory)); - reloc_dir->parent = root; - reloc_dir->next = root->subdir; - root->subdir = reloc_dir; - reloc_dir->depth = 1; - reloc_dir->whole_name = strdup("./rr_moved"); - reloc_dir->de_name = strdup("rr_moved"); - reloc_dir->extent = 0; - - - /* Now create an actual directory entry */ - s_entry = (struct directory_entry *) - e_malloc(sizeof (struct directory_entry)); - memset(s_entry, 0, sizeof(struct directory_entry)); - s_entry->next = root->contents; - reloc_dir->self = s_entry; - - /* - * The rr_moved entry will not appear in the Joliet tree. - */ - reloc_dir->dir_flags |= INHIBIT_JOLIET_ENTRY; - s_entry->de_flags |= INHIBIT_JOLIET_ENTRY; - - root->contents = s_entry; - root->contents->name = strdup(reloc_dir->de_name); - root->contents->filedir = root; - root->contents->isorec.flags[0] = 2; - root->contents->priority = 32768; - iso9660_date(root->contents->isorec.date, current_time); - root->contents->inode = UNCACHED_INODE; - root->contents->dev = (dev_t) UNCACHED_DEVICE; - set_723(root->contents->isorec.volume_sequence_number, volume_sequence_number); - iso9660_file_length (reloc_dir->de_name, root->contents, 1); - - if(use_RockRidge){ - fstatbuf.st_mode = 0555 | S_IFDIR; - fstatbuf.st_nlink = 2; - generate_rock_ridge_attributes("", - "rr_moved", s_entry, - &fstatbuf, &fstatbuf, 0); - }; - - /* Now create the . and .. entries in rr_moved */ - /* Now create an actual directory entry */ - attach_dot_entries(reloc_dir, &root_statbuf); -} - -/* - * Function: attach_dot_entries - * - * Purpose: Create . and .. entries for a new directory. - * - * Notes: Only used for artificial directories that - * we are creating. - */ -static void FDECL2(attach_dot_entries, struct directory *, dirnode, - struct stat *, parent_stat) -{ - struct directory_entry *s_entry; - struct directory_entry *orig_contents; - int deep_flag = 0; - - init_fstatbuf(); - - orig_contents = dirnode->contents; - - if( (dirnode->dir_flags & DIR_HAS_DOTDOT) == 0 ) - { - s_entry = (struct directory_entry *) - e_malloc(sizeof (struct directory_entry)); - memcpy(s_entry, dirnode->self, - sizeof(struct directory_entry)); - s_entry->name = strdup(".."); - s_entry->whole_name = NULL; - s_entry->isorec.name_len[0] = 1; - s_entry->isorec.flags[0] = 2; /* Mark as a directory */ - iso9660_file_length ("..", s_entry, 1); - iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime); - s_entry->filedir = dirnode->parent; - - dirnode->contents = s_entry; - dirnode->contents->next = orig_contents; - orig_contents = s_entry; - - if(use_RockRidge) - { - if( parent_stat == NULL ) - { - parent_stat = &fstatbuf; - } - generate_rock_ridge_attributes("", - "..", s_entry, - parent_stat, - parent_stat, 0); - } - dirnode->dir_flags |= DIR_HAS_DOTDOT; - } - - if( (dirnode->dir_flags & DIR_HAS_DOT) == 0 ) - { - s_entry = (struct directory_entry *) - e_malloc(sizeof (struct directory_entry)); - memcpy(s_entry, dirnode->self, - sizeof(struct directory_entry)); - s_entry->name = strdup("."); - s_entry->whole_name = NULL; - s_entry->isorec.name_len[0] = 1; - s_entry->isorec.flags[0] = 2; /* Mark as a directory */ - iso9660_file_length (".", s_entry, 1); - iso9660_date(s_entry->isorec.date, fstatbuf.st_mtime); - s_entry->filedir = dirnode; - - dirnode->contents = s_entry; - dirnode->contents->next = orig_contents; - - if(use_RockRidge) - { - fstatbuf.st_mode = 0555 | S_IFDIR; - fstatbuf.st_nlink = 2; - - if( dirnode == root ) - { - deep_flag |= NEED_CE | NEED_SP; /* For extension record */ - } - - generate_rock_ridge_attributes("", - ".", s_entry, - &fstatbuf, &fstatbuf, deep_flag); - } - - dirnode->dir_flags |= DIR_HAS_DOT; - } - -} - -static void FDECL2(update_nlink, struct directory_entry *, s_entry, int, value) -{ - unsigned char * pnt; - int len; - - pnt = s_entry->rr_attributes; - len = s_entry->total_rr_attr_size; - while(len) - { - if(pnt[0] == 'P' && pnt[1] == 'X') - { - set_733((char *) pnt+12, value); - break; - } - len -= pnt[2]; - pnt += pnt[2]; - } -} - -static void FDECL1(increment_nlink, struct directory_entry *, s_entry) -{ - unsigned char * pnt; - int len, nlink; - - pnt = s_entry->rr_attributes; - len = s_entry->total_rr_attr_size; - while(len) - { - if(pnt[0] == 'P' && pnt[1] == 'X') - { - nlink = get_733((char *) pnt+12); - set_733((char *) pnt+12, nlink+1); - break; - } - len -= pnt[2]; - pnt += pnt[2]; - } -} - -void finish_cl_pl_entries(){ - struct directory_entry *s_entry, *s_entry1; - struct directory * d_entry; - - /* if the reloc_dir is hidden (empty), then return */ - if (reloc_dir->dir_flags & INHIBIT_ISO9660_ENTRY) - return; - - s_entry = reloc_dir->contents; - s_entry = s_entry->next->next; /* Skip past . and .. */ - for(; s_entry; s_entry = s_entry->next){ - /* skip if it's hidden */ - if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) { - continue; - } - d_entry = reloc_dir->subdir; - while(d_entry){ - if(d_entry->self == s_entry) break; - d_entry = d_entry->next; - }; - if(!d_entry) - error (1, 0, _("Unable to locate directory parent\n")); - - /* First fix the PL pointer in the directory in the rr_reloc dir */ - s_entry1 = d_entry->contents->next; - set_733((char *) s_entry1->rr_attributes + s_entry1->total_rr_attr_size - 8, - s_entry->filedir->extent); - - /* Now fix the CL pointer */ - s_entry1 = s_entry->parent_rec; - - set_733((char *) s_entry1->rr_attributes + s_entry1->total_rr_attr_size - 8, - d_entry->extent); - - s_entry->filedir = reloc_dir; /* Now we can fix this */ - } - /* Next we need to modify the NLINK terms in the assorted root directory records - to account for the presence of the RR_MOVED directory */ - - increment_nlink(root->self); - increment_nlink(root->self->next); - d_entry = root->subdir; - while(d_entry){ - increment_nlink(d_entry->contents->next); - d_entry = d_entry->next; - }; -} - -/* - * Function: scan_directory_tree - * - * Purpose: Walk through a directory on the local machine - * filter those things we don't want to include - * and build our representation of a dir. - * - * Notes: - */ -int -FDECL3(scan_directory_tree,struct directory *, this_dir, - char *, path, - struct directory_entry *, de) -{ - DIR * current_dir; - char whole_path[1024]; - struct dirent * d_entry; - struct directory * parent; - int dflag; - char * old_path; - - if (verbose > 1) - { - fprintf (stderr, _("Scanning %s\n"), path); - } - - current_dir = opendir(path); - d_entry = NULL; - - /* Apparently NFS sometimes allows you to open the directory, but - then refuses to allow you to read the contents. Allow for this */ - - old_path = path; - - if(current_dir) d_entry = readdir(current_dir); - - if(!current_dir || !d_entry) - { - fprintf (stderr, _("Unable to open directory %s\n"), path); - de->isorec.flags[0] &= ~2; /* Mark as not a directory */ - if(current_dir) closedir(current_dir); - return 0; - } - - parent = de->filedir; - /* Set up the struct for the current directory, and insert it into the - tree */ - -#ifdef VMS - vms_path_fixup(path); -#endif - - /* - * if entry for this sub-directory is hidden, then hide this directory - */ - if (de->de_flags & INHIBIT_ISO9660_ENTRY) - this_dir->dir_flags |= INHIBIT_ISO9660_ENTRY; - - if (de->de_flags & INHIBIT_JOLIET_ENTRY) - this_dir->dir_flags |= INHIBIT_JOLIET_ENTRY; - - /* - * Now we scan the directory itself, and look at what is inside of it. - */ - dflag = 0; - while(1==1){ - - /* The first time through, skip this, since we already asked for - the first entry when we opened the directory. */ - if(dflag) d_entry = readdir(current_dir); - dflag++; - - if(!d_entry) break; - - /* OK, got a valid entry */ - - /* If we do not want all files, then pitch the backups. */ - if(!all_files){ - if( strchr(d_entry->d_name,'~') - || strchr(d_entry->d_name,'#')) - { - if( verbose > 0 ) - { - fprintf (stderr, _("Ignoring file %s\n"), d_entry->d_name); - } - continue; - } - } - - if(strlen(path)+strlen(d_entry->d_name) + 2 > sizeof(whole_path)) - error (1, 0, _("Overflow of stat buffer\n")); - - /* Generate the complete ASCII path for this file */ - strcpy(whole_path, path); -#ifndef VMS - if(whole_path[strlen(whole_path)-1] != '/') - strcat(whole_path, "/"); -#endif - strcat(whole_path, d_entry->d_name); - - /** Should we exclude this file ? */ - if (matches(d_entry->d_name) || matches(whole_path)) { - if (verbose > 1) { - fprintf (stderr, _("Excluded by match: %s\n"), whole_path); - } - continue; - } - - if( generate_tables - && strcmp(d_entry->d_name, "TRANS.TBL") == 0 ) - { - /* - * Ignore this entry. We are going to be generating new - * versions of these files, and we need to ignore any - * originals that we might have found. - */ - if (verbose > 1) - { - fprintf (stderr, _("Excluded: %s\n"), whole_path); - } - continue; - } - - /* - * If we already have a '.' or a '..' entry, then don't - * insert new ones. - */ - if( strcmp(d_entry->d_name, ".") == 0 - && this_dir->dir_flags & DIR_HAS_DOT ) - { - continue; - } - - if( strcmp(d_entry->d_name, "..") == 0 - && this_dir->dir_flags & DIR_HAS_DOTDOT ) - { - continue; - } - -#if 0 - if (verbose > 1) fprintf(stderr, "%s\n",whole_path); -#endif - /* - * This actually adds the entry to the directory in question. - */ - insert_file_entry(this_dir, whole_path, d_entry->d_name); - } - closedir(current_dir); - - return 1; -} - - -/* - * Function: insert_file_entry - * - * Purpose: Insert one entry into our directory node. - * - * Note: - * This function inserts a single entry into the directory. It - * is assumed that all filtering and decision making regarding what - * we want to include has already been made, so the purpose of this - * is to insert one entry (file, link, dir, etc), into this directory. - * Note that if the entry is a dir (or if we are following links, - * and the thing it points to is a dir), then we will scan those - * trees before we return. - */ -int -FDECL3(insert_file_entry,struct directory *, this_dir, - char *, whole_path, - char *, short_name) -{ - struct stat statbuf, lstatbuf; - struct directory_entry * s_entry, *s_entry1; - int lstatus; - int status; - int deep_flag; - - status = stat_filter(whole_path, &statbuf); - - lstatus = lstat_filter(whole_path, &lstatbuf); - - if( (status == -1) && (lstatus == -1) ) - { - /* - * This means that the file doesn't exist, or isn't accessible. - * Sometimes this is because of NFS permissions problems. - */ - fprintf (stderr, _("Non-existant or inaccessible: %s\n"),whole_path); - return 0; - } - - if(this_dir == root && strcmp(short_name, ".") == 0) - root_statbuf = statbuf; /* Save this for later on */ - - /* We do this to make sure that the root entries are consistent */ - if(this_dir == root && strcmp(short_name, "..") == 0) - { - statbuf = root_statbuf; - lstatbuf = root_statbuf; - } - - if(S_ISLNK(lstatbuf.st_mode)) - { - - /* Here we decide how to handle the symbolic links. Here - we handle the general case - if we are not following - links or there is an error, then we must change - something. If RR is in use, it is easy, we let RR - describe the file. If not, then we punt the file. */ - - if((status || !follow_links)) - { - if(use_RockRidge) - { - status = 0; - statbuf.st_size = 0; - STAT_INODE(statbuf) = UNCACHED_INODE; - statbuf.st_dev = (dev_t) UNCACHED_DEVICE; - statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG; - } else { - if(follow_links) - { - fprintf (stderr, - _("Unable to stat file %s - ignoring and continuing.\n"), - whole_path); - } - else - { - fprintf (stderr, - _("Symlink %s ignored - continuing.\n"), - whole_path); - return 0; /* Non Rock Ridge discs - ignore all symlinks */ - } - } - } - - /* Here we handle a different kind of case. Here we have - a symlink, but we want to follow symlinks. If we run - across a directory loop, then we need to pretend that - we are not following symlinks for this file. If this - is the first time we have seen this, then make this - seem as if there was no symlink there in the first - place */ - - if( follow_links - && S_ISDIR(statbuf.st_mode) ) - { - if( strcmp(short_name, ".") - && strcmp(short_name, "..") ) - { - if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) - { - if(!use_RockRidge) - { - fprintf (stderr, _("Already cached directory seen (%s)\n"), - whole_path); - return 0; - } - statbuf.st_size = 0; - STAT_INODE(statbuf) = UNCACHED_INODE; - statbuf.st_dev = (dev_t) UNCACHED_DEVICE; - statbuf.st_mode = (statbuf.st_mode & ~S_IFMT) | S_IFREG; - } - else - { - lstatbuf = statbuf; - add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); - } - } - } - - /* - * For non-directories, we just copy the stat information over - * so we correctly include this file. - */ - if( follow_links - && !S_ISDIR(statbuf.st_mode) ) - { - lstatbuf = statbuf; - } - } - - /* - * Add directories to the cache so that we don't waste space even - * if we are supposed to be following symlinks. - */ - if( follow_links - && strcmp(short_name, ".") - && strcmp(short_name, "..") - && S_ISDIR(statbuf.st_mode) ) - { - add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); - } - - if(S_ISREG(lstatbuf.st_mode) && (status = access(whole_path, R_OK))) - { - fprintf (stderr, _("File %s is not readable (%s) - ignoring\n"), - whole_path, strerror (errno)); - return 0; - } - - /* Add this so that we can detect directory loops with hard links. - If we are set up to follow symlinks, then we skip this checking. */ - if( !follow_links - && S_ISDIR(lstatbuf.st_mode) - && strcmp(short_name, ".") - && strcmp(short_name, "..") ) - { - if(find_directory_hash(statbuf.st_dev, STAT_INODE(statbuf))) - error (1, 0, _("Directory loop - fatal goof (%s %lx %lu).\n"), - whole_path, (unsigned long) statbuf.st_dev, - (unsigned long) STAT_INODE(statbuf)); - add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf)); - } - - if (!S_ISCHR(lstatbuf.st_mode) && !S_ISBLK(lstatbuf.st_mode) && - !S_ISFIFO(lstatbuf.st_mode) && !S_ISSOCK(lstatbuf.st_mode) - && !S_ISLNK(lstatbuf.st_mode) && !S_ISREG(lstatbuf.st_mode) && - !S_ISDIR(lstatbuf.st_mode)) { - fprintf (stderr, _("Unknown file type %s - ignoring and continuing.\n"), - whole_path); - return 0; - } - - /* Who knows what trash this is - ignore and continue */ - - if(status) - { - fprintf (stderr, - _("Unable to stat file %s - ignoring and continuing.\n"), - whole_path); - return 0; - } - - /* - * Check to see if we have already seen this directory node. - * If so, then we don't create a new entry for it, but we do want - * to recurse beneath it and add any new files we do find. - */ - if (S_ISDIR(statbuf.st_mode)) - { - int dflag; - - for( s_entry = this_dir->contents; s_entry; s_entry = s_entry->next) - { - if( strcmp(s_entry->name, short_name) == 0 ) - { - break; - } - } - if ( s_entry != NULL - && strcmp(short_name,".") - && strcmp(short_name,"..")) - { - struct directory * child; - - if ( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0) - { - for( s_entry = reloc_dir->contents; s_entry; s_entry = s_entry->next) - { - if( strcmp(s_entry->name, short_name) == 0 ) - { - break; - } - } - child = find_or_create_directory(reloc_dir, whole_path, - s_entry, 1); - } - else - { - child = find_or_create_directory(this_dir, whole_path, - s_entry, 1); - /* If unable to scan directory, mark this as a non-directory */ - } - dflag = scan_directory_tree(child, whole_path, s_entry); - if(!dflag) - { - lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG; - } - return 0; - } - } - - s_entry = (struct directory_entry *) - e_malloc(sizeof (struct directory_entry)); - s_entry->next = this_dir->contents; - memset(s_entry->isorec.extent, 0, 8); - this_dir->contents = s_entry; - deep_flag = 0; - s_entry->table = NULL; - - s_entry->name = strdup(short_name); - s_entry->whole_name = strdup (whole_path); - - s_entry->de_flags = 0; - - /* - * If the current directory is hidden, then hide all it's members - * otherwise check if this entry needs to be hidden as well */ - if (this_dir->dir_flags & INHIBIT_ISO9660_ENTRY) { - s_entry->de_flags |= INHIBIT_ISO9660_ENTRY; - } - else if (strcmp(short_name,".") && strcmp(short_name,"..")) { - if (i_matches(short_name) || i_matches(whole_path)) { - if (verbose > 1) { - fprintf (stderr, _("Hidden from ISO9660 tree: %s\n"), whole_path); - } - s_entry->de_flags |= INHIBIT_ISO9660_ENTRY; - } - } - - if (this_dir != reloc_dir && this_dir->dir_flags & INHIBIT_JOLIET_ENTRY) { - s_entry->de_flags |= INHIBIT_JOLIET_ENTRY; - } - else if (strcmp(short_name,".") && strcmp(short_name,"..")) { - if (j_matches(short_name) || j_matches(whole_path)) { - if (verbose > 1) { - fprintf (stderr, _("Hidden from Joliet tree: %s\n"), whole_path); - } - s_entry->de_flags |= INHIBIT_JOLIET_ENTRY; - } - } - - s_entry->filedir = this_dir; - s_entry->isorec.flags[0] = 0; - s_entry->isorec.ext_attr_length[0] = 0; - iso9660_date(s_entry->isorec.date, statbuf.st_mtime); - s_entry->isorec.file_unit_size[0] = 0; - s_entry->isorec.interleave[0] = 0; - - if( strcmp(short_name, ".") == 0) - { - this_dir->dir_flags |= DIR_HAS_DOT; - } - - if( strcmp(short_name, "..") == 0) - { - this_dir->dir_flags |= DIR_HAS_DOTDOT; - } - - if( this_dir->parent - && this_dir->parent == reloc_dir - && strcmp(short_name, "..") == 0) - { - s_entry->inode = UNCACHED_INODE; - s_entry->dev = (dev_t) UNCACHED_DEVICE; - deep_flag = NEED_PL; - } - else - { - s_entry->inode = STAT_INODE(statbuf); - s_entry->dev = statbuf.st_dev; - } - set_723(s_entry->isorec.volume_sequence_number, volume_sequence_number); - iso9660_file_length(short_name, s_entry, S_ISDIR(statbuf.st_mode)); - s_entry->rr_attr_size = 0; - s_entry->total_rr_attr_size = 0; - s_entry->rr_attributes = NULL; - - /* Directories are assigned sizes later on */ - if (!S_ISDIR(statbuf.st_mode)) - { - if (S_ISCHR(lstatbuf.st_mode) || S_ISBLK(lstatbuf.st_mode) || - S_ISFIFO(lstatbuf.st_mode) || S_ISSOCK(lstatbuf.st_mode) - || S_ISLNK(lstatbuf.st_mode)) - { - s_entry->size = 0; - statbuf.st_size = 0; - } - else - { - s_entry->size = statbuf.st_size; - } - - set_733((char *) s_entry->isorec.size, statbuf.st_size); - } - else - { - s_entry->isorec.flags[0] = 2; - } - - if (strcmp(short_name,".") && strcmp(short_name,"..") && - S_ISDIR(statbuf.st_mode) && this_dir->depth > RR_relocation_depth) - { - struct directory * child; - - if(!reloc_dir) generate_reloc_directory(); - - /* - * Replicate the entry for this directory. The old one will stay where it - * is, and it will be neutered so that it no longer looks like a directory. - * The new one will look like a directory, and it will be put in the reloc_dir. - */ - s_entry1 = (struct directory_entry *) - e_malloc(sizeof (struct directory_entry)); - memcpy(s_entry1, s_entry, sizeof(struct directory_entry)); - s_entry1->table = NULL; - s_entry1->name = strdup(this_dir->contents->name); - s_entry1->whole_name = strdup(this_dir->contents->whole_name); - s_entry1->next = reloc_dir->contents; - reloc_dir->contents = s_entry1; - s_entry1->priority = 32768; - s_entry1->parent_rec = this_dir->contents; - - deep_flag = NEED_RE; - - if(use_RockRidge) - { - generate_rock_ridge_attributes(whole_path, - short_name, s_entry1, - &statbuf, &lstatbuf, deep_flag); - } - - deep_flag = 0; - - /* We need to set this temporarily so that the parent to this - is correctly determined. */ - s_entry1->filedir = reloc_dir; - child = find_or_create_directory(reloc_dir, whole_path, - s_entry1, 0); - scan_directory_tree(child, whole_path, s_entry1); - s_entry1->filedir = this_dir; - - statbuf.st_size = 0; - statbuf.st_mode &= 0777; - set_733((char *) s_entry->isorec.size, 0); - s_entry->size = 0; - s_entry->isorec.flags[0] = 0; - s_entry->inode = UNCACHED_INODE; - s_entry->de_flags |= RELOCATED_DIRECTORY; - deep_flag = NEED_CL; - } - - if(generate_tables - && strcmp(s_entry->name, ".") - && strcmp(s_entry->name, "..")) - { - char buffer[2048]; - int nchar; - switch(lstatbuf.st_mode & S_IFMT) - { - case S_IFDIR: - sprintf(buffer,"D\t%s\n", - s_entry->name); - break; -#ifdef S_IFBLK -/* extra for WIN32 - if it doesn't have the major/minor defined, then - S_IFBLK and S_IFCHR type files are unlikely to exist anyway ... - code similar to that in rock.c */ - -/* for some reason, MAJOR_IN_SYSMACROS isn't defined on a SunOS when - it should be, so see if major() is defined instead */ -/* -#if !(defined(MAJOR_IN_SYSMACROS) || defined(MAJOR_IN_MKDEV)) -*/ -#ifndef major -#define major(dev) (sizeof(dev_t) <= 2 ? ((dev) >> 8) : \ - (sizeof(dev_t) <= 4 ? (((dev) >> 8) >> 8) : \ - (((dev) >> 16) >> 16))) -#define minor(dev) (sizeof(dev_t) <= 2 ? (dev) & 0xff : \ - (sizeof(dev_t) <= 4 ? (dev) & 0xffff : \ - (dev) & 0xffffffff)) -#endif - case S_IFBLK: - sprintf(buffer,"B\t%s\t%lu %lu\n", - s_entry->name, - (unsigned long) major(statbuf.st_rdev), - (unsigned long) minor(statbuf.st_rdev)); - break; -#endif -#ifdef S_IFIFO - case S_IFIFO: - sprintf(buffer,"P\t%s\n", - s_entry->name); - break; -#endif -#ifdef S_IFCHR - case S_IFCHR: - sprintf(buffer,"C\t%s\t%lu %lu\n", - s_entry->name, - (unsigned long) major(statbuf.st_rdev), - (unsigned long) minor(statbuf.st_rdev)); - break; -#endif -#ifdef S_IFLNK - case S_IFLNK: - nchar = readlink(whole_path, - (char *)symlink_buff, - sizeof(symlink_buff)); - symlink_buff[nchar < 0 ? 0 : nchar] = 0; - sprintf(buffer,"L\t%s\t%s\n", - s_entry->name, symlink_buff); - break; -#endif -#ifdef S_IFSOCK - case S_IFSOCK: - sprintf(buffer,"S\t%s\n", - s_entry->name); - break; -#endif - case S_IFREG: - default: - sprintf(buffer,"F\t%s\n", - s_entry->name); - break; - }; - s_entry->table = strdup(buffer); - } - - if(S_ISDIR(statbuf.st_mode)) - { - int dflag; - if (strcmp(short_name,".") && strcmp(short_name,"..")) - { - struct directory * child; - - child = find_or_create_directory(this_dir, whole_path, - s_entry, 1); - dflag = scan_directory_tree(child, whole_path, s_entry); - - if(!dflag) - { - lstatbuf.st_mode = (lstatbuf.st_mode & ~S_IFMT) | S_IFREG; - if( child->contents == NULL ) - { - delete_directory(this_dir, child); - } - } - } - /* If unable to scan directory, mark this as a non-directory */ - } - - if(use_RockRidge && this_dir == root && strcmp(s_entry->name, ".") == 0) - { - deep_flag |= NEED_CE | NEED_SP; /* For extension record */ - } - - /* Now figure out how much room this file will take in the - directory */ - - if(use_RockRidge) - { - generate_rock_ridge_attributes(whole_path, - short_name, s_entry, - &statbuf, &lstatbuf, deep_flag); - - } - - return 1; -} - - -void FDECL2(generate_iso9660_directories, struct directory *, node, FILE*, outfile){ - struct directory * dpnt; - - dpnt = node; - - while (dpnt){ - if( dpnt->extent > session_start ) - { - generate_one_directory(dpnt, outfile); - } - if(dpnt->subdir) generate_iso9660_directories(dpnt->subdir, outfile); - dpnt = dpnt->next; - } -} - -/* - * Function: find_or_create_directory - * - * Purpose: Locate a directory entry in the tree, create if needed. - * - * Arguments: - */ -struct directory * FDECL4(find_or_create_directory, struct directory *, parent, - const char *, path, - struct directory_entry *, de, int, flag) -{ - struct directory * dpnt; - struct directory_entry * orig_de; - struct directory * next_brother; - const char * cpnt; - const char * pnt; - - orig_de = de; - - pnt = strrchr(path, PATH_SEPARATOR); - if( pnt == NULL ) - { - pnt = path; - } - else - { - pnt++; - } - - if( parent != NULL ) - { - dpnt = parent->subdir; - - while (dpnt) - { - /* - * Weird hack time - if there are two directories by the - * same name in the reloc_dir, they are not treated as the - * same thing unless the entire path matches completely. - */ - if( flag && strcmp(dpnt->de_name, pnt) == 0 ) - { - return dpnt; - } - dpnt = dpnt->next; - } - } - - /* - * We don't know if we have a valid directory entry for this one - * yet. If not, we need to create one. - */ - if( de == NULL ) - { - de = (struct directory_entry *) - e_malloc(sizeof (struct directory_entry)); - memset(de, 0, sizeof(struct directory_entry)); - de->next = parent->contents; - parent->contents = de; - de->name = strdup(pnt); - de->filedir = parent; - de->isorec.flags[0] = 2; - de->priority = 32768; - de->inode = UNCACHED_INODE; - de->dev = (dev_t) UNCACHED_DEVICE; - set_723(de->isorec.volume_sequence_number, volume_sequence_number); - iso9660_file_length (pnt, de, 1); - - init_fstatbuf(); - /* - * It doesn't exist for real, so we cannot add any Rock Ridge. - */ - if(use_RockRidge) - { - fstatbuf.st_mode = 0555 | S_IFDIR; - fstatbuf.st_nlink = 2; - generate_rock_ridge_attributes("", - (char *) pnt, de, - &fstatbuf, - &fstatbuf, 0); - } - iso9660_date(de->isorec.date, fstatbuf.st_mtime); - - } - - /* - * If we don't have a directory for this one yet, then allocate it - * now, and patch it into the tree in the appropriate place. - */ - dpnt = (struct directory *) e_malloc(sizeof(struct directory)); - memset(dpnt, 0, sizeof(struct directory)); - dpnt->next = NULL; - dpnt->subdir = NULL; - dpnt->self = de; - dpnt->contents = NULL; - dpnt->whole_name = strdup(path); - cpnt = strrchr(path, PATH_SEPARATOR); - if(cpnt) - cpnt++; - else - cpnt = path; - dpnt->de_name = strdup(cpnt); - dpnt->size = 0; - dpnt->extent = 0; - dpnt->jextent = 0; - dpnt->jsize = 0; - - if( orig_de == NULL ) - { - struct stat xstatbuf; - int sts; - - /* - * Now add a . and .. entry in the directory itself. - * This is a little tricky - if the real directory - * exists, we need to stat it first. Otherwise, we - * use the fictitious fstatbuf which points to the time - * at which mkisofs was started. - */ - sts = stat_filter(parent->whole_name, &xstatbuf); - if( sts == 0 ) - { - attach_dot_entries(dpnt, &xstatbuf); - } - else - { - attach_dot_entries(dpnt, &fstatbuf); - } - } - - if(!parent || parent == root) - { - if (!root) - { - root = dpnt; /* First time through for root directory only */ - root->depth = 0; - root->parent = root; - } else { - dpnt->depth = 1; - if(!root->subdir) - { - root->subdir = dpnt; - } - else - { - next_brother = root->subdir; - while(next_brother->next) next_brother = next_brother->next; - next_brother->next = dpnt; - } - dpnt->parent = parent; - } - } - else - { - /* Come through here for normal traversal of tree */ -#ifdef DEBUG - fprintf(stderr,"%s(%d) ", path, dpnt->depth); -#endif - if(parent->depth > RR_relocation_depth) - error (1, 0, _("Directories too deep %s\n"), path); - - dpnt->parent = parent; - dpnt->depth = parent->depth + 1; - - if(!parent->subdir) - { - parent->subdir = dpnt; - } - else - { - next_brother = parent->subdir; - while(next_brother->next) next_brother = next_brother->next; - next_brother->next = dpnt; - } - } - - return dpnt; -} - -/* - * Function: delete_directory - * - * Purpose: Locate a directory entry in the tree, create if needed. - * - * Arguments: - */ -static void FDECL2(delete_directory, struct directory *, parent, struct directory *, child) -{ - struct directory * tdir; - - if( child->contents != NULL ) - error (1, 0, _("Unable to delete non-empty directory\n")); - - free(child->whole_name); - child->whole_name = NULL; - - free(child->de_name); - child->de_name = NULL; - - if( parent->subdir == child ) - { - parent->subdir = child->next; - } - else - { - for( tdir = parent->subdir; tdir->next != NULL; tdir = tdir->next ) - { - if( tdir->next == child ) - { - tdir->next = child->next; - break; - } - } - if( tdir == NULL ) - error (1, 0, _("Unable to locate child directory in parent list\n")); - } - free(child); - return; -} - -int FDECL1(sort_tree, struct directory *, node){ - struct directory * dpnt; - int ret = 0; - - dpnt = node; - - while (dpnt){ - ret = sort_n_finish(dpnt); - if( ret ) - { - break; - } - - if(dpnt->subdir) sort_tree(dpnt->subdir); - dpnt = dpnt->next; - } - return ret; -} - -void FDECL1(dump_tree, struct directory *, node){ - struct directory * dpnt; - - dpnt = node; - - while (dpnt){ - fprintf(stderr,"%4d %5d %s\n",dpnt->extent, dpnt->size, dpnt->de_name); - if(dpnt->subdir) dump_tree(dpnt->subdir); - dpnt = dpnt->next; - } -} - -void FDECL1(update_nlink_field, struct directory *, node) -{ - struct directory * dpnt; - struct directory * xpnt; - struct directory_entry * s_entry; - int i; - - dpnt = node; - - while (dpnt) - { - if (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) { - dpnt = dpnt->next; - continue; - } - - /* - * First, count up the number of subdirectories this guy has. - */ - for(i=0, xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next) - if ((xpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0) - i++; - /* - * Next check to see if we have any relocated directories - * in this directory. The nlink field will include these - * as real directories when they are properly relocated. - * - * In the non-rockridge disk, the relocated entries appear - * as zero length files. - */ - for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) - { - if( (s_entry->de_flags & RELOCATED_DIRECTORY) != 0 && - (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) == 0) - { - i++; - } - } - /* - * Now update the field in the Rock Ridge entry. - */ - update_nlink(dpnt->self, i + 2); - - /* - * Update the '.' entry for this directory. - */ - update_nlink(dpnt->contents, i + 2); - - /* - * Update all of the '..' entries that point to this guy. - */ - for(xpnt = dpnt->subdir; xpnt; xpnt = xpnt->next) - update_nlink(xpnt->contents->next, i + 2); - - if(dpnt->subdir) update_nlink_field(dpnt->subdir); - dpnt = dpnt->next; - } -} - -/* - * something quick and dirty to locate a file given a path - * recursively walks down path in filename until it finds the - * directory entry for the desired file - */ -struct directory_entry * FDECL2(search_tree_file, struct directory *, - node,char *, filename) -{ - struct directory_entry * depnt; - struct directory * dpnt; - char * p1; - char * rest; - char * subdir; - - /* - * strip off next directory name from filename - */ - subdir = strdup(filename); - - if( (p1=strchr(subdir, '/')) == subdir ) - { - fprintf (stderr, _("call to search_tree_file with an absolute path, stripping\n")); - fprintf (stderr, _("initial path separator. Hope this was intended...\n")); - memmove(subdir, subdir+1, strlen(subdir)-1); - p1 = strchr(subdir, '/'); - } - - /* - * do we need to find a subdirectory - */ - if (p1) - { - *p1 = '\0'; - -#ifdef DEBUG_TORITO - fprintf(stderr,"Looking for subdir called %s\n",p1); -#endif - - rest = p1+1; - -#ifdef DEBUG_TORITO - fprintf(stderr,"Remainder of path name is now %s\n", rest); -#endif - - dpnt = node->subdir; - while( dpnt ) - { -#ifdef DEBUG_TORITO - fprintf(stderr,"%4d %5d %s\n", dpnt->extent, dpnt->size, - dpnt->de_name); -#endif - if (!strcmp(subdir, dpnt->de_name)) - { -#ifdef DEBUG_TORITO - fprintf(stderr,"Calling next level with filename = %s", rest); -#endif - return(search_tree_file( dpnt, rest )); - } - dpnt = dpnt->next; - } - - /* if we got here means we couldnt find the subdir */ - return (NULL); - } - else - { - /* - * look for a normal file now - */ - depnt = node->contents; - while (depnt) - { -#ifdef DEBUG_TORITO - fprintf(stderr,"%4d %5d %s\n",depnt->isorec.extent, - depnt->size, depnt->name); -#endif - if (!strcmp(filename, depnt->name)) - { -#ifdef DEBUG_TORITO - fprintf(stderr,"Found our file %s", filename); -#endif - return(depnt); - } - depnt = depnt->next; - } - /* - * if we got here means we couldnt find the subdir - */ - return (NULL); - } - fprintf (stderr, "We cant get here in search_tree_file :-/ \n"); -} - -void init_fstatbuf() -{ - time_t current_time; - - if(fstatbuf.st_ctime == 0) - { - time (¤t_time); - if( rationalize ) - { - fstatbuf.st_uid = 0; - fstatbuf.st_gid = 0; - } - else - { - fstatbuf.st_uid = getuid(); - fstatbuf.st_gid = getgid(); - } - fstatbuf.st_ctime = current_time; - fstatbuf.st_mtime = current_time; - fstatbuf.st_atime = current_time; - } -} diff --git a/util/mkisofs/write.c b/util/mkisofs/write.c deleted file mode 100644 index 73c220827..000000000 --- a/util/mkisofs/write.c +++ /dev/null @@ -1,1444 +0,0 @@ -/* - * Program write.c - dump memory structures to file for iso9660 filesystem. - - Written by Eric Youngdale (1993). - - Copyright 1993 Yggdrasil Computing, Incorporated - - Copyright (C) 2009 Free Software Foundation, Inc. - - This program 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, or (at your option) - any later version. - - This program 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 this program; if not, see . - */ - -#include -#include -#include "config.h" -#include "mkisofs.h" -#include "iso9660.h" -#include -#include - -#include -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef __SVR4 -extern char * strdup(const char *); -#endif - -#ifdef VMS -extern char * strdup(const char *); -#endif - - -/* Max number of sectors we will write at one time */ -#define NSECT 16 - -/* Counters for statistics */ - -static int table_size = 0; -static int total_dir_size = 0; -static int rockridge_size = 0; -static struct directory ** pathlist; -static int next_path_index = 1; -static int sort_goof; - -struct output_fragment * out_tail; -struct output_fragment * out_list; - -struct iso_primary_descriptor vol_desc; - -static int root_gen __PR((void)); -static int generate_path_tables __PR((void)); -static int file_gen __PR((void)); -static int dirtree_dump __PR((void)); - -/* Routines to actually write the disc. We write sequentially so that - we could write a tape, or write the disc directly */ - - -#define FILL_SPACE(X) memset(vol_desc.X, ' ', sizeof(vol_desc.X)) - -void FDECL2(set_721, char *, pnt, unsigned int, i) -{ - pnt[0] = i & 0xff; - pnt[1] = (i >> 8) & 0xff; -} - -void FDECL2(set_722, char *, pnt, unsigned int, i) -{ - pnt[0] = (i >> 8) & 0xff; - pnt[1] = i & 0xff; -} - -void FDECL2(set_723, char *, pnt, unsigned int, i) -{ - pnt[3] = pnt[0] = i & 0xff; - pnt[2] = pnt[1] = (i >> 8) & 0xff; -} - -void FDECL2(set_731, char *, pnt, unsigned int, i) -{ - pnt[0] = i & 0xff; - pnt[1] = (i >> 8) & 0xff; - pnt[2] = (i >> 16) & 0xff; - pnt[3] = (i >> 24) & 0xff; -} - -void FDECL2(set_732, char *, pnt, unsigned int, i) -{ - pnt[3] = i & 0xff; - pnt[2] = (i >> 8) & 0xff; - pnt[1] = (i >> 16) & 0xff; - pnt[0] = (i >> 24) & 0xff; -} - -int FDECL1(get_731, char *, p) -{ - return ((p[0] & 0xff) - | ((p[1] & 0xff) << 8) - | ((p[2] & 0xff) << 16) - | ((p[3] & 0xff) << 24)); -} - -int FDECL1(get_733, char *, p) -{ - return ((p[0] & 0xff) - | ((p[1] & 0xff) << 8) - | ((p[2] & 0xff) << 16) - | ((p[3] & 0xff) << 24)); -} - -void FDECL2(set_733, char *, pnt, unsigned int, i) -{ - pnt[7] = pnt[0] = i & 0xff; - pnt[6] = pnt[1] = (i >> 8) & 0xff; - pnt[5] = pnt[2] = (i >> 16) & 0xff; - pnt[4] = pnt[3] = (i >> 24) & 0xff; -} - -void FDECL4(xfwrite, void *, buffer, uint64_t, count, uint64_t, size, FILE *, file) -{ - /* - * This is a hack that could be made better. XXXIs this the only place? - * It is definitely needed on Operating Systems that do not - * allow to write files that are > 2GB. - * If the system is fast enough to be able to feed 1400 KB/s - * writing speed of a DVD-R drive, use stdout. - * If the system cannot do this reliable, you need to use this - * hacky option. - */ - static int idx = 0; - if (split_output != 0 && - (idx == 0 || ftell(file) >= (1024 * 1024 * 1024) )) { - char nbuf[512]; - extern char *outfile; - - if (idx == 0) - unlink(outfile); - sprintf(nbuf, "%s_%02d", outfile, idx++); - file = freopen(nbuf, "wb", file); - if (file == NULL) - error (1, errno, _("Cannot open '%s'"), nbuf); - - } - while(count) - { - size_t got = fwrite (buffer, size, count, file); - - if (got != count) - error (1, errno, _("cannot fwrite %llu*%llu\n"), size, count); - count-=got,*(char**)&buffer+=size*got; - } -} - -struct deferred_write -{ - struct deferred_write * next; - char * table; - uint64_t extent; - uint64_t size; - char * name; -}; - -static struct deferred_write * dw_head = NULL, * dw_tail = NULL; - -uint64_t last_extent_written = 0; -static unsigned int path_table_index; -static time_t begun; - -/* We recursively walk through all of the directories and assign extent - numbers to them. We have already assigned extent numbers to everything that - goes in front of them */ - -static int FDECL1(assign_directory_addresses, struct directory *, node) -{ - int dir_size; - struct directory * dpnt; - - dpnt = node; - - while (dpnt) - { - /* skip if it's hidden */ - if(dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) { - dpnt = dpnt->next; - continue; - } - - /* - * If we already have an extent for this (i.e. it came from - * a multisession disc), then don't reassign a new extent. - */ - dpnt->path_index = next_path_index++; - if( dpnt->extent == 0 ) - { - dpnt->extent = last_extent; - dir_size = (dpnt->size + (SECTOR_SIZE - 1)) >> 11; - - last_extent += dir_size; - - /* - * Leave room for the CE entries for this directory. Keep them - * close to the reference directory so that access will be - * quick. - */ - if(dpnt->ce_bytes) - { - last_extent += ROUND_UP(dpnt->ce_bytes) >> 11; - } - } - - if(dpnt->subdir) - { - assign_directory_addresses(dpnt->subdir); - } - - dpnt = dpnt->next; - } - return 0; -} - -static void FDECL3(write_one_file, char *, filename, - uint64_t, size, FILE *, outfile) -{ - char buffer[SECTOR_SIZE * NSECT]; - FILE * infile; - int64_t remain; - size_t use; - - - if ((infile = fopen(filename, "rb")) == NULL) - error (1, errno, _("cannot open %s\n"), filename); - remain = size; - - while(remain > 0) - { - use = (remain > SECTOR_SIZE * NSECT - 1 ? NSECT*SECTOR_SIZE : remain); - use = ROUND_UP(use); /* Round up to nearest sector boundary */ - memset(buffer, 0, use); - if (fread(buffer, 1, use, infile) == 0) - error (1, errno, _("cannot read %llu bytes from %s"), use, filename); - xfwrite(buffer, 1, use, outfile); - last_extent_written += use/SECTOR_SIZE; -#if 0 - if((last_extent_written % 1000) < use/SECTOR_SIZE) - { - fprintf(stderr,"%d..", last_extent_written); - } -#else - if((last_extent_written % 5000) < use/SECTOR_SIZE) - { - time_t now; - time_t the_end; - double frac; - - time(&now); - frac = last_extent_written / (double)last_extent; - the_end = begun + (now - begun) / frac; - fprintf (stderr, _("%6.2f%% done, estimate finish %s"), - frac * 100., ctime(&the_end)); - } -#endif - remain -= use; - } - fclose(infile); -} /* write_one_file(... */ - -static void FDECL1(write_files, FILE *, outfile) -{ - struct deferred_write * dwpnt, *dwnext; - dwpnt = dw_head; - while(dwpnt) - { - if(dwpnt->table) - { - write_one_file (dwpnt->table, dwpnt->size, outfile); - table_size += dwpnt->size; - free (dwpnt->table); - } - else - { - -#ifdef VMS - vms_write_one_file(dwpnt->name, dwpnt->size, outfile); -#else - write_one_file(dwpnt->name, dwpnt->size, outfile); -#endif - free(dwpnt->name); - } - - dwnext = dwpnt; - dwpnt = dwpnt->next; - free(dwnext); - } -} /* write_files(... */ - -#if 0 -static void dump_filelist() -{ - struct deferred_write * dwpnt; - dwpnt = dw_head; - while(dwpnt) - { - fprintf(stderr, "File %s\n",dwpnt->name); - dwpnt = dwpnt->next; - } - fprintf(stderr,"\n"); -} -#endif - -static int FDECL2(compare_dirs, const void *, rr, const void *, ll) -{ - char * rpnt, *lpnt; - struct directory_entry ** r, **l; - - r = (struct directory_entry **) rr; - l = (struct directory_entry **) ll; - rpnt = (*r)->isorec.name; - lpnt = (*l)->isorec.name; - - /* - * If the entries are the same, this is an error. - */ - if( strcmp(rpnt, lpnt) == 0 ) - { - sort_goof++; - } - - /* - * Put the '.' and '..' entries on the head of the sorted list. - * For normal ASCII, this always happens to be the case, but out of - * band characters cause this not to be the case sometimes. - * - * FIXME(eric) - these tests seem redundant, in taht the name is - * never assigned these values. It will instead be \000 or \001, - * and thus should always be sorted correctly. I need to figure - * out why I thought I needed this in the first place. - */ -#if 0 - if( strcmp(rpnt, ".") == 0 ) return -1; - if( strcmp(lpnt, ".") == 0 ) return 1; - - if( strcmp(rpnt, "..") == 0 ) return -1; - if( strcmp(lpnt, "..") == 0 ) return 1; -#else - /* - * The code above is wrong (as explained in Eric's comment), leading to incorrect - * sort order iff the -L option ("allow leading dots") is in effect and a directory - * contains entries that start with a dot. - * - * (TF, Tue Dec 29 13:49:24 CET 1998) - */ - if((*r)->isorec.name_len[0] == 1 && *rpnt == 0) return -1; /* '.' */ - if((*l)->isorec.name_len[0] == 1 && *lpnt == 0) return 1; - - if((*r)->isorec.name_len[0] == 1 && *rpnt == 1) return -1; /* '..' */ - if((*l)->isorec.name_len[0] == 1 && *lpnt == 1) return 1; -#endif - - while(*rpnt && *lpnt) - { - if(*rpnt == ';' && *lpnt != ';') return -1; - if(*rpnt != ';' && *lpnt == ';') return 1; - - if(*rpnt == ';' && *lpnt == ';') return 0; - - if(*rpnt == '.' && *lpnt != '.') return -1; - if(*rpnt != '.' && *lpnt == '.') return 1; - - if((unsigned char)*rpnt < (unsigned char)*lpnt) return -1; - if((unsigned char)*rpnt > (unsigned char)*lpnt) return 1; - rpnt++; lpnt++; - } - if(*rpnt) return 1; - if(*lpnt) return -1; - return 0; -} - -/* - * Function: sort_directory - * - * Purpose: Sort the directory in the appropriate ISO9660 - * order. - * - * Notes: Returns 0 if OK, returns > 0 if an error occurred. - */ -int FDECL1(sort_directory, struct directory_entry **, sort_dir) -{ - int dcount = 0; - int xcount = 0; - int j; - int i, len; - struct directory_entry * s_entry; - struct directory_entry ** sortlist; - - /* need to keep a count of how many entries are hidden */ - s_entry = *sort_dir; - while(s_entry) - { - if (s_entry->de_flags & INHIBIT_ISO9660_ENTRY) - xcount++; - dcount++; - s_entry = s_entry->next; - } - - if( dcount == 0 ) - { - return 0; - } - - /* - * OK, now we know how many there are. Build a vector for sorting. - */ - sortlist = (struct directory_entry **) - e_malloc(sizeof(struct directory_entry *) * dcount); - - j = dcount - 1; - dcount = 0; - s_entry = *sort_dir; - while(s_entry) - { - if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) - { - /* put any hidden entries at the end of the vector */ - sortlist[j--] = s_entry; - } - else - { - sortlist[dcount] = s_entry; - dcount++; - } - len = s_entry->isorec.name_len[0]; - s_entry->isorec.name[len] = 0; - s_entry = s_entry->next; - } - - /* - * Each directory is required to contain at least . and .. - */ - if( dcount < 2 ) - { - sort_goof = 1; - - } - else - { - /* only sort the non-hidden entries */ - sort_goof = 0; -#ifdef __STDC__ - qsort(sortlist, dcount, sizeof(struct directory_entry *), - (int (*)(const void *, const void *))compare_dirs); -#else - qsort(sortlist, dcount, sizeof(struct directory_entry *), - compare_dirs); -#endif - - /* - * Now reassemble the linked list in the proper sorted order - * We still need the hidden entries, as they may be used in the - * Joliet tree. - */ - for(i=0; inext = sortlist[i+1]; - } - - sortlist[dcount+xcount-1]->next = NULL; - *sort_dir = sortlist[0]; - } - - free(sortlist); - return sort_goof; -} - -static int root_gen() -{ - init_fstatbuf(); - - root_record.length[0] = 1 + sizeof(struct iso_directory_record) - - sizeof(root_record.name); - root_record.ext_attr_length[0] = 0; - set_733((char *) root_record.extent, root->extent); - set_733((char *) root_record.size, ROUND_UP(root->size)); - iso9660_date(root_record.date, root_statbuf.st_mtime); - root_record.flags[0] = 2; - root_record.file_unit_size[0] = 0; - root_record.interleave[0] = 0; - set_723(root_record.volume_sequence_number, volume_sequence_number); - root_record.name_len[0] = 1; - return 0; -} - -static void FDECL1(assign_file_addresses, struct directory *, dpnt) -{ - struct directory * finddir; - struct directory_entry * s_entry; - struct file_hash *s_hash; - struct deferred_write * dwpnt; - char whole_path[1024]; - - while (dpnt) - { - s_entry = dpnt->contents; - for(s_entry = dpnt->contents; s_entry; s_entry = s_entry->next) - { - /* - * If we already have an extent for this entry, - * then don't assign a new one. It must have come - * from a previous session on the disc. Note that - * we don't end up scheduling the thing for writing - * either. - */ - if( isonum_733((unsigned char *) s_entry->isorec.extent) != 0 ) - { - continue; - } - - /* - * This saves some space if there are symlinks present - */ - s_hash = find_hash(s_entry->dev, s_entry->inode); - if(s_hash) - { - if(verbose > 2) - { - fprintf (stderr, _("Cache hit for %s%s%s\n"), s_entry->filedir->de_name, - SPATH_SEPARATOR, s_entry->name); - } - set_733((char *) s_entry->isorec.extent, s_hash->starting_block); - set_733((char *) s_entry->isorec.size, s_hash->size); - continue; - } - - /* - * If this is for a directory that is not a . or a .. entry, - * then look up the information for the entry. We have already - * assigned extents for directories, so we just need to - * fill in the blanks here. - */ - if (strcmp(s_entry->name,".") && strcmp(s_entry->name,"..") && - s_entry->isorec.flags[0] == 2) - { - finddir = dpnt->subdir; - while(1==1) - { - if(finddir->self == s_entry) break; - finddir = finddir->next; - if (!finddir) - error (1, 0, _("Fatal goof\n")); - } - set_733((char *) s_entry->isorec.extent, finddir->extent); - s_entry->starting_block = finddir->extent; - s_entry->size = ROUND_UP(finddir->size); - total_dir_size += s_entry->size; - add_hash(s_entry); - set_733((char *) s_entry->isorec.size, ROUND_UP(finddir->size)); - continue; - } - - - /* - * If this is . or .., then look up the relevant info from the - * tables. - */ - if(strcmp(s_entry->name,".") == 0) - { - set_733((char *) s_entry->isorec.extent, dpnt->extent); - - /* - * Set these so that the hash table has the - * correct information - */ - s_entry->starting_block = dpnt->extent; - s_entry->size = ROUND_UP(dpnt->size); - - add_hash(s_entry); - s_entry->starting_block = dpnt->extent; - set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->size)); - continue; - } - - if(strcmp(s_entry->name,"..") == 0) - { - if(dpnt == root) - { - total_dir_size += root->size; - } - set_733((char *) s_entry->isorec.extent, dpnt->parent->extent); - - /* - * Set these so that the hash table has the - * correct information - */ - s_entry->starting_block = dpnt->parent->extent; - s_entry->size = ROUND_UP(dpnt->parent->size); - - add_hash(s_entry); - s_entry->starting_block = dpnt->parent->extent; - set_733((char *) s_entry->isorec.size, ROUND_UP(dpnt->parent->size)); - continue; - } - - /* - * Some ordinary non-directory file. Just schedule the - * file to be written. This is all quite - * straightforward, just make a list and assign extents - * as we go. Once we get through writing all of the - * directories, we should be ready write out these - * files - */ - if(s_entry->size) - { - dwpnt = (struct deferred_write *) - e_malloc(sizeof(struct deferred_write)); - if(dw_tail) - { - dw_tail->next = dwpnt; - dw_tail = dwpnt; - } - else - { - dw_head = dwpnt; - dw_tail = dwpnt; - } - if(s_entry->inode == TABLE_INODE) - { - dwpnt->table = s_entry->table; - dwpnt->name = NULL; - sprintf(whole_path,"%s%sTRANS.TBL", - s_entry->filedir->whole_name, SPATH_SEPARATOR); - } - else - { - dwpnt->table = NULL; - strcpy(whole_path, s_entry->whole_name); - dwpnt->name = strdup(whole_path); - } - dwpnt->next = NULL; - dwpnt->size = s_entry->size; - dwpnt->extent = last_extent; - set_733((char *) s_entry->isorec.extent, last_extent); - s_entry->starting_block = last_extent; - add_hash(s_entry); - last_extent += ROUND_UP(s_entry->size) >> 11; - if(verbose > 2) - { - fprintf(stderr,"%llu %llu %s\n", s_entry->starting_block, - last_extent-1, whole_path); - } -#ifdef DBG_ISO - if((ROUND_UP(s_entry->size) >> 11) > 500) - { - fprintf (stderr, "Warning: large file %s\n", whole_path); - fprintf (stderr, "Starting block is %d\n", s_entry->starting_block); - fprintf (stderr, "Reported file size is %d extents\n", s_entry->size); - - } -#endif -#ifdef NOT_NEEDED /* Never use this code if you like to create a DVD */ - - if(last_extent > (800000000 >> 11)) - { - /* - * More than 800Mb? Punt - */ - fprintf(stderr,"Extent overflow processing file %s\n", whole_path); - fprintf(stderr,"Starting block is %d\n", s_entry->starting_block); - fprintf(stderr,"Reported file size is %d extents\n", s_entry->size); - exit(1); - } -#endif - continue; - } - - /* - * This is for zero-length files. If we leave the extent 0, - * then we get screwed, because many readers simply drop files - * that have an extent of zero. Thus we leave the size 0, - * and just assign the extent number. - */ - set_733((char *) s_entry->isorec.extent, last_extent); - } - if(dpnt->subdir) - { - assign_file_addresses(dpnt->subdir); - } - dpnt = dpnt->next; - } -} /* assign_file_addresses(... */ - -static void FDECL1(free_one_directory, struct directory *, dpnt) -{ - struct directory_entry * s_entry; - struct directory_entry * s_entry_d; - - s_entry = dpnt->contents; - while(s_entry) - { - s_entry_d = s_entry; - s_entry = s_entry->next; - - if( s_entry_d->name != NULL ) - { - free (s_entry_d->name); - } - if( s_entry_d->whole_name != NULL ) - { - free (s_entry_d->whole_name); - } - free (s_entry_d); - } - dpnt->contents = NULL; -} /* free_one_directory(... */ - -static void FDECL1(free_directories, struct directory *, dpnt) -{ - while (dpnt) - { - free_one_directory(dpnt); - if(dpnt->subdir) free_directories(dpnt->subdir); - dpnt = dpnt->next; - } -} - -void FDECL2(generate_one_directory, struct directory *, dpnt, FILE *, outfile) -{ - unsigned int ce_address = 0; - char * ce_buffer; - unsigned int ce_index = 0; - unsigned int ce_size; - unsigned int dir_index; - char * directory_buffer; - int new_reclen; - struct directory_entry * s_entry; - struct directory_entry * s_entry_d; - unsigned int total_size; - - total_size = (dpnt->size + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1); - directory_buffer = (char *) e_malloc(total_size); - memset(directory_buffer, 0, total_size); - dir_index = 0; - - ce_size = (dpnt->ce_bytes + (SECTOR_SIZE - 1)) & ~(SECTOR_SIZE - 1); - ce_buffer = NULL; - - if(ce_size) - { - ce_buffer = (char *) e_malloc(ce_size); - memset(ce_buffer, 0, ce_size); - - ce_index = 0; - - /* - * Absolute byte address of CE entries for this directory - */ - ce_address = last_extent_written + (total_size >> 11); - ce_address = ce_address << 11; - } - - s_entry = dpnt->contents; - while(s_entry) - { - /* skip if it's hidden */ - if(s_entry->de_flags & INHIBIT_ISO9660_ENTRY) { - s_entry = s_entry->next; - continue; - } - - /* - * We do not allow directory entries to cross sector boundaries. - * Simply pad, and then start the next entry at the next sector - */ - new_reclen = s_entry->isorec.length[0]; - if( (dir_index & (SECTOR_SIZE - 1)) + new_reclen >= SECTOR_SIZE ) - { - dir_index = (dir_index + (SECTOR_SIZE - 1)) & - ~(SECTOR_SIZE - 1); - } - - memcpy(directory_buffer + dir_index, &s_entry->isorec, - sizeof(struct iso_directory_record) - - sizeof(s_entry->isorec.name) + s_entry->isorec.name_len[0]); - dir_index += sizeof(struct iso_directory_record) - - sizeof (s_entry->isorec.name)+ s_entry->isorec.name_len[0]; - - /* - * Add the Rock Ridge attributes, if present - */ - if(s_entry->rr_attr_size) - { - if(dir_index & 1) - { - directory_buffer[dir_index++] = 0; - } - - /* - * If the RR attributes were too long, then write the - * CE records, as required. - */ - if(s_entry->rr_attr_size != s_entry->total_rr_attr_size) - { - unsigned char * pnt; - int len, nbytes; - - /* - * Go through the entire record and fix up the CE entries - * so that the extent and offset are correct - */ - - pnt = s_entry->rr_attributes; - len = s_entry->total_rr_attr_size; - while(len > 3) - { -#ifdef DEBUG - if (!ce_size) - { - fprintf(stderr,"Warning: ce_index(%d) && ce_address(%d) not initialized\n", - ce_index, ce_address); - } -#endif - - if(pnt[0] == 'C' && pnt[1] == 'E') - { - nbytes = get_733( (char *) pnt+20); - - if((ce_index & (SECTOR_SIZE - 1)) + nbytes >= - SECTOR_SIZE) - { - ce_index = ROUND_UP(ce_index); - } - - set_733( (char *) pnt+4, - (ce_address + ce_index) >> 11); - set_733( (char *) pnt+12, - (ce_address + ce_index) & (SECTOR_SIZE - 1)); - - - /* - * Now store the block in the ce buffer - */ - memcpy(ce_buffer + ce_index, - pnt + pnt[2], nbytes); - ce_index += nbytes; - if(ce_index & 1) - { - ce_index++; - } - } - len -= pnt[2]; - pnt += pnt[2]; - } - - } - - rockridge_size += s_entry->total_rr_attr_size; - memcpy(directory_buffer + dir_index, s_entry->rr_attributes, - s_entry->rr_attr_size); - dir_index += s_entry->rr_attr_size; - } - if(dir_index & 1) - { - directory_buffer[dir_index++] = 0; - } - - s_entry_d = s_entry; - s_entry = s_entry->next; - - /* - * Joliet doesn't use the Rock Ridge attributes, so we free it here. - */ - if (s_entry_d->rr_attributes) - { - free(s_entry_d->rr_attributes); - s_entry_d->rr_attributes = NULL; - } - } - - if(dpnt->size != dir_index) - { - fprintf (stderr, _("Unexpected directory length %d %d %s\n"), dpnt->size, - dir_index, dpnt->de_name); - } - - xfwrite(directory_buffer, 1, total_size, outfile); - last_extent_written += total_size >> 11; - free(directory_buffer); - - if(ce_size) - { - if(ce_index != dpnt->ce_bytes) - { - fprintf (stderr, _("Continuation entry record length mismatch (%d %d).\n"), - ce_index, dpnt->ce_bytes); - } - xfwrite(ce_buffer, 1, ce_size, outfile); - last_extent_written += ce_size >> 11; - free(ce_buffer); - } - -} /* generate_one_directory(... */ - -static -void FDECL1(build_pathlist, struct directory *, node) -{ - struct directory * dpnt; - - dpnt = node; - - while (dpnt) - { - /* skip if it's hidden */ - if( (dpnt->dir_flags & INHIBIT_ISO9660_ENTRY) == 0 ) - pathlist[dpnt->path_index] = dpnt; - - if(dpnt->subdir) build_pathlist(dpnt->subdir); - dpnt = dpnt->next; - } -} /* build_pathlist(... */ - -static int FDECL2(compare_paths, void const *, r, void const *, l) -{ - struct directory const *ll = *(struct directory * const *)l; - struct directory const *rr = *(struct directory * const *)r; - - if (rr->parent->path_index < ll->parent->path_index) - { - return -1; - } - - if (rr->parent->path_index > ll->parent->path_index) - { - return 1; - } - - return strcmp(rr->self->isorec.name, ll->self->isorec.name); - -} /* compare_paths(... */ - -static int generate_path_tables() -{ - struct directory_entry * de; - struct directory * dpnt; - int fix; - int i; - int j; - int namelen; - char * npnt; - char * npnt1; - int tablesize; - - /* - * First allocate memory for the tables and initialize the memory - */ - tablesize = path_blocks << 11; - path_table_m = (char *) e_malloc(tablesize); - path_table_l = (char *) e_malloc(tablesize); - memset(path_table_l, 0, tablesize); - memset(path_table_m, 0, tablesize); - - /* - * Now start filling in the path tables. Start with root directory - */ - if( next_path_index > 0xffff ) - { - error (1, 0, _("Unable to generate sane path tables - too many directories (%d)\n"), - next_path_index); - } - - path_table_index = 0; - pathlist = (struct directory **) e_malloc(sizeof(struct directory *) - * next_path_index); - memset(pathlist, 0, sizeof(struct directory *) * next_path_index); - build_pathlist(root); - - do - { - fix = 0; -#ifdef __STDC__ - qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *), - (int (*)(const void *, const void *))compare_paths); -#else - qsort(&pathlist[1], next_path_index-1, sizeof(struct directory *), - compare_paths); -#endif - - for(j=1; jpath_index != j) - { - pathlist[j]->path_index = j; - fix++; - } - } - } while(fix); - - for(j=1; jde_name; - - /* - * So the root comes out OK - */ - if( (*npnt == 0) || (dpnt == root) ) - { - npnt = "."; - } - npnt1 = strrchr(npnt, PATH_SEPARATOR); - if(npnt1) - { - npnt = npnt1 + 1; - } - - de = dpnt->self; - if(!de) - { - error (1, 0, _("Fatal goof\n")); - } - - - namelen = de->isorec.name_len[0]; - - path_table_l[path_table_index] = namelen; - path_table_m[path_table_index] = namelen; - path_table_index += 2; - - set_731(path_table_l + path_table_index, dpnt->extent); - set_732(path_table_m + path_table_index, dpnt->extent); - path_table_index += 4; - - set_721(path_table_l + path_table_index, - dpnt->parent->path_index); - set_722(path_table_m + path_table_index, - dpnt->parent->path_index); - path_table_index += 2; - - for(i =0; iisorec.name[i]; - path_table_m[path_table_index] = de->isorec.name[i]; - path_table_index++; - } - if(path_table_index & 1) - { - path_table_index++; /* For odd lengths we pad */ - } - } - - free(pathlist); - if(path_table_index != path_table_size) - { - fprintf (stderr, _("Path table lengths do not match %d %d\n"), - path_table_index, - path_table_size); - } - return 0; -} /* generate_path_tables(... */ - -void -FDECL3(memcpy_max, char *, to, char *, from, int, max) -{ - int n = strlen(from); - if (n > max) - { - n = max; - } - memcpy(to, from, n); - -} /* memcpy_max(... */ - -void FDECL1(outputlist_insert, struct output_fragment *, frag) -{ - if( out_tail == NULL ) - { - out_list = out_tail = frag; - } - else - { - out_tail->of_next = frag; - out_tail = frag; - } -} - -static int FDECL1(file_write, FILE *, outfile) -{ - int should_write; - - /* - * OK, all done with that crap. Now write out the directories. - * This is where the fur starts to fly, because we need to keep track of - * each file as we find it and keep track of where we put it. - */ - - should_write = last_extent - session_start; - - if( print_size > 0 ) - { - fprintf (stderr, _("Total extents scheduled to be written = %llu\n"), - last_extent - session_start); - exit (0); - } - if( verbose > 2 ) - { -#ifdef DBG_ISO - fprintf(stderr,"Total directory extents being written = %llu\n", last_extent); -#endif - - fprintf (stderr, _("Total extents scheduled to be written = %llu\n"), - last_extent - session_start); - } - - /* - * Now write all of the files that we need. - */ - write_files(outfile); - - /* - * The rest is just fluff. - */ - if( verbose == 0 ) - { - return 0; - } - - fprintf (stderr, _("Total extents actually written = %llu\n"), - last_extent_written - session_start); - - /* - * Hard links throw us off here - */ - assert (last_extent > session_start); - if(should_write + session_start != last_extent) - { - fprintf (stderr, _("Number of extents written different than what was predicted. Please fix.\n")); - fprintf (stderr, _("Predicted = %d, written = %llu\n"), should_write, last_extent); - } - - fprintf (stderr, _("Total translation table size: %d\n"), table_size); - fprintf (stderr, _("Total rockridge attributes bytes: %d\n"), rockridge_size); - fprintf (stderr, _("Total directory bytes: %d\n"), total_dir_size); - fprintf (stderr, _("Path table size(bytes): %d\n"), path_table_size); - -#ifdef DEBUG - fprintf(stderr, "next extent, last_extent, last_extent_written %d %d %d\n", - next_extent, last_extent, last_extent_written); -#endif - - return 0; - -} /* iso_write(... */ - -char *creation_date = NULL; -char *modification_date = NULL; -char *expiration_date = NULL; -char *effective_date = NULL; - -/* - * Function to write the PVD for the disc. - */ -static int FDECL1(pvd_write, FILE *, outfile) -{ - char iso_time[17]; - int should_write; - struct tm local; - struct tm gmt; - - - time(&begun); - - local = *localtime(&begun); - gmt = *gmtime(&begun); - - /* - * This will break in the year 2000, I supose, but there is no good way - * to get the top two digits of the year. - */ - sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00", 1900 + local.tm_year, - local.tm_mon+1, local.tm_mday, - local.tm_hour, local.tm_min, local.tm_sec); - - local.tm_min -= gmt.tm_min; - local.tm_hour -= gmt.tm_hour; - local.tm_yday -= gmt.tm_yday; - iso_time[16] = (local.tm_min + 60*(local.tm_hour + 24*local.tm_yday)) / 15; - - /* - * Next we write out the primary descriptor for the disc - */ - memset(&vol_desc, 0, sizeof(vol_desc)); - vol_desc.type[0] = ISO_VD_PRIMARY; - memcpy(vol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID)); - vol_desc.version[0] = 1; - - memset(vol_desc.system_id, ' ', sizeof(vol_desc.system_id)); - memcpy_max(vol_desc.system_id, system_id, strlen(system_id)); - - memset(vol_desc.volume_id, ' ', sizeof(vol_desc.volume_id)); - memcpy_max(vol_desc.volume_id, volume_id, strlen(volume_id)); - - should_write = last_extent - session_start; - set_733((char *) vol_desc.volume_space_size, should_write); - set_723(vol_desc.volume_set_size, volume_set_size); - set_723(vol_desc.volume_sequence_number, volume_sequence_number); - set_723(vol_desc.logical_block_size, 2048); - - /* - * The path tables are used by DOS based machines to cache directory - * locations - */ - - set_733((char *) vol_desc.path_table_size, path_table_size); - set_731(vol_desc.type_l_path_table, path_table[0]); - set_731(vol_desc.opt_type_l_path_table, path_table[1]); - set_732(vol_desc.type_m_path_table, path_table[2]); - set_732(vol_desc.opt_type_m_path_table, path_table[3]); - - /* - * Now we copy the actual root directory record - */ - memcpy(vol_desc.root_directory_record, &root_record, - sizeof(struct iso_directory_record) + 1); - - /* - * The rest is just fluff. It looks nice to fill in many of these fields, - * though. - */ - FILL_SPACE(volume_set_id); - if(volset_id) memcpy_max(vol_desc.volume_set_id, volset_id, strlen(volset_id)); - - FILL_SPACE(publisher_id); - if(publisher) memcpy_max(vol_desc.publisher_id, publisher, strlen(publisher)); - - FILL_SPACE(preparer_id); - if(preparer) memcpy_max(vol_desc.preparer_id, preparer, strlen(preparer)); - - FILL_SPACE(application_id); - if(appid) memcpy_max(vol_desc.application_id, appid, strlen(appid)); - - FILL_SPACE(copyright_file_id); - if(copyright) memcpy_max(vol_desc.copyright_file_id, copyright, - strlen(copyright)); - - FILL_SPACE(abstract_file_id); - if(abstract) memcpy_max(vol_desc.abstract_file_id, abstract, - strlen(abstract)); - - FILL_SPACE(bibliographic_file_id); - if(biblio) memcpy_max(vol_desc.bibliographic_file_id, biblio, - strlen(biblio)); - - FILL_SPACE(creation_date); - FILL_SPACE(modification_date); - FILL_SPACE(expiration_date); - FILL_SPACE(effective_date); - vol_desc.file_structure_version[0] = 1; - FILL_SPACE(application_data); - - memcpy(vol_desc.creation_date, creation_date ? creation_date : iso_time, 17); - memcpy(vol_desc.modification_date, modification_date ? modification_date : iso_time, 17); - memcpy(vol_desc.expiration_date, expiration_date ? expiration_date : "0000000000000000", 17); - memcpy(vol_desc.effective_date, effective_date ? effective_date : iso_time, 17); - - /* - * if not a bootable cd do it the old way - */ - xfwrite(&vol_desc, 1, 2048, outfile); - last_extent_written++; - return 0; -} - -/* - * Function to write the EVD for the disc. - */ -static int FDECL1(evd_write, FILE *, outfile) -{ - struct iso_primary_descriptor evol_desc; - - /* - * Now write the end volume descriptor. Much simpler than the other one - */ - memset(&evol_desc, 0, sizeof(evol_desc)); - evol_desc.type[0] = ISO_VD_END; - memcpy(evol_desc.id, ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID)); - evol_desc.version[0] = 1; - xfwrite(&evol_desc, 1, 2048, outfile); - last_extent_written += 1; - return 0; -} - -/* - * Function to write the EVD for the disc. - */ -static int FDECL1(pathtab_write, FILE *, outfile) -{ - /* - * Next we write the path tables - */ - xfwrite(path_table_l, 1, path_blocks << 11, outfile); - xfwrite(path_table_m, 1, path_blocks << 11, outfile); - last_extent_written += 2*path_blocks; - free(path_table_l); - free(path_table_m); - path_table_l = NULL; - path_table_m = NULL; - return 0; -} - -static int FDECL1(exten_write, FILE *, outfile) -{ - xfwrite(extension_record, 1, SECTOR_SIZE, outfile); - last_extent_written++; - return 0; -} - -/* - * Functions to describe padding block at the start of the disc. - */ -int FDECL1(oneblock_size, int, starting_extent) -{ - last_extent++; - return 0; -} - -/* - * Functions to describe padding block at the start of the disc. - */ -static int FDECL1(pathtab_size, int, starting_extent) -{ - path_table[0] = starting_extent; - - path_table[1] = 0; - path_table[2] = path_table[0] + path_blocks; - path_table[3] = 0; - last_extent += 2*path_blocks; - return 0; -} - -static int FDECL1(padblock_size, int, starting_extent) -{ - last_extent += 16; - return 0; -} - -static int file_gen() -{ - assign_file_addresses(root); - return 0; -} - -static int dirtree_dump() -{ - if (verbose > 2) - { - dump_tree(root); - } - return 0; -} - -static int FDECL1(dirtree_fixup, int, starting_extent) -{ - if (use_RockRidge && reloc_dir) - finish_cl_pl_entries(); - - if (use_RockRidge ) - update_nlink_field(root); - return 0; -} - -static int FDECL1(dirtree_size, int, starting_extent) -{ - assign_directory_addresses(root); - return 0; -} - -static int FDECL1(ext_size, int, starting_extent) -{ - extern int extension_record_size; - struct directory_entry * s_entry; - extension_record_extent = starting_extent; - s_entry = root->contents; - set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 24, - extension_record_extent); - set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 8, - extension_record_size); - last_extent++; - return 0; -} - -static int FDECL1(dirtree_write, FILE *, outfile) -{ - generate_iso9660_directories(root, outfile); - return 0; -} - -static int FDECL1(dirtree_cleanup, FILE *, outfile) -{ - free_directories(root); - return 0; -} - -static int FDECL1(padblock_write, FILE *, outfile) -{ - char buffer[2048]; - int i; - - memset(buffer, 0, sizeof(buffer)); - - for(i=0; i<16; i++) - { - xfwrite(buffer, 1, sizeof(buffer), outfile); - } - - last_extent_written += 16; - return 0; -} - -struct output_fragment padblock_desc = {NULL, padblock_size, NULL, padblock_write}; -struct output_fragment voldesc_desc = {NULL, oneblock_size, root_gen, pvd_write}; -struct output_fragment end_vol = {NULL, oneblock_size, NULL, evd_write}; -struct output_fragment pathtable_desc = {NULL, pathtab_size, generate_path_tables, pathtab_write}; -struct output_fragment dirtree_desc = {NULL, dirtree_size, NULL, dirtree_write}; -struct output_fragment dirtree_clean = {NULL, dirtree_fixup, dirtree_dump, dirtree_cleanup}; -struct output_fragment extension_desc = {NULL, ext_size, NULL, exten_write}; -struct output_fragment files_desc = {NULL, NULL, file_gen, file_write}; diff --git a/util/powerpc/ieee1275/grub-mkrescue.in b/util/powerpc/ieee1275/grub-mkrescue.in index 0110e799c..16658505b 100644 --- a/util/powerpc/ieee1275/grub-mkrescue.in +++ b/util/powerpc/ieee1275/grub-mkrescue.in @@ -30,7 +30,7 @@ target_cpu=@target_cpu@ platform=@platform@ pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` -grub_mkimage=${bindir}/`echo grub-mkelfimage | sed ${transform}` +grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` # Usage: usage # Print the usage. @@ -104,7 +104,7 @@ boot_dir=${iso_dir}/boot/grub mkdir ${iso_dir}/boot mkdir ${boot_dir} core_img=${boot_dir}/grub.img -${grub_mkimage} -n -d ${input_dir}/ -o ${core_img} ${modules} +${grub_mkimage} -O powerpc-ieee1275 -n -d ${input_dir}/ -o ${core_img} ${modules} genisoimage -hfs -part -no-desktop -r -J -o ${output_image} \ -map ${map_file} -hfs-bless ${boot_dir} -chrp-boot -sysid PPC \ ${iso_dir} diff --git a/util/raid.c b/util/raid.c index 83a0ee6e2..ec3ecd26e 100644 --- a/util/raid.c +++ b/util/raid.c @@ -50,7 +50,7 @@ grub_util_getdiskname (int major, int minor) else if (major == SCSI_DISK0_MAJOR) sprintf (name, "/dev/sd%c", 'a' + minor / 16); else - grub_util_error ("Unknown device number: %d, %d", major, minor); + grub_util_error ("unknown device number: %d, %d", major, minor); return name; } @@ -72,7 +72,7 @@ grub_util_raid_getmembers (char *name) fd = open (devname, O_RDONLY); if (fd == -1) - grub_util_error ("Can't open %s: %s", devname, strerror (errno)); + grub_util_error ("can't open %s: %s", devname, strerror (errno)); free (devname); @@ -81,7 +81,7 @@ grub_util_raid_getmembers (char *name) grub_util_error ("ioctl RAID_VERSION error: %s", strerror (errno)); if (version.major != 0 || version.minor != 90) - grub_util_error ("Unsupported RAID version: %d.%d", + grub_util_error ("unsupported RAID version: %d.%d", version.major, version.minor); ret = ioctl (fd, GET_ARRAY_INFO, &info); diff --git a/util/sparc64/ieee1275/grub-install.in b/util/sparc64/ieee1275/grub-install.in deleted file mode 100644 index 5cfb858d7..000000000 --- a/util/sparc64/ieee1275/grub-install.in +++ /dev/null @@ -1,276 +0,0 @@ -#! /bin/sh - -# Install GRUB on your drive. -# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 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 . - -# Initialize some variables. -transform="@program_transform_name@" - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -sbindir=@sbindir@ -bindir=@bindir@ -libdir=@libdir@ -PACKAGE_NAME=@PACKAGE_NAME@ -PACKAGE_TARNAME=@PACKAGE_TARNAME@ -PACKAGE_VERSION=@PACKAGE_VERSION@ -target_cpu=@target_cpu@ -platform=@platform@ -pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` - -grub_setup=${sbindir}/`echo grub-setup | sed ${transform}` -grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` -grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}` -grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` -rootdir= -grub_prefix=`echo /boot/grub | sed ${transform}` -modules= - -install_device= -no_floppy= -force_lba= -recheck=no -debug=no - -# Usage: usage -# Print the usage. -usage () { - cat <. -EOF -} - -# Check the arguments. -for option in "$@"; do - case "$option" in - -h | --help) - usage - exit 0 ;; - -v | --version) - echo "grub-install (GNU GRUB ${PACKAGE_VERSION})" - exit 0 ;; - --modules=*) - modules=`echo "$option" | sed 's/--modules=//'` ;; - --root-directory=*) - rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; - --grub-setup=*) - grub_setup=`echo "$option" | sed 's/--grub-setup=//'` ;; - --grub-mkimage=*) - grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; - --grub-mkdevicemap=*) - grub_mkdevicemap=`echo "$option" | sed 's/--grub-mkdevicemap=//'` ;; - --grub-probe=*) - grub_probe=`echo "$option" | sed 's/--grub-probe=//'` ;; - --no-floppy) - no_floppy="--no-floppy" ;; - --recheck) - recheck=yes ;; - # This is an undocumented feature... - --debug) - debug=yes ;; - -*) - echo "Unrecognized option \`$option'" 1>&2 - usage - exit 1 - ;; - *) - if test "x$install_device" != x; then - echo "More than one install_devices?" 1>&2 - usage - exit 1 - fi - install_device="${option}" ;; - esac -done - -# for make_system_path_relative_to_its_root() -. ${libdir}/grub/grub-mkconfig_lib - -if test "x$install_device" = x; then - echo "install_device not specified." 1>&2 - usage - exit 1 -fi - -# If the debugging feature is enabled, print commands. -setup_verbose= -if test $debug = yes; then - set -x - setup_verbose="--verbose" -fi - -# Initialize these directories here, since ROOTDIR was initialized. -bootdir=${rootdir}/boot -grubdir=${bootdir}/`echo grub | sed ${transform}` -device_map=${grubdir}/device.map - -grub_probe="${grub_probe} --device-map=${device_map}" - -# Check if GRUB is installed. -set $grub_setup dummy -if test -f "$1"; then - : -else - echo "$1: Not found." 1>&2 - exit 1 -fi - -set $grub_mkimage dummy -if test -f "$1"; then - : -else - echo "$1: Not found." 1>&2 - exit 1 -fi - -set $grub_mkdevicemap dummy -if test -f "$1"; then - : -else - echo "$1: Not found." 1>&2 - exit 1 -fi - -# Create the GRUB directory if it is not present. -test -d "$bootdir" || mkdir "$bootdir" || exit 1 -test -d "$grubdir" || mkdir "$grubdir" || exit 1 - -# If --recheck is specified, remove the device map, if present. -if test $recheck = yes; then - rm -f $device_map -fi - -# Create the device map file if it is not present. -if test -f "$device_map"; then - : -else - # Create a safe temporary file. - test -n "$mklog" && log_file=`$mklog` - - $grub_mkdevicemap --device-map=$device_map $no_floppy || exit 1 -fi - -# Make sure that there is no duplicated entry. -tmp=`sed -n '/^([fh]d[0-9]*)/s/\(^(.*)\).*/\1/p' $device_map \ - | sort | uniq -d | sed -n 1p` -if test -n "$tmp"; then - echo "The drive $tmp is defined multiple times in the device map $device_map" 1>&2 - exit 1 -fi - -# Copy the GRUB images to the GRUB directory. -for file in ${grubdir}/*.mod ${grubdir}/*.lst ${grubdir}/*.img; do - if test -f $file && [ "`basename $file`" != menu.lst ]; then - rm -f $file || exit 1 - fi -done -for file in ${pkglibdir}/*.mod ${pkglibdir}/*.lst; do - cp -f $file ${grubdir} || exit 1 -done - -for file in ${pkglibdir}/*.img; do - cp -f $file ${grubdir} || exit 1 -done - -# Write device to a variable so we don't have to traverse /dev every time. -grub_device=`$grub_probe --target=device ${grubdir}` - -# Create the core image. First, auto-detect the filesystem module. -fs_module=`$grub_probe --target=fs --device ${grub_device}` -if test "x$fs_module" = x -a "x$modules" = x; then - echo "Auto-detection of a filesystem module failed." 1>&2 - echo "Please specify the module with the option \`--modules' explicitly." 1>&2 - exit 1 -fi - -# Then the partition map module. In order to support partition-less media, -# this command is allowed to fail (--target=fs already grants us that the -# filesystem will be accessible). -partmap_module=`$grub_probe --target=partmap --device ${grub_device} 2> /dev/null` - -# Device abstraction module, if any (lvm, raid). -devabstraction_module=`$grub_probe --target=abstraction --device ${grub_device}` - -modules="$modules $fs_module $partmap_module $devabstraction_module" - -prefix_drive= -if [ "x${devabstraction_module}" = "x" ] ; then - if echo "${install_device}" | grep -qx "(.*)" ; then - install_drive="${install_device}" - else - install_drive="`$grub_probe --target=drive --device ${install_device}`" - fi - grub_drive="`$grub_probe --target=drive --device ${grub_device}`" - - # Strip partition number - install_drive="`echo ${install_drive} | sed -e 's/\([^\]\),[0-9]*/\1/g'`" - grub_drive="`echo ${grub_drive} | sed -e 's/\([^\]\),[0-9]*/\1/g'`" - if [ "x${grub_drive}" != "x${install_drive}" ] ; then - uuid="`$grub_probe --target=fs_uuid --device ${grub_device}`" - if [ "x${uuid}" = "x" ] ; then - echo "You attempted a cross-disk install, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 - exit 1 - fi - prefix_drive="(UUID=${uuid})" - modules="$modules fs_uuid" - fi -else - prefix_drive=`$grub_probe --target=drive --device ${grub_device}` -fi - -relative_grubdir=`make_system_path_relative_to_its_root ${grubdir}` || exit 1 -if [ "x${relative_grubdir}" = "x" ] ; then - relative_grubdir=/ -fi - -$grub_mkimage --output=${grubdir}/core.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 - -# Now perform the installation. -$grub_setup ${setup_verbose} --directory=${grubdir} --device-map=${device_map} \ - ${install_device} || exit 1 - -# Prompt the user to check if the device map is correct. -echo "Installation finished. No error reported." -echo "This is the contents of the device map $device_map." -echo "Check if this is correct or not. If any of the lines is incorrect," -echo "fix it and re-run the script \`grub-install'." -echo - -cat $device_map - -# Bye. -exit 0 diff --git a/util/sparc64/ieee1275/grub-mkimage.c b/util/sparc64/ieee1275/grub-mkimage.c deleted file mode 100644 index d756586af..000000000 --- a/util/sparc64/ieee1275/grub-mkimage.c +++ /dev/null @@ -1,301 +0,0 @@ -/* grub-mkimage.c - make a bootable image */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008,2009 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 . - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define _GNU_SOURCE 1 -#include - -#include "progname.h" - -static void -compress_kernel (char *kernel_img, size_t kernel_size, - char **core_img, size_t *core_size) -{ - /* No compression support yet. */ - grub_util_info ("kernel_img=%p, kernel_size=0x%x", kernel_img, kernel_size); - *core_img = xmalloc (kernel_size); - memcpy (*core_img, kernel_img, kernel_size); - *core_size = kernel_size; -} - -static void -generate_image (const char *dir, const char *prefix, FILE *out, char *mods[], char *memdisk_path) -{ - size_t kernel_size, total_module_size, memdisk_size, core_size, boot_size, offset; - char *kernel_path, *kernel_img, *core_img, *boot_path, *boot_img; - struct grub_util_path_list *path_list, *p; - struct grub_module_info *modinfo; - grub_addr_t module_addr; - unsigned int num; - - path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); - - kernel_path = grub_util_get_path (dir, "kernel.img"); - kernel_size = grub_util_get_image_size (kernel_path); - - total_module_size = sizeof (struct grub_module_info); - for (p = path_list; p; p = p->next) - total_module_size += (grub_util_get_image_size (p->name) - + sizeof (struct grub_module_header)); - - memdisk_size = 0; - if (memdisk_path) - { - memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); - grub_util_info ("the size of memory disk is 0x%x", memdisk_size); - total_module_size += memdisk_size + sizeof (struct grub_module_header); - } - - grub_util_info ("the total module size is 0x%x", total_module_size); - - kernel_img = xmalloc (kernel_size + total_module_size); - grub_util_load_image (kernel_path, kernel_img); - - if ((GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1) - > GRUB_KERNEL_MACHINE_DATA_END) - grub_util_error ("prefix too long"); - strcpy (kernel_img + GRUB_KERNEL_MACHINE_PREFIX, prefix); - - /* Fill in the grub_module_info structure. */ - modinfo = (struct grub_module_info *) (kernel_img + kernel_size); - modinfo->magic = GRUB_MODULE_MAGIC; - modinfo->offset = sizeof (struct grub_module_info); - modinfo->size = total_module_size; - - offset = kernel_size + sizeof (struct grub_module_info); - for (p = path_list; p; p = p->next) - { - struct grub_module_header *header; - size_t mod_size; - - mod_size = grub_util_get_image_size (p->name); - - header = (struct grub_module_header *) (kernel_img + offset); - header->type = OBJ_TYPE_ELF; - header->size = grub_host_to_target32 (mod_size + sizeof (*header)); - offset += sizeof (*header); - - grub_util_load_image (p->name, kernel_img + offset); - offset += mod_size; - } - - if (memdisk_path) - { - struct grub_module_header *header; - - header = (struct grub_module_header *) (kernel_img + offset); - header->type = OBJ_TYPE_MEMDISK; - header->size = grub_host_to_target32 (memdisk_size + sizeof (*header)); - offset += sizeof (*header); - - grub_util_load_image (memdisk_path, kernel_img + offset); - offset += memdisk_size; - } - - compress_kernel (kernel_img, kernel_size + total_module_size, - &core_img, &core_size); - - grub_util_info ("the core size is 0x%x", core_size); - - num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); - num <<= GRUB_DISK_SECTOR_BITS; - - boot_path = grub_util_get_path (dir, "diskboot.img"); - boot_size = grub_util_get_image_size (boot_path); - if (boot_size != GRUB_DISK_SECTOR_SIZE) - grub_util_error ("diskboot.img is not one sector size"); - - boot_img = grub_util_read_image (boot_path); - - /* sparc is a big endian architecture. */ - *((grub_uint32_t *) (boot_img + GRUB_DISK_SECTOR_SIZE - - GRUB_BOOT_MACHINE_LIST_SIZE + 8)) - = grub_cpu_to_be32 (num); - - grub_util_write_image (boot_img, boot_size, out); - free (boot_img); - free (boot_path); - - module_addr = (path_list - ? (GRUB_BOOT_MACHINE_IMAGE_ADDRESS + kernel_size) - : 0); - - grub_util_info ("the first module address is 0x%x", module_addr); - - *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE)) - = grub_cpu_to_be32 (total_module_size); - *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE)) - = grub_cpu_to_be32 (kernel_size); - - /* No compression support yet. */ - *((grub_uint32_t *) (core_img + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE)) - = grub_cpu_to_be32 (0); - - grub_util_write_image (core_img, core_size, out); - free (kernel_img); - free (core_img); - free (kernel_path); - - while (path_list) - { - struct grub_util_path_list *next = path_list->next; - free ((void *) path_list->name); - free (path_list); - path_list = next; - } -} - -static struct option options[] = - { - {"directory", required_argument, 0, 'd'}, - {"prefix", required_argument, 0, 'p'}, - {"memdisk", required_argument, 0, 'm'}, - {"output", required_argument, 0, 'o'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {"verbose", no_argument, 0, 'v'}, - {0, 0, 0, 0} - }; - -static void -usage (int status) -{ - if (status) - fprintf (stderr, "Try ``%s --help'' for more information.\n", program_name); - else - printf ("\ -Usage: %s [OPTION]... [MODULES]\n\ -\n\ -Make a bootable image of GRUB.\n\ -\n\ - -d, --directory=DIR use images and modules under DIR [default=%s]\n\ - -p, --prefix=DIR set grub_prefix directory [default=%s]\n\ - -m, --memdisk=FILE embed FILE as a memdisk image\n\ - -o, --output=FILE output a generated image to FILE [default=stdout]\n\ - -h, --help display this message and exit\n\ - -V, --version print version information and exit\n\ - -v, --verbose print verbose messages\n\ -\n\ -Report bugs to <%s>.\n\ -", program_name, GRUB_LIBDIR, DEFAULT_DIRECTORY, PACKAGE_BUGREPORT); - - exit (status); -} - -int -main (int argc, char *argv[]) -{ - char *output = NULL; - char *dir = NULL; - char *prefix = NULL; - char *memdisk = NULL; - FILE *fp = stdout; - - set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - while (1) - { - int c = getopt_long (argc, argv, "d:p:m:o:hVv", options, 0); - - if (c == -1) - break; - else - switch (c) - { - case 'o': - if (output) - free (output); - output = xstrdup (optarg); - break; - - case 'd': - if (dir) - free (dir); - dir = xstrdup (optarg); - break; - - case 'm': - if (memdisk) - free (memdisk); - memdisk = xstrdup (optarg); - - if (prefix) - free (prefix); - prefix = xstrdup ("(memdisk)/boot/grub"); - break; - - case 'h': - usage (0); - break; - - case 'p': - if (prefix) - free (prefix); - prefix = xstrdup (optarg); - break; - - case 'V': - printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); - return 0; - - case 'v': - verbosity++; - break; - - default: - usage (1); - break; - } - } - - if (output) - { - fp = fopen (output, "wb"); - if (! fp) - grub_util_error ("cannot open %s", output); - } - - generate_image (dir ? : GRUB_LIBDIR, - prefix ? : DEFAULT_DIRECTORY, fp, - argv + optind, memdisk); - - fclose (fp); - - if (dir) - free (dir); - - return 0; -} diff --git a/util/sparc64/ieee1275/grub-setup.c b/util/sparc64/ieee1275/grub-setup.c index ade1bd595..8a2d30ba1 100644 --- a/util/sparc64/ieee1275/grub-setup.c +++ b/util/sparc64/ieee1275/grub-setup.c @@ -1,7 +1,7 @@ /* grub-setup.c - make GRUB usable */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,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 @@ -29,12 +29,13 @@ #include #include #include -#include +#include #include #include #include #include #include +#include #include @@ -45,7 +46,7 @@ #include #include #include -#include +#include #define _GNU_SOURCE 1 #include @@ -75,6 +76,13 @@ #define DEFAULT_BOOT_FILE "boot.img" #define DEFAULT_CORE_FILE "core.img" +#define grub_target_to_host16(x) grub_be_to_cpu16(x) +#define grub_target_to_host32(x) grub_be_to_cpu32(x) +#define grub_target_to_host64(x) grub_be_to_cpu64(x) +#define grub_host_to_target16(x) grub_cpu_to_be16(x) +#define grub_host_to_target32(x) grub_cpu_to_be32(x) +#define grub_host_to_target64(x) grub_cpu_to_be64(x) + /* This is the blocklist used in the diskboot image. */ struct boot_blocklist { @@ -103,28 +111,6 @@ grub_refresh (void) fflush (stdout); } -static char *compute_dest_ofpath (const char *dest) -{ - int len = strlen (dest); - char *res, *p, c; - - res = xmalloc (len); - p = res; - while ((c = *dest++) != '\0') - { - if (c == '\\' && *dest == ',') - { - *p++ = ','; - dest++; - } - else - *p++ = c; - } - *p++ = '\0'; - - return res; -} - static void setup (const char *prefix, const char *dir, const char *boot_file, const char *core_file, @@ -135,8 +121,8 @@ setup (const char *prefix, const char *dir, size_t boot_size, core_size; grub_uint16_t core_sectors; grub_device_t root_dev, dest_dev; - char *boot_devpath, *dest_ofpath; - grub_disk_addr_t *kernel_sector; + char *boot_devpath; + grub_disk_addr_t *kernel_byte; struct boot_blocklist *first_block, *block; char *tmp_img; int i; @@ -161,7 +147,7 @@ setup (const char *prefix, const char *dir, grub_util_info ("first sector is <%llu,%u,%u>", sector, offset, length); if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE) - grub_util_error ("The first sector of the core file " + grub_util_error ("the first sector of the core file " "is not sector-aligned"); first_sector = sector; @@ -176,7 +162,7 @@ setup (const char *prefix, const char *dir, grub_util_info ("saving <%llu,%u,%u>", sector, offset, length); if (offset != 0 || last_length != GRUB_DISK_SECTOR_SIZE) - grub_util_error ("Non-sector-aligned data is found in the core file"); + grub_util_error ("non-sector-aligned data is found in the core file"); if (block != first_block && (grub_be_to_cpu64 (prev->start) @@ -189,19 +175,17 @@ setup (const char *prefix, const char *dir, block--; if (block->len) - grub_util_error ("The sectors of the core file are too fragmented"); + grub_util_error ("the sectors of the core file are too fragmented"); } last_length = length; } - dest_ofpath = compute_dest_ofpath (dest); - /* Read the boot image by the OS service. */ boot_path = grub_util_get_path (dir, boot_file); boot_size = grub_util_get_image_size (boot_path); if (boot_size != GRUB_DISK_SECTOR_SIZE) - grub_util_error ("The size of `%s' is not %d", + grub_util_error ("the size of `%s' is not %d", boot_path, GRUB_DISK_SECTOR_SIZE); boot_img = grub_util_read_image (boot_path); free (boot_path); @@ -210,16 +194,16 @@ setup (const char *prefix, const char *dir, boot_devpath = (char *) (boot_img + GRUB_BOOT_AOUT_HEADER_SIZE + GRUB_BOOT_MACHINE_BOOT_DEVPATH); - kernel_sector = (grub_disk_addr_t *) (boot_img - + GRUB_BOOT_AOUT_HEADER_SIZE - + GRUB_BOOT_MACHINE_KERNEL_SECTOR); + kernel_byte = (grub_disk_addr_t *) (boot_img + + GRUB_BOOT_AOUT_HEADER_SIZE + + GRUB_BOOT_MACHINE_KERNEL_BYTE); core_path = grub_util_get_path (dir, core_file); core_size = grub_util_get_image_size (core_path); core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); if (core_size < GRUB_DISK_SECTOR_SIZE) - grub_util_error ("The size of `%s' is too small", core_path); + grub_util_error ("the size of `%s' is too small", core_path); core_img = grub_util_read_image (core_path); free (core_path); @@ -229,8 +213,7 @@ setup (const char *prefix, const char *dir, + GRUB_DISK_SECTOR_SIZE - sizeof (*block)); - grub_util_info ("root is '%s', dest is '%s', and dest_ofpath is '%s'", - root, dest, dest_ofpath); + grub_util_info ("root is `%s', dest is `%s'", root, dest); /* Open the root device and the destination device. */ grub_util_info ("Opening root"); @@ -320,7 +303,7 @@ setup (const char *prefix, const char *dir, } if (i == MAX_TRIES) - grub_util_error ("Cannot read `%s' correctly", core_path); + grub_util_error ("cannot read `%s' correctly", core_path); /* Clean out the blocklists. */ block = first_block; @@ -332,7 +315,7 @@ setup (const char *prefix, const char *dir, block--; if ((char *) block <= core_img) - grub_util_error ("No terminator in the core image"); + grub_util_error ("no terminator in the core image"); } /* Now read the core image to determine where the sectors are. */ @@ -343,22 +326,38 @@ setup (const char *prefix, const char *dir, file->read_hook = save_first_sector; if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE) - grub_util_error ("Failed to read the first sector of the core image"); + grub_util_error ("failed to read the first sector of the core image"); block = first_block; file->read_hook = save_blocklists; if (grub_file_read (file, tmp_img, core_size - GRUB_DISK_SECTOR_SIZE) != (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE) - grub_util_error ("Failed to read the rest sectors of the core image"); + grub_util_error ("failed to read the rest sectors of the core image"); + + if (file->device->disk->id != dest_dev->disk->id) + { + const char *dest_ofpath; + dest_ofpath + = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (file->device->disk)); + grub_util_info ("dest_ofpath is `%s'", dest_ofpath); + strncpy (boot_devpath, dest_ofpath, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1); + boot_devpath[GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0; + } + else + { + grub_util_info ("non cross-disk install"); + memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH); + } grub_file_close (file); free (core_path); free (tmp_img); - *kernel_sector = grub_cpu_to_be64 (first_sector); - - strcpy(boot_devpath, dest_ofpath); + *kernel_byte = grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS); grub_util_info ("boot device path %s, prefix is %s, dest is %s", boot_devpath, prefix, dest); @@ -368,7 +367,7 @@ setup (const char *prefix, const char *dir, grub_util_info ("opening the core image `%s'", core_path); fp = fopen (core_path, "r+b"); if (! fp) - grub_util_error ("Cannot open `%s'", core_path); + grub_util_error ("cannot open `%s'", core_path); grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE, fp); fclose (fp); @@ -404,13 +403,13 @@ static void usage (int status) { if (status) - fprintf (stderr, "Try ``%s --help'' for more information.\n", program_name); + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); else printf ("\ Usage: %s [OPTION]... DEVICE\n\ \n\ Set up images to boot from DEVICE.\n\ -DEVICE must be a GRUB device (e.g. ``(hd0,1)'').\n\ +DEVICE must be a GRUB device (e.g. `(hd0,1)').\n\ \n\ -b, --boot-image=FILE use FILE as the boot image [default=%s]\n\ -c, --core-image=FILE use FILE as the core image [default=%s]\n\ @@ -559,14 +558,14 @@ find_dest_dev (struct grub_setup_info *gp, char *argv[]) fprintf (stderr, "Invalid device `%s'.\n", argv[optind]); usage (1); } - grub_util_info ("transformed OS device '%s' into GRUB device '%s'", + grub_util_info ("transformed OS device `%s' into GRUB device `%s'", argv[optind], gp->dest_dev); } else { /* For simplicity. */ gp->dest_dev = xstrdup (gp->dest_dev); - grub_util_info ("Using '%s' as GRUB device", gp->dest_dev); + grub_util_info ("Using `%s' as GRUB device", gp->dest_dev); } } @@ -578,7 +577,7 @@ check_root_dev (struct grub_setup_info *gp) char *tmp = get_device_name (gp->root_dev); if (! tmp) - grub_util_error ("Invalid root device `%s'", gp->root_dev); + grub_util_error ("invalid root device `%s'", gp->root_dev); tmp = xstrdup (tmp); free (gp->root_dev); @@ -594,11 +593,11 @@ check_root_dev (struct grub_setup_info *gp) { grub_util_info ("guessing the root device failed, because of `%s'", grub_errmsg); - grub_util_error ("Cannot guess the root device. " - "Specify the option ``--root-device''."); + grub_util_error ("cannot guess the root device. " + "Specify the option `--root-device'"); } - grub_util_info ("Guessed root device '%s' and root_dev '%s' from " - "dir '%s'", root_device, gp->root_dev, dir); + grub_util_info ("guessed root device `%s' and root_dev `%s' from " + "dir `%s'", root_device, gp->root_dev, dir); } } @@ -620,9 +619,8 @@ main (int argc, char *argv[]) struct grub_setup_info ginfo; set_program_name (argv[0]); - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); + + grub_util_init_nls (); init_info (&ginfo); if (!parse_options (&ginfo, argc, argv)) @@ -636,7 +634,8 @@ main (int argc, char *argv[]) find_dest_dev (&ginfo, argv); - ginfo.prefix = grub_get_prefix (ginfo.dir ? : DEFAULT_DIRECTORY); + ginfo.prefix = grub_make_system_path_relative_to_its_root (ginfo.dir ? + : DEFAULT_DIRECTORY); check_root_dev (&ginfo); diff --git a/video/bitmap.c b/video/bitmap.c index 7b135a5dc..e06a5b696 100644 --- a/video/bitmap.c +++ b/video/bitmap.c @@ -58,12 +58,12 @@ grub_video_bitmap_create (struct grub_video_bitmap **bitmap, unsigned int size; if (!bitmap) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid argument."); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument"); *bitmap = 0; if (width == 0 || height == 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid argument."); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument"); *bitmap = (struct grub_video_bitmap *)grub_malloc (sizeof (struct grub_video_bitmap)); if (! *bitmap) @@ -129,7 +129,7 @@ grub_video_bitmap_create (struct grub_video_bitmap **bitmap, *bitmap = 0; return grub_error (GRUB_ERR_BAD_ARGUMENT, - "Unsupported bitmap format"); + "unsupported bitmap format"); } mode_info->pitch = width * mode_info->bytes_per_pixel; @@ -188,7 +188,7 @@ grub_video_bitmap_load (struct grub_video_bitmap **bitmap, grub_video_bitmap_reader_t reader = bitmap_readers_list; if (!bitmap) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid argument."); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument"); *bitmap = 0; @@ -243,11 +243,11 @@ void *grub_video_bitmap_get_data (struct grub_video_bitmap *bitmap) } /* Initialize bitmap module. */ -GRUB_MOD_INIT(video_bitmap) +GRUB_MOD_INIT(bitmap) { } /* Finalize bitmap module. */ -GRUB_MOD_FINI(video_bitmap) +GRUB_MOD_FINI(bitmap) { } diff --git a/video/bitmap_scale.c b/video/bitmap_scale.c new file mode 100644 index 000000000..6f8ff247e --- /dev/null +++ b/video/bitmap_scale.c @@ -0,0 +1,308 @@ +/* bitmap_scale.c - Bitmap scaling. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008,2009 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 . + */ + +#include +#include +#include +#include +#include +#include + +/* Prototypes for module-local functions. */ +static grub_err_t scale_nn (struct grub_video_bitmap *dst, + struct grub_video_bitmap *src); +static grub_err_t scale_bilinear (struct grub_video_bitmap *dst, + struct grub_video_bitmap *src); + +/* This function creates a new scaled version of the bitmap SRC. The new + bitmap has dimensions DST_WIDTH by DST_HEIGHT. The scaling algorithm + is given by SCALE_METHOD. If an error is encountered, the return code is + not equal to GRUB_ERR_NONE, and the bitmap DST is either not created, or + it is destroyed before this function returns. + + Supports only direct color modes which have components separated + into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color). + But because of this simplifying assumption, the implementation is + greatly simplified. */ +grub_err_t +grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst, + int dst_width, int dst_height, + struct grub_video_bitmap *src, + enum grub_video_bitmap_scale_method + scale_method) +{ + *dst = 0; + + /* Verify the simplifying assumptions. */ + if (src == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "null src bitmap in grub_video_bitmap_create_scaled"); + if (src->mode_info.red_field_pos % 8 != 0 + || src->mode_info.green_field_pos % 8 != 0 + || src->mode_info.blue_field_pos % 8 != 0 + || src->mode_info.reserved_field_pos % 8 != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "src format not supported for scale"); + if (src->mode_info.width == 0 || src->mode_info.height == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "source bitmap has a zero dimension"); + if (dst_width <= 0 || dst_height <= 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "requested to scale to a size w/ a zero dimension"); + if (src->mode_info.bytes_per_pixel * 8 != src->mode_info.bpp) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "bitmap to scale has inconsistent Bpp and bpp"); + + /* Create the new bitmap. */ + grub_err_t ret; + ret = grub_video_bitmap_create (dst, dst_width, dst_height, + src->mode_info.blit_format); + if (ret != GRUB_ERR_NONE) + return ret; /* Error. */ + + switch (scale_method) + { + case GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST: + case GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST: + ret = scale_nn (*dst, src); + break; + case GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST: + case GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR: + ret = scale_bilinear (*dst, src); + break; + default: + ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid scale_method value"); + break; + } + + if (ret == GRUB_ERR_NONE) + { + /* Success: *dst is now a pointer to the scaled bitmap. */ + return GRUB_ERR_NONE; + } + else + { + /* Destroy the bitmap and return the error code. */ + grub_video_bitmap_destroy (*dst); + *dst = 0; + return ret; + } +} + +/* Nearest neighbor bitmap scaling algorithm. + + Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the + dimensions of DST. This function uses the nearest neighbor algorithm to + interpolate the pixels. + + Supports only direct color modes which have components separated + into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color). + But because of this simplifying assumption, the implementation is + greatly simplified. */ +static grub_err_t +scale_nn (struct grub_video_bitmap *dst, struct grub_video_bitmap *src) +{ + /* Verify the simplifying assumptions. */ + if (dst == 0 || src == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "null bitmap in scale_nn"); + if (dst->mode_info.red_field_pos % 8 != 0 + || dst->mode_info.green_field_pos % 8 != 0 + || dst->mode_info.blue_field_pos % 8 != 0 + || dst->mode_info.reserved_field_pos % 8 != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst format not supported"); + if (src->mode_info.red_field_pos % 8 != 0 + || src->mode_info.green_field_pos % 8 != 0 + || src->mode_info.blue_field_pos % 8 != 0 + || src->mode_info.reserved_field_pos % 8 != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "src format not supported"); + if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos + || dst->mode_info.red_mask_size != src->mode_info.red_mask_size + || dst->mode_info.green_field_pos != src->mode_info.green_field_pos + || dst->mode_info.green_mask_size != src->mode_info.green_mask_size + || dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos + || dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size + || dst->mode_info.reserved_field_pos != + src->mode_info.reserved_field_pos + || dst->mode_info.reserved_mask_size != + src->mode_info.reserved_mask_size) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible"); + if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible"); + if (dst->mode_info.width == 0 || dst->mode_info.height == 0 + || src->mode_info.width == 0 || src->mode_info.height == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension"); + + grub_uint8_t *ddata = dst->data; + grub_uint8_t *sdata = src->data; + int dw = dst->mode_info.width; + int dh = dst->mode_info.height; + int sw = src->mode_info.width; + int sh = src->mode_info.height; + int dstride = dst->mode_info.pitch; + int sstride = src->mode_info.pitch; + /* bytes_per_pixel is the same for both src and dst. */ + int bytes_per_pixel = dst->mode_info.bytes_per_pixel; + + int dy; + for (dy = 0; dy < dh; dy++) + { + int dx; + for (dx = 0; dx < dw; dx++) + { + grub_uint8_t *dptr; + grub_uint8_t *sptr; + int sx; + int sy; + int comp; + + /* Compute the source coordinate that the destination coordinate + maps to. Note: sx/sw = dx/dw => sx = sw*dx/dw. */ + sx = sw * dx / dw; + sy = sh * dy / dh; + + /* Get the address of the pixels in src and dst. */ + dptr = ddata + dy * dstride + dx * bytes_per_pixel; + sptr = sdata + sy * sstride + sx * bytes_per_pixel; + + /* Copy the pixel color value. */ + for (comp = 0; comp < bytes_per_pixel; comp++) + dptr[comp] = sptr[comp]; + } + } + return GRUB_ERR_NONE; +} + +/* Bilinear interpolation image scaling algorithm. + + Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the + dimensions of DST. This function uses the bilinear interpolation algorithm + to interpolate the pixels. + + Supports only direct color modes which have components separated + into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color). + But because of this simplifying assumption, the implementation is + greatly simplified. */ +static grub_err_t +scale_bilinear (struct grub_video_bitmap *dst, struct grub_video_bitmap *src) +{ + /* Verify the simplifying assumptions. */ + if (dst == 0 || src == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "null bitmap in scale func"); + if (dst->mode_info.red_field_pos % 8 != 0 + || dst->mode_info.green_field_pos % 8 != 0 + || dst->mode_info.blue_field_pos % 8 != 0 + || dst->mode_info.reserved_field_pos % 8 != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst format not supported"); + if (src->mode_info.red_field_pos % 8 != 0 + || src->mode_info.green_field_pos % 8 != 0 + || src->mode_info.blue_field_pos % 8 != 0 + || src->mode_info.reserved_field_pos % 8 != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "src format not supported"); + if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos + || dst->mode_info.red_mask_size != src->mode_info.red_mask_size + || dst->mode_info.green_field_pos != src->mode_info.green_field_pos + || dst->mode_info.green_mask_size != src->mode_info.green_mask_size + || dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos + || dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size + || dst->mode_info.reserved_field_pos != + src->mode_info.reserved_field_pos + || dst->mode_info.reserved_mask_size != + src->mode_info.reserved_mask_size) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible"); + if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "dst and src not compatible"); + if (dst->mode_info.width == 0 || dst->mode_info.height == 0 + || src->mode_info.width == 0 || src->mode_info.height == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bitmap has a zero dimension"); + + grub_uint8_t *ddata = dst->data; + grub_uint8_t *sdata = src->data; + int dw = dst->mode_info.width; + int dh = dst->mode_info.height; + int sw = src->mode_info.width; + int sh = src->mode_info.height; + int dstride = dst->mode_info.pitch; + int sstride = src->mode_info.pitch; + /* bytes_per_pixel is the same for both src and dst. */ + int bytes_per_pixel = dst->mode_info.bytes_per_pixel; + + int dy; + for (dy = 0; dy < dh; dy++) + { + int dx; + for (dx = 0; dx < dw; dx++) + { + grub_uint8_t *dptr; + grub_uint8_t *sptr; + int sx; + int sy; + int comp; + + /* Compute the source coordinate that the destination coordinate + maps to. Note: sx/sw = dx/dw => sx = sw*dx/dw. */ + sx = sw * dx / dw; + sy = sh * dy / dh; + + /* Get the address of the pixels in src and dst. */ + dptr = ddata + dy * dstride + dx * bytes_per_pixel; + sptr = sdata + sy * sstride + sx * bytes_per_pixel; + + /* If we have enough space to do so, use bilinear interpolation. + Otherwise, fall back to nearest neighbor for this pixel. */ + if (sx < sw - 1 && sy < sh - 1) + { + /* Do bilinear interpolation. */ + + /* Fixed-point .8 numbers representing the fraction of the + distance in the x (u) and y (v) direction within the + box of 4 pixels in the source. */ + int u = (256 * sw * dx / dw) - (sx * 256); + int v = (256 * sh * dy / dh) - (sy * 256); + + for (comp = 0; comp < bytes_per_pixel; comp++) + { + /* Get the component's values for the + four source corner pixels. */ + grub_uint8_t f00 = sptr[comp]; + grub_uint8_t f10 = sptr[comp + bytes_per_pixel]; + grub_uint8_t f01 = sptr[comp + sstride]; + grub_uint8_t f11 = sptr[comp + sstride + bytes_per_pixel]; + + /* Do linear interpolations along the top and bottom + rows of the box. */ + grub_uint8_t f0y = (256 - v) * f00 / 256 + v * f01 / 256; + grub_uint8_t f1y = (256 - v) * f10 / 256 + v * f11 / 256; + + /* Interpolate vertically. */ + grub_uint8_t fxy = (256 - u) * f0y / 256 + u * f1y / 256; + + dptr[comp] = fxy; + } + } + else + { + /* Fall back to nearest neighbor interpolation. */ + /* Copy the pixel color value. */ + for (comp = 0; comp < bytes_per_pixel; comp++) + dptr[comp] = sptr[comp]; + } + } + } + return GRUB_ERR_NONE; +} diff --git a/video/efi_gop.c b/video/efi_gop.c index e2eb2f7ae..86a2881f8 100644 --- a/video/efi_gop.c +++ b/video/efi_gop.c @@ -93,7 +93,7 @@ grub_video_gop_get_bpp (struct grub_efi_gop_mode_info *in) total_mask = in->pixel_bitmask.r | in->pixel_bitmask.g | in->pixel_bitmask.b | in->pixel_bitmask.a; - + for (i = 31; i >= 0; i--) if (total_mask & (1 << i)) return i + 1; @@ -123,7 +123,7 @@ grub_video_gop_get_bitmask (grub_uint32_t mask, unsigned int *mask_size, if (!(mask & (1 << i))) break; *field_pos = i + 1; - *mask_size = last_p - *field_pos; + *mask_size = last_p - *field_pos + 1; } static grub_err_t @@ -137,7 +137,7 @@ grub_video_gop_fill_mode_info (struct grub_efi_gop_mode_info *in, out->bpp = grub_video_gop_get_bpp (in); out->bytes_per_pixel = out->bpp >> 3; if (!out->bpp) - return grub_error (GRUB_ERR_IO, "Unsupported video mode"); + return grub_error (GRUB_ERR_IO, "unsupported video mode"); out->pitch = in->pixels_per_scanline * out->bytes_per_pixel; switch (in->pixel_format) @@ -176,7 +176,7 @@ grub_video_gop_fill_mode_info (struct grub_efi_gop_mode_info *in, break; default: - return grub_error (GRUB_ERR_IO, "Unsupported video mode"); + return grub_error (GRUB_ERR_IO, "unsupported video mode"); } out->blit_format = grub_video_get_blit_format (out); @@ -185,7 +185,7 @@ grub_video_gop_fill_mode_info (struct grub_efi_gop_mode_info *in, static grub_err_t grub_video_gop_setup (unsigned int width, unsigned int height, - unsigned int mode_type) + unsigned int mode_type, unsigned int mode_mask __attribute__ ((unused))) { unsigned int depth; struct grub_efi_gop_mode_info *info = NULL; @@ -212,7 +212,7 @@ grub_video_gop_setup (unsigned int width, unsigned int height, found = 1; } } - + if (!found) { unsigned mode; @@ -221,7 +221,7 @@ grub_video_gop_setup (unsigned int width, unsigned int height, { grub_efi_uintn_t size; grub_efi_status_t status; - + status = efi_call_4 (gop->query_mode, gop, mode, &size, &info); if (status) { @@ -255,7 +255,7 @@ grub_video_gop_setup (unsigned int width, unsigned int height, * ((unsigned long long) bpp)) { best_volume = ((unsigned long long) info->width) - * ((unsigned long long) info->height) + * ((unsigned long long) info->height) * ((unsigned long long) bpp); best_mode = mode; } @@ -266,7 +266,7 @@ grub_video_gop_setup (unsigned int width, unsigned int height, if (!found) { grub_dprintf ("video", "GOP: no mode found\n"); - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found."); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found"); } if (best_mode != gop->mode->mode) @@ -293,8 +293,8 @@ grub_video_gop_setup (unsigned int width, unsigned int height, grub_dprintf ("video", "GOP: initialising FB @ %p %dx%dx%d\n", framebuffer.ptr, framebuffer.mode_info.width, framebuffer.mode_info.height, framebuffer.mode_info.bpp); - - err = grub_video_fb_create_render_target_from_pointer + + err = grub_video_fb_create_render_target_from_pointer (&framebuffer.render_target, &framebuffer.mode_info, framebuffer.ptr); if (err) @@ -302,15 +302,15 @@ grub_video_gop_setup (unsigned int width, unsigned int height, grub_dprintf ("video", "GOP: Couldn't create FB target\n"); return err; } - + err = grub_video_fb_set_active_render_target (framebuffer.render_target); - + if (err) { grub_dprintf ("video", "GOP: Couldn't set FB target\n"); return err; } - + err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, grub_video_fbstd_colors); @@ -318,7 +318,7 @@ grub_video_gop_setup (unsigned int width, unsigned int height, grub_dprintf ("video", "GOP: Couldn't set palette\n"); else grub_dprintf ("video", "GOP: Success\n"); - + return err; } @@ -353,6 +353,7 @@ grub_video_gop_get_info_and_fini (struct grub_video_mode_info *mode_info, static struct grub_video_adapter grub_video_gop_adapter = { .name = "EFI GOP driver", + .id = GRUB_VIDEO_DRIVER_EFI_GOP, .init = grub_video_gop_init, .fini = grub_video_gop_fini, diff --git a/video/efi_uga.c b/video/efi_uga.c index 31062c5f5..eb4e6b42e 100644 --- a/video/efi_uga.c +++ b/video/efi_uga.c @@ -84,21 +84,22 @@ find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len) { int found = 0; - auto int NESTED_FUNC_ATTR find_card (int bus, int dev, int func, + auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid); - int NESTED_FUNC_ATTR find_card (int bus, int dev, int func, + int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid) { grub_pci_address_t addr; - addr = grub_pci_make_address (bus, dev, func, 2); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); if (grub_pci_read (addr) >> 24 == 0x3) { int i; grub_dprintf ("fb", "Display controller: %d:%d.%d\nDevice id: %x\n", - bus, dev, func, pciid); + grub_pci_get_bus (dev), grub_pci_get_device (dev), + grub_pci_get_function (dev), pciid); addr += 8; for (i = 0; i < 6; i++, addr += 4) { @@ -197,7 +198,7 @@ grub_video_uga_fini (void) static grub_err_t grub_video_uga_setup (unsigned int width, unsigned int height, - unsigned int mode_type) + unsigned int mode_type, unsigned int mode_mask __attribute__ ((unused))) { unsigned int depth; int found = 0; @@ -265,7 +266,7 @@ grub_video_uga_setup (unsigned int width, unsigned int height, return err; } - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found."); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found"); } static grub_err_t @@ -299,6 +300,7 @@ grub_video_uga_get_info_and_fini (struct grub_video_mode_info *mode_info, static struct grub_video_adapter grub_video_uga_adapter = { .name = "EFI UGA driver", + .id = GRUB_VIDEO_DRIVER_EFI_UGA, .init = grub_video_uga_init, .fini = grub_video_uga_fini, diff --git a/video/emu/sdl.c b/video/emu/sdl.c new file mode 100644 index 000000000..d261db6b0 --- /dev/null +++ b/video/emu/sdl.c @@ -0,0 +1,237 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,2009 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 . + */ + +#define grub_video_render_target grub_video_fbrender_target + +#include +#include +#include +#include +#include +#include +#include +#include + +static SDL_Surface *window = 0; +static struct grub_video_render_target *sdl_render_target; +static struct grub_video_mode_info mode_info; + +static grub_err_t +grub_video_sdl_set_palette (unsigned int start, unsigned int count, + struct grub_video_palette_data *palette_data); + +static grub_err_t +grub_video_sdl_init (void) +{ + window = 0; + + if (SDL_Init (SDL_INIT_VIDEO) < 0) + return grub_error (GRUB_ERR_BAD_DEVICE, "Couldn't init SDL: %s", + SDL_GetError ()); + + grub_memset (&mode_info, 0, sizeof (mode_info)); + + return grub_video_fb_init (); +} + +static grub_err_t +grub_video_sdl_fini (void) +{ + SDL_Quit (); + window = 0; + + grub_memset (&mode_info, 0, sizeof (mode_info)); + + return grub_video_fb_fini (); +} + +static inline unsigned int +get_mask_size (grub_uint32_t mask) +{ + unsigned i; + for (i = 0; mask > 1U << i; i++); + return i; +} + +static grub_err_t +grub_video_sdl_setup (unsigned int width, unsigned int height, + unsigned int mode_type, unsigned int mode_mask) +{ + int depth; + int flags = 0; + grub_err_t err; + + /* Decode depth from mode_type. If it is zero, then autodetect. */ + depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) + >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS; + + if (depth == 0) + depth = 32; + + if (width == 0 && height == 0) + { + width = 800; + height = 600; + } + + if ((mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) + || !(mode_mask & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED)) + flags |= SDL_DOUBLEBUF; + + window = SDL_SetVideoMode (width, height, depth, flags | SDL_HWSURFACE); + if (! window) + window = SDL_SetVideoMode (width, height, depth, flags | SDL_SWSURFACE); + if (! window) + return grub_error (GRUB_ERR_BAD_DEVICE, "Couldn't open window: %s", + SDL_GetError ()); + + grub_memset (&sdl_render_target, 0, sizeof (sdl_render_target)); + + mode_info.width = window->w; + mode_info.height = window->h; + mode_info.mode_type = 0; + if (window->flags & SDL_DOUBLEBUF) + mode_info.mode_type + |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + if (window->format->palette) + mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + else + mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_RGB; + + mode_info.bpp = window->format->BitsPerPixel; + mode_info.bytes_per_pixel = window->format->BytesPerPixel; + mode_info.pitch = window->pitch; + + /* In index color mode, number of colors. In RGB mode this is 256. */ + if (window->format->palette) + mode_info.number_of_colors + = 1 << window->format->BitsPerPixel; + else + mode_info.number_of_colors = 256; + + if (! window->format->palette) + { + mode_info.red_mask_size + = get_mask_size (window->format->Rmask >> window->format->Rshift); + mode_info.red_field_pos = window->format->Rshift; + mode_info.green_mask_size + = get_mask_size (window->format->Gmask >> window->format->Gshift); + mode_info.green_field_pos = window->format->Gshift; + mode_info.blue_mask_size + = get_mask_size (window->format->Bmask >> window->format->Bshift); + mode_info.blue_field_pos = window->format->Bshift; + mode_info.reserved_mask_size + = get_mask_size (window->format->Amask >> window->format->Ashift); + mode_info.reserved_field_pos = window->format->Ashift; + mode_info.blit_format + = grub_video_get_blit_format (&mode_info); + } + + err = grub_video_fb_create_render_target_from_pointer (&sdl_render_target, + &mode_info, + window->pixels); + if (err) + return err; + + /* Copy default palette to initialize emulated palette. */ + grub_video_sdl_set_palette (0, (sizeof (grub_video_fbstd_colors) + / sizeof (grub_video_fbstd_colors[0])), + grub_video_fbstd_colors); + + /* Reset render target to SDL one. */ + return grub_video_fb_set_active_render_target (sdl_render_target); +} + +static grub_err_t +grub_video_sdl_set_palette (unsigned int start, unsigned int count, + struct grub_video_palette_data *palette_data) +{ + unsigned i; + if (window->format->palette) + { + SDL_Color *tmp = grub_malloc (count * sizeof (tmp[0])); + for (i = 0; i < count; i++) + { + tmp[i].r = palette_data[i].r; + tmp[i].g = palette_data[i].g; + tmp[i].b = palette_data[i].b; + tmp[i].unused = palette_data[i].a; + } + SDL_SetColors (window, tmp, start, count); + grub_free (tmp); + } + + return grub_video_fb_set_palette (start, count, palette_data); +} + +static grub_err_t +grub_video_sdl_swap_buffers (void) +{ + if (SDL_Flip (window) < 0) + return grub_error (GRUB_ERR_BAD_DEVICE, "couldn't swap buffers: %s", + SDL_GetError ()); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_sdl_set_active_render_target (struct grub_video_render_target *target) +{ + if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY) + return grub_video_fb_set_active_render_target (sdl_render_target); + + return grub_video_fb_set_active_render_target (target); +} + +static struct grub_video_adapter grub_video_sdl_adapter = + { + .name = "SDL Video Driver", + + .init = grub_video_sdl_init, + .fini = grub_video_sdl_fini, + .setup = grub_video_sdl_setup, + .get_info = grub_video_fb_get_info, + .set_palette = grub_video_sdl_set_palette, + .get_palette = grub_video_fb_get_palette, + .set_viewport = grub_video_fb_set_viewport, + .get_viewport = grub_video_fb_get_viewport, + .map_color = grub_video_fb_map_color, + .map_rgb = grub_video_fb_map_rgb, + .map_rgba = grub_video_fb_map_rgba, + .unmap_color = grub_video_fb_unmap_color, + .fill_rect = grub_video_fb_fill_rect, + .blit_bitmap = grub_video_fb_blit_bitmap, + .blit_render_target = grub_video_fb_blit_render_target, + .scroll = grub_video_fb_scroll, + .swap_buffers = grub_video_sdl_swap_buffers, + .create_render_target = grub_video_fb_create_render_target, + .delete_render_target = grub_video_fb_delete_render_target, + .set_active_render_target = grub_video_sdl_set_active_render_target, + .get_active_render_target = grub_video_fb_get_active_render_target, + + .next = 0 + }; + +GRUB_MOD_INIT(sdl) +{ + grub_video_register (&grub_video_sdl_adapter); +} + +GRUB_MOD_FINI(sdl) +{ + grub_video_unregister (&grub_video_sdl_adapter); +} diff --git a/video/fb/fbblit.c b/video/fb/fbblit.c index a0f44d268..15797be97 100644 --- a/video/fb/fbblit.c +++ b/video/fb/fbblit.c @@ -1170,10 +1170,15 @@ grub_video_fbblit_blend_XXXA8888_1bit (struct grub_video_fbblit_info *dst, grub_uint8_t a; if (*srcptr & srcmask) - color = fgcolor; + { + color = fgcolor; + a = src->mode_info->fg_alpha; + } else - color = bgcolor; - a = (color >> 24) & 0xff; + { + color = bgcolor; + a = src->mode_info->bg_alpha; + } if (a == 255) *(grub_uint32_t *) dstptr = color; diff --git a/video/fb/video_fb.c b/video/fb/video_fb.c index 5f2917da6..9c5577bb9 100644 --- a/video/fb/video_fb.c +++ b/video/fb/video_fb.c @@ -66,6 +66,8 @@ grub_video_fb_init (void) grub_err_t grub_video_fb_fini (void) { + /* TODO: destroy render targets. */ + grub_free (palette); render_target = 0; palette = 0; @@ -974,32 +976,85 @@ grub_video_fb_scroll (grub_video_color_t color, int dx, int dy) { /* 3. Move data in render target. */ struct grub_video_fbblit_info target; - grub_uint8_t *src; - grub_uint8_t *dst; - int j; + int i, j; + int linedelta, linelen; target.mode_info = &render_target->mode_info; target.data = render_target->data; - /* Check vertical direction of the move. */ - if (dy <= 0) - /* 3a. Move data upwards. */ - for (j = 0; j < height; j++) - { - dst = grub_video_fb_get_video_ptr (&target, dst_x, dst_y + j); - src = grub_video_fb_get_video_ptr (&target, src_x, src_y + j); - grub_memmove (dst, src, - width * target.mode_info->bytes_per_pixel); - } + linedelta = target.mode_info->pitch + - width * target.mode_info->bytes_per_pixel; + linelen = width * target.mode_info->bytes_per_pixel; +#define DO_SCROLL \ + /* Check vertical direction of the move. */ \ + if (dy < 0 || (dy == 0 && dx < 0)) \ + { \ + dst = (void *) grub_video_fb_get_video_ptr (&target, \ + dst_x, dst_y); \ + src = (void *) grub_video_fb_get_video_ptr (&target, \ + src_x, src_y); \ + /* 3a. Move data upwards. */ \ + for (j = 0; j < height; j++) \ + { \ + for (i = 0; i < linelen; i++) \ + *(dst++) = *(src++); \ + dst += linedelta; \ + src += linedelta; \ + } \ + } \ + else \ + { \ + /* 3b. Move data downwards. */ \ + dst = (void *) grub_video_fb_get_video_ptr (&target, \ + dst_x + width, \ + dst_y + height - 1); \ + src = (void *) grub_video_fb_get_video_ptr (&target, \ + src_x + width, \ + src_y + height - 1); \ + dst--; \ + src--; \ + for (j = 0; j < height; j++) \ + { \ + for (i = 0; i < linelen; i++) \ + *(dst--) = *(src--); \ + dst -= linedelta; \ + src -= linedelta; \ + } \ + } + + /* If everything is aligned on 32-bit use 32-bit copy. */ + if ((grub_addr_t) grub_video_fb_get_video_ptr (&target, src_x, src_y) + % sizeof (grub_uint32_t) == 0 + && (grub_addr_t) grub_video_fb_get_video_ptr (&target, dst_x, dst_y) + % sizeof (grub_uint32_t) == 0 + && linelen % sizeof (grub_uint32_t) == 0 + && linedelta % sizeof (grub_uint32_t) == 0) + { + grub_uint32_t *src, *dst; + linelen /= sizeof (grub_uint32_t); + linedelta /= sizeof (grub_uint32_t); + DO_SCROLL + } + /* If everything is aligned on 16-bit use 16-bit copy. */ + else if ((grub_addr_t) grub_video_fb_get_video_ptr (&target, src_x, src_y) + % sizeof (grub_uint16_t) == 0 + && (grub_addr_t) grub_video_fb_get_video_ptr (&target, + dst_x, dst_y) + % sizeof (grub_uint16_t) == 0 + && linelen % sizeof (grub_uint16_t) == 0 + && linedelta % sizeof (grub_uint16_t) == 0) + { + grub_uint16_t *src, *dst; + linelen /= sizeof (grub_uint16_t); + linedelta /= sizeof (grub_uint16_t); + DO_SCROLL + } + /* If not aligned at all use 8-bit copy. */ else - /* 3b. Move data downwards. */ - for (j = (height - 1); j >= 0; j--) - { - dst = grub_video_fb_get_video_ptr (&target, dst_x, dst_y + j); - src = grub_video_fb_get_video_ptr (&target, src_x, src_y + j); - grub_memmove (dst, src, - width * target.mode_info->bytes_per_pixel); - } + { + grub_uint8_t *src, *dst; + DO_SCROLL + } } /* 4. Fill empty space with specified color. In this implementation @@ -1048,7 +1103,7 @@ grub_video_fb_create_render_target (struct grub_video_fbrender_target **result, || (width == 0) || (height == 0)) return grub_error (GRUB_ERR_BAD_ARGUMENT, - "invalid argument given."); + "invalid argument given"); /* Allocate memory for render target. */ target = grub_malloc (sizeof (struct grub_video_fbrender_target)); @@ -1168,7 +1223,7 @@ grub_video_fb_set_active_render_target (struct grub_video_fbrender_target *targe { if (! target->data) return grub_error (GRUB_ERR_BAD_ARGUMENT, - "invalid render target given."); + "invalid render target given"); render_target = target; @@ -1182,3 +1237,53 @@ grub_video_fb_get_active_render_target (struct grub_video_fbrender_target **targ return GRUB_ERR_NONE; } + +static grub_err_t +doublebuf_blit_update_screen (struct grub_video_fbrender_target *front, + struct grub_video_fbrender_target *back) +{ + grub_memcpy (front->data, back->data, + front->mode_info.pitch * front->mode_info.height); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_video_fb_doublebuf_blit_init (struct grub_video_fbrender_target **front, + struct grub_video_fbrender_target **back, + grub_video_fb_doublebuf_update_screen_t *update_screen, + struct grub_video_mode_info mode_info, + void *framebuf) +{ + grub_err_t err; + int page_size = mode_info.pitch * mode_info.height; + void *offscreen_buffer; + + err = grub_video_fb_create_render_target_from_pointer (front, &mode_info, + framebuf); + if (err) + return err; + + offscreen_buffer = grub_malloc (page_size); + if (! offscreen_buffer) + { + grub_video_fb_delete_render_target (*front); + *front = 0; + return grub_errno; + } + + err = grub_video_fb_create_render_target_from_pointer (back, &mode_info, + offscreen_buffer); + + if (err) + { + grub_video_fb_delete_render_target (*front); + grub_free (offscreen_buffer); + *front = 0; + return grub_errno; + } + (*back)->is_allocated = 1; + + *update_screen = doublebuf_blit_update_screen; + + return GRUB_ERR_NONE; +} diff --git a/video/i386/pc/vbe.c b/video/i386/pc/vbe.c index a285b26ba..72b8f1831 100644 --- a/video/i386/pc/vbe.c +++ b/video/i386/pc/vbe.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -33,16 +34,31 @@ static int vbe_detected = -1; static struct grub_vbe_info_block controller_info; static struct grub_vbe_mode_info_block active_vbe_mode_info; +/* Track last mode to support cards which fail on get_mode. */ +static grub_uint32_t last_set_mode = 3; + static struct { struct grub_video_mode_info mode_info; - struct grub_video_render_target *render_target; + struct grub_video_render_target *front_target; + struct grub_video_render_target *back_target; unsigned int bytes_per_scan_line; unsigned int bytes_per_pixel; grub_uint32_t active_vbe_mode; grub_uint8_t *ptr; int index_color_mode; + + char *offscreen_buffer; + + grub_size_t page_size; /* The size of a page in bytes. */ + + /* For page flipping strategy. */ + int displayed_page; /* The page # that is the front buffer. */ + int render_page; /* The page # that is the back buffer. */ + + /* Virtual functions. */ + grub_video_fb_doublebuf_update_screen_t update_screen; } framebuffer; static grub_uint32_t initial_vbe_mode; @@ -160,6 +176,7 @@ grub_vbe_set_video_mode (grub_uint32_t vbe_mode, status = grub_vbe_bios_set_mode (vbe_mode, 0); if (status != GRUB_VBE_STATUS_OK) return grub_error (GRUB_ERR_BAD_DEVICE, "cannot set VBE mode %x", vbe_mode); + last_set_mode = vbe_mode; /* Save information for later usage. */ framebuffer.active_vbe_mode = vbe_mode; @@ -203,6 +220,7 @@ grub_vbe_set_video_mode (grub_uint32_t vbe_mode, case 8: framebuffer.bytes_per_pixel = 1; break; default: grub_vbe_bios_set_mode (old_vbe_mode, 0); + last_set_mode = old_vbe_mode; return grub_error (GRUB_ERR_BAD_DEVICE, "cannot set VBE mode %x", vbe_mode); @@ -256,8 +274,9 @@ grub_vbe_get_video_mode (grub_uint32_t *mode) /* Try to query current mode from VESA BIOS. */ status = grub_vbe_bios_get_mode (mode); + /* XXX: ATI cards don't support get_mode. */ if (status != GRUB_VBE_STATUS_OK) - return grub_error (GRUB_ERR_BAD_DEVICE, "cannot get current VBE mode"); + *mode = last_set_mode; return GRUB_ERR_NONE; } @@ -344,25 +363,206 @@ static grub_err_t grub_video_vbe_fini (void) { grub_vbe_status_t status; + grub_err_t err; /* Restore old video mode. */ status = grub_vbe_bios_set_mode (initial_vbe_mode, 0); if (status != GRUB_VBE_STATUS_OK) /* TODO: Decide, is this something we want to do. */ return grub_errno; + last_set_mode = initial_vbe_mode; /* TODO: Free any resources allocated by driver. */ grub_free (vbe_mode_list); vbe_mode_list = NULL; - /* TODO: destroy render targets. */ + err = grub_video_fb_fini (); + grub_free (framebuffer.offscreen_buffer); + return err; +} - return grub_video_fb_fini (); +/* + Set framebuffer render target page and display the proper page, based on + `doublebuf_state.render_page' and `doublebuf_state.displayed_page', + respectively. +*/ +static grub_err_t +doublebuf_pageflipping_commit (void) +{ + /* Tell the video adapter to display the new front page. */ + int display_start_line + = framebuffer.mode_info.height * framebuffer.displayed_page; + + grub_vbe_status_t vbe_err = + grub_vbe_bios_set_display_start (0, display_start_line); + + if (vbe_err != GRUB_VBE_STATUS_OK) + return grub_error (GRUB_ERR_IO, "couldn't commit pageflip"); + + return 0; } +static grub_err_t +doublebuf_pageflipping_update_screen (struct grub_video_fbrender_target *front + __attribute__ ((unused)), + struct grub_video_fbrender_target *back + __attribute__ ((unused))) +{ + int new_displayed_page; + struct grub_video_fbrender_target *target; + grub_err_t err; + + /* Swap the page numbers in the framebuffer struct. */ + new_displayed_page = framebuffer.render_page; + framebuffer.render_page = framebuffer.displayed_page; + framebuffer.displayed_page = new_displayed_page; + + err = doublebuf_pageflipping_commit (); + if (err) + { + /* Restore previous state. */ + framebuffer.render_page = framebuffer.displayed_page; + framebuffer.displayed_page = new_displayed_page; + return err; + } + + if (framebuffer.mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP) + grub_memcpy (framebuffer.ptr + framebuffer.render_page + * framebuffer.page_size, framebuffer.ptr + + framebuffer.displayed_page * framebuffer.page_size, + framebuffer.page_size); + + target = framebuffer.back_target; + framebuffer.back_target = framebuffer.front_target; + framebuffer.front_target = target; + + err = grub_video_fb_get_active_render_target (&target); + if (err) + return err; + + if (target == framebuffer.back_target) + err = grub_video_fb_set_active_render_target (framebuffer.front_target); + else if (target == framebuffer.front_target) + err = grub_video_fb_set_active_render_target (framebuffer.back_target); + + return err; +} + +static grub_err_t +doublebuf_pageflipping_init (void) +{ + /* Get video RAM size in bytes. */ + grub_size_t vram_size = controller_info.total_memory << 16; + grub_err_t err; + + framebuffer.page_size = + framebuffer.mode_info.pitch * framebuffer.mode_info.height; + + if (2 * framebuffer.page_size > vram_size) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "Not enough video memory for double buffering."); + + framebuffer.displayed_page = 0; + framebuffer.render_page = 1; + + framebuffer.update_screen = doublebuf_pageflipping_update_screen; + + err = grub_video_fb_create_render_target_from_pointer (&framebuffer.front_target, &framebuffer.mode_info, framebuffer.ptr); + if (err) + return err; + + err = grub_video_fb_create_render_target_from_pointer (&framebuffer.back_target, &framebuffer.mode_info, framebuffer.ptr + framebuffer.page_size); + if (err) + { + grub_video_fb_delete_render_target (framebuffer.front_target); + return err; + } + + /* Set the framebuffer memory data pointer and display the right page. */ + err = doublebuf_pageflipping_commit (); + if (err) + { + grub_video_fb_delete_render_target (framebuffer.front_target); + grub_video_fb_delete_render_target (framebuffer.back_target); + return err; + } + + return GRUB_ERR_NONE; +} + +/* Select the best double buffering mode available. */ +static grub_err_t +double_buffering_init (unsigned int mode_type, unsigned int mode_mask) +{ + grub_err_t err; + int updating_swap_needed; + + updating_swap_needed + = grub_video_check_mode_flag (mode_type, mode_mask, + GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP, 0); + + /* Do double buffering only if it's either requested or efficient. */ + if (grub_video_check_mode_flag (mode_type, mode_mask, + GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED, + !updating_swap_needed)) + { + framebuffer.mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + if (updating_swap_needed) + framebuffer.mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP; + err = doublebuf_pageflipping_init (); + if (!err) + return GRUB_ERR_NONE; + + framebuffer.mode_info.mode_type + &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); + + grub_errno = GRUB_ERR_NONE; + } + + if (grub_video_check_mode_flag (mode_type, mode_mask, + GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED, + 0)) + { + framebuffer.mode_info.mode_type + |= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); + + err = grub_video_fb_doublebuf_blit_init (&framebuffer.front_target, + &framebuffer.back_target, + &framebuffer.update_screen, + framebuffer.mode_info, + framebuffer.ptr); + + if (!err) + return GRUB_ERR_NONE; + + framebuffer.mode_info.mode_type + &= ~(GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED + | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); + + grub_errno = GRUB_ERR_NONE; + } + + /* Fall back to no double buffering. */ + err = grub_video_fb_create_render_target_from_pointer (&framebuffer.front_target, &framebuffer.mode_info, framebuffer.ptr); + + if (err) + return err; + + framebuffer.back_target = framebuffer.front_target; + framebuffer.update_screen = 0; + + framebuffer.mode_info.mode_type &= ~GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + + return GRUB_ERR_NONE; +} + + + static grub_err_t grub_video_vbe_setup (unsigned int width, unsigned int height, - unsigned int mode_type) + unsigned int mode_type, unsigned int mode_mask) { grub_uint16_t *p; struct grub_vbe_mode_info_block vbe_mode_info; @@ -391,10 +591,6 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, /* If not available, skip it. */ continue; - if ((vbe_mode_info.mode_attributes & 0x002) == 0) - /* Not enough information. */ - continue; - if ((vbe_mode_info.mode_attributes & 0x008) == 0) /* Monochrome is unusable. */ continue; @@ -412,32 +608,40 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, /* Not compatible memory model. */ continue; - if ((vbe_mode_info.x_resolution != width) - || (vbe_mode_info.y_resolution != height)) + if (((vbe_mode_info.x_resolution != width) + || (vbe_mode_info.y_resolution != height)) && width != 0 && height != 0) /* Non matching resolution. */ continue; /* Check if user requested RGB or index color mode. */ - if ((mode_type & GRUB_VIDEO_MODE_TYPE_COLOR_MASK) != 0) + if ((mode_mask & GRUB_VIDEO_MODE_TYPE_COLOR_MASK) != 0) { - if (((mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0) - && (vbe_mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL)) - /* Requested only index color modes. */ - continue; + unsigned my_mode_type = 0; - if (((mode_type & GRUB_VIDEO_MODE_TYPE_RGB) != 0) - && (vbe_mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR)) - /* Requested only RGB modes. */ - continue; + if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL) + my_mode_type |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + + if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR) + my_mode_type |= GRUB_VIDEO_MODE_TYPE_RGB; + + if ((my_mode_type & mode_mask + & (GRUB_VIDEO_MODE_TYPE_RGB | GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)) + != (mode_type & mode_mask + & (GRUB_VIDEO_MODE_TYPE_RGB + | GRUB_VIDEO_MODE_TYPE_INDEX_COLOR))) + continue; } /* If there is a request for specific depth, ignore others. */ if ((depth != 0) && (vbe_mode_info.bits_per_pixel != depth)) continue; - /* Select mode with most number of bits per pixel. */ + /* Select mode with most of "volume" (size of framebuffer in bits). */ if (best_vbe_mode != 0) - if (vbe_mode_info.bits_per_pixel < best_vbe_mode_info.bits_per_pixel) + if ((grub_uint64_t) vbe_mode_info.bits_per_pixel + * vbe_mode_info.x_resolution * vbe_mode_info.y_resolution + < (grub_uint64_t) best_vbe_mode_info.bits_per_pixel + * best_vbe_mode_info.x_resolution * best_vbe_mode_info.y_resolution) continue; /* Save so far best mode information for later use. */ @@ -480,12 +684,12 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, framebuffer.mode_info.blit_format = grub_video_get_blit_format (&framebuffer.mode_info); - err = grub_video_fb_create_render_target_from_pointer (&framebuffer.render_target, &framebuffer.mode_info, framebuffer.ptr); - + /* Set up double buffering and targets. */ + err = double_buffering_init (mode_type, mode_mask); if (err) return err; - err = grub_video_fb_set_active_render_target (framebuffer.render_target); + err = grub_video_fb_set_active_render_target (framebuffer.back_target); if (err) return err; @@ -497,7 +701,7 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, } /* Couldn't found matching mode. */ - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found."); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found"); } static grub_err_t @@ -522,7 +726,15 @@ grub_video_vbe_set_palette (unsigned int start, unsigned int count, static grub_err_t grub_video_vbe_swap_buffers (void) { - /* TODO: Implement buffer swapping. */ + grub_err_t err; + if (!framebuffer.update_screen) + return GRUB_ERR_NONE; + + err = framebuffer.update_screen (framebuffer.front_target, + framebuffer.back_target); + if (err) + return err; + return GRUB_ERR_NONE; } @@ -530,30 +742,46 @@ static grub_err_t grub_video_vbe_set_active_render_target (struct grub_video_render_target *target) { if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY) - target = framebuffer.render_target; + target = framebuffer.back_target; return grub_video_fb_set_active_render_target (target); } +static grub_err_t +grub_video_vbe_get_active_render_target (struct grub_video_render_target **target) +{ + grub_err_t err; + err = grub_video_fb_get_active_render_target (target); + if (err) + return err; + + if (*target == framebuffer.back_target) + *target = GRUB_VIDEO_RENDER_TARGET_DISPLAY; + + return GRUB_ERR_NONE; +} + static grub_err_t grub_video_vbe_get_info_and_fini (struct grub_video_mode_info *mode_info, void **framebuf) { grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info)); - *framebuf = (char *) framebuffer.ptr; + *framebuf = (char *) framebuffer.ptr + + framebuffer.displayed_page * framebuffer.page_size; grub_free (vbe_mode_list); vbe_mode_list = NULL; grub_video_fb_fini (); + grub_free (framebuffer.offscreen_buffer); return GRUB_ERR_NONE; } - static struct grub_video_adapter grub_video_vbe_adapter = { .name = "VESA BIOS Extension Video Driver", + .id = GRUB_VIDEO_DRIVER_VBE, .init = grub_video_vbe_init, .fini = grub_video_vbe_fini, @@ -576,7 +804,7 @@ static struct grub_video_adapter grub_video_vbe_adapter = .create_render_target = grub_video_fb_create_render_target, .delete_render_target = grub_video_fb_delete_render_target, .set_active_render_target = grub_video_vbe_set_active_render_target, - .get_active_render_target = grub_video_fb_get_active_render_target, + .get_active_render_target = grub_video_vbe_get_active_render_target, .next = 0 }; diff --git a/video/i386/pc/vga.c b/video/i386/pc/vga.c new file mode 100644 index 000000000..222a71272 --- /dev/null +++ b/video/i386/pc/vga.c @@ -0,0 +1,412 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,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 . + */ + +#define grub_video_render_target grub_video_fbrender_target + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VGA_WIDTH 640 +#define VGA_HEIGHT 350 +#define VGA_MEM ((grub_uint8_t *) GRUB_MEMORY_MACHINE_VGA_ADDR) +#define PAGE_OFFSET(x) ((x) * (VGA_WIDTH * VGA_HEIGHT / 8)) + +static unsigned char text_mode; +static unsigned char saved_map_mask; + +static struct +{ + struct grub_video_mode_info mode_info; + struct grub_video_render_target *render_target; + grub_uint8_t *temporary_buffer; + int front_page; + int back_page; +} framebuffer; + +#define SEQUENCER_ADDR_PORT 0x3C4 +#define SEQUENCER_DATA_PORT 0x3C5 +#define MAP_MASK_REGISTER 0x02 + +#define CRTC_ADDR_PORT 0x3D4 +#define CRTC_DATA_PORT 0x3D5 +#define START_ADDR_HIGH_REGISTER 0x0C +#define START_ADDR_LOW_REGISTER 0x0D + +#define GRAPHICS_ADDR_PORT 0x3CE +#define GRAPHICS_DATA_PORT 0x3CF +#define READ_MAP_REGISTER 0x04 + +#define INPUT_STATUS1_REGISTER 0x3DA +#define INPUT_STATUS1_VERTR_BIT 0x08 + +static inline void +wait_vretrace (void) +{ + /* Wait until there is a vertical retrace. */ + while (! (grub_inb (INPUT_STATUS1_REGISTER) & INPUT_STATUS1_VERTR_BIT)); +} + +/* Get Map Mask Register. */ +static unsigned char +get_map_mask (void) +{ + unsigned char old_addr; + unsigned char old_data; + + old_addr = grub_inb (SEQUENCER_ADDR_PORT); + grub_outb (MAP_MASK_REGISTER, SEQUENCER_ADDR_PORT); + + old_data = grub_inb (SEQUENCER_DATA_PORT); + + grub_outb (old_addr, SEQUENCER_ADDR_PORT); + + return old_data; +} + +/* Set Map Mask Register. */ +static void +set_map_mask (unsigned char mask) +{ + unsigned char old_addr; + + old_addr = grub_inb (SEQUENCER_ADDR_PORT); + grub_outb (MAP_MASK_REGISTER, SEQUENCER_ADDR_PORT); + + grub_outb (mask, SEQUENCER_DATA_PORT); + + grub_outb (old_addr, SEQUENCER_ADDR_PORT); +} + +#if 0 +/* Set Read Map Register. */ +static void +set_read_map (unsigned char map) +{ + unsigned char old_addr; + + old_addr = grub_inb (GRAPHICS_ADDR_PORT); + + grub_outb (READ_MAP_REGISTER, GRAPHICS_ADDR_PORT); + grub_outb (map, GRAPHICS_DATA_PORT); + + grub_outb (old_addr, GRAPHICS_ADDR_PORT); +} +#endif + +/* Set start address. */ +static void +set_start_address (unsigned int start) +{ + unsigned char old_addr; + + old_addr = grub_inb (CRTC_ADDR_PORT); + + grub_outb (START_ADDR_LOW_REGISTER, CRTC_ADDR_PORT); + grub_outb (start & 0xFF, CRTC_DATA_PORT); + + grub_outb (START_ADDR_HIGH_REGISTER, CRTC_ADDR_PORT); + grub_outb (start >> 8, CRTC_DATA_PORT); + + grub_outb (old_addr, CRTC_ADDR_PORT); +} + +static int setup = 0; +static int is_target = 0; + +static grub_err_t +grub_video_vga_init (void) +{ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_vga_setup (unsigned int width, unsigned int height, + unsigned int mode_type, unsigned int mode_mask) +{ + grub_err_t err; + + if ((width && width != VGA_WIDTH) || (height && height != VGA_HEIGHT)) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching mode found"); + + framebuffer.temporary_buffer = grub_malloc (VGA_HEIGHT * VGA_WIDTH); + framebuffer.front_page = 0; + framebuffer.back_page = 0; + if (!framebuffer.temporary_buffer) + return grub_errno; + + saved_map_mask = get_map_mask (); + + text_mode = grub_vga_set_mode (0x10); + setup = 1; + set_map_mask (0x0f); + set_start_address (PAGE_OFFSET (framebuffer.front_page)); + + framebuffer.mode_info.width = VGA_WIDTH; + framebuffer.mode_info.height = VGA_HEIGHT; + + framebuffer.mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + + if (grub_video_check_mode_flag (mode_type, mode_mask, + GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED, 1)) + { + framebuffer.back_page = 1; + framebuffer.mode_info.mode_type |= GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED; + } + + framebuffer.mode_info.bpp = 8; + framebuffer.mode_info.bytes_per_pixel = 1; + framebuffer.mode_info.pitch = VGA_WIDTH; + framebuffer.mode_info.number_of_colors = 16; + framebuffer.mode_info.red_mask_size = 0; + framebuffer.mode_info.red_field_pos = 0; + framebuffer.mode_info.green_mask_size = 0; + framebuffer.mode_info.green_field_pos = 0; + framebuffer.mode_info.blue_mask_size = 0; + framebuffer.mode_info.blue_field_pos = 0; + framebuffer.mode_info.reserved_mask_size = 0; + framebuffer.mode_info.reserved_field_pos = 0; + + framebuffer.mode_info.blit_format + = grub_video_get_blit_format (&framebuffer.mode_info); + + err = grub_video_fb_create_render_target_from_pointer (&framebuffer.render_target, + &framebuffer.mode_info, + framebuffer.temporary_buffer); + + if (err) + { + grub_dprintf ("video", "Couldn't create FB target\n"); + return err; + } + + is_target = 1; + err = grub_video_fb_set_active_render_target (framebuffer.render_target); + + if (err) + return err; + + err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_vga_fini (void) +{ + if (setup) + { + set_map_mask (saved_map_mask); + grub_vga_set_mode (text_mode); + } + setup = 0; + grub_free (framebuffer.temporary_buffer); + framebuffer.temporary_buffer = 0; + return GRUB_ERR_NONE; +} + +static inline void +update_target (void) +{ + int plane; + + if (!is_target) + return; + + for (plane = 0x01; plane <= 0x08; plane <<= 1) + { + grub_uint8_t *ptr; + volatile grub_uint8_t *ptr2; + unsigned cbyte = 0; + int shift = 7; + set_map_mask (plane); + for (ptr = framebuffer.temporary_buffer, + ptr2 = VGA_MEM + PAGE_OFFSET (framebuffer.back_page); + ptr < framebuffer.temporary_buffer + VGA_WIDTH * VGA_HEIGHT; ptr++) + { + cbyte |= (!!(plane & *ptr)) << shift; + shift--; + if (shift == -1) + { + *ptr2++ = cbyte; + shift = 7; + cbyte = 0; + } + } + } +} + +static grub_err_t +grub_video_vga_blit_bitmap (struct grub_video_bitmap *bitmap, + enum grub_video_blit_operators oper, int x, int y, + int offset_x, int offset_y, + unsigned int width, unsigned int height) +{ + grub_err_t ret; + ret = grub_video_fb_blit_bitmap (bitmap, oper, x, y, offset_x, offset_y, + width, height); + update_target (); + return ret; +} + +static grub_err_t +grub_video_vga_blit_render_target (struct grub_video_fbrender_target *source, + enum grub_video_blit_operators oper, + int x, int y, int offset_x, int offset_y, + unsigned int width, unsigned int height) +{ + grub_err_t ret; + + ret = grub_video_fb_blit_render_target (source, oper, x, y, + offset_x, offset_y, width, height); + update_target (); + + return ret; +} + +static grub_err_t +grub_video_vga_set_active_render_target (struct grub_video_render_target *target) +{ + if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY) + { + is_target = 1; + target = framebuffer.render_target; + } + else + is_target = 0; + + return grub_video_fb_set_active_render_target (target); +} + +static grub_err_t +grub_video_vga_get_active_render_target (struct grub_video_render_target **target) +{ + grub_err_t err; + err = grub_video_fb_get_active_render_target (target); + if (err) + return err; + + if (*target == framebuffer.render_target) + *target = GRUB_VIDEO_RENDER_TARGET_DISPLAY; + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_vga_swap_buffers (void) +{ + if (!(framebuffer.mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED)) + return GRUB_ERR_NONE; + + /* Activate the other page. */ + framebuffer.front_page = !framebuffer.front_page; + framebuffer.back_page = !framebuffer.back_page; + wait_vretrace (); + set_start_address (PAGE_OFFSET (framebuffer.front_page)); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_vga_set_palette (unsigned int start __attribute__ ((unused)), + unsigned int count __attribute__ ((unused)), + struct grub_video_palette_data *palette_data __attribute__ ((unused))) +{ + return grub_error (GRUB_ERR_IO, "can't change palette"); +} + +static grub_err_t +grub_video_vga_get_info_and_fini (struct grub_video_mode_info *mode_info, + void **framebuf) +{ + set_map_mask (0xf); + + grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info)); + mode_info->bpp = 1; + mode_info->bytes_per_pixel = 0; + mode_info->pitch = VGA_WIDTH / 8; + mode_info->number_of_colors = 1; + + mode_info->bg_red = 0; + mode_info->bg_green = 0; + mode_info->bg_blue = 0; + mode_info->bg_alpha = 255; + + mode_info->fg_red = 255; + mode_info->fg_green = 255; + mode_info->fg_blue = 255; + mode_info->fg_alpha = 255; + + *framebuf = VGA_MEM + PAGE_OFFSET (framebuffer.front_page); + + grub_video_fb_fini (); + grub_free (framebuffer.temporary_buffer); + framebuffer.temporary_buffer = 0; + setup = 0; + + return GRUB_ERR_NONE; +} + + +static struct grub_video_adapter grub_video_vga_adapter = + { + .name = "VGA Video Driver", + .id = GRUB_VIDEO_DRIVER_VGA, + + .init = grub_video_vga_init, + .fini = grub_video_vga_fini, + .setup = grub_video_vga_setup, + .get_info = grub_video_fb_get_info, + .get_info_and_fini = grub_video_vga_get_info_and_fini, + .set_palette = grub_video_vga_set_palette, + .get_palette = grub_video_fb_get_palette, + .set_viewport = grub_video_fb_set_viewport, + .get_viewport = grub_video_fb_get_viewport, + .map_color = grub_video_fb_map_color, + .map_rgb = grub_video_fb_map_rgb, + .map_rgba = grub_video_fb_map_rgba, + .unmap_color = grub_video_fb_unmap_color, + .fill_rect = grub_video_fb_fill_rect, + .blit_bitmap = grub_video_vga_blit_bitmap, + .blit_render_target = grub_video_vga_blit_render_target, + .scroll = grub_video_fb_scroll, + .swap_buffers = grub_video_vga_swap_buffers, + .create_render_target = grub_video_fb_create_render_target, + .delete_render_target = grub_video_fb_delete_render_target, + .set_active_render_target = grub_video_vga_set_active_render_target, + .get_active_render_target = grub_video_vga_get_active_render_target, + + .next = 0 + }; + +GRUB_MOD_INIT(vga) +{ + grub_video_register (&grub_video_vga_adapter); +} + +GRUB_MOD_FINI(vga) +{ + grub_video_unregister (&grub_video_vga_adapter); +} diff --git a/video/ieee1275.c b/video/ieee1275.c new file mode 100644 index 000000000..5c6bc1594 --- /dev/null +++ b/video/ieee1275.c @@ -0,0 +1,300 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,2009 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 . + */ + +#define grub_video_render_target grub_video_fbrender_target + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Only 8-bit indexed color is supported for now. */ + +static unsigned old_width, old_height; +static int restore_needed; +static char *display; + +static struct +{ + struct grub_video_mode_info mode_info; + struct grub_video_render_target *render_target; + grub_uint8_t *ptr; +} framebuffer; + +static grub_err_t +grub_video_ieee1275_set_palette (unsigned int start, unsigned int count, + struct grub_video_palette_data *palette_data); + +static void +set_video_mode (unsigned width __attribute__ ((unused)), + unsigned height __attribute__ ((unused))) +{ + /* TODO */ +} + +static void +find_display (void) +{ + auto int hook (struct grub_ieee1275_devalias *alias); + int hook (struct grub_ieee1275_devalias *alias) + { + if (grub_strcmp (alias->type, "display") == 0) + { + grub_dprintf ("video", "Found display %s\n", alias->path); + display = grub_strdup (alias->path); + return 1; + } + return 0; + } + + grub_ieee1275_devices_iterate (hook); +} + +static grub_err_t +grub_video_ieee1275_init (void) +{ + grub_memset (&framebuffer, 0, sizeof(framebuffer)); + return grub_video_fb_init (); +} + +static grub_err_t +grub_video_ieee1275_fini (void) +{ + if (restore_needed) + { + set_video_mode (old_width, old_height); + restore_needed = 0; + } + return grub_video_fb_fini (); +} + +static grub_err_t +grub_video_ieee1275_fill_mode_info (grub_ieee1275_phandle_t dev, + struct grub_video_mode_info *out) +{ + grub_uint32_t tmp; + + grub_memset (out, 0, sizeof (*out)); + + if (grub_ieee1275_get_integer_property (dev, "width", &tmp, + sizeof (tmp), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display width."); + out->width = tmp; + + if (grub_ieee1275_get_integer_property (dev, "height", &tmp, + sizeof (tmp), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display height."); + out->height = tmp; + + if (grub_ieee1275_get_integer_property (dev, "linebytes", &tmp, + sizeof (tmp), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display pitch."); + out->pitch = tmp; + + out->mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + out->bpp = 8; + out->bytes_per_pixel = 1; + out->number_of_colors = 256; + + out->blit_format = grub_video_get_blit_format (out); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_ieee1275_setup (unsigned int width, unsigned int height, + unsigned int mode_type __attribute__ ((unused)), + unsigned int mode_mask __attribute__ ((unused))) +{ + grub_uint32_t current_width, current_height, address; + grub_err_t err; + grub_ieee1275_phandle_t dev; + + if (!display) + return grub_error (GRUB_ERR_IO, "Couldn't find display device."); + + if (grub_ieee1275_finddevice (display, &dev)) + return grub_error (GRUB_ERR_IO, "Couldn't open display device."); + + if (grub_ieee1275_get_integer_property (dev, "width", ¤t_width, + sizeof (current_width), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display width."); + + if (grub_ieee1275_get_integer_property (dev, "height", ¤t_height, + sizeof (current_width), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display height."); + + if ((width == current_width && height == current_height) + || (width == 0 && height == 0)) + { + grub_dprintf ("video", "IEEE1275: keeping current mode %dx%d\n", + current_width, current_height); + } + else + { + grub_dprintf ("video", "IEEE1275: Setting mode %dx%d\n", width, height); + /* TODO. */ + return grub_error (GRUB_ERR_IO, "can't set mode %dx%d", width, height); + } + + err = grub_video_ieee1275_fill_mode_info (dev, &framebuffer.mode_info); + if (err) + { + grub_dprintf ("video", "IEEE1275: couldn't fill mode info\n"); + return err; + } + + if (grub_ieee1275_get_integer_property (dev, "address", (void *) &address, + sizeof (address), 0)) + return grub_error (GRUB_ERR_IO, "Couldn't retrieve display address."); + + /* For some reason sparc64 uses 32-bit pointer too. */ + framebuffer.ptr = (void *) (grub_addr_t) address; + + grub_video_ieee1275_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); + + grub_dprintf ("video", "IEEE1275: initialising FB @ %p %dx%dx%d\n", + framebuffer.ptr, framebuffer.mode_info.width, + framebuffer.mode_info.height, framebuffer.mode_info.bpp); + + err = grub_video_fb_create_render_target_from_pointer + (&framebuffer.render_target, &framebuffer.mode_info, framebuffer.ptr); + + if (err) + { + grub_dprintf ("video", "IEEE1275: Couldn't create FB target\n"); + return err; + } + + err = grub_video_fb_set_active_render_target (framebuffer.render_target); + + if (err) + { + grub_dprintf ("video", "IEEE1275: Couldn't set FB target\n"); + return err; + } + + err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); + + if (err) + grub_dprintf ("video", "IEEE1275: Couldn't set palette\n"); + else + grub_dprintf ("video", "IEEE1275: Success\n"); + + return err; +} + +static grub_err_t +grub_video_ieee1275_swap_buffers (void) +{ + /* TODO: Implement buffer swapping. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_ieee1275_set_active_render_target (struct grub_video_render_target *target) +{ + if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY) + target = framebuffer.render_target; + + return grub_video_fb_set_active_render_target (target); +} + +static grub_err_t +grub_video_ieee1275_get_info_and_fini (struct grub_video_mode_info *mode_info, + void **framebuf) +{ + grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info)); + *framebuf = (char *) framebuffer.ptr; + + grub_video_fb_fini (); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_ieee1275_set_palette (unsigned int start, unsigned int count, + struct grub_video_palette_data *palette_data) +{ + grub_err_t err; + struct grub_video_palette_data fb_palette_data[256]; + + err = grub_video_fb_set_palette (start, count, palette_data); + if (err) + return err; + + grub_video_fb_get_palette (0, 256, fb_palette_data); + + /* TODO. */ + + return GRUB_ERR_NONE; +} + +static struct grub_video_adapter grub_video_ieee1275_adapter = + { + .name = "IEEE1275 video driver", + + .init = grub_video_ieee1275_init, + .fini = grub_video_ieee1275_fini, + .setup = grub_video_ieee1275_setup, + .get_info = grub_video_fb_get_info, + .get_info_and_fini = grub_video_ieee1275_get_info_and_fini, + .set_palette = grub_video_ieee1275_set_palette, + .get_palette = grub_video_fb_get_palette, + .set_viewport = grub_video_fb_set_viewport, + .get_viewport = grub_video_fb_get_viewport, + .map_color = grub_video_fb_map_color, + .map_rgb = grub_video_fb_map_rgb, + .map_rgba = grub_video_fb_map_rgba, + .unmap_color = grub_video_fb_unmap_color, + .fill_rect = grub_video_fb_fill_rect, + .blit_bitmap = grub_video_fb_blit_bitmap, + .blit_render_target = grub_video_fb_blit_render_target, + .scroll = grub_video_fb_scroll, + .swap_buffers = grub_video_ieee1275_swap_buffers, + .create_render_target = grub_video_fb_create_render_target, + .delete_render_target = grub_video_fb_delete_render_target, + .set_active_render_target = grub_video_ieee1275_set_active_render_target, + .get_active_render_target = grub_video_fb_get_active_render_target, + + .next = 0 + }; + +GRUB_MOD_INIT(ieee1275_fb) +{ + find_display (); + if (display) + grub_video_register (&grub_video_ieee1275_adapter); +} + +GRUB_MOD_FINI(ieee1275_fb) +{ + if (restore_needed) + { + set_video_mode (old_width, old_height); + restore_needed = 0; + } + if (display) + grub_video_unregister (&grub_video_ieee1275_adapter); + grub_free (display); +} diff --git a/video/readers/jpeg.c b/video/readers/jpeg.c index 460a52872..9d88163bd 100644 --- a/video/readers/jpeg.c +++ b/video/readers/jpeg.c @@ -54,6 +54,10 @@ static const grub_uint8_t jpeg_zigzag_order[64] = { 53, 60, 61, 54, 47, 55, 62, 63 }; +#ifdef JPEG_DEBUG +static grub_command_t cmd; +#endif + typedef int jpeg_data_unit_t[64]; struct grub_jpeg_data @@ -149,10 +153,11 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num) static int grub_jpeg_get_huff_code (struct grub_jpeg_data *data, int id) { - int code, i; + int code; + unsigned i; code = 0; - for (i = 0; i < 16; i++) + for (i = 0; i < ARRAY_SIZE (data->huff_maxval[id]); i++) { code <<= 1; if (grub_jpeg_get_bit (data)) @@ -167,47 +172,51 @@ grub_jpeg_get_huff_code (struct grub_jpeg_data *data, int id) static grub_err_t grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) { - int id, ac, i, n, base, ofs; + int id, ac, n, base, ofs; grub_uint32_t next_marker; grub_uint8_t count[16]; + unsigned i; next_marker = data->file->offset; next_marker += grub_jpeg_get_word (data); - id = grub_jpeg_get_byte (data); - ac = (id >> 4); - id &= 0xF; - if (id > 1) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "jpeg: too many huffman tables"); - - if (grub_file_read (data->file, &count, sizeof (count)) != - sizeof (count)) - return grub_errno; - - n = 0; - for (i = 0; i < 16; i++) - n += count[i]; - - id += ac * 2; - data->huff_value[id] = grub_malloc (n); - if (grub_errno) - return grub_errno; - - if (grub_file_read (data->file, data->huff_value[id], n) != n) - return grub_errno; - - base = 0; - ofs = 0; - for (i = 0; i < 16; i++) + while (data->file->offset + sizeof (count) + 1 <= next_marker) { - base += count[i]; - ofs += count[i]; + id = grub_jpeg_get_byte (data); + ac = (id >> 4) & 1; + id &= 0xF; + if (id > 1) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: too many huffman tables"); - data->huff_maxval[id][i] = base; - data->huff_offset[id][i] = ofs - base; + if (grub_file_read (data->file, &count, sizeof (count)) != + sizeof (count)) + return grub_errno; - base <<= 1; + n = 0; + for (i = 0; i < ARRAY_SIZE (count); i++) + n += count[i]; + + id += ac * 2; + data->huff_value[id] = grub_malloc (n); + if (grub_errno) + return grub_errno; + + if (grub_file_read (data->file, data->huff_value[id], n) != n) + return grub_errno; + + base = 0; + ofs = 0; + for (i = 0; i < ARRAY_SIZE (count); i++) + { + base += count[i]; + ofs += count[i]; + + data->huff_maxval[id][i] = base; + data->huff_offset[id][i] = ofs - base; + + base <<= 1; + } } if (data->file->offset != next_marker) @@ -225,17 +234,24 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) next_marker = data->file->offset; next_marker += grub_jpeg_get_word (data); - id = grub_jpeg_get_byte (data); - if (id >= 0x10) /* Upper 4-bit is precision. */ - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "jpeg: only 8-bit precision is supported"); + while (data->file->offset + sizeof (data->quan_table[id]) + 1 + <= next_marker) + { + id = grub_jpeg_get_byte (data); + if (id >= 0x10) /* Upper 4-bit is precision. */ + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); - if (id > 1) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "jpeg: too many quantization tables"); + if (id > 1) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: too many quantization tables"); - if (grub_file_read (data->file, &data->quan_table[id], 64) != 64) - return grub_errno; + if (grub_file_read (data->file, &data->quan_table[id], + sizeof (data->quan_table[id])) + != sizeof (data->quan_table[id])) + return grub_errno; + + } if (data->file->offset != next_marker) grub_error (GRUB_ERR_BAD_FILE_TYPE, @@ -440,7 +456,8 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du) static void grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) { - int pos, h1, h2, qt; + int h1, h2, qt; + unsigned pos; grub_memset (du, 0, sizeof (jpeg_data_unit_t)); @@ -453,7 +470,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) du[0] = data->dc_value[id] * (int) data->quan_table[qt][0]; pos = 1; - while (pos < 64) + while (pos < ARRAY_SIZE (data->quan_table[qt])) { int num, val; @@ -695,7 +712,7 @@ grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, #if defined(JPEG_DEBUG) static grub_err_t -grub_cmd_jpegtest (struct grub_arg_list *state __attribute__ ((unused)), +grub_cmd_jpegtest (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { struct grub_video_bitmap *bitmap = 0; @@ -725,21 +742,20 @@ static struct grub_video_bitmap_reader jpeg_reader = { .next = 0 }; -GRUB_MOD_INIT (video_reader_jpeg) +GRUB_MOD_INIT (jpeg) { grub_video_bitmap_reader_register (&jpg_reader); grub_video_bitmap_reader_register (&jpeg_reader); #if defined(JPEG_DEBUG) - grub_register_command ("jpegtest", grub_cmd_jpegtest, - GRUB_COMMAND_FLAG_BOTH, "jpegtest FILE", - "Tests loading of JPEG bitmap.", 0); + cmd = grub_register_command ("jpegtest", grub_cmd_jpegtest, + "FILE", "Tests loading of JPEG bitmap."); #endif } -GRUB_MOD_FINI (video_reader_jpeg) +GRUB_MOD_FINI (jpeg) { #if defined(JPEG_DEBUG) - grub_unregister_command ("jpegtest"); + grub_unregister_command (cmd); #endif grub_video_bitmap_reader_unregister (&jpeg_reader); grub_video_bitmap_reader_unregister (&jpg_reader); diff --git a/video/readers/png.c b/video/readers/png.c index c2008aeb2..2cec49e2f 100644 --- a/video/readers/png.c +++ b/video/readers/png.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009 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 @@ -73,6 +73,10 @@ #define DEFLATE_HUFF_LEN 16 +#ifdef PNG_DEBUG +static grub_command_t cmd; +#endif + struct huff_table { int *values, *maxval, *offset; @@ -866,7 +870,7 @@ grub_video_reader_png (struct grub_video_bitmap **bitmap, #if defined(PNG_DEBUG) static grub_err_t -grub_cmd_pngtest (struct grub_arg_list *state __attribute__ ((unused)), +grub_cmd_pngtest (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { struct grub_video_bitmap *bitmap = 0; @@ -890,20 +894,20 @@ static struct grub_video_bitmap_reader png_reader = { .next = 0 }; -GRUB_MOD_INIT (video_reader_png) +GRUB_MOD_INIT (png) { grub_video_bitmap_reader_register (&png_reader); #if defined(PNG_DEBUG) - grub_register_command ("pngtest", grub_cmd_pngtest, - GRUB_COMMAND_FLAG_BOTH, "pngtest FILE", - "Tests loading of PNG bitmap.", 0); + cmd = grub_register_command ("pngtest", grub_cmd_pngtest, + "FILE", + "Tests loading of PNG bitmap."); #endif } -GRUB_MOD_FINI (video_reader_png) +GRUB_MOD_FINI (png) { #if defined(PNG_DEBUG) - grub_unregister_command ("pngtest"); + grub_unregister_command (cmd); #endif grub_video_bitmap_reader_unregister (&png_reader); } diff --git a/video/readers/tga.c b/video/readers/tga.c index d0ca2770f..6c9e9d691 100644 --- a/video/readers/tga.c +++ b/video/readers/tga.c @@ -29,6 +29,7 @@ #if defined(TGA_DEBUG) #define dump_int_field(x) grub_printf( #x " = %d (0x%04x)\n", x, x); +static grub_command_t cmd; #endif enum @@ -370,7 +371,7 @@ grub_video_reader_tga (struct grub_video_bitmap **bitmap, default: grub_file_close (file); return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "Unsupported bitmap format (unknown encoding)."); + "unsupported bitmap format (unknown encoding)"); } /* Check that bitmap depth is supported. */ @@ -387,7 +388,7 @@ grub_video_reader_tga (struct grub_video_bitmap **bitmap, default: grub_file_close (file); return grub_error (GRUB_ERR_BAD_FILE_TYPE, - "Unsupported bitmap format (bpp=%d).", + "unsupported bitmap format (bpp=%d)", header.image_bpp); } @@ -452,7 +453,7 @@ grub_video_reader_tga (struct grub_video_bitmap **bitmap, #if defined(TGA_DEBUG) static grub_err_t -grub_cmd_tgatest (struct grub_arg_list *state __attribute__ ((unused)), +grub_cmd_tgatest (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { struct grub_video_bitmap *bitmap = 0; @@ -476,19 +477,19 @@ static struct grub_video_bitmap_reader tga_reader = { .next = 0 }; -GRUB_MOD_INIT(video_reader_tga) +GRUB_MOD_INIT(tga) { grub_video_bitmap_reader_register (&tga_reader); #if defined(TGA_DEBUG) - grub_register_command ("tgatest", grub_cmd_tgatest, GRUB_COMMAND_FLAG_BOTH, - "tgatest FILE", "Tests loading of TGA bitmap.", 0); + cmd = grub_register_command ("tgatest", grub_cmd_tgatest, + "FILE", "Tests loading of TGA bitmap."); #endif } -GRUB_MOD_FINI(video_reader_tga) +GRUB_MOD_FINI(tga) { #if defined(TGA_DEBUG) - grub_unregister_command ("tgatest"); + grub_unregister_command (cmd); #endif grub_video_bitmap_reader_unregister (&tga_reader); } diff --git a/video/sm712.c b/video/sm712.c new file mode 100644 index 000000000..33861beef --- /dev/null +++ b/video/sm712.c @@ -0,0 +1,230 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,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 . + */ + +#define grub_video_render_target grub_video_fbrender_target + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct +{ + struct grub_video_mode_info mode_info; + struct grub_video_render_target *render_target; + + unsigned int bytes_per_scan_line; + unsigned int bytes_per_pixel; + grub_uint8_t *ptr; + int index_color_mode; + int mapped; + grub_uint32_t base; + grub_pci_device_t dev; +} framebuffer; + +static grub_err_t +grub_video_sm712_video_init (void) +{ + /* Reset frame buffer. */ + grub_memset (&framebuffer, 0, sizeof(framebuffer)); + + return grub_video_fb_init (); +} + +static grub_err_t +grub_video_sm712_video_fini (void) +{ + if (framebuffer.mapped) + grub_pci_device_unmap_range (framebuffer.dev, framebuffer.ptr, + 1024 * 600 * 2); + + return grub_video_fb_fini (); +} + +static grub_err_t +grub_video_sm712_setup (unsigned int width, unsigned int height, + unsigned int mode_type, unsigned int mode_mask __attribute__ ((unused))) +{ + int depth; + grub_err_t err; + int found = 0; + + auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused))); + int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused))) + { + grub_pci_address_t addr; + grub_uint32_t class; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); + class = grub_pci_read (addr); + + if (((class >> 16) & 0xffff) != 0x0300 || pciid != 0x0712126f) + return 0; + + found = 1; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); + framebuffer.base = grub_pci_read (addr); + framebuffer.dev = dev; + + return 1; + } + + /* Decode depth from mode_type. If it is zero, then autodetect. */ + depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) + >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS; + + if ((width != 1024 && width != 0) || (height != 600 && height != 0) + || (depth != 16 && depth != 0)) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Only 1024x600x16 is supported"); + + grub_pci_iterate (find_card); + if (!found) + return grub_error (GRUB_ERR_IO, "Couldn't find graphics card"); + + if (found && framebuffer.base == 0) + { + /* FIXME: change framebuffer base */ + } + + /* Fill mode info details. */ + framebuffer.mode_info.width = 1024; + framebuffer.mode_info.height = 600; + framebuffer.mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_RGB; + framebuffer.mode_info.bpp = 16; + framebuffer.mode_info.bytes_per_pixel = 2; + framebuffer.mode_info.pitch = 1024 * 2; + framebuffer.mode_info.number_of_colors = 256; + framebuffer.mode_info.red_mask_size = 5; + framebuffer.mode_info.red_field_pos = 11; + framebuffer.mode_info.green_mask_size = 6; + framebuffer.mode_info.green_field_pos = 5; + framebuffer.mode_info.blue_mask_size = 5; + framebuffer.mode_info.blue_field_pos = 0; + framebuffer.mode_info.reserved_mask_size = 0; + framebuffer.mode_info.reserved_field_pos = 0; + framebuffer.mode_info.blit_format = grub_video_get_blit_format (&framebuffer.mode_info); + /* We can safely discard volatile attribute. */ + framebuffer.ptr = (void *) grub_pci_device_map_range (framebuffer.dev, + framebuffer.base, + 1024 * 600 * 2); + framebuffer.mapped = 1; + + err = grub_video_fb_create_render_target_from_pointer (&framebuffer.render_target, &framebuffer.mode_info, framebuffer.ptr); + + if (err) + return err; + + err = grub_video_fb_set_active_render_target (framebuffer.render_target); + + if (err) + return err; + + /* Copy default palette to initialize emulated palette. */ + err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); + return err; +} + +static grub_err_t +grub_video_sm712_set_palette (unsigned int start, unsigned int count, + struct grub_video_palette_data *palette_data) +{ + if (framebuffer.index_color_mode) + { + /* TODO: Implement setting indexed color mode palette to hardware. */ + } + + /* Then set color to emulated palette. */ + return grub_video_fb_set_palette (start, count, palette_data); +} + +static grub_err_t +grub_video_sm712_swap_buffers (void) +{ + /* TODO: Implement buffer swapping. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_sm712_set_active_render_target (struct grub_video_render_target *target) +{ + if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY) + target = framebuffer.render_target; + + return grub_video_fb_set_active_render_target (target); +} + +static grub_err_t +grub_video_sm712_get_info_and_fini (struct grub_video_mode_info *mode_info, + void **framebuf) +{ + grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info)); + *framebuf = (char *) framebuffer.ptr; + + grub_video_fb_fini (); + + return GRUB_ERR_NONE; +} + + +static struct grub_video_adapter grub_video_sm712_adapter = + { + .name = "SM712 Video Driver", + .id = GRUB_VIDEO_DRIVER_SM712, + + .init = grub_video_sm712_video_init, + .fini = grub_video_sm712_video_fini, + .setup = grub_video_sm712_setup, + .get_info = grub_video_fb_get_info, + .get_info_and_fini = grub_video_sm712_get_info_and_fini, + .set_palette = grub_video_sm712_set_palette, + .get_palette = grub_video_fb_get_palette, + .set_viewport = grub_video_fb_set_viewport, + .get_viewport = grub_video_fb_get_viewport, + .map_color = grub_video_fb_map_color, + .map_rgb = grub_video_fb_map_rgb, + .map_rgba = grub_video_fb_map_rgba, + .unmap_color = grub_video_fb_unmap_color, + .fill_rect = grub_video_fb_fill_rect, + .blit_bitmap = grub_video_fb_blit_bitmap, + .blit_render_target = grub_video_fb_blit_render_target, + .scroll = grub_video_fb_scroll, + .swap_buffers = grub_video_sm712_swap_buffers, + .create_render_target = grub_video_fb_create_render_target, + .delete_render_target = grub_video_fb_delete_render_target, + .set_active_render_target = grub_video_sm712_set_active_render_target, + .get_active_render_target = grub_video_fb_get_active_render_target, + + .next = 0 + }; + +GRUB_MOD_INIT(video_sm712) +{ + grub_video_register (&grub_video_sm712_adapter); +} + +GRUB_MOD_FINI(video_sm712) +{ + grub_video_unregister (&grub_video_sm712_adapter); +} diff --git a/video/video.c b/video/video.c index c1d66bdd0..42418f980 100644 --- a/video/video.c +++ b/video/video.c @@ -81,7 +81,7 @@ grub_err_t grub_video_get_info (struct grub_video_mode_info *mode_info) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); /* If mode_info is NULL just report that video adapter is active. */ if (! mode_info) @@ -93,6 +93,14 @@ grub_video_get_info (struct grub_video_mode_info *mode_info) return grub_video_adapter_active->get_info (mode_info); } +grub_video_driver_id_t +grub_video_get_driver_id (void) +{ + if (! grub_video_adapter_active) + return GRUB_VIDEO_DRIVER_NONE; + return grub_video_adapter_active->id; +} + /* Get information about active video mode. */ grub_err_t grub_video_get_info_and_fini (struct grub_video_mode_info *mode_info, @@ -101,7 +109,7 @@ grub_video_get_info_and_fini (struct grub_video_mode_info *mode_info, grub_err_t err; if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); err = grub_video_adapter_active->get_info_and_fini (mode_info, framebuffer); if (err) @@ -209,7 +217,7 @@ grub_video_set_palette (unsigned int start, unsigned int count, struct grub_video_palette_data *palette_data) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->set_palette (start, count, palette_data); } @@ -220,7 +228,7 @@ grub_video_get_palette (unsigned int start, unsigned int count, struct grub_video_palette_data *palette_data) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->get_palette (start, count, palette_data); } @@ -231,7 +239,7 @@ grub_video_set_viewport (unsigned int x, unsigned int y, unsigned int width, unsigned int height) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->set_viewport (x, y, width, height); } @@ -242,7 +250,7 @@ grub_video_get_viewport (unsigned int *x, unsigned int *y, unsigned int *width, unsigned int *height) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->get_viewport (x, y, width, height); } @@ -285,7 +293,7 @@ grub_video_unmap_color (grub_video_color_t color, grub_uint8_t *red, grub_uint8_t *alpha) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->unmap_color (color, red, @@ -300,7 +308,7 @@ grub_video_fill_rect (grub_video_color_t color, int x, int y, unsigned int width, unsigned int height) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->fill_rect (color, x, y, width, height); } @@ -313,7 +321,7 @@ grub_video_blit_bitmap (struct grub_video_bitmap *bitmap, unsigned int width, unsigned int height) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->blit_bitmap (bitmap, oper, x, y, offset_x, offset_y, @@ -328,7 +336,7 @@ grub_video_blit_render_target (struct grub_video_render_target *target, unsigned int width, unsigned int height) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->blit_render_target (target, oper, x, y, offset_x, offset_y, @@ -340,7 +348,7 @@ grub_err_t grub_video_scroll (grub_video_color_t color, int dx, int dy) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->scroll (color, dx, dy); } @@ -350,7 +358,7 @@ grub_err_t grub_video_swap_buffers (void) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->swap_buffers (); } @@ -362,7 +370,7 @@ grub_video_create_render_target (struct grub_video_render_target **result, unsigned int mode_type) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->create_render_target (result, width, height, @@ -374,7 +382,7 @@ grub_err_t grub_video_delete_render_target (struct grub_video_render_target *target) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->delete_render_target (target); } @@ -384,7 +392,7 @@ grub_err_t grub_video_set_active_render_target (struct grub_video_render_target *target) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->set_active_render_target (target); } @@ -394,26 +402,86 @@ grub_err_t grub_video_get_active_render_target (struct grub_video_render_target **target) { if (! grub_video_adapter_active) - return grub_error (GRUB_ERR_BAD_DEVICE, "No video mode activated"); + return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated"); return grub_video_adapter_active->get_active_render_target (target); } +/* Parse x[x]*/ +static grub_err_t +parse_modespec (const char *current_mode, int *width, int *height, int *depth) +{ + const char *value; + const char *param = current_mode; + + *width = *height = *depth = -1; + + if (grub_strcmp (param, "auto") == 0) + { + *width = *height = 0; + return GRUB_ERR_NONE; + } + + /* Find width value. */ + value = param; + param = grub_strchr(param, 'x'); + if (param == NULL) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Invalid mode: %s\n", + current_mode); + + param++; + + *width = grub_strtoul (value, 0, 0); + if (grub_errno != GRUB_ERR_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Invalid mode: %s\n", + current_mode); + + /* Find height value. */ + value = param; + param = grub_strchr(param, 'x'); + if (param == NULL) + { + *height = grub_strtoul (value, 0, 0); + if (grub_errno != GRUB_ERR_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Invalid mode: %s\n", + current_mode); + } + else + { + /* We have optional color depth value. */ + param++; + + *height = grub_strtoul (value, 0, 0); + if (grub_errno != GRUB_ERR_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Invalid mode: %s\n", + current_mode); + + /* Convert color depth value. */ + value = param; + *depth = grub_strtoul (value, 0, 0); + if (grub_errno != GRUB_ERR_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Invalid mode: %s\n", + current_mode); + } + return GRUB_ERR_NONE; +} + grub_err_t grub_video_set_mode (const char *modestring, - int NESTED_FUNC_ATTR (*hook) (grub_video_adapter_t p, - struct grub_video_mode_info *mode_info)) + unsigned int modemask, + unsigned int modevalue) { char *tmp; char *next_mode; char *current_mode; - char *param; - char *value; char *modevar; - int width = -1; - int height = -1; - int depth = -1; - int flags = 0; + + modevalue &= modemask; /* Take copy of env.var. as we don't want to modify that. */ modevar = grub_strdup (modestring); @@ -429,26 +497,26 @@ grub_video_set_mode (const char *modestring, || grub_memcmp (next_mode, "keep,", sizeof ("keep,") - 1) == 0 || grub_memcmp (next_mode, "keep;", sizeof ("keep;") - 1) == 0) { - struct grub_video_mode_info mode_info; int suitable = 1; grub_err_t err; - grub_memset (&mode_info, 0, sizeof (mode_info)); - if (grub_video_adapter_active) { + struct grub_video_mode_info mode_info; + grub_memset (&mode_info, 0, sizeof (mode_info)); err = grub_video_get_info (&mode_info); if (err) { suitable = 0; grub_errno = GRUB_ERR_NONE; } + if ((mode_info.mode_type & modemask) != modevalue) + suitable = 0; } - else - mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_PURE_TEXT; + else if (((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modemask) != 0) + && ((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modevalue) == 0)) + suitable = 0; - if (suitable && hook) - suitable = hook (grub_video_adapter_active, &mode_info); if (suitable) { grub_free (modevar); @@ -460,7 +528,7 @@ grub_video_set_mode (const char *modestring, grub_free (modevar); return grub_error (GRUB_ERR_BAD_ARGUMENT, - "No suitable mode found."); + "no suitable mode found"); } /* Skip separator. */ @@ -482,15 +550,16 @@ grub_video_set_mode (const char *modestring, /* Loop until all modes has been tested out. */ while (next_mode != NULL) { + int width = -1; + int height = -1; + int depth = -1; + grub_err_t err; + unsigned int flags = modevalue; + unsigned int flagmask = modemask; + /* Use last next_mode as current mode. */ tmp = next_mode; - /* Reset video mode settings. */ - width = -1; - height = -1; - depth = -1; - flags = 0; - /* Save position of next mode and separate modes. */ for (; *next_mode; next_mode++) if (*next_mode == ',' || *next_mode == ';') @@ -509,19 +578,16 @@ grub_video_set_mode (const char *modestring, /* Initialize token holders. */ current_mode = tmp; - param = tmp; - value = NULL; /* XXX: we assume that we're in pure text mode if no video mode is initialized. Is it always true? */ - if (grub_strcmp (param, "text") == 0) + if (grub_strcmp (current_mode, "text") == 0) { struct grub_video_mode_info mode_info; grub_memset (&mode_info, 0, sizeof (mode_info)); - mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_PURE_TEXT; - - if (! hook || hook (0, &mode_info)) + if (((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modemask) == 0) + || ((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modevalue) != 0)) { /* Valid mode found from adapter, and it has been activated. Specify it as active adapter. */ @@ -534,121 +600,31 @@ grub_video_set_mode (const char *modestring, } } - /* Parse x[x]*/ - - /* Find width value. */ - value = param; - param = grub_strchr(param, 'x'); - if (param == NULL) + err = parse_modespec (current_mode, &width, &height, &depth); + if (err) { - grub_err_t rc; - - /* First setup error message. */ - rc = grub_error (GRUB_ERR_BAD_ARGUMENT, - "Invalid mode: %s\n", - current_mode); - /* Free memory before returning. */ grub_free (modevar); - return rc; - } - - *param = 0; - param++; - - width = grub_strtoul (value, 0, 0); - if (grub_errno != GRUB_ERR_NONE) - { - grub_err_t rc; - - /* First setup error message. */ - rc = grub_error (GRUB_ERR_BAD_ARGUMENT, - "Invalid mode: %s\n", - current_mode); - - /* Free memory before returning. */ - grub_free (modevar); - - return rc; - } - - /* Find height value. */ - value = param; - param = grub_strchr(param, 'x'); - if (param == NULL) - { - height = grub_strtoul (value, 0, 0); - if (grub_errno != GRUB_ERR_NONE) - { - grub_err_t rc; - - /* First setup error message. */ - rc = grub_error (GRUB_ERR_BAD_ARGUMENT, - "Invalid mode: %s\n", - current_mode); - - /* Free memory before returning. */ - grub_free (modevar); - - return rc; - } - } - else - { - /* We have optional color depth value. */ - *param = 0; - param++; - - height = grub_strtoul (value, 0, 0); - if (grub_errno != GRUB_ERR_NONE) - { - grub_err_t rc; - - /* First setup error message. */ - rc = grub_error (GRUB_ERR_BAD_ARGUMENT, - "Invalid mode: %s\n", - current_mode); - - /* Free memory before returning. */ - grub_free (modevar); - - return rc; - } - - /* Convert color depth value. */ - value = param; - depth = grub_strtoul (value, 0, 0); - if (grub_errno != GRUB_ERR_NONE) - { - grub_err_t rc; - - /* First setup error message. */ - rc = grub_error (GRUB_ERR_BAD_ARGUMENT, - "Invalid mode: %s\n", - current_mode); - - /* Free memory before returning. */ - grub_free (modevar); - - return rc; - } + return err; } /* Try out video mode. */ - /* If we have 8 or less bits, then assume that it is indexed color mode. */ - if ((depth <= 8) && (depth != -1)) - flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + /* If user requested specific depth check if this depth is supported. */ + if (depth != -1 && (flagmask & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) + && + (((flags & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) + != ((depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) + & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)))) + continue; - /* We have more than 8 bits, then assume that it is RGB color mode. */ - if (depth > 8) - flags |= GRUB_VIDEO_MODE_TYPE_RGB; - - /* If user requested specific depth, forward that information to driver. */ if (depth != -1) - flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) - & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK; + { + flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) + & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK; + flagmask |= GRUB_VIDEO_MODE_TYPE_DEPTH_MASK; + } /* Try to initialize requested mode. Ignore any errors. */ grub_video_adapter_t p; @@ -656,7 +632,6 @@ grub_video_set_mode (const char *modestring, /* Loop thru all possible video adapter trying to find requested mode. */ for (p = grub_video_adapter_list; p; p = p->next) { - grub_err_t err; struct grub_video_mode_info mode_info; grub_memset (&mode_info, 0, sizeof (mode_info)); @@ -670,7 +645,7 @@ grub_video_set_mode (const char *modestring, } /* Try to initialize video mode. */ - err = p->setup (width, height, flags); + err = p->setup (width, height, flags, flagmask); if (err != GRUB_ERR_NONE) { p->fini (); @@ -686,7 +661,15 @@ grub_video_set_mode (const char *modestring, continue; } - if (hook && ! hook (p, &mode_info)) + flags = mode_info.mode_type & ~GRUB_VIDEO_MODE_TYPE_DEPTH_MASK; + flags |= (mode_info.bpp << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) + & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK; + + /* Check that mode is suitable for upper layer. */ + if ((flags & GRUB_VIDEO_MODE_TYPE_PURE_TEXT) + ? (((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modemask) != 0) + && ((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modevalue) == 0)) + : ((flags & modemask) != modevalue)) { p->fini (); grub_errno = GRUB_ERR_NONE; @@ -709,15 +692,15 @@ grub_video_set_mode (const char *modestring, grub_free (modevar); return grub_error (GRUB_ERR_BAD_ARGUMENT, - "No suitable mode found."); + "no suitable mode found"); } /* Initialize Video API module. */ -GRUB_MOD_INIT(video_video) +GRUB_MOD_INIT(video) { } /* Finalize Video API module. */ -GRUB_MOD_FINI(video_video) +GRUB_MOD_FINI(video) { }