From: BVK Chaitanya Date: Tue, 27 Apr 2010 05:20:28 +0000 (+0530) Subject: reorganized grub-emu sources to suite upcoming automake build system X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=840b61d8f0fc4919fbfdfb0e8495f2c0da81b715;p=grub2.git reorganized grub-emu sources to suite upcoming automake build system --- 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/usb/emu/usb.c b/bus/usb/emu/usb.c new file mode 100644 index 000000000..a687eea9b --- /dev/null +++ b/bus/usb/emu/usb.c @@ -0,0 +1,195 @@ +/* usb.c -- libusb USB support for GRUB. */ +/* + * 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 + + +static struct grub_usb_controller_dev usb_controller = +{ + .name = "libusb" +}; + +static struct grub_usb_device *grub_usb_devs[128]; + +struct usb_bus *busses; + +static grub_err_t +grub_libusb_devices (void) + +{ + struct usb_bus *bus; + int last = 0; + + busses = usb_get_busses(); + + for (bus = busses; bus; bus = bus->next) + { + struct usb_device *usbdev; + struct grub_usb_device *dev; + + for (usbdev = bus->devices; usbdev; usbdev = usbdev->next) + { + struct usb_device_descriptor *desc = &usbdev->descriptor; + grub_err_t err; + + if (! desc->bcdUSB) + continue; + + dev = grub_malloc (sizeof (*dev)); + if (! dev) + return grub_errno; + + dev->data = usbdev; + + /* Fill in all descriptors. */ + err = grub_usb_device_initialize (dev); + if (err) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + + /* Register the device. */ + grub_usb_devs[last++] = dev; + } + } + + return GRUB_USB_ERR_NONE; +} + + +int +grub_usb_iterate (int (*hook) (grub_usb_device_t dev)) +{ + int i; + + for (i = 0; i < 128; i++) + { + if (grub_usb_devs[i]) + { + if (hook (grub_usb_devs[i])) + return 1; + } + } + + return 0; +} + +grub_usb_err_t +grub_usb_root_hub (grub_usb_controller_t controller __attribute__((unused))) +{ + return GRUB_USB_ERR_NONE; +} + +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) +{ + 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) + { + usb_close (devh); + return GRUB_USB_ERR_STALL; + } + + usb_close (devh); + + return GRUB_USB_ERR_NONE; +} + +grub_usb_err_t +grub_usb_bulk_read (grub_usb_device_t dev, + int endpoint, grub_size_t size, char *data) +{ + usb_dev_handle *devh; + struct usb_device *d = dev->data; + + devh = usb_open (d); + if (usb_claim_interface (devh, 0) < 1) + { + usb_close (devh); + return GRUB_USB_ERR_STALL; + } + + if (usb_bulk_read (devh, endpoint, data, size, 20) < 1) + { + usb_close (devh); + return GRUB_USB_ERR_STALL; + } + + usb_release_interface (devh, 0); + usb_close (devh); + + return GRUB_USB_ERR_NONE; +} + +grub_usb_err_t +grub_usb_bulk_write (grub_usb_device_t dev, + int endpoint, grub_size_t size, char *data) +{ + usb_dev_handle *devh; + struct usb_device *d = dev->data; + + devh = usb_open (d); + if (usb_claim_interface (devh, 0) < 0) + goto fail; + + if (usb_bulk_write (devh, endpoint, data, size, 20) < 0) + goto fail; + + if (usb_release_interface (devh, 0) < 0) + goto fail; + + usb_close (devh); + + return GRUB_USB_ERR_NONE; + + fail: + usb_close (devh); + return GRUB_USB_ERR_STALL; +} + +GRUB_MOD_INIT (libusb) +{ + usb_init(); + usb_find_busses(); + usb_find_devices(); + + if (grub_libusb_devices ()) + return; + + grub_usb_controller_dev_register (&usb_controller); + + return; +} + +GRUB_MOD_FINI (libusb) +{ + return; +} diff --git a/conf/any-emu.rmk b/conf/any-emu.rmk index d1e5754dc..5f6798d79 100644 --- a/conf/any-emu.rmk +++ b/conf/any-emu.rmk @@ -10,11 +10,11 @@ kernel_img_SOURCES = kern/device.c kern/disk.c kern/dl.c kern/env.c \ kern/parser.c kern/partition.c kern/term.c \ kern/rescue_reader.c kern/rescue_parser.c \ \ - util/console.c util/grub-emu.c util/misc.c \ - util/hostdisk.c util/getroot.c util/mm.c util/time.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 util/hostfs.c disk/host.c -kernel_img_HEADERS += datetime.h util/misc.h + gnulib/progname.c disk/host.c +kernel_img_HEADERS += datetime.h emu/misc.h kernel_img_CFLAGS = $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-undef -I$(srcdir)/gnulib kernel_img_LDFLAGS = $(COMMON_LDFLAGS) TARGET_NO_STRIP = yes @@ -49,7 +49,7 @@ ifeq ($(enable_grub_emu_usb), yes) kernel_img_HEADERS += libusb.h pkglib_MODULES += libusb.mod -libusb_mod_SOURCES = util/usb.c +libusb_mod_SOURCES = bus/usb/emu/usb.c libusb_mod_CFLAGS = libusb_mod_LDFLAGS = $(COMMON_LDFLAGS) @@ -76,7 +76,7 @@ endif ifeq ($(enable_grub_emu_sdl), yes) pkglib_MODULES += sdl.mod -sdl_mod_SOURCES = util/sdl.c +sdl_mod_SOURCES = video/emu/sdl.c sdl_mod_CFLAGS = sdl_mod_LDFLAGS = $(COMMON_LDFLAGS) grub_emu_LDFLAGS += $(LIBSDL) @@ -106,8 +106,13 @@ ifneq ($(TARGET_NO_MODULES), yes) grub-emu: $(pkglib_PROGRAMS) $(CC) -o $@ $(pkglib_PROGRAMS) $(grub_emu_LDFLAGS) $(LDFLAGS) else + +pkglib_MODULES += emu.mod +emu_mod_SOURCES = kern/emu/main.c +emu_mod_CFLAGS = -I$(srcdir)/gnulib + grub-emu: $(pkglib_MODULES) $(pkglib_PROGRAMS) - $(CC) -o $@ $(pkglib_MODULES) $(pkglib_PROGRAMS) $(grub_emu_LDFLAGS) $(LDFLAGS) + $(CC) -o $@ $^ $(grub_emu_LDFLAGS) $(LDFLAGS) endif GRUB_EMU=grub-emu diff --git a/conf/common.rmk b/conf/common.rmk index 8df232a0b..6267d7818 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -25,7 +25,7 @@ util/elf/grub-mkimage.c_DEPENDENCIES = Makefile 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 util/mm.c \ + kern/emu/hostdisk.c util/misc.c kern/emu/getroot.c util/mm.c \ kern/device.c kern/disk.c kern/err.c kern/misc.c \ kern/parser.c kern/partition.c kern/file.c kern/list.c \ \ @@ -60,7 +60,7 @@ grub_mkisofs_CFLAGS = -D_FILE_OFFSET_BITS=64 \ # 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 \ +grub_fstest_SOURCES = gnulib/progname.c util/grub-fstest.c kern/emu/hostfs.c \ util/misc.c util/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 \ diff --git a/include/grub/emu/console.h b/include/grub/emu/console.h new file mode 100644 index 000000000..1e5568282 --- /dev/null +++ b/include/grub/emu/console.h @@ -0,0 +1,28 @@ +/* + * 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_CONSOLE_UTIL_HEADER +#define GRUB_CONSOLE_UTIL_HEADER 1 + +/* Initialize the console system. */ +void grub_console_init (void); + +/* Finish the console system. */ +void grub_console_fini (void); + +#endif /* ! GRUB_CONSOLE_UTIL_HEADER */ diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h new file mode 100644 index 000000000..f9f7f9baa --- /dev/null +++ b/include/grub/emu/getroot.h @@ -0,0 +1,35 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003, 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_UTIL_GETROOT_HEADER +#define GRUB_UTIL_GETROOT_HEADER 1 + +enum grub_dev_abstraction_types { + GRUB_DEV_ABSTRACTION_NONE, + GRUB_DEV_ABSTRACTION_LVM, + GRUB_DEV_ABSTRACTION_RAID, +}; + +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); +const char *grub_util_check_char_device (const char *blk_dev); + +#endif /* ! GRUB_UTIL_GETROOT_HEADER */ diff --git a/include/grub/emu/hostdisk.h b/include/grub/emu/hostdisk.h new file mode 100644 index 000000000..246046ee0 --- /dev/null +++ b/include/grub/emu/hostdisk.h @@ -0,0 +1,30 @@ +/* biosdisk.h - emulate biosdisk */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,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_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..e62aeba08 --- /dev/null +++ b/include/grub/emu/misc.h @@ -0,0 +1,31 @@ +#ifndef GRUB_EMU_MISC_H +#define GRUB_EMU_MISC_H 1 + +#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 int verbosity; +extern const char *program_name; + +void grub_init_all (void); +void grub_fini_all (void); + +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)); + +#endif /* GRUB_EMU_MISC_H */ diff --git a/include/grub/util/console.h b/include/grub/util/console.h deleted file mode 100644 index 1e5568282..000000000 --- a/include/grub/util/console.h +++ /dev/null @@ -1,28 +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 . - */ - -#ifndef GRUB_CONSOLE_UTIL_HEADER -#define GRUB_CONSOLE_UTIL_HEADER 1 - -/* Initialize the console system. */ -void grub_console_init (void); - -/* Finish the console system. */ -void grub_console_fini (void); - -#endif /* ! GRUB_CONSOLE_UTIL_HEADER */ diff --git a/include/grub/util/getroot.h b/include/grub/util/getroot.h deleted file mode 100644 index f9f7f9baa..000000000 --- a/include/grub/util/getroot.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003, 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_UTIL_GETROOT_HEADER -#define GRUB_UTIL_GETROOT_HEADER 1 - -enum grub_dev_abstraction_types { - GRUB_DEV_ABSTRACTION_NONE, - GRUB_DEV_ABSTRACTION_LVM, - GRUB_DEV_ABSTRACTION_RAID, -}; - -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); -const char *grub_util_check_char_device (const char *blk_dev); - -#endif /* ! GRUB_UTIL_GETROOT_HEADER */ diff --git a/include/grub/util/hostdisk.h b/include/grub/util/hostdisk.h deleted file mode 100644 index 246046ee0..000000000 --- a/include/grub/util/hostdisk.h +++ /dev/null @@ -1,30 +0,0 @@ -/* biosdisk.h - emulate biosdisk */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,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_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/kern/emu/cache.S b/kern/emu/cache.S new file mode 100644 index 000000000..087b2b495 --- /dev/null +++ b/kern/emu/cache.S @@ -0,0 +1,17 @@ +#ifndef GRUB_MACHINE_EMU +#error "This source is only meant for grub-emu platform" +#endif + +#if GRUB_CPU_I386 +#elif GRUB_CPU_X86_64 +#elif GRUB_CPU_SPARC64 +#include "../sparc64/cache.S" +#elif GRUB_CPU_MIPS +#include "../mips/cache.S" +#elif GRUB_CPU_MIPSEL +#include "../mips/cache.S" +#elif GRUB_CPU_POWERPC +#include "../powerpc/cache.S" +#else +#error "No target cpu type is defined" +#endif diff --git a/kern/emu/console.c b/kern/emu/console.c new file mode 100644 index 000000000..f7fbc899a --- /dev/null +++ b/kern/emu/console.c @@ -0,0 +1,384 @@ +/* console.c -- Ncurses console for GRUB. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2005,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 + +/* For compatibility. */ +#ifndef A_NORMAL +# define A_NORMAL 0 +#endif /* ! A_NORMAL */ +#ifndef A_STANDOUT +# define A_STANDOUT 0 +#endif /* ! A_STANDOUT */ + +#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; + +static grub_uint8_t grub_console_standard_color = 0x7; +static grub_uint8_t grub_console_normal_color = 0x7; +static grub_uint8_t grub_console_highlight_color = 0x70; + +#define NUM_COLORS 8 + +static grub_uint8_t color_map[NUM_COLORS] = +{ + COLOR_BLACK, + COLOR_BLUE, + COLOR_GREEN, + COLOR_CYAN, + COLOR_RED, + COLOR_MAGENTA, + COLOR_YELLOW, + COLOR_WHITE +}; + +static int use_color; + +static void +grub_ncurses_putchar (grub_uint32_t c) +{ + /* 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: + /* ncurses does not support Unicode. */ + if (c > 0x7f) + c = '?'; + break; + } + + addch (c | grub_console_attr); +} + +static grub_ssize_t +grub_ncurses_getcharwidth (grub_uint32_t code __attribute__ ((unused))) +{ + return 1; +} + +static void +grub_ncurses_setcolorstate (grub_term_color_state state) +{ + switch (state) + { + case GRUB_TERM_COLOR_STANDARD: + grub_console_cur_color = grub_console_standard_color; + grub_console_attr = A_NORMAL; + break; + case GRUB_TERM_COLOR_NORMAL: + grub_console_cur_color = grub_console_normal_color; + grub_console_attr = A_NORMAL; + break; + case GRUB_TERM_COLOR_HIGHLIGHT: + grub_console_cur_color = grub_console_highlight_color; + grub_console_attr = A_STANDOUT; + break; + default: + break; + } + + if (use_color) + { + grub_uint8_t fg, bg; + + fg = (grub_console_cur_color & 7); + bg = (grub_console_cur_color >> 4) & 7; + + grub_console_attr = (grub_console_cur_color & 8) ? A_BOLD : A_NORMAL; + color_set ((bg << 3) + fg, 0); + } +} + +/* XXX: This function is never called. */ +static void +grub_ncurses_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color) +{ + grub_console_normal_color = normal_color; + grub_console_highlight_color = highlight_color; +} + +static void +grub_ncurses_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color) +{ + *normal_color = grub_console_normal_color; + *highlight_color = grub_console_highlight_color; +} + +static int saved_char = ERR; + +static int +grub_ncurses_checkkey (void) +{ + int c; + + /* Check for SAVED_CHAR. This should not be true, because this + means checkkey is called twice continuously. */ + if (saved_char != ERR) + return saved_char; + + wtimeout (stdscr, 100); + c = getch (); + /* If C is not ERR, then put it back in the input queue. */ + if (c != ERR) + { + saved_char = c; + return c; + } + + return -1; +} + +static int +grub_ncurses_getkey (void) +{ + int c; + + /* If checkkey has already got a character, then return it. */ + if (saved_char != ERR) + { + c = saved_char; + saved_char = ERR; + } + else + { + wtimeout (stdscr, -1); + c = getch (); + } + + switch (c) + { + case KEY_LEFT: + c = 2; + break; + + case KEY_RIGHT: + c = 6; + break; + + case KEY_UP: + c = 16; + break; + + case KEY_DOWN: + c = 14; + break; + + case KEY_IC: + c = 24; + break; + + case KEY_DC: + c = 4; + break; + + case KEY_BACKSPACE: + /* XXX: For some reason ncurses on xterm does not return + KEY_BACKSPACE. */ + case 127: + c = 8; + break; + + case KEY_HOME: + c = 1; + break; + + case KEY_END: + c = 5; + break; + + case KEY_NPAGE: + c = 3; + break; + + case KEY_PPAGE: + c = 7; + break; + } + + return c; +} + +static grub_uint16_t +grub_ncurses_getxy (void) +{ + int x; + int y; + + getyx (stdscr, y, x); + + return (x << 8) | y; +} + +static grub_uint16_t +grub_ncurses_getwh (void) +{ + int x; + int y; + + getmaxyx (stdscr, y, x); + + return (x << 8) | y; +} + +static void +grub_ncurses_gotoxy (grub_uint8_t x, grub_uint8_t y) +{ + move (y, x); +} + +static void +grub_ncurses_cls (void) +{ + clear (); + refresh (); +} + +static void +grub_ncurses_setcursor (int on) +{ + curs_set (on ? 1 : 0); +} + +static void +grub_ncurses_refresh (void) +{ + refresh (); +} + +static grub_err_t +grub_ncurses_init (void) +{ + initscr (); + raw (); + noecho (); + scrollok (stdscr, TRUE); + + nonl (); + intrflush (stdscr, FALSE); + keypad (stdscr, TRUE); + + if (has_colors ()) + { + start_color (); + + if ((COLORS >= NUM_COLORS) && (COLOR_PAIRS >= NUM_COLORS * NUM_COLORS)) + { + int i, j, n; + + n = 0; + for (i = 0; i < NUM_COLORS; i++) + for (j = 0; j < NUM_COLORS; j++) + init_pair(n++, color_map[j], color_map[i]); + + use_color = 1; + } + } + + return 0; +} + +static grub_err_t +grub_ncurses_fini (void) +{ + endwin (); + return 0; +} + + +static struct grub_term_input grub_ncurses_term_input = + { + .name = "console", + .checkkey = grub_ncurses_checkkey, + .getkey = grub_ncurses_getkey, + }; + +static struct grub_term_output grub_ncurses_term_output = + { + .name = "console", + .init = grub_ncurses_init, + .fini = grub_ncurses_fini, + .putchar = grub_ncurses_putchar, + .getcharwidth = grub_ncurses_getcharwidth, + .getxy = grub_ncurses_getxy, + .getwh = grub_ncurses_getwh, + .gotoxy = grub_ncurses_gotoxy, + .cls = grub_ncurses_cls, + .setcolorstate = grub_ncurses_setcolorstate, + .setcolor = grub_ncurses_setcolor, + .getcolor = grub_ncurses_getcolor, + .setcursor = grub_ncurses_setcursor, + .refresh = grub_ncurses_refresh + }; + +void +grub_console_init (void) +{ + grub_term_register_output ("console", &grub_ncurses_term_output); + grub_term_register_input ("console", &grub_ncurses_term_input); +} + +void +grub_console_fini (void) +{ + grub_ncurses_fini (); +} diff --git a/kern/emu/dummy/dl.c b/kern/emu/dummy/dl.c new file mode 100644 index 000000000..8e9fabfc2 --- /dev/null +++ b/kern/emu/dummy/dl.c @@ -0,0 +1,51 @@ +/* + * 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_arch_dl_check_header (void *ehdr) +{ + (void) ehdr; + + return GRUB_ERR_BAD_MODULE; +} + +grub_err_t +grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) +{ + (void) mod; + (void) ehdr; + + return GRUB_ERR_BAD_MODULE; +} + +/* 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/kern/emu/getroot.c b/kern/emu/getroot.c new file mode 100644 index 000000000..91799aa8f --- /dev/null +++ b/kern/emu/getroot.c @@ -0,0 +1,644 @@ +/* getroot.c - Get root device */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,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 + +#ifdef __CYGWIN__ +# include +# include +# include +# define DEV_CYGDRIVE_MAJOR 98 +#endif + +#ifdef __GNU__ +#include +#include +#include +#endif + +#include +#include +#include +#include +#include + +static void +strip_extra_slashes (char *dir) +{ + char *p = dir; + + while ((p = strchr (p, '/')) != 0) + { + if (p[1] == '/') + { + memmove (p, p + 1, strlen (p)); + continue; + } + else if (p[1] == '\0') + { + if (p > dir) + p[0] = '\0'; + break; + } + + p++; + } +} + +static char * +xgetcwd (void) +{ + size_t size = 10; + char *path; + + path = xmalloc (size); + while (! getcwd (path, size)) + { + size <<= 1; + path = xrealloc (path, size); + } + + 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 * +find_root_device (const char *dir __attribute__ ((unused)), + dev_t dev __attribute__ ((unused))) +{ + return 0; +} + +#elif ! defined(__CYGWIN__) + +static char * +find_root_device (const char *dir, dev_t dev) +{ + DIR *dp; + char *saved_cwd; + struct dirent *ent; + + dp = opendir (dir); + if (! dp) + return 0; + + saved_cwd = xgetcwd (); + + grub_util_info ("changing current directory to %s", dir); + if (chdir (dir) < 0) + { + free (saved_cwd); + closedir (dp); + return 0; + } + + while ((ent = readdir (dp)) != 0) + { + struct stat st; + + /* Avoid: + - dotfiles (like "/dev/.tmp.md0") since they could be duplicates. + - dotdirs (like "/dev/.static") since they could contain duplicates. */ + if (ent->d_name[0] == '.') + continue; + + if (lstat (ent->d_name, &st) < 0) + /* Ignore any error. */ + continue; + + if (S_ISLNK (st.st_mode)) + /* Don't follow symbolic links. */ + continue; + + if (S_ISDIR (st.st_mode)) + { + /* Find it recursively. */ + char *res; + + res = find_root_device (ent->d_name, dev); + + if (res) + { + if (chdir (saved_cwd) < 0) + grub_util_error ("cannot restore the original directory"); + + free (saved_cwd); + closedir (dp); + return res; + } + } + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) + if (S_ISCHR (st.st_mode) && st.st_rdev == dev) +#else + if (S_ISBLK (st.st_mode) && st.st_rdev == dev) +#endif + { +#ifdef __linux__ + /* Skip device names like /dev/dm-0, which are short-hand aliases + to more descriptive device names, e.g. those under /dev/mapper */ + if (ent->d_name[0] == 'd' && + ent->d_name[1] == 'm' && + ent->d_name[2] == '-' && + ent->d_name[3] >= '0' && + ent->d_name[3] <= '9') + continue; +#endif + + /* 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) + 3); + sprintf (res, template, cwd, ent->d_name); + strip_extra_slashes (res); + free (cwd); + + /* /dev/root is not a real block device keep looking, takes care + of situation where root filesystem is on the same partition as + grub files */ + + if (strcmp(res, "/dev/root") == 0) + continue; + + if (chdir (saved_cwd) < 0) + grub_util_error ("cannot restore the original directory"); + + free (saved_cwd); + closedir (dp); + return res; + } + } + + if (chdir (saved_cwd) < 0) + grub_util_error ("cannot restore the original directory"); + + free (saved_cwd); + closedir (dp); + return 0; +} + +#else /* __CYGWIN__ */ + +/* Read drive/partition serial number from mbr/boot sector, + return 0 on read error, ~0 on unknown serial. */ +static unsigned +get_bootsec_serial (const char *os_dev, int mbr) +{ + /* Read boot sector. */ + int fd = open (os_dev, O_RDONLY); + if (fd < 0) + return 0; + unsigned char buf[0x200]; + int n = read (fd, buf, sizeof (buf)); + close (fd); + if (n != sizeof(buf)) + return 0; + + /* Check signature. */ + if (!(buf[0x1fe] == 0x55 && buf[0x1ff] == 0xaa)) + return ~0; + + /* Serial number offset depends on boot sector type. */ + if (mbr) + n = 0x1b8; + else if (memcmp (buf + 0x03, "NTFS", 4) == 0) + n = 0x048; + else if (memcmp (buf + 0x52, "FAT32", 5) == 0) + n = 0x043; + else if (memcmp (buf + 0x36, "FAT", 3) == 0) + n = 0x027; + else + return ~0; + + unsigned serial = *(unsigned *)(buf + n); + if (serial == 0) + return ~0; + return serial; +} + +static char * +find_cygwin_root_device (const char *path, dev_t dev) +{ + /* No root device for /cygdrive. */ + if (dev == (DEV_CYGDRIVE_MAJOR << 16)) + return 0; + + /* Convert to full POSIX and Win32 path. */ + char fullpath[PATH_MAX], winpath[PATH_MAX]; + cygwin_conv_to_full_posix_path (path, fullpath); + cygwin_conv_to_full_win32_path (fullpath, winpath); + + /* If identical, this is no real filesystem path. */ + if (strcmp (fullpath, winpath) == 0) + return 0; + + /* Check for floppy drive letter. */ + if (winpath[0] && winpath[1] == ':' && strchr ("AaBb", winpath[0])) + return xstrdup (strchr ("Aa", winpath[0]) ? "/dev/fd0" : "/dev/fd1"); + + /* Cygwin returns the partition serial number in stat.st_dev. + This is never identical to the device number of the emulated + /dev/sdXN device, so above find_root_device () does not work. + Search the partition with the same serial in boot sector instead. */ + char devpath[sizeof ("/dev/sda15") + 13]; /* Size + Paranoia. */ + int d; + for (d = 'a'; d <= 'z'; d++) + { + sprintf (devpath, "/dev/sd%c", d); + if (get_bootsec_serial (devpath, 1) == 0) + continue; + int p; + for (p = 1; p <= 15; p++) + { + sprintf (devpath, "/dev/sd%c%d", d, p); + unsigned ser = get_bootsec_serial (devpath, 0); + if (ser == 0) + break; + if (ser != (unsigned)~0 && dev == (dev_t)ser) + return xstrdup (devpath); + } + } + return 0; +} + +#endif /* __CYGWIN__ */ + +char * +grub_guess_root_device (const char *dir) +{ + char *os_dev; +#ifdef __GNU__ + file_t file; + mach_port_t *ports; + int *ints; + loff_t *offsets; + char *data; + error_t err; + mach_msg_type_number_t num_ports = 0, num_ints = 0, num_offsets = 0, data_len = 0; + size_t name_len; + + file = file_name_lookup (dir, 0, 0); + if (file == MACH_PORT_NULL) + return 0; + + err = file_get_storage_info (file, + &ports, &num_ports, + &ints, &num_ints, + &offsets, &num_offsets, + &data, &data_len); + + if (num_ints < 1) + grub_util_error ("Storage info for `%s' does not include type", dir); + if (ints[0] != STORAGE_DEVICE) + grub_util_error ("Filesystem of `%s' is not stored on local disk", dir); + + if (num_ints < 5) + grub_util_error ("Storage info for `%s' does not include name", dir); + name_len = ints[4]; + if (name_len < data_len) + grub_util_error ("Bogus name length for storage info for `%s'", dir); + if (data[name_len - 1] != '\0') + grub_util_error ("Storage name for `%s' not NUL-terminated", dir); + + os_dev = xmalloc (strlen ("/dev/") + data_len); + memcpy (os_dev, "/dev/", strlen ("/dev/")); + memcpy (os_dev + strlen ("/dev/"), data, data_len); + + if (ports && num_ports > 0) + { + mach_msg_type_number_t i; + for (i = 0; i < num_ports; i++) + { + mach_port_t port = ports[i]; + if (port != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self(), port); + } + munmap ((caddr_t) ports, num_ports * sizeof (*ports)); + } + + if (ints && num_ints > 0) + munmap ((caddr_t) ints, num_ints * sizeof (*ints)); + if (offsets && num_offsets > 0) + munmap ((caddr_t) offsets, num_offsets * sizeof (*offsets)); + if (data && data_len > 0) + munmap (data, data_len); + mach_port_deallocate (mach_task_self (), file); +#else /* !__GNU__ */ + struct stat st; + + if (stat (dir, &st) < 0) + grub_util_error ("cannot stat `%s'", dir); + +#ifdef __CYGWIN__ + /* Cygwin specific function. */ + os_dev = find_cygwin_root_device (dir, st.st_dev); + +#else + + /* This might be truly slow, but is there any better way? */ + os_dev = find_root_device ("/dev", st.st_dev); +#endif +#endif /* !__GNU__ */ + + return os_dev; +} + +static int +grub_util_is_dmraid (const char *os_dev) +{ + if (! strncmp (os_dev, "/dev/mapper/nvidia_", 19)) + return 1; + else if (! strncmp (os_dev, "/dev/mapper/isw_", 16)) + return 1; + else if (! strncmp (os_dev, "/dev/mapper/hpt37x_", 19)) + return 1; + else if (! strncmp (os_dev, "/dev/mapper/hpt45x_", 19)) + return 1; + else if (! strncmp (os_dev, "/dev/mapper/via_", 16)) + return 1; + else if (! strncmp (os_dev, "/dev/mapper/lsi_", 16)) + return 1; + else if (! strncmp (os_dev, "/dev/mapper/pdc_", 16)) + return 1; + else if (! strncmp (os_dev, "/dev/mapper/jmicron_", 20)) + return 1; + else if (! strncmp (os_dev, "/dev/mapper/asr_", 16)) + 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 __attribute__((unused))) +{ +#ifdef __linux__ + /* Check for LVM. */ + if (!strncmp (os_dev, "/dev/mapper/", 12) + && ! grub_util_is_dmraid (os_dev) + && strncmp (os_dev, "/dev/mapper/mpath", 17) != 0) + return GRUB_DEV_ABSTRACTION_LVM; + + /* Check for RAID. */ + if (!strncmp (os_dev, "/dev/md", 7)) + return GRUB_DEV_ABSTRACTION_RAID; +#endif + + /* No abstraction found. */ + return GRUB_DEV_ABSTRACTION_NONE; +} + +char * +grub_util_get_grub_dev (const char *os_dev) +{ + char *grub_dev; + + switch (grub_util_get_dev_abstraction (os_dev)) + { + case GRUB_DEV_ABSTRACTION_LVM: + + { + unsigned short i, len; + grub_size_t offset = sizeof ("/dev/mapper/") - 1; + + len = strlen (os_dev) - offset + 1; + grub_dev = xmalloc (len); + + for (i = 0; i < len; i++, offset++) + { + grub_dev[i] = os_dev[offset]; + if (os_dev[offset] == '-' && os_dev[offset + 1] == '-') + offset++; + } + } + + break; + + case GRUB_DEV_ABSTRACTION_RAID: + + if (os_dev[7] == '_' && os_dev[8] == 'd') + { + /* This a partitionable RAID device of the form /dev/md_dNNpMM. */ + + char *p, *q; + + p = strdup (os_dev + sizeof ("/dev/md_d") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + grub_dev = xasprintf ("md%s", p); + free (p); + } + else if (os_dev[7] == '/' && os_dev[8] == 'd') + { + /* This a partitionable RAID device of the form /dev/md/dNNpMM. */ + + char *p, *q; + + p = strdup (os_dev + sizeof ("/dev/md/d") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + grub_dev = xasprintf ("md%s", p); + free (p); + } + else if (os_dev[7] >= '0' && os_dev[7] <= '9') + { + char *p , *q; + + p = strdup (os_dev + sizeof ("/dev/md") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + grub_dev = xasprintf ("md%s", p); + free (p); + } + else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9') + { + char *p , *q; + + p = strdup (os_dev + sizeof ("/dev/md/") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + grub_dev = xasprintf ("md%s", p); + free (p); + } + else + grub_util_error ("unknown kind of RAID device `%s'", os_dev); + + break; + + default: /* GRUB_DEV_ABSTRACTION_NONE */ + grub_dev = grub_util_biosdisk_get_grub_dev (os_dev); + } + + return grub_dev; +} + +const char * +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); + + if (S_ISBLK (st.st_mode)) + return (blk_dev); + else + return 0; +} + +const char * +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); + + if (S_ISCHR (st.st_mode)) + return (blk_dev); + else + return 0; +} + diff --git a/kern/emu/hostdisk.c b/kern/emu/hostdisk.c new file mode 100644 index 000000000..983f101ae --- /dev/null +++ b/kern/emu/hostdisk.c @@ -0,0 +1,1360 @@ +/* hostdisk.c - emulate biosdisk */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +# include /* ioctl */ +# if !defined(__GLIBC__) || \ + ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))) +/* Maybe libc doesn't have large file support. */ +# include /* _llseek */ +# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */ +# ifndef BLKFLSBUF +# define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */ +# endif /* ! BLKFLSBUF */ +# include /* ioctl */ +# ifndef HDIO_GETGEO +# define HDIO_GETGEO 0x0301 /* get device geometry */ +/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is + defined. */ +struct hd_geometry +{ + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + unsigned long start; +}; +# endif /* ! HDIO_GETGEO */ +# ifndef BLKGETSIZE64 +# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */ +# endif /* ! BLKGETSIZE64 */ +# ifndef MAJOR +# ifndef MINORBITS +# define MINORBITS 8 +# endif /* ! MINORBITS */ +# define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS)) +# endif /* ! MAJOR */ +# ifndef FLOPPY_MAJOR +# define FLOPPY_MAJOR 2 +# endif /* ! FLOPPY_MAJOR */ +# ifndef LOOP_MAJOR +# define LOOP_MAJOR 7 +# endif /* ! LOOP_MAJOR */ +#endif /* __linux__ */ + +#ifdef __CYGWIN__ +# include +# include /* BLKGETSIZE64 */ +# include /* HDIO_GETGEO */ +# define MAJOR(dev) ((unsigned) ((dev) >> 16)) +# define FLOPPY_MAJOR 2 +#endif + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +# include /* DIOCGMEDIASIZE */ +# include +# include +#endif + +#if defined(__APPLE__) +# 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 +have_devfs (void) +{ + static int dev_devfsd_exists = -1; + + if (dev_devfsd_exists < 0) + { + struct stat st; + + dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0; + } + + return dev_devfsd_exists; +} +#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) +{ + unsigned int i; + + if (name) + { + for (i = 0; i < ARRAY_SIZE (map); i++) + if (map[i].drive && ! strcmp (map[i].drive, name)) + return i; + } + + return -1; +} + +static int +find_free_slot (void) +{ + unsigned int i; + + for (i = 0; i < sizeof (map) / sizeof (map[0]); i++) + if (! map[i].drive) + return i; + + return -1; +} + +static int +grub_util_biosdisk_iterate (int (*hook) (const char *name)) +{ + unsigned i; + + for (i = 0; i < sizeof (map) / sizeof (map[0]); i++) + if (map[i].drive && hook (map[i].drive)) + return 1; + + return 0; +} + +static grub_err_t +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_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__) + { + grub_uint64_t size; + + size = grub_util_get_disk_size (map[drive].device); + + if (size % 512) + grub_util_error ("unaligned device size"); + + disk->total_sectors = size >> 9; + + grub_util_info ("the size of %s is %llu", name, disk->total_sectors); + + return GRUB_ERR_NONE; + } +#elif defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \ + 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_UNKNOWN_DEVICE, "cannot open `%s' while attempting to get disk size", map[drive].device); + +# 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)) +# endif + { + close (fd); + goto fail; + } + +# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + 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 + { + close (fd); + goto fail; + } + + close (fd); + +# if defined (__APPLE__) + disk->total_sectors = nr; +# 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 + + grub_util_info ("the size of %s is %llu", name, disk->total_sectors); + + return GRUB_ERR_NONE; + } + + fail: + /* In GNU/Hurd, stat() will return the right size. */ +#elif !defined (__GNU__) +# 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_UNKNOWN_DEVICE, "cannot stat `%s'", map[drive].device); + + disk->total_sectors = st.st_size >> GRUB_DISK_SECTOR_BITS; + + grub_util_info ("the size of %s is %lu", name, disk->total_sectors); + + return GRUB_ERR_NONE; +} + +#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) +{ + size_t len = strlen (dev); + const char *format; + char *p; + int i; + char real_dev[PATH_MAX]; + struct linux_partition_cache *cache; + + strcpy(real_dev, dev); + + if (have_devfs () && strcmp (real_dev + len - 5, "/disc") == 0) + { + p = real_dev + len - 4; + format = "part%d"; + } + else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9') + { + p = real_dev + len; + format = "p%d"; + } + else + { + p = real_dev + len; + 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; + + 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) + { + 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 = hdg.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; + } + } + + return 0; +} +#endif /* __linux__ */ + +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; +#endif +#ifdef O_SYNC + flags |= O_SYNC; +#endif +#ifdef O_FSYNC + flags |= O_FSYNC; +#endif +#ifdef O_BINARY + flags |= O_BINARY; +#endif + +#ifdef __linux__ + /* Linux has a bug that the disk cache for a whole disk is not consistent + with the one for a partition of the disk. */ + { + 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 && sector >= part_start + && strncmp (map[disk->id].device, "/dev/", 5) == 0) + is_partition = linux_find_partition (dev, part_start); + + if (data->dev && strcmp (data->dev, dev) == 0 && + data->access_mode == (flags & O_ACCMODE)) + { + 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; + } + + if (is_partition) + sector -= part_start; + } +#else /* ! __linux__ */ +#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) + int sysctl_flags, sysctl_oldflags; + size_t sysctl_size = sizeof (sysctl_flags); + + if (sysctlbyname ("kern.geom.debugflags", &sysctl_oldflags, &sysctl_size, NULL, 0)) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot get current flags of sysctl kern.geom.debugflags"); + return -1; + } + sysctl_flags = sysctl_oldflags | 0x10; + if (! (sysctl_oldflags & 0x10) + && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_flags, sysctl_size)) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags of sysctl kern.geom.debugflags"); + return -1; + } +#endif + + 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) + && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_oldflags, sysctl_size)) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags back to the old value for sysctl kern.geom.debugflags"); + return -1; + } +#endif + +#if defined(__APPLE__) + /* If we can't have exclusive access, try shared access */ + if (fd < 0) + fd = open(map[disk->id].device, flags | O_SHLOCK); +#endif + + if (fd < 0) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' in open_device()", map[disk->id].device); + return -1; + } +#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. */ + { + loff_t offset, result; + static int _llseek (uint filedes, ulong hi, ulong lo, + loff_t *res, uint wh); + _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo, + loff_t *, res, uint, wh); + + offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS; + if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET)) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device); + close (fd); + return -1; + } + } +#else + { + off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS; + + if (lseek (fd, offset, SEEK_SET) != offset) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device); + close (fd); + return -1; + } + } +#endif + + return fd; +} + +/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an + error occurs, otherwise return LEN. */ +static ssize_t +nread (int fd, char *buf, size_t len) +{ + ssize_t size = len; + + while (len) + { + ssize_t ret = read (fd, buf, len); + + if (ret <= 0) + { + if (errno == EINTR) + continue; + else + return ret; + } + + len -= ret; + buf += ret; + } + + return size; +} + +/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an + error occurs, otherwise return LEN. */ +static ssize_t +nwrite (int fd, const char *buf, size_t len) +{ + ssize_t size = len; + + while (len) + { + ssize_t ret = write (fd, buf, len); + + if (ret <= 0) + { + if (errno == EINTR) + continue; + else + return ret; + } + + len -= ret; + buf += ret; + } + + return size; +} + +static grub_err_t +grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + 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; + +#ifdef __linux__ + if (sector == 0 && size > 1) + { + /* Work around a bug in Linux ez remapping. Linux remaps all + sectors that are read together with the MBR in one read. It + should only remap the MBR, so we split the read in two + parts. -jochen */ + if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE) + { + grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device); + close (fd); + return grub_errno; + } + + buf += GRUB_DISK_SECTOR_SIZE; + size--; + } +#endif /* __linux__ */ + + if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS) + != (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) + grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device); + + return grub_errno; +} + +static grub_err_t +grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, const char *buf) +{ + 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; + + if (nwrite (fd, buf, size << GRUB_DISK_SECTOR_BITS) + != (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) + grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device); + + 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 = grub_util_biosdisk_close, + .read = grub_util_biosdisk_read, + .write = grub_util_biosdisk_write, + .next = 0 + }; + +static void +read_device_map (const char *dev_map) +{ + FILE *fp; + char buf[1024]; /* XXX */ + int lineno = 0; + struct stat st; + + auto void show_error (const char *msg); + void show_error (const char *msg) + { + grub_util_error ("%s:%d: %s", dev_map, lineno, msg); + } + + fp = fopen (dev_map, "r"); + if (! fp) + { + grub_util_info (_("cannot open `%s'"), dev_map); + return; + } + + while (fgets (buf, sizeof (buf), fp)) + { + char *p = buf; + char *e; + int drive; + + lineno++; + + /* Skip leading spaces. */ + while (*p && isspace (*p)) + p++; + + /* If the first character is `#' or NUL, skip this line. */ + if (*p == '\0' || *p == '#') + continue; + + if (*p != '(') + show_error ("No open parenthesis found"); + + p++; + /* Find a free slot. */ + drive = find_free_slot (); + if (drive < 0) + show_error ("Map table size exceeded"); + + e = p; + p = strchr (p, ')'); + if (! p) + show_error ("No close parenthesis found"); + + map[drive].drive = xmalloc (p - e + sizeof ('\0')); + strncpy (map[drive].drive, e, p - e + sizeof ('\0')); + map[drive].drive[p - e] = '\0'; + + p++; + /* Skip leading spaces. */ + while (*p && isspace (*p)) + p++; + + if (*p == '\0') + show_error ("No filename found"); + + /* NUL-terminate the filename. */ + e = p; + while (*e && ! isspace (*e)) + e++; + *e = '\0'; + +#ifdef __MINGW32__ + (void) st; + if (grub_util_get_disk_size (p) == -1LL) +#else + if (stat (p, &st) == -1) +#endif + { + free (map[drive].drive); + map[drive].drive = NULL; + grub_util_info ("Cannot stat `%s', skipping", p); + continue; + } + +#ifdef __linux__ + /* On Linux, the devfs uses symbolic links horribly, and that + confuses the interface very much, so use realpath to expand + 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); +#else + map[drive].device = xstrdup (p); +#endif + } + + fclose (fp); +} + +void +grub_util_biosdisk_init (const char *dev_map) +{ + read_device_map (dev_map); + grub_disk_dev_register (&grub_util_biosdisk_dev); +} + +void +grub_util_biosdisk_fini (void) +{ + unsigned i; + + for (i = 0; i < sizeof (map) / sizeof (map[0]); i++) + { + if (map[i].drive) + free (map[i].drive); + if (map[i].device) + free (map[i].device); + map[i].drive = map[i].device = NULL; + } + + grub_disk_dev_unregister (&grub_util_biosdisk_dev); +} + +static char * +make_device_name (int drive, int dos_part, int bsd_part) +{ + char *ret; + char *dos_part_str = NULL; + char *bsd_part_str = NULL; + + if (dos_part >= 0) + dos_part_str = xasprintf (",%d", dos_part + 1); + + if (bsd_part >= 0) + bsd_part_str = xasprintf (",%d", bsd_part + 1); + + ret = xasprintf ("%s%s%s", map[drive].drive, + dos_part_str ? : "", + bsd_part_str ? : ""); + + if (dos_part_str) + free (dos_part_str); + + if (bsd_part_str) + free (bsd_part_str); + + return ret; +} + +static char * +convert_system_partition_to_system_disk (const char *os_dev) +{ +#if defined(__linux__) + char *path = xmalloc (PATH_MAX); + if (! realpath (os_dev, path)) + return NULL; + + if (strncmp ("/dev/", path, 5) == 0) + { + char *p = path + 5; + + /* If this is an IDE disk. */ + if (strncmp ("ide/", p, 4) == 0) + { + p = strstr (p, "part"); + if (p) + strcpy (p, "disc"); + + return path; + } + + /* If this is a SCSI disk. */ + if (strncmp ("scsi/", p, 5) == 0) + { + p = strstr (p, "part"); + if (p) + strcpy (p, "disc"); + + return path; + } + + /* If this is a DAC960 disk. */ + if (strncmp ("rd/c", p, 4) == 0) + { + /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; + + return path; + } + + /* If this is a Mylex AcceleRAID Array. */ + if (strncmp ("rs/c", p, 4) == 0) + { + /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; + + return path; + } + /* If this is a CCISS disk. */ + if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0) + { + /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; + + return path; + } + + /* If this is a Compaq Intelligent Drive Array. */ + if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0) + { + /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; + + return path; + } + + /* If this is an I2O disk. */ + if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0) + { + /* /dev/i2o/hd[a-z]([0-9]+)? */ + p[sizeof ("i2o/hda") - 1] = '\0'; + return path; + } + + /* If this is a MultiMediaCard (MMC). */ + if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0) + { + /* /dev/mmcblk[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; + + return path; + } + + /* If this is an IDE, SCSI or Virtio disk. */ + if (strncmp ("vdisk", p, 5) == 0 + && p[5] >= 'a' && p[5] <= 'z') + { + /* /dev/vdisk[a-z][0-9]* */ + p[6] = '\0'; + return path; + } + if ((strncmp ("hd", p, 2) == 0 + || strncmp ("vd", p, 2) == 0 + || strncmp ("sd", p, 2) == 0) + && p[2] >= 'a' && p[2] <= 'z') + { + /* /dev/[hsv]d[a-z][0-9]* */ + p[3] = '\0'; + return path; + } + + /* If this is a Xen virtual block device. */ + if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z') + { + /* /dev/xvd[a-z][0-9]* */ + p[4] = '\0'; + return path; + } + } + + return path; + +#elif defined(__GNU__) + char *path = xstrdup (os_dev); + if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0) + { + char *p = strchr (path + 7, 's'); + if (p) + *p = '\0'; + } + return path; + +#elif defined(__CYGWIN__) + char *path = xstrdup (os_dev); + if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z') + path[8] = 0; + return path; + +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) + char *path = xstrdup (os_dev); + if (strncmp ("/dev/", path, 5) == 0) + { + char *p; + for (p = path + 5; *p; ++p) + if (grub_isdigit(*p)) + { + p = strchr (p, 's'); + if (p) + *p = '\0'; + break; + } + } + 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); +#endif +} + +#if defined(__linux__) || defined(__CYGWIN__) +static int +device_is_wholedisk (const char *os_dev) +{ + int len = strlen (os_dev); + + if (os_dev[len - 1] < '0' || os_dev[len - 1] > '9') + return 1; + return 0; +} +#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 +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) +{ + unsigned int i; + char *os_disk; + + os_disk = convert_system_partition_to_system_disk (os_dev); + if (! os_disk) + return -1; + + for (i = 0; i < ARRAY_SIZE (map); i++) + if (! map[i].device) + break; + else if (strcmp (map[i].device, os_disk) == 0) + { + free (os_disk); + return i; + } + + if (i == ARRAY_SIZE (map)) + grub_util_error (_("device count exceeds limit")); + + map[i].device = os_disk; + map[i].drive = xstrdup (os_disk); + + return i; +} + +char * +grub_util_biosdisk_get_grub_dev (const char *os_dev) +{ + struct stat st; + int drive; + + if (stat (os_dev, &st) < 0) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev); + return 0; + } + + drive = find_system_device (os_dev); + if (drive < 0) + { + 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) + return make_device_name (drive, -1, -1); + +#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__) || 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 + compare it with each partition GRUB recognizes. + + 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. + + 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; +# if !defined(__NetBSD__) + struct hd_geometry hdg; + typeof (hdg.start) p_offset; +# else /* defined(__NetBSD__) */ + struct disklabel label; + int index; + u_int32_t p_offset; +# endif /* !defined(__NetBSD__) */ + int dos_part = -1; + int bsd_part = -1; + auto int find_partition (grub_disk_t dsk, + const grub_partition_t partition); + + int find_partition (grub_disk_t dsk __attribute__ ((unused)), + const grub_partition_t partition) + { + grub_disk_addr_t part_start = 0; + grub_util_info ("Partition %d starts from %lu", + partition->number, partition->start); + + part_start = grub_partition_get_start (partition); + + if (p_offset == part_start) + { + if (partition->parent) + { + dos_part = partition->parent->number; + bsd_part = partition->number; + } + else + { + dos_part = partition->number; + bsd_part = -1; + } + + return 1; + } + + return 0; + } + + 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. */ + index = os_dev[strlen(os_dev) - 1] - 'a'; +# endif /* !defined(__NetBSD__) */ + + fd = open (os_dev, O_RDONLY); + if (fd == -1) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk geometry", os_dev); + free (name); + 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'", os_dev); + close (fd); + free (name); + return 0; + } + + close (fd); + +# if !defined(__NetBSD__) + p_offset = hdg.start; +# else /* defined(__NetBSD__) */ + if (index >= label.d_npartitions) + { + grub_error (GRUB_ERR_BAD_DEVICE, + "no disk label entry for `%s'", os_dev); + free (name); + return 0; + } + p_offset = label.d_partitions[index].p_offset; +# endif /* !defined(__NetBSD__) */ + + grub_util_info ("%s starts from %lu", os_dev, p_offset); + + if (p_offset == 0 && device_is_wholedisk (os_dev)) + return name; + + grub_util_info ("opening the device %s", name); + disk = grub_disk_open (name); + free (name); + + if (! disk) + return 0; + + grub_partition_iterate (disk, find_partition); + if (grub_errno != GRUB_ERR_NONE) + { + grub_disk_close (disk); + return 0; + } + + if (dos_part < 0) + { + grub_disk_close (disk); + grub_error (GRUB_ERR_BAD_DEVICE, + "cannot find the partition of `%s'", os_dev); + return 0; + } + + return make_device_name (drive, dos_part, bsd_part); + } + +#elif defined(__GNU__) + /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */ + { + char *p; + int dos_part = -1; + int bsd_part = -1; + + p = strrchr (os_dev, 's'); + if (p) + { + long int n; + char *q; + + p++; + n = strtol (p, &q, 10); + if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX) + { + dos_part = (int) n - 1; + + if (*q >= 'a' && *q <= 'g') + bsd_part = *q - 'a'; + } + } + + return make_device_name (drive, dos_part, bsd_part); + } + +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) + /* FreeBSD uses "/dev/[a-z]+[0-9]+(s[0-9]+[a-z]?)?". */ + { + int dos_part = -1; + int bsd_part = -1; + + if (strncmp ("/dev/", os_dev, 5) == 0) + { + const char *p; + char *q; + long int n; + + for (p = os_dev + 5; *p; ++p) + if (grub_isdigit(*p)) + { + p = strchr (p, 's'); + if (p) + { + p++; + n = strtol (p, &q, 10); + if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX) + { + dos_part = (int) n - 1; + + if (*q >= 'a' && *q <= 'g') + bsd_part = *q - 'a'; + } + } + break; + } + } + + return make_device_name (drive, dos_part, bsd_part); + } + +#else +# warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly." + 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/kern/emu/hostfs.c b/kern/emu/hostfs.c new file mode 100644 index 000000000..501ad4664 --- /dev/null +++ b/kern/emu/hostfs.c @@ -0,0 +1,175 @@ +/* hostfs.c - Dummy filesystem to provide access to the hosts filesystem */ +/* + * GRUB -- GRand Unified Bootloader + * 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 + * 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 _BSD_SOURCE +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* dirent.d_type is a BSD extension, not part of POSIX */ +#include +#include + +static int +is_dir (const char *path, const char *name) +{ + int len1 = strlen(path); + int len2 = strlen(name); + + char pathname[len1 + 1 + len2 + 1 + 13]; + strcpy (pathname, path); + + /* Avoid UNC-path "//name" on Cygwin. */ + if (len1 > 0 && pathname[len1 - 1] != '/') + strcat (pathname, "/"); + + strcat (pathname, name); + + struct stat st; + if (stat (pathname, &st)) + return 0; + return S_ISDIR (st.st_mode); +} + +static grub_err_t +grub_hostfs_dir (grub_device_t device, const char *path, + int (*hook) (const char *filename, + const struct grub_dirhook_info *info)) +{ + DIR *dir; + + /* Check if the disk is our dummy disk. */ + if (grub_strcmp (device->disk->name, "host")) + return grub_error (GRUB_ERR_BAD_FS, "not a hostfs"); + + dir = opendir (path); + if (! dir) + return grub_error (GRUB_ERR_BAD_FILENAME, + "can't open the hostfs directory `%s'", path); + + while (1) + { + struct dirent *de; + struct grub_dirhook_info info; + grub_memset (&info, 0, sizeof (info)); + + de = readdir (dir); + if (! de) + break; + + info.dir = !! is_dir (path, de->d_name); + hook (de->d_name, &info); + + } + + closedir (dir); + + return GRUB_ERR_NONE; +} + +/* Open a file named NAME and initialize FILE. */ +static grub_err_t +grub_hostfs_open (struct grub_file *file, const char *name) +{ + FILE *f; + + f = fopen (name, "rb"); + if (! f) + return grub_error (GRUB_ERR_BAD_FILENAME, + "can't open `%s'", name); + file->data = f; + +#ifdef __MINGW32__ + file->size = grub_util_get_disk_size (name); +#else + fseeko (f, 0, SEEK_END); + file->size = ftello (f); + fseeko (f, 0, SEEK_SET); +#endif + + return GRUB_ERR_NONE; +} + +static grub_ssize_t +grub_hostfs_read (grub_file_t file, char *buf, grub_size_t len) +{ + FILE *f; + + f = (FILE *) file->data; + if (fseeko (f, file->offset, SEEK_SET) != 0) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "fseeko: %s", strerror (errno)); + return -1; + } + + 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 +grub_hostfs_close (grub_file_t file) +{ + FILE *f; + + f = (FILE *) file->data; + fclose (f); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_hostfs_label (grub_device_t device __attribute ((unused)), + char **label __attribute ((unused))) +{ + *label = 0; + return GRUB_ERR_NONE; +} + +static struct grub_fs grub_hostfs_fs = + { + .name = "hostfs", + .dir = grub_hostfs_dir, + .open = grub_hostfs_open, + .read = grub_hostfs_read, + .close = grub_hostfs_close, + .label = grub_hostfs_label, + .next = 0 + }; + + + +GRUB_MOD_INIT(hostfs) +{ + grub_fs_register (&grub_hostfs_fs); +} + +GRUB_MOD_FINI(hostfs) +{ + grub_fs_unregister (&grub_hostfs_fs); +} diff --git a/kern/emu/lite.c b/kern/emu/lite.c new file mode 100644 index 000000000..1f06e39dc --- /dev/null +++ b/kern/emu/lite.c @@ -0,0 +1,16 @@ +#include +#include + +/* grub-emu-lite supports dynamic module loading, so it won't have any + embedded modules. */ +void +grub_init_all(void) +{ + return; +} + +void +grub_fini_all(void) +{ + return; +} diff --git a/kern/emu/main.c b/kern/emu/main.c new file mode 100644 index 000000000..978919f2a --- /dev/null +++ b/kern/emu/main.c @@ -0,0 +1,295 @@ +/* + * GRUB -- GRand Unified Bootloader + * 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 + * 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 +#include +#include +#include +#include + +#define ENABLE_RELOCATABLE 0 +#include "progname.h" + +/* Used for going back to the main function. */ +static jmp_buf main_env; + +/* Store the prefix specified by an argument. */ +static char *prefix = NULL; + +grub_addr_t +grub_arch_modules_addr (void) +{ + return 0; +} + +#if GRUB_NO_MODULES +grub_err_t +grub_arch_dl_check_header (void *ehdr) +{ + (void) ehdr; + + return GRUB_ERR_BAD_MODULE; +} + +grub_err_t +grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) +{ + (void) mod; + (void) ehdr; + + return GRUB_ERR_BAD_MODULE; +} +#endif + +void +grub_reboot (void) +{ + longjmp (main_env, 1); +} + +void +grub_halt ( +#ifdef GRUB_MACHINE_PCBIOS + int no_apm __attribute__ ((unused)) +#endif + ) +{ + grub_reboot (); +} + +void +grub_machine_init (void) +{ +} + +void +grub_machine_set_prefix (void) +{ + grub_env_set ("prefix", prefix); + free (prefix); + prefix = 0; +} + +void +grub_machine_fini (void) +{ + grub_console_fini (); +} + + + +static struct option options[] = + { + {"root-device", required_argument, 0, 'r'}, + {"device-map", required_argument, 0, 'm'}, + {"directory", required_argument, 0, 'd'}, + {"hold", optional_argument, 0, 'H'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + { 0, 0, 0, 0 } + }; + +static int +usage (int status) +{ + if (status) + fprintf (stderr, + "Try `%s --help' for more information.\n", program_name); + else + printf ( + "Usage: %s [OPTION]...\n" + "\n" + "GRUB emulator.\n" + "\n" + " -r, --root-device=DEV use DEV as the root device [default=guessed]\n" + " -m, --device-map=FILE use FILE as the device map [default=%s]\n" + " -d, --directory=DIR use GRUB files in the directory DIR [default=%s]\n" + " -v, --verbose print verbose messages\n" + " -H, --hold[=SECONDS] wait until a debugger will attach\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, 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[]) +{ + char *root_dev = 0; + char *dir = DEFAULT_DIRECTORY; + char *dev_map = DEFAULT_DEVICE_MAP; + volatile int hold = 0; + int opt; + + set_program_name (argv[0]); + + while ((opt = getopt_long (argc, argv, "r:d:m:vH:hV", options, 0)) != -1) + switch (opt) + { + case 'r': + root_dev = optarg; + break; + case 'd': + dir = optarg; + break; + case 'm': + dev_map = optarg; + break; + case 'v': + verbosity++; + break; + case 'H': + hold = (optarg ? atoi (optarg) : -1); + break; + case 'h': + return usage (0); + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + default: + return usage (1); + } + + if (optind < argc) + { + fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind]); + return usage (1); + } + + /* Wait until the ARGS.HOLD variable is cleared by an attached debugger. */ + if (hold && verbosity > 0) + printf ("Run \"gdb %s %d\", and set ARGS.HOLD to zero.\n", + program_name, (int) getpid ()); + while (hold) + { + if (hold > 0) + hold--; + + sleep (1); + } + + 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", 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'"); + } + } + + if (strcmp (root_dev, "host") == 0) + dir = xstrdup (dir); + else + dir = grub_get_prefix (dir); + prefix = xmalloc (strlen (root_dev) + 2 + strlen (dir) + 1); + sprintf (prefix, "(%s)%s", root_dev, dir); + free (dir); + + /* Start GRUB! */ + 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..d8dfc938d --- /dev/null +++ b/kern/emu/misc.c @@ -0,0 +1,199 @@ +#include + +#include +#include +#include +#include +#include + +#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 * +grub_malloc (grub_size_t size) +{ + return malloc (size); +} + +void * +grub_zalloc (grub_size_t size) +{ + void *ret; + + ret = malloc (size); + memset (ret, 0, size); + return ret; +} + +void +grub_free (void *ptr) +{ + free (ptr); +} + +void * +grub_realloc (void *ptr, grub_size_t size) +{ + return realloc (ptr, size); +} + +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 *); + + else if (align % sizeof (void *)) + grub_fatal ("bad alignment"); + + if (posix_memalign (&p, align, size) != 0) + p = 0; +#elif defined(HAVE_MEMALIGN) + p = memalign (align, size); +#else + (void) align; + (void) size; + grub_fatal ("grub_memalign is not supported"); +#endif + + if (! p) + grub_fatal ("out of memory"); + + return p; +} + +void * +xmalloc (grub_size_t size) +{ + void *p; + + p = grub_malloc (size); + if (! p) + grub_fatal ("out of memory"); + + return p; +} + +void * +xrealloc (void *ptr, grub_size_t size) +{ + ptr = grub_realloc (ptr, size); + if (! ptr) + grub_fatal ("out of memory"); + + return ptr; +} + +char * +xstrdup (const char *str) +{ + size_t len; + char *newstr; + + len = grub_strlen (str); + newstr = (char *) xmalloc (len + 1); + grub_memcpy (newstr, str, len + 1); + + return newstr; +} + +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)); +} 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/util/console.c b/util/console.c deleted file mode 100644 index 382fd7f89..000000000 --- a/util/console.c +++ /dev/null @@ -1,384 +0,0 @@ -/* console.c -- Ncurses console for GRUB. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2005,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 - -/* For compatibility. */ -#ifndef A_NORMAL -# define A_NORMAL 0 -#endif /* ! A_NORMAL */ -#ifndef A_STANDOUT -# define A_STANDOUT 0 -#endif /* ! A_STANDOUT */ - -#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; - -static grub_uint8_t grub_console_standard_color = 0x7; -static grub_uint8_t grub_console_normal_color = 0x7; -static grub_uint8_t grub_console_highlight_color = 0x70; - -#define NUM_COLORS 8 - -static grub_uint8_t color_map[NUM_COLORS] = -{ - COLOR_BLACK, - COLOR_BLUE, - COLOR_GREEN, - COLOR_CYAN, - COLOR_RED, - COLOR_MAGENTA, - COLOR_YELLOW, - COLOR_WHITE -}; - -static int use_color; - -static void -grub_ncurses_putchar (grub_uint32_t c) -{ - /* 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: - /* ncurses does not support Unicode. */ - if (c > 0x7f) - c = '?'; - break; - } - - addch (c | grub_console_attr); -} - -static grub_ssize_t -grub_ncurses_getcharwidth (grub_uint32_t code __attribute__ ((unused))) -{ - return 1; -} - -static void -grub_ncurses_setcolorstate (grub_term_color_state state) -{ - switch (state) - { - case GRUB_TERM_COLOR_STANDARD: - grub_console_cur_color = grub_console_standard_color; - grub_console_attr = A_NORMAL; - break; - case GRUB_TERM_COLOR_NORMAL: - grub_console_cur_color = grub_console_normal_color; - grub_console_attr = A_NORMAL; - break; - case GRUB_TERM_COLOR_HIGHLIGHT: - grub_console_cur_color = grub_console_highlight_color; - grub_console_attr = A_STANDOUT; - break; - default: - break; - } - - if (use_color) - { - grub_uint8_t fg, bg; - - fg = (grub_console_cur_color & 7); - bg = (grub_console_cur_color >> 4) & 7; - - grub_console_attr = (grub_console_cur_color & 8) ? A_BOLD : A_NORMAL; - color_set ((bg << 3) + fg, 0); - } -} - -/* XXX: This function is never called. */ -static void -grub_ncurses_setcolor (grub_uint8_t normal_color, grub_uint8_t highlight_color) -{ - grub_console_normal_color = normal_color; - grub_console_highlight_color = highlight_color; -} - -static void -grub_ncurses_getcolor (grub_uint8_t *normal_color, grub_uint8_t *highlight_color) -{ - *normal_color = grub_console_normal_color; - *highlight_color = grub_console_highlight_color; -} - -static int saved_char = ERR; - -static int -grub_ncurses_checkkey (void) -{ - int c; - - /* Check for SAVED_CHAR. This should not be true, because this - means checkkey is called twice continuously. */ - if (saved_char != ERR) - return saved_char; - - wtimeout (stdscr, 100); - c = getch (); - /* If C is not ERR, then put it back in the input queue. */ - if (c != ERR) - { - saved_char = c; - return c; - } - - return -1; -} - -static int -grub_ncurses_getkey (void) -{ - int c; - - /* If checkkey has already got a character, then return it. */ - if (saved_char != ERR) - { - c = saved_char; - saved_char = ERR; - } - else - { - wtimeout (stdscr, -1); - c = getch (); - } - - switch (c) - { - case KEY_LEFT: - c = 2; - break; - - case KEY_RIGHT: - c = 6; - break; - - case KEY_UP: - c = 16; - break; - - case KEY_DOWN: - c = 14; - break; - - case KEY_IC: - c = 24; - break; - - case KEY_DC: - c = 4; - break; - - case KEY_BACKSPACE: - /* XXX: For some reason ncurses on xterm does not return - KEY_BACKSPACE. */ - case 127: - c = 8; - break; - - case KEY_HOME: - c = 1; - break; - - case KEY_END: - c = 5; - break; - - case KEY_NPAGE: - c = 3; - break; - - case KEY_PPAGE: - c = 7; - break; - } - - return c; -} - -static grub_uint16_t -grub_ncurses_getxy (void) -{ - int x; - int y; - - getyx (stdscr, y, x); - - return (x << 8) | y; -} - -static grub_uint16_t -grub_ncurses_getwh (void) -{ - int x; - int y; - - getmaxyx (stdscr, y, x); - - return (x << 8) | y; -} - -static void -grub_ncurses_gotoxy (grub_uint8_t x, grub_uint8_t y) -{ - move (y, x); -} - -static void -grub_ncurses_cls (void) -{ - clear (); - refresh (); -} - -static void -grub_ncurses_setcursor (int on) -{ - curs_set (on ? 1 : 0); -} - -static void -grub_ncurses_refresh (void) -{ - refresh (); -} - -static grub_err_t -grub_ncurses_init (void) -{ - initscr (); - raw (); - noecho (); - scrollok (stdscr, TRUE); - - nonl (); - intrflush (stdscr, FALSE); - keypad (stdscr, TRUE); - - if (has_colors ()) - { - start_color (); - - if ((COLORS >= NUM_COLORS) && (COLOR_PAIRS >= NUM_COLORS * NUM_COLORS)) - { - int i, j, n; - - n = 0; - for (i = 0; i < NUM_COLORS; i++) - for (j = 0; j < NUM_COLORS; j++) - init_pair(n++, color_map[j], color_map[i]); - - use_color = 1; - } - } - - return 0; -} - -static grub_err_t -grub_ncurses_fini (void) -{ - endwin (); - return 0; -} - - -static struct grub_term_input grub_ncurses_term_input = - { - .name = "console", - .checkkey = grub_ncurses_checkkey, - .getkey = grub_ncurses_getkey, - }; - -static struct grub_term_output grub_ncurses_term_output = - { - .name = "console", - .init = grub_ncurses_init, - .fini = grub_ncurses_fini, - .putchar = grub_ncurses_putchar, - .getcharwidth = grub_ncurses_getcharwidth, - .getxy = grub_ncurses_getxy, - .getwh = grub_ncurses_getwh, - .gotoxy = grub_ncurses_gotoxy, - .cls = grub_ncurses_cls, - .setcolorstate = grub_ncurses_setcolorstate, - .setcolor = grub_ncurses_setcolor, - .getcolor = grub_ncurses_getcolor, - .setcursor = grub_ncurses_setcursor, - .refresh = grub_ncurses_refresh - }; - -void -grub_console_init (void) -{ - grub_term_register_output ("console", &grub_ncurses_term_output); - grub_term_register_input ("console", &grub_ncurses_term_input); -} - -void -grub_console_fini (void) -{ - grub_ncurses_fini (); -} diff --git a/util/getroot.c b/util/getroot.c deleted file mode 100644 index 94eadc5e1..000000000 --- a/util/getroot.c +++ /dev/null @@ -1,640 +0,0 @@ -/* getroot.c - Get root device */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,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 - -#ifdef __CYGWIN__ -# include -# include -# include -# define DEV_CYGDRIVE_MAJOR 98 -#endif - -#ifdef __GNU__ -#include -#include -#include -#endif - -#include -#include -#include - -static void -strip_extra_slashes (char *dir) -{ - char *p = dir; - - while ((p = strchr (p, '/')) != 0) - { - if (p[1] == '/') - { - memmove (p, p + 1, strlen (p)); - continue; - } - else if (p[1] == '\0') - { - if (p > dir) - p[0] = '\0'; - break; - } - - p++; - } -} - -static char * -xgetcwd (void) -{ - size_t size = 10; - char *path; - - path = xmalloc (size); - while (! getcwd (path, size)) - { - size <<= 1; - path = xrealloc (path, size); - } - - 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 * -find_root_device (const char *dir __attribute__ ((unused)), - dev_t dev __attribute__ ((unused))) -{ - return 0; -} - -#elif ! defined(__CYGWIN__) - -static char * -find_root_device (const char *dir, dev_t dev) -{ - DIR *dp; - char *saved_cwd; - struct dirent *ent; - - dp = opendir (dir); - if (! dp) - return 0; - - saved_cwd = xgetcwd (); - - grub_util_info ("changing current directory to %s", dir); - if (chdir (dir) < 0) - { - free (saved_cwd); - closedir (dp); - return 0; - } - - while ((ent = readdir (dp)) != 0) - { - struct stat st; - - /* Avoid: - - dotfiles (like "/dev/.tmp.md0") since they could be duplicates. - - dotdirs (like "/dev/.static") since they could contain duplicates. */ - if (ent->d_name[0] == '.') - continue; - - if (lstat (ent->d_name, &st) < 0) - /* Ignore any error. */ - continue; - - if (S_ISLNK (st.st_mode)) - /* Don't follow symbolic links. */ - continue; - - if (S_ISDIR (st.st_mode)) - { - /* Find it recursively. */ - char *res; - - res = find_root_device (ent->d_name, dev); - - if (res) - { - if (chdir (saved_cwd) < 0) - grub_util_error ("cannot restore the original directory"); - - free (saved_cwd); - closedir (dp); - return res; - } - } - -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) - if (S_ISCHR (st.st_mode) && st.st_rdev == dev) -#else - if (S_ISBLK (st.st_mode) && st.st_rdev == dev) -#endif - { -#ifdef __linux__ - /* Skip device names like /dev/dm-0, which are short-hand aliases - to more descriptive device names, e.g. those under /dev/mapper */ - if (ent->d_name[0] == 'd' && - ent->d_name[1] == 'm' && - ent->d_name[2] == '-' && - ent->d_name[3] >= '0' && - ent->d_name[3] <= '9') - continue; -#endif - - /* 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) + 3); - sprintf (res, template, cwd, ent->d_name); - strip_extra_slashes (res); - free (cwd); - - /* /dev/root is not a real block device keep looking, takes care - of situation where root filesystem is on the same partition as - grub files */ - - if (strcmp(res, "/dev/root") == 0) - continue; - - if (chdir (saved_cwd) < 0) - grub_util_error ("cannot restore the original directory"); - - free (saved_cwd); - closedir (dp); - return res; - } - } - - if (chdir (saved_cwd) < 0) - grub_util_error ("cannot restore the original directory"); - - free (saved_cwd); - closedir (dp); - return 0; -} - -#else /* __CYGWIN__ */ - -/* Read drive/partition serial number from mbr/boot sector, - return 0 on read error, ~0 on unknown serial. */ -static unsigned -get_bootsec_serial (const char *os_dev, int mbr) -{ - /* Read boot sector. */ - int fd = open (os_dev, O_RDONLY); - if (fd < 0) - return 0; - unsigned char buf[0x200]; - int n = read (fd, buf, sizeof (buf)); - close (fd); - if (n != sizeof(buf)) - return 0; - - /* Check signature. */ - if (!(buf[0x1fe] == 0x55 && buf[0x1ff] == 0xaa)) - return ~0; - - /* Serial number offset depends on boot sector type. */ - if (mbr) - n = 0x1b8; - else if (memcmp (buf + 0x03, "NTFS", 4) == 0) - n = 0x048; - else if (memcmp (buf + 0x52, "FAT32", 5) == 0) - n = 0x043; - else if (memcmp (buf + 0x36, "FAT", 3) == 0) - n = 0x027; - else - return ~0; - - unsigned serial = *(unsigned *)(buf + n); - if (serial == 0) - return ~0; - return serial; -} - -static char * -find_cygwin_root_device (const char *path, dev_t dev) -{ - /* No root device for /cygdrive. */ - if (dev == (DEV_CYGDRIVE_MAJOR << 16)) - return 0; - - /* Convert to full POSIX and Win32 path. */ - char fullpath[PATH_MAX], winpath[PATH_MAX]; - cygwin_conv_to_full_posix_path (path, fullpath); - cygwin_conv_to_full_win32_path (fullpath, winpath); - - /* If identical, this is no real filesystem path. */ - if (strcmp (fullpath, winpath) == 0) - return 0; - - /* Check for floppy drive letter. */ - if (winpath[0] && winpath[1] == ':' && strchr ("AaBb", winpath[0])) - return xstrdup (strchr ("Aa", winpath[0]) ? "/dev/fd0" : "/dev/fd1"); - - /* Cygwin returns the partition serial number in stat.st_dev. - This is never identical to the device number of the emulated - /dev/sdXN device, so above find_root_device () does not work. - Search the partition with the same serial in boot sector instead. */ - char devpath[sizeof ("/dev/sda15") + 13]; /* Size + Paranoia. */ - int d; - for (d = 'a'; d <= 'z'; d++) - { - sprintf (devpath, "/dev/sd%c", d); - if (get_bootsec_serial (devpath, 1) == 0) - continue; - int p; - for (p = 1; p <= 15; p++) - { - sprintf (devpath, "/dev/sd%c%d", d, p); - unsigned ser = get_bootsec_serial (devpath, 0); - if (ser == 0) - break; - if (ser != (unsigned)~0 && dev == (dev_t)ser) - return xstrdup (devpath); - } - } - return 0; -} - -#endif /* __CYGWIN__ */ - -char * -grub_guess_root_device (const char *dir) -{ - char *os_dev; -#ifdef __GNU__ - file_t file; - mach_port_t *ports; - int *ints; - loff_t *offsets; - char *data; - error_t err; - mach_msg_type_number_t num_ports = 0, num_ints = 0, num_offsets = 0, data_len = 0; - size_t name_len; - - file = file_name_lookup (dir, 0, 0); - if (file == MACH_PORT_NULL) - return 0; - - err = file_get_storage_info (file, - &ports, &num_ports, - &ints, &num_ints, - &offsets, &num_offsets, - &data, &data_len); - - if (num_ints < 1) - grub_util_error ("Storage info for `%s' does not include type", dir); - if (ints[0] != STORAGE_DEVICE) - grub_util_error ("Filesystem of `%s' is not stored on local disk", dir); - - if (num_ints < 5) - grub_util_error ("Storage info for `%s' does not include name", dir); - name_len = ints[4]; - if (name_len < data_len) - grub_util_error ("Bogus name length for storage info for `%s'", dir); - if (data[name_len - 1] != '\0') - grub_util_error ("Storage name for `%s' not NUL-terminated", dir); - - os_dev = xmalloc (strlen ("/dev/") + data_len); - memcpy (os_dev, "/dev/", strlen ("/dev/")); - memcpy (os_dev + strlen ("/dev/"), data, data_len); - - if (ports && num_ports > 0) - { - mach_msg_type_number_t i; - for (i = 0; i < num_ports; i++) - { - mach_port_t port = ports[i]; - if (port != MACH_PORT_NULL) - mach_port_deallocate (mach_task_self(), port); - } - munmap ((caddr_t) ports, num_ports * sizeof (*ports)); - } - - if (ints && num_ints > 0) - munmap ((caddr_t) ints, num_ints * sizeof (*ints)); - if (offsets && num_offsets > 0) - munmap ((caddr_t) offsets, num_offsets * sizeof (*offsets)); - if (data && data_len > 0) - munmap (data, data_len); - mach_port_deallocate (mach_task_self (), file); -#else /* !__GNU__ */ - struct stat st; - - if (stat (dir, &st) < 0) - grub_util_error ("cannot stat `%s'", dir); - -#ifdef __CYGWIN__ - /* Cygwin specific function. */ - os_dev = find_cygwin_root_device (dir, st.st_dev); - -#else - - /* This might be truly slow, but is there any better way? */ - os_dev = find_root_device ("/dev", st.st_dev); -#endif -#endif /* !__GNU__ */ - - return os_dev; -} - -static int -grub_util_is_dmraid (const char *os_dev) -{ - if (! strncmp (os_dev, "/dev/mapper/nvidia_", 19)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/isw_", 16)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/hpt37x_", 19)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/hpt45x_", 19)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/via_", 16)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/lsi_", 16)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/pdc_", 16)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/jmicron_", 20)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/asr_", 16)) - 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 __attribute__((unused))) -{ -#ifdef __linux__ - /* Check for LVM. */ - if (!strncmp (os_dev, "/dev/mapper/", 12) - && ! grub_util_is_dmraid (os_dev) - && strncmp (os_dev, "/dev/mapper/mpath", 17) != 0) - return GRUB_DEV_ABSTRACTION_LVM; - - /* Check for RAID. */ - if (!strncmp (os_dev, "/dev/md", 7)) - return GRUB_DEV_ABSTRACTION_RAID; -#endif - - /* No abstraction found. */ - return GRUB_DEV_ABSTRACTION_NONE; -} - -char * -grub_util_get_grub_dev (const char *os_dev) -{ - char *grub_dev; - - switch (grub_util_get_dev_abstraction (os_dev)) - { - case GRUB_DEV_ABSTRACTION_LVM: - - { - unsigned short i, len; - grub_size_t offset = sizeof ("/dev/mapper/") - 1; - - len = strlen (os_dev) - offset + 1; - grub_dev = xmalloc (len); - - for (i = 0; i < len; i++, offset++) - { - grub_dev[i] = os_dev[offset]; - if (os_dev[offset] == '-' && os_dev[offset + 1] == '-') - offset++; - } - } - - break; - - case GRUB_DEV_ABSTRACTION_RAID: - - if (os_dev[7] == '_' && os_dev[8] == 'd') - { - /* This a partitionable RAID device of the form /dev/md_dNNpMM. */ - - char *p, *q; - - p = strdup (os_dev + sizeof ("/dev/md_d") - 1); - - q = strchr (p, 'p'); - if (q) - *q = ','; - - grub_dev = xasprintf ("md%s", p); - free (p); - } - else if (os_dev[7] == '/' && os_dev[8] == 'd') - { - /* This a partitionable RAID device of the form /dev/md/dNNpMM. */ - - char *p, *q; - - p = strdup (os_dev + sizeof ("/dev/md/d") - 1); - - q = strchr (p, 'p'); - if (q) - *q = ','; - - grub_dev = xasprintf ("md%s", p); - free (p); - } - else if (os_dev[7] >= '0' && os_dev[7] <= '9') - { - char *p , *q; - - p = strdup (os_dev + sizeof ("/dev/md") - 1); - - q = strchr (p, 'p'); - if (q) - *q = ','; - - grub_dev = xasprintf ("md%s", p); - free (p); - } - else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9') - { - char *p , *q; - - p = strdup (os_dev + sizeof ("/dev/md/") - 1); - - q = strchr (p, 'p'); - if (q) - *q = ','; - - grub_dev = xasprintf ("md%s", p); - free (p); - } - else - grub_util_error ("unknown kind of RAID device `%s'", os_dev); - - break; - - default: /* GRUB_DEV_ABSTRACTION_NONE */ - grub_dev = grub_util_biosdisk_get_grub_dev (os_dev); - } - - return grub_dev; -} - -const char * -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); - - if (S_ISBLK (st.st_mode)) - return (blk_dev); - else - return 0; -} - -const char * -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); - - if (S_ISCHR (st.st_mode)) - return (blk_dev); - else - return 0; -} - diff --git a/util/grub-emu.c b/util/grub-emu.c deleted file mode 100644 index 8660f0aa0..000000000 --- a/util/grub-emu.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * 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 - * 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 -#include - -#define ENABLE_RELOCATABLE 0 -#include "progname.h" - -/* Used for going back to the main function. */ -static jmp_buf main_env; - -/* Store the prefix specified by an argument. */ -static char *prefix = NULL; - -grub_addr_t -grub_arch_modules_addr (void) -{ - return 0; -} - -#if GRUB_NO_MODULES -grub_err_t -grub_arch_dl_check_header (void *ehdr) -{ - (void) ehdr; - - return GRUB_ERR_BAD_MODULE; -} - -grub_err_t -grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) -{ - (void) mod; - (void) ehdr; - - return GRUB_ERR_BAD_MODULE; -} -#endif - -void -grub_reboot (void) -{ - longjmp (main_env, 1); -} - -void -grub_halt ( -#ifdef GRUB_MACHINE_PCBIOS - int no_apm __attribute__ ((unused)) -#endif - ) -{ - grub_reboot (); -} - -void -grub_machine_init (void) -{ -} - -void -grub_machine_set_prefix (void) -{ - grub_env_set ("prefix", prefix); - free (prefix); - prefix = 0; -} - -void -grub_machine_fini (void) -{ - grub_console_fini (); -} - - - -static struct option options[] = - { - {"root-device", required_argument, 0, 'r'}, - {"device-map", required_argument, 0, 'm'}, - {"directory", required_argument, 0, 'd'}, - {"hold", optional_argument, 0, 'H'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {"verbose", no_argument, 0, 'v'}, - { 0, 0, 0, 0 } - }; - -static int -usage (int status) -{ - if (status) - fprintf (stderr, - "Try `%s --help' for more information.\n", program_name); - else - printf ( - "Usage: %s [OPTION]...\n" - "\n" - "GRUB emulator.\n" - "\n" - " -r, --root-device=DEV use DEV as the root device [default=guessed]\n" - " -m, --device-map=FILE use FILE as the device map [default=%s]\n" - " -d, --directory=DIR use GRUB files in the directory DIR [default=%s]\n" - " -v, --verbose print verbose messages\n" - " -H, --hold[=SECONDS] wait until a debugger will attach\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, 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[]) -{ - char *root_dev = 0; - char *dir = DEFAULT_DIRECTORY; - char *dev_map = DEFAULT_DEVICE_MAP; - volatile int hold = 0; - int opt; - - set_program_name (argv[0]); - - while ((opt = getopt_long (argc, argv, "r:d:m:vH:hV", options, 0)) != -1) - switch (opt) - { - case 'r': - root_dev = optarg; - break; - case 'd': - dir = optarg; - break; - case 'm': - dev_map = optarg; - break; - case 'v': - verbosity++; - break; - case 'H': - hold = (optarg ? atoi (optarg) : -1); - break; - case 'h': - return usage (0); - case 'V': - printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); - return 0; - default: - return usage (1); - } - - if (optind < argc) - { - fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind]); - return usage (1); - } - - /* Wait until the ARGS.HOLD variable is cleared by an attached debugger. */ - if (hold && verbosity > 0) - printf ("Run \"gdb %s %d\", and set ARGS.HOLD to zero.\n", - program_name, (int) getpid ()); - while (hold) - { - if (hold > 0) - hold--; - - sleep (1); - } - - 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", 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'"); - } - } - - if (strcmp (root_dev, "host") == 0) - dir = xstrdup (dir); - else - dir = grub_get_prefix (dir); - prefix = xmalloc (strlen (root_dev) + 2 + strlen (dir) + 1); - sprintf (prefix, "(%s)%s", root_dev, dir); - free (dir); - - /* Start GRUB! */ - 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; -} diff --git a/util/grub-probe.c b/util/grub-probe.c index bb41480e2..1b2606dc7 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -26,8 +27,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/util/hostdisk.c b/util/hostdisk.c deleted file mode 100644 index 8be487461..000000000 --- a/util/hostdisk.c +++ /dev/null @@ -1,1360 +0,0 @@ -/* hostdisk.c - emulate biosdisk */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 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 -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __linux__ -# include /* ioctl */ -# if !defined(__GLIBC__) || \ - ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))) -/* Maybe libc doesn't have large file support. */ -# include /* _llseek */ -# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */ -# ifndef BLKFLSBUF -# define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */ -# endif /* ! BLKFLSBUF */ -# include /* ioctl */ -# ifndef HDIO_GETGEO -# define HDIO_GETGEO 0x0301 /* get device geometry */ -/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is - defined. */ -struct hd_geometry -{ - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; - unsigned long start; -}; -# endif /* ! HDIO_GETGEO */ -# ifndef BLKGETSIZE64 -# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */ -# endif /* ! BLKGETSIZE64 */ -# ifndef MAJOR -# ifndef MINORBITS -# define MINORBITS 8 -# endif /* ! MINORBITS */ -# define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS)) -# endif /* ! MAJOR */ -# ifndef FLOPPY_MAJOR -# define FLOPPY_MAJOR 2 -# endif /* ! FLOPPY_MAJOR */ -# ifndef LOOP_MAJOR -# define LOOP_MAJOR 7 -# endif /* ! LOOP_MAJOR */ -#endif /* __linux__ */ - -#ifdef __CYGWIN__ -# include -# include /* BLKGETSIZE64 */ -# include /* HDIO_GETGEO */ -# define MAJOR(dev) ((unsigned) ((dev) >> 16)) -# define FLOPPY_MAJOR 2 -#endif - -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -# include /* DIOCGMEDIASIZE */ -# include -# include -#endif - -#if defined(__APPLE__) -# 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 -have_devfs (void) -{ - static int dev_devfsd_exists = -1; - - if (dev_devfsd_exists < 0) - { - struct stat st; - - dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0; - } - - return dev_devfsd_exists; -} -#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) -{ - unsigned int i; - - if (name) - { - for (i = 0; i < ARRAY_SIZE (map); i++) - if (map[i].drive && ! strcmp (map[i].drive, name)) - return i; - } - - return -1; -} - -static int -find_free_slot (void) -{ - unsigned int i; - - for (i = 0; i < sizeof (map) / sizeof (map[0]); i++) - if (! map[i].drive) - return i; - - return -1; -} - -static int -grub_util_biosdisk_iterate (int (*hook) (const char *name)) -{ - unsigned i; - - for (i = 0; i < sizeof (map) / sizeof (map[0]); i++) - if (map[i].drive && hook (map[i].drive)) - return 1; - - return 0; -} - -static grub_err_t -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_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__) - { - grub_uint64_t size; - - size = grub_util_get_disk_size (map[drive].device); - - if (size % 512) - grub_util_error ("unaligned device size"); - - disk->total_sectors = size >> 9; - - grub_util_info ("the size of %s is %llu", name, disk->total_sectors); - - return GRUB_ERR_NONE; - } -#elif defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \ - 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_UNKNOWN_DEVICE, "cannot open `%s' while attempting to get disk size", map[drive].device); - -# 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)) -# endif - { - close (fd); - goto fail; - } - -# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - 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 - { - close (fd); - goto fail; - } - - close (fd); - -# if defined (__APPLE__) - disk->total_sectors = nr; -# 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 - - grub_util_info ("the size of %s is %llu", name, disk->total_sectors); - - return GRUB_ERR_NONE; - } - - fail: - /* In GNU/Hurd, stat() will return the right size. */ -#elif !defined (__GNU__) -# 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_UNKNOWN_DEVICE, "cannot stat `%s'", map[drive].device); - - disk->total_sectors = st.st_size >> GRUB_DISK_SECTOR_BITS; - - grub_util_info ("the size of %s is %lu", name, disk->total_sectors); - - return GRUB_ERR_NONE; -} - -#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) -{ - size_t len = strlen (dev); - const char *format; - char *p; - int i; - char real_dev[PATH_MAX]; - struct linux_partition_cache *cache; - - strcpy(real_dev, dev); - - if (have_devfs () && strcmp (real_dev + len - 5, "/disc") == 0) - { - p = real_dev + len - 4; - format = "part%d"; - } - else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9') - { - p = real_dev + len; - format = "p%d"; - } - else - { - p = real_dev + len; - 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; - - 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) - { - 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 = hdg.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; - } - } - - return 0; -} -#endif /* __linux__ */ - -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; -#endif -#ifdef O_SYNC - flags |= O_SYNC; -#endif -#ifdef O_FSYNC - flags |= O_FSYNC; -#endif -#ifdef O_BINARY - flags |= O_BINARY; -#endif - -#ifdef __linux__ - /* Linux has a bug that the disk cache for a whole disk is not consistent - with the one for a partition of the disk. */ - { - 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 && sector >= part_start - && strncmp (map[disk->id].device, "/dev/", 5) == 0) - is_partition = linux_find_partition (dev, part_start); - - if (data->dev && strcmp (data->dev, dev) == 0 && - data->access_mode == (flags & O_ACCMODE)) - { - 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; - } - - if (is_partition) - sector -= part_start; - } -#else /* ! __linux__ */ -#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) - int sysctl_flags, sysctl_oldflags; - size_t sysctl_size = sizeof (sysctl_flags); - - if (sysctlbyname ("kern.geom.debugflags", &sysctl_oldflags, &sysctl_size, NULL, 0)) - { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot get current flags of sysctl kern.geom.debugflags"); - return -1; - } - sysctl_flags = sysctl_oldflags | 0x10; - if (! (sysctl_oldflags & 0x10) - && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_flags, sysctl_size)) - { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags of sysctl kern.geom.debugflags"); - return -1; - } -#endif - - 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) - && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_oldflags, sysctl_size)) - { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags back to the old value for sysctl kern.geom.debugflags"); - return -1; - } -#endif - -#if defined(__APPLE__) - /* If we can't have exclusive access, try shared access */ - if (fd < 0) - fd = open(map[disk->id].device, flags | O_SHLOCK); -#endif - - if (fd < 0) - { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' in open_device()", map[disk->id].device); - return -1; - } -#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. */ - { - loff_t offset, result; - static int _llseek (uint filedes, ulong hi, ulong lo, - loff_t *res, uint wh); - _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo, - loff_t *, res, uint, wh); - - offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS; - if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET)) - { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device); - close (fd); - return -1; - } - } -#else - { - off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS; - - if (lseek (fd, offset, SEEK_SET) != offset) - { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device); - close (fd); - return -1; - } - } -#endif - - return fd; -} - -/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an - error occurs, otherwise return LEN. */ -static ssize_t -nread (int fd, char *buf, size_t len) -{ - ssize_t size = len; - - while (len) - { - ssize_t ret = read (fd, buf, len); - - if (ret <= 0) - { - if (errno == EINTR) - continue; - else - return ret; - } - - len -= ret; - buf += ret; - } - - return size; -} - -/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an - error occurs, otherwise return LEN. */ -static ssize_t -nwrite (int fd, const char *buf, size_t len) -{ - ssize_t size = len; - - while (len) - { - ssize_t ret = write (fd, buf, len); - - if (ret <= 0) - { - if (errno == EINTR) - continue; - else - return ret; - } - - len -= ret; - buf += ret; - } - - return size; -} - -static grub_err_t -grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, - grub_size_t size, char *buf) -{ - 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; - -#ifdef __linux__ - if (sector == 0 && size > 1) - { - /* Work around a bug in Linux ez remapping. Linux remaps all - sectors that are read together with the MBR in one read. It - should only remap the MBR, so we split the read in two - parts. -jochen */ - if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE) - { - grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device); - close (fd); - return grub_errno; - } - - buf += GRUB_DISK_SECTOR_SIZE; - size--; - } -#endif /* __linux__ */ - - if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS) - != (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) - grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device); - - return grub_errno; -} - -static grub_err_t -grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector, - grub_size_t size, const char *buf) -{ - 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; - - if (nwrite (fd, buf, size << GRUB_DISK_SECTOR_BITS) - != (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) - grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device); - - 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 = grub_util_biosdisk_close, - .read = grub_util_biosdisk_read, - .write = grub_util_biosdisk_write, - .next = 0 - }; - -static void -read_device_map (const char *dev_map) -{ - FILE *fp; - char buf[1024]; /* XXX */ - int lineno = 0; - struct stat st; - - auto void show_error (const char *msg); - void show_error (const char *msg) - { - grub_util_error ("%s:%d: %s", dev_map, lineno, msg); - } - - fp = fopen (dev_map, "r"); - if (! fp) - { - grub_util_info (_("cannot open `%s'"), dev_map); - return; - } - - while (fgets (buf, sizeof (buf), fp)) - { - char *p = buf; - char *e; - int drive; - - lineno++; - - /* Skip leading spaces. */ - while (*p && isspace (*p)) - p++; - - /* If the first character is `#' or NUL, skip this line. */ - if (*p == '\0' || *p == '#') - continue; - - if (*p != '(') - show_error ("No open parenthesis found"); - - p++; - /* Find a free slot. */ - drive = find_free_slot (); - if (drive < 0) - show_error ("Map table size exceeded"); - - e = p; - p = strchr (p, ')'); - if (! p) - show_error ("No close parenthesis found"); - - map[drive].drive = xmalloc (p - e + sizeof ('\0')); - strncpy (map[drive].drive, e, p - e + sizeof ('\0')); - map[drive].drive[p - e] = '\0'; - - p++; - /* Skip leading spaces. */ - while (*p && isspace (*p)) - p++; - - if (*p == '\0') - show_error ("No filename found"); - - /* NUL-terminate the filename. */ - e = p; - while (*e && ! isspace (*e)) - e++; - *e = '\0'; - -#ifdef __MINGW32__ - (void) st; - if (grub_util_get_disk_size (p) == -1LL) -#else - if (stat (p, &st) == -1) -#endif - { - free (map[drive].drive); - map[drive].drive = NULL; - grub_util_info ("Cannot stat `%s', skipping", p); - continue; - } - -#ifdef __linux__ - /* On Linux, the devfs uses symbolic links horribly, and that - confuses the interface very much, so use realpath to expand - 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); -#else - map[drive].device = xstrdup (p); -#endif - } - - fclose (fp); -} - -void -grub_util_biosdisk_init (const char *dev_map) -{ - read_device_map (dev_map); - grub_disk_dev_register (&grub_util_biosdisk_dev); -} - -void -grub_util_biosdisk_fini (void) -{ - unsigned i; - - for (i = 0; i < sizeof (map) / sizeof (map[0]); i++) - { - if (map[i].drive) - free (map[i].drive); - if (map[i].device) - free (map[i].device); - map[i].drive = map[i].device = NULL; - } - - grub_disk_dev_unregister (&grub_util_biosdisk_dev); -} - -static char * -make_device_name (int drive, int dos_part, int bsd_part) -{ - char *ret; - char *dos_part_str = NULL; - char *bsd_part_str = NULL; - - if (dos_part >= 0) - dos_part_str = xasprintf (",%d", dos_part + 1); - - if (bsd_part >= 0) - bsd_part_str = xasprintf (",%d", bsd_part + 1); - - ret = xasprintf ("%s%s%s", map[drive].drive, - dos_part_str ? : "", - bsd_part_str ? : ""); - - if (dos_part_str) - free (dos_part_str); - - if (bsd_part_str) - free (bsd_part_str); - - return ret; -} - -static char * -convert_system_partition_to_system_disk (const char *os_dev) -{ -#if defined(__linux__) - char *path = xmalloc (PATH_MAX); - if (! realpath (os_dev, path)) - return NULL; - - if (strncmp ("/dev/", path, 5) == 0) - { - char *p = path + 5; - - /* If this is an IDE disk. */ - if (strncmp ("ide/", p, 4) == 0) - { - p = strstr (p, "part"); - if (p) - strcpy (p, "disc"); - - return path; - } - - /* If this is a SCSI disk. */ - if (strncmp ("scsi/", p, 5) == 0) - { - p = strstr (p, "part"); - if (p) - strcpy (p, "disc"); - - return path; - } - - /* If this is a DAC960 disk. */ - if (strncmp ("rd/c", p, 4) == 0) - { - /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */ - p = strchr (p, 'p'); - if (p) - *p = '\0'; - - return path; - } - - /* If this is a Mylex AcceleRAID Array. */ - if (strncmp ("rs/c", p, 4) == 0) - { - /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */ - p = strchr (p, 'p'); - if (p) - *p = '\0'; - - return path; - } - /* If this is a CCISS disk. */ - if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0) - { - /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */ - p = strchr (p, 'p'); - if (p) - *p = '\0'; - - return path; - } - - /* If this is a Compaq Intelligent Drive Array. */ - if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0) - { - /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */ - p = strchr (p, 'p'); - if (p) - *p = '\0'; - - return path; - } - - /* If this is an I2O disk. */ - if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0) - { - /* /dev/i2o/hd[a-z]([0-9]+)? */ - p[sizeof ("i2o/hda") - 1] = '\0'; - return path; - } - - /* If this is a MultiMediaCard (MMC). */ - if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0) - { - /* /dev/mmcblk[0-9]+(p[0-9]+)? */ - p = strchr (p, 'p'); - if (p) - *p = '\0'; - - return path; - } - - /* If this is an IDE, SCSI or Virtio disk. */ - if (strncmp ("vdisk", p, 5) == 0 - && p[5] >= 'a' && p[5] <= 'z') - { - /* /dev/vdisk[a-z][0-9]* */ - p[6] = '\0'; - return path; - } - if ((strncmp ("hd", p, 2) == 0 - || strncmp ("vd", p, 2) == 0 - || strncmp ("sd", p, 2) == 0) - && p[2] >= 'a' && p[2] <= 'z') - { - /* /dev/[hsv]d[a-z][0-9]* */ - p[3] = '\0'; - return path; - } - - /* If this is a Xen virtual block device. */ - if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z') - { - /* /dev/xvd[a-z][0-9]* */ - p[4] = '\0'; - return path; - } - } - - return path; - -#elif defined(__GNU__) - char *path = xstrdup (os_dev); - if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0) - { - char *p = strchr (path + 7, 's'); - if (p) - *p = '\0'; - } - return path; - -#elif defined(__CYGWIN__) - char *path = xstrdup (os_dev); - if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z') - path[8] = 0; - return path; - -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) - char *path = xstrdup (os_dev); - if (strncmp ("/dev/", path, 5) == 0) - { - char *p; - for (p = path + 5; *p; ++p) - if (grub_isdigit(*p)) - { - p = strchr (p, 's'); - if (p) - *p = '\0'; - break; - } - } - 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); -#endif -} - -#if defined(__linux__) || defined(__CYGWIN__) -static int -device_is_wholedisk (const char *os_dev) -{ - int len = strlen (os_dev); - - if (os_dev[len - 1] < '0' || os_dev[len - 1] > '9') - return 1; - return 0; -} -#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 -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) -{ - unsigned int i; - char *os_disk; - - os_disk = convert_system_partition_to_system_disk (os_dev); - if (! os_disk) - return -1; - - for (i = 0; i < ARRAY_SIZE (map); i++) - if (! map[i].device) - break; - else if (strcmp (map[i].device, os_disk) == 0) - { - free (os_disk); - return i; - } - - if (i == ARRAY_SIZE (map)) - grub_util_error (_("device count exceeds limit")); - - map[i].device = os_disk; - map[i].drive = xstrdup (os_disk); - - return i; -} - -char * -grub_util_biosdisk_get_grub_dev (const char *os_dev) -{ - struct stat st; - int drive; - - if (stat (os_dev, &st) < 0) - { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev); - return 0; - } - - drive = find_system_device (os_dev); - if (drive < 0) - { - 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) - return make_device_name (drive, -1, -1); - -#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__) || 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 - compare it with each partition GRUB recognizes. - - 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. - - 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; -# if !defined(__NetBSD__) - struct hd_geometry hdg; - typeof (hdg.start) p_offset; -# else /* defined(__NetBSD__) */ - struct disklabel label; - int index; - u_int32_t p_offset; -# endif /* !defined(__NetBSD__) */ - int dos_part = -1; - int bsd_part = -1; - auto int find_partition (grub_disk_t dsk, - const grub_partition_t partition); - - int find_partition (grub_disk_t dsk __attribute__ ((unused)), - const grub_partition_t partition) - { - grub_disk_addr_t part_start = 0; - grub_util_info ("Partition %d starts from %lu", - partition->number, partition->start); - - part_start = grub_partition_get_start (partition); - - if (p_offset == part_start) - { - if (partition->parent) - { - dos_part = partition->parent->number; - bsd_part = partition->number; - } - else - { - dos_part = partition->number; - bsd_part = -1; - } - - return 1; - } - - return 0; - } - - 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. */ - index = os_dev[strlen(os_dev) - 1] - 'a'; -# endif /* !defined(__NetBSD__) */ - - fd = open (os_dev, O_RDONLY); - if (fd == -1) - { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk geometry", os_dev); - free (name); - 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'", os_dev); - close (fd); - free (name); - return 0; - } - - close (fd); - -# if !defined(__NetBSD__) - p_offset = hdg.start; -# else /* defined(__NetBSD__) */ - if (index >= label.d_npartitions) - { - grub_error (GRUB_ERR_BAD_DEVICE, - "no disk label entry for `%s'", os_dev); - free (name); - return 0; - } - p_offset = label.d_partitions[index].p_offset; -# endif /* !defined(__NetBSD__) */ - - grub_util_info ("%s starts from %lu", os_dev, p_offset); - - if (p_offset == 0 && device_is_wholedisk (os_dev)) - return name; - - grub_util_info ("opening the device %s", name); - disk = grub_disk_open (name); - free (name); - - if (! disk) - return 0; - - grub_partition_iterate (disk, find_partition); - if (grub_errno != GRUB_ERR_NONE) - { - grub_disk_close (disk); - return 0; - } - - if (dos_part < 0) - { - grub_disk_close (disk); - grub_error (GRUB_ERR_BAD_DEVICE, - "cannot find the partition of `%s'", os_dev); - return 0; - } - - return make_device_name (drive, dos_part, bsd_part); - } - -#elif defined(__GNU__) - /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */ - { - char *p; - int dos_part = -1; - int bsd_part = -1; - - p = strrchr (os_dev, 's'); - if (p) - { - long int n; - char *q; - - p++; - n = strtol (p, &q, 10); - if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX) - { - dos_part = (int) n - 1; - - if (*q >= 'a' && *q <= 'g') - bsd_part = *q - 'a'; - } - } - - return make_device_name (drive, dos_part, bsd_part); - } - -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) - /* FreeBSD uses "/dev/[a-z]+[0-9]+(s[0-9]+[a-z]?)?". */ - { - int dos_part = -1; - int bsd_part = -1; - - if (strncmp ("/dev/", os_dev, 5) == 0) - { - const char *p; - char *q; - long int n; - - for (p = os_dev + 5; *p; ++p) - if (grub_isdigit(*p)) - { - p = strchr (p, 's'); - if (p) - { - p++; - n = strtol (p, &q, 10); - if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX) - { - dos_part = (int) n - 1; - - if (*q >= 'a' && *q <= 'g') - bsd_part = *q - 'a'; - } - } - break; - } - } - - return make_device_name (drive, dos_part, bsd_part); - } - -#else -# warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly." - 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/util/hostfs.c deleted file mode 100644 index 501ad4664..000000000 --- a/util/hostfs.c +++ /dev/null @@ -1,175 +0,0 @@ -/* hostfs.c - Dummy filesystem to provide access to the hosts filesystem */ -/* - * GRUB -- GRand Unified Bootloader - * 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 - * 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 _BSD_SOURCE -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -/* dirent.d_type is a BSD extension, not part of POSIX */ -#include -#include - -static int -is_dir (const char *path, const char *name) -{ - int len1 = strlen(path); - int len2 = strlen(name); - - char pathname[len1 + 1 + len2 + 1 + 13]; - strcpy (pathname, path); - - /* Avoid UNC-path "//name" on Cygwin. */ - if (len1 > 0 && pathname[len1 - 1] != '/') - strcat (pathname, "/"); - - strcat (pathname, name); - - struct stat st; - if (stat (pathname, &st)) - return 0; - return S_ISDIR (st.st_mode); -} - -static grub_err_t -grub_hostfs_dir (grub_device_t device, const char *path, - int (*hook) (const char *filename, - const struct grub_dirhook_info *info)) -{ - DIR *dir; - - /* Check if the disk is our dummy disk. */ - if (grub_strcmp (device->disk->name, "host")) - return grub_error (GRUB_ERR_BAD_FS, "not a hostfs"); - - dir = opendir (path); - if (! dir) - return grub_error (GRUB_ERR_BAD_FILENAME, - "can't open the hostfs directory `%s'", path); - - while (1) - { - struct dirent *de; - struct grub_dirhook_info info; - grub_memset (&info, 0, sizeof (info)); - - de = readdir (dir); - if (! de) - break; - - info.dir = !! is_dir (path, de->d_name); - hook (de->d_name, &info); - - } - - closedir (dir); - - return GRUB_ERR_NONE; -} - -/* Open a file named NAME and initialize FILE. */ -static grub_err_t -grub_hostfs_open (struct grub_file *file, const char *name) -{ - FILE *f; - - f = fopen (name, "rb"); - if (! f) - return grub_error (GRUB_ERR_BAD_FILENAME, - "can't open `%s'", name); - file->data = f; - -#ifdef __MINGW32__ - file->size = grub_util_get_disk_size (name); -#else - fseeko (f, 0, SEEK_END); - file->size = ftello (f); - fseeko (f, 0, SEEK_SET); -#endif - - return GRUB_ERR_NONE; -} - -static grub_ssize_t -grub_hostfs_read (grub_file_t file, char *buf, grub_size_t len) -{ - FILE *f; - - f = (FILE *) file->data; - if (fseeko (f, file->offset, SEEK_SET) != 0) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "fseeko: %s", strerror (errno)); - return -1; - } - - 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 -grub_hostfs_close (grub_file_t file) -{ - FILE *f; - - f = (FILE *) file->data; - fclose (f); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_hostfs_label (grub_device_t device __attribute ((unused)), - char **label __attribute ((unused))) -{ - *label = 0; - return GRUB_ERR_NONE; -} - -static struct grub_fs grub_hostfs_fs = - { - .name = "hostfs", - .dir = grub_hostfs_dir, - .open = grub_hostfs_open, - .read = grub_hostfs_read, - .close = grub_hostfs_close, - .label = grub_hostfs_label, - .next = 0 - }; - - - -GRUB_MOD_INIT(hostfs) -{ - grub_fs_register (&grub_hostfs_fs); -} - -GRUB_MOD_FINI(hostfs) -{ - grub_fs_unregister (&grub_hostfs_fs); -} diff --git a/util/pci.c b/util/pci.c deleted file mode 100644 index 420ae320b..000000000 --- a/util/pci.c +++ /dev/null @@ -1,76 +0,0 @@ -/* 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/util/sdl.c b/util/sdl.c deleted file mode 100644 index d261db6b0..000000000 --- a/util/sdl.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * 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/util/time.c b/util/time.c deleted file mode 100644 index 5da8092a9..000000000 --- a/util/time.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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/util/usb.c b/util/usb.c deleted file mode 100644 index a687eea9b..000000000 --- a/util/usb.c +++ /dev/null @@ -1,195 +0,0 @@ -/* usb.c -- libusb USB support for GRUB. */ -/* - * 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 - - -static struct grub_usb_controller_dev usb_controller = -{ - .name = "libusb" -}; - -static struct grub_usb_device *grub_usb_devs[128]; - -struct usb_bus *busses; - -static grub_err_t -grub_libusb_devices (void) - -{ - struct usb_bus *bus; - int last = 0; - - busses = usb_get_busses(); - - for (bus = busses; bus; bus = bus->next) - { - struct usb_device *usbdev; - struct grub_usb_device *dev; - - for (usbdev = bus->devices; usbdev; usbdev = usbdev->next) - { - struct usb_device_descriptor *desc = &usbdev->descriptor; - grub_err_t err; - - if (! desc->bcdUSB) - continue; - - dev = grub_malloc (sizeof (*dev)); - if (! dev) - return grub_errno; - - dev->data = usbdev; - - /* Fill in all descriptors. */ - err = grub_usb_device_initialize (dev); - if (err) - { - grub_errno = GRUB_ERR_NONE; - continue; - } - - /* Register the device. */ - grub_usb_devs[last++] = dev; - } - } - - return GRUB_USB_ERR_NONE; -} - - -int -grub_usb_iterate (int (*hook) (grub_usb_device_t dev)) -{ - int i; - - for (i = 0; i < 128; i++) - { - if (grub_usb_devs[i]) - { - if (hook (grub_usb_devs[i])) - return 1; - } - } - - return 0; -} - -grub_usb_err_t -grub_usb_root_hub (grub_usb_controller_t controller __attribute__((unused))) -{ - return GRUB_USB_ERR_NONE; -} - -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) -{ - 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) - { - usb_close (devh); - return GRUB_USB_ERR_STALL; - } - - usb_close (devh); - - return GRUB_USB_ERR_NONE; -} - -grub_usb_err_t -grub_usb_bulk_read (grub_usb_device_t dev, - int endpoint, grub_size_t size, char *data) -{ - usb_dev_handle *devh; - struct usb_device *d = dev->data; - - devh = usb_open (d); - if (usb_claim_interface (devh, 0) < 1) - { - usb_close (devh); - return GRUB_USB_ERR_STALL; - } - - if (usb_bulk_read (devh, endpoint, data, size, 20) < 1) - { - usb_close (devh); - return GRUB_USB_ERR_STALL; - } - - usb_release_interface (devh, 0); - usb_close (devh); - - return GRUB_USB_ERR_NONE; -} - -grub_usb_err_t -grub_usb_bulk_write (grub_usb_device_t dev, - int endpoint, grub_size_t size, char *data) -{ - usb_dev_handle *devh; - struct usb_device *d = dev->data; - - devh = usb_open (d); - if (usb_claim_interface (devh, 0) < 0) - goto fail; - - if (usb_bulk_write (devh, endpoint, data, size, 20) < 0) - goto fail; - - if (usb_release_interface (devh, 0) < 0) - goto fail; - - usb_close (devh); - - return GRUB_USB_ERR_NONE; - - fail: - usb_close (devh); - return GRUB_USB_ERR_STALL; -} - -GRUB_MOD_INIT (libusb) -{ - usb_init(); - usb_find_busses(); - usb_find_devices(); - - if (grub_libusb_devices ()) - return; - - grub_usb_controller_dev_register (&usb_controller); - - return; -} - -GRUB_MOD_FINI (libusb) -{ - return; -} 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); +}